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"
68 #ifdef HAVE_ABI_CXA_DEMANGLE
76 #define PACKAGE tdelibs
77 #define PACKAGE_VERSION TDE_VERSION
81 #ifdef HAVE_DEMANGLE_H
83 #endif // HAVE_DEMANGLE_H
86 #endif // HAVE_BACKTRACE
90 #endif // HAVE_ALLOCA_H
94 #endif // HAVE_STDINT_H
101 KDebugEntry (
int n,
const TQCString& d) {number=n; descr=d;}
106 static TQIntDict<KDebugEntry> *KDebugCache;
110 static TQCString getDescrFromNum(
unsigned int _num)
113 kdd.
setObject(KDebugCache,
new TQIntDict<KDebugEntry>( 601 ));
116 KDebugCache->setAutoDelete(
true);
119 KDebugEntry *ent = KDebugCache->find( _num );
123 if ( !KDebugCache->isEmpty() )
126 TQString filename(
locate(
"config",
"kdebug.areas"));
127 if (filename.isEmpty())
130 TQFile file(filename);
131 if (!file.open(IO_ReadOnly)) {
132 tqWarning(
"Couldn't open %s", filename.local8Bit().data());
138 TQCString line(1024);
141 while (( len = file.readLine(line.data(),line.size()-1) ) > 0) {
145 while (line[i] && line[i] <=
' ')
148 unsigned char ch=line[i];
150 if ( !ch || ch ==
'#' || ch ==
'\n')
153 if (ch < '0' && ch >
'9') {
154 tqWarning(
"Syntax error: no number (line %u)",lineNumber);
158 const int numStart=i;
161 }
while ( ch >=
'0' && ch <=
'9');
163 const TQ_ULONG number =line.mid(numStart,i).toULong();
165 while (line[i] && line[i] <=
' ')
168 KDebugCache->insert(number,
new KDebugEntry(number, line.mid(i, len-i-1)));
172 ent = KDebugCache->find( _num );
187 struct kDebugPrivate {
189 oldarea(0), config(0) { }
191 ~kDebugPrivate() {
delete config; }
194 unsigned int oldarea;
198 static kDebugPrivate *kDebug_data = 0;
203 static void kDebugBackend(
unsigned short nLevel,
unsigned int nArea,
const char *data)
207 pcd.
setObject(kDebug_data,
new kDebugPrivate());
212 if (!kDebugDCOPIface)
218 if (!kDebug_data->config && TDEGlobal::_instance )
220 kDebug_data->config =
new TDEConfig(
"kdebugrc",
false,
false);
221 kDebug_data->config->setGroup(
"0");
225 if ( TDEGlobal::_instance )
229 if ( kDebug_data->oldarea != nArea ) {
230 kDebug_data->oldarea = nArea;
231 if( TDEGlobal::_instance ) {
233 kDebug_data->aAreaName = getDescrFromNum(nArea);
235 if ( nArea == 0 || kDebug_data->aAreaName.isEmpty() ) {
252 nPriority = LOG_INFO;
256 aCaption =
"Warning";
257 nPriority = LOG_WARNING;
261 aCaption =
"Fatal Error";
262 nPriority = LOG_CRIT;
274 if ( kDebug_data->config ) {
275 kDebug_data->config->setGroup( TQString::number(static_cast<int>(nArea)) );
276 nOutput = kDebug_data->config->readNumEntry(key, -1);
277 if( nOutput == -1 ) {
278 kDebug_data->config->setGroup( TQString::fromAscii(
"Default") );
279 nOutput = kDebug_data->config->readNumEntry(key, -1);
286 if ( nOutput == -1 ) {
292 if ( nOutput == 1 && ( !kapp || !kapp->guiEnabled()) ) {
294 }
else if ( nOutput == 4 && nLevel != KDEBUG_FATAL ) {
298 const int BUFSIZE = 4096;
300 if ( !kDebug_data->aAreaName.isEmpty() ) {
301 strlcpy( buf, TQDateTime::currentDateTime().toString(
"[yyyy/MM/dd hh:mm:ss.zzz] [").ascii(), BUFSIZE );
302 strlcat( buf, kDebug_data->aAreaName.data(), BUFSIZE );
303 strlcat( buf,
"] ", BUFSIZE );
304 strlcat( buf, data, BUFSIZE );
307 strlcpy( buf, TQDateTime::currentDateTime().toString(
"[yyyy/MM/dd hh:mm:ss.zzz] ").ascii(), BUFSIZE );
308 strlcat( buf, data, BUFSIZE );
320 aKey =
"InfoFilename";
323 aKey =
"WarnFilename";
326 aKey =
"FatalFilename";
330 aKey =
"ErrorFilename";
333 TQFile aOutputFile( kDebug_data->config->readPathEntry(aKey,
"kdebug.dbg") );
334 aOutputFile.open( (TQIODevice_OpenModeFlag)((
int)IO_WriteOnly | (
int)IO_Append | (
int)IO_Raw) );
335 aOutputFile.writeBlock( buf, strlen( buf ) );
343 if ( !kDebug_data->aAreaName.isEmpty() )
344 aCaption += TQString(
"(%1)").arg( QString(kDebug_data->aAreaName) );
345 TQMessageBox::warning( 0L, aCaption, data,
i18n(
"&OK") );
350 if (write( 2, buf, strlen( buf ) ) < 0) {
357 syslog( nPriority,
"%s", buf);
363 if( ( nLevel == KDEBUG_FATAL )
364 && ( !kDebug_data->config || kDebug_data->config->readNumEntry(
"AbortFatal", 1 ) ) )
368 kdbgstream& perror(
kdbgstream &s) {
return s << TQString(TQString::fromLocal8Bit(strerror(errno))); }
380 : output(str.output), area(str.area), level(str.level), print(str.print)
382 str.output.truncate(0);
386 if (output.isEmpty() || !print)
388 kDebugBackend( level, area, output.local8Bit().data() );
389 output = TQString::null;
396 va_start( arguments, format );
397 vsnprintf( buf,
sizeof(buf), format, arguments );
403 kdbgstream::~kdbgstream() {
404 if (!output.isEmpty()) {
405 fprintf(stderr,
"ASSERT: debug output not ended with \\n\n");
406 TQString backtrace = kdBacktrace();
407 if (backtrace.ascii() != NULL) {
408 fprintf(stderr,
"%s", backtrace.latin1());
416 if (!print)
return *
this;
418 output +=
"\\x" + TQString::number( static_cast<uint>( ch ), 16 ).rightJustify(2,
'0');
421 if (ch ==
'\n')
flush();
428 if (!print)
return *
this;
430 output +=
"\\x" + TQString::number( ch.unicode(), 16 ).rightJustify(2,
'0');
433 if (ch == QChar(
'\n'))
flush();
440 return *this << const_cast< const TQWidget* >( widget );
445 TQString string, temp;
449 string=(TQString)
"[Null pointer]";
451 temp.setNum((ulong)widget, 16);
452 string=(TQString)
"["+widget->className()+
" pointer "
453 +
"(0x" + temp +
")";
454 if(widget->name(0)==0)
456 string +=
" to unnamed widget, ";
458 string += (TQString)
" to widget " + widget->name() +
", ";
460 string +=
"geometry="
461 + TQString().setNum(widget->width())
462 +
"x"+TQString().setNum(widget->height())
463 +
"+"+TQString().setNum(widget->x())
464 +
"+"+TQString().setNum(widget->y())
472 if (output.at(output.length() -1 ) == QChar(
'\n'))
484 *
this << time.toString();
488 *
this << TQString(date.toString());
493 *
this << TQString(time.toString());
497 *
this <<
"(" << p.x() <<
", " << p.y() <<
")";
501 *
this <<
"[" << s.width() <<
"x" << s.height() <<
"]";
505 *
this <<
"[" << r.x() <<
"," << r.y() <<
" - " << r.width() <<
"x" << r.height() <<
"]";
511 TQMemArray<TQRect>rs=reg.rects();
512 for (uint i=0;i<rs.size();++i)
513 *
this << TQString(TQString(
"[%1,%2 - %3x%4] ").arg(rs[i].x()).arg(rs[i].y()).arg(rs[i].width()).arg(rs[i].height() )) ;
524 *
this << l.join(
",");
531 *
this << TQString(c.name());
533 *
this <<
"(invalid/default)";
537 static const char*
const s_penStyles[] = {
538 "NoPen",
"SolidLine",
"DashLine",
"DotLine",
"DashDotLine",
540 static const char*
const s_capStyles[] = {
541 "FlatCap",
"SquareCap",
"RoundCap" };
543 *
this << s_penStyles[ p.style() ];
547 if ( p.color().isValid() )
548 *
this << TQString(p.color().name());
550 *
this <<
"(invalid/default)";
553 *
this <<
" capstyle:";
554 *
this << s_capStyles[ p.capStyle() >> 4 ];
561 static const char*
const s_brushStyles[] = {
562 "NoBrush",
"SolidPattern",
"Dense1Pattern",
"Dense2Pattern",
"Dense3Pattern",
563 "Dense4Pattern",
"Dense5Pattern",
"Dense6Pattern",
"Dense7Pattern",
564 "HorPattern",
"VerPattern",
"CrossPattern",
"BDiagPattern",
"FDiagPattern",
565 "DiagCrossPattern" };
568 *
this <<s_brushStyles[ b.style() ];
571 if ( b.color().isValid() )
572 *
this << TQString(b.color().name()) ;
574 *
this <<
"(invalid/default)";
576 *
this <<
" has a pixmap";
582 *
this <<
"[variant: ";
583 *
this << v.typeName();
586 *
this <<
" toString=";
587 *
this << v.toString();
593 if (!print)
return *
this;
596 unsigned int sz = TQMIN( data.size(), 64 );
597 for ( ; i < sz ; ++i ) {
598 output += TQString::number( (
unsigned char) data[i], 16 ).rightJustify(2,
'0');
602 if ( sz < data.size() )
608 #ifdef HAVE_BACKTRACE
609 struct BacktraceFunctionInfo {
611 const char* fileName;
614 TQString functionName;
623 asymbol** bfdLoadSymtab (bfd *abfd) {
627 bfd_boolean dynamic = FALSE;
630 if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
635 symtab_sz = bfd_get_symtab_upper_bound (abfd);
636 if (symtab_sz == 0) {
637 symtab_sz = bfd_get_dynamic_symtab_upper_bound (abfd);
645 rv = (asymbol **) malloc(symtab_sz);
652 symCount = bfd_canonicalize_dynamic_symtab (abfd, rv);
654 symCount = bfd_canonicalize_symtab (abfd, rv);
667 void bfdFillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
668 static bool inited=0;
674 bfd *abfd = bfd_openr(func.fileName, 0);
680 if( !bfd_check_format(abfd, bfd_object) ) {
686 asymbol **syms= bfdLoadSymtab(abfd);
693 for (asection *sect = abfd->sections; sect != NULL; sect = sect->next) {
695 if (bfd_get_section_flags(abfd, sect) & SEC_ALLOC) {
696 bfd_vma sectStart = bfd_get_section_vma(abfd, sect);
697 bfd_vma sectEnd = sectStart + bfd_section_size(abfd, sect);
698 if (sectStart <= func.offset && func.offset < sectEnd) {
699 bfd_vma sectOffset = func.offset - sectStart;
700 const char* functionName;
701 const char* sourceName;
703 if (bfd_find_nearest_line(abfd, sect, syms, sectOffset,
704 &sourceName, &functionName, &sourceLine))
706 func.sourceName = sourceName;
707 func.sourceLine = sourceLine;
708 if(func.functionName.isEmpty()) {
709 func.functionName = TQString::fromAscii(functionName);
716 #ifdef HAVE_DEMANGLE_H
717 if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
718 char *demangled = bfd_demangle(abfd, func.functionName.ascii(), DMGL_AUTO | DMGL_PARAMS);
720 func.prettyName = demangled;
724 #endif // HAVE_DEMANGLE_H
732 #endif // WITH_LIBBFD
734 void fillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
736 bfdFillAdditionalFunctionsInfo(func);
737 #endif // WITH_LIBBFD
739 #ifdef HAVE_ABI_CXA_DEMANGLE
740 if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
742 char *demangled = abi::__cxa_demangle(func.functionName.ascii(), 0, 0, &status);
744 func.prettyName = demangled;
748 #endif // HAVE_ABI_CXA_DEMANGLE
752 TQString formatBacktrace(
void *addr) {
754 BacktraceFunctionInfo func;
760 dladdr(func.addr, &info);
762 func.fileName = info.dli_fname;
763 func.base = info.dli_fbase;
764 func.offset = (uintptr_t)func.addr - (uintptr_t)func.base;
765 func.functionName = TQString::fromAscii(info.dli_sname);
768 fillAdditionalFunctionsInfo(func);
770 rv.sprintf(
"0x%0*lx", (
int)
sizeof(
void*)*2, (uintptr_t) func.addr);
773 if (!func.prettyName.isEmpty()) {
774 rv += func.prettyName;
775 }
else if (!func.functionName.isEmpty()) {
776 rv += func.functionName;
781 if (!func.sourceName.isEmpty()) {
783 rv += func.sourceName;
785 rv += func.sourceLine ? TQString::number(func.sourceLine) :
"??";
786 }
else if (func.fileName && func.fileName[0]) {
787 rv += TQString().sprintf(
" from %s:0x%08lx",func.fileName, func.offset);
794 #endif // HAVE_BACKTRACE
800 #ifdef HAVE_BACKTRACE
801 if (levels < 0 || levels > 256 ) {
809 void** trace = (
void**)alloca(levels *
sizeof(
void*));
812 #endif // HAVE_ALLOCA
813 levels = backtrace(trace, levels);
816 for (
int i = 0; i < levels; ++i) {
817 rv += QString().sprintf(
"#%-2d ", i);
818 rv += formatBacktrace(trace[i]);
822 rv +=
"backtrace() failed\n";
827 #endif // HAVE_BACKTRACE
839 #ifdef HAVE_BACKTRACE
843 levels = backtrace(trace, 256);
845 backtrace_symbols_fd(trace, levels, fd);
847 #endif // HAVE_BACKTRACE
852 delete kDebug_data->config;
853 kDebug_data->config = 0;
860 #define kdDebug kndDebug
Access KDE Configuration entries.
Represents and parses a URL.
TQString kdBacktrace(int levels=-1)
void flush()
Flushes the output.
Little helper class to clean up static objects that are held as pointer.
kdbgstream kdError(int area=0)
kdbgstream is a text stream that allows you to print debug messages.
kdbgstream kdDebug(int area=0)
TQString i18n(const char *text)
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.
kdbgstream kdWarning(int area=0)
DCOP interface to KDebug.
kdbgstream & form(const char *format,...)
Prints the string format which can contain printf-style formatted values.
void kdBacktraceFD(int fd=2)
TQCString instanceName() const
Returns the name of the instance.
kdbgstream kdFatal(int area=0)
void kdClearDebugConfig()
TQString locate(const char *type, const TQString &filename, const TDEInstance *instance=TDEGlobal::instance())
kdbgstream & operator<<(bool i)
Prints the given value.
static void unregisterStaticDeleter(KStaticDeleterBase *d)
Unregisters a static deleter.
TQString prettyURL(int _trailing=0) const
Returns the URL as string in human-friendly format.