Gaudi Framework, version v22r0

Home   Generated: 9 Feb 2011

IgHook_IgHookTrace.cpp

Go to the documentation of this file.
00001 //<<<<<< INCLUDES                                                       >>>>>>
00002 
00003 #include "IgHook_IgHookTrace.h"
00004 #include <cstdlib>
00005 #include <cstdio>
00006 #include <dlfcn.h>
00007 #include <unistd.h>
00008 #include <sys/mman.h>
00009 #if __linux
00010 # include <execinfo.h>
00011 # include <ucontext.h>
00012 # include <sys/syscall.h>
00013 # if __x86_64__
00014 #  define UNW_LOCAL_ONLY
00015 #  include <libunwind.h>
00016 # endif
00017 #endif
00018 #if __APPLE__
00019 extern "C" void _sigtramp (void);
00020 #endif
00021 
00022 //<<<<<< PRIVATE DEFINES                                                >>>>>>
00023 
00024 #if !defined MAP_ANONYMOUS && defined MAP_ANON
00025 # define MAP_ANONYMOUS MAP_ANON
00026 #endif
00027 
00028 //<<<<<< PRIVATE CONSTANTS                                              >>>>>>
00029 //<<<<<< PRIVATE TYPES                                                  >>>>>>
00030 //<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
00031 //<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
00032 //<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
00033 //<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
00034 
00035 #if 0 && __x86_64__ && __linux
00036 // Linux x86-64 does not use regular call frames, like IA-32 does for
00037 // example, and it would be a very difficult job to decipher the call
00038 // stack.  In order to walk the call stack correctly, we have to use
00039 // the DWARF-2 unwind data.  This alone is incredibly, uselessly slow
00040 // for our purposes.
00041 //
00042 // We avoid using the unwind data by caching frame structures for
00043 // recently seen functions.  This is slow to start with, but very
00044 // quickly gets fast enough for our purposes.  Fortunately the x86-64
00045 // unwind library appears to be robust enough to be called in signal
00046 // handlers (unlike at least some IA-32 versions).
00047 //
00048 // The cache consists of two arrays arranged as an open-addressed
00049 // unprobed hash table.  Hash collisions overwrite the entry with the
00050 // latest data.  We try to avoid making this a problem by using a
00051 // high-quality hash function and pure brute force in the form of a
00052 // large hash table.  A couple of megabytes goes a long way to help!
00053 //
00054 // The first of the cache arrays, of "void *", tracks program counter
00055 // addresses.  A parallel array of "int" tracks the size of the call
00056 // frame at that address.  Given a program counter and the canonical
00057 // frame address (CFA) of the previous (= above) call frame, the new
00058 // frame address is the previous plus the delta.  We find the address
00059 // of the caller just above this new frame address.
00060 //
00061 // We use the cache as long as we can find the addresses there.  When
00062 // we fall off the cache, we resort to the language run time unwinder.
00063 
00064 struct IgHookTraceArgs
00065 {
00066   struct
00067   {
00068     void **pc;
00069     int **frame;
00070   } cache;
00071   struct
00072   {
00073     void **addresses;
00074     int top;
00075     int size;
00076   } stack;
00077   void **prevframe;
00078 };
00079 
00080 static _Unwind_Reason_Code
00081 GCCBackTrace (_Unwind_Context *context, void *arg)
00082 {
00083   IgHookTraceArgs *args = (IgHookTraceArgs *) arg;
00084   if (args->stack.top < 0 || args->stack.top >= args->stack.size)
00085     return _URC_END_OF_STACK;
00086 
00087   args->stack.addresses [args->stack.top++] = (void *) _Unwind_GetIP (context);
00088   args->prevframe = (void **) _Unwind_GetCFA (context);
00089   return _URC_NO_REASON;
00090 }
00091 #endif
00092 
00093 //<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
00094 //<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
00095 
00099 IgHookTraceAlloc::IgHookTraceAlloc (void)
00100     : m_pool (0),
00101       m_left (0)
00102 {}
00103 
00104 void *
00105 IgHookTraceAlloc::allocate (size_t bytes)
00106 {
00107     // The reason for the existence of this class is to allocate
00108     // memory directly using mmap() so we don't create calls to
00109     // malloc() and friends.  This is for two reasons: it must be
00110     // possible to use this in asynchronous signal handlers, and
00111     // calling malloc() in those is a really bad idea; and this is
00112     // meant to be used by profiling code and it's nicer to not
00113     // allocate memory in ways tracked by the profiler.
00114     if (m_left < bytes)
00115     {
00116         size_t psize = getpagesize ();
00117         size_t hunk = psize * 20;
00118         if (hunk < bytes) hunk = (hunk + psize - 1) & ~(psize-1);
00119         void *addr = mmap (0, hunk, PROT_READ | PROT_WRITE,
00120                            MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
00121         if (addr == MAP_FAILED)
00122             return 0;
00123 
00124         m_pool = addr;
00125         m_left = hunk;
00126     }
00127 
00128     void *ptr = m_pool;
00129     m_pool = (char *) m_pool + bytes;
00130     m_left -= bytes;
00131     return ptr;
00132 }
00133 
00137 void *
00138 IgHookTrace::CounterValue::operator new (size_t n, IgHookTraceAlloc *alloc /* = 0 */)
00139 { return alloc ? alloc->allocate (n) : ::operator new (n); }
00140 
00141 IgHookTrace::CounterValue::CounterValue (Counter *counter,
00142                                          CounterValue *next /* = 0 */,
00143                                          unsigned long long value /* = 0 */)
00144     : m_counter (counter),
00145       m_next (next),
00146       m_value (value),
00147       m_count (0)
00148 {}
00149 
00150 IgHookTrace::Counter *
00151 IgHookTrace::CounterValue::counter (void)
00152 { return m_counter; }
00153 
00154 IgHookTrace::CounterValue *
00155 IgHookTrace::CounterValue::next (void)
00156 { return m_next; }
00157 
00158 unsigned long long
00159 IgHookTrace::CounterValue::value (void)
00160 { return m_value; }
00161     
00162 unsigned long long
00163 IgHookTrace::CounterValue::count (void)
00164 { return m_count; }
00165     
00166 unsigned long long
00167 IgHookTrace::CounterValue::tick (void)
00168 { ++m_count; return ++m_value; }
00169 
00170 unsigned long long
00171 IgHookTrace::CounterValue::untick (void)
00172 { --m_count; return --m_value; }
00173 
00174 unsigned long long
00175 IgHookTrace::CounterValue::add (unsigned long long value)
00176 { ++m_count; return m_value += value; }
00177 
00178 unsigned long long
00179 IgHookTrace::CounterValue::sub (unsigned long long value)
00180 { --m_count; return m_value -= value; }
00181 
00182 unsigned long long
00183 IgHookTrace::CounterValue::max (unsigned long long value)
00184 { ++m_count; if (m_value < value) m_value = value; return m_value; }
00185 
00186 unsigned long long
00187 IgHookTrace::CounterValue::add (CounterValue &x)
00188 { m_count += x.m_count; m_value += x.m_value; return m_value; }
00189 
00190 unsigned long long
00191 IgHookTrace::CounterValue::sub (CounterValue &x)
00192 { m_count -= x.m_count; m_value -= x.m_value; return m_value; }
00193 
00194 unsigned long long
00195 IgHookTrace::CounterValue::max (CounterValue &x)
00196 { m_count += x.m_count; if (m_value < x.m_value) m_value = x.m_value; return m_value; }
00197 
00201 void *
00202 IgHookTrace::operator new (size_t n, IgHookTraceAlloc *alloc /* = 0 */)
00203 { return alloc ? alloc->allocate (n) : ::operator new (n); }
00204 
00205 IgHookTrace::IgHookTrace (IgHookTrace *parent /* = 0 */, void *address /* = 0 */)
00206     : m_alloc (parent ? parent->m_alloc : new IgHookTraceAlloc),
00207       m_parent (parent),
00208       m_next (parent ? parent->m_children : 0),
00209       m_children (0),
00210       m_address (address),
00211       m_counters (0)
00212 { if (m_parent) m_parent->m_children = this; }
00213 
00214 IgHookTrace *
00215 IgHookTrace::parent (void)
00216 { return m_parent; }
00217 
00218 IgHookTrace *
00219 IgHookTrace::next (void)
00220 { return m_next; }
00221 
00222 void *
00223 IgHookTrace::address (void)
00224 { return m_address; }
00225 
00226 bool
00227 IgHookTrace::symbol (void *address,
00228                      const char *&sym,
00229                      const char *&lib,
00230                      int &offset,
00231                      int &liboffset)
00232 {
00233     sym = lib = 0;
00234     offset = 0;
00235     liboffset = (unsigned long) address;
00236 
00237     Dl_info info;
00238     if (dladdr (address, &info))
00239     {
00240         if (info.dli_fname && info.dli_fname [0])
00241             lib = info.dli_fname;
00242 
00243         if (info.dli_fbase)
00244             liboffset = (unsigned long) address - (unsigned long) info.dli_fbase;
00245 
00246         if (info.dli_saddr)
00247             offset = (unsigned long) address - (unsigned long) info.dli_saddr;
00248 
00249         if (info.dli_sname && info.dli_sname [0])
00250             sym = info.dli_sname;
00251 
00252         return true;
00253     }
00254 
00255     return false;
00256 }
00257 
00258 bool
00259 IgHookTrace::symbol (const char *&sym, const char *&lib, int &offset, int &liboffset)
00260 { return symbol (m_address, sym, lib, offset, liboffset); }
00261 
00262 void *
00263 IgHookTrace::tosymbol (void *address)
00264 {
00265     Dl_info info;
00266     return (dladdr (address, &info)
00267             && info.dli_fname
00268             && info.dli_fname [0]
00269             && info.dli_saddr)
00270         ? info.dli_saddr : address;
00271 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Wed Feb 9 16:24:58 2011 for Gaudi Framework, version v22r0 by Doxygen version 1.6.2 written by Dimitri van Heesch, © 1997-2004