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