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