• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

kdebug.cpp

00001 /* This file is part of the KDE libraries
00002     Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
00003                   2002 Holger Freyther (freyther@kde.org)
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "kdebug.h"
00022 
00023 #ifdef NDEBUG
00024 #undef kdDebug
00025 #endif
00026 
00027 #include "kdebugdcopiface.h"
00028 
00029 #include "tdeapplication.h"
00030 #include "tdeglobal.h"
00031 #include "kinstance.h"
00032 #include "kstandarddirs.h"
00033 
00034 #include <tqmessagebox.h>
00035 #include <tdelocale.h>
00036 #include <tqfile.h>
00037 #include <tqintdict.h>
00038 #include <tqstring.h>
00039 #include <tqdatetime.h>
00040 #include <tqpoint.h>
00041 #include <tqrect.h>
00042 #include <tqregion.h>
00043 #include <tqstringlist.h>
00044 #include <tqpen.h>
00045 #include <tqbrush.h>
00046 #include <tqsize.h>
00047 
00048 #include <kurl.h>
00049 
00050 #include <stdlib.h> // abort
00051 #include <unistd.h> // getpid
00052 #include <stdarg.h> // vararg stuff
00053 #include <ctype.h>      // isprint
00054 #include <syslog.h>
00055 #include <errno.h>
00056 #include <cstring>
00057 #include <tdeconfig.h>
00058 #include "kstaticdeleter.h"
00059 #include <config.h>
00060 
00061 #ifdef HAVE_BACKTRACE
00062 #include <execinfo.h>
00063 
00064 #ifdef HAVE_ABI_CXA_DEMANGLE
00065 #include <cxxabi.h>
00066 #endif
00067 
00068 #include <link.h>
00069 #ifdef WITH_LIBBFD
00070 /* newer versions of libbfd require some autotools-specific macros to be defined */
00071 /* see binutils Bug 14243 and 14072 */
00072 #define PACKAGE tdelibs
00073 #define PACKAGE_VERSION TDE_VERSION
00074 
00075 #include <bfd.h>
00076 
00077 #ifdef HAVE_DEMANGLE_H
00078 #include <demangle.h>
00079 #endif // HAVE_DEMANGLE_H
00080 #endif // WITH_LIBBFD
00081 
00082 #endif // HAVE_BACKTRACE
00083 
00084 #ifdef HAVE_ALLOCA_H
00085 #include <alloca.h>
00086 #endif // HAVE_ALLOCA_H
00087 
00088 #ifdef HAVE_STDINT_H
00089 #include <stdint.h>
00090 #endif // HAVE_STDINT_H
00091 
00092 class KDebugEntry;
00093 
00094 class KDebugEntry
00095 {
00096 public:
00097     KDebugEntry (int n, const TQCString& d) {number=n; descr=d;}
00098     unsigned int number;
00099     TQCString descr;
00100 };
00101 
00102 static TQIntDict<KDebugEntry> *KDebugCache;
00103 
00104 static KStaticDeleter< TQIntDict<KDebugEntry> > kdd;
00105 
00106 static TQCString getDescrFromNum(unsigned int _num)
00107 {
00108   if (!KDebugCache) {
00109     kdd.setObject(KDebugCache, new TQIntDict<KDebugEntry>( 601 ));
00110     // Do not call this deleter from ~TDEApplication
00111     TDEGlobal::unregisterStaticDeleter(&kdd);
00112     KDebugCache->setAutoDelete(true);
00113   }
00114 
00115   KDebugEntry *ent = KDebugCache->find( _num );
00116   if ( ent )
00117     return ent->descr;
00118 
00119   if ( !KDebugCache->isEmpty() ) // areas already loaded
00120     return TQCString();
00121 
00122   TQString filename(locate("config","kdebug.areas"));
00123   if (filename.isEmpty())
00124       return TQCString();
00125 
00126   TQFile file(filename);
00127   if (!file.open(IO_ReadOnly)) {
00128     tqWarning("Couldn't open %s", filename.local8Bit().data());
00129     file.close();
00130     return TQCString();
00131   }
00132 
00133   uint lineNumber=0;
00134   TQCString line(1024);
00135   int len;
00136 
00137   while (( len = file.readLine(line.data(),line.size()-1) ) > 0) {
00138       int i=0;
00139       ++lineNumber;
00140 
00141       while (line[i] && line[i] <= ' ')
00142         i++;
00143 
00144       unsigned char ch=line[i];
00145 
00146       if ( !ch || ch =='#' || ch =='\n')
00147           continue; // We have an eof, a comment or an empty line
00148 
00149       if (ch < '0' && ch > '9') {
00150           tqWarning("Syntax error: no number (line %u)",lineNumber);
00151           continue;
00152       }
00153 
00154       const int numStart=i;
00155       do {
00156           ch=line[++i];
00157       } while ( ch >= '0' && ch <= '9');
00158 
00159       const TQ_ULONG number =line.mid(numStart,i).toULong();
00160 
00161       while (line[i] && line[i] <= ' ')
00162         i++;
00163 
00164       KDebugCache->insert(number, new KDebugEntry(number, line.mid(i, len-i-1)));
00165   }
00166   file.close();
00167 
00168   ent = KDebugCache->find( _num );
00169   if ( ent )
00170       return ent->descr;
00171 
00172   return TQCString();
00173 }
00174 
00175 enum DebugLevels {
00176     KDEBUG_INFO=    0,
00177     KDEBUG_WARN=    1,
00178     KDEBUG_ERROR=   2,
00179     KDEBUG_FATAL=   3
00180 };
00181 
00182 
00183 struct kDebugPrivate {
00184   kDebugPrivate() :
00185     oldarea(0), config(0) { }
00186 
00187   ~kDebugPrivate() { delete config; }
00188 
00189   TQCString aAreaName;
00190   unsigned int oldarea;
00191   TDEConfig *config;
00192 };
00193 
00194 static kDebugPrivate *kDebug_data = 0;
00195 static KStaticDeleter<kDebugPrivate> pcd;
00196 static KStaticDeleter<KDebugDCOPIface> dcopsd;
00197 static KDebugDCOPIface* kDebugDCOPIface = 0;
00198 
00199 static void kDebugBackend( unsigned short nLevel, unsigned int nArea, const char *data)
00200 {
00201   if ( !kDebug_data )
00202   {
00203       pcd.setObject(kDebug_data, new kDebugPrivate());
00204       // Do not call this deleter from ~TDEApplication
00205       TDEGlobal::unregisterStaticDeleter(&pcd);
00206 
00207       // create the dcop interface if it has not been created yet
00208       if (!kDebugDCOPIface)
00209       {
00210           kDebugDCOPIface = dcopsd.setObject(kDebugDCOPIface, new KDebugDCOPIface);
00211       }
00212   }
00213 
00214   if (!kDebug_data->config && TDEGlobal::_instance )
00215   {
00216       kDebug_data->config = new TDEConfig("kdebugrc", false, false);
00217       kDebug_data->config->setGroup("0");
00218 
00219       //AB: this is necessary here, otherwise all output with area 0 won't be
00220       //prefixed with anything, unless something with area != 0 is called before
00221       if ( TDEGlobal::_instance )
00222         kDebug_data->aAreaName = TDEGlobal::instance()->instanceName();
00223   }
00224 
00225   if ( kDebug_data->oldarea != nArea ) {
00226     kDebug_data->oldarea = nArea;
00227     if( TDEGlobal::_instance ) {
00228       if ( nArea > 0 ) {
00229         kDebug_data->aAreaName = getDescrFromNum(nArea);
00230       }
00231       if ( nArea == 0 || kDebug_data->aAreaName.isEmpty() ) {
00232         kDebug_data->aAreaName = TDEGlobal::instance()->instanceName();
00233       }
00234     }
00235   }
00236 
00237   int nPriority = 0;
00238   TQString aCaption;
00239 
00240     /* Determine output */
00241 
00242   TQString key;
00243   switch( nLevel )
00244   {
00245   case KDEBUG_INFO:
00246       key = "InfoOutput";
00247       aCaption = "Info";
00248       nPriority = LOG_INFO;
00249       break;
00250   case KDEBUG_WARN:
00251       key = "WarnOutput";
00252       aCaption = "Warning";
00253       nPriority = LOG_WARNING;
00254     break;
00255   case KDEBUG_FATAL:
00256       key = "FatalOutput";
00257       aCaption = "Fatal Error";
00258       nPriority = LOG_CRIT;
00259       break;
00260   case KDEBUG_ERROR:
00261   default:
00262       /* Programmer error, use "Error" as default */
00263       key = "ErrorOutput";
00264       aCaption = "Error";
00265       nPriority = LOG_ERR;
00266       break;
00267   }
00268 
00269   short nOutput = -1;
00270   if ( kDebug_data->config ) {
00271     kDebug_data->config->setGroup( TQString::number(static_cast<int>(nArea)) );
00272     nOutput = kDebug_data->config->readNumEntry(key, -1);
00273     if( nOutput == -1 ) {
00274       kDebug_data->config->setGroup( TQString::fromAscii("Default") );
00275       nOutput = kDebug_data->config->readNumEntry(key, -1);
00276     }
00277   }
00278   // if no output mode is specified default to no stderr output
00279   // NOTE: don't set this to 4 (no output) because in that case you won't be
00280   //       able to get any output from applications which don't create
00281   //       TDEApplication objects.
00282   if ( nOutput == -1 ) {
00283     nOutput = 2;
00284   }
00285 
00286   // If the application doesn't have a TQApplication object it can't use
00287   // a messagebox, as well as in case of GUI is disabled.
00288   if ( nOutput == 1 && ( !kapp || !kapp->guiEnabled()) ) {
00289     nOutput = 2;
00290   } else if ( nOutput == 4 && nLevel != KDEBUG_FATAL ) {
00291       return;
00292   }
00293 
00294   const int BUFSIZE = 4096;
00295   char buf[BUFSIZE];
00296   if ( !kDebug_data->aAreaName.isEmpty() ) {
00297       strlcpy( buf, kDebug_data->aAreaName.data(), BUFSIZE );
00298       strlcat( buf, ": ", BUFSIZE );
00299       strlcat( buf, data, BUFSIZE );
00300   }
00301   else
00302       strlcpy( buf, data, BUFSIZE );
00303 
00304 
00305   // Output
00306   switch( nOutput )
00307   {
00308   case 0: // File
00309   {
00310       const char* aKey;
00311       switch( nLevel )
00312       {
00313       case KDEBUG_INFO:
00314           aKey = "InfoFilename";
00315           break;
00316       case KDEBUG_WARN:
00317           aKey = "WarnFilename";
00318           break;
00319       case KDEBUG_FATAL:
00320           aKey = "FatalFilename";
00321           break;
00322       case KDEBUG_ERROR:
00323       default:
00324           aKey = "ErrorFilename";
00325           break;
00326       }
00327       TQFile aOutputFile( kDebug_data->config->readPathEntry(aKey, "kdebug.dbg") );
00328       aOutputFile.open( (TQIODevice_OpenModeFlag)((int)IO_WriteOnly | (int)IO_Append | (int)IO_Raw) );
00329       aOutputFile.writeBlock( buf, strlen( buf ) );
00330       aOutputFile.close();
00331       break;
00332   }
00333   case 1: // Message Box
00334   {
00335       // Since we are in tdecore here, we cannot use KMsgBox and use
00336       // TQMessageBox instead
00337       if ( !kDebug_data->aAreaName.isEmpty() )
00338           aCaption += TQString("(%1)").arg( QString(kDebug_data->aAreaName) );
00339       TQMessageBox::warning( 0L, aCaption, data, i18n("&OK") );
00340       break;
00341   }
00342   case 2: // Shell
00343   {
00344       if (write( 2, buf, strlen( buf ) ) < 0) {  //fputs( buf, stderr );
00345           // ERROR
00346       }
00347       break;
00348   }
00349   case 3: // syslog
00350   {
00351       syslog( nPriority, "%s", buf);
00352       break;
00353   }
00354   }
00355 
00356   // check if we should abort
00357   if( ( nLevel == KDEBUG_FATAL )
00358       && ( !kDebug_data->config || kDebug_data->config->readNumEntry( "AbortFatal", 1 ) ) )
00359         abort();
00360 }
00361 
00362 kdbgstream& perror( kdbgstream &s) { return s << TQString(TQString::fromLocal8Bit(strerror(errno))); }
00363 kdbgstream kdDebug(int area) { return kdbgstream(area, KDEBUG_INFO); }
00364 kdbgstream kdDebug(bool cond, int area) { if (cond) return kdbgstream(area, KDEBUG_INFO); else return kdbgstream(0, 0, false); }
00365 
00366 kdbgstream kdError(int area) { return kdbgstream("ERROR: ", area, KDEBUG_ERROR); }
00367 kdbgstream kdError(bool cond, int area) { if (cond) return kdbgstream("ERROR: ", area, KDEBUG_ERROR); else return kdbgstream(0,0,false); }
00368 kdbgstream kdWarning(int area) { return kdbgstream("WARNING: ", area, KDEBUG_WARN); }
00369 kdbgstream kdWarning(bool cond, int area) { if (cond) return kdbgstream("WARNING: ", area, KDEBUG_WARN); else return kdbgstream(0,0,false); }
00370 kdbgstream kdFatal(int area) { return kdbgstream("FATAL: ", area, KDEBUG_FATAL); }
00371 kdbgstream kdFatal(bool cond, int area) { if (cond) return kdbgstream("FATAL: ", area, KDEBUG_FATAL); else return kdbgstream(0,0,false); }
00372 
00373 kdbgstream::kdbgstream(kdbgstream &str)
00374  : output(str.output), area(str.area), level(str.level), print(str.print) 
00375 { 
00376     str.output.truncate(0); 
00377 }
00378 
00379 void kdbgstream::flush() {
00380     if (output.isEmpty() || !print)
00381     return;
00382     kDebugBackend( level, area, output.local8Bit().data() );
00383     output = TQString::null;
00384 }
00385 
00386 kdbgstream &kdbgstream::form(const char *format, ...)
00387 {
00388     char buf[4096];
00389     va_list arguments;
00390     va_start( arguments, format );
00391     vsnprintf( buf, sizeof(buf), format, arguments );
00392     va_end(arguments);
00393     *this << buf;
00394     return *this;
00395 }
00396 
00397 kdbgstream::~kdbgstream() {
00398     if (!output.isEmpty()) {
00399     fprintf(stderr, "ASSERT: debug output not ended with \\n\n");
00400         TQString backtrace = kdBacktrace();
00401         if (backtrace.ascii() != NULL) {
00402                 fprintf(stderr, "%s", backtrace.latin1());
00403         }
00404     *this << '\n';
00405     }
00406 }
00407 
00408 kdbgstream& kdbgstream::operator<< (char ch)
00409 {
00410   if (!print) return *this;
00411   if (!isprint(ch))
00412     output += "\\x" + TQString::number( static_cast<uint>( ch ), 16 ).rightJustify(2, '0');
00413   else {
00414     output += ch;
00415     if (ch == '\n') flush();
00416   }
00417   return *this;
00418 }
00419 
00420 kdbgstream& kdbgstream::operator<< (TQChar ch)
00421 {
00422   if (!print) return *this;
00423   if (!ch.isPrint())
00424     output += "\\x" + TQString::number( ch.unicode(), 16 ).rightJustify(2, '0');
00425   else {
00426     output += ch;
00427     if (ch == QChar('\n')) flush();
00428   }
00429   return *this;
00430 }
00431 
00432 kdbgstream& kdbgstream::operator<< (TQWidget* widget)
00433 {
00434     return *this << const_cast< const TQWidget* >( widget );
00435 }
00436 
00437 kdbgstream& kdbgstream::operator<< (const TQWidget* widget)
00438 {
00439   TQString string, temp;
00440   // -----
00441   if(widget==0)
00442     {
00443       string=(TQString)"[Null pointer]";
00444     } else {
00445       temp.setNum((ulong)widget, 16);
00446       string=(TQString)"["+widget->className()+" pointer "
00447     + "(0x" + temp + ")";
00448       if(widget->name(0)==0)
00449     {
00450       string += " to unnamed widget, ";
00451     } else {
00452       string += (TQString)" to widget " + widget->name() + ", ";
00453     }
00454       string += "geometry="
00455     + TQString().setNum(widget->width())
00456     + "x"+TQString().setNum(widget->height())
00457     + "+"+TQString().setNum(widget->x())
00458     + "+"+TQString().setNum(widget->y())
00459     + "]";
00460     }
00461   if (!print)
00462     {
00463       return *this;
00464     }
00465   output += string;
00466   if (output.at(output.length() -1 ) == QChar('\n'))
00467     {
00468       flush();
00469     }
00470   return *this;
00471 }
00472 /*
00473  * either use 'output' directly and do the flush if needed
00474  * or use the TQString operator which calls the char* operator
00475  *
00476  */
00477 kdbgstream& kdbgstream::operator<<( const TQDateTime& time) {
00478     *this << time.toString();
00479     return *this;
00480 }
00481 kdbgstream& kdbgstream::operator<<( const TQDate& date) {
00482     *this << TQString(date.toString());
00483 
00484     return *this;
00485 }
00486 kdbgstream& kdbgstream::operator<<( const TQTime& time ) {
00487     *this << TQString(time.toString());
00488     return *this;
00489 }
00490 kdbgstream& kdbgstream::operator<<( const TQPoint& p ) {
00491     *this << "(" << p.x() << ", " << p.y() << ")";
00492     return *this;
00493 }
00494 kdbgstream& kdbgstream::operator<<( const TQSize& s ) {
00495     *this << "[" << s.width() << "x" << s.height() << "]";
00496     return *this;
00497 }
00498 kdbgstream& kdbgstream::operator<<( const TQRect& r ) {
00499     *this << "[" << r.x() << "," << r.y() << " - " << r.width() << "x" << r.height() << "]";
00500     return *this;
00501 }
00502 kdbgstream& kdbgstream::operator<<( const TQRegion& reg ) {
00503     *this<< "[ ";
00504 
00505     TQMemArray<TQRect>rs=reg.rects();
00506     for (uint i=0;i<rs.size();++i)
00507         *this << TQString(TQString("[%1,%2 - %3x%4] ").arg(rs[i].x()).arg(rs[i].y()).arg(rs[i].width()).arg(rs[i].height() )) ;
00508 
00509     *this <<"]";
00510     return *this;
00511 }
00512 kdbgstream& kdbgstream::operator<<( const KURL& u ) {
00513     *this << u.prettyURL();
00514     return *this;
00515 }
00516 kdbgstream& kdbgstream::operator<<( const TQStringList& l ) {
00517     *this << "(";
00518     *this << l.join(",");
00519     *this << ")";
00520 
00521     return *this;
00522 }
00523 kdbgstream& kdbgstream::operator<<( const TQColor& c ) {
00524     if ( c.isValid() )
00525         *this << TQString(c.name());
00526     else
00527         *this << "(invalid/default)";
00528     return *this;
00529 }
00530 kdbgstream& kdbgstream::operator<<( const TQPen& p ) {
00531     static const char* const s_penStyles[] = {
00532         "NoPen", "SolidLine", "DashLine", "DotLine", "DashDotLine",
00533         "DashDotDotLine" };
00534     static const char* const s_capStyles[] = {
00535         "FlatCap", "SquareCap", "RoundCap" };
00536     *this << "[ style:";
00537     *this << s_penStyles[ p.style() ];
00538     *this << " width:";
00539     *this << p.width();
00540     *this << " color:";
00541     if ( p.color().isValid() )
00542         *this << TQString(p.color().name());
00543     else
00544         *this <<"(invalid/default)";
00545     if ( p.width() > 0 ) // cap style doesn't matter, otherwise
00546     {
00547         *this << " capstyle:";
00548         *this << s_capStyles[ p.capStyle() >> 4 ];
00549         // join style omitted
00550     }
00551     *this <<" ]";
00552     return *this;
00553 }
00554 kdbgstream& kdbgstream::operator<<( const TQBrush& b) {
00555     static const char* const s_brushStyles[] = {
00556         "NoBrush", "SolidPattern", "Dense1Pattern", "Dense2Pattern", "Dense3Pattern",
00557         "Dense4Pattern", "Dense5Pattern", "Dense6Pattern", "Dense7Pattern",
00558         "HorPattern", "VerPattern", "CrossPattern", "BDiagPattern", "FDiagPattern",
00559         "DiagCrossPattern" };
00560 
00561     *this <<"[ style: ";
00562     *this <<s_brushStyles[ b.style() ];
00563     *this <<" color: ";
00564     // can't use operator<<(str, b.color()) because that terminates a kdbgstream (flushes)
00565     if ( b.color().isValid() )
00566         *this << TQString(b.color().name()) ;
00567     else
00568         *this <<"(invalid/default)";
00569     if ( b.pixmap() )
00570         *this <<" has a pixmap";
00571     *this <<" ]";
00572     return *this;
00573 }
00574 
00575 kdbgstream& kdbgstream::operator<<( const TQVariant& v) {
00576     *this << "[variant: ";
00577     *this << v.typeName();
00578     // For now we just attempt a conversion to string.
00579     // Feel free to switch(v.type()) and improve the output.
00580     *this << " toString=";
00581     *this << v.toString();
00582     *this << "]";
00583     return *this;
00584 }
00585 
00586 kdbgstream& kdbgstream::operator<<( const TQByteArray& data) {
00587     if (!print) return *this;
00588     output += '[';
00589     unsigned int i = 0;
00590     unsigned int sz = TQMIN( data.size(), 64 );
00591     for ( ; i < sz ; ++i ) {
00592         output += TQString::number( (unsigned char) data[i], 16 ).rightJustify(2, '0');
00593         if ( i < sz )
00594             output += ' ';
00595     }
00596     if ( sz < data.size() )
00597         output += "...";
00598     output += ']';
00599     return *this;
00600 }
00601 
00602 #ifdef HAVE_BACKTRACE
00603 struct BacktraceFunctionInfo {
00604     const void *addr;      //< the address of function returned by backtrace()
00605     const char* fileName;  //< the file of binary owning the function (e.g. shared library or current header)
00606     const void *base;      //< the base address there the binary is loaded to
00607     uintptr_t offset;      //< offset of the function in binary (base - address)
00608     TQString functionName; //< mangled name of function
00609     TQString prettyName;   //< demangled name of function
00610     TQString sourceName;   //< name of source file function declared in
00611     unsigned sourceLine;   //< line where function defined
00612 };
00613 
00614 #ifdef WITH_LIBBFD
00615 
00616 // load symbol table from file
00617 asymbol** bfdLoadSymtab (bfd *abfd) {
00618     long symCount;  // count of entries in symbol table
00619     long symtab_sz;      // size of the table
00620     asymbol** rv;
00621     bfd_boolean dynamic = FALSE;
00622 
00623     // make shure the file has symbol table
00624     if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
00625         return 0;
00626     }
00627     
00628     // determin the amount of space we'll need to store the table
00629     symtab_sz = bfd_get_symtab_upper_bound (abfd);
00630     if (symtab_sz == 0) {
00631         symtab_sz = bfd_get_dynamic_symtab_upper_bound (abfd);
00632         dynamic = TRUE;
00633     }
00634     if (symtab_sz < 0) {
00635         return 0;
00636     }
00637     
00638     // allocate memory
00639     rv = (asymbol **) malloc(symtab_sz); // dunno, why not malloc
00640     if ( !rv ) {
00641         return 0;
00642     }
00643     
00644     // actually load the table
00645     if (dynamic) {
00646         symCount = bfd_canonicalize_dynamic_symtab (abfd, rv);
00647     } else {
00648         symCount = bfd_canonicalize_symtab (abfd, rv);
00649     }
00650     
00651     if (symCount < 0) {
00652         if (rv) {
00653             free(rv);
00654         }
00655         return 0;
00656     }
00657 
00658     return rv;
00659 }
00660 
00661 void bfdFillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
00662     static bool inited=0;
00663     if (!inited) {
00664         bfd_init();
00665         inited=1;
00666     }
00667     
00668     bfd *abfd = bfd_openr(func.fileName, 0); // a bfd object
00669     if( !abfd ) {
00670         return;
00671     }
00672     
00673     //  check format of the object
00674     if( !bfd_check_format(abfd, bfd_object) ) {
00675         bfd_close(abfd);
00676         return;
00677     } 
00678     
00679     // load symbol table
00680     asymbol **syms= bfdLoadSymtab(abfd);    
00681     if(!syms) {
00682         bfd_close(abfd);
00683         return;
00684     }
00685 
00686     // found source file and line for given address
00687     for (asection *sect = abfd->sections; sect != NULL; sect = sect->next) {
00688 
00689         if (bfd_get_section_flags(abfd, sect) & SEC_ALLOC) {
00690             bfd_vma sectStart = bfd_get_section_vma(abfd, sect);
00691             bfd_vma sectEnd   = sectStart + bfd_section_size(abfd, sect);
00692             if (sectStart <= func.offset && func.offset < sectEnd) {
00693                 bfd_vma sectOffset = func.offset - sectStart;
00694                 const char* functionName;
00695                 const char* sourceName;
00696                 unsigned sourceLine;
00697                 if (bfd_find_nearest_line(abfd, sect, syms, sectOffset, 
00698                             &sourceName, &functionName, &sourceLine))
00699                 {
00700                     func.sourceName   = sourceName;
00701                     func.sourceLine   = sourceLine;
00702                     if(func.functionName.isEmpty()) {
00703                         func.functionName = TQString::fromAscii(functionName);
00704                     }
00705                     break;
00706                 }
00707             }
00708         }
00709     }
00710 #ifdef HAVE_DEMANGLE_H  
00711     if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
00712         char *demangled = bfd_demangle(abfd, func.functionName.ascii(), DMGL_AUTO | DMGL_PARAMS);
00713         if (demangled) {
00714             func.prettyName = demangled;
00715             free(demangled);
00716         }
00717     }
00718 #endif // HAVE_DEMANGLE_H   
00719 
00720     if( syms ) {
00721         free(syms);
00722     }
00723     bfd_close(abfd);
00724 }
00725 
00726 #endif // WITH_LIBBFD
00727 
00728 void fillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
00729 #ifdef WITH_LIBBFD
00730     bfdFillAdditionalFunctionsInfo(func);
00731 #endif // WITH_LIBBFD
00732 
00733 #ifdef HAVE_ABI_CXA_DEMANGLE
00734     if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
00735         int status=0;
00736         char *demangled = abi::__cxa_demangle(func.functionName.ascii(), 0, 0, &status);
00737         if (demangled) {
00738             func.prettyName = demangled;
00739             free(demangled);
00740         }
00741     }
00742 #endif // HAVE_ABI_CXA_DEMANGLE
00743 
00744 }
00745 
00746 TQString formatBacktrace(void *addr) {
00747     TQString rv;
00748     BacktraceFunctionInfo func;
00749     func.addr = addr;
00750     
00751     // NOTE: if somebody would compile for some non-linux-glibc platform
00752     //       check if dladdr function is avalible there
00753     Dl_info info;
00754     dladdr(func.addr, &info); // obtain information about the function.
00755 
00756     func.fileName = info.dli_fname;
00757     func.base = info.dli_fbase;
00758     func.offset = (uintptr_t)func.addr - (uintptr_t)func.base;
00759     func.functionName = TQString::fromAscii(info.dli_sname);
00760     func.sourceLine = 0;
00761 
00762     fillAdditionalFunctionsInfo(func);
00763 
00764     rv.sprintf("0x%0*lx", (int) sizeof(void*)*2, (uintptr_t) func.addr);
00765     
00766     rv += " in ";
00767     if (!func.prettyName.isEmpty()) {
00768         rv += func.prettyName;
00769     } else if (!func.functionName.isEmpty()) {
00770         rv += func.functionName;
00771     } else {
00772         rv += "??";
00773     }
00774     
00775     if (!func.sourceName.isEmpty()) {
00776         rv += " in "; 
00777         rv += func.sourceName;
00778         rv += ":";
00779         rv += func.sourceLine ? TQString::number(func.sourceLine) : "??";
00780     } else if (func.fileName && func.fileName[0]) {
00781         rv += TQString().sprintf(" from %s:0x%08lx",func.fileName, func.offset);
00782     } else {
00783         rv += " from ??";
00784     }
00785     
00786     return rv;
00787 }
00788 #endif // HAVE_BACKTRACE
00789 
00790 
00791 TQString kdBacktrace(int levels)
00792 {
00793     TQString rv;
00794 #ifdef HAVE_BACKTRACE
00795     if (levels < 0 || levels > 256 ) {
00796         levels = 256;
00797     }
00798     
00799     rv = "[\n";
00800 
00801     if (levels) {
00802 #ifdef HAVE_ALLOCA
00803         void** trace = (void**)alloca(levels * sizeof(void*));
00804 #else  // HAVE_ALLOCA
00805         void* trace[256];
00806 #endif // HAVE_ALLOCA
00807         levels = backtrace(trace, levels);
00808 
00809         if (levels) { 
00810             for (int i = 0; i < levels; ++i) {
00811                 rv += QString().sprintf("#%-2d ", i);
00812                 rv += formatBacktrace(trace[i]);
00813                 rv += '\n';
00814             }
00815         } else {
00816             rv += "backtrace() failed\n";
00817         }
00818     }
00819     
00820     rv += "]\n";
00821 #endif // HAVE_BACKTRACE
00822     return rv;
00823 }
00824 
00825 // Keep for ABI compatability for some time
00826 // FIXME remove this (2013-08-18, 18:09, Fat-Zer)
00827 TQString kdBacktrace()
00828 {
00829     return kdBacktrace(-1 /*all*/);
00830 }
00831 
00832 void kdBacktraceFD(int fd) {
00833 #ifdef HAVE_BACKTRACE
00834     void *trace[256];
00835     int levels;
00836     
00837     levels = backtrace(trace, 256);
00838     if (levels) {
00839         backtrace_symbols_fd(trace, levels, fd);
00840     }
00841 #endif // HAVE_BACKTRACE
00842 }
00843 void kdClearDebugConfig()
00844 {
00845     if (kDebug_data) {
00846         delete kDebug_data->config;
00847         kDebug_data->config = 0;
00848     }
00849 }
00850 
00851 
00852 // Needed for --enable-final
00853 #ifdef NDEBUG
00854 #define kdDebug kndDebug
00855 #endif

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.6.3
This website is maintained by Timothy Pearson.