Home | History | Annotate | Download | only in util
      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 (at) vmware.com>
     36  */
     37 
     38 #ifndef U_DEBUG_H_
     39 #define U_DEBUG_H_
     40 
     41 
     42 #include "os/os_misc.h"
     43 
     44 #if defined(PIPE_OS_HAIKU)
     45 /* Haiku provides debug_printf in libroot with OS.h */
     46 #include <OS.h>
     47 #endif
     48 
     49 #include "pipe/p_format.h"
     50 #include "pipe/p_defines.h"
     51 
     52 
     53 #ifdef	__cplusplus
     54 extern "C" {
     55 #endif
     56 
     57 
     58 #if defined(__GNUC__)
     59 #define _util_printf_format(fmt, list) __attribute__ ((format (printf, fmt, list)))
     60 #else
     61 #define _util_printf_format(fmt, list)
     62 #endif
     63 
     64 void _debug_vprintf(const char *format, va_list ap);
     65 
     66 
     67 static 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 !defined(PIPE_OS_HAIKU)
     87 static inline void
     88 debug_printf(const char *format, ...) _util_printf_format(1,2);
     89 
     90 static inline void
     91 debug_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 boolean 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  */
    133 void debug_print_blob( const char *name, const void *blob, unsigned size );
    134 
    135 /* Print a message along with a prettified format string
    136  */
    137 void debug_print_format(const char *msg, unsigned fmt );
    138 #else
    139 #define debug_print_blob(_name, _blob, _size) ((void)0)
    140 #define debug_print_format(_msg, _fmt) ((void)0)
    141 #endif
    142 
    143 
    144 /**
    145  * Disable interactive error message boxes.
    146  *
    147  * Should be called as soon as possible for effectiveness.
    148  */
    149 void
    150 debug_disable_error_message_boxes(void);
    151 
    152 
    153 /**
    154  * Hard-coded breakpoint.
    155  */
    156 #ifdef DEBUG
    157 #define debug_break() os_break()
    158 #else /* !DEBUG */
    159 #define debug_break() ((void)0)
    160 #endif /* !DEBUG */
    161 
    162 
    163 long
    164 debug_get_num_option(const char *name, long dfault);
    165 
    166 #ifdef _MSC_VER
    167 __declspec(noreturn)
    168 #endif
    169 void _debug_assert_fail(const char *expr,
    170                         const char *file,
    171                         unsigned line,
    172                         const char *function)
    173 #ifdef __GNUC__
    174    __attribute__((__noreturn__))
    175 #endif
    176 ;
    177 
    178 
    179 /**
    180  * Assert macro
    181  *
    182  * Do not expect that the assert call terminates -- errors must be handled
    183  * regardless of assert behavior.
    184  *
    185  * For non debug builds the assert macro will expand to a no-op, so do not
    186  * call functions with side effects in the assert expression.
    187  */
    188 #ifdef DEBUG
    189 #define debug_assert(expr) ((expr) ? (void)0 : _debug_assert_fail(#expr, __FILE__, __LINE__, __FUNCTION__))
    190 #else
    191 #define debug_assert(expr) (void)(0 && (expr))
    192 #endif
    193 
    194 
    195 /** Override standard assert macro */
    196 #ifdef assert
    197 #undef assert
    198 #endif
    199 #define assert(expr) debug_assert(expr)
    200 
    201 
    202 /**
    203  * Output the current function name.
    204  */
    205 #ifdef DEBUG
    206 #define debug_checkpoint() \
    207    _debug_printf("%s\n", __FUNCTION__)
    208 #else
    209 #define debug_checkpoint() \
    210    ((void)0)
    211 #endif
    212 
    213 
    214 /**
    215  * Output the full source code position.
    216  */
    217 #ifdef DEBUG
    218 #define debug_checkpoint_full() \
    219    _debug_printf("%s:%u:%s\n", __FILE__, __LINE__, __FUNCTION__)
    220 #else
    221 #define debug_checkpoint_full() \
    222    ((void)0)
    223 #endif
    224 
    225 
    226 /**
    227  * Output a warning message. Muted on release version.
    228  */
    229 #ifdef DEBUG
    230 #define debug_warning(__msg) \
    231    _debug_printf("%s:%u:%s: warning: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg)
    232 #else
    233 #define debug_warning(__msg) \
    234    ((void)0)
    235 #endif
    236 
    237 
    238 /**
    239  * Emit a warning message, but only once.
    240  */
    241 #ifdef DEBUG
    242 #define debug_warn_once(__msg) \
    243    do { \
    244       static bool warned = FALSE; \
    245       if (!warned) { \
    246          _debug_printf("%s:%u:%s: one time warning: %s\n", \
    247                        __FILE__, __LINE__, __FUNCTION__, __msg); \
    248          warned = TRUE; \
    249       } \
    250    } while (0)
    251 #else
    252 #define debug_warn_once(__msg) \
    253    ((void)0)
    254 #endif
    255 
    256 
    257 /**
    258  * Output an error message. Not muted on release version.
    259  */
    260 #ifdef DEBUG
    261 #define debug_error(__msg) \
    262    _debug_printf("%s:%u:%s: error: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg)
    263 #else
    264 #define debug_error(__msg) \
    265    _debug_printf("error: %s\n", __msg)
    266 #endif
    267 
    268 /**
    269  * Output a debug log message to the debug info callback.
    270  */
    271 #define pipe_debug_message(cb, type, fmt, ...) do { \
    272    static unsigned id = 0; \
    273    if ((cb) && (cb)->debug_message) { \
    274       _pipe_debug_message(cb, &id, \
    275                           PIPE_DEBUG_TYPE_ ## type, \
    276                           fmt, ##__VA_ARGS__); \
    277    } \
    278 } while (0)
    279 
    280 struct pipe_debug_callback;
    281 
    282 void
    283 _pipe_debug_message(
    284    struct pipe_debug_callback *cb,
    285    unsigned *id,
    286    enum pipe_debug_type type,
    287    const char *fmt, ...) _util_printf_format(4, 5);
    288 
    289 
    290 /**
    291  * Used by debug_dump_enum and debug_dump_flags to describe symbols.
    292  */
    293 struct debug_named_value
    294 {
    295    const char *name;
    296    uint64_t value;
    297    const char *desc;
    298 };
    299 
    300 
    301 /**
    302  * Some C pre-processor magic to simplify creating named values.
    303  *
    304  * Example:
    305  * @code
    306  * static const debug_named_value my_names[] = {
    307  *    DEBUG_NAMED_VALUE(MY_ENUM_VALUE_X),
    308  *    DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Y),
    309  *    DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Z),
    310  *    DEBUG_NAMED_VALUE_END
    311  * };
    312  *
    313  *    ...
    314  *    debug_printf("%s = %s\n",
    315  *                 name,
    316  *                 debug_dump_enum(my_names, my_value));
    317  *    ...
    318  * @endcode
    319  */
    320 #define DEBUG_NAMED_VALUE(__symbol) {#__symbol, (unsigned long)__symbol, NULL}
    321 #define DEBUG_NAMED_VALUE_WITH_DESCRIPTION(__symbol, __desc) {#__symbol, (unsigned long)__symbol, __desc}
    322 #define DEBUG_NAMED_VALUE_END {NULL, 0, NULL}
    323 
    324 
    325 /**
    326  * Convert a enum value to a string.
    327  */
    328 const char *
    329 debug_dump_enum(const struct debug_named_value *names,
    330                 unsigned long value);
    331 
    332 const char *
    333 debug_dump_enum_noprefix(const struct debug_named_value *names,
    334                          const char *prefix,
    335                          unsigned long value);
    336 
    337 
    338 /**
    339  * Convert binary flags value to a string.
    340  */
    341 const char *
    342 debug_dump_flags(const struct debug_named_value *names,
    343                  unsigned long value);
    344 
    345 
    346 /**
    347  * Function enter exit loggers
    348  */
    349 #ifdef DEBUG
    350 int debug_funclog_enter(const char* f, const int line, const char* file);
    351 void debug_funclog_exit(const char* f, const int line, const char* file);
    352 void debug_funclog_enter_exit(const char* f, const int line, const char* file);
    353 
    354 #define DEBUG_FUNCLOG_ENTER() \
    355    int __debug_decleration_work_around = \
    356       debug_funclog_enter(__FUNCTION__, __LINE__, __FILE__)
    357 #define DEBUG_FUNCLOG_EXIT() \
    358    do { \
    359       (void)__debug_decleration_work_around; \
    360       debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \
    361       return; \
    362    } while(0)
    363 #define DEBUG_FUNCLOG_EXIT_RET(ret) \
    364    do { \
    365       (void)__debug_decleration_work_around; \
    366       debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \
    367       return ret; \
    368    } while(0)
    369 #define DEBUG_FUNCLOG_ENTER_EXIT() \
    370    debug_funclog_enter_exit(__FUNCTION__, __LINE__, __FILE__)
    371 
    372 #else
    373 #define DEBUG_FUNCLOG_ENTER() \
    374    int __debug_decleration_work_around
    375 #define DEBUG_FUNCLOG_EXIT() \
    376    do { (void)__debug_decleration_work_around; return; } while(0)
    377 #define DEBUG_FUNCLOG_EXIT_RET(ret) \
    378    do { (void)__debug_decleration_work_around; return ret; } while(0)
    379 #define DEBUG_FUNCLOG_ENTER_EXIT()
    380 #endif
    381 
    382 
    383 /**
    384  * Get option.
    385  *
    386  * It is an alias for getenv on Linux.
    387  *
    388  * On Windows it reads C:\gallium.cfg, which is a text file with CR+LF line
    389  * endings with one option per line as
    390  *
    391  *   NAME=value
    392  *
    393  * This file must be terminated with an extra empty line.
    394  */
    395 const char *
    396 debug_get_option(const char *name, const char *dfault);
    397 
    398 boolean
    399 debug_get_bool_option(const char *name, boolean dfault);
    400 
    401 long
    402 debug_get_num_option(const char *name, long dfault);
    403 
    404 uint64_t
    405 debug_get_flags_option(const char *name,
    406                        const struct debug_named_value *flags,
    407                        uint64_t dfault);
    408 
    409 #define DEBUG_GET_ONCE_OPTION(suffix, name, dfault) \
    410 static const char * \
    411 debug_get_option_ ## suffix (void) \
    412 { \
    413    static boolean first = TRUE; \
    414    static const char * value; \
    415    if (first) { \
    416       first = FALSE; \
    417       value = debug_get_option(name, dfault); \
    418    } \
    419    return value; \
    420 }
    421 
    422 #define DEBUG_GET_ONCE_BOOL_OPTION(sufix, name, dfault) \
    423 static boolean \
    424 debug_get_option_ ## sufix (void) \
    425 { \
    426    static boolean first = TRUE; \
    427    static boolean value; \
    428    if (first) { \
    429       first = FALSE; \
    430       value = debug_get_bool_option(name, dfault); \
    431    } \
    432    return value; \
    433 }
    434 
    435 #define DEBUG_GET_ONCE_NUM_OPTION(sufix, name, dfault) \
    436 static long \
    437 debug_get_option_ ## sufix (void) \
    438 { \
    439    static boolean first = TRUE; \
    440    static long value; \
    441    if (first) { \
    442       first = FALSE; \
    443       value = debug_get_num_option(name, dfault); \
    444    } \
    445    return value; \
    446 }
    447 
    448 #define DEBUG_GET_ONCE_FLAGS_OPTION(sufix, name, flags, dfault) \
    449 static unsigned long \
    450 debug_get_option_ ## sufix (void) \
    451 { \
    452    static boolean first = TRUE; \
    453    static unsigned long value; \
    454    if (first) { \
    455       first = FALSE; \
    456       value = debug_get_flags_option(name, flags, dfault); \
    457    } \
    458    return value; \
    459 }
    460 
    461 
    462 unsigned long
    463 debug_memory_begin(void);
    464 
    465 void
    466 debug_memory_end(unsigned long beginning);
    467 
    468 
    469 void
    470 debug_print_transfer_flags(const char *msg, unsigned usage);
    471 
    472 void
    473 debug_print_bind_flags(const char *msg, unsigned usage);
    474 
    475 void
    476 debug_print_usage_enum(const char *msg, enum pipe_resource_usage usage);
    477 
    478 
    479 #ifdef	__cplusplus
    480 }
    481 #endif
    482 
    483 #endif /* U_DEBUG_H_ */
    484