Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bdbg.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2012 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 // Note: This used to use BFD to get more useful debugging information.
24 // (See SVN r8270 if you want that code.)
25 // That requires binutils at runtime, which hits some bugs and library versioning
26 // issues on some Linux distros.
27 // The debugging info reported by this code with BFD wasn't especially useful,
28 // and it's easy enough to get people to run in gdb if we want a proper backtrace.
29 // So we now go with the simple approach of not using BFD.
30 
31 #include "precompiled.h"
32 
33 #include "lib/sysdep/sysdep.h"
34 #include "lib/debug.h"
35 
36 #include <execinfo.h>
37 
38 void* debug_GetCaller(void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
39 {
40  // bt[0] == this function
41  // bt[1] == our caller
42  // bt[2] == the first caller they are interested in
43  // HACK: we currently don't support lastFuncToSkip (would require debug information),
44  // instead just returning the caller of the function calling us
45  void *bt[3];
46  int bt_size = backtrace(bt, 3);
47  if (bt_size < 3)
48  return NULL;
49  return bt[2];
50 }
51 
52 Status debug_DumpStack(wchar_t* buf, size_t max_chars, void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
53 {
54  static const size_t N_FRAMES = 16;
55  void *bt[N_FRAMES];
56  int bt_size = 0;
57  wchar_t *bufpos = buf;
58  wchar_t *bufend = buf + max_chars;
59 
60  bt_size = backtrace(bt, ARRAY_SIZE(bt));
61 
62  // Assumed max length of a single print-out
63  static const size_t MAX_OUT_CHARS = 1024;
64 
65  for (size_t i = 0; (int)i < bt_size && bufpos+MAX_OUT_CHARS < bufend; i++)
66  {
67  wchar_t file[DEBUG_FILE_CHARS];
68  wchar_t symbol[DEBUG_SYMBOL_CHARS];
69  int line;
70  int len;
71 
72  if (debug_ResolveSymbol(bt[i], symbol, file, &line) == 0)
73  {
74  if (file[0])
75  len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p) %ls:%d %ls\n", bt[i], file, line, symbol);
76  else
77  len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p) %ls\n", bt[i], symbol);
78  }
79  else
80  {
81  len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p)\n", bt[i]);
82  }
83 
84  if (len < 0)
85  {
86  // MAX_OUT_CHARS exceeded, realistically this was caused by some
87  // mindbogglingly long symbol name... replace the end with an
88  // ellipsis and a newline
89  memcpy(&bufpos[MAX_OUT_CHARS-6], L"...\n", 5*sizeof(wchar_t));
90  len = MAX_OUT_CHARS;
91  }
92 
93  bufpos += len;
94  }
95 
96  return INFO::OK;
97 }
98 
99 Status debug_ResolveSymbol(void* ptr_of_interest, wchar_t* sym_name, wchar_t* file, int* line)
100 {
101  if (sym_name)
102  *sym_name = 0;
103  if (file)
104  *file = 0;
105  if (line)
106  *line = 0;
107 
108  char** symbols = backtrace_symbols(&ptr_of_interest, 1);
109  if (symbols)
110  {
111  swprintf_s(sym_name, DEBUG_SYMBOL_CHARS, L"%hs", symbols[0]);
112  free(symbols);
113 
114  // (Note that this will usually return a pretty useless string,
115  // because we compile with -fvisibility=hidden and there won't be
116  // any exposed symbols for backtrace_symbols to report.)
117 
118  return INFO::OK;
119  }
120  else
121  {
122  return ERR::FAIL;
123  }
124 }
125 
126 void debug_SetThreadName(char const* UNUSED(name))
127 {
128  // Currently unimplemented
129 }
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
static const size_t DEBUG_SYMBOL_CHARS
Maximum number of characters (including null terminator) written to user&#39;s buffers by debug_ResolveSy...
Definition: debug.h:428
const Status OK
Definition: status.h:386
int swprintf_s(wchar_t *buf, size_t max_chars, const wchar_t *fmt,...) WPRINTF_ARGS(3)
#define ARRAY_SIZE(name)
LIB_API void debug_SetThreadName(const char *name)
inform the debugger of the current thread&#39;s name.
Definition: bdbg.cpp:126
static const size_t DEBUG_FILE_CHARS
Definition: debug.h:429
LIB_API void * debug_GetCaller(void *context, const wchar_t *lastFuncToSkip)
return the caller of a certain function on the call stack.
Definition: bdbg.cpp:38
i64 Status
Error handling system.
Definition: status.h:171
const Status FAIL
Definition: status.h:406
LIB_API Status debug_ResolveSymbol(void *ptr_of_interest, wchar_t *sym_name, wchar_t *file, int *line)
read and return symbol information for the given address.
Definition: bdbg.cpp:99
LIB_API Status debug_DumpStack(wchar_t *buf, size_t maxChars, void *context, const wchar_t *lastFuncToSkip)
write a complete stack trace (including values of local variables) into the specified buffer...
Definition: bdbg.cpp:52