u_debug.c revision 01e04c3f
1/************************************************************************** 2 * 3 * Copyright 2008 VMware, Inc. 4 * Copyright (c) 2008 VMware, Inc. 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28 29 30#include "pipe/p_config.h" 31 32#include "pipe/p_compiler.h" 33#include "util/u_debug.h" 34#include "pipe/p_format.h" 35#include "pipe/p_state.h" 36#include "util/u_string.h" 37#include "util/u_math.h" 38#include <inttypes.h> 39 40#include <stdio.h> 41#include <limits.h> /* CHAR_BIT */ 42#include <ctype.h> /* isalnum */ 43 44#ifdef _WIN32 45#include <windows.h> 46#include <stdlib.h> 47#endif 48 49 50void 51_debug_vprintf(const char *format, va_list ap) 52{ 53 static char buf[4096] = {'\0'}; 54#if defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_EMBEDDED) 55 /* We buffer until we find a newline. */ 56 size_t len = strlen(buf); 57 int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap); 58 if (ret > (int)(sizeof(buf) - len - 1) || util_strchr(buf + len, '\n')) { 59 os_log_message(buf); 60 buf[0] = '\0'; 61 } 62#else 63 util_vsnprintf(buf, sizeof(buf), format, ap); 64 os_log_message(buf); 65#endif 66} 67 68 69void 70_pipe_debug_message(struct pipe_debug_callback *cb, 71 unsigned *id, 72 enum pipe_debug_type type, 73 const char *fmt, ...) 74{ 75 va_list args; 76 va_start(args, fmt); 77 if (cb && cb->debug_message) 78 cb->debug_message(cb->data, id, type, fmt, args); 79 va_end(args); 80} 81 82 83void 84debug_disable_error_message_boxes(void) 85{ 86#ifdef _WIN32 87 /* When Windows' error message boxes are disabled for this process (as is 88 * typically the case when running tests in an automated fashion) we disable 89 * CRT message boxes too. 90 */ 91 UINT uMode = SetErrorMode(0); 92 SetErrorMode(uMode); 93 if (uMode & SEM_FAILCRITICALERRORS) { 94 /* Disable assertion failure message box. 95 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx 96 */ 97 _set_error_mode(_OUT_TO_STDERR); 98#ifdef _MSC_VER 99 /* Disable abort message box. 100 * http://msdn.microsoft.com/en-us/library/e631wekh.aspx 101 */ 102 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); 103#endif 104 } 105#endif /* _WIN32 */ 106} 107 108 109#ifdef DEBUG 110void 111debug_print_blob(const char *name, const void *blob, unsigned size) 112{ 113 const unsigned *ublob = (const unsigned *)blob; 114 unsigned i; 115 116 debug_printf("%s (%d dwords%s)\n", name, size/4, 117 size%4 ? "... plus a few bytes" : ""); 118 119 for (i = 0; i < size/4; i++) { 120 debug_printf("%d:\t%08x\n", i, ublob[i]); 121 } 122} 123#endif 124 125 126static boolean 127debug_get_option_should_print(void) 128{ 129 static boolean first = TRUE; 130 static boolean value = FALSE; 131 132 if (!first) 133 return value; 134 135 /* Oh hey this will call into this function, 136 * but its cool since we set first to false 137 */ 138 first = FALSE; 139 value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", FALSE); 140 /* XXX should we print this option? Currently it wont */ 141 return value; 142} 143 144 145const char * 146debug_get_option(const char *name, const char *dfault) 147{ 148 const char *result; 149 150 result = os_get_option(name); 151 if (!result) 152 result = dfault; 153 154 if (debug_get_option_should_print()) 155 debug_printf("%s: %s = %s\n", __FUNCTION__, name, 156 result ? result : "(null)"); 157 158 return result; 159} 160 161 162boolean 163debug_get_bool_option(const char *name, boolean dfault) 164{ 165 const char *str = os_get_option(name); 166 boolean result; 167 168 if (str == NULL) 169 result = dfault; 170 else if (!util_strcmp(str, "n")) 171 result = FALSE; 172 else if (!util_strcmp(str, "no")) 173 result = FALSE; 174 else if (!util_strcmp(str, "0")) 175 result = FALSE; 176 else if (!util_strcmp(str, "f")) 177 result = FALSE; 178 else if (!util_strcmp(str, "F")) 179 result = FALSE; 180 else if (!util_strcmp(str, "false")) 181 result = FALSE; 182 else if (!util_strcmp(str, "FALSE")) 183 result = FALSE; 184 else 185 result = TRUE; 186 187 if (debug_get_option_should_print()) 188 debug_printf("%s: %s = %s\n", __FUNCTION__, name, 189 result ? "TRUE" : "FALSE"); 190 191 return result; 192} 193 194 195long 196debug_get_num_option(const char *name, long dfault) 197{ 198 long result; 199 const char *str; 200 201 str = os_get_option(name); 202 if (!str) { 203 result = dfault; 204 } else { 205 char *endptr; 206 207 result = strtol(str, &endptr, 0); 208 if (str == endptr) { 209 /* Restore the default value when no digits were found. */ 210 result = dfault; 211 } 212 } 213 214 if (debug_get_option_should_print()) 215 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result); 216 217 return result; 218} 219 220 221static boolean 222str_has_option(const char *str, const char *name) 223{ 224 /* Empty string. */ 225 if (!*str) { 226 return FALSE; 227 } 228 229 /* OPTION=all */ 230 if (!util_strcmp(str, "all")) { 231 return TRUE; 232 } 233 234 /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */ 235 { 236 const char *start = str; 237 unsigned name_len = strlen(name); 238 239 /* 'start' is the beginning of the currently-parsed word, 240 * we increment 'str' each iteration. 241 * if we find either the end of string or a non-alphanumeric character, 242 * we compare 'start' up to 'str-1' with 'name'. */ 243 244 while (1) { 245 if (!*str || !(isalnum(*str) || *str == '_')) { 246 if (str-start == name_len && 247 !memcmp(start, name, name_len)) { 248 return TRUE; 249 } 250 251 if (!*str) { 252 return FALSE; 253 } 254 255 start = str+1; 256 } 257 258 str++; 259 } 260 } 261 262 return FALSE; 263} 264 265 266uint64_t 267debug_get_flags_option(const char *name, 268 const struct debug_named_value *flags, 269 uint64_t dfault) 270{ 271 uint64_t result; 272 const char *str; 273 const struct debug_named_value *orig = flags; 274 unsigned namealign = 0; 275 276 str = os_get_option(name); 277 if (!str) 278 result = dfault; 279 else if (!util_strcmp(str, "help")) { 280 result = dfault; 281 _debug_printf("%s: help for %s:\n", __FUNCTION__, name); 282 for (; flags->name; ++flags) 283 namealign = MAX2(namealign, strlen(flags->name)); 284 for (flags = orig; flags->name; ++flags) 285 _debug_printf("| %*s [0x%0*"PRIx64"]%s%s\n", namealign, flags->name, 286 (int)sizeof(uint64_t)*CHAR_BIT/4, flags->value, 287 flags->desc ? " " : "", flags->desc ? flags->desc : ""); 288 } 289 else { 290 result = 0; 291 while (flags->name) { 292 if (str_has_option(str, flags->name)) 293 result |= flags->value; 294 ++flags; 295 } 296 } 297 298 if (debug_get_option_should_print()) { 299 if (str) { 300 debug_printf("%s: %s = 0x%"PRIx64" (%s)\n", 301 __FUNCTION__, name, result, str); 302 } else { 303 debug_printf("%s: %s = 0x%"PRIx64"\n", __FUNCTION__, name, result); 304 } 305 } 306 307 return result; 308} 309 310 311void 312_debug_assert_fail(const char *expr, const char *file, unsigned line, 313 const char *function) 314{ 315 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", 316 file, line, function, expr); 317 os_abort(); 318} 319 320 321const char * 322debug_dump_enum(const struct debug_named_value *names, 323 unsigned long value) 324{ 325 static char rest[64]; 326 327 while (names->name) { 328 if (names->value == value) 329 return names->name; 330 ++names; 331 } 332 333 util_snprintf(rest, sizeof(rest), "0x%08lx", value); 334 return rest; 335} 336 337 338const char * 339debug_dump_enum_noprefix(const struct debug_named_value *names, 340 const char *prefix, 341 unsigned long value) 342{ 343 static char rest[64]; 344 345 while (names->name) { 346 if (names->value == value) { 347 const char *name = names->name; 348 while (*name == *prefix) { 349 name++; 350 prefix++; 351 } 352 return name; 353 } 354 ++names; 355 } 356 357 util_snprintf(rest, sizeof(rest), "0x%08lx", value); 358 return rest; 359} 360 361 362const char * 363debug_dump_flags(const struct debug_named_value *names, unsigned long value) 364{ 365 static char output[4096]; 366 static char rest[256]; 367 int first = 1; 368 369 output[0] = '\0'; 370 371 while (names->name) { 372 if ((names->value & value) == names->value) { 373 if (!first) 374 util_strncat(output, "|", sizeof(output) - strlen(output) - 1); 375 else 376 first = 0; 377 util_strncat(output, names->name, sizeof(output) - strlen(output) - 1); 378 output[sizeof(output) - 1] = '\0'; 379 value &= ~names->value; 380 } 381 ++names; 382 } 383 384 if (value) { 385 if (!first) 386 util_strncat(output, "|", sizeof(output) - strlen(output) - 1); 387 else 388 first = 0; 389 390 util_snprintf(rest, sizeof(rest), "0x%08lx", value); 391 util_strncat(output, rest, sizeof(output) - strlen(output) - 1); 392 output[sizeof(output) - 1] = '\0'; 393 } 394 395 if (first) 396 return "0"; 397 398 return output; 399} 400 401 402 403#ifdef DEBUG 404int fl_indent = 0; 405const char* fl_function[1024]; 406 407int 408debug_funclog_enter(const char* f, UNUSED const int line, 409 UNUSED const char* file) 410{ 411 int i; 412 413 for (i = 0; i < fl_indent; i++) 414 debug_printf(" "); 415 debug_printf("%s\n", f); 416 417 assert(fl_indent < 1023); 418 fl_function[fl_indent++] = f; 419 420 return 0; 421} 422 423void 424debug_funclog_exit(const char* f, UNUSED const int line, 425 UNUSED const char* file) 426{ 427 --fl_indent; 428 assert(fl_indent >= 0); 429 assert(fl_function[fl_indent] == f); 430} 431 432void 433debug_funclog_enter_exit(const char* f, UNUSED const int line, 434 UNUSED const char* file) 435{ 436 int i; 437 for (i = 0; i < fl_indent; i++) 438 debug_printf(" "); 439 debug_printf("%s\n", f); 440} 441#endif 442