ROOT logo
// @(#)root/new:$Name$:$Id: TMemStatDepend.cxx 31781 2009-12-10 13:02:50Z rdm $
// Author: M.Ivanov   18/06/2007  -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008

/*************************************************************************
 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//______________________________________________________________________________
//
//  TMemStatDepend - non standard C++ functions - Needed to make
//  memory statistic (Used by TMemStatManager)
//
//  To be implemented for differnt platforms.
//______________________________________________________________________________


//STD
#include <string>
#include <vector>
// ROOT
#include "TString.h"
// API
#if defined(R__MACOSX)
#if defined(MAC_OS_X_VERSION_10_5)
#include <malloc/malloc.h>
#include <execinfo.h>
#endif
#else
#include <malloc.h>
#include <execinfo.h>
#endif
#include <cxxabi.h>
// MemStat
#include "TMemStatDepend.h"

#if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD)) && !defined(__alpha__)
#define SUPPORTS_MEMSTAT
#endif

// This is a global variable set at MSManager init time.
// It marks the highest used stack address.
void *g_global_stack_end = NULL;

#if defined(SUPPORTS_MEMSTAT)
// Comment from Anar:
// HACK: there is an ugly bug in gcc (Bug#8743): http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8743
// "receiving result from __builtin_return_address() beyond stack top causes segfault"
// NOTE that __builtin_return_address should only be used with a non-zero argument for
// debugging purposes. So we use it on our risk.
// A workaround:
// This means the address is out of range.  Note that for the
// toplevel we see a frame pointer with value NULL which clearly is out of range.
// NOTE 2: With gcc 4.1, some optimization levels (e.g., -O, -Os, -O2) have started to imply -fomit-frame-pointer.
// One should use GCC builtin function with -fno-omit-frame-pointer option.
#define G__builtin_return_address(N) \
 ((__builtin_frame_address(N) == NULL)  || \
  (__builtin_frame_address(N) >= g_global_stack_end) || \
  (__builtin_frame_address(N) < __builtin_frame_address(0))) ? \
  NULL : __builtin_return_address(N)
// __builtin_return_address(0) yields the address to which the current
// function will return.  __builtin_return_address(1) yields the address to
// which the caller will return, and so on up the stack.
#define _RET_ADDR(x)   case x: return G__builtin_return_address(x);

#endif

using namespace std;

ClassImp(TMemStatDepend)


//______________________________________________________________________________
static void *return_address(int _frame)
{
   // we have a limit on the depth = 35

#if defined(SUPPORTS_MEMSTAT)
   switch (_frame) {
      _RET_ADDR(0);_RET_ADDR(1);_RET_ADDR(2);_RET_ADDR(3);_RET_ADDR(4);_RET_ADDR(5);_RET_ADDR(6);_RET_ADDR(7);
      _RET_ADDR(8);_RET_ADDR(9);_RET_ADDR(10);_RET_ADDR(11);_RET_ADDR(12);_RET_ADDR(13);_RET_ADDR(14);
      _RET_ADDR(15);_RET_ADDR(16);_RET_ADDR(17);_RET_ADDR(18);_RET_ADDR(19);_RET_ADDR(20);_RET_ADDR(21);
      _RET_ADDR(22);_RET_ADDR(23);_RET_ADDR(24);_RET_ADDR(25);_RET_ADDR(26);_RET_ADDR(27);_RET_ADDR(28);
      _RET_ADDR(29);_RET_ADDR(30);_RET_ADDR(31);_RET_ADDR(32);_RET_ADDR(33);_RET_ADDR(34);_RET_ADDR(35);
   default:
      return 0;
   }
#else
   if (_frame) { }
   return 0;
#endif
}

//______________________________________________________________________________
size_t builtin_return_address(void **_Container, size_t _limit)
{
   size_t i(0);
   void *addr;
   for (i = 0; (i < _limit) && (addr = return_address(i)); ++i)
      _Container[i] = addr;
   return i;
}

//______________________________________________________________________________
TMemStatDepend::MallocHookFunc_t TMemStatDepend::GetMallocHook()
{
   //malloc function getter

#if defined(SUPPORTS_MEMSTAT)
   return __malloc_hook;
#else
   return 0;
#endif
}

//______________________________________________________________________________
TMemStatDepend::FreeHookFunc_t TMemStatDepend::GetFreeHook()
{
   //free function   getter

#if defined(SUPPORTS_MEMSTAT)
   return __free_hook;
#else
   return 0;
#endif
}

//______________________________________________________________________________
void TMemStatDepend::SetMallocHook(MallocHookFunc_t p)
{
   // Set pointer to function replacing alloc function

#if defined(SUPPORTS_MEMSTAT)
   __malloc_hook = p;
#else
   if (p) { }
#endif
}

//______________________________________________________________________________
void TMemStatDepend::SetFreeHook(FreeHookFunc_t p)
{
   // Set pointer to function replacing free function

#if defined(SUPPORTS_MEMSTAT)
   __free_hook = p;
#else
   if (p) { }
#endif
}

//______________________________________________________________________________
size_t TMemStatDepend::Backtrace(void **trace, size_t dsize, Bool_t _bUseGNUBuildinBacktrace)
{
   // Get the backtrace
   // dsize - maximal deepness of stack information
   // trace - array of pointers
   // return value =  min(stack deepness, dsize)

   if ( _bUseGNUBuildinBacktrace )
   {
#if defined(SUPPORTS_MEMSTAT)
      // Initialize the stack end variable.
      return builtin_return_address(trace, dsize);
#else
      if (trace || dsize) { }
      return 0;
#endif
   }
#if defined(R__MACOSX)
#if defined(MAC_OS_X_VERSION_10_5)
   return backtrace(trace, dsize);
#else
   if (trace || dsize) { }
   return 0;
#endif
#else
   return backtrace(trace, dsize);
#endif
}

//______________________________________________________________________________
char** TMemStatDepend::BacktraceSymbols(void **trace, size_t size)
{
   // TODO: Comment me

#if defined(SUPPORTS_MEMSTAT)
   return backtrace_symbols(trace, size);
#else
   if (trace || size) { }
#endif
   return 0;
}

//______________________________________________________________________________
void TMemStatDepend::GetSymbols(void *_pFunction,
                                TString &_strInfo, TString &_strLib, TString &_strFun, TString &/*_strLine*/)
{
   // get the name of the function and library

#if defined(SUPPORTS_MEMSTAT)
   char ** code = backtrace_symbols(&_pFunction, 1);
   if (!code || !code[0])
      return;
   const string codeInfo(code[0]);
   // it is the responsibility of the caller to free that pointer
   free(code);

   // information about the call
   _strInfo = codeInfo.c_str();

   // Resolving a library name
   const string::size_type pos_begin = codeInfo.find_first_of("( [");
   if (string::npos == pos_begin) {
      _strLib = codeInfo;
      return;
   }
   _strLib = codeInfo.substr(0, pos_begin);

   // Resolving a function name
   string::size_type pos_end = codeInfo.find('+', pos_begin);
   if (string::npos == pos_end) {
      pos_end = codeInfo.find(')', pos_begin);
      if (string::npos == pos_end)
         return; // TODO: log me!
   }
   const string func(codeInfo.substr(pos_begin + 1, pos_end - pos_begin - 1));

   // Demangling the function name
   int status(0);
   char *ch = abi::__cxa_demangle(func.c_str(), 0, 0, &status);
   if (!ch)
      return;
   _strFun = (!status) ? ch : func.c_str();
   // it is the responsibility of the caller to free that pointer
   free(ch);
#else
   if (!_pFunction) { _strInfo = ""; _strLib = ""; _strFun = ""; }
#endif
}

//______________________________________________________________________________
void TMemStatDepend::Demangle(char *codeInfo, TString &str)
{
   //    get the name of the function and library

#if defined(SUPPORTS_MEMSTAT)
   int status = 0;
   char *ch = abi::__cxa_demangle(codeInfo, 0, 0, &status);
   if (ch) {
      str = ch;
      free(ch);
   } else {
      str = "unknown";
   }
#else
   if (!codeInfo) { str = ""; }
#endif
}
 TMemStatDepend.cxx:1
 TMemStatDepend.cxx:2
 TMemStatDepend.cxx:3
 TMemStatDepend.cxx:4
 TMemStatDepend.cxx:5
 TMemStatDepend.cxx:6
 TMemStatDepend.cxx:7
 TMemStatDepend.cxx:8
 TMemStatDepend.cxx:9
 TMemStatDepend.cxx:10
 TMemStatDepend.cxx:11
 TMemStatDepend.cxx:12
 TMemStatDepend.cxx:13
 TMemStatDepend.cxx:14
 TMemStatDepend.cxx:15
 TMemStatDepend.cxx:16
 TMemStatDepend.cxx:17
 TMemStatDepend.cxx:18
 TMemStatDepend.cxx:19
 TMemStatDepend.cxx:20
 TMemStatDepend.cxx:21
 TMemStatDepend.cxx:22
 TMemStatDepend.cxx:23
 TMemStatDepend.cxx:24
 TMemStatDepend.cxx:25
 TMemStatDepend.cxx:26
 TMemStatDepend.cxx:27
 TMemStatDepend.cxx:28
 TMemStatDepend.cxx:29
 TMemStatDepend.cxx:30
 TMemStatDepend.cxx:31
 TMemStatDepend.cxx:32
 TMemStatDepend.cxx:33
 TMemStatDepend.cxx:34
 TMemStatDepend.cxx:35
 TMemStatDepend.cxx:36
 TMemStatDepend.cxx:37
 TMemStatDepend.cxx:38
 TMemStatDepend.cxx:39
 TMemStatDepend.cxx:40
 TMemStatDepend.cxx:41
 TMemStatDepend.cxx:42
 TMemStatDepend.cxx:43
 TMemStatDepend.cxx:44
 TMemStatDepend.cxx:45
 TMemStatDepend.cxx:46
 TMemStatDepend.cxx:47
 TMemStatDepend.cxx:48
 TMemStatDepend.cxx:49
 TMemStatDepend.cxx:50
 TMemStatDepend.cxx:51
 TMemStatDepend.cxx:52
 TMemStatDepend.cxx:53
 TMemStatDepend.cxx:54
 TMemStatDepend.cxx:55
 TMemStatDepend.cxx:56
 TMemStatDepend.cxx:57
 TMemStatDepend.cxx:58
 TMemStatDepend.cxx:59
 TMemStatDepend.cxx:60
 TMemStatDepend.cxx:61
 TMemStatDepend.cxx:62
 TMemStatDepend.cxx:63
 TMemStatDepend.cxx:64
 TMemStatDepend.cxx:65
 TMemStatDepend.cxx:66
 TMemStatDepend.cxx:67
 TMemStatDepend.cxx:68
 TMemStatDepend.cxx:69
 TMemStatDepend.cxx:70
 TMemStatDepend.cxx:71
 TMemStatDepend.cxx:72
 TMemStatDepend.cxx:73
 TMemStatDepend.cxx:74
 TMemStatDepend.cxx:75
 TMemStatDepend.cxx:76
 TMemStatDepend.cxx:77
 TMemStatDepend.cxx:78
 TMemStatDepend.cxx:79
 TMemStatDepend.cxx:80
 TMemStatDepend.cxx:81
 TMemStatDepend.cxx:82
 TMemStatDepend.cxx:83
 TMemStatDepend.cxx:84
 TMemStatDepend.cxx:85
 TMemStatDepend.cxx:86
 TMemStatDepend.cxx:87
 TMemStatDepend.cxx:88
 TMemStatDepend.cxx:89
 TMemStatDepend.cxx:90
 TMemStatDepend.cxx:91
 TMemStatDepend.cxx:92
 TMemStatDepend.cxx:93
 TMemStatDepend.cxx:94
 TMemStatDepend.cxx:95
 TMemStatDepend.cxx:96
 TMemStatDepend.cxx:97
 TMemStatDepend.cxx:98
 TMemStatDepend.cxx:99
 TMemStatDepend.cxx:100
 TMemStatDepend.cxx:101
 TMemStatDepend.cxx:102
 TMemStatDepend.cxx:103
 TMemStatDepend.cxx:104
 TMemStatDepend.cxx:105
 TMemStatDepend.cxx:106
 TMemStatDepend.cxx:107
 TMemStatDepend.cxx:108
 TMemStatDepend.cxx:109
 TMemStatDepend.cxx:110
 TMemStatDepend.cxx:111
 TMemStatDepend.cxx:112
 TMemStatDepend.cxx:113
 TMemStatDepend.cxx:114
 TMemStatDepend.cxx:115
 TMemStatDepend.cxx:116
 TMemStatDepend.cxx:117
 TMemStatDepend.cxx:118
 TMemStatDepend.cxx:119
 TMemStatDepend.cxx:120
 TMemStatDepend.cxx:121
 TMemStatDepend.cxx:122
 TMemStatDepend.cxx:123
 TMemStatDepend.cxx:124
 TMemStatDepend.cxx:125
 TMemStatDepend.cxx:126
 TMemStatDepend.cxx:127
 TMemStatDepend.cxx:128
 TMemStatDepend.cxx:129
 TMemStatDepend.cxx:130
 TMemStatDepend.cxx:131
 TMemStatDepend.cxx:132
 TMemStatDepend.cxx:133
 TMemStatDepend.cxx:134
 TMemStatDepend.cxx:135
 TMemStatDepend.cxx:136
 TMemStatDepend.cxx:137
 TMemStatDepend.cxx:138
 TMemStatDepend.cxx:139
 TMemStatDepend.cxx:140
 TMemStatDepend.cxx:141
 TMemStatDepend.cxx:142
 TMemStatDepend.cxx:143
 TMemStatDepend.cxx:144
 TMemStatDepend.cxx:145
 TMemStatDepend.cxx:146
 TMemStatDepend.cxx:147
 TMemStatDepend.cxx:148
 TMemStatDepend.cxx:149
 TMemStatDepend.cxx:150
 TMemStatDepend.cxx:151
 TMemStatDepend.cxx:152
 TMemStatDepend.cxx:153
 TMemStatDepend.cxx:154
 TMemStatDepend.cxx:155
 TMemStatDepend.cxx:156
 TMemStatDepend.cxx:157
 TMemStatDepend.cxx:158
 TMemStatDepend.cxx:159
 TMemStatDepend.cxx:160
 TMemStatDepend.cxx:161
 TMemStatDepend.cxx:162
 TMemStatDepend.cxx:163
 TMemStatDepend.cxx:164
 TMemStatDepend.cxx:165
 TMemStatDepend.cxx:166
 TMemStatDepend.cxx:167
 TMemStatDepend.cxx:168
 TMemStatDepend.cxx:169
 TMemStatDepend.cxx:170
 TMemStatDepend.cxx:171
 TMemStatDepend.cxx:172
 TMemStatDepend.cxx:173
 TMemStatDepend.cxx:174
 TMemStatDepend.cxx:175
 TMemStatDepend.cxx:176
 TMemStatDepend.cxx:177
 TMemStatDepend.cxx:178
 TMemStatDepend.cxx:179
 TMemStatDepend.cxx:180
 TMemStatDepend.cxx:181
 TMemStatDepend.cxx:182
 TMemStatDepend.cxx:183
 TMemStatDepend.cxx:184
 TMemStatDepend.cxx:185
 TMemStatDepend.cxx:186
 TMemStatDepend.cxx:187
 TMemStatDepend.cxx:188
 TMemStatDepend.cxx:189
 TMemStatDepend.cxx:190
 TMemStatDepend.cxx:191
 TMemStatDepend.cxx:192
 TMemStatDepend.cxx:193
 TMemStatDepend.cxx:194
 TMemStatDepend.cxx:195
 TMemStatDepend.cxx:196
 TMemStatDepend.cxx:197
 TMemStatDepend.cxx:198
 TMemStatDepend.cxx:199
 TMemStatDepend.cxx:200
 TMemStatDepend.cxx:201
 TMemStatDepend.cxx:202
 TMemStatDepend.cxx:203
 TMemStatDepend.cxx:204
 TMemStatDepend.cxx:205
 TMemStatDepend.cxx:206
 TMemStatDepend.cxx:207
 TMemStatDepend.cxx:208
 TMemStatDepend.cxx:209
 TMemStatDepend.cxx:210
 TMemStatDepend.cxx:211
 TMemStatDepend.cxx:212
 TMemStatDepend.cxx:213
 TMemStatDepend.cxx:214
 TMemStatDepend.cxx:215
 TMemStatDepend.cxx:216
 TMemStatDepend.cxx:217
 TMemStatDepend.cxx:218
 TMemStatDepend.cxx:219
 TMemStatDepend.cxx:220
 TMemStatDepend.cxx:221
 TMemStatDepend.cxx:222
 TMemStatDepend.cxx:223
 TMemStatDepend.cxx:224
 TMemStatDepend.cxx:225
 TMemStatDepend.cxx:226
 TMemStatDepend.cxx:227
 TMemStatDepend.cxx:228
 TMemStatDepend.cxx:229
 TMemStatDepend.cxx:230
 TMemStatDepend.cxx:231
 TMemStatDepend.cxx:232
 TMemStatDepend.cxx:233
 TMemStatDepend.cxx:234
 TMemStatDepend.cxx:235
 TMemStatDepend.cxx:236
 TMemStatDepend.cxx:237
 TMemStatDepend.cxx:238
 TMemStatDepend.cxx:239
 TMemStatDepend.cxx:240
 TMemStatDepend.cxx:241
 TMemStatDepend.cxx:242
 TMemStatDepend.cxx:243
 TMemStatDepend.cxx:244
 TMemStatDepend.cxx:245
 TMemStatDepend.cxx:246
 TMemStatDepend.cxx:247
 TMemStatDepend.cxx:248
 TMemStatDepend.cxx:249
 TMemStatDepend.cxx:250
 TMemStatDepend.cxx:251
 TMemStatDepend.cxx:252
 TMemStatDepend.cxx:253
 TMemStatDepend.cxx:254
 TMemStatDepend.cxx:255
 TMemStatDepend.cxx:256
 TMemStatDepend.cxx:257
 TMemStatDepend.cxx:258
 TMemStatDepend.cxx:259
 TMemStatDepend.cxx:260
 TMemStatDepend.cxx:261
 TMemStatDepend.cxx:262