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 "util/u_debug.h"
31 #include "util/u_string.h"
32 #include "util/u_math.h"
33 #include <inttypes.h>
34
35 #include <stdio.h>
36 #include <limits.h> /* CHAR_BIT */
37 #include <ctype.h> /* isalnum */
38
39 #ifdef _WIN32
40 #include <windows.h>
41 #include <stdlib.h>
42 #endif
43
44
45 void
_debug_vprintf(const char * format,va_list ap)46 _debug_vprintf(const char *format, va_list ap)
47 {
48 static char buf[4096] = {'\0'};
49 #if DETECT_OS_WINDOWS || defined(EMBEDDED_DEVICE)
50 /* We buffer until we find a newline. */
51 size_t len = strlen(buf);
52 int ret = vsnprintf(buf + len, sizeof(buf) - len, format, ap);
53 if (ret > (int)(sizeof(buf) - len - 1) || strchr(buf + len, '\n')) {
54 os_log_message(buf);
55 buf[0] = '\0';
56 }
57 #else
58 vsnprintf(buf, sizeof(buf), format, ap);
59 os_log_message(buf);
60 #endif
61 }
62
63
64 void
_util_debug_message(struct util_debug_callback * cb,unsigned * id,enum util_debug_type type,const char * fmt,...)65 _util_debug_message(struct util_debug_callback *cb,
66 unsigned *id,
67 enum util_debug_type type,
68 const char *fmt, ...)
69 {
70 va_list args;
71 va_start(args, fmt);
72 if (cb && cb->debug_message)
73 cb->debug_message(cb->data, id, type, fmt, args);
74 va_end(args);
75 }
76
77
78 #ifdef _WIN32
79 void
debug_disable_win32_error_dialogs(void)80 debug_disable_win32_error_dialogs(void)
81 {
82 /* When Windows' error message boxes are disabled for this process (as is
83 * typically the case when running tests in an automated fashion) we disable
84 * CRT message boxes too.
85 */
86 UINT uMode = SetErrorMode(0);
87 SetErrorMode(uMode);
88 if (uMode & SEM_FAILCRITICALERRORS) {
89 /* Disable assertion failure message box.
90 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
91 */
92 _set_error_mode(_OUT_TO_STDERR);
93 #ifdef _MSC_VER
94 /* Disable abort message box.
95 * http://msdn.microsoft.com/en-us/library/e631wekh.aspx
96 */
97 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
98 #endif
99 }
100 }
101 #endif /* _WIN32 */
102
103
104 #ifdef DEBUG
105 void
debug_print_blob(const char * name,const void * blob,unsigned size)106 debug_print_blob(const char *name, const void *blob, unsigned size)
107 {
108 const unsigned *ublob = (const unsigned *)blob;
109 unsigned i;
110
111 debug_printf("%s (%d dwords%s)\n", name, size/4,
112 size%4 ? "... plus a few bytes" : "");
113
114 for (i = 0; i < size/4; i++) {
115 debug_printf("%d:\t%08x\n", i, ublob[i]);
116 }
117 }
118 #endif
119
120
121 static bool
debug_get_option_should_print(void)122 debug_get_option_should_print(void)
123 {
124 static bool initialized = false;
125 static bool value = false;
126
127 if (initialized)
128 return value;
129
130 /* Oh hey this will call into this function,
131 * but its cool since we set first to false
132 */
133 initialized = true;
134 value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", false);
135 /* XXX should we print this option? Currently it wont */
136 return value;
137 }
138
139
140 const char *
debug_get_option(const char * name,const char * dfault)141 debug_get_option(const char *name, const char *dfault)
142 {
143 const char *result;
144
145 result = os_get_option(name);
146 if (!result)
147 result = dfault;
148
149 if (debug_get_option_should_print())
150 debug_printf("%s: %s = %s\n", __FUNCTION__, name,
151 result ? result : "(null)");
152
153 return result;
154 }
155
156
157 bool
debug_get_bool_option(const char * name,bool dfault)158 debug_get_bool_option(const char *name, bool dfault)
159 {
160 const char *str = os_get_option(name);
161 bool result;
162
163 if (str == NULL)
164 result = dfault;
165 else if (!strcmp(str, "n"))
166 result = false;
167 else if (!strcmp(str, "no"))
168 result = false;
169 else if (!strcmp(str, "0"))
170 result = false;
171 else if (!strcmp(str, "f"))
172 result = false;
173 else if (!strcmp(str, "F"))
174 result = false;
175 else if (!strcmp(str, "false"))
176 result = false;
177 else if (!strcmp(str, "FALSE"))
178 result = false;
179 else
180 result = true;
181
182 if (debug_get_option_should_print())
183 debug_printf("%s: %s = %s\n", __FUNCTION__, name,
184 result ? "TRUE" : "FALSE");
185
186 return result;
187 }
188
189
190 long
debug_get_num_option(const char * name,long dfault)191 debug_get_num_option(const char *name, long dfault)
192 {
193 long result;
194 const char *str;
195
196 str = os_get_option(name);
197 if (!str) {
198 result = dfault;
199 } else {
200 char *endptr;
201
202 result = strtol(str, &endptr, 0);
203 if (str == endptr) {
204 /* Restore the default value when no digits were found. */
205 result = dfault;
206 }
207 }
208
209 if (debug_get_option_should_print())
210 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
211
212 return result;
213 }
214
215 void
debug_get_version_option(const char * name,unsigned * major,unsigned * minor)216 debug_get_version_option(const char *name, unsigned *major, unsigned *minor)
217 {
218 const char *str;
219
220 str = os_get_option(name);
221 if (str) {
222 unsigned v_maj, v_min;
223 int n;
224
225 n = sscanf(str, "%u.%u", &v_maj, &v_min);
226 if (n != 2) {
227 debug_printf("Illegal version specified for %s : %s\n", name, str);
228 return;
229 }
230 *major = v_maj;
231 *minor = v_min;
232 }
233
234 if (debug_get_option_should_print())
235 debug_printf("%s: %s = %u.%u\n", __FUNCTION__, name, *major, *minor);
236
237 return;
238 }
239
240 static bool
str_has_option(const char * str,const char * name)241 str_has_option(const char *str, const char *name)
242 {
243 /* Empty string. */
244 if (!*str) {
245 return false;
246 }
247
248 /* OPTION=all */
249 if (!strcmp(str, "all")) {
250 return true;
251 }
252
253 /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
254 {
255 const char *start = str;
256 unsigned name_len = strlen(name);
257
258 /* 'start' is the beginning of the currently-parsed word,
259 * we increment 'str' each iteration.
260 * if we find either the end of string or a non-alphanumeric character,
261 * we compare 'start' up to 'str-1' with 'name'. */
262
263 while (1) {
264 if (!*str || !(isalnum(*str) || *str == '_')) {
265 if (str-start == name_len &&
266 !memcmp(start, name, name_len)) {
267 return true;
268 }
269
270 if (!*str) {
271 return false;
272 }
273
274 start = str+1;
275 }
276
277 str++;
278 }
279 }
280
281 return false;
282 }
283
284
285 uint64_t
debug_get_flags_option(const char * name,const struct debug_named_value * flags,uint64_t dfault)286 debug_get_flags_option(const char *name,
287 const struct debug_named_value *flags,
288 uint64_t dfault)
289 {
290 uint64_t result;
291 const char *str;
292 const struct debug_named_value *orig = flags;
293 unsigned namealign = 0;
294
295 str = os_get_option(name);
296 if (!str)
297 result = dfault;
298 else if (!strcmp(str, "help")) {
299 result = dfault;
300 _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
301 for (; flags->name; ++flags)
302 namealign = MAX2(namealign, strlen(flags->name));
303 for (flags = orig; flags->name; ++flags)
304 _debug_printf("| %*s [0x%0*"PRIx64"]%s%s\n", namealign, flags->name,
305 (int)sizeof(uint64_t)*CHAR_BIT/4, flags->value,
306 flags->desc ? " " : "", flags->desc ? flags->desc : "");
307 }
308 else {
309 result = 0;
310 while (flags->name) {
311 if (str_has_option(str, flags->name))
312 result |= flags->value;
313 ++flags;
314 }
315 }
316
317 if (debug_get_option_should_print()) {
318 if (str) {
319 debug_printf("%s: %s = 0x%"PRIx64" (%s)\n",
320 __FUNCTION__, name, result, str);
321 } else {
322 debug_printf("%s: %s = 0x%"PRIx64"\n", __FUNCTION__, name, result);
323 }
324 }
325
326 return result;
327 }
328
329
330 const char *
debug_dump_enum(const struct debug_named_value * names,unsigned long value)331 debug_dump_enum(const struct debug_named_value *names,
332 unsigned long value)
333 {
334 static char rest[64];
335
336 while (names->name) {
337 if (names->value == value)
338 return names->name;
339 ++names;
340 }
341
342 snprintf(rest, sizeof(rest), "0x%08lx", value);
343 return rest;
344 }
345
346
347 const char *
debug_dump_enum_noprefix(const struct debug_named_value * names,const char * prefix,unsigned long value)348 debug_dump_enum_noprefix(const struct debug_named_value *names,
349 const char *prefix,
350 unsigned long value)
351 {
352 static char rest[64];
353
354 while (names->name) {
355 if (names->value == value) {
356 const char *name = names->name;
357 while (*name == *prefix) {
358 name++;
359 prefix++;
360 }
361 return name;
362 }
363 ++names;
364 }
365
366 snprintf(rest, sizeof(rest), "0x%08lx", value);
367 return rest;
368 }
369
370
371 const char *
debug_dump_flags(const struct debug_named_value * names,unsigned long value)372 debug_dump_flags(const struct debug_named_value *names, unsigned long value)
373 {
374 static char output[4096];
375 static char rest[256];
376 int first = 1;
377
378 output[0] = '\0';
379
380 while (names->name) {
381 if ((names->value & value) == names->value) {
382 if (!first)
383 strncat(output, "|", sizeof(output) - strlen(output) - 1);
384 else
385 first = 0;
386 strncat(output, names->name, sizeof(output) - strlen(output) - 1);
387 output[sizeof(output) - 1] = '\0';
388 value &= ~names->value;
389 }
390 ++names;
391 }
392
393 if (value) {
394 if (!first)
395 strncat(output, "|", sizeof(output) - strlen(output) - 1);
396 else
397 first = 0;
398
399 snprintf(rest, sizeof(rest), "0x%08lx", value);
400 strncat(output, rest, sizeof(output) - strlen(output) - 1);
401 output[sizeof(output) - 1] = '\0';
402 }
403
404 if (first)
405 return "0";
406
407 return output;
408 }
409
410
411
412 #ifdef DEBUG
413 int fl_indent = 0;
414 const char* fl_function[1024];
415
416 int
debug_funclog_enter(const char * f,UNUSED const int line,UNUSED const char * file)417 debug_funclog_enter(const char* f, UNUSED const int line,
418 UNUSED const char* file)
419 {
420 int i;
421
422 for (i = 0; i < fl_indent; i++)
423 debug_printf(" ");
424 debug_printf("%s\n", f);
425
426 assert(fl_indent < 1023);
427 fl_function[fl_indent++] = f;
428
429 return 0;
430 }
431
432 void
debug_funclog_exit(const char * f,UNUSED const int line,UNUSED const char * file)433 debug_funclog_exit(const char* f, UNUSED const int line,
434 UNUSED const char* file)
435 {
436 --fl_indent;
437 assert(fl_indent >= 0);
438 assert(fl_function[fl_indent] == f);
439 }
440
441 void
debug_funclog_enter_exit(const char * f,UNUSED const int line,UNUSED const char * file)442 debug_funclog_enter_exit(const char* f, UNUSED const int line,
443 UNUSED const char* file)
444 {
445 int i;
446 for (i = 0; i < fl_indent; i++)
447 debug_printf(" ");
448 debug_printf("%s\n", f);
449 }
450 #endif
451