Home | History | Annotate | Download | only in util
      1 /**************************************************************************
      2  *
      3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      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 TUNGSTEN GRAPHICS 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 <jrfonseca (at) tungstengraphics.com>
     36  */
     37 
     38 #ifndef U_DEBUG_H_
     39 #define U_DEBUG_H_
     40 
     41 
     42 #include "os/os_misc.h"
     43 
     44 
     45 #ifdef	__cplusplus
     46 extern "C" {
     47 #endif
     48 
     49 
     50 #if defined(__GNUC__)
     51 #define _util_printf_format(fmt, list) __attribute__ ((format (printf, fmt, list)))
     52 #else
     53 #define _util_printf_format(fmt, list)
     54 #endif
     55 
     56 void _debug_vprintf(const char *format, va_list ap);
     57 
     58 
     59 static INLINE void
     60 _debug_printf(const char *format, ...)
     61 {
     62    va_list ap;
     63    va_start(ap, format);
     64    _debug_vprintf(format, ap);
     65    va_end(ap);
     66 }
     67 
     68 
     69 /**
     70  * Print debug messages.
     71  *
     72  * The actual channel used to output debug message is platform specific. To
     73  * avoid misformating or truncation, follow these rules of thumb:
     74  * - output whole lines
     75  * - avoid outputing large strings (512 bytes is the current maximum length
     76  * that is guaranteed to be printed in all platforms)
     77  */
     78 #if !defined(PIPE_OS_HAIKU)
     79 static INLINE void
     80 debug_printf(const char *format, ...) _util_printf_format(1,2);
     81 
     82 static INLINE void
     83 debug_printf(const char *format, ...)
     84 {
     85 #ifdef DEBUG
     86    va_list ap;
     87    va_start(ap, format);
     88    _debug_vprintf(format, ap);
     89    va_end(ap);
     90 #else
     91    (void) format; /* silence warning */
     92 #endif
     93 }
     94 #else /* is Haiku */
     95 /* Haiku provides debug_printf in libroot with OS.h */
     96 #include <OS.h>
     97 #endif
     98 
     99 
    100 /*
    101  * ... isn't portable so we need to pass arguments in parentheses.
    102  *
    103  * usage:
    104  *    debug_printf_once(("answer: %i\n", 42));
    105  */
    106 #define debug_printf_once(args) \
    107    do { \
    108       static boolean once = TRUE; \
    109       if (once) { \
    110          once = FALSE; \
    111          debug_printf args; \
    112       } \
    113    } while (0)
    114 
    115 
    116 #ifdef DEBUG
    117 #define debug_vprintf(_format, _ap) _debug_vprintf(_format, _ap)
    118 #else
    119 #define debug_vprintf(_format, _ap) ((void)0)
    120 #endif
    121 
    122 
    123 #ifdef DEBUG
    124 /**
    125  * Dump a blob in hex to the same place that debug_printf sends its
    126  * messages.
    127  */
    128 void debug_print_blob( const char *name, const void *blob, unsigned size );
    129 
    130 /* Print a message along with a prettified format string
    131  */
    132 void debug_print_format(const char *msg, unsigned fmt );
    133 #else
    134 #define debug_print_blob(_name, _blob, _size) ((void)0)
    135 #define debug_print_format(_msg, _fmt) ((void)0)
    136 #endif
    137 
    138 
    139 /**
    140  * Hard-coded breakpoint.
    141  */
    142 #ifdef DEBUG
    143 #define debug_break() os_break()
    144 #else /* !DEBUG */
    145 #define debug_break() ((void)0)
    146 #endif /* !DEBUG */
    147 
    148 
    149 long
    150 debug_get_num_option(const char *name, long dfault);
    151 
    152 void _debug_assert_fail(const char *expr,
    153                         const char *file,
    154                         unsigned line,
    155                         const char *function);
    156 
    157 
    158 /**
    159  * Assert macro
    160  *
    161  * Do not expect that the assert call terminates -- errors must be handled
    162  * regardless of assert behavior.
    163  *
    164  * For non debug builds the assert macro will expand to a no-op, so do not
    165  * call functions with side effects in the assert expression.
    166  */
    167 #ifdef DEBUG
    168 #define debug_assert(expr) ((expr) ? (void)0 : _debug_assert_fail(#expr, __FILE__, __LINE__, __FUNCTION__))
    169 #else
    170 #define debug_assert(expr) do { } while (0 && (expr))
    171 #endif
    172 
    173 
    174 /** Override standard assert macro */
    175 #ifdef assert
    176 #undef assert
    177 #endif
    178 #define assert(expr) debug_assert(expr)
    179 
    180 
    181 /**
    182  * Output the current function name.
    183  */
    184 #ifdef DEBUG
    185 #define debug_checkpoint() \
    186    _debug_printf("%s\n", __FUNCTION__)
    187 #else
    188 #define debug_checkpoint() \
    189    ((void)0)
    190 #endif
    191 
    192 
    193 /**
    194  * Output the full source code position.
    195  */
    196 #ifdef DEBUG
    197 #define debug_checkpoint_full() \
    198    _debug_printf("%s:%u:%s\n", __FILE__, __LINE__, __FUNCTION__)
    199 #else
    200 #define debug_checkpoint_full() \
    201    ((void)0)
    202 #endif
    203 
    204 
    205 /**
    206  * Output a warning message. Muted on release version.
    207  */
    208 #ifdef DEBUG
    209 #define debug_warning(__msg) \
    210    _debug_printf("%s:%u:%s: warning: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg)
    211 #else
    212 #define debug_warning(__msg) \
    213    ((void)0)
    214 #endif
    215 
    216 
    217 /**
    218  * Emit a warning message, but only once.
    219  */
    220 #ifdef DEBUG
    221 #define debug_warn_once(__msg) \
    222    do { \
    223       static bool warned = FALSE; \
    224       if (!warned) { \
    225          _debug_printf("%s:%u:%s: one time warning: %s\n", \
    226                        __FILE__, __LINE__, __FUNCTION__, __msg); \
    227          warned = TRUE; \
    228       } \
    229    } while (0)
    230 #else
    231 #define debug_warn_once(__msg) \
    232    ((void)0)
    233 #endif
    234 
    235 
    236 /**
    237  * Output an error message. Not muted on release version.
    238  */
    239 #ifdef DEBUG
    240 #define debug_error(__msg) \
    241    _debug_printf("%s:%u:%s: error: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg)
    242 #else
    243 #define debug_error(__msg) \
    244    _debug_printf("error: %s\n", __msg)
    245 #endif
    246 
    247 
    248 /**
    249  * Used by debug_dump_enum and debug_dump_flags to describe symbols.
    250  */
    251 struct debug_named_value
    252 {
    253    const char *name;
    254    unsigned long value;
    255    const char *desc;
    256 };
    257 
    258 
    259 /**
    260  * Some C pre-processor magic to simplify creating named values.
    261  *
    262  * Example:
    263  * @code
    264  * static const debug_named_value my_names[] = {
    265  *    DEBUG_NAMED_VALUE(MY_ENUM_VALUE_X),
    266  *    DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Y),
    267  *    DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Z),
    268  *    DEBUG_NAMED_VALUE_END
    269  * };
    270  *
    271  *    ...
    272  *    debug_printf("%s = %s\n",
    273  *                 name,
    274  *                 debug_dump_enum(my_names, my_value));
    275  *    ...
    276  * @endcode
    277  */
    278 #define DEBUG_NAMED_VALUE(__symbol) DEBUG_NAMED_VALUE_WITH_DESCRIPTION(__symbol, NULL)
    279 #define DEBUG_NAMED_VALUE_WITH_DESCRIPTION(__symbol, __desc) {#__symbol, (unsigned long)__symbol, __desc}
    280 #define DEBUG_NAMED_VALUE_END {NULL, 0, NULL}
    281 
    282 
    283 /**
    284  * Convert a enum value to a string.
    285  */
    286 const char *
    287 debug_dump_enum(const struct debug_named_value *names,
    288                 unsigned long value);
    289 
    290 const char *
    291 debug_dump_enum_noprefix(const struct debug_named_value *names,
    292                          const char *prefix,
    293                          unsigned long value);
    294 
    295 
    296 /**
    297  * Convert binary flags value to a string.
    298  */
    299 const char *
    300 debug_dump_flags(const struct debug_named_value *names,
    301                  unsigned long value);
    302 
    303 
    304 /**
    305  * Function enter exit loggers
    306  */
    307 #ifdef DEBUG
    308 int debug_funclog_enter(const char* f, const int line, const char* file);
    309 void debug_funclog_exit(const char* f, const int line, const char* file);
    310 void debug_funclog_enter_exit(const char* f, const int line, const char* file);
    311 
    312 #define DEBUG_FUNCLOG_ENTER() \
    313    int __debug_decleration_work_around = \
    314       debug_funclog_enter(__FUNCTION__, __LINE__, __FILE__)
    315 #define DEBUG_FUNCLOG_EXIT() \
    316    do { \
    317       (void)__debug_decleration_work_around; \
    318       debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \
    319       return; \
    320    } while(0)
    321 #define DEBUG_FUNCLOG_EXIT_RET(ret) \
    322    do { \
    323       (void)__debug_decleration_work_around; \
    324       debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \
    325       return ret; \
    326    } while(0)
    327 #define DEBUG_FUNCLOG_ENTER_EXIT() \
    328    debug_funclog_enter_exit(__FUNCTION__, __LINE__, __FILE__)
    329 
    330 #else
    331 #define DEBUG_FUNCLOG_ENTER() \
    332    int __debug_decleration_work_around
    333 #define DEBUG_FUNCLOG_EXIT() \
    334    do { (void)__debug_decleration_work_around; return; } while(0)
    335 #define DEBUG_FUNCLOG_EXIT_RET(ret) \
    336    do { (void)__debug_decleration_work_around; return ret; } while(0)
    337 #define DEBUG_FUNCLOG_ENTER_EXIT()
    338 #endif
    339 
    340 
    341 /**
    342  * Get option.
    343  *
    344  * It is an alias for getenv on Linux.
    345  *
    346  * On Windows it reads C:\gallium.cfg, which is a text file with CR+LF line
    347  * endings with one option per line as
    348  *
    349  *   NAME=value
    350  *
    351  * This file must be terminated with an extra empty line.
    352  */
    353 const char *
    354 debug_get_option(const char *name, const char *dfault);
    355 
    356 boolean
    357 debug_get_bool_option(const char *name, boolean dfault);
    358 
    359 long
    360 debug_get_num_option(const char *name, long dfault);
    361 
    362 unsigned long
    363 debug_get_flags_option(const char *name,
    364                        const struct debug_named_value *flags,
    365                        unsigned long dfault);
    366 
    367 #define DEBUG_GET_ONCE_BOOL_OPTION(sufix, name, dfault) \
    368 static boolean \
    369 debug_get_option_ ## sufix (void) \
    370 { \
    371    static boolean first = TRUE; \
    372    static boolean value; \
    373    if (first) { \
    374       first = FALSE; \
    375       value = debug_get_bool_option(name, dfault); \
    376    } \
    377    return value; \
    378 }
    379 
    380 #define DEBUG_GET_ONCE_NUM_OPTION(sufix, name, dfault) \
    381 static long \
    382 debug_get_option_ ## sufix (void) \
    383 { \
    384    static boolean first = TRUE; \
    385    static long value; \
    386    if (first) { \
    387       first = FALSE; \
    388       value = debug_get_num_option(name, dfault); \
    389    } \
    390    return value; \
    391 }
    392 
    393 #define DEBUG_GET_ONCE_FLAGS_OPTION(sufix, name, flags, dfault) \
    394 static unsigned long \
    395 debug_get_option_ ## sufix (void) \
    396 { \
    397    static boolean first = TRUE; \
    398    static unsigned long value; \
    399    if (first) { \
    400       first = FALSE; \
    401       value = debug_get_flags_option(name, flags, dfault); \
    402    } \
    403    return value; \
    404 }
    405 
    406 
    407 unsigned long
    408 debug_memory_begin(void);
    409 
    410 void
    411 debug_memory_end(unsigned long beginning);
    412 
    413 
    414 #ifdef DEBUG
    415 struct pipe_context;
    416 struct pipe_surface;
    417 struct pipe_transfer;
    418 struct pipe_resource;
    419 
    420 void debug_dump_image(const char *prefix,
    421                       unsigned format, unsigned cpp,
    422                       unsigned width, unsigned height,
    423                       unsigned stride,
    424                       const void *data);
    425 void debug_dump_surface(struct pipe_context *pipe,
    426 			const char *prefix,
    427                         struct pipe_surface *surface);
    428 void debug_dump_texture(struct pipe_context *pipe,
    429 			const char *prefix,
    430                         struct pipe_resource *texture);
    431 void debug_dump_surface_bmp(struct pipe_context *pipe,
    432                             const char *filename,
    433                             struct pipe_surface *surface);
    434 void debug_dump_transfer_bmp(struct pipe_context *pipe,
    435                              const char *filename,
    436                              struct pipe_transfer *transfer);
    437 void debug_dump_float_rgba_bmp(const char *filename,
    438                                unsigned width, unsigned height,
    439                                float *rgba, unsigned stride);
    440 #else
    441 #define debug_dump_image(prefix, format, cpp, width, height, stride, data) ((void)0)
    442 #define debug_dump_surface(pipe, prefix, surface) ((void)0)
    443 #define debug_dump_surface_bmp(pipe, filename, surface) ((void)0)
    444 #define debug_dump_transfer_bmp(filename, transfer) ((void)0)
    445 #define debug_dump_float_rgba_bmp(filename, width, height, rgba, stride) ((void)0)
    446 #endif
    447 
    448 
    449 #ifdef	__cplusplus
    450 }
    451 #endif
    452 
    453 #endif /* U_DEBUG_H_ */
    454