xref: /third_party/mesa3d/src/util/u_debug.h (revision bf215546)
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
58extern "C" {
59#endif
60
61enum 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 */
76struct 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
105void _debug_vprintf(const char *format, va_list ap);
106
107
108static inline void
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
128static inline void
129debug_printf(const char *format, ...) _util_printf_format(1,2);
130
131static inline void
132debug_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 */
174void 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 */
186void
187debug_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
201long
202debug_get_num_option(const char *name, long dfault);
203
204void
205debug_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
286void
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 */
297struct 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 */
332const char *
333debug_dump_enum(const struct debug_named_value *names,
334                unsigned long value);
335
336const char *
337debug_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 */
345const char *
346debug_dump_flags(const struct debug_named_value *names,
347                 unsigned long value);
348
349
350/**
351 * Function enter exit loggers
352 */
353#ifdef DEBUG
354int debug_funclog_enter(const char* f, const int line, const char* file);
355void debug_funclog_exit(const char* f, const int line, const char* file);
356void 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 */
399const char *
400debug_get_option(const char *name, const char *dfault);
401
402bool
403debug_get_bool_option(const char *name, bool dfault);
404
405long
406debug_get_num_option(const char *name, long dfault);
407
408uint64_t
409debug_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) \
414static const char * \
415debug_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
426static inline bool
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) \
443static FILE * \
444debug_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) \
460static bool \
461debug_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) \
473static long \
474debug_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) \
486static unsigned long \
487debug_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