gallium: Give some chance for the table to actually grow.
[mesa.git] / src / gallium / auxiliary / util / p_debug.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29 #include <stdarg.h>
30
31 #ifdef WIN32
32 #include <windows.h>
33 #include <winddi.h>
34 #else
35 #include <stdio.h>
36 #include <stdlib.h>
37 #endif
38
39 #include "pipe/p_compiler.h"
40 #include "pipe/p_util.h"
41 #include "pipe/p_debug.h"
42
43
44 #ifdef WIN32
45 static INLINE void
46 rpl_EngDebugPrint(const char *format, ...)
47 {
48 va_list ap;
49 va_start(ap, format);
50 EngDebugPrint("", (PCHAR)format, ap);
51 va_end(ap);
52 }
53
54 int rpl_vsnprintf(char *, size_t, const char *, va_list);
55 int rpl_snprintf(char *str, size_t size, const char *format, ...);
56 #define vsnprintf rpl_vsnprintf
57 #define snprintf rpl_snprintf
58 #endif
59
60
61 void debug_vprintf(const char *format, va_list ap)
62 {
63 #ifdef WIN32
64 #ifndef WINCE
65 /* EngDebugPrint does not handle float point arguments, so we need to use
66 * our own vsnprintf implementation */
67 char buf[512 + 1];
68 rpl_vsnprintf(buf, sizeof(buf), format, ap);
69 rpl_EngDebugPrint("%s", buf);
70 #else
71 /* TODO: Implement debug print for WINCE */
72 #endif
73 #else
74 vfprintf(stderr, format, ap);
75 #endif
76 }
77
78
79 void debug_printf(const char *format, ...)
80 {
81 va_list ap;
82 va_start(ap, format);
83 debug_vprintf(format, ap);
84 va_end(ap);
85 }
86
87
88 void debug_print_blob( const char *name,
89 const void *blob,
90 unsigned size )
91 {
92 const unsigned *ublob = (const unsigned *)blob;
93 unsigned i;
94
95 debug_printf("%s (%d dwords%s)\n", name, size/4,
96 size%4 ? "... plus a few bytes" : "");
97
98 for (i = 0; i < size/4; i++) {
99 debug_printf("%d:\t%08x\n", i, ublob[i]);
100 }
101 }
102
103
104 /* TODO: implement a debug_abort that calls EngBugCheckEx on WIN32 */
105
106
107 static INLINE void debug_break(void)
108 {
109 #if (defined(__i386__) || defined(__386__)) && defined(__GNUC__)
110 __asm("int3");
111 #elif (defined(__i386__) || defined(__386__)) && defined(__MSC__)
112 _asm {int 3};
113 #elif defined(WIN32) && !defined(WINCE)
114 EngDebugBreak();
115 #else
116 abort();
117 #endif
118 }
119
120 #if defined(WIN32)
121 ULONG_PTR debug_config_file = 0;
122 void *mapped_config_file = 0;
123
124 enum {
125 eAssertAbortEn = 0x1,
126 };
127
128 /* Check for aborts enabled. */
129 static unsigned abort_en()
130 {
131 if (!mapped_config_file)
132 {
133 /* Open an 8 byte file for configuration data. */
134 mapped_config_file = EngMapFile(L"\\??\\c:\\gaDebug.cfg", 8, &debug_config_file);
135 }
136
137 /* A value of "0" (ascii) in the configuration file will clear the
138 * first 8 bits in the test byte.
139 *
140 * A value of "1" (ascii) in the configuration file will set the
141 * first bit in the test byte.
142 *
143 * A value of "2" (ascii) in the configuration file will set the
144 * second bit in the test byte.
145 *
146 * Currently the only interesting values are 0 and 1, which clear
147 * and set abort-on-assert behaviour respectively.
148 */
149 return ((((char *)mapped_config_file)[0]) - 0x30) & eAssertAbortEn;
150 }
151 #else /* WIN32 */
152 static unsigned abort_en()
153 {
154 return !GETENV("GALLIUM_ABORT_ON_ASSERT");
155 }
156 #endif
157
158 void debug_assert_fail(const char *expr, const char *file, unsigned line)
159 {
160 debug_printf("%s:%i: Assertion `%s' failed.\n", file, line, expr);
161 if (abort_en())
162 {
163 debug_break();
164 } else
165 {
166 debug_printf("continuing...\n");
167 }
168 }
169
170
171 #define DEBUG_MASK_TABLE_SIZE 256
172
173
174 /**
175 * Mask hash table.
176 *
177 * For now we just take the lower bits of the key, and do no attempt to solve
178 * collisions. Use a proper hash table when we have dozens of drivers.
179 */
180 static uint32_t debug_mask_table[DEBUG_MASK_TABLE_SIZE];
181
182
183 void debug_mask_set(uint32_t uuid, uint32_t mask)
184 {
185 unsigned hash = uuid & (DEBUG_MASK_TABLE_SIZE - 1);
186 debug_mask_table[hash] = mask;
187 }
188
189
190 uint32_t debug_mask_get(uint32_t uuid)
191 {
192 unsigned hash = uuid & (DEBUG_MASK_TABLE_SIZE - 1);
193 return debug_mask_table[hash];
194 }
195
196
197 void debug_mask_vprintf(uint32_t uuid, uint32_t what, const char *format, va_list ap)
198 {
199 uint32_t mask = debug_mask_get(uuid);
200 if(mask & what)
201 debug_vprintf(format, ap);
202 }
203
204
205 const char *
206 debug_dump_enum(const struct debug_named_value *names,
207 unsigned long value)
208 {
209 static char rest[256];
210
211 while(names->name) {
212 if(names->value == value)
213 return names->name;
214 ++names;
215 }
216
217 snprintf(rest, sizeof(rest), "0x%08x", value);
218 return rest;
219 }
220
221
222 const char *
223 debug_dump_flags(const struct debug_named_value *names,
224 unsigned long value)
225 {
226 static char output[4096];
227 static char rest[256];
228 int first = 1;
229
230 output[0] = '\0';
231
232 while(names->name) {
233 if((names->value & value) == names->value) {
234 if (!first)
235 strncat(output, "|", sizeof(output));
236 else
237 first = 0;
238 strncat(output, names->name, sizeof(output));
239 value &= ~names->value;
240 }
241 ++names;
242 }
243
244 if (value) {
245 if (!first)
246 strncat(output, "|", sizeof(output));
247 else
248 first = 0;
249
250 snprintf(rest, sizeof(rest), "0x%08x", value);
251 strncat(output, rest, sizeof(output));
252 }
253
254 if(first)
255 return "0";
256
257 return output;
258 }
259
260