1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
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 VMWARE 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 * @file
30 * Cross-platform debugging helpers.
31 *
32 * For now it just has assert and printf replacements, but it might be extended
33 * with stack trace reports and more advanced logging in the near future.
34 *
35 * @author Jose Fonseca <jfonseca@vmware.com>
36 */
37
38 #ifndef U_DEBUG_H_
39 #define U_DEBUG_H_
40
41 #include <stdarg.h>
42 #include <string.h>
43 #if !defined(_WIN32)
44 #include <sys/types.h>
45 #include <unistd.h>
46 #endif
47
48 #include "util/os_misc.h"
49 #include "util/detect_os.h"
50 #include "util/macros.h"
51
52 #if DETECT_OS_HAIKU
53 /* Haiku provides debug_printf in libroot with OS.h */
54 #include <OS.h>
55 #endif
56
57 #ifdef __cplusplus
58 extern "C" {
59 #endif
60
61 enum util_debug_type
62 {
63 UTIL_DEBUG_TYPE_OUT_OF_MEMORY = 1,
64 UTIL_DEBUG_TYPE_ERROR,
65 UTIL_DEBUG_TYPE_SHADER_INFO,
66 UTIL_DEBUG_TYPE_PERF_INFO,
67 UTIL_DEBUG_TYPE_INFO,
68 UTIL_DEBUG_TYPE_FALLBACK,
69 UTIL_DEBUG_TYPE_CONFORMANCE,
70 };
71
72 /**
73 * Structure that contains a callback for debug messages from the driver back
74 * to the gallium frontend.
75 */
76 struct util_debug_callback
77 {
78 /**
79 * When set to \c true, the callback may be called asynchronously from a
80 * driver-created thread.
81 */
82 bool async;
83
84 /**
85 * Callback for the driver to report debug/performance/etc information back
86 * to the gallium frontend.
87 *
88 * \param data user-supplied data pointer
89 * \param id message type identifier, if pointed value is 0, then a
90 * new id is assigned
91 * \param type UTIL_DEBUG_TYPE_*
92 * \param format printf-style format string
93 * \param args args for format string
94 */
95 void (*debug_message)(void *data,
96 unsigned *id,
97 enum util_debug_type type,
98 const char *fmt,
99 va_list args);
100 void *data;
101 };
102
103 #define _util_printf_format(fmt, list) PRINTFLIKE(fmt, list)
104
105 void _debug_vprintf(const char *format, va_list ap);
106
107
108 static inline void
_debug_printf(const char * format,...)109 _debug_printf(const char *format, ...)
110 {
111 va_list ap;
112 va_start(ap, format);
113 _debug_vprintf(format, ap);
114 va_end(ap);
115 }
116
117
118 /**
119 * Print debug messages.
120 *
121 * The actual channel used to output debug message is platform specific. To
122 * avoid misformating or truncation, follow these rules of thumb:
123 * - output whole lines
124 * - avoid outputing large strings (512 bytes is the current maximum length
125 * that is guaranteed to be printed in all platforms)
126 */
127 #if !DETECT_OS_HAIKU
128 static inline void
129 debug_printf(const char *format, ...) _util_printf_format(1,2);
130
131 static inline void
debug_printf(const char * format,...)132 debug_printf(const char *format, ...)
133 {
134 #ifdef DEBUG
135 va_list ap;
136 va_start(ap, format);
137 _debug_vprintf(format, ap);
138 va_end(ap);
139 #else
140 (void) format; /* silence warning */
141 #endif
142 }
143 #endif
144
145
146 /*
147 * ... isn't portable so we need to pass arguments in parentheses.
148 *
149 * usage:
150 * debug_printf_once(("answer: %i\n", 42));
151 */
152 #define debug_printf_once(args) \
153 do { \
154 static bool once = true; \
155 if (once) { \
156 once = false; \
157 debug_printf args; \
158 } \
159 } while (0)
160
161
162 #ifdef DEBUG
163 #define debug_vprintf(_format, _ap) _debug_vprintf(_format, _ap)
164 #else
165 #define debug_vprintf(_format, _ap) ((void)0)
166 #endif
167
168
169 #ifdef DEBUG
170 /**
171 * Dump a blob in hex to the same place that debug_printf sends its
172 * messages.
173 */
174 void debug_print_blob( const char *name, const void *blob, unsigned size );
175 #else
176 #define debug_print_blob(_name, _blob, _size) ((void)0)
177 #endif
178
179
180 #ifdef _WIN32
181 /**
182 * Disable Win32 interactive error message boxes.
183 *
184 * Should be called as soon as possible for effectiveness.
185 */
186 void
187 debug_disable_win32_error_dialogs(void);
188 #endif
189
190
191 /**
192 * Hard-coded breakpoint.
193 */
194 #ifdef DEBUG
195 #define debug_break() os_break()
196 #else /* !DEBUG */
197 #define debug_break() ((void)0)
198 #endif /* !DEBUG */
199
200
201 long
202 debug_get_num_option(const char *name, long dfault);
203
204 void
205 debug_get_version_option(const char *name, unsigned *major, unsigned *minor);
206
207
208 /**
209 * Output the current function name.
210 */
211 #ifdef DEBUG
212 #define debug_checkpoint() \
213 _debug_printf("%s\n", __FUNCTION__)
214 #else
215 #define debug_checkpoint() \
216 ((void)0)
217 #endif
218
219
220 /**
221 * Output the full source code position.
222 */
223 #ifdef DEBUG
224 #define debug_checkpoint_full() \
225 _debug_printf("%s:%u:%s\n", __FILE__, __LINE__, __FUNCTION__)
226 #else
227 #define debug_checkpoint_full() \
228 ((void)0)
229 #endif
230
231
232 /**
233 * Output a warning message. Muted on release version.
234 */
235 #ifdef DEBUG
236 #define debug_warning(__msg) \
237 _debug_printf("%s:%u:%s: warning: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg)
238 #else
239 #define debug_warning(__msg) \
240 ((void)0)
241 #endif
242
243
244 /**
245 * Emit a warning message, but only once.
246 */
247 #ifdef DEBUG
248 #define debug_warn_once(__msg) \
249 do { \
250 static bool warned = false; \
251 if (!warned) { \
252 _debug_printf("%s:%u:%s: one time warning: %s\n", \
253 __FILE__, __LINE__, __FUNCTION__, __msg); \
254 warned = true; \
255 } \
256 } while (0)
257 #else
258 #define debug_warn_once(__msg) \
259 ((void)0)
260 #endif
261
262
263 /**
264 * Output an error message. Not muted on release version.
265 */
266 #ifdef DEBUG
267 #define debug_error(__msg) \
268 _debug_printf("%s:%u:%s: error: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg)
269 #else
270 #define debug_error(__msg) \
271 _debug_printf("error: %s\n", __msg)
272 #endif
273
274 /**
275 * Output a debug log message to the debug info callback.
276 */
277 #define util_debug_message(cb, type, fmt, ...) do { \
278 static unsigned id = 0; \
279 if ((cb) && (cb)->debug_message) { \
280 _util_debug_message(cb, &id, \
281 UTIL_DEBUG_TYPE_ ## type, \
282 fmt, ##__VA_ARGS__); \
283 } \
284 } while (0)
285
286 void
287 _util_debug_message(
288 struct util_debug_callback *cb,
289 unsigned *id,
290 enum util_debug_type type,
291 const char *fmt, ...) _util_printf_format(4, 5);
292
293
294 /**
295 * Used by debug_dump_enum and debug_dump_flags to describe symbols.
296 */
297 struct debug_named_value
298 {
299 const char *name;
300 uint64_t value;
301 const char *desc;
302 };
303
304
305 /**
306 * Some C pre-processor magic to simplify creating named values.
307 *
308 * Example:
309 * @code
310 * static const debug_named_value my_names[] = {
311 * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_X),
312 * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Y),
313 * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Z),
314 * DEBUG_NAMED_VALUE_END
315 * };
316 *
317 * ...
318 * debug_printf("%s = %s\n",
319 * name,
320 * debug_dump_enum(my_names, my_value));
321 * ...
322 * @endcode
323 */
324 #define DEBUG_NAMED_VALUE(__symbol) {#__symbol, (unsigned long)__symbol, NULL}
325 #define DEBUG_NAMED_VALUE_WITH_DESCRIPTION(__symbol, __desc) {#__symbol, (unsigned long)__symbol, __desc}
326 #define DEBUG_NAMED_VALUE_END {NULL, 0, NULL}
327
328
329 /**
330 * Convert a enum value to a string.
331 */
332 const char *
333 debug_dump_enum(const struct debug_named_value *names,
334 unsigned long value);
335
336 const char *
337 debug_dump_enum_noprefix(const struct debug_named_value *names,
338 const char *prefix,
339 unsigned long value);
340
341
342 /**
343 * Convert binary flags value to a string.
344 */
345 const char *
346 debug_dump_flags(const struct debug_named_value *names,
347 unsigned long value);
348
349
350 /**
351 * Function enter exit loggers
352 */
353 #ifdef DEBUG
354 int debug_funclog_enter(const char* f, const int line, const char* file);
355 void debug_funclog_exit(const char* f, const int line, const char* file);
356 void debug_funclog_enter_exit(const char* f, const int line, const char* file);
357
358 #define DEBUG_FUNCLOG_ENTER() \
359 int __debug_decleration_work_around = \
360 debug_funclog_enter(__FUNCTION__, __LINE__, __FILE__)
361 #define DEBUG_FUNCLOG_EXIT() \
362 do { \
363 (void)__debug_decleration_work_around; \
364 debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \
365 return; \
366 } while(0)
367 #define DEBUG_FUNCLOG_EXIT_RET(ret) \
368 do { \
369 (void)__debug_decleration_work_around; \
370 debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \
371 return ret; \
372 } while(0)
373 #define DEBUG_FUNCLOG_ENTER_EXIT() \
374 debug_funclog_enter_exit(__FUNCTION__, __LINE__, __FILE__)
375
376 #else
377 #define DEBUG_FUNCLOG_ENTER() \
378 int __debug_decleration_work_around
379 #define DEBUG_FUNCLOG_EXIT() \
380 do { (void)__debug_decleration_work_around; return; } while(0)
381 #define DEBUG_FUNCLOG_EXIT_RET(ret) \
382 do { (void)__debug_decleration_work_around; return ret; } while(0)
383 #define DEBUG_FUNCLOG_ENTER_EXIT()
384 #endif
385
386
387 /**
388 * Get option.
389 *
390 * It is an alias for getenv on Linux.
391 *
392 * On Windows it reads C:\gallium.cfg, which is a text file with CR+LF line
393 * endings with one option per line as
394 *
395 * NAME=value
396 *
397 * This file must be terminated with an extra empty line.
398 */
399 const char *
400 debug_get_option(const char *name, const char *dfault);
401
402 bool
403 debug_get_bool_option(const char *name, bool dfault);
404
405 long
406 debug_get_num_option(const char *name, long dfault);
407
408 uint64_t
409 debug_get_flags_option(const char *name,
410 const struct debug_named_value *flags,
411 uint64_t dfault);
412
413 #define DEBUG_GET_ONCE_OPTION(suffix, name, dfault) \
414 static const char * \
415 debug_get_option_ ## suffix (void) \
416 { \
417 static bool initialized = false; \
418 static const char * value; \
419 if (!initialized) { \
420 initialized = true; \
421 value = debug_get_option(name, dfault); \
422 } \
423 return value; \
424 }
425
426 static inline bool
__check_suid(void)427 __check_suid(void)
428 {
429 #if !defined(_WIN32)
430 if (geteuid() != getuid())
431 return true;
432 #endif
433 return false;
434 }
435
436 /**
437 * Define a getter for a debug option which specifies a 'FILE *'
438 * to open, with additional checks for suid executables. Note
439 * that if the return is not NULL, the caller owns the 'FILE *'
440 * reference.
441 */
442 #define DEBUG_GET_ONCE_FILE_OPTION(suffix, name, dfault, mode) \
443 static FILE * \
444 debug_get_option_ ## suffix (void) \
445 { \
446 static bool initialized = false; \
447 static const char * value; \
448 if (__check_suid()) \
449 return NULL; \
450 if (!initialized) { \
451 initialized = true; \
452 value = debug_get_option(name, dfault); \
453 } \
454 if (!value) \
455 return NULL; \
456 return fopen(value, mode); \
457 }
458
459 #define DEBUG_GET_ONCE_BOOL_OPTION(sufix, name, dfault) \
460 static bool \
461 debug_get_option_ ## sufix (void) \
462 { \
463 static bool initialized = false; \
464 static bool value; \
465 if (!initialized) { \
466 initialized = true; \
467 value = debug_get_bool_option(name, dfault); \
468 } \
469 return value; \
470 }
471
472 #define DEBUG_GET_ONCE_NUM_OPTION(sufix, name, dfault) \
473 static long \
474 debug_get_option_ ## sufix (void) \
475 { \
476 static bool initialized = false; \
477 static long value; \
478 if (!initialized) { \
479 initialized = true; \
480 value = debug_get_num_option(name, dfault); \
481 } \
482 return value; \
483 }
484
485 #define DEBUG_GET_ONCE_FLAGS_OPTION(sufix, name, flags, dfault) \
486 static unsigned long \
487 debug_get_option_ ## sufix (void) \
488 { \
489 static bool initialized = false; \
490 static unsigned long value; \
491 if (!initialized) { \
492 initialized = true; \
493 value = debug_get_flags_option(name, flags, dfault); \
494 } \
495 return value; \
496 }
497
498
499 #ifdef __cplusplus
500 }
501 #endif
502
503 #endif /* U_DEBUG_H_ */
504