| # Gaudi Framework, version v23r0 |

Home |  | Generated: Mon Jan 30 2012

# 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