• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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