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 "util/u_debug.h" 33#include "pipe/p_format.h" 34#include "pipe/p_state.h" 35#include "util/u_string.h" 36#include "util/u_math.h" 37#include <inttypes.h> 38 39#include <stdio.h> 40#include <limits.h> /* CHAR_BIT */ 41#include <ctype.h> /* isalnum */ 42 43#ifdef _WIN32 44#include <windows.h> 45#include <stdlib.h> 46#endif 47 48 49void 50_debug_vprintf(const char *format, va_list ap) 51{ 52 static char buf[4096] = {'\0'}; 53#if DETECT_OS_WINDOWS || defined(EMBEDDED_DEVICE) 54 /* We buffer until we find a newline. */ 55 size_t len = strlen(buf); 56 int ret = vsnprintf(buf + len, sizeof(buf) - len, format, ap); 57 if (ret > (int)(sizeof(buf) - len - 1) || strchr(buf + len, '\n')) { 58 os_log_message(buf); 59 buf[0] = '\0'; 60 } 61#else 62 vsnprintf(buf, sizeof(buf), format, ap); 63 os_log_message(buf); 64#endif 65} 66 67 68void 69_pipe_debug_message(struct pipe_debug_callback *cb, 70 unsigned *id, 71 enum pipe_debug_type type, 72 const char *fmt, ...) 73{ 74 va_list args; 75 va_start(args, fmt); 76 if (cb && cb->debug_message) 77 cb->debug_message(cb->data, id, type, fmt, args); 78 va_end(args); 79} 80 81 82void 83debug_disable_error_message_boxes(void) 84{ 85#ifdef _WIN32 86 /* When Windows' error message boxes are disabled for this process (as is 87 * typically the case when running tests in an automated fashion) we disable 88 * CRT message boxes too. 89 */ 90 UINT uMode = SetErrorMode(0); 91 SetErrorMode(uMode); 92 if (uMode & SEM_FAILCRITICALERRORS) { 93 /* Disable assertion failure message box. 94 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx 95 */ 96 _set_error_mode(_OUT_TO_STDERR); 97#ifdef _MSC_VER 98 /* Disable abort message box. 99 * http://msdn.microsoft.com/en-us/library/e631wekh.aspx 100 */ 101 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); 102#endif 103 } 104#endif /* _WIN32 */ 105} 106 107 108#ifdef DEBUG 109void 110debug_print_blob(const char *name, const void *blob, unsigned size) 111{ 112 const unsigned *ublob = (const unsigned *)blob; 113 unsigned i; 114 115 debug_printf("%s (%d dwords%s)\n", name, size/4, 116 size%4 ? "... plus a few bytes" : ""); 117 118 for (i = 0; i < size/4; i++) { 119 debug_printf("%d:\t%08x\n", i, ublob[i]); 120 } 121} 122#endif 123 124 125static bool 126debug_get_option_should_print(void) 127{ 128 static bool first = true; 129 static bool value = false; 130 131 if (!first) 132 return value; 133 134 /* Oh hey this will call into this function, 135 * but its cool since we set first to false 136 */ 137 first = false; 138 value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", false); 139 /* XXX should we print this option? Currently it wont */ 140 return value; 141} 142 143 144const char * 145debug_get_option(const char *name, const char *dfault) 146{ 147 const char *result; 148 149 result = os_get_option(name); 150 if (!result) 151 result = dfault; 152 153 if (debug_get_option_should_print()) 154 debug_printf("%s: %s = %s\n", __FUNCTION__, name, 155 result ? result : "(null)"); 156 157 return result; 158} 159 160 161bool 162debug_get_bool_option(const char *name, bool dfault) 163{ 164 const char *str = os_get_option(name); 165 bool result; 166 167 if (str == NULL) 168 result = dfault; 169 else if (!strcmp(str, "n")) 170 result = false; 171 else if (!strcmp(str, "no")) 172 result = false; 173 else if (!strcmp(str, "0")) 174 result = false; 175 else if (!strcmp(str, "f")) 176 result = false; 177 else if (!strcmp(str, "F")) 178 result = false; 179 else if (!strcmp(str, "false")) 180 result = false; 181 else if (!strcmp(str, "FALSE")) 182 result = false; 183 else 184 result = true; 185 186 if (debug_get_option_should_print()) 187 debug_printf("%s: %s = %s\n", __FUNCTION__, name, 188 result ? "TRUE" : "FALSE"); 189 190 return result; 191} 192 193 194long 195debug_get_num_option(const char *name, long dfault) 196{ 197 long result; 198 const char *str; 199 200 str = os_get_option(name); 201 if (!str) { 202 result = dfault; 203 } else { 204 char *endptr; 205 206 result = strtol(str, &endptr, 0); 207 if (str == endptr) { 208 /* Restore the default value when no digits were found. */ 209 result = dfault; 210 } 211 } 212 213 if (debug_get_option_should_print()) 214 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result); 215 216 return result; 217} 218 219void 220debug_get_version_option(const char *name, unsigned *major, unsigned *minor) 221{ 222 const char *str; 223 224 str = os_get_option(name); 225 if (str) { 226 unsigned v_maj, v_min; 227 int n; 228 229 n = sscanf(str, "%u.%u", &v_maj, &v_min); 230 if (n != 2) { 231 debug_printf("Illegal version specified for %s : %s\n", name, str); 232 return; 233 } 234 *major = v_maj; 235 *minor = v_min; 236 } 237 238 if (debug_get_option_should_print()) 239 debug_printf("%s: %s = %u.%u\n", __FUNCTION__, name, *major, *minor); 240 241 return; 242} 243 244static bool 245str_has_option(const char *str, const char *name) 246{ 247 /* Empty string. */ 248 if (!*str) { 249 return false; 250 } 251 252 /* OPTION=all */ 253 if (!strcmp(str, "all")) { 254 return true; 255 } 256 257 /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */ 258 { 259 const char *start = str; 260 unsigned name_len = strlen(name); 261 262 /* 'start' is the beginning of the currently-parsed word, 263 * we increment 'str' each iteration. 264 * if we find either the end of string or a non-alphanumeric character, 265 * we compare 'start' up to 'str-1' with 'name'. */ 266 267 while (1) { 268 if (!*str || !(isalnum(*str) || *str == '_')) { 269 if (str-start == name_len && 270 !memcmp(start, name, name_len)) { 271 return true; 272 } 273 274 if (!*str) { 275 return false; 276 } 277 278 start = str+1; 279 } 280 281 str++; 282 } 283 } 284 285 return false; 286} 287 288 289uint64_t 290debug_get_flags_option(const char *name, 291 const struct debug_named_value *flags, 292 uint64_t dfault) 293{ 294 uint64_t result; 295 const char *str; 296 const struct debug_named_value *orig = flags; 297 unsigned namealign = 0; 298 299 str = os_get_option(name); 300 if (!str) 301 result = dfault; 302 else if (!strcmp(str, "help")) { 303 result = dfault; 304 _debug_printf("%s: help for %s:\n", __FUNCTION__, name); 305 for (; flags->name; ++flags) 306 namealign = MAX2(namealign, strlen(flags->name)); 307 for (flags = orig; flags->name; ++flags) 308 _debug_printf("| %*s [0x%0*"PRIx64"]%s%s\n", namealign, flags->name, 309 (int)sizeof(uint64_t)*CHAR_BIT/4, flags->value, 310 flags->desc ? " " : "", flags->desc ? flags->desc : ""); 311 } 312 else { 313 result = 0; 314 while (flags->name) { 315 if (str_has_option(str, flags->name)) 316 result |= flags->value; 317 ++flags; 318 } 319 } 320 321 if (debug_get_option_should_print()) { 322 if (str) { 323 debug_printf("%s: %s = 0x%"PRIx64" (%s)\n", 324 __FUNCTION__, name, result, str); 325 } else { 326 debug_printf("%s: %s = 0x%"PRIx64"\n", __FUNCTION__, name, result); 327 } 328 } 329 330 return result; 331} 332 333 334void 335_debug_assert_fail(const char *expr, const char *file, unsigned line, 336 const char *function) 337{ 338 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n", 339 file, line, function, expr); 340 os_abort(); 341} 342 343 344const char * 345debug_dump_enum(const struct debug_named_value *names, 346 unsigned long value) 347{ 348 static char rest[64]; 349 350 while (names->name) { 351 if (names->value == value) 352 return names->name; 353 ++names; 354 } 355 356 snprintf(rest, sizeof(rest), "0x%08lx", value); 357 return rest; 358} 359 360 361const char * 362debug_dump_enum_noprefix(const struct debug_named_value *names, 363 const char *prefix, 364 unsigned long value) 365{ 366 static char rest[64]; 367 368 while (names->name) { 369 if (names->value == value) { 370 const char *name = names->name; 371 while (*name == *prefix) { 372 name++; 373 prefix++; 374 } 375 return name; 376 } 377 ++names; 378 } 379 380 snprintf(rest, sizeof(rest), "0x%08lx", value); 381 return rest; 382} 383 384 385const char * 386debug_dump_flags(const struct debug_named_value *names, unsigned long value) 387{ 388 static char output[4096]; 389 static char rest[256]; 390 int first = 1; 391 392 output[0] = '\0'; 393 394 while (names->name) { 395 if ((names->value & value) == names->value) { 396 if (!first) 397 strncat(output, "|", sizeof(output) - strlen(output) - 1); 398 else 399 first = 0; 400 strncat(output, names->name, sizeof(output) - strlen(output) - 1); 401 output[sizeof(output) - 1] = '\0'; 402 value &= ~names->value; 403 } 404 ++names; 405 } 406 407 if (value) { 408 if (!first) 409 strncat(output, "|", sizeof(output) - strlen(output) - 1); 410 else 411 first = 0; 412 413 snprintf(rest, sizeof(rest), "0x%08lx", value); 414 strncat(output, rest, sizeof(output) - strlen(output) - 1); 415 output[sizeof(output) - 1] = '\0'; 416 } 417 418 if (first) 419 return "0"; 420 421 return output; 422} 423 424 425 426#ifdef DEBUG 427int fl_indent = 0; 428const char* fl_function[1024]; 429 430int 431debug_funclog_enter(const char* f, UNUSED const int line, 432 UNUSED const char* file) 433{ 434 int i; 435 436 for (i = 0; i < fl_indent; i++) 437 debug_printf(" "); 438 debug_printf("%s\n", f); 439 440 assert(fl_indent < 1023); 441 fl_function[fl_indent++] = f; 442 443 return 0; 444} 445 446void 447debug_funclog_exit(const char* f, UNUSED const int line, 448 UNUSED const char* file) 449{ 450 --fl_indent; 451 assert(fl_indent >= 0); 452 assert(fl_function[fl_indent] == f); 453} 454 455void 456debug_funclog_enter_exit(const char* f, UNUSED const int line, 457 UNUSED const char* file) 458{ 459 int i; 460 for (i = 0; i < fl_indent; i++) 461 debug_printf(" "); 462 debug_printf("%s\n", f); 463} 464#endif 465