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

kdecore

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

kdecore

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

kdecore

Skip menu "kdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdecore by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |