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