u_debug.c revision 7ec681f3
101e04c3fSmrg/**************************************************************************
201e04c3fSmrg *
301e04c3fSmrg * Copyright 2008 VMware, Inc.
401e04c3fSmrg * Copyright (c) 2008 VMware, Inc.
501e04c3fSmrg * All Rights Reserved.
601e04c3fSmrg *
701e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
801e04c3fSmrg * copy of this software and associated documentation files (the
901e04c3fSmrg * "Software"), to deal in the Software without restriction, including
1001e04c3fSmrg * without limitation the rights to use, copy, modify, merge, publish,
1101e04c3fSmrg * distribute, sub license, and/or sell copies of the Software, and to
1201e04c3fSmrg * permit persons to whom the Software is furnished to do so, subject to
1301e04c3fSmrg * the following conditions:
1401e04c3fSmrg *
1501e04c3fSmrg * The above copyright notice and this permission notice (including the
1601e04c3fSmrg * next paragraph) shall be included in all copies or substantial portions
1701e04c3fSmrg * of the Software.
1801e04c3fSmrg *
1901e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2001e04c3fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2101e04c3fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
2201e04c3fSmrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
2301e04c3fSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2401e04c3fSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2501e04c3fSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2601e04c3fSmrg *
2701e04c3fSmrg **************************************************************************/
2801e04c3fSmrg
2901e04c3fSmrg
3001e04c3fSmrg#include "pipe/p_config.h"
3101e04c3fSmrg
3201e04c3fSmrg#include "util/u_debug.h"
3301e04c3fSmrg#include "pipe/p_format.h"
3401e04c3fSmrg#include "pipe/p_state.h"
3501e04c3fSmrg#include "util/u_string.h"
3601e04c3fSmrg#include "util/u_math.h"
3701e04c3fSmrg#include <inttypes.h>
3801e04c3fSmrg
3901e04c3fSmrg#include <stdio.h>
4001e04c3fSmrg#include <limits.h> /* CHAR_BIT */
4101e04c3fSmrg#include <ctype.h> /* isalnum */
4201e04c3fSmrg
4301e04c3fSmrg#ifdef _WIN32
4401e04c3fSmrg#include <windows.h>
4501e04c3fSmrg#include <stdlib.h>
4601e04c3fSmrg#endif
4701e04c3fSmrg
4801e04c3fSmrg
4901e04c3fSmrgvoid
5001e04c3fSmrg_debug_vprintf(const char *format, va_list ap)
5101e04c3fSmrg{
5201e04c3fSmrg   static char buf[4096] = {'\0'};
537ec681f3Smrg#if DETECT_OS_WINDOWS || defined(EMBEDDED_DEVICE)
5401e04c3fSmrg   /* We buffer until we find a newline. */
5501e04c3fSmrg   size_t len = strlen(buf);
567ec681f3Smrg   int ret = vsnprintf(buf + len, sizeof(buf) - len, format, ap);
577ec681f3Smrg   if (ret > (int)(sizeof(buf) - len - 1) || strchr(buf + len, '\n')) {
5801e04c3fSmrg      os_log_message(buf);
5901e04c3fSmrg      buf[0] = '\0';
6001e04c3fSmrg   }
6101e04c3fSmrg#else
627ec681f3Smrg   vsnprintf(buf, sizeof(buf), format, ap);
6301e04c3fSmrg   os_log_message(buf);
6401e04c3fSmrg#endif
6501e04c3fSmrg}
6601e04c3fSmrg
6701e04c3fSmrg
6801e04c3fSmrgvoid
6901e04c3fSmrg_pipe_debug_message(struct pipe_debug_callback *cb,
7001e04c3fSmrg                    unsigned *id,
7101e04c3fSmrg                    enum pipe_debug_type type,
7201e04c3fSmrg                    const char *fmt, ...)
7301e04c3fSmrg{
7401e04c3fSmrg   va_list args;
7501e04c3fSmrg   va_start(args, fmt);
7601e04c3fSmrg   if (cb && cb->debug_message)
7701e04c3fSmrg      cb->debug_message(cb->data, id, type, fmt, args);
7801e04c3fSmrg   va_end(args);
7901e04c3fSmrg}
8001e04c3fSmrg
8101e04c3fSmrg
8201e04c3fSmrgvoid
8301e04c3fSmrgdebug_disable_error_message_boxes(void)
8401e04c3fSmrg{
8501e04c3fSmrg#ifdef _WIN32
8601e04c3fSmrg   /* When Windows' error message boxes are disabled for this process (as is
8701e04c3fSmrg    * typically the case when running tests in an automated fashion) we disable
8801e04c3fSmrg    * CRT message boxes too.
8901e04c3fSmrg    */
9001e04c3fSmrg   UINT uMode = SetErrorMode(0);
9101e04c3fSmrg   SetErrorMode(uMode);
9201e04c3fSmrg   if (uMode & SEM_FAILCRITICALERRORS) {
9301e04c3fSmrg      /* Disable assertion failure message box.
9401e04c3fSmrg       * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
9501e04c3fSmrg       */
9601e04c3fSmrg      _set_error_mode(_OUT_TO_STDERR);
9701e04c3fSmrg#ifdef _MSC_VER
9801e04c3fSmrg      /* Disable abort message box.
9901e04c3fSmrg       * http://msdn.microsoft.com/en-us/library/e631wekh.aspx
10001e04c3fSmrg       */
10101e04c3fSmrg      _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
10201e04c3fSmrg#endif
10301e04c3fSmrg   }
10401e04c3fSmrg#endif /* _WIN32 */
10501e04c3fSmrg}
10601e04c3fSmrg
10701e04c3fSmrg
10801e04c3fSmrg#ifdef DEBUG
10901e04c3fSmrgvoid
11001e04c3fSmrgdebug_print_blob(const char *name, const void *blob, unsigned size)
11101e04c3fSmrg{
11201e04c3fSmrg   const unsigned *ublob = (const unsigned *)blob;
11301e04c3fSmrg   unsigned i;
11401e04c3fSmrg
11501e04c3fSmrg   debug_printf("%s (%d dwords%s)\n", name, size/4,
11601e04c3fSmrg                size%4 ? "... plus a few bytes" : "");
11701e04c3fSmrg
11801e04c3fSmrg   for (i = 0; i < size/4; i++) {
11901e04c3fSmrg      debug_printf("%d:\t%08x\n", i, ublob[i]);
12001e04c3fSmrg   }
12101e04c3fSmrg}
12201e04c3fSmrg#endif
12301e04c3fSmrg
12401e04c3fSmrg
1257ec681f3Smrgstatic bool
12601e04c3fSmrgdebug_get_option_should_print(void)
12701e04c3fSmrg{
1287ec681f3Smrg   static bool first = true;
1297ec681f3Smrg   static bool value = false;
13001e04c3fSmrg
13101e04c3fSmrg   if (!first)
13201e04c3fSmrg      return value;
13301e04c3fSmrg
13401e04c3fSmrg   /* Oh hey this will call into this function,
13501e04c3fSmrg    * but its cool since we set first to false
13601e04c3fSmrg    */
1377ec681f3Smrg   first = false;
1387ec681f3Smrg   value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", false);
13901e04c3fSmrg   /* XXX should we print this option? Currently it wont */
14001e04c3fSmrg   return value;
14101e04c3fSmrg}
14201e04c3fSmrg
14301e04c3fSmrg
14401e04c3fSmrgconst char *
14501e04c3fSmrgdebug_get_option(const char *name, const char *dfault)
14601e04c3fSmrg{
14701e04c3fSmrg   const char *result;
14801e04c3fSmrg
14901e04c3fSmrg   result = os_get_option(name);
15001e04c3fSmrg   if (!result)
15101e04c3fSmrg      result = dfault;
15201e04c3fSmrg
15301e04c3fSmrg   if (debug_get_option_should_print())
15401e04c3fSmrg      debug_printf("%s: %s = %s\n", __FUNCTION__, name,
15501e04c3fSmrg                   result ? result : "(null)");
15601e04c3fSmrg
15701e04c3fSmrg   return result;
15801e04c3fSmrg}
15901e04c3fSmrg
16001e04c3fSmrg
1617ec681f3Smrgbool
1627ec681f3Smrgdebug_get_bool_option(const char *name, bool dfault)
16301e04c3fSmrg{
16401e04c3fSmrg   const char *str = os_get_option(name);
1657ec681f3Smrg   bool result;
16601e04c3fSmrg
16701e04c3fSmrg   if (str == NULL)
16801e04c3fSmrg      result = dfault;
1697ec681f3Smrg   else if (!strcmp(str, "n"))
1707ec681f3Smrg      result = false;
1717ec681f3Smrg   else if (!strcmp(str, "no"))
1727ec681f3Smrg      result = false;
1737ec681f3Smrg   else if (!strcmp(str, "0"))
1747ec681f3Smrg      result = false;
1757ec681f3Smrg   else if (!strcmp(str, "f"))
1767ec681f3Smrg      result = false;
1777ec681f3Smrg   else if (!strcmp(str, "F"))
1787ec681f3Smrg      result = false;
1797ec681f3Smrg   else if (!strcmp(str, "false"))
1807ec681f3Smrg      result = false;
1817ec681f3Smrg   else if (!strcmp(str, "FALSE"))
1827ec681f3Smrg      result = false;
18301e04c3fSmrg   else
1847ec681f3Smrg      result = true;
18501e04c3fSmrg
18601e04c3fSmrg   if (debug_get_option_should_print())
18701e04c3fSmrg      debug_printf("%s: %s = %s\n", __FUNCTION__, name,
18801e04c3fSmrg                   result ? "TRUE" : "FALSE");
18901e04c3fSmrg
19001e04c3fSmrg   return result;
19101e04c3fSmrg}
19201e04c3fSmrg
19301e04c3fSmrg
19401e04c3fSmrglong
19501e04c3fSmrgdebug_get_num_option(const char *name, long dfault)
19601e04c3fSmrg{
19701e04c3fSmrg   long result;
19801e04c3fSmrg   const char *str;
19901e04c3fSmrg
20001e04c3fSmrg   str = os_get_option(name);
20101e04c3fSmrg   if (!str) {
20201e04c3fSmrg      result = dfault;
20301e04c3fSmrg   } else {
20401e04c3fSmrg      char *endptr;
20501e04c3fSmrg
20601e04c3fSmrg      result = strtol(str, &endptr, 0);
20701e04c3fSmrg      if (str == endptr) {
20801e04c3fSmrg         /* Restore the default value when no digits were found. */
20901e04c3fSmrg         result = dfault;
21001e04c3fSmrg      }
21101e04c3fSmrg   }
21201e04c3fSmrg
21301e04c3fSmrg   if (debug_get_option_should_print())
21401e04c3fSmrg      debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
21501e04c3fSmrg
21601e04c3fSmrg   return result;
21701e04c3fSmrg}
21801e04c3fSmrg
2197ec681f3Smrgvoid
2207ec681f3Smrgdebug_get_version_option(const char *name, unsigned *major, unsigned *minor)
2217ec681f3Smrg{
2227ec681f3Smrg   const char *str;
2237ec681f3Smrg
2247ec681f3Smrg   str = os_get_option(name);
2257ec681f3Smrg   if (str) {
2267ec681f3Smrg      unsigned v_maj, v_min;
2277ec681f3Smrg      int n;
2287ec681f3Smrg
2297ec681f3Smrg      n = sscanf(str, "%u.%u", &v_maj, &v_min);
2307ec681f3Smrg      if (n != 2) {
2317ec681f3Smrg         debug_printf("Illegal version specified for %s : %s\n", name, str);
2327ec681f3Smrg         return;
2337ec681f3Smrg      }
2347ec681f3Smrg      *major = v_maj;
2357ec681f3Smrg      *minor = v_min;
2367ec681f3Smrg   }
2377ec681f3Smrg
2387ec681f3Smrg   if (debug_get_option_should_print())
2397ec681f3Smrg      debug_printf("%s: %s = %u.%u\n", __FUNCTION__, name, *major, *minor);
2407ec681f3Smrg
2417ec681f3Smrg   return;
2427ec681f3Smrg}
24301e04c3fSmrg
2447ec681f3Smrgstatic bool
24501e04c3fSmrgstr_has_option(const char *str, const char *name)
24601e04c3fSmrg{
24701e04c3fSmrg   /* Empty string. */
24801e04c3fSmrg   if (!*str) {
2497ec681f3Smrg      return false;
25001e04c3fSmrg   }
25101e04c3fSmrg
25201e04c3fSmrg   /* OPTION=all */
2537ec681f3Smrg   if (!strcmp(str, "all")) {
2547ec681f3Smrg      return true;
25501e04c3fSmrg   }
25601e04c3fSmrg
25701e04c3fSmrg   /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
25801e04c3fSmrg   {
25901e04c3fSmrg      const char *start = str;
26001e04c3fSmrg      unsigned name_len = strlen(name);
26101e04c3fSmrg
26201e04c3fSmrg      /* 'start' is the beginning of the currently-parsed word,
26301e04c3fSmrg       * we increment 'str' each iteration.
26401e04c3fSmrg       * if we find either the end of string or a non-alphanumeric character,
26501e04c3fSmrg       * we compare 'start' up to 'str-1' with 'name'. */
26601e04c3fSmrg
26701e04c3fSmrg      while (1) {
26801e04c3fSmrg         if (!*str || !(isalnum(*str) || *str == '_')) {
26901e04c3fSmrg            if (str-start == name_len &&
27001e04c3fSmrg                !memcmp(start, name, name_len)) {
2717ec681f3Smrg               return true;
27201e04c3fSmrg            }
27301e04c3fSmrg
27401e04c3fSmrg            if (!*str) {
2757ec681f3Smrg               return false;
27601e04c3fSmrg            }
27701e04c3fSmrg
27801e04c3fSmrg            start = str+1;
27901e04c3fSmrg         }
28001e04c3fSmrg
28101e04c3fSmrg         str++;
28201e04c3fSmrg      }
28301e04c3fSmrg   }
28401e04c3fSmrg
2857ec681f3Smrg   return false;
28601e04c3fSmrg}
28701e04c3fSmrg
28801e04c3fSmrg
28901e04c3fSmrguint64_t
29001e04c3fSmrgdebug_get_flags_option(const char *name,
29101e04c3fSmrg                       const struct debug_named_value *flags,
29201e04c3fSmrg                       uint64_t dfault)
29301e04c3fSmrg{
29401e04c3fSmrg   uint64_t result;
29501e04c3fSmrg   const char *str;
29601e04c3fSmrg   const struct debug_named_value *orig = flags;
29701e04c3fSmrg   unsigned namealign = 0;
29801e04c3fSmrg
29901e04c3fSmrg   str = os_get_option(name);
30001e04c3fSmrg   if (!str)
30101e04c3fSmrg      result = dfault;
3027ec681f3Smrg   else if (!strcmp(str, "help")) {
30301e04c3fSmrg      result = dfault;
30401e04c3fSmrg      _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
30501e04c3fSmrg      for (; flags->name; ++flags)
30601e04c3fSmrg         namealign = MAX2(namealign, strlen(flags->name));
30701e04c3fSmrg      for (flags = orig; flags->name; ++flags)
30801e04c3fSmrg         _debug_printf("| %*s [0x%0*"PRIx64"]%s%s\n", namealign, flags->name,
30901e04c3fSmrg                      (int)sizeof(uint64_t)*CHAR_BIT/4, flags->value,
31001e04c3fSmrg                      flags->desc ? " " : "", flags->desc ? flags->desc : "");
31101e04c3fSmrg   }
31201e04c3fSmrg   else {
31301e04c3fSmrg      result = 0;
31401e04c3fSmrg      while (flags->name) {
31501e04c3fSmrg	 if (str_has_option(str, flags->name))
31601e04c3fSmrg	    result |= flags->value;
31701e04c3fSmrg	 ++flags;
31801e04c3fSmrg      }
31901e04c3fSmrg   }
32001e04c3fSmrg
32101e04c3fSmrg   if (debug_get_option_should_print()) {
32201e04c3fSmrg      if (str) {
32301e04c3fSmrg         debug_printf("%s: %s = 0x%"PRIx64" (%s)\n",
32401e04c3fSmrg                      __FUNCTION__, name, result, str);
32501e04c3fSmrg      } else {
32601e04c3fSmrg         debug_printf("%s: %s = 0x%"PRIx64"\n", __FUNCTION__, name, result);
32701e04c3fSmrg      }
32801e04c3fSmrg   }
32901e04c3fSmrg
33001e04c3fSmrg   return result;
33101e04c3fSmrg}
33201e04c3fSmrg
33301e04c3fSmrg
33401e04c3fSmrgvoid
33501e04c3fSmrg_debug_assert_fail(const char *expr, const char *file, unsigned line,
33601e04c3fSmrg                   const char *function)
33701e04c3fSmrg{
33801e04c3fSmrg   _debug_printf("%s:%u:%s: Assertion `%s' failed.\n",
33901e04c3fSmrg                 file, line, function, expr);
34001e04c3fSmrg   os_abort();
34101e04c3fSmrg}
34201e04c3fSmrg
34301e04c3fSmrg
34401e04c3fSmrgconst char *
34501e04c3fSmrgdebug_dump_enum(const struct debug_named_value *names,
34601e04c3fSmrg                unsigned long value)
34701e04c3fSmrg{
34801e04c3fSmrg   static char rest[64];
34901e04c3fSmrg
35001e04c3fSmrg   while (names->name) {
35101e04c3fSmrg      if (names->value == value)
35201e04c3fSmrg	 return names->name;
35301e04c3fSmrg      ++names;
35401e04c3fSmrg   }
35501e04c3fSmrg
3567ec681f3Smrg   snprintf(rest, sizeof(rest), "0x%08lx", value);
35701e04c3fSmrg   return rest;
35801e04c3fSmrg}
35901e04c3fSmrg
36001e04c3fSmrg
36101e04c3fSmrgconst char *
36201e04c3fSmrgdebug_dump_enum_noprefix(const struct debug_named_value *names,
36301e04c3fSmrg                         const char *prefix,
36401e04c3fSmrg                         unsigned long value)
36501e04c3fSmrg{
36601e04c3fSmrg   static char rest[64];
36701e04c3fSmrg
36801e04c3fSmrg   while (names->name) {
36901e04c3fSmrg      if (names->value == value) {
37001e04c3fSmrg         const char *name = names->name;
37101e04c3fSmrg         while (*name == *prefix) {
37201e04c3fSmrg            name++;
37301e04c3fSmrg            prefix++;
37401e04c3fSmrg         }
37501e04c3fSmrg         return name;
37601e04c3fSmrg      }
37701e04c3fSmrg      ++names;
37801e04c3fSmrg   }
37901e04c3fSmrg
3807ec681f3Smrg   snprintf(rest, sizeof(rest), "0x%08lx", value);
38101e04c3fSmrg   return rest;
38201e04c3fSmrg}
38301e04c3fSmrg
38401e04c3fSmrg
38501e04c3fSmrgconst char *
38601e04c3fSmrgdebug_dump_flags(const struct debug_named_value *names, unsigned long value)
38701e04c3fSmrg{
38801e04c3fSmrg   static char output[4096];
38901e04c3fSmrg   static char rest[256];
39001e04c3fSmrg   int first = 1;
39101e04c3fSmrg
39201e04c3fSmrg   output[0] = '\0';
39301e04c3fSmrg
39401e04c3fSmrg   while (names->name) {
39501e04c3fSmrg      if ((names->value & value) == names->value) {
39601e04c3fSmrg	 if (!first)
3977ec681f3Smrg	    strncat(output, "|", sizeof(output) - strlen(output) - 1);
39801e04c3fSmrg	 else
39901e04c3fSmrg	    first = 0;
4007ec681f3Smrg	 strncat(output, names->name, sizeof(output) - strlen(output) - 1);
40101e04c3fSmrg	 output[sizeof(output) - 1] = '\0';
40201e04c3fSmrg	 value &= ~names->value;
40301e04c3fSmrg      }
40401e04c3fSmrg      ++names;
40501e04c3fSmrg   }
40601e04c3fSmrg
40701e04c3fSmrg   if (value) {
40801e04c3fSmrg      if (!first)
4097ec681f3Smrg	 strncat(output, "|", sizeof(output) - strlen(output) - 1);
41001e04c3fSmrg      else
41101e04c3fSmrg	 first = 0;
41201e04c3fSmrg
4137ec681f3Smrg      snprintf(rest, sizeof(rest), "0x%08lx", value);
4147ec681f3Smrg      strncat(output, rest, sizeof(output) - strlen(output) - 1);
41501e04c3fSmrg      output[sizeof(output) - 1] = '\0';
41601e04c3fSmrg   }
41701e04c3fSmrg
41801e04c3fSmrg   if (first)
41901e04c3fSmrg      return "0";
42001e04c3fSmrg
42101e04c3fSmrg   return output;
42201e04c3fSmrg}
42301e04c3fSmrg
42401e04c3fSmrg
42501e04c3fSmrg
42601e04c3fSmrg#ifdef DEBUG
42701e04c3fSmrgint fl_indent = 0;
42801e04c3fSmrgconst char* fl_function[1024];
42901e04c3fSmrg
43001e04c3fSmrgint
43101e04c3fSmrgdebug_funclog_enter(const char* f, UNUSED const int line,
43201e04c3fSmrg                    UNUSED const char* file)
43301e04c3fSmrg{
43401e04c3fSmrg   int i;
43501e04c3fSmrg
43601e04c3fSmrg   for (i = 0; i < fl_indent; i++)
43701e04c3fSmrg      debug_printf("  ");
43801e04c3fSmrg   debug_printf("%s\n", f);
43901e04c3fSmrg
44001e04c3fSmrg   assert(fl_indent < 1023);
44101e04c3fSmrg   fl_function[fl_indent++] = f;
44201e04c3fSmrg
44301e04c3fSmrg   return 0;
44401e04c3fSmrg}
44501e04c3fSmrg
44601e04c3fSmrgvoid
44701e04c3fSmrgdebug_funclog_exit(const char* f, UNUSED const int line,
44801e04c3fSmrg                   UNUSED const char* file)
44901e04c3fSmrg{
45001e04c3fSmrg   --fl_indent;
45101e04c3fSmrg   assert(fl_indent >= 0);
45201e04c3fSmrg   assert(fl_function[fl_indent] == f);
45301e04c3fSmrg}
45401e04c3fSmrg
45501e04c3fSmrgvoid
45601e04c3fSmrgdebug_funclog_enter_exit(const char* f, UNUSED const int line,
45701e04c3fSmrg                         UNUSED const char* file)
45801e04c3fSmrg{
45901e04c3fSmrg   int i;
46001e04c3fSmrg   for (i = 0; i < fl_indent; i++)
46101e04c3fSmrg      debug_printf("  ");
46201e04c3fSmrg   debug_printf("%s\n", f);
46301e04c3fSmrg}
46401e04c3fSmrg#endif
465