TMemStatDepend.cxx

Go to the documentation of this file.
00001 // @(#)root/new:$Name$:$Id: TMemStatDepend.cxx 31781 2009-12-10 13:02:50Z rdm $
00002 // Author: M.Ivanov   18/06/2007  -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //______________________________________________________________________________
00013 //
00014 //  TMemStatDepend - non standard C++ functions - Needed to make
00015 //  memory statistic (Used by TMemStatManager)
00016 //
00017 //  To be implemented for differnt platforms.
00018 //______________________________________________________________________________
00019 
00020 
00021 //STD
00022 #include <string>
00023 #include <vector>
00024 // ROOT
00025 #include "TString.h"
00026 // API
00027 #if defined(R__MACOSX)
00028 #if defined(MAC_OS_X_VERSION_10_5)
00029 #include <malloc/malloc.h>
00030 #include <execinfo.h>
00031 #endif
00032 #else
00033 #include <malloc.h>
00034 #include <execinfo.h>
00035 #endif
00036 #include <cxxabi.h>
00037 // MemStat
00038 #include "TMemStatDepend.h"
00039 
00040 #if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD)) && !defined(__alpha__)
00041 #define SUPPORTS_MEMSTAT
00042 #endif
00043 
00044 // This is a global variable set at MSManager init time.
00045 // It marks the highest used stack address.
00046 void *g_global_stack_end = NULL;
00047 
00048 #if defined(SUPPORTS_MEMSTAT)
00049 // Comment from Anar:
00050 // HACK: there is an ugly bug in gcc (Bug#8743): http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8743
00051 // "receiving result from __builtin_return_address() beyond stack top causes segfault"
00052 // NOTE that __builtin_return_address should only be used with a non-zero argument for
00053 // debugging purposes. So we use it on our risk.
00054 // A workaround:
00055 // This means the address is out of range.  Note that for the
00056 // toplevel we see a frame pointer with value NULL which clearly is out of range.
00057 // NOTE 2: With gcc 4.1, some optimization levels (e.g., -O, -Os, -O2) have started to imply -fomit-frame-pointer.
00058 // One should use GCC builtin function with -fno-omit-frame-pointer option.
00059 #define G__builtin_return_address(N) \
00060  ((__builtin_frame_address(N) == NULL)  || \
00061   (__builtin_frame_address(N) >= g_global_stack_end) || \
00062   (__builtin_frame_address(N) < __builtin_frame_address(0))) ? \
00063   NULL : __builtin_return_address(N)
00064 // __builtin_return_address(0) yields the address to which the current
00065 // function will return.  __builtin_return_address(1) yields the address to
00066 // which the caller will return, and so on up the stack.
00067 #define _RET_ADDR(x)   case x: return G__builtin_return_address(x);
00068 
00069 #endif
00070 
00071 using namespace std;
00072 
00073 ClassImp(TMemStatDepend)
00074 
00075 
00076 //______________________________________________________________________________
00077 static void *return_address(int _frame)
00078 {
00079    // we have a limit on the depth = 35
00080 
00081 #if defined(SUPPORTS_MEMSTAT)
00082    switch (_frame) {
00083       _RET_ADDR(0);_RET_ADDR(1);_RET_ADDR(2);_RET_ADDR(3);_RET_ADDR(4);_RET_ADDR(5);_RET_ADDR(6);_RET_ADDR(7);
00084       _RET_ADDR(8);_RET_ADDR(9);_RET_ADDR(10);_RET_ADDR(11);_RET_ADDR(12);_RET_ADDR(13);_RET_ADDR(14);
00085       _RET_ADDR(15);_RET_ADDR(16);_RET_ADDR(17);_RET_ADDR(18);_RET_ADDR(19);_RET_ADDR(20);_RET_ADDR(21);
00086       _RET_ADDR(22);_RET_ADDR(23);_RET_ADDR(24);_RET_ADDR(25);_RET_ADDR(26);_RET_ADDR(27);_RET_ADDR(28);
00087       _RET_ADDR(29);_RET_ADDR(30);_RET_ADDR(31);_RET_ADDR(32);_RET_ADDR(33);_RET_ADDR(34);_RET_ADDR(35);
00088    default:
00089       return 0;
00090    }
00091 #else
00092    if (_frame) { }
00093    return 0;
00094 #endif
00095 }
00096 
00097 //______________________________________________________________________________
00098 size_t builtin_return_address(void **_Container, size_t _limit)
00099 {
00100    size_t i(0);
00101    void *addr;
00102    for (i = 0; (i < _limit) && (addr = return_address(i)); ++i)
00103       _Container[i] = addr;
00104    return i;
00105 }
00106 
00107 //______________________________________________________________________________
00108 TMemStatDepend::MallocHookFunc_t TMemStatDepend::GetMallocHook()
00109 {
00110    //malloc function getter
00111 
00112 #if defined(SUPPORTS_MEMSTAT)
00113    return __malloc_hook;
00114 #else
00115    return 0;
00116 #endif
00117 }
00118 
00119 //______________________________________________________________________________
00120 TMemStatDepend::FreeHookFunc_t TMemStatDepend::GetFreeHook()
00121 {
00122    //free function   getter
00123 
00124 #if defined(SUPPORTS_MEMSTAT)
00125    return __free_hook;
00126 #else
00127    return 0;
00128 #endif
00129 }
00130 
00131 //______________________________________________________________________________
00132 void TMemStatDepend::SetMallocHook(MallocHookFunc_t p)
00133 {
00134    // Set pointer to function replacing alloc function
00135 
00136 #if defined(SUPPORTS_MEMSTAT)
00137    __malloc_hook = p;
00138 #else
00139    if (p) { }
00140 #endif
00141 }
00142 
00143 //______________________________________________________________________________
00144 void TMemStatDepend::SetFreeHook(FreeHookFunc_t p)
00145 {
00146    // Set pointer to function replacing free function
00147 
00148 #if defined(SUPPORTS_MEMSTAT)
00149    __free_hook = p;
00150 #else
00151    if (p) { }
00152 #endif
00153 }
00154 
00155 //______________________________________________________________________________
00156 size_t TMemStatDepend::Backtrace(void **trace, size_t dsize, Bool_t _bUseGNUBuildinBacktrace)
00157 {
00158    // Get the backtrace
00159    // dsize - maximal deepness of stack information
00160    // trace - array of pointers
00161    // return value =  min(stack deepness, dsize)
00162 
00163    if ( _bUseGNUBuildinBacktrace )
00164    {
00165 #if defined(SUPPORTS_MEMSTAT)
00166       // Initialize the stack end variable.
00167       return builtin_return_address(trace, dsize);
00168 #else
00169       if (trace || dsize) { }
00170       return 0;
00171 #endif
00172    }
00173 #if defined(R__MACOSX)
00174 #if defined(MAC_OS_X_VERSION_10_5)
00175    return backtrace(trace, dsize);
00176 #else
00177    if (trace || dsize) { }
00178    return 0;
00179 #endif
00180 #else
00181    return backtrace(trace, dsize);
00182 #endif
00183 }
00184 
00185 //______________________________________________________________________________
00186 char** TMemStatDepend::BacktraceSymbols(void **trace, size_t size)
00187 {
00188    // TODO: Comment me
00189 
00190 #if defined(SUPPORTS_MEMSTAT)
00191    return backtrace_symbols(trace, size);
00192 #else
00193    if (trace || size) { }
00194 #endif
00195    return 0;
00196 }
00197 
00198 //______________________________________________________________________________
00199 void TMemStatDepend::GetSymbols(void *_pFunction,
00200                                 TString &_strInfo, TString &_strLib, TString &_strFun, TString &/*_strLine*/)
00201 {
00202    // get the name of the function and library
00203 
00204 #if defined(SUPPORTS_MEMSTAT)
00205    char ** code = backtrace_symbols(&_pFunction, 1);
00206    if (!code || !code[0])
00207       return;
00208    const string codeInfo(code[0]);
00209    // it is the responsibility of the caller to free that pointer
00210    free(code);
00211 
00212    // information about the call
00213    _strInfo = codeInfo.c_str();
00214 
00215    // Resolving a library name
00216    const string::size_type pos_begin = codeInfo.find_first_of("( [");
00217    if (string::npos == pos_begin) {
00218       _strLib = codeInfo;
00219       return;
00220    }
00221    _strLib = codeInfo.substr(0, pos_begin);
00222 
00223    // Resolving a function name
00224    string::size_type pos_end = codeInfo.find('+', pos_begin);
00225    if (string::npos == pos_end) {
00226       pos_end = codeInfo.find(')', pos_begin);
00227       if (string::npos == pos_end)
00228          return; // TODO: log me!
00229    }
00230    const string func(codeInfo.substr(pos_begin + 1, pos_end - pos_begin - 1));
00231 
00232    // Demangling the function name
00233    int status(0);
00234    char *ch = abi::__cxa_demangle(func.c_str(), 0, 0, &status);
00235    if (!ch)
00236       return;
00237    _strFun = (!status) ? ch : func.c_str();
00238    // it is the responsibility of the caller to free that pointer
00239    free(ch);
00240 #else
00241    if (!_pFunction) { _strInfo = ""; _strLib = ""; _strFun = ""; }
00242 #endif
00243 }
00244 
00245 //______________________________________________________________________________
00246 void TMemStatDepend::Demangle(char *codeInfo, TString &str)
00247 {
00248    //    get the name of the function and library
00249 
00250 #if defined(SUPPORTS_MEMSTAT)
00251    int status = 0;
00252    char *ch = abi::__cxa_demangle(codeInfo, 0, 0, &status);
00253    if (ch) {
00254       str = ch;
00255       free(ch);
00256    } else {
00257       str = "unknown";
00258    }
00259 #else
00260    if (!codeInfo) { str = ""; }
00261 #endif
00262 }

Generated on Tue Jul 5 14:43:48 2011 for ROOT_528-00b_version by  doxygen 1.5.1