27 #include "kdebugdcopiface.h" 29 #include "tdeapplication.h" 30 #include "tdeglobal.h" 31 #include "kinstance.h" 32 #include "kstandarddirs.h" 34 #include <tqmessagebox.h> 37 #include <tqintdict.h> 39 #include <tqdatetime.h> 43 #include <tqstringlist.h> 57 #include <tdeconfig.h> 58 #include "kstaticdeleter.h" 64 #ifdef HAVE_ABI_CXA_DEMANGLE 72 #define PACKAGE tdelibs 73 #define PACKAGE_VERSION TDE_VERSION 77 #ifdef HAVE_DEMANGLE_H 79 #endif // HAVE_DEMANGLE_H 82 #endif // HAVE_BACKTRACE 86 #endif // HAVE_ALLOCA_H 90 #endif // HAVE_STDINT_H 97 KDebugEntry (
int n,
const TQCString& d) {number=n; descr=d;}
102 static TQIntDict<KDebugEntry> *KDebugCache;
106 static TQCString getDescrFromNum(
unsigned int _num)
109 kdd.
setObject(KDebugCache,
new TQIntDict<KDebugEntry>( 601 ));
112 KDebugCache->setAutoDelete(
true);
115 KDebugEntry *ent = KDebugCache->find( _num );
119 if ( !KDebugCache->isEmpty() )
122 TQString filename(locate(
"config",
"kdebug.areas"));
123 if (filename.isEmpty())
126 TQFile file(filename);
127 if (!file.open(IO_ReadOnly)) {
128 tqWarning(
"Couldn't open %s", filename.local8Bit().data());
134 TQCString line(1024);
137 while (( len = file.readLine(line.data(),line.size()-1) ) > 0) {
141 while (line[i] && line[i] <=
' ')
144 unsigned char ch=line[i];
146 if ( !ch || ch ==
'#' || ch ==
'\n')
149 if (ch < '0' && ch >
'9') {
150 tqWarning(
"Syntax error: no number (line %u)",lineNumber);
154 const int numStart=i;
157 }
while ( ch >=
'0' && ch <=
'9');
159 const TQ_ULONG number =line.mid(numStart,i).toULong();
161 while (line[i] && line[i] <=
' ')
164 KDebugCache->insert(number,
new KDebugEntry(number, line.mid(i, len-i-1)));
168 ent = KDebugCache->find( _num );
183 struct kDebugPrivate {
185 oldarea(0), config(0) { }
187 ~kDebugPrivate() {
delete config; }
190 unsigned int oldarea;
194 static kDebugPrivate *kDebug_data = 0;
199 static void kDebugBackend(
unsigned short nLevel,
unsigned int nArea,
const char *data)
203 pcd.
setObject(kDebug_data,
new kDebugPrivate());
208 if (!kDebugDCOPIface)
214 if (!kDebug_data->config && TDEGlobal::_instance )
216 kDebug_data->config =
new TDEConfig(
"kdebugrc",
false,
false);
217 kDebug_data->config->setGroup(
"0");
221 if ( TDEGlobal::_instance )
225 if ( kDebug_data->oldarea != nArea ) {
226 kDebug_data->oldarea = nArea;
227 if( TDEGlobal::_instance ) {
229 kDebug_data->aAreaName = getDescrFromNum(nArea);
231 if ( nArea == 0 || kDebug_data->aAreaName.isEmpty() ) {
248 nPriority = LOG_INFO;
252 aCaption =
"Warning";
253 nPriority = LOG_WARNING;
257 aCaption =
"Fatal Error";
258 nPriority = LOG_CRIT;
270 if ( kDebug_data->config ) {
271 kDebug_data->config->setGroup( TQString::number(static_cast<int>(nArea)) );
272 nOutput = kDebug_data->config->readNumEntry(key, -1);
273 if( nOutput == -1 ) {
274 kDebug_data->config->setGroup( TQString::fromAscii(
"Default") );
275 nOutput = kDebug_data->config->readNumEntry(key, -1);
282 if ( nOutput == -1 ) {
288 if ( nOutput == 1 && ( !kapp || !kapp->guiEnabled()) ) {
290 }
else if ( nOutput == 4 && nLevel != KDEBUG_FATAL ) {
294 const int BUFSIZE = 4096;
296 if ( !kDebug_data->aAreaName.isEmpty() ) {
297 strlcpy( buf, kDebug_data->aAreaName.data(), BUFSIZE );
298 strlcat( buf,
": ", BUFSIZE );
299 strlcat( buf, data, BUFSIZE );
302 strlcpy( buf, data, BUFSIZE );
314 aKey =
"InfoFilename";
317 aKey =
"WarnFilename";
320 aKey =
"FatalFilename";
324 aKey =
"ErrorFilename";
327 TQFile aOutputFile( kDebug_data->config->readPathEntry(aKey,
"kdebug.dbg") );
328 aOutputFile.open( (TQIODevice_OpenModeFlag)((
int)IO_WriteOnly | (
int)IO_Append | (
int)IO_Raw) );
329 aOutputFile.writeBlock( buf, strlen( buf ) );
337 if ( !kDebug_data->aAreaName.isEmpty() )
338 aCaption += TQString(
"(%1)").arg( QString(kDebug_data->aAreaName) );
339 TQMessageBox::warning( 0L, aCaption, data, i18n(
"&OK") );
344 if (write( 2, buf, strlen( buf ) ) < 0) {
351 syslog( nPriority,
"%s", buf);
357 if( ( nLevel == KDEBUG_FATAL )
358 && ( !kDebug_data->config || kDebug_data->config->readNumEntry(
"AbortFatal", 1 ) ) )
362 kdbgstream& perror(
kdbgstream &s) {
return s << TQString(TQString::fromLocal8Bit(strerror(errno))); }
374 : output(str.output), area(str.area), level(str.level), print(str.print)
376 str.output.truncate(0);
380 if (output.isEmpty() || !print)
382 kDebugBackend( level, area, output.local8Bit().data() );
383 output = TQString::null;
390 va_start( arguments, format );
391 vsnprintf( buf,
sizeof(buf), format, arguments );
397 kdbgstream::~kdbgstream() {
398 if (!output.isEmpty()) {
399 fprintf(stderr,
"ASSERT: debug output not ended with \\n\n");
400 TQString backtrace = kdBacktrace();
401 if (backtrace.ascii() != NULL) {
402 fprintf(stderr,
"%s", backtrace.latin1());
410 if (!print)
return *
this;
412 output +=
"\\x" + TQString::number( static_cast<uint>( ch ), 16 ).rightJustify(2,
'0');
415 if (ch ==
'\n')
flush();
422 if (!print)
return *
this;
424 output +=
"\\x" + TQString::number( ch.unicode(), 16 ).rightJustify(2,
'0');
427 if (ch == QChar(
'\n'))
flush();
434 return *this << const_cast< const TQWidget* >( widget );
439 TQString string, temp;
443 string=(TQString)
"[Null pointer]";
445 temp.setNum((ulong)widget, 16);
446 string=(TQString)
"["+widget->className()+
" pointer " 447 +
"(0x" + temp +
")";
448 if(widget->name(0)==0)
450 string +=
" to unnamed widget, ";
452 string += (TQString)
" to widget " + widget->name() +
", ";
454 string +=
"geometry=" 455 + TQString().setNum(widget->width())
456 +
"x"+TQString().setNum(widget->height())
457 +
"+"+TQString().setNum(widget->x())
458 +
"+"+TQString().setNum(widget->y())
466 if (output.at(output.length() -1 ) == QChar(
'\n'))
478 *
this << time.toString();
482 *
this << TQString(date.toString());
487 *
this << TQString(time.toString());
491 *
this <<
"(" << p.x() <<
", " << p.y() <<
")";
495 *
this <<
"[" << s.width() <<
"x" << s.height() <<
"]";
499 *
this <<
"[" << r.x() <<
"," << r.y() <<
" - " << r.width() <<
"x" << r.height() <<
"]";
505 TQMemArray<TQRect>rs=reg.rects();
506 for (uint i=0;i<rs.size();++i)
507 *
this << TQString(TQString(
"[%1,%2 - %3x%4] ").arg(rs[i].x()).arg(rs[i].y()).arg(rs[i].width()).arg(rs[i].height() )) ;
518 *
this << l.join(
",");
525 *
this << TQString(c.name());
527 *
this <<
"(invalid/default)";
531 static const char*
const s_penStyles[] = {
532 "NoPen",
"SolidLine",
"DashLine",
"DotLine",
"DashDotLine",
534 static const char*
const s_capStyles[] = {
535 "FlatCap",
"SquareCap",
"RoundCap" };
537 *
this << s_penStyles[ p.style() ];
541 if ( p.color().isValid() )
542 *
this << TQString(p.color().name());
544 *
this <<
"(invalid/default)";
547 *
this <<
" capstyle:";
548 *
this << s_capStyles[ p.capStyle() >> 4 ];
555 static const char*
const s_brushStyles[] = {
556 "NoBrush",
"SolidPattern",
"Dense1Pattern",
"Dense2Pattern",
"Dense3Pattern",
557 "Dense4Pattern",
"Dense5Pattern",
"Dense6Pattern",
"Dense7Pattern",
558 "HorPattern",
"VerPattern",
"CrossPattern",
"BDiagPattern",
"FDiagPattern",
559 "DiagCrossPattern" };
562 *
this <<s_brushStyles[ b.style() ];
565 if ( b.color().isValid() )
566 *
this << TQString(b.color().name()) ;
568 *
this <<
"(invalid/default)";
570 *
this <<
" has a pixmap";
576 *
this <<
"[variant: ";
577 *
this << v.typeName();
580 *
this <<
" toString=";
581 *
this << v.toString();
587 if (!print)
return *
this;
590 unsigned int sz = TQMIN( data.size(), 64 );
591 for ( ; i < sz ; ++i ) {
592 output += TQString::number( (
unsigned char) data[i], 16 ).rightJustify(2,
'0');
596 if ( sz < data.size() )
602 #ifdef HAVE_BACKTRACE 603 struct BacktraceFunctionInfo {
605 const char* fileName;
608 TQString functionName;
617 asymbol** bfdLoadSymtab (bfd *abfd) {
621 bfd_boolean dynamic = FALSE;
624 if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
629 symtab_sz = bfd_get_symtab_upper_bound (abfd);
630 if (symtab_sz == 0) {
631 symtab_sz = bfd_get_dynamic_symtab_upper_bound (abfd);
639 rv = (asymbol **) malloc(symtab_sz);
646 symCount = bfd_canonicalize_dynamic_symtab (abfd, rv);
648 symCount = bfd_canonicalize_symtab (abfd, rv);
661 void bfdFillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
662 static bool inited=0;
668 bfd *abfd = bfd_openr(func.fileName, 0);
674 if( !bfd_check_format(abfd, bfd_object) ) {
680 asymbol **syms= bfdLoadSymtab(abfd);
687 for (asection *sect = abfd->sections; sect != NULL; sect = sect->next) {
689 if (bfd_get_section_flags(abfd, sect) & SEC_ALLOC) {
690 bfd_vma sectStart = bfd_get_section_vma(abfd, sect);
691 bfd_vma sectEnd = sectStart + bfd_section_size(abfd, sect);
692 if (sectStart <= func.offset && func.offset < sectEnd) {
693 bfd_vma sectOffset = func.offset - sectStart;
694 const char* functionName;
695 const char* sourceName;
697 if (bfd_find_nearest_line(abfd, sect, syms, sectOffset,
698 &sourceName, &functionName, &sourceLine))
700 func.sourceName = sourceName;
701 func.sourceLine = sourceLine;
702 if(func.functionName.isEmpty()) {
703 func.functionName = TQString::fromAscii(functionName);
710 #ifdef HAVE_DEMANGLE_H 711 if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
712 char *demangled = bfd_demangle(abfd, func.functionName.ascii(), DMGL_AUTO | DMGL_PARAMS);
714 func.prettyName = demangled;
718 #endif // HAVE_DEMANGLE_H 726 #endif // WITH_LIBBFD 728 void fillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
730 bfdFillAdditionalFunctionsInfo(func);
731 #endif // WITH_LIBBFD 733 #ifdef HAVE_ABI_CXA_DEMANGLE 734 if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
736 char *demangled = abi::__cxa_demangle(func.functionName.ascii(), 0, 0, &status);
738 func.prettyName = demangled;
742 #endif // HAVE_ABI_CXA_DEMANGLE 746 TQString formatBacktrace(
void *addr) {
748 BacktraceFunctionInfo func;
754 dladdr((
void *)func.addr, &info);
756 func.fileName = info.dli_fname;
757 func.base = info.dli_fbase;
758 func.offset = (uintptr_t)func.addr - (uintptr_t)func.base;
759 func.functionName = TQString::fromAscii(info.dli_sname);
762 fillAdditionalFunctionsInfo(func);
764 rv.sprintf(
"0x%0*lx", (
int)
sizeof(
void*)*2, (uintptr_t) func.addr);
767 if (!func.prettyName.isEmpty()) {
768 rv += func.prettyName;
769 }
else if (!func.functionName.isEmpty()) {
770 rv += func.functionName;
775 if (!func.sourceName.isEmpty()) {
777 rv += func.sourceName;
779 rv += func.sourceLine ? TQString::number(func.sourceLine) :
"??";
780 }
else if (func.fileName && func.fileName[0]) {
781 rv += TQString().sprintf(
" from %s:0x%08lx",func.fileName, func.offset);
788 #endif // HAVE_BACKTRACE 791 TQString kdBacktrace(
int levels)
794 #ifdef HAVE_BACKTRACE 795 if (levels < 0 || levels > 256 ) {
803 void** trace = (
void**)alloca(levels *
sizeof(
void*));
806 #endif // HAVE_ALLOCA 807 levels = backtrace(trace, levels);
810 for (
int i = 0; i < levels; ++i) {
811 rv += QString().sprintf(
"#%-2d ", i);
812 rv += formatBacktrace(trace[i]);
816 rv +=
"backtrace() failed\n";
821 #endif // HAVE_BACKTRACE 827 TQString kdBacktrace()
829 return kdBacktrace(-1 );
832 void kdBacktraceFD(
int fd) {
833 #ifdef HAVE_BACKTRACE 837 levels = backtrace(trace, 256);
839 backtrace_symbols_fd(trace, levels, fd);
841 #endif // HAVE_BACKTRACE 843 void kdClearDebugConfig()
846 delete kDebug_data->config;
847 kDebug_data->config = 0;
854 #define kdDebug kndDebug Access KDE Configuration entries.
Represents and parses a URL.
void flush()
Flushes the output.
Little helper class to clean up static objects that are held as pointer.
TQCString instanceName() const
Returns the name of the instance.
kdbgstream is a text stream that allows you to print debug messages.
KDE_DEPRECATED type * setObject(type *obj, bool isArray=false)
Sets the object to delete and registers the object to be deleted to TDEGlobal.
static TDEInstance * instance()
Returns the global instance.
DCOP interface to KDebug.
TQString prettyURL(int _trailing=0) const
Returns the URL as string in human-friendly format.
kdbgstream & form(const char *format,...)
Prints the string format which can contain printf-style formatted values.
kdbgstream & operator<<(bool i)
Prints the given value.
static void unregisterStaticDeleter(KStaticDeleterBase *d)
Unregisters a static deleter.