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