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, TQDateTime::currentDateTime().toString("[yyyy/MM/dd hh:mm:ss.zzz] [").ascii(), BUFSIZE ); 00298 strlcat( buf, kDebug_data->aAreaName.data(), BUFSIZE ); 00299 strlcat( buf, "] ", BUFSIZE ); 00300 strlcat( buf, data, BUFSIZE ); 00301 } 00302 else { 00303 strlcpy( buf, TQDateTime::currentDateTime().toString("[yyyy/MM/dd hh:mm:ss.zzz] ").ascii(), BUFSIZE ); 00304 strlcat( buf, data, BUFSIZE ); 00305 } 00306 00307 // Output 00308 switch( nOutput ) 00309 { 00310 case 0: // File 00311 { 00312 const char* aKey; 00313 switch( nLevel ) 00314 { 00315 case KDEBUG_INFO: 00316 aKey = "InfoFilename"; 00317 break; 00318 case KDEBUG_WARN: 00319 aKey = "WarnFilename"; 00320 break; 00321 case KDEBUG_FATAL: 00322 aKey = "FatalFilename"; 00323 break; 00324 case KDEBUG_ERROR: 00325 default: 00326 aKey = "ErrorFilename"; 00327 break; 00328 } 00329 TQFile aOutputFile( kDebug_data->config->readPathEntry(aKey, "kdebug.dbg") ); 00330 aOutputFile.open( (TQIODevice_OpenModeFlag)((int)IO_WriteOnly | (int)IO_Append | (int)IO_Raw) ); 00331 aOutputFile.writeBlock( buf, strlen( buf ) ); 00332 aOutputFile.close(); 00333 break; 00334 } 00335 case 1: // Message Box 00336 { 00337 // Since we are in tdecore here, we cannot use KMsgBox and use 00338 // TQMessageBox instead 00339 if ( !kDebug_data->aAreaName.isEmpty() ) 00340 aCaption += TQString("(%1)").arg( QString(kDebug_data->aAreaName) ); 00341 TQMessageBox::warning( 0L, aCaption, data, i18n("&OK") ); 00342 break; 00343 } 00344 case 2: // Shell 00345 { 00346 if (write( 2, buf, strlen( buf ) ) < 0) { //fputs( buf, stderr ); 00347 // ERROR 00348 } 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 = TQMIN( 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