00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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>
00051 #include <unistd.h>
00052 #include <stdarg.h>
00053 #include <ctype.h>
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
00071
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
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() )
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;
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
00205 TDEGlobal::unregisterStaticDeleter(&pcd);
00206
00207
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
00220
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
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
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
00279
00280
00281
00282 if ( nOutput == -1 ) {
00283 nOutput = 2;
00284 }
00285
00286
00287
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
00306 switch( nOutput )
00307 {
00308 case 0:
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:
00334 {
00335
00336
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:
00343 {
00344 if (write( 2, buf, strlen( buf ) ) < 0) {
00345
00346 }
00347 break;
00348 }
00349 case 3:
00350 {
00351 syslog( nPriority, "%s", buf);
00352 break;
00353 }
00354 }
00355
00356
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
00474
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 )
00546 {
00547 *this << " capstyle:";
00548 *this << s_capStyles[ p.capStyle() >> 4 ];
00549
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
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
00579
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;
00605 const char* fileName;
00606 const void *base;
00607 uintptr_t offset;
00608 TQString functionName;
00609 TQString prettyName;
00610 TQString sourceName;
00611 unsigned sourceLine;
00612 };
00613
00614 #ifdef WITH_LIBBFD
00615
00616
00617 asymbol** bfdLoadSymtab (bfd *abfd) {
00618 long symCount;
00619 long symtab_sz;
00620 asymbol** rv;
00621 bfd_boolean dynamic = FALSE;
00622
00623
00624 if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
00625 return 0;
00626 }
00627
00628
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
00639 rv = (asymbol **) malloc(symtab_sz);
00640 if ( !rv ) {
00641 return 0;
00642 }
00643
00644
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);
00669 if( !abfd ) {
00670 return;
00671 }
00672
00673
00674 if( !bfd_check_format(abfd, bfd_object) ) {
00675 bfd_close(abfd);
00676 return;
00677 }
00678
00679
00680 asymbol **syms= bfdLoadSymtab(abfd);
00681 if(!syms) {
00682 bfd_close(abfd);
00683 return;
00684 }
00685
00686
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
00752
00753 Dl_info info;
00754 dladdr(func.addr, &info);
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
00826
00827 TQString kdBacktrace()
00828 {
00829 return kdBacktrace(-1 );
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
00853 #ifdef NDEBUG
00854 #define kdDebug kndDebug
00855 #endif