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