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