• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
kdebug.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
3  2002 Holger Freyther (freyther@kde.org)
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "kdebug.h"
22 
23 #ifdef NDEBUG
24 #undef kdDebug
25 #endif
26 
27 #include "kdebugdcopiface.h"
28 
29 #include "tdeapplication.h"
30 #include "tdeglobal.h"
31 #include "kinstance.h"
32 #include "kstandarddirs.h"
33 
34 #include <tqmessagebox.h>
35 #include <tdelocale.h>
36 #include <tqfile.h>
37 #include <tqintdict.h>
38 #include <tqstring.h>
39 #include <tqdatetime.h>
40 #include <tqpoint.h>
41 #include <tqrect.h>
42 #include <tqregion.h>
43 #include <tqstringlist.h>
44 #include <tqpen.h>
45 #include <tqbrush.h>
46 #include <tqsize.h>
47 
48 #include <kurl.h>
49 
50 #include <stdlib.h> // abort
51 #include <unistd.h> // getpid
52 #include <stdarg.h> // vararg stuff
53 #include <ctype.h> // isprint
54 #include <syslog.h>
55 #include <errno.h>
56 #include <cstring>
57 #include <tdeconfig.h>
58 #include "kstaticdeleter.h"
59 #include <config.h>
60 
61 #ifdef HAVE_BACKTRACE
62 #include BACKTRACE_H
63 
64 #ifdef HAVE_DLFCN_H
65 #include <dlfcn.h>
66 #endif
67 
68 #ifdef HAVE_ABI_CXA_DEMANGLE
69 #include <cxxabi.h>
70 #endif
71 
72 #include <link.h>
73 #ifdef WITH_LIBBFD
74 /* newer versions of libbfd require some autotools-specific macros to be defined */
75 /* see binutils Bug 14243 and 14072 */
76 #define PACKAGE tdelibs
77 #define PACKAGE_VERSION TDE_VERSION
78 
79 #include <bfd.h>
80 
81 #ifdef HAVE_DEMANGLE_H
82 #include <demangle.h>
83 #endif // HAVE_DEMANGLE_H
84 #endif // WITH_LIBBFD
85 
86 #endif // HAVE_BACKTRACE
87 
88 #ifdef HAVE_ALLOCA_H
89 #include <alloca.h>
90 #endif // HAVE_ALLOCA_H
91 
92 #ifdef HAVE_STDINT_H
93 #include <stdint.h>
94 #endif // HAVE_STDINT_H
95 
96 class KDebugEntry;
97 
98 class KDebugEntry
99 {
100 public:
101  KDebugEntry (int n, const TQCString& d) {number=n; descr=d;}
102  unsigned int number;
103  TQCString descr;
104 };
105 
106 static TQIntDict<KDebugEntry> *KDebugCache;
107 
108 static KStaticDeleter< TQIntDict<KDebugEntry> > kdd;
109 
110 static TQCString getDescrFromNum(unsigned int _num)
111 {
112  if (!KDebugCache) {
113  kdd.setObject(KDebugCache, new TQIntDict<KDebugEntry>( 601 ));
114  // Do not call this deleter from ~TDEApplication
115  TDEGlobal::unregisterStaticDeleter(&kdd);
116  KDebugCache->setAutoDelete(true);
117  }
118 
119  KDebugEntry *ent = KDebugCache->find( _num );
120  if ( ent )
121  return ent->descr;
122 
123  if ( !KDebugCache->isEmpty() ) // areas already loaded
124  return TQCString();
125 
126  TQString filename(locate("config","kdebug.areas"));
127  if (filename.isEmpty())
128  return TQCString();
129 
130  TQFile file(filename);
131  if (!file.open(IO_ReadOnly)) {
132  tqWarning("Couldn't open %s", filename.local8Bit().data());
133  file.close();
134  return TQCString();
135  }
136 
137  uint lineNumber=0;
138  TQCString line(1024);
139  int len;
140 
141  while (( len = file.readLine(line.data(),line.size()-1) ) > 0) {
142  int i=0;
143  ++lineNumber;
144 
145  while (line[i] && line[i] <= ' ')
146  i++;
147 
148  unsigned char ch=line[i];
149 
150  if ( !ch || ch =='#' || ch =='\n')
151  continue; // We have an eof, a comment or an empty line
152 
153  if (ch < '0' && ch > '9') {
154  tqWarning("Syntax error: no number (line %u)",lineNumber);
155  continue;
156  }
157 
158  const int numStart=i;
159  do {
160  ch=line[++i];
161  } while ( ch >= '0' && ch <= '9');
162 
163  const TQ_ULONG number =line.mid(numStart,i).toULong();
164 
165  while (line[i] && line[i] <= ' ')
166  i++;
167 
168  KDebugCache->insert(number, new KDebugEntry(number, line.mid(i, len-i-1)));
169  }
170  file.close();
171 
172  ent = KDebugCache->find( _num );
173  if ( ent )
174  return ent->descr;
175 
176  return TQCString();
177 }
178 
179 enum DebugLevels {
180  KDEBUG_INFO= 0,
181  KDEBUG_WARN= 1,
182  KDEBUG_ERROR= 2,
183  KDEBUG_FATAL= 3
184 };
185 
186 
187 struct kDebugPrivate {
188  kDebugPrivate() :
189  oldarea(0), config(0) { }
190 
191  ~kDebugPrivate() { delete config; }
192 
193  TQCString aAreaName;
194  unsigned int oldarea;
195  TDEConfig *config;
196 };
197 
198 static kDebugPrivate *kDebug_data = 0;
199 static KStaticDeleter<kDebugPrivate> pcd;
200 static KStaticDeleter<KDebugDCOPIface> dcopsd;
201 static KDebugDCOPIface* kDebugDCOPIface = 0;
202 
203 static void kDebugBackend( unsigned short nLevel, unsigned int nArea, const char *data)
204 {
205  if ( !kDebug_data )
206  {
207  pcd.setObject(kDebug_data, new kDebugPrivate());
208  // Do not call this deleter from ~TDEApplication
209  TDEGlobal::unregisterStaticDeleter(&pcd);
210 
211  // create the dcop interface if it has not been created yet
212  if (!kDebugDCOPIface)
213  {
214  kDebugDCOPIface = dcopsd.setObject(kDebugDCOPIface, new KDebugDCOPIface);
215  }
216  }
217 
218  if (!kDebug_data->config && TDEGlobal::_instance )
219  {
220  kDebug_data->config = new TDEConfig("kdebugrc", false, false);
221  kDebug_data->config->setGroup("0");
222 
223  //AB: this is necessary here, otherwise all output with area 0 won't be
224  //prefixed with anything, unless something with area != 0 is called before
225  if ( TDEGlobal::_instance )
226  kDebug_data->aAreaName = TDEGlobal::instance()->instanceName();
227  }
228 
229  if ( kDebug_data->oldarea != nArea ) {
230  kDebug_data->oldarea = nArea;
231  if( TDEGlobal::_instance ) {
232  if ( nArea > 0 ) {
233  kDebug_data->aAreaName = getDescrFromNum(nArea);
234  }
235  if ( nArea == 0 || kDebug_data->aAreaName.isEmpty() ) {
236  kDebug_data->aAreaName = TDEGlobal::instance()->instanceName();
237  }
238  }
239  }
240 
241  int nPriority = 0;
242  TQString aCaption;
243 
244  /* Determine output */
245 
246  TQString key;
247  switch( nLevel )
248  {
249  case KDEBUG_INFO:
250  key = "InfoOutput";
251  aCaption = "Info";
252  nPriority = LOG_INFO;
253  break;
254  case KDEBUG_WARN:
255  key = "WarnOutput";
256  aCaption = "Warning";
257  nPriority = LOG_WARNING;
258  break;
259  case KDEBUG_FATAL:
260  key = "FatalOutput";
261  aCaption = "Fatal Error";
262  nPriority = LOG_CRIT;
263  break;
264  case KDEBUG_ERROR:
265  default:
266  /* Programmer error, use "Error" as default */
267  key = "ErrorOutput";
268  aCaption = "Error";
269  nPriority = LOG_ERR;
270  break;
271  }
272 
273  short nOutput = -1;
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);
280  }
281  }
282  // if no output mode is specified default to no stderr output
283  // NOTE: don't set this to 4 (no output) because in that case you won't be
284  // able to get any output from applications which don't create
285  // TDEApplication objects.
286  if ( nOutput == -1 ) {
287  nOutput = 2;
288  }
289 
290  // If the application doesn't have a TQApplication object it can't use
291  // a messagebox, as well as in case of GUI is disabled.
292  if ( nOutput == 1 && ( !kapp || !kapp->guiEnabled()) ) {
293  nOutput = 2;
294  } else if ( nOutput == 4 && nLevel != KDEBUG_FATAL ) {
295  return;
296  }
297 
298  const int BUF_SIZE = 4096;
299  const int BUF_PID_SIZE = 20;
300  char buf[BUF_SIZE];
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())
304  {
305  strlcat( buf, "[", BUF_SIZE );
306  strlcat( buf, kDebug_data->aAreaName.data(), BUF_SIZE );
307  strlcat( buf, "] ", BUF_SIZE );
308  }
309  snprintf(buf_pid, BUF_PID_SIZE, "[%d] ", getpid());
310  strlcat(buf, buf_pid, BUF_SIZE);
311  strlcat(buf, data, BUF_SIZE);
312 
313  // Output
314  switch( nOutput )
315  {
316  case 0: // File
317  {
318  const char* aKey;
319  switch( nLevel )
320  {
321  case KDEBUG_INFO:
322  aKey = "InfoFilename";
323  break;
324  case KDEBUG_WARN:
325  aKey = "WarnFilename";
326  break;
327  case KDEBUG_FATAL:
328  aKey = "FatalFilename";
329  break;
330  case KDEBUG_ERROR:
331  default:
332  aKey = "ErrorFilename";
333  break;
334  }
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 ) );
338  aOutputFile.close();
339  break;
340  }
341  case 1: // Message Box
342  {
343  // Since we are in tdecore here, we cannot use KMsgBox and use
344  // TQMessageBox instead
345  if ( !kDebug_data->aAreaName.isEmpty() )
346  aCaption += TQString("(%1)").arg( TQString(kDebug_data->aAreaName) );
347  TQMessageBox::warning( 0L, aCaption, data, i18n("&OK") );
348  break;
349  }
350  case 2: // Shell
351  {
352  if (write( 2, buf, strlen( buf ) ) < 0) { //fputs( buf, stderr );
353  // ERROR
354  }
355  break;
356  }
357  case 3: // syslog
358  {
359  syslog( nPriority, "%s", buf);
360  break;
361  }
362  }
363 
364  // check if we should abort
365  if( ( nLevel == KDEBUG_FATAL )
366  && ( !kDebug_data->config || kDebug_data->config->readNumEntry( "AbortFatal", 1 ) ) )
367  abort();
368 }
369 
370 kdbgstream& perror( kdbgstream &s) { return s << TQString(TQString::fromLocal8Bit(strerror(errno))); }
371 kdbgstream kdDebug(int area) { return kdbgstream(area, KDEBUG_INFO); }
372 kdbgstream kdDebug(bool cond, int area) { if (cond) return kdbgstream(area, KDEBUG_INFO); else return kdbgstream(0, 0, false); }
373 
374 kdbgstream kdError(int area) { return kdbgstream("ERROR: ", area, KDEBUG_ERROR); }
375 kdbgstream kdError(bool cond, int area) { if (cond) return kdbgstream("ERROR: ", area, KDEBUG_ERROR); else return kdbgstream(0,0,false); }
376 kdbgstream kdWarning(int area) { return kdbgstream("WARNING: ", area, KDEBUG_WARN); }
377 kdbgstream kdWarning(bool cond, int area) { if (cond) return kdbgstream("WARNING: ", area, KDEBUG_WARN); else return kdbgstream(0,0,false); }
378 kdbgstream kdFatal(int area) { return kdbgstream("FATAL: ", area, KDEBUG_FATAL); }
379 kdbgstream kdFatal(bool cond, int area) { if (cond) return kdbgstream("FATAL: ", area, KDEBUG_FATAL); else return kdbgstream(0,0,false); }
380 
381 kdbgstream::kdbgstream(kdbgstream &str)
382  : output(str.output), area(str.area), level(str.level), print(str.print)
383 {
384  str.output.truncate(0);
385 }
386 
387 void kdbgstream::flush() {
388  if (output.isEmpty() || !print)
389  return;
390  kDebugBackend( level, area, output.local8Bit().data() );
391  output = TQString::null;
392 }
393 
394 kdbgstream &kdbgstream::form(const char *format, ...)
395 {
396  char buf[4096];
397  va_list arguments;
398  va_start( arguments, format );
399  vsnprintf( buf, sizeof(buf), format, arguments );
400  va_end(arguments);
401  *this << buf;
402  return *this;
403 }
404 
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());
411  }
412  *this << '\n';
413  }
414 }
415 
416 kdbgstream& kdbgstream::operator<< (char ch)
417 {
418  if (!print) return *this;
419  if (!isprint(ch))
420  output += "\\x" + TQString::number( static_cast<uint>( ch ), 16 ).rightJustify(2, '0');
421  else {
422  output += ch;
423  if (ch == '\n') flush();
424  }
425  return *this;
426 }
427 
428 kdbgstream& kdbgstream::operator<< (TQChar ch)
429 {
430  if (!print) return *this;
431  if (!ch.isPrint())
432  output += "\\x" + TQString::number( ch.unicode(), 16 ).rightJustify(2, '0');
433  else {
434  output += ch;
435  if (ch == TQChar('\n')) flush();
436  }
437  return *this;
438 }
439 
440 kdbgstream& kdbgstream::operator<< (TQWidget* widget)
441 {
442  return *this << const_cast< const TQWidget* >( widget );
443 }
444 
445 kdbgstream& kdbgstream::operator<< (const TQWidget* widget)
446 {
447  TQString string, temp;
448  // -----
449  if(widget==0)
450  {
451  string=(TQString)"[Null pointer]";
452  } else {
453  temp.setNum((ulong)widget, 16);
454  string=(TQString)"["+widget->className()+" pointer "
455  + "(0x" + temp + ")";
456  if(widget->name(0)==0)
457  {
458  string += " to unnamed widget, ";
459  } else {
460  string += (TQString)" to widget " + widget->name() + ", ";
461  }
462  string += "geometry="
463  + TQString().setNum(widget->width())
464  + "x"+TQString().setNum(widget->height())
465  + "+"+TQString().setNum(widget->x())
466  + "+"+TQString().setNum(widget->y())
467  + "]";
468  }
469  if (!print)
470  {
471  return *this;
472  }
473  output += string;
474  if (output.at(output.length() -1 ) == TQChar('\n'))
475  {
476  flush();
477  }
478  return *this;
479 }
480 /*
481  * either use 'output' directly and do the flush if needed
482  * or use the TQString operator which calls the char* operator
483  *
484  */
485 kdbgstream& kdbgstream::operator<<( const TQDateTime& time) {
486  *this << time.toString();
487  return *this;
488 }
489 kdbgstream& kdbgstream::operator<<( const TQDate& date) {
490  *this << TQString(date.toString());
491 
492  return *this;
493 }
494 kdbgstream& kdbgstream::operator<<( const TQTime& time ) {
495  *this << TQString(time.toString());
496  return *this;
497 }
498 kdbgstream& kdbgstream::operator<<( const TQPoint& p ) {
499  *this << "(" << p.x() << ", " << p.y() << ")";
500  return *this;
501 }
502 kdbgstream& kdbgstream::operator<<( const TQSize& s ) {
503  *this << "[" << s.width() << "x" << s.height() << "]";
504  return *this;
505 }
506 kdbgstream& kdbgstream::operator<<( const TQRect& r ) {
507  *this << "[" << r.x() << "," << r.y() << " - " << r.width() << "x" << r.height() << "]";
508  return *this;
509 }
510 kdbgstream& kdbgstream::operator<<( const TQRegion& reg ) {
511  *this<< "[ ";
512 
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() )) ;
516 
517  *this <<"]";
518  return *this;
519 }
520 kdbgstream& kdbgstream::operator<<( const KURL& u ) {
521  *this << u.prettyURL();
522  return *this;
523 }
524 kdbgstream& kdbgstream::operator<<( const TQStringList& l ) {
525  *this << "(";
526  *this << l.join(",");
527  *this << ")";
528 
529  return *this;
530 }
531 kdbgstream& kdbgstream::operator<<( const TQColor& c ) {
532  if ( c.isValid() )
533  *this << TQString(c.name());
534  else
535  *this << "(invalid/default)";
536  return *this;
537 }
538 kdbgstream& kdbgstream::operator<<( const TQPen& p ) {
539  static const char* const s_penStyles[] = {
540  "NoPen", "SolidLine", "DashLine", "DotLine", "DashDotLine",
541  "DashDotDotLine" };
542  static const char* const s_capStyles[] = {
543  "FlatCap", "SquareCap", "RoundCap" };
544  *this << "[ style:";
545  *this << s_penStyles[ p.style() ];
546  *this << " width:";
547  *this << p.width();
548  *this << " color:";
549  if ( p.color().isValid() )
550  *this << TQString(p.color().name());
551  else
552  *this <<"(invalid/default)";
553  if ( p.width() > 0 ) // cap style doesn't matter, otherwise
554  {
555  *this << " capstyle:";
556  *this << s_capStyles[ p.capStyle() >> 4 ];
557  // join style omitted
558  }
559  *this <<" ]";
560  return *this;
561 }
562 kdbgstream& kdbgstream::operator<<( const TQBrush& b) {
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" };
568 
569  *this <<"[ style: ";
570  *this <<s_brushStyles[ b.style() ];
571  *this <<" color: ";
572  // can't use operator<<(str, b.color()) because that terminates a kdbgstream (flushes)
573  if ( b.color().isValid() )
574  *this << TQString(b.color().name()) ;
575  else
576  *this <<"(invalid/default)";
577  if ( b.pixmap() )
578  *this <<" has a pixmap";
579  *this <<" ]";
580  return *this;
581 }
582 
583 kdbgstream& kdbgstream::operator<<( const TQVariant& v) {
584  *this << "[variant: ";
585  *this << v.typeName();
586  // For now we just attempt a conversion to string.
587  // Feel free to switch(v.type()) and improve the output.
588  *this << " toString=";
589  *this << v.toString();
590  *this << "]";
591  return *this;
592 }
593 
594 kdbgstream& kdbgstream::operator<<( const TQByteArray& data) {
595  if (!print) return *this;
596  output += '[';
597  unsigned int i = 0;
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');
601  if ( i < sz )
602  output += ' ';
603  }
604  if ( sz < data.size() )
605  output += "...";
606  output += ']';
607  return *this;
608 }
609 
610 #ifdef HAVE_BACKTRACE
611 struct BacktraceFunctionInfo {
612  const void *addr; //< the address of function returned by backtrace()
613  const char* fileName; //< the file of binary owning the function (e.g. shared library or current header)
614  const void *base; //< the base address there the binary is loaded to
615  uintptr_t offset; //< offset of the function in binary (base - address)
616  TQString functionName; //< mangled name of function
617  TQString prettyName; //< demangled name of function
618  TQString sourceName; //< name of source file function declared in
619  unsigned sourceLine; //< line where function defined
620 };
621 
622 #ifdef WITH_LIBBFD
623 
624 // load symbol table from file
625 asymbol** bfdLoadSymtab (bfd *abfd) {
626  long symCount; // count of entries in symbol table
627  long symtab_sz; // size of the table
628  asymbol** rv;
629  bfd_boolean dynamic = FALSE;
630 
631  // make shure the file has symbol table
632  if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
633  return 0;
634  }
635 
636  // determin the amount of space we'll need to store the table
637  symtab_sz = bfd_get_symtab_upper_bound (abfd);
638  if (symtab_sz == 0) {
639  symtab_sz = bfd_get_dynamic_symtab_upper_bound (abfd);
640  dynamic = TRUE;
641  }
642  if (symtab_sz < 0) {
643  return 0;
644  }
645 
646  // allocate memory
647  rv = (asymbol **) malloc(symtab_sz); // dunno, why not malloc
648  if ( !rv ) {
649  return 0;
650  }
651 
652  // actually load the table
653  if (dynamic) {
654  symCount = bfd_canonicalize_dynamic_symtab (abfd, rv);
655  } else {
656  symCount = bfd_canonicalize_symtab (abfd, rv);
657  }
658 
659  if (symCount < 0) {
660  if (rv) {
661  free(rv);
662  }
663  return 0;
664  }
665 
666  return rv;
667 }
668 
669 void bfdFillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
670  static bool inited=0;
671  if (!inited) {
672  bfd_init();
673  inited=1;
674  }
675 
676  bfd *abfd = bfd_openr(func.fileName, 0); // a bfd object
677  if( !abfd ) {
678  return;
679  }
680 
681  // check format of the object
682  if( !bfd_check_format(abfd, bfd_object) ) {
683  bfd_close(abfd);
684  return;
685  }
686 
687  // load symbol table
688  asymbol **syms= bfdLoadSymtab(abfd);
689  if(!syms) {
690  bfd_close(abfd);
691  return;
692  }
693 
694  // found source file and line for given address
695  for (asection *sect = abfd->sections; sect != NULL; sect = sect->next) {
696 
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;
704  unsigned sourceLine;
705  if (bfd_find_nearest_line(abfd, sect, syms, sectOffset,
706  &sourceName, &functionName, &sourceLine))
707  {
708  func.sourceName = sourceName;
709  func.sourceLine = sourceLine;
710  if(func.functionName.isEmpty()) {
711  func.functionName = TQString::fromAscii(functionName);
712  }
713  break;
714  }
715  }
716  }
717  }
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);
721  if (demangled) {
722  func.prettyName = demangled;
723  free(demangled);
724  }
725  }
726 #endif // HAVE_DEMANGLE_H
727 
728  if( syms ) {
729  free(syms);
730  }
731  bfd_close(abfd);
732 }
733 
734 #endif // WITH_LIBBFD
735 
736 void fillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
737 #ifdef WITH_LIBBFD
738  bfdFillAdditionalFunctionsInfo(func);
739 #endif // WITH_LIBBFD
740 
741 #ifdef HAVE_ABI_CXA_DEMANGLE
742  if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
743  int status=0;
744  char *demangled = abi::__cxa_demangle(func.functionName.ascii(), 0, 0, &status);
745  if (demangled) {
746  func.prettyName = demangled;
747  free(demangled);
748  }
749  }
750 #endif // HAVE_ABI_CXA_DEMANGLE
751 
752 }
753 
754 TQString formatBacktrace(void *addr) {
755  TQString rv;
756  BacktraceFunctionInfo func;
757  func.addr = addr;
758 
759  // NOTE: if somebody would compile for some non-linux-glibc platform
760  // check if dladdr function is avalible there
761  Dl_info info;
762 
763  // obtain information about the function.
764 #ifdef Q_OS_SOLARIS
765  dladdr((void *)func.addr, &info);
766 #else
767  dladdr(func.addr, &info);
768 #endif /* Solaris */
769 
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);
774  func.sourceLine = 0;
775 
776  fillAdditionalFunctionsInfo(func);
777 
778  rv.sprintf("0x%0*lx", (int) sizeof(void*)*2, (uintptr_t) func.addr);
779 
780  rv += " in ";
781  if (!func.prettyName.isEmpty()) {
782  rv += func.prettyName;
783  } else if (!func.functionName.isEmpty()) {
784  rv += func.functionName;
785  } else {
786  rv += "??";
787  }
788 
789  if (!func.sourceName.isEmpty()) {
790  rv += " in ";
791  rv += func.sourceName;
792  rv += ":";
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);
796  } else {
797  rv += " from ??";
798  }
799 
800  return rv;
801 }
802 #endif // HAVE_BACKTRACE
803 
804 
805 TQString kdBacktrace(int levels)
806 {
807  TQString rv;
808 #ifdef HAVE_BACKTRACE
809  if (levels < 0 || levels > 256 ) {
810  levels = 256;
811  }
812 
813  rv = "[\n";
814 
815  if (levels) {
816 #ifdef HAVE_ALLOCA
817  void** trace = (void**)alloca(levels * sizeof(void*));
818 #else // HAVE_ALLOCA
819  void* trace[256];
820 #endif // HAVE_ALLOCA
821  levels = backtrace(trace, levels);
822 
823  if (levels) {
824  for (int i = 0; i < levels; ++i) {
825  rv += TQString().sprintf("#%-2d ", i);
826  rv += formatBacktrace(trace[i]);
827  rv += '\n';
828  }
829  } else {
830  rv += "backtrace() failed\n";
831  }
832  }
833 
834  rv += "]\n";
835 #endif // HAVE_BACKTRACE
836  return rv;
837 }
838 
839 // Keep for ABI compatability for some time
840 // FIXME remove this (2013-08-18, 18:09, Fat-Zer)
841 TQString kdBacktrace()
842 {
843  return kdBacktrace(-1 /*all*/);
844 }
845 
846 void kdBacktraceFD(int fd) {
847 #ifdef HAVE_BACKTRACE
848  void *trace[256];
849  int levels;
850 
851  levels = backtrace(trace, 256);
852  if (levels) {
853  backtrace_symbols_fd(trace, levels, fd);
854  }
855 #endif // HAVE_BACKTRACE
856 }
857 void kdClearDebugConfig()
858 {
859  if (kDebug_data) {
860  delete kDebug_data->config;
861  kDebug_data->config = 0;
862  }
863 }
864 
865 
866 // Needed for --enable-final
867 #ifdef NDEBUG
868 #define kdDebug kndDebug
869 #endif
KDebugDCOPIface
DCOP interface to KDebug.
Definition: kdebugdcopiface.h:31
KStaticDeleter
Little helper class to clean up static objects that are held as pointer.
Definition: kstaticdeleter.h:74
KURL
Represents and parses a URL.
Definition: kurl.h:128
KURL::prettyURL
TQString prettyURL(int _trailing=0) const
Returns the URL as string in human-friendly format.
Definition: kurl.cpp:1559
TDEConfig
Access KDE Configuration entries.
Definition: tdeconfig.h:44
TDEGlobal::unregisterStaticDeleter
static void unregisterStaticDeleter(KStaticDeleterBase *d)
Unregisters a static deleter.
Definition: tdeglobal.cpp:198
TDEGlobal::instance
static TDEInstance * instance()
Returns the global instance.
Definition: tdeglobal.cpp:102
TDEInstance::instanceName
TQCString instanceName() const
Returns the name of the instance.
Definition: kinstance.cpp:342
TDELocale::i18n
TQString i18n(const char *text)
i18n is the function that does everything you need to translate a string.
Definition: tdelocale.cpp:1976
kdbgstream
kdbgstream is a text stream that allows you to print debug messages.
Definition: kdebug.h:80
kdbgstream::flush
void flush()
Flushes the output.
Definition: kdebug.cpp:387
kdbgstream::operator<<
kdbgstream & operator<<(bool i)
Prints the given value.
Definition: kdebug.h:99
kdbgstream::form
kdbgstream & form(const char *format,...)
Prints the string format which can contain printf-style formatted values.
Definition: kdebug.cpp:394
TDEGlobal::kdFatal
kdbgstream kdFatal(int area=0)
Returns a fatal error stream.
Definition: kdebug.cpp:378
TDEGlobal::kdBacktraceFD
void kdBacktraceFD(int fd=2)
Writes a backtrace to the given file descriptor.
Definition: kdebug.cpp:846
TDEGlobal::kdBacktrace
TQString kdBacktrace(int levels=-1)
Returns a backtrace.
Definition: kdebug.cpp:805
TDEGlobal::kdWarning
kdbgstream kdWarning(int area=0)
Returns a warning stream.
Definition: kdebug.cpp:376
TDEGlobal::kdClearDebugConfig
void kdClearDebugConfig()
Deletes the kdebugrc cache and therefore forces KDebug to reread the config file.
Definition: kdebug.cpp:857
TDEGlobal::kdError
kdbgstream kdError(int area=0)
Returns an error stream.
Definition: kdebug.cpp:374
TDEGlobal::kdDebug
kdbgstream kdDebug(int area=0)
Returns a debug stream.
Definition: kdebug.cpp:371
TDEStandardDirs::locate
TQString locate(const char *type, const TQString &filename, const TDEInstance *instance=TDEGlobal::instance())
Definition: kstandarddirs.cpp:1689
TDEStdAccel::key
int key(StdAccel id)
Definition: tdestdaccel.cpp:383
tdelocale.h

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.1
This website is maintained by Timothy Pearson.