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, 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
00308 switch( nOutput )
00309 {
00310 case 0:
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:
00336 {
00337
00338
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:
00345 {
00346 if (write( 2, buf, strlen( buf ) ) < 0) {
00347
00348 }
00349 break;
00350 }
00351 case 3:
00352 {
00353 syslog( nPriority, "%s", buf);
00354 break;
00355 }
00356 }
00357
00358
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
00476
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 )
00548 {
00549 *this << " capstyle:";
00550 *this << s_capStyles[ p.capStyle() >> 4 ];
00551
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
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
00581
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;
00607 const char* fileName;
00608 const void *base;
00609 uintptr_t offset;
00610 TQString functionName;
00611 TQString prettyName;
00612 TQString sourceName;
00613 unsigned sourceLine;
00614 };
00615
00616 #ifdef WITH_LIBBFD
00617
00618
00619 asymbol** bfdLoadSymtab (bfd *abfd) {
00620 long symCount;
00621 long symtab_sz;
00622 asymbol** rv;
00623 bfd_boolean dynamic = FALSE;
00624
00625
00626 if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
00627 return 0;
00628 }
00629
00630
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
00641 rv = (asymbol **) malloc(symtab_sz);
00642 if ( !rv ) {
00643 return 0;
00644 }
00645
00646
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);
00671 if( !abfd ) {
00672 return;
00673 }
00674
00675
00676 if( !bfd_check_format(abfd, bfd_object) ) {
00677 bfd_close(abfd);
00678 return;
00679 }
00680
00681
00682 asymbol **syms= bfdLoadSymtab(abfd);
00683 if(!syms) {
00684 bfd_close(abfd);
00685 return;
00686 }
00687
00688
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
00754
00755 Dl_info info;
00756 dladdr(func.addr, &info);
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
00828
00829 TQString kdBacktrace()
00830 {
00831 return kdBacktrace(-1 );
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
00855 #ifdef NDEBUG
00856 #define kdDebug kndDebug
00857 #endif