Backtrace.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/common/Backtrace.cpp#12 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2005-2009 SQLstream, Inc.
00006 // Copyright (C) 2005-2009 LucidEra, Inc.
00007 // Portions Copyright (C) 1999-2009 John V. Sichi
00008 //
00009 // This program is free software; you can redistribute it and/or modify it
00010 // under the terms of the GNU General Public License as published by the Free
00011 // Software Foundation; either version 2 of the License, or (at your option)
00012 // any later version approved by The Eigenbase Project.
00013 //
00014 // This program is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU General Public License
00020 // along with this program; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 // NOTE: mberkowitz 22-Dec-2005 Not implemented on mingw:
00065 //  could use signal() in lieu of sigaction(), but is there backtrace()?
00066 
00067 void Backtrace::print(int fd) const
00068 {
00069 #ifndef __MSVC__
00070     // skip 1st stack frame (the Backtrace constructor)
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 // NOTE jvs 25-Dec-2005:  we could theoretically call the addr2line utility
00091 // from this method to produce source file/line numbers directly, but
00092 // that seems like tempting fate given the handler context in which this
00093 // method may be called.  Instead, we defer that to the
00094 // open/util/bin/analyzeBacktrace utility.
00095 ostream& Backtrace::print(ostream& os) const
00096 {
00097 #ifndef __MSVC__
00098     char **syms = backtrace_symbols(addrbuf, depth);
00099     if (syms) {
00100         // skip 1st stack frame (the Backtrace constructor)
00101         for (int i = 1; i < depth; i++) {
00102             // Attempt to demangle C++ function names.
00103             // Input is of the form "imagename(mangledname+offset) [0xaddr]"
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             // Special case:  unmangled C names like 'main' can't
00112             // go through the demangler, so skip anything that
00113             // doesn't start with an underscore
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                 // Unrecognized format; dump as is.
00124                 os << pSymbol << endl;
00125                 continue;
00126             }
00127 
00128             // attempt to determine the library base address if the
00129             // absolute address is in a region of memory mapped to a .so;
00130             // lookup "imagename" in list of loaded libraries
00131             *pLeftParen = 0;
00132             LibraryInfo libInfo;
00133             libInfo.baseAddress = 0;
00134             libInfo.pImageName = pSymbol;
00135             dl_iterate_phdr(lookupLibraryBase, &libInfo);
00136 
00137             // dump everything up to lparen
00138             os << pSymbol << '(';
00139 
00140             // restore lparen we zeroed out earlier
00141             *pLeftParen = '(';
00142 
00143             *pPlus = 0;
00144             writeDemangled(os, pLeftParen + 1);
00145             // dump plus and everything up to lbracket
00146             *pPlus = '+';
00147             *pLeftBracket = 0;
00148             os << pPlus;
00149             *pLeftBracket = '[';
00150             os << '[';
00151 
00152             // apply .so base address bias if relevant and available
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         // non-zero status means demangling failed;
00183         // use mangled name instead
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     // invoke next handler: never coming back, so reset the signal handler
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     // Traps SIGABRT: this handles assert(); unless NDEBUG, permAssert() =>
00242     // assert(), so that's covered. std::terminate() also => abort().  TODO:
00243     // trap permAssert() directly.
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;                         // failed
00268     }
00269     if (old_act.sa_handler != signal_handler) {
00270         // installed for the first time
00271         nextAction[signum] = old_act;
00272     }
00273 #endif
00274 }
00275 
00276 FENNEL_END_CPPFILE("$Id");
00277 // End Backtrace.cpp
00278 

Generated on Mon Jun 22 04:00:17 2009 for Fennel by  doxygen 1.5.1