TuttleOFX  1
TuttleOFX/libraries/tuttle/src/tuttle/common/utils/backtrace.cpp
Go to the documentation of this file.
00001 //
00002 //  Copyright (c) 2010 Artyom Beilis (Tonkikh)
00003 //
00004 //  Distributed under the Boost Software License, Version 1.0. (See
00005 //  accompanying file LICENSE_1_0.txt or copy at
00006 //  http://www.boost.org/LICENSE_1_0.txt)
00007 //
00008 #define BOOST_SOURCE
00009 
00010 #include "backtrace.hpp"
00011 
00012 #if defined(__linux) || defined(__APPLE__) || defined(__sun)
00013 #define BOOST_HAVE_EXECINFO
00014 #define BOOST_HAVE_DLADDR
00015 #endif
00016 
00017 #if defined(__GNUC__)
00018 #define BOOST_HAVE_ABI_CXA_DEMANGLE
00019 #endif
00020 
00021 #ifdef BOOST_HAVE_EXECINFO
00022 #include <execinfo.h>
00023 #endif
00024 
00025 #ifdef BOOST_HAVE_ABI_CXA_DEMANGLE
00026 #include <cxxabi.h>
00027 #endif
00028 
00029 #ifdef BOOST_HAVE_DLADDR
00030 #include <dlfcn.h>
00031 #endif
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #include <ostream>
00035 #include <sstream>
00036 #include <iomanip>
00037 
00038 #if defined(BOOST_MSVC)
00039 #include <windows.h>
00040 #include <stdlib.h>
00041 #include <dbghelp.h>
00042 #endif
00043 
00044 
00045 namespace boost {
00046 
00047 namespace stack_trace {
00048 
00049 #if defined(BOOST_HAVE_EXECINFO) && defined(TUTTLE_DEBUG)
00050 
00051 int trace(void **array,int n)
00052 {
00053         return ::backtrace(array,n);
00054 }
00055 
00056 #elif defined(BOOST_MSVC) && defined(TUTTLE_DEBUG)
00057 
00058 int trace(void **array,int n)
00059 {
00060         if( n>=63 )
00061                 n=62;
00062         return RtlCaptureStackBackTrace( 0, n, array, 0 );
00063 }
00064 
00065 #else
00066 
00067 int trace(void ** /*array*/,int /*n*/)
00068 {
00069         return 0;
00070 }
00071 
00072 #endif
00073 
00074 #if defined(BOOST_HAVE_DLADDR) && defined(BOOST_HAVE_ABI_CXA_DEMANGLE) && defined(TUTTLE_DEBUG)
00075 
00076 std::string get_symbol(void *ptr)
00077 {
00078         if( !ptr )
00079                 return std::string();
00080         std::ostringstream res;
00081         res.imbue( std::locale::classic() );
00082         res << ptr << ": ";
00083         Dl_info info = {0};
00084         if( dladdr(ptr,&info) == 0 )
00085         {
00086                 res << "???";
00087         }
00088         else
00089         {
00090                 if( info.dli_sname )
00091                 {
00092                         int status = 0;
00093                         char *demangled = abi::__cxa_demangle( info.dli_sname, 0, 0, &status );
00094                         if( demangled )
00095                         {
00096                                 res << demangled;
00097                                 free(demangled);
00098                         }
00099                         else
00100                         {
00101                                 res << info.dli_sname;
00102                         }
00103                 }
00104                 else
00105                 {
00106                         res << "???";
00107                 }
00108 
00109                 unsigned offset = (char *)ptr - (char *)info.dli_saddr;
00110                 res << std::hex <<" + 0x" << offset ;
00111 
00112                 if(info.dli_fname)
00113                         res << " in " << info.dli_fname;
00114         }
00115    return res.str();
00116 }
00117 
00118 std::string get_symbols( void *const *addresses, int size )
00119 {
00120         std::string res;
00121         for(int i=0;i<size;i++) {
00122                 std::string tmp = get_symbol(addresses[i]);
00123                 if(!tmp.empty()) {
00124                         res+=tmp;
00125                         res+='\n';
00126                 }
00127         }
00128         return res;
00129 }
00130 void write_symbols( void *const *addresses, int size, std::ostream &out )
00131 {
00132         for(int i=0;i<size;i++) {
00133                 std::string tmp = get_symbol(addresses[i]);
00134                 if(!tmp.empty()) {
00135                         out << tmp << '\n';
00136                 }
00137         }
00138         out << std::flush;
00139 }
00140 
00141 #elif defined(BOOST_HAVE_EXECINFO)
00142 std::string get_symbol( void *address )
00143 {
00144         char ** ptr = backtrace_symbols(&address,1);
00145         try {
00146                 if(ptr == 0)
00147                         return std::string();
00148                 std::string res = ptr[0];
00149                 free(ptr);
00150                 ptr = 0;
00151                 return res;
00152         }
00153         catch(...) {
00154                 free(ptr);
00155                 throw;
00156         }
00157 }
00158 
00159 std::string get_symbols( void * const *address, int size )
00160 {
00161         char ** ptr = backtrace_symbols(address,size);
00162         try {
00163                 if(ptr==0)
00164                         return std::string();
00165                 std::string res;
00166                 for(int i=0;i<size;i++) {
00167                         res+=ptr[i];
00168                         res+='\n';
00169                 }
00170                 free(ptr);
00171                 ptr = 0;
00172                 return res;
00173         }
00174         catch(...) {
00175                 free(ptr);
00176                 throw;
00177         }
00178 }
00179 
00180 
00181 void write_symbols( void *const *addresses, int size, std::ostream &out )
00182 {
00183         char ** ptr = backtrace_symbols(addresses,size);
00184         try {
00185                 if(ptr==0)
00186                         return;
00187                 for(int i=0;i<size;i++)
00188                         out << ptr[i] << '\n';
00189                 free(ptr);
00190                 ptr = 0;
00191                 out << std::flush;
00192         }
00193         catch(...) {
00194                 free(ptr);
00195                 throw;
00196         }
00197 }
00198 
00199 #elif defined(BOOST_MSVC) && defined(TUTTLE_DEBUG)
00200 
00201 namespace {
00202         HANDLE hProcess = 0;
00203         bool syms_ready = false;
00204 
00205         void init()
00206         {
00207                 if(hProcess == 0)
00208                 {
00209                         hProcess = GetCurrentProcess();
00210                         SymSetOptions(SYMOPT_DEFERRED_LOADS);
00211 
00212                         if( SymInitialize(hProcess, NULL, TRUE) )
00213                         {
00214                                 syms_ready = true;
00215                         }
00216                 }
00217         }
00218 }
00219 
00220 std::string get_symbol( void *ptr )
00221 {
00222         if( ptr == 0 )
00223                 return std::string();
00224 
00225         init();
00226         std::ostringstream ss;
00227         ss << ptr;
00228         if( syms_ready )
00229         {
00230                 DWORD64  dwDisplacement = 0;
00231                 DWORD64  dwAddress = (DWORD64)ptr;
00232 
00233                 std::vector<char> buffer(sizeof(SYMBOL_INFO) + MAX_SYM_NAME);
00234                 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)&buffer.front();
00235 
00236                 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
00237                 pSymbol->MaxNameLen = MAX_SYM_NAME;
00238 
00239                 if( SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol) )
00240                 {
00241                         ss <<": " << pSymbol->Name << std::hex << " +0x" << dwDisplacement;
00242                 }
00243                 else
00244                 {
00245                         ss << ": ???";
00246                 }
00247         }
00248         return ss.str();
00249 }
00250 
00251 std::string get_symbols( void *const *addresses, int size )
00252 {
00253         std::string res;
00254         for( int i = 0; i < size; ++i )
00255         {
00256                 std::string tmp = get_symbol(addresses[i]);
00257                 if( !tmp.empty() )
00258                 {
00259                         res += tmp;
00260                         res += '\n';
00261                 }
00262         }
00263         return res;
00264 }
00265 
00266 void write_symbols( void *const *addresses, int size, std::ostream &out )
00267 {
00268         for( int i = 0; i < size; ++i )
00269         {
00270                 std::string tmp = get_symbol( addresses[i] );
00271                 if( ! tmp.empty() )
00272                 {
00273                         out << tmp << '\n';
00274                 }
00275         }
00276         out << std::flush;
00277 }
00278 
00279 #else
00280 
00281 std::string get_symbol( void *ptr )
00282 {
00283         if( !ptr )
00284                 return std::string();
00285         std::ostringstream res;
00286         res.imbue( std::locale::classic() );
00287         res << ptr;
00288         return res.str();
00289 }
00290 
00291 std::string get_symbols( void *const *ptrs, int size )
00292 {
00293         if( !ptrs )
00294                 return std::string();
00295         std::ostringstream res;
00296         res.imbue(std::locale::classic());
00297         write_symbols(ptrs,size,res);
00298         return res.str();
00299 }
00300 
00301 void write_symbols( void *const *addresses, int size, std::ostream &out )
00302 {
00303         for( int i = 0; i < size; ++i )
00304         {
00305                 if( addresses[i] != 0 )
00306                         out << addresses[i] << '\n';
00307         }
00308         out << std::flush;
00309 }
00310 
00311 #endif
00312 
00313 } // stack_trace
00314 } // boost
00315 
00316