TuttleOFX
1
|
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