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
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)
214 kDebugDCOPIface = dcopsd.setObject(kDebugDCOPIface,
new 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 BUF_SIZE = 4096;
299 const int BUF_PID_SIZE = 20;
301 char buf_pid[BUF_PID_SIZE];
302 strlcpy(buf, TQDateTime::currentDateTime().toString(
"[yyyy/MM/dd hh:mm:ss.zzz] ").ascii(), BUF_SIZE);
303 if (!kDebug_data->aAreaName.isEmpty())
305 strlcat( buf,
"[", BUF_SIZE );
306 strlcat( buf, kDebug_data->aAreaName.data(), BUF_SIZE );
307 strlcat( buf,
"] ", BUF_SIZE );
309 snprintf(buf_pid, BUF_PID_SIZE,
"[%d] ", getpid());
310 strlcat(buf, buf_pid, BUF_SIZE);
311 strlcat(buf, data, BUF_SIZE);
322 aKey =
"InfoFilename";
325 aKey =
"WarnFilename";
328 aKey =
"FatalFilename";
332 aKey =
"ErrorFilename";
335 TQFile aOutputFile( kDebug_data->config->readPathEntry(aKey,
"kdebug.dbg") );
336 aOutputFile.open( IO_WriteOnly | IO_Append | IO_Raw );
337 aOutputFile.writeBlock( buf, strlen( buf ) );
345 if ( !kDebug_data->aAreaName.isEmpty() )
346 aCaption += TQString(
"(%1)").arg( TQString(kDebug_data->aAreaName) );
347 TQMessageBox::warning( 0L, aCaption, data,
i18n(
"&OK") );
352 if (write( 2, buf, strlen( buf ) ) < 0) {
359 syslog( nPriority,
"%s", buf);
365 if( ( nLevel == KDEBUG_FATAL )
366 && ( !kDebug_data->config || kDebug_data->config->readNumEntry(
"AbortFatal", 1 ) ) )
370 kdbgstream& perror(
kdbgstream &s) {
return s << TQString(TQString::fromLocal8Bit(strerror(errno))); }
382 : output(str.output), area(str.area), level(str.level), print(str.print)
384 str.output.truncate(0);
388 if (output.isEmpty() || !print)
390 kDebugBackend( level, area, output.local8Bit().data() );
391 output = TQString::null;
398 va_start( arguments, format );
399 vsnprintf( buf,
sizeof(buf), format, arguments );
405 kdbgstream::~kdbgstream() {
406 if (!output.isEmpty()) {
407 fprintf(stderr,
"ASSERT: debug output not ended with \\n\n");
408 TQString backtrace = kdBacktrace();
409 if (backtrace.ascii() != NULL) {
410 fprintf(stderr,
"%s", backtrace.latin1());
418 if (!print)
return *
this;
420 output +=
"\\x" + TQString::number(
static_cast<uint
>( ch ), 16 ).rightJustify(2,
'0');
423 if (ch ==
'\n')
flush();
430 if (!print)
return *
this;
432 output +=
"\\x" + TQString::number( ch.unicode(), 16 ).rightJustify(2,
'0');
435 if (ch == TQChar(
'\n'))
flush();
442 return *this << const_cast< const TQWidget* >( widget );
447 TQString string, temp;
451 string=(TQString)
"[Null pointer]";
453 temp.setNum((ulong)widget, 16);
454 string=(TQString)
"["+widget->className()+
" pointer "
455 +
"(0x" + temp +
")";
456 if(widget->name(0)==0)
458 string +=
" to unnamed widget, ";
460 string += (TQString)
" to widget " + widget->name() +
", ";
462 string +=
"geometry="
463 + TQString().setNum(widget->width())
464 +
"x"+TQString().setNum(widget->height())
465 +
"+"+TQString().setNum(widget->x())
466 +
"+"+TQString().setNum(widget->y())
474 if (output.at(output.length() -1 ) == TQChar(
'\n'))
486 *
this << time.toString();
490 *
this << TQString(date.toString());
495 *
this << TQString(time.toString());
499 *
this <<
"(" << p.x() <<
", " << p.y() <<
")";
503 *
this <<
"[" << s.width() <<
"x" << s.height() <<
"]";
507 *
this <<
"[" << r.x() <<
"," << r.y() <<
" - " << r.width() <<
"x" << r.height() <<
"]";
513 TQMemArray<TQRect>rs=reg.rects();
514 for (uint i=0;i<rs.size();++i)
515 *
this << TQString(TQString(
"[%1,%2 - %3x%4] ").arg(rs[i].x()).arg(rs[i].y()).arg(rs[i].width()).arg(rs[i].height() )) ;
526 *
this << l.join(
",");
533 *
this << TQString(c.name());
535 *
this <<
"(invalid/default)";
539 static const char*
const s_penStyles[] = {
540 "NoPen",
"SolidLine",
"DashLine",
"DotLine",
"DashDotLine",
542 static const char*
const s_capStyles[] = {
543 "FlatCap",
"SquareCap",
"RoundCap" };
545 *
this << s_penStyles[ p.style() ];
549 if ( p.color().isValid() )
550 *
this << TQString(p.color().name());
552 *
this <<
"(invalid/default)";
555 *
this <<
" capstyle:";
556 *
this << s_capStyles[ p.capStyle() >> 4 ];
563 static const char*
const s_brushStyles[] = {
564 "NoBrush",
"SolidPattern",
"Dense1Pattern",
"Dense2Pattern",
"Dense3Pattern",
565 "Dense4Pattern",
"Dense5Pattern",
"Dense6Pattern",
"Dense7Pattern",
566 "HorPattern",
"VerPattern",
"CrossPattern",
"BDiagPattern",
"FDiagPattern",
567 "DiagCrossPattern" };
570 *
this <<s_brushStyles[ b.style() ];
573 if ( b.color().isValid() )
574 *
this << TQString(b.color().name()) ;
576 *
this <<
"(invalid/default)";
578 *
this <<
" has a pixmap";
584 *
this <<
"[variant: ";
585 *
this << v.typeName();
588 *
this <<
" toString=";
589 *
this << v.toString();
595 if (!print)
return *
this;
598 unsigned int sz = TQMIN( data.size(), 64 );
599 for ( ; i < sz ; ++i ) {
600 output += TQString::number( (
unsigned char) data[i], 16 ).rightJustify(2,
'0');
604 if ( sz < data.size() )
610 #ifdef HAVE_BACKTRACE
611 struct BacktraceFunctionInfo {
613 const char* fileName;
616 TQString functionName;
625 asymbol** bfdLoadSymtab (bfd *abfd) {
629 bfd_boolean dynamic = FALSE;
632 if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
637 symtab_sz = bfd_get_symtab_upper_bound (abfd);
638 if (symtab_sz == 0) {
639 symtab_sz = bfd_get_dynamic_symtab_upper_bound (abfd);
647 rv = (asymbol **) malloc(symtab_sz);
654 symCount = bfd_canonicalize_dynamic_symtab (abfd, rv);
656 symCount = bfd_canonicalize_symtab (abfd, rv);
669 void bfdFillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
670 static bool inited=0;
676 bfd *abfd = bfd_openr(func.fileName, 0);
682 if( !bfd_check_format(abfd, bfd_object) ) {
688 asymbol **syms= bfdLoadSymtab(abfd);
695 for (asection *sect = abfd->sections; sect != NULL; sect = sect->next) {
697 if (bfd_get_section_flags(abfd, sect) & SEC_ALLOC) {
698 bfd_vma sectStart = bfd_get_section_vma(abfd, sect);
699 bfd_vma sectEnd = sectStart + bfd_section_size(abfd, sect);
700 if (sectStart <= func.offset && func.offset < sectEnd) {
701 bfd_vma sectOffset = func.offset - sectStart;
702 const char* functionName;
703 const char* sourceName;
705 if (bfd_find_nearest_line(abfd, sect, syms, sectOffset,
706 &sourceName, &functionName, &sourceLine))
708 func.sourceName = sourceName;
709 func.sourceLine = sourceLine;
710 if(func.functionName.isEmpty()) {
711 func.functionName = TQString::fromAscii(functionName);
718 #ifdef HAVE_DEMANGLE_H
719 if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
720 char *demangled = bfd_demangle(abfd, func.functionName.ascii(), DMGL_AUTO | DMGL_PARAMS);
722 func.prettyName = demangled;
736 void fillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
738 bfdFillAdditionalFunctionsInfo(func);
741 #ifdef HAVE_ABI_CXA_DEMANGLE
742 if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
744 char *demangled = abi::__cxa_demangle(func.functionName.ascii(), 0, 0, &status);
746 func.prettyName = demangled;
754 TQString formatBacktrace(
void *addr) {
756 BacktraceFunctionInfo func;
765 dladdr((
void *)func.addr, &info);
767 dladdr(func.addr, &info);
770 func.fileName = info.dli_fname;
771 func.base = info.dli_fbase;
772 func.offset = (uintptr_t)func.addr - (uintptr_t)func.base;
773 func.functionName = TQString::fromAscii(info.dli_sname);
776 fillAdditionalFunctionsInfo(func);
778 rv.sprintf(
"0x%0*lx", (
int)
sizeof(
void*)*2, (uintptr_t) func.addr);
781 if (!func.prettyName.isEmpty()) {
782 rv += func.prettyName;
783 }
else if (!func.functionName.isEmpty()) {
784 rv += func.functionName;
789 if (!func.sourceName.isEmpty()) {
791 rv += func.sourceName;
793 rv += func.sourceLine ? TQString::number(func.sourceLine) :
"??";
794 }
else if (func.fileName && func.fileName[0]) {
795 rv += TQString().sprintf(
" from %s:0x%08lx",func.fileName, func.offset);
808 #ifdef HAVE_BACKTRACE
809 if (levels < 0 || levels > 256 ) {
817 void** trace = (
void**)alloca(levels *
sizeof(
void*));
821 levels = backtrace(trace, levels);
824 for (
int i = 0; i < levels; ++i) {
825 rv += TQString().sprintf(
"#%-2d ", i);
826 rv += formatBacktrace(trace[i]);
830 rv +=
"backtrace() failed\n";
847 #ifdef HAVE_BACKTRACE
851 levels = backtrace(trace, 256);
853 backtrace_symbols_fd(trace, levels, fd);
860 delete kDebug_data->config;
861 kDebug_data->config = 0;
868 #define kdDebug kndDebug
DCOP interface to KDebug.
Little helper class to clean up static objects that are held as pointer.
Represents and parses a URL.
TQString prettyURL(int _trailing=0) const
Returns the URL as string in human-friendly format.
Access KDE Configuration entries.
static void unregisterStaticDeleter(KStaticDeleterBase *d)
Unregisters a static deleter.
static TDEInstance * instance()
Returns the global instance.
TQCString instanceName() const
Returns the name of the instance.
TQString i18n(const char *text)
i18n is the function that does everything you need to translate a string.
kdbgstream is a text stream that allows you to print debug messages.
void flush()
Flushes the output.
kdbgstream & operator<<(bool i)
Prints the given value.
kdbgstream & form(const char *format,...)
Prints the string format which can contain printf-style formatted values.
kdbgstream kdFatal(int area=0)
Returns a fatal error stream.
void kdBacktraceFD(int fd=2)
Writes a backtrace to the given file descriptor.
TQString kdBacktrace(int levels=-1)
Returns a backtrace.
kdbgstream kdWarning(int area=0)
Returns a warning stream.
void kdClearDebugConfig()
Deletes the kdebugrc cache and therefore forces KDebug to reread the config file.
kdbgstream kdError(int area=0)
Returns an error stream.
kdbgstream kdDebug(int area=0)
Returns a debug stream.
TQString locate(const char *type, const TQString &filename, const TDEInstance *instance=TDEGlobal::instance())