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