Libbarrett
1.2.4
|
00001 00036 #ifndef BARRETT_DETAIL_STACKTRACE_H_ 00037 #define BARRETT_DETAIL_STACKTRACE_H_ 00038 00039 00040 #include <stdio.h> 00041 #include <syslog.h> 00042 #include <stdlib.h> 00043 #include <execinfo.h> 00044 #include <cxxabi.h> 00045 00046 00047 namespace barrett { 00048 namespace detail { 00049 00050 00051 /* Print a demangled stack backtrace of the caller function to FILE* out. */ 00052 static inline void print_stacktrace(FILE *out = stderr, 00053 unsigned int max_frames = 63) 00054 { 00055 fprintf(out, "stack trace:\n"); 00056 00057 // storage array for stack trace address data 00058 void* addrlist[max_frames+1]; 00059 00060 // retrieve current stack addresses 00061 int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(addrlist[0])); 00062 00063 if (addrlen == 0) { 00064 fprintf(out, " <empty, possibly corrupt>\n"); 00065 return; 00066 } 00067 00068 // resolve addresses into strings containing "filename(function+address)", 00069 // this array must be free()-ed 00070 char** symbollist = backtrace_symbols(addrlist, addrlen); 00071 00072 // allocate string which will be filled with the demangled function name 00073 size_t funcnamesize = 256; 00074 char* funcname = reinterpret_cast<char*>(malloc(funcnamesize)); 00075 00076 // iterate over the returned symbol lines. skip the first, it is the 00077 // address of this function. 00078 for (int i = 1; i < addrlen; i++) 00079 { 00080 char *begin_name = 0, *begin_offset = 0, *end_offset = 0; 00081 00082 // find parentheses and +address offset surrounding the mangled name: 00083 // ./module(function+0x15c) [0x8048a6d] 00084 for (char *p = symbollist[i]; *p; ++p) 00085 { 00086 if (*p == '(') 00087 begin_name = p; 00088 else if (*p == '+') 00089 begin_offset = p; 00090 else if (*p == ')' && begin_offset) { 00091 end_offset = p; 00092 break; 00093 } 00094 } 00095 00096 if (begin_name && begin_offset && end_offset 00097 && begin_name < begin_offset) 00098 { 00099 *begin_name++ = '\0'; 00100 *begin_offset++ = '\0'; 00101 *end_offset = '\0'; 00102 00103 // mangled name is now in [begin_name, begin_offset) and caller 00104 // offset in [begin_offset, end_offset). now apply 00105 // __cxa_demangle(): 00106 00107 int status; 00108 char* ret = abi::__cxa_demangle(begin_name, 00109 funcname, &funcnamesize, &status); 00110 if (status == 0) { 00111 funcname = ret; // use possibly realloc()-ed string 00112 fprintf(out, " %s : %s+%s\n", 00113 symbollist[i], funcname, begin_offset); 00114 } else { 00115 // demangling failed. Output function name as a C function with 00116 // no arguments. 00117 fprintf(out, " %s : %s()+%s\n", 00118 symbollist[i], begin_name, begin_offset); 00119 } 00120 } else { 00121 // couldn't parse the line? print the whole line. 00122 fprintf(out, " %s\n", symbollist[i]); 00123 } 00124 } 00125 00126 free(funcname); 00127 free(symbollist); 00128 } 00129 00130 /* Print a demangled stack backtrace of the caller function to syslog. */ 00131 static inline void syslog_stacktrace(int pri = LOG_ERR, 00132 unsigned int max_frames = 63) 00133 { 00134 syslog(pri, "stack trace:\n"); 00135 00136 // storage array for stack trace address data 00137 void* addrlist[max_frames+1]; 00138 00139 // retrieve current stack addresses 00140 int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(addrlist[0])); 00141 00142 if (addrlen == 0) { 00143 syslog(pri, " <empty, possibly corrupt>\n"); 00144 return; 00145 } 00146 00147 // resolve addresses into strings containing "filename(function+address)", 00148 // this array must be free()-ed 00149 char** symbollist = backtrace_symbols(addrlist, addrlen); 00150 00151 // allocate string which will be filled with the demangled function name 00152 size_t funcnamesize = 256; 00153 char* funcname = reinterpret_cast<char*>(malloc(funcnamesize)); 00154 00155 // iterate over the returned symbol lines. skip the first, it is the 00156 // address of this function. 00157 for (int i = 1; i < addrlen; i++) 00158 { 00159 char *begin_name = 0, *begin_offset = 0, *end_offset = 0; 00160 00161 // find parentheses and +address offset surrounding the mangled name: 00162 // ./module(function+0x15c) [0x8048a6d] 00163 for (char *p = symbollist[i]; *p; ++p) 00164 { 00165 if (*p == '(') 00166 begin_name = p; 00167 else if (*p == '+') 00168 begin_offset = p; 00169 else if (*p == ')' && begin_offset) { 00170 end_offset = p; 00171 break; 00172 } 00173 } 00174 00175 if (begin_name && begin_offset && end_offset 00176 && begin_name < begin_offset) 00177 { 00178 *begin_name++ = '\0'; 00179 *begin_offset++ = '\0'; 00180 *end_offset = '\0'; 00181 00182 // mangled name is now in [begin_name, begin_offset) and caller 00183 // offset in [begin_offset, end_offset). now apply 00184 // __cxa_demangle(): 00185 00186 int status; 00187 char* ret = abi::__cxa_demangle(begin_name, 00188 funcname, &funcnamesize, &status); 00189 if (status == 0) { 00190 funcname = ret; // use possibly realloc()-ed string 00191 syslog(pri, " %s : %s+%s\n", 00192 symbollist[i], funcname, begin_offset); 00193 } else { 00194 // demangling failed. Output function name as a C function with 00195 // no arguments. 00196 syslog(pri, " %s : %s()+%s\n", 00197 symbollist[i], begin_name, begin_offset); 00198 } 00199 } else { 00200 // couldn't parse the line? print the whole line. 00201 syslog(pri, " %s\n", symbollist[i]); 00202 } 00203 } 00204 00205 free(funcname); 00206 free(symbollist); 00207 } 00208 00209 00210 } 00211 } 00212 00213 00214 #endif /* BARRETT_DETAIL_STACKTRACE_H_ */