00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #include "fennel/common/CommonPreamble.h"
00025 #include "fennel/common/Backtrace.h"
00026 #include "fennel/common/TraceTarget.h"
00027 
00028 #include <sstream>
00029 
00030 #ifndef __MSVC__
00031 #include <cxxabi.h>
00032 #endif
00033 
00034 using std::endl;
00035 using std::ostream;
00036 
00037 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/common/Backtrace.cpp#12 $");
00038 
00039 Backtrace::~Backtrace()
00040 {
00041     if (ownbuf) {
00042         delete[] addrbuf;
00043     }
00044 }
00045 
00046 Backtrace::Backtrace(size_t maxdepth)
00047     : ownbuf(true), bufsize(maxdepth + 1)
00048 {
00049 #ifndef __MSVC__
00050     addrbuf = new void * [bufsize];
00051     depth = backtrace(addrbuf, bufsize);
00052 #endif
00053 }
00054 
00055 Backtrace::Backtrace(size_t bufsize, void** buffer)
00056     : ownbuf(false), bufsize(bufsize)
00057 {
00058 #ifndef __MSVC__
00059     addrbuf = buffer;
00060     depth = backtrace(addrbuf, bufsize);
00061 #endif
00062 }
00063 
00064 
00065 
00066 
00067 void Backtrace::print(int fd) const
00068 {
00069 #ifndef __MSVC__
00070     
00071     if (depth > 1) {
00072         backtrace_symbols_fd(addrbuf + 1, depth - 1, fd);
00073     }
00074 #endif
00075 }
00076 
00077 #ifndef __MSVC__
00078 int Backtrace::lookupLibraryBase(
00079     struct dl_phdr_info *pInfo, size_t size, void *pData)
00080 {
00081     LibraryInfo *pLibInfo = reinterpret_cast<LibraryInfo *>(pData);
00082     if (strcmp(pLibInfo->pImageName, pInfo->dlpi_name) == 0) {
00083         pLibInfo->baseAddress = pInfo->dlpi_addr;
00084         return 1;
00085     }
00086     return 0;
00087 }
00088 #endif
00089 
00090 
00091 
00092 
00093 
00094 
00095 ostream& Backtrace::print(ostream& os) const
00096 {
00097 #ifndef __MSVC__
00098     char **syms = backtrace_symbols(addrbuf, depth);
00099     if (syms) {
00100         
00101         for (int i = 1; i < depth; i++) {
00102             
00103             
00104 
00105             char *pSymbol = syms[i];
00106             char *pLeftParen = strchr(pSymbol, '(');
00107             char *pPlus = strchr(pSymbol, '+');
00108             char *pLeftBracket = strchr(pSymbol, '[');
00109             char *pRightBracket = strchr(pSymbol, ']');
00110 
00111             
00112             
00113             
00114             if (pLeftParen && (pLeftParen[1] != '_')) {
00115                 pLeftParen = NULL;
00116             }
00117 
00118             if (!pLeftParen || !pPlus || (pLeftParen > pPlus)
00119                 || !pLeftBracket || !pRightBracket
00120                 || (pLeftBracket > pRightBracket)
00121                 || (pPlus > pLeftBracket))
00122             {
00123                 
00124                 os << pSymbol << endl;
00125                 continue;
00126             }
00127 
00128             
00129             
00130             
00131             *pLeftParen = 0;
00132             LibraryInfo libInfo;
00133             libInfo.baseAddress = 0;
00134             libInfo.pImageName = pSymbol;
00135             dl_iterate_phdr(lookupLibraryBase, &libInfo);
00136 
00137             
00138             os << pSymbol << '(';
00139 
00140             
00141             *pLeftParen = '(';
00142 
00143             *pPlus = 0;
00144             writeDemangled(os, pLeftParen + 1);
00145             
00146             *pPlus = '+';
00147             *pLeftBracket = 0;
00148             os << pPlus;
00149             *pLeftBracket = '[';
00150             os << '[';
00151 
00152             
00153             *pRightBracket = 0;
00154             unsigned long addr = strtoul(
00155                 pLeftBracket + 1, NULL, 16);
00156             *pRightBracket = ']';
00157             if (libInfo.baseAddress) {
00158                 addr -= libInfo.baseAddress;
00159             }
00160             os << "0x";
00161             os << std::hex;
00162             os << addr;
00163             os << std::dec;
00164             os << ']';
00165             os << endl;
00166         }
00167         free(syms);
00168     }
00169 #endif
00170     return os;
00171 }
00172 
00173 void Backtrace::writeDemangled(std::ostream &out, char const *pMangled)
00174 {
00175     int status = -3;
00176     char *pDemangled = NULL;
00177 #ifndef __MSVC__
00178     pDemangled =
00179         abi::__cxa_demangle(pMangled, NULL, NULL, &status);
00180 #endif
00181     if (status || !pDemangled) {
00182         
00183         
00184         out << pMangled;
00185     } else {
00186         out << pDemangled;
00187         free(pDemangled);
00188     }
00189 }
00190 
00191 std::ostream* AutoBacktrace::pstream = &std::cerr;
00192 SharedTraceTarget AutoBacktrace::ptrace;
00193 
00194 #ifndef __MSVC__
00195 struct sigaction AutoBacktrace::nextAction[BACKTRACE_SIG_MAX];
00196 #endif
00197 
00198 void AutoBacktrace::signal_handler(int signum)
00199 {
00200 #ifndef __MSVC__
00201     Backtrace bt;
00202     if (ptrace) {
00203         std::ostringstream oss;
00204         oss <<
00205             "*** CAUGHT SIGNAL " << signum << "; BACKTRACE:" << std::endl;
00206         oss << bt;
00207         std::string msg = oss.str();
00208         if (pstream) {
00209             *pstream << msg;
00210         }
00211         ptrace->notifyTrace("backtrace", TRACE_SEVERE, msg);
00212     } else if (pstream) {
00213         *pstream <<
00214             "*** CAUGHT SIGNAL " << signum << "; BACKTRACE:" << std::endl;
00215         *pstream << bt;
00216     }
00217 
00218     
00219     sigaction(signum, &(nextAction[signum]), NULL);
00220     raise(signum);
00221 #endif
00222 }
00223 
00224 void AutoBacktrace::setOutputStream()
00225 {
00226     pstream = 0;
00227 }
00228 
00229 void AutoBacktrace::setOutputStream(ostream& os)
00230 {
00231     pstream = &os;
00232 }
00233 
00234 void AutoBacktrace::setTraceTarget(SharedTraceTarget p)
00235 {
00236     ptrace = p;
00237 }
00238 
00239 void AutoBacktrace::install(bool includeSegFault)
00240 {
00241     
00242     
00243     
00244 #ifndef __MSVC__
00245     installSignal(SIGILL);
00246     installSignal(SIGABRT);
00247 
00248     if (includeSegFault) {
00249         installSignal(SIGSEGV);
00250     }
00251 
00252     installSignal(SIGBUS);
00253 #endif
00254 }
00255 
00256 void AutoBacktrace::installSignal(int signum)
00257 {
00258 #ifndef __MSVC__
00259     permAssert(signum < BACKTRACE_SIG_MAX);
00260     struct sigaction act;
00261     struct sigaction old_act;
00262     act.sa_handler = signal_handler;
00263     sigemptyset (&act.sa_mask);
00264     act.sa_flags = 0;
00265     int rc = sigaction(signum, &act, &old_act);
00266     if (rc) {
00267         return;                         
00268     }
00269     if (old_act.sa_handler != signal_handler) {
00270         
00271         nextAction[signum] = old_act;
00272     }
00273 #endif
00274 }
00275 
00276 FENNEL_END_CPPFILE("$Id");
00277 
00278