Home | History | Annotate | Download | only in ustl-1.0
      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