Libbarrett  1.2.4
include/barrett/detail/stacktrace.h
Go to the documentation of this file.
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_ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Defines