Logo ROOT   6.14/05
Reference Guide
TMemStatBacktrace.cxx
Go to the documentation of this file.
1 // @(#)root/memstat:$Id$
2 // Author: Anar Manafov (A.Manafov@gsi.de) 2010-03-02
3 
4 /*************************************************************************
5 * Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11 #include "TMemStatBacktrace.h"
12 
13 // STD
14 #include <cstdlib>
15 
16 #ifndef __CINT__
17 #if !defined(__APPLE__) || defined(MAC_OS_X_VERSION_10_5)
18 #include <execinfo.h>
19 #endif
20 #include <cxxabi.h>
21 #endif
22 
23 #include <dlfcn.h>
24 // ROOT
25 #include "TString.h"
26 
27 #if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD) || (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_5)))
28 #define SUPPORTS_MEMSTAT
29 #endif
30 
31 #if defined(__GNUC__) && !defined(__clang__)
32 #if __GNUC__ > 5
33 #pragma GCC diagnostic ignored "-Wframe-address"
34 #endif
35 #endif
36 
37 // This is a global variable set at MSManager init time.
38 // It marks the highest used stack address.
39 void *g_global_stack_end = NULL;
40 
41 #if defined(SUPPORTS_MEMSTAT)
42 // Comment from Anar:
43 // HACK: there is an ugly bug in gcc (Bug#8743): http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8743
44 // "receiving result from __builtin_return_address() beyond stack top causes segfault"
45 // NOTE that __builtin_return_address should only be used with a non-zero argument for
46 // debugging purposes. So we use it on our risk.
47 // A workaround:
48 // This means the address is out of range. Note that for the
49 // toplevel we see a frame pointer with value NULL which clearly is out of range.
50 // NOTE 2: With gcc 4.1, some optimization levels (e.g., -O, -Os, -O2) have started to imply -fomit-frame-pointer.
51 // One should use GCC builtin function with -fno-omit-frame-pointer option.
52 #define G__builtin_return_address(N) \
53  ((__builtin_frame_address(N) == NULL) || \
54  (__builtin_frame_address(N) >= g_global_stack_end) || \
55  (__builtin_frame_address(N) < __builtin_frame_address(0))) ? \
56  NULL : __builtin_return_address(N)
57 // __builtin_return_address(0) yields the address to which the current
58 // function will return. __builtin_return_address(1) yields the address to
59 // which the caller will return, and so on up the stack.
60 #define _RET_ADDR(x) case x: return G__builtin_return_address(x);
61 
62 #endif
63 
64 namespace Memstat {
65 
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 /// we have a limit on the depth = 35
69 
70  static void *return_address(int _frame)
71  {
72 #if defined(SUPPORTS_MEMSTAT)
73  switch(_frame) {
74  _RET_ADDR(0);
75  _RET_ADDR(1);
76  _RET_ADDR(2);
77  _RET_ADDR(3);
78  _RET_ADDR(4);
79  _RET_ADDR(5);
80  _RET_ADDR(6);
81  _RET_ADDR(7);
82  _RET_ADDR(8);
83  _RET_ADDR(9);
84  _RET_ADDR(10);
85  _RET_ADDR(11);
86  _RET_ADDR(12);
87  _RET_ADDR(13);
88  _RET_ADDR(14);
89  _RET_ADDR(15);
90  _RET_ADDR(16);
91  _RET_ADDR(17);
92  _RET_ADDR(18);
93  _RET_ADDR(19);
94  _RET_ADDR(20);
95  _RET_ADDR(21);
96  _RET_ADDR(22);
97  _RET_ADDR(23);
98  _RET_ADDR(24);
99  _RET_ADDR(25);
100  _RET_ADDR(26);
101  _RET_ADDR(27);
102  _RET_ADDR(28);
103  _RET_ADDR(29);
104  _RET_ADDR(30);
105  _RET_ADDR(31);
106  _RET_ADDR(32);
107  _RET_ADDR(33);
108  _RET_ADDR(34);
109  _RET_ADDR(35);
110  default:
111  return 0;
112  }
113 #else
114  if(_frame) { }
115  return 0;
116 #endif
117  }
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 
121  size_t builtin_return_address(void **_container, size_t _limit)
122  {
123  size_t i(0);
124  void *addr;
125  for(i = 0; (i < _limit) && (addr = return_address(i)); ++i)
126  _container[i] = addr;
127 
128  return i;
129  }
130 ////////////////////////////////////////////////////////////////////////////////
131 /// Get the backtrace
132 /// _trace - array of pointers
133 /// _size - maximal deepness of stack information
134 /// _bUseGNUBuiltinBacktrace - whether to use gcc builtin backtrace or C library one.
135 /// The builtin version is much faster, but very sensitive and in some conditions could fail to return a proper result.
136 /// return value = min(stack deepness, dsize)
137 
138  size_t getBacktrace(void **_trace, size_t _size, Bool_t _bUseGNUBuiltinBacktrace)
139  {
140 #if defined(SUPPORTS_MEMSTAT)
141  if(_bUseGNUBuiltinBacktrace) {
142  // Initialize the stack end variable.
143  return builtin_return_address(_trace, _size);
144  }
145  return backtrace(_trace, _size);
146 #else
147  if(_trace || _size || _bUseGNUBuiltinBacktrace) { }
148  return 0;
149 #endif
150  }
151 
152 ////////////////////////////////////////////////////////////////////////////////
153 /// get the name of the function and library
154 
155  int getSymbols(void *_pAddr,
156  TString &/*_strInfo*/, TString &_strLib, TString &_strSymbol)
157  {
158 #if defined(SUPPORTS_MEMSTAT)
159  Dl_info info;
160  if(0 == dladdr(_pAddr, &info)) {
161  return -1;
162  }
163  if(NULL != info.dli_sname) {
164  int status(0);
165  char *ch = abi::__cxa_demangle(info.dli_sname, 0, 0, &status);
166 
167  _strSymbol = (0 == status) ? ch : info.dli_sname;
168 
169  // it's our responsibility to free that pointer
170  free(ch);
171  }
172  if(NULL != info.dli_fname)
173  _strLib = info.dli_fname;
174 #else
175  if(!_pAddr) {
176  _strLib = "";
177  _strSymbol = "";
178  }
179 #endif
180  return 0;
181  }
182 
183 ////////////////////////////////////////////////////////////////////////////////
184 
185  void getSymbolFullInfo(void *_pAddr, TString *_retInfo, const char *const _separator)
186  {
187  if(!_retInfo)
188  return;
189 
190 #if defined(SUPPORTS_MEMSTAT)
191  TString strInfo;
192  TString strLib;
193  TString strFun;
194  int res = getSymbols(_pAddr, strInfo, strLib, strFun);
195  if(0 != res)
196  return;
197 
198  *_retInfo += strInfo;
199  *_retInfo += _separator;
200  *_retInfo += strLib;
201  *_retInfo += _separator;
202  *_retInfo += strFun;
203 #else
204  if(_pAddr || _separator) { }
205 #endif
206  }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// demangle symbols
210 
211  void demangle(char *_codeInfo, TString &_str)
212  {
213 #if defined(SUPPORTS_MEMSTAT)
214  int status = 0;
215  char *ch = abi::__cxa_demangle(_codeInfo, 0, 0, &status);
216  if(ch) {
217  _str = ch;
218  free(ch);
219  } else {
220  _str = "unknown";
221  }
222 #else
223  if(!_codeInfo) {
224  _str = "";
225  }
226 #endif
227  }
228 
229 }
void demangle(char *_codeInfo, TString &_str)
demangle symbols
size_t getBacktrace(void **_trace, size_t _size, Bool_t _bUseGNUBuiltinBacktrace=kFALSE)
Get the backtrace _trace - array of pointers _size - maximal deepness of stack information _bUseGNUBu...
Basic string class.
Definition: TString.h:131
bool Bool_t
Definition: RtypesCore.h:59
int getSymbols(void *_pAddr, TString &_strInfo, TString &_strLib, TString &_strSymbol)
get the name of the function and library
static void * return_address(int _frame)
we have a limit on the depth = 35
#define free
Definition: civetweb.c:1350
void * g_global_stack_end
void getSymbolFullInfo(void *_pAddr, TString *_retInfo, const char *const _seporator=" | ")
size_t builtin_return_address(void **_container, size_t _limit)