Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ldbg.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2010 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 #if OS_ANDROID
37 
38 // Android NDK doesn't support backtrace()
39 // TODO: use unwind.h or similar?
40 
41 void* debug_GetCaller(void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
42 {
43  return NULL;
44 }
45 
46 Status debug_DumpStack(wchar_t* UNUSED(buf), size_t UNUSED(max_chars), void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
47 {
48  return ERR::NOT_SUPPORTED;
49 }
50 
51 Status debug_ResolveSymbol(void* UNUSED(ptr_of_interest), wchar_t* UNUSED(sym_name), wchar_t* UNUSED(file), int* UNUSED(line))
52 {
53  return ERR::NOT_SUPPORTED;
54 }
55 
56 #else
57 
58 #include <execinfo.h>
59 
60 void* debug_GetCaller(void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
61 {
62  // bt[0] == this function
63  // bt[1] == our caller
64  // bt[2] == the first caller they are interested in
65  // HACK: we currently don't support lastFuncToSkip (would require debug information),
66  // instead just returning the caller of the function calling us
67  void *bt[3];
68  int bt_size = backtrace(bt, 3);
69  if (bt_size < 3)
70  return NULL;
71  return bt[2];
72 }
73 
74 Status debug_DumpStack(wchar_t* buf, size_t max_chars, void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
75 {
76  static const size_t N_FRAMES = 16;
77  void *bt[N_FRAMES];
78  int bt_size = 0;
79  wchar_t *bufpos = buf;
80  wchar_t *bufend = buf + max_chars;
81 
82  bt_size = backtrace(bt, ARRAY_SIZE(bt));
83 
84  // Assumed max length of a single print-out
85  static const size_t MAX_OUT_CHARS = 1024;
86 
87  for (size_t i = 0; (int)i < bt_size && bufpos+MAX_OUT_CHARS < bufend; i++)
88  {
89  wchar_t file[DEBUG_FILE_CHARS];
90  wchar_t symbol[DEBUG_SYMBOL_CHARS];
91  int line;
92  int len;
93 
94  if (debug_ResolveSymbol(bt[i], symbol, file, &line) == 0)
95  {
96  if (file[0])
97  len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p) %ls:%d %ls\n", bt[i], file, line, symbol);
98  else
99  len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p) %ls\n", bt[i], symbol);
100  }
101  else
102  {
103  len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p)\n", bt[i]);
104  }
105 
106  if (len < 0)
107  {
108  // MAX_OUT_CHARS exceeded, realistically this was caused by some
109  // mindbogglingly long symbol name... replace the end with an
110  // ellipsis and a newline
111  memcpy(&bufpos[MAX_OUT_CHARS-6], L"...\n", 5*sizeof(wchar_t));
112  len = MAX_OUT_CHARS;
113  }
114 
115  bufpos += len;
116  }
117 
118  return INFO::OK;
119 }
120 
121 Status debug_ResolveSymbol(void* ptr_of_interest, wchar_t* sym_name, wchar_t* file, int* line)
122 {
123  if (sym_name)
124  *sym_name = 0;
125  if (file)
126  *file = 0;
127  if (line)
128  *line = 0;
129 
130  char** symbols = backtrace_symbols(&ptr_of_interest, 1);
131  if (symbols)
132  {
133  swprintf_s(sym_name, DEBUG_SYMBOL_CHARS, L"%hs", symbols[0]);
134  free(symbols);
135 
136  // (Note that this will usually return a pretty useless string,
137  // because we compile with -fvisibility=hidden and there won't be
138  // any exposed symbols for backtrace_symbols to report.)
139 
140  return INFO::OK;
141  }
142  else
143  {
144  return ERR::FAIL;
145  }
146 }
147 
148 #endif
149 
150 void debug_SetThreadName(char const* UNUSED(name))
151 {
152  // Currently unimplemented
153 }
#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
const Status NOT_SUPPORTED
Definition: status.h:429
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