StackTrace.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2004 Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2005 Novell, Inc. All rights reserved.
00004 *
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 *
00008 *  - Redistributions of source code must retain the above copyright notice,
00009 *    this list of conditions and the following disclaimer.
00010 *
00011 *  - Redistributions in binary form must reproduce the above copyright notice,
00012 *    this list of conditions and the following disclaimer in the documentation
00013 *    and/or other materials provided with the distribution.
00014 *
00015 *  - Neither the name of Vintela, Inc., Novell, Inc., nor the names of its
00016 *    contributors may be used to endorse or promote products derived from this
00017 *    software without specific prior written permission.
00018 *
00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00022 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc., Novell, Inc., OR THE 
00023 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00024 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00025 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00026 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00027 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00028 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
00029 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030 *******************************************************************************/
00031 
00032 
00037 #include "blocxx/BLOCXX_config.h"
00038 #include "blocxx/StackTrace.hpp"
00039 
00040 #ifdef BLOCXX_WIN32
00041 #include <iostream>  // for cerr
00042 namespace BLOCXX_NAMESPACE
00043 {
00044 using std::cerr;
00045 using std::endl;
00046 void StackTrace::printStackTrace()
00047 {
00048    cerr << "StackTrace::printStackTrace not implemented yet" << endl;
00049 }
00050 }
00051 #else
00052 
00053 #include "blocxx/Exec.hpp"
00054 #include "blocxx/UnnamedPipe.hpp"
00055 #include "blocxx/Format.hpp"
00056 #include "blocxx/Array.hpp"
00057 #include <fstream>
00058 #include <iostream>  // for cerr
00059 
00060 #if defined(BLOCXX_HAVE_BACKTRACE)
00061 #include <execinfo.h>
00062 #endif
00063 
00064 #if defined(BLOCXX_HAVE_CXXABI_H)
00065 #include <cxxabi.h>
00066 #endif
00067 
00068 #ifdef BLOCXX_HAVE_UNISTD_H
00069 extern "C"
00070 {
00071 #include <unistd.h> // for getpid()
00072 }
00073 #endif
00074 
00075 namespace BLOCXX_NAMESPACE
00076 {
00077 
00078 using std::ifstream;
00079 using std::ofstream;
00080 using std::flush;
00081 
00082 #ifndef BLOCXX_DEFAULT_GDB_PATH
00083 #define BLOCXX_DEFAULT_GDB_PATH "/usr/bin/gdb"
00084 #endif
00085 
00086 // static
00087 void StackTrace::printStackTrace()
00088 {
00089    if (getenv("BLOCXX_STACKTRACE"))
00090    {
00091       // if we have the GNU backtrace functions we use them.  They don't give
00092       // as good information as gdb does, but they are orders of magnitude
00093       // faster!
00094 #ifdef BLOCXX_HAVE_BACKTRACE
00095       void *array[200];
00096       
00097       size_t size = backtrace (array, 200);
00098       char **strings = backtrace_symbols (array, size);
00099       
00100       String bt;
00101       
00102       size_t i;
00103       for (i = 0; i < size; i++)
00104       {
00105 #if defined(BLOCXX_HAVE_CXXABI_H)
00106          bt += strings[i];
00107          int status;
00108          // extract the identifier from strings[i].  It's inside of parens.
00109          char* firstparen = ::strchr(strings[i], '(');
00110          char* lastparen = ::strchr(strings[i], '+');
00111          if (firstparen != 0 && lastparen != 0 && firstparen < lastparen)
00112          {
00113             bt += ": ";
00114             *lastparen = '\0';
00115             char* realname = abi::__cxa_demangle(firstparen+1, 0, 0, &status);
00116             bt += realname;
00117             free(realname);
00118          }
00119 #else
00120          bt += strings[i];
00121 #endif
00122          bt += "\n";
00123       }
00124       
00125       free (strings);
00126       
00127       std::cerr << bt << std::endl;
00128 #else
00129       ifstream file(BLOCXX_DEFAULT_GDB_PATH);
00130       if (file)
00131       {
00132          file.close();
00133          String scriptName("/tmp/owgdb-");
00134          String outputName("/tmp/owgdbout-");
00135          // TODO: don't use getppid, get it from somewhere else!
00136          outputName += String(UInt32(::getpid()));
00137          scriptName += String(UInt32(::getpid())) + ".sh";
00138          String exeName("/proc/");
00139          exeName += String(UInt32(::getpid())) + "/exe";
00140          
00141          ofstream scriptFile(scriptName.c_str(), std::ios::out);
00142          scriptFile << "#!/bin/sh\n"
00143             << "gdb " << exeName << " " << ::getpid() << " << EOS > " << outputName << " 2>&1\n"
00144 // doesn't work with gdb 5.1           << "thread apply all bt\n"
00145             << "bt\n"
00146             << "detach\n"
00147             << "q\n"
00148             << "EOS\n" << flush;
00149          scriptFile.close();
00150          Array<String> command;
00151          command.push_back( "/bin/sh" );
00152          command.push_back( scriptName );
00153          Exec::safeSystem(command);
00154          ifstream outputFile(outputName.c_str(), std::ios::in);
00155          String output;
00156          while (outputFile)
00157          {
00158             output += String::getLine(outputFile) + "\n";
00159          }
00160          outputFile.close();
00161          unlink(outputName.c_str());
00162          unlink(scriptName.c_str());
00163          std::cerr << output << std::endl;
00164       }
00165 #endif
00166    }
00167 }
00168 
00169 } // end namespace BLOCXX_NAMESPACE
00170 
00171 #endif   // ifdef BLOCXX_WIN32

Generated on Fri Jun 16 15:39:09 2006 for blocxx by  doxygen 1.4.6