27#include "kdebugdcopiface.h"
29#include "tdeapplication.h"
31#include "tdeinstance.h"
32#include "tdestandarddirs.h"
34#include <tqmessagebox.h>
39#include <tqdatetime.h>
43#include <tqstringlist.h>
59#include "kstaticdeleter.h"
69#ifdef HAVE_ABI_CXA_DEMANGLE
77#define PACKAGE tdelibs
78#define PACKAGE_VERSION TDE_VERSION
102 KDebugEntry (
int n,
const TQCString& d) {number=n; descr=d;}
107static TQIntDict<KDebugEntry> *KDebugCache;
111static TQCString getDescrFromNum(
unsigned int _num)
114 kdd.setObject(KDebugCache,
new TQIntDict<KDebugEntry>( 601 ));
117 KDebugCache->setAutoDelete(
true);
120 KDebugEntry *ent = KDebugCache->find( _num );
124 if ( !KDebugCache->isEmpty() )
127 TQString filename(
locate(
"config",
"kdebug.areas"));
128 if (filename.isEmpty())
131 TQFile file(filename);
132 if (!file.open(IO_ReadOnly)) {
133 tqWarning(
"Couldn't open %s", filename.local8Bit().data());
139 TQCString line(1024);
142 while (( len = file.readLine(line.data(),line.size()-1) ) > 0) {
146 while (line[i] && line[i] <=
' ')
149 unsigned char ch=line[i];
151 if ( !ch || ch ==
'#' || ch ==
'\n')
154 if (ch < '0' && ch >
'9') {
155 tqWarning(
"Syntax error: no number (line %u)",lineNumber);
159 const int numStart=i;
162 }
while ( ch >=
'0' && ch <=
'9');
164 const TQ_ULONG number =line.mid(numStart,i).toULong();
166 while (line[i] && line[i] <=
' ')
169 KDebugCache->insert(number,
new KDebugEntry(number, line.mid(i, len-i-1)));
173 ent = KDebugCache->find( _num );
188struct kDebugPrivate {
190 oldarea(0), config(0) { }
192 ~kDebugPrivate() {
delete config; }
195 unsigned int oldarea;
199static kDebugPrivate *kDebug_data = 0;
204static void kDebugBackend(
unsigned short nLevel,
unsigned int nArea,
const char *data)
208 pcd.setObject(kDebug_data,
new kDebugPrivate());
213 if (!kDebugDCOPIface)
215 kDebugDCOPIface = dcopsd.setObject(kDebugDCOPIface,
new KDebugDCOPIface);
219 if (!kDebug_data->config && TDEGlobal::_instance )
221 kDebug_data->config =
new TDEConfig(
"kdebugrc",
false,
false);
222 kDebug_data->config->setGroup(
"0");
226 if ( TDEGlobal::_instance )
230 if ( kDebug_data->oldarea != nArea ) {
231 kDebug_data->oldarea = nArea;
232 if( TDEGlobal::_instance ) {
234 kDebug_data->aAreaName = getDescrFromNum(nArea);
236 if ( nArea == 0 || kDebug_data->aAreaName.isEmpty() ) {
253 nPriority = LOG_INFO;
257 aCaption =
"Warning";
258 nPriority = LOG_WARNING;
262 aCaption =
"Fatal Error";
263 nPriority = LOG_CRIT;
275 if ( kDebug_data->config ) {
276 kDebug_data->config->setGroup( TQString::number(
static_cast<int>(nArea)) );
277 nOutput = kDebug_data->config->readNumEntry(key, -1);
278 if( nOutput == -1 ) {
279 kDebug_data->config->setGroup( TQString::fromAscii(
"Default") );
280 nOutput = kDebug_data->config->readNumEntry(key, -1);
287 if ( nOutput == -1 ) {
293 if ( nOutput == 1 && ( !tdeApp || !tdeApp->guiEnabled()) ) {
295 }
else if ( nOutput == 4 && nLevel != KDEBUG_FATAL ) {
299 const int BUF_SIZE = 4096;
300 const int BUF_PID_SIZE = 20;
302 char buf_pid[BUF_PID_SIZE];
303 strlcpy(buf, TQDateTime::currentDateTime().toString(
"[yyyy/MM/dd hh:mm:ss.zzz] ").ascii(), BUF_SIZE);
304 if (!kDebug_data->aAreaName.isEmpty())
306 strlcat( buf,
"[", BUF_SIZE );
307 strlcat( buf, kDebug_data->aAreaName.data(), BUF_SIZE );
308 strlcat( buf,
"] ", BUF_SIZE );
310 snprintf(buf_pid, BUF_PID_SIZE,
"[%d] ", getpid());
311 strlcat(buf, buf_pid, BUF_SIZE);
312 strlcat(buf, data, BUF_SIZE);
323 aKey =
"InfoFilename";
326 aKey =
"WarnFilename";
329 aKey =
"FatalFilename";
333 aKey =
"ErrorFilename";
336 TQFile aOutputFile( kDebug_data->config->readPathEntry(aKey,
"kdebug.dbg") );
337 aOutputFile.open( IO_WriteOnly | IO_Append | IO_Raw );
338 aOutputFile.writeBlock( buf, strlen( buf ) );
346 if ( !kDebug_data->aAreaName.isEmpty() )
347 aCaption += TQString(
"(%1)").arg( TQString(kDebug_data->aAreaName) );
348 TQMessageBox::warning( 0L, aCaption, data,
i18n(
"&OK") );
353 if (write( 2, buf, strlen( buf ) ) < 0) {
360 syslog( nPriority,
"%s", buf);
366 if( ( nLevel == KDEBUG_FATAL )
367 && ( !kDebug_data->config || kDebug_data->config->readNumEntry(
"AbortFatal", 1 ) ) )
371kdbgstream& perror(
kdbgstream &s) {
return s << TQString(TQString::fromLocal8Bit(strerror(errno))); }
383 : output(str.output), area(str.area), level(str.level), print(str.print)
385 str.output.truncate(0);
389 if (output.isEmpty() || !print)
391 kDebugBackend( level, area, output.local8Bit().data() );
392 output = TQString::null;
399 va_start( arguments, format );
400 vsnprintf( buf,
sizeof(buf), format, arguments );
406kdbgstream::~kdbgstream() {
407 if (!output.isEmpty()) {
408 fprintf(stderr,
"ASSERT: debug output not ended with \\n\n");
409 TQString backtrace = kdBacktrace();
410 if (backtrace.ascii() != NULL) {
411 fprintf(stderr,
"%s", backtrace.latin1());
419 if (!print)
return *
this;
421 output +=
"\\x" + TQString::number(
static_cast<uint
>( ch ), 16 ).rightJustify(2,
'0');
424 if (ch ==
'\n')
flush();
431 if (!print)
return *
this;
433 output +=
"\\x" + TQString::number( ch.unicode(), 16 ).rightJustify(2,
'0');
436 if (ch == TQChar(
'\n'))
flush();
443 return *this << const_cast< const TQWidget* >( widget );
448 TQString string, temp;
452 string=(TQString)
"[Null pointer]";
454 temp.setNum((ulong)widget, 16);
455 string=(TQString)
"["+widget->className()+
" pointer "
456 +
"(0x" + temp +
")";
457 if(widget->name(0)==0)
459 string +=
" to unnamed widget, ";
461 string += (TQString)
" to widget " + widget->name() +
", ";
463 string +=
"geometry="
464 + TQString().setNum(widget->width())
465 +
"x"+TQString().setNum(widget->height())
466 +
"+"+TQString().setNum(widget->x())
467 +
"+"+TQString().setNum(widget->y())
475 if (output.at(output.length() -1 ) == TQChar(
'\n'))
487 *
this << time.toString();
491 *
this << TQString(date.toString());
496 *
this << TQString(time.toString());
500 *
this <<
"(" << p.x() <<
", " << p.y() <<
")";
504 *
this <<
"[" << s.width() <<
"x" << s.height() <<
"]";
508 *
this <<
"[" << r.x() <<
"," << r.y() <<
" - " << r.width() <<
"x" << r.height() <<
"]";
514 TQMemArray<TQRect>rs=reg.rects();
515 for (uint i=0;i<rs.size();++i)
516 *
this << TQString(TQString(
"[%1,%2 - %3x%4] ").arg(rs[i].x()).arg(rs[i].y()).arg(rs[i].width()).arg(rs[i].height() )) ;
527 *
this << l.join(
",");
534 *
this << TQString(c.name());
536 *
this <<
"(invalid/default)";
540 static const char*
const s_penStyles[] = {
541 "NoPen",
"SolidLine",
"DashLine",
"DotLine",
"DashDotLine",
543 static const char*
const s_capStyles[] = {
544 "FlatCap",
"SquareCap",
"RoundCap" };
546 *
this << s_penStyles[ p.style() ];
550 if ( p.color().isValid() )
551 *
this << TQString(p.color().name());
553 *
this <<
"(invalid/default)";
556 *
this <<
" capstyle:";
557 *
this << s_capStyles[ p.capStyle() >> 4 ];
564 static const char*
const s_brushStyles[] = {
565 "NoBrush",
"SolidPattern",
"Dense1Pattern",
"Dense2Pattern",
"Dense3Pattern",
566 "Dense4Pattern",
"Dense5Pattern",
"Dense6Pattern",
"Dense7Pattern",
567 "HorPattern",
"VerPattern",
"CrossPattern",
"BDiagPattern",
"FDiagPattern",
568 "DiagCrossPattern" };
571 *
this <<s_brushStyles[ b.style() ];
574 if ( b.color().isValid() )
575 *
this << TQString(b.color().name()) ;
577 *
this <<
"(invalid/default)";
579 *
this <<
" has a pixmap";
585 *
this <<
"[variant: ";
586 *
this << v.typeName();
589 *
this <<
" toString=";
590 *
this << v.toString();
596 if (!print)
return *
this;
599 unsigned int sz = TQMIN( data.size(), 64 );
600 for ( ; i < sz ; ++i ) {
601 output += TQString::number( (
unsigned char) data[i], 16 ).rightJustify(2,
'0');
605 if ( sz < data.size() )
612struct BacktraceFunctionInfo {
614 const char* fileName;
617 TQString functionName;
626asymbol** bfdLoadSymtab (bfd *abfd) {
630 bool dynamic =
false;
633 if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
638 symtab_sz = bfd_get_symtab_upper_bound (abfd);
639 if (symtab_sz == 0) {
640 symtab_sz = bfd_get_dynamic_symtab_upper_bound (abfd);
648 rv = (asymbol **) malloc(symtab_sz);
655 symCount = bfd_canonicalize_dynamic_symtab (abfd, rv);
657 symCount = bfd_canonicalize_symtab (abfd, rv);
670void bfdFillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
671 static bool inited=0;
677 bfd *abfd = bfd_openr(func.fileName, 0);
683 if( !bfd_check_format(abfd, bfd_object) ) {
689 asymbol **syms= bfdLoadSymtab(abfd);
696 for (asection *sect = abfd->sections; sect != NULL; sect = sect->next) {
697#ifdef HAVE_LIBBFD_2_34_API
698 if (bfd_section_flags(sect) & SEC_ALLOC) {
699 bfd_vma sectStart = bfd_section_vma(sect);
700 bfd_vma sectEnd = sectStart + bfd_section_size(sect);
702 if (bfd_get_section_flags(abfd, sect) & SEC_ALLOC) {
703 bfd_vma sectStart = bfd_get_section_vma(abfd, sect);
704 bfd_vma sectEnd = sectStart + bfd_section_size(abfd, sect);
706 if (sectStart <= func.offset && func.offset < sectEnd) {
707 bfd_vma sectOffset = func.offset - sectStart;
708 const char* functionName;
709 const char* sourceName;
711 if (bfd_find_nearest_line(abfd, sect, syms, sectOffset,
712 &sourceName, &functionName, &sourceLine))
714 func.sourceName = sourceName;
715 func.sourceLine = sourceLine;
716 if(func.functionName.isEmpty()) {
717 func.functionName = TQString::fromAscii(functionName);
724#ifdef HAVE_DEMANGLE_H
725 if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
726 char *demangled = bfd_demangle(abfd, func.functionName.ascii(), DMGL_AUTO | DMGL_PARAMS);
728 func.prettyName = demangled;
742void fillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
744 bfdFillAdditionalFunctionsInfo(func);
747#ifdef HAVE_ABI_CXA_DEMANGLE
748 if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
750 char *demangled = abi::__cxa_demangle(func.functionName.ascii(), 0, 0, &status);
752 func.prettyName = demangled;
760TQString formatBacktrace(
void *addr) {
762 BacktraceFunctionInfo func;
771 dladdr((
void *)func.addr, &info);
773 dladdr(func.addr, &info);
776 func.fileName = info.dli_fname;
777 func.base = info.dli_fbase;
778 func.offset = (uintptr_t)func.addr - (uintptr_t)func.base;
779 func.functionName = TQString::fromAscii(info.dli_sname);
782 fillAdditionalFunctionsInfo(func);
784 rv.sprintf(
"0x%0*lx", (
int)
sizeof(
void*)*2, (uintptr_t) func.addr);
787 if (!func.prettyName.isEmpty()) {
788 rv += func.prettyName;
789 }
else if (!func.functionName.isEmpty()) {
790 rv += func.functionName;
795 if (!func.sourceName.isEmpty()) {
797 rv += func.sourceName;
799 rv += func.sourceLine ? TQString::number(func.sourceLine) :
"??";
800 }
else if (func.fileName && func.fileName[0]) {
801 rv += TQString().sprintf(
" from %s:0x%08lx",func.fileName, func.offset);
815 if (levels < 0 || levels > 256 ) {
823 void** trace = (
void**)alloca(levels *
sizeof(
void*));
827 levels = backtrace(trace, levels);
830 for (
int i = 0; i < levels; ++i) {
831 rv += TQString().sprintf(
"#%-2d ", i);
832 rv += formatBacktrace(trace[i]);
836 rv +=
"backtrace() failed\n";
857 levels = backtrace(trace, 256);
859 backtrace_symbols_fd(trace, levels, fd);
866 delete kDebug_data->config;
867 kDebug_data->config = 0;
874#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())