gallium/util: move debug_print_bind_flags to u_debug_gallium
[mesa.git] / src / gallium / auxiliary / util / u_debug.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * Copyright (c) 2008 VMware, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29
30 #include "pipe/p_config.h"
31
32 #include "pipe/p_compiler.h"
33 #include "util/u_debug.h"
34 #include "util/u_dump.h"
35 #include "pipe/p_format.h"
36 #include "pipe/p_state.h"
37 #include "util/u_inlines.h"
38 #include "util/u_memory.h"
39 #include "util/u_string.h"
40 #include "util/u_math.h"
41 #include <inttypes.h>
42
43 #include <stdio.h>
44 #include <limits.h> /* CHAR_BIT */
45 #include <ctype.h> /* isalnum */
46
47 #ifdef _WIN32
48 #include <windows.h>
49 #include <stdlib.h>
50 #endif
51
52
53 void
54 _debug_vprintf(const char *format, va_list ap)
55 {
56 static char buf[4096] = {'\0'};
57 #if defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_EMBEDDED)
58 /* We buffer until we find a newline. */
59 size_t len = strlen(buf);
60 int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
61 if (ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) {
62 os_log_message(buf);
63 buf[0] = '\0';
64 }
65 #else
66 util_vsnprintf(buf, sizeof(buf), format, ap);
67 os_log_message(buf);
68 #endif
69 }
70
71
72 void
73 _pipe_debug_message(struct pipe_debug_callback *cb,
74 unsigned *id,
75 enum pipe_debug_type type,
76 const char *fmt, ...)
77 {
78 va_list args;
79 va_start(args, fmt);
80 if (cb && cb->debug_message)
81 cb->debug_message(cb->data, id, type, fmt, args);
82 va_end(args);
83 }
84
85
86 void
87 debug_disable_error_message_boxes(void)
88 {
89 #ifdef _WIN32
90 /* When Windows' error message boxes are disabled for this process (as is
91 * typically the case when running tests in an automated fashion) we disable
92 * CRT message boxes too.
93 */
94 UINT uMode = SetErrorMode(0);
95 SetErrorMode(uMode);
96 if (uMode & SEM_FAILCRITICALERRORS) {
97 /* Disable assertion failure message box.
98 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
99 */
100 _set_error_mode(_OUT_TO_STDERR);
101 #ifdef _MSC_VER
102 /* Disable abort message box.
103 * http://msdn.microsoft.com/en-us/library/e631wekh.aspx
104 */
105 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
106 #endif
107 }
108 #endif /* _WIN32 */
109 }
110
111
112 #ifdef DEBUG
113 void
114 debug_print_blob(const char *name, const void *blob, unsigned size)
115 {
116 const unsigned *ublob = (const unsigned *)blob;
117 unsigned i;
118
119 debug_printf("%s (%d dwords%s)\n", name, size/4,
120 size%4 ? "... plus a few bytes" : "");
121
122 for (i = 0; i < size/4; i++) {
123 debug_printf("%d:\t%08x\n", i, ublob[i]);
124 }
125 }
126 #endif
127
128
129 static boolean
130 debug_get_option_should_print(void)
131 {
132 static boolean first = TRUE;
133 static boolean value = FALSE;
134
135 if (!first)
136 return value;
137
138 /* Oh hey this will call into this function,
139 * but its cool since we set first to false
140 */
141 first = FALSE;
142 value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", FALSE);
143 /* XXX should we print this option? Currently it wont */
144 return value;
145 }
146
147
148 const char *
149 debug_get_option(const char *name, const char *dfault)
150 {
151 const char *result;
152
153 result = os_get_option(name);
154 if (!result)
155 result = dfault;
156
157 if (debug_get_option_should_print())
158 debug_printf("%s: %s = %s\n", __FUNCTION__, name,
159 result ? result : "(null)");
160
161 return result;
162 }
163
164
165 boolean
166 debug_get_bool_option(const char *name, boolean dfault)
167 {
168 const char *str = os_get_option(name);
169 boolean result;
170
171 if (str == NULL)
172 result = dfault;
173 else if (!util_strcmp(str, "n"))
174 result = FALSE;
175 else if (!util_strcmp(str, "no"))
176 result = FALSE;
177 else if (!util_strcmp(str, "0"))
178 result = FALSE;
179 else if (!util_strcmp(str, "f"))
180 result = FALSE;
181 else if (!util_strcmp(str, "F"))
182 result = FALSE;
183 else if (!util_strcmp(str, "false"))
184 result = FALSE;
185 else if (!util_strcmp(str, "FALSE"))
186 result = FALSE;
187 else
188 result = TRUE;
189
190 if (debug_get_option_should_print())
191 debug_printf("%s: %s = %s\n", __FUNCTION__, name,
192 result ? "TRUE" : "FALSE");
193
194 return result;
195 }
196
197
198 long
199 debug_get_num_option(const char *name, long dfault)
200 {
201 long result;
202 const char *str;
203
204 str = os_get_option(name);
205 if (!str) {
206 result = dfault;
207 } else {
208 char *endptr;
209
210 result = strtol(str, &endptr, 0);
211 if (str == endptr) {
212 /* Restore the default value when no digits were found. */
213 result = dfault;
214 }
215 }
216
217 if (debug_get_option_should_print())
218 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
219
220 return result;
221 }
222
223
224 static boolean
225 str_has_option(const char *str, const char *name)
226 {
227 /* Empty string. */
228 if (!*str) {
229 return FALSE;
230 }
231
232 /* OPTION=all */
233 if (!util_strcmp(str, "all")) {
234 return TRUE;
235 }
236
237 /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
238 {
239 const char *start = str;
240 unsigned name_len = strlen(name);
241
242 /* 'start' is the beginning of the currently-parsed word,
243 * we increment 'str' each iteration.
244 * if we find either the end of string or a non-alphanumeric character,
245 * we compare 'start' up to 'str-1' with 'name'. */
246
247 while (1) {
248 if (!*str || !(isalnum(*str) || *str == '_')) {
249 if (str-start == name_len &&
250 !memcmp(start, name, name_len)) {
251 return TRUE;
252 }
253
254 if (!*str) {
255 return FALSE;
256 }
257
258 start = str+1;
259 }
260
261 str++;
262 }
263 }
264
265 return FALSE;
266 }
267
268
269 uint64_t
270 debug_get_flags_option(const char *name,
271 const struct debug_named_value *flags,
272 uint64_t dfault)
273 {
274 uint64_t result;
275 const char *str;
276 const struct debug_named_value *orig = flags;
277 unsigned namealign = 0;
278
279 str = os_get_option(name);
280 if (!str)
281 result = dfault;
282 else if (!util_strcmp(str, "help")) {
283 result = dfault;
284 _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
285 for (; flags->name; ++flags)
286 namealign = MAX2(namealign, strlen(flags->name));
287 for (flags = orig; flags->name; ++flags)
288 _debug_printf("| %*s [0x%0*"PRIx64"]%s%s\n", namealign, flags->name,
289 (int)sizeof(uint64_t)*CHAR_BIT/4, flags->value,
290 flags->desc ? " " : "", flags->desc ? flags->desc : "");
291 }
292 else {
293 result = 0;
294 while (flags->name) {
295 if (str_has_option(str, flags->name))
296 result |= flags->value;
297 ++flags;
298 }
299 }
300
301 if (debug_get_option_should_print()) {
302 if (str) {
303 debug_printf("%s: %s = 0x%"PRIx64" (%s)\n",
304 __FUNCTION__, name, result, str);
305 } else {
306 debug_printf("%s: %s = 0x%"PRIx64"\n", __FUNCTION__, name, result);
307 }
308 }
309
310 return result;
311 }
312
313
314 void
315 _debug_assert_fail(const char *expr, const char *file, unsigned line,
316 const char *function)
317 {
318 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n",
319 file, line, function, expr);
320 os_abort();
321 }
322
323
324 const char *
325 debug_dump_enum(const struct debug_named_value *names,
326 unsigned long value)
327 {
328 static char rest[64];
329
330 while (names->name) {
331 if (names->value == value)
332 return names->name;
333 ++names;
334 }
335
336 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
337 return rest;
338 }
339
340
341 const char *
342 debug_dump_enum_noprefix(const struct debug_named_value *names,
343 const char *prefix,
344 unsigned long value)
345 {
346 static char rest[64];
347
348 while (names->name) {
349 if (names->value == value) {
350 const char *name = names->name;
351 while (*name == *prefix) {
352 name++;
353 prefix++;
354 }
355 return name;
356 }
357 ++names;
358 }
359
360 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
361 return rest;
362 }
363
364
365 const char *
366 debug_dump_flags(const struct debug_named_value *names, unsigned long value)
367 {
368 static char output[4096];
369 static char rest[256];
370 int first = 1;
371
372 output[0] = '\0';
373
374 while (names->name) {
375 if ((names->value & value) == names->value) {
376 if (!first)
377 util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
378 else
379 first = 0;
380 util_strncat(output, names->name, sizeof(output) - strlen(output) - 1);
381 output[sizeof(output) - 1] = '\0';
382 value &= ~names->value;
383 }
384 ++names;
385 }
386
387 if (value) {
388 if (!first)
389 util_strncat(output, "|", sizeof(output) - strlen(output) - 1);
390 else
391 first = 0;
392
393 util_snprintf(rest, sizeof(rest), "0x%08lx", value);
394 util_strncat(output, rest, sizeof(output) - strlen(output) - 1);
395 output[sizeof(output) - 1] = '\0';
396 }
397
398 if (first)
399 return "0";
400
401 return output;
402 }
403
404
405
406 #ifdef DEBUG
407 int fl_indent = 0;
408 const char* fl_function[1024];
409
410 int
411 debug_funclog_enter(const char* f, UNUSED const int line,
412 UNUSED const char* file)
413 {
414 int i;
415
416 for (i = 0; i < fl_indent; i++)
417 debug_printf(" ");
418 debug_printf("%s\n", f);
419
420 assert(fl_indent < 1023);
421 fl_function[fl_indent++] = f;
422
423 return 0;
424 }
425
426 void
427 debug_funclog_exit(const char* f, UNUSED const int line,
428 UNUSED const char* file)
429 {
430 --fl_indent;
431 assert(fl_indent >= 0);
432 assert(fl_function[fl_indent] == f);
433 }
434
435 void
436 debug_funclog_enter_exit(const char* f, UNUSED const int line,
437 UNUSED const char* file)
438 {
439 int i;
440 for (i = 0; i < fl_indent; i++)
441 debug_printf(" ");
442 debug_printf("%s\n", f);
443 }
444 #endif
445
446
447
448 #ifdef DEBUG
449 /**
450 * Print PIPE_TRANSFER_x flags with a message.
451 */
452 void
453 debug_print_transfer_flags(const char *msg, unsigned usage)
454 {
455 debug_printf("%s: ", msg);
456 util_dump_transfer_usage(stdout, usage);
457 printf("\n");
458 }
459
460
461 #endif