Logo ROOT  
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.
39void *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
64namespace 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}
bool Bool_t
Definition: RtypesCore.h:59
void * g_global_stack_end
#define free
Definition: civetweb.c:1539
Basic string class.
Definition: TString.h:131
int getSymbols(void *_pAddr, TString &_strInfo, TString &_strLib, TString &_strSymbol)
get the name of the function and library
size_t builtin_return_address(void **_container, size_t _limit)
void getSymbolFullInfo(void *_pAddr, TString *_retInfo, const char *const _seporator=" | ")
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...
void demangle(char *_codeInfo, TString &_str)
demangle symbols
static void * return_address(int _frame)
we have a limit on the depth = 35