1 // This file is part of the ustl library, an STL implementation. 2 // 3 // Copyright (C) 2006 by Mike Sharov <msharov (at) users.sourceforge.net> 4 // This file is free software, distributed under the MIT License. 5 // 6 // bktrace.cc 7 // 8 9 #include "bktrace.h" 10 #include "sostream.h" 11 #include "mistream.h" 12 #include "uassert.h" 13 #if linux && __GNUC__ && !defined(HAVE_ANDROID_OS) 14 #include <execinfo.h> 15 #else 16 static inline int backtrace (void**, int) { return (0); } 17 static inline char** backtrace_symbols (void* const*, int) { return (NULL); } 18 #endif 19 #if __GNUC__ >= 3 && !PLATFORM_ANDROID 20 #include <cxxabi.h> 21 #endif 22 23 namespace ustl { 24 25 /// Default constructor. The backtrace is obtained here. 26 CBacktrace::CBacktrace (void) 27 : m_Symbols (NULL), 28 m_nFrames (0), 29 m_SymbolsSize (0) 30 { 31 #if !PLATFORM_ANDROID 32 try { 33 #endif 34 m_nFrames = backtrace (VectorBlock (m_Addresses)); 35 GetSymbols(); 36 #if !PLATFORM_ANDROID 37 } catch (...) {} 38 #endif 39 } 40 41 /// Copy constructor. 42 CBacktrace::CBacktrace (const CBacktrace& v) 43 : m_Symbols (NULL), 44 m_nFrames (0), 45 m_SymbolsSize (0) 46 { 47 operator= (v); 48 } 49 50 /// Copy operator. 51 const CBacktrace& CBacktrace::operator= (const CBacktrace& v) 52 { 53 memcpy (m_Addresses, v.m_Addresses, sizeof(m_Addresses)); 54 m_Symbols = strdup (v.m_Symbols); 55 m_nFrames = v.m_nFrames; 56 m_SymbolsSize = v.m_SymbolsSize; 57 return (*this); 58 } 59 60 /// Converts a string returned by backtrace_symbols into readable form. 61 static size_t ExtractAbiName (const char* isym, char* nmbuf) 62 { 63 // Prepare the demangled name, if possible 64 size_t nmSize = 0; 65 if (isym) { 66 // Copy out the name; the strings are: "file(function+0x42) [0xAddress]" 67 const char* mnStart = strchr (isym, '('); 68 if (++mnStart == (const char*)(1)) 69 mnStart = isym; 70 const char* mnEnd = strchr (isym, '+'); 71 const char* isymEnd = isym + strlen (isym); 72 if (!mnEnd) 73 mnEnd = isymEnd; 74 nmSize = min (size_t (distance (mnStart, mnEnd)), 256U); 75 memcpy (nmbuf, mnStart, nmSize); 76 } 77 nmbuf[nmSize] = 0; 78 // Demangle 79 demangle_type_name (nmbuf, 256U, &nmSize); 80 return (nmSize); 81 } 82 83 /// Tries to get symbol information for the addresses. 84 void CBacktrace::GetSymbols (void) 85 { 86 auto_ptr<char*> symbols (backtrace_symbols (m_Addresses, m_nFrames)); 87 if (!symbols.get()) 88 return; 89 char nmbuf [256]; 90 size_t symSize = 1; 91 for (uoff_t i = 0; i < m_nFrames; ++ i) 92 symSize += ExtractAbiName (symbols.get()[i], nmbuf) + 1; 93 if (!(m_Symbols = (char*) calloc (symSize, 1))) 94 return; 95 for (uoff_t i = 0; m_SymbolsSize < symSize - 1; ++ i) { 96 size_t sz = ExtractAbiName (symbols.get()[i], nmbuf); 97 memcpy (m_Symbols + m_SymbolsSize, nmbuf, sz); 98 m_SymbolsSize += sz + 1; 99 m_Symbols [m_SymbolsSize - 1] = '\n'; 100 } 101 } 102 103 /// Default destructor. 104 CBacktrace::~CBacktrace (void) 105 { 106 free_nullok (m_Symbols); 107 } 108 109 #if SIZE_OF_LONG == 8 110 #define ADDRESS_FMT "%16p " 111 #else 112 #define ADDRESS_FMT "%8p " 113 #endif 114 115 /// Prints the backtrace to \p os. 116 void CBacktrace::text_write (ostringstream& os) const 117 { 118 const char *ss = m_Symbols, *se; 119 for (uoff_t i = 0; i < m_nFrames; ++ i) { 120 os.format (ADDRESS_FMT, m_Addresses[i]); 121 se = strchr (ss, '\n') + 1; 122 os.write (ss, distance (ss, se)); 123 ss = se; 124 } 125 } 126 127 /// Reads the object from stream \p is. 128 void CBacktrace::read (istream& is) 129 { 130 assert (is.aligned (alignof (m_Addresses[0])) && "Backtrace object contains pointers and must be void* aligned"); 131 is >> m_nFrames >> m_SymbolsSize; 132 free_nullok (m_Symbols); 133 m_Symbols = (char*) malloc (m_SymbolsSize + 1); 134 is.read (m_Symbols, m_SymbolsSize); 135 m_Symbols [m_SymbolsSize] = 0; 136 is.align(); 137 is.read (m_Addresses, m_nFrames * sizeof(void*)); 138 } 139 140 /// Writes the object to stream \p os. 141 void CBacktrace::write (ostream& os) const 142 { 143 assert (os.aligned (alignof (m_Addresses[0])) && "Backtrace object contains pointers and must be void* aligned"); 144 os << m_nFrames << m_SymbolsSize; 145 os.write (m_Symbols, m_SymbolsSize); 146 os.align(); 147 os.write (m_Addresses, m_nFrames * sizeof(void*)); 148 } 149 150 /// Returns the size of the written object. 151 size_t CBacktrace::stream_size (void) const 152 { 153 return (Align (stream_size_of (m_nFrames) + 154 stream_size_of (m_SymbolsSize) + 155 m_nFrames * sizeof(void*) + 156 m_SymbolsSize)); 157 } 158 159 } // namespace ustl 160 161