• 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 <execinfo.h>
63 
64 #ifdef HAVE_ABI_CXA_DEMANGLE
65 #include <cxxabi.h>
66 #endif
67 
68 #include <link.h>
69 #ifdef WITH_LIBBFD
70 /* newer versions of libbfd require some autotools-specific macros to be defined */
71 /* see binutils Bug 14243 and 14072 */
72 #define PACKAGE tdelibs
73 #define PACKAGE_VERSION TDE_VERSION
74 
75 #include <bfd.h>
76 
77 #ifdef HAVE_DEMANGLE_H
78 #include <demangle.h>
79 #endif // HAVE_DEMANGLE_H
80 #endif // WITH_LIBBFD
81 
82 #endif // HAVE_BACKTRACE
83 
84 #ifdef HAVE_ALLOCA_H
85 #include <alloca.h>
86 #endif // HAVE_ALLOCA_H
87 
88 #ifdef HAVE_STDINT_H
89 #include <stdint.h>
90 #endif // HAVE_STDINT_H
91 
92 class KDebugEntry;
93 
94 class KDebugEntry
95 {
96 public:
97  KDebugEntry (int n, const TQCString& d) {number=n; descr=d;}
98  unsigned int number;
99  TQCString descr;
100 };
101 
102 static TQIntDict<KDebugEntry> *KDebugCache;
103 
104 static KStaticDeleter< TQIntDict<KDebugEntry> > kdd;
105 
106 static TQCString getDescrFromNum(unsigned int _num)
107 {
108  if (!KDebugCache) {
109  kdd.setObject(KDebugCache, new TQIntDict<KDebugEntry>( 601 ));
110  // Do not call this deleter from ~TDEApplication
111  TDEGlobal::unregisterStaticDeleter(&kdd);
112  KDebugCache->setAutoDelete(true);
113  }
114 
115  KDebugEntry *ent = KDebugCache->find( _num );
116  if ( ent )
117  return ent->descr;
118 
119  if ( !KDebugCache->isEmpty() ) // areas already loaded
120  return TQCString();
121 
122  TQString filename(locate("config","kdebug.areas"));
123  if (filename.isEmpty())
124  return TQCString();
125 
126  TQFile file(filename);
127  if (!file.open(IO_ReadOnly)) {
128  tqWarning("Couldn't open %s", filename.local8Bit().data());
129  file.close();
130  return TQCString();
131  }
132 
133  uint lineNumber=0;
134  TQCString line(1024);
135  int len;
136 
137  while (( len = file.readLine(line.data(),line.size()-1) ) > 0) {
138  int i=0;
139  ++lineNumber;
140 
141  while (line[i] && line[i] <= ' ')
142  i++;
143 
144  unsigned char ch=line[i];
145 
146  if ( !ch || ch =='#' || ch =='\n')
147  continue; // We have an eof, a comment or an empty line
148 
149  if (ch < '0' && ch > '9') {
150  tqWarning("Syntax error: no number (line %u)",lineNumber);
151  continue;
152  }
153 
154  const int numStart=i;
155  do {
156  ch=line[++i];
157  } while ( ch >= '0' && ch <= '9');
158 
159  const TQ_ULONG number =line.mid(numStart,i).toULong();
160 
161  while (line[i] && line[i] <= ' ')
162  i++;
163 
164  KDebugCache->insert(number, new KDebugEntry(number, line.mid(i, len-i-1)));
165  }
166  file.close();
167 
168  ent = KDebugCache->find( _num );
169  if ( ent )
170  return ent->descr;
171 
172  return TQCString();
173 }
174 
175 enum DebugLevels {
176  KDEBUG_INFO= 0,
177  KDEBUG_WARN= 1,
178  KDEBUG_ERROR= 2,
179  KDEBUG_FATAL= 3
180 };
181 
182 
183 struct kDebugPrivate {
184  kDebugPrivate() :
185  oldarea(0), config(0) { }
186 
187  ~kDebugPrivate() { delete config; }
188 
189  TQCString aAreaName;
190  unsigned int oldarea;
191  TDEConfig *config;
192 };
193 
194 static kDebugPrivate *kDebug_data = 0;
195 static KStaticDeleter<kDebugPrivate> pcd;
196 static KStaticDeleter<KDebugDCOPIface> dcopsd;
197 static KDebugDCOPIface* kDebugDCOPIface = 0;
198 
199 static void kDebugBackend( unsigned short nLevel, unsigned int nArea, const char *data)
200 {
201  if ( !kDebug_data )
202  {
203  pcd.setObject(kDebug_data, new kDebugPrivate());
204  // Do not call this deleter from ~TDEApplication
205  TDEGlobal::unregisterStaticDeleter(&pcd);
206 
207  // create the dcop interface if it has not been created yet
208  if (!kDebugDCOPIface)
209  {
210  kDebugDCOPIface = dcopsd.setObject(kDebugDCOPIface, new KDebugDCOPIface);
211  }
212  }
213 
214  if (!kDebug_data->config && TDEGlobal::_instance )
215  {
216  kDebug_data->config = new TDEConfig("kdebugrc", false, false);
217  kDebug_data->config->setGroup("0");
218 
219  //AB: this is necessary here, otherwise all output with area 0 won't be
220  //prefixed with anything, unless something with area != 0 is called before
221  if ( TDEGlobal::_instance )
222  kDebug_data->aAreaName = TDEGlobal::instance()->instanceName();
223  }
224 
225  if ( kDebug_data->oldarea != nArea ) {
226  kDebug_data->oldarea = nArea;
227  if( TDEGlobal::_instance ) {
228  if ( nArea > 0 ) {
229  kDebug_data->aAreaName = getDescrFromNum(nArea);
230  }
231  if ( nArea == 0 || kDebug_data->aAreaName.isEmpty() ) {
232  kDebug_data->aAreaName = TDEGlobal::instance()->instanceName();
233  }
234  }
235  }
236 
237  int nPriority = 0;
238  TQString aCaption;
239 
240  /* Determine output */
241 
242  TQString key;
243  switch( nLevel )
244  {
245  case KDEBUG_INFO:
246  key = "InfoOutput";
247  aCaption = "Info";
248  nPriority = LOG_INFO;
249  break;
250  case KDEBUG_WARN:
251  key = "WarnOutput";
252  aCaption = "Warning";
253  nPriority = LOG_WARNING;
254  break;
255  case KDEBUG_FATAL:
256  key = "FatalOutput";
257  aCaption = "Fatal Error";
258  nPriority = LOG_CRIT;
259  break;
260  case KDEBUG_ERROR:
261  default:
262  /* Programmer error, use "Error" as default */
263  key = "ErrorOutput";
264  aCaption = "Error";
265  nPriority = LOG_ERR;
266  break;
267  }
268 
269  short nOutput = -1;
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);
276  }
277  }
278  // if no output mode is specified default to no stderr output
279  // NOTE: don't set this to 4 (no output) because in that case you won't be
280  // able to get any output from applications which don't create
281  // TDEApplication objects.
282  if ( nOutput == -1 ) {
283  nOutput = 2;
284  }
285 
286  // If the application doesn't have a TQApplication object it can't use
287  // a messagebox, as well as in case of GUI is disabled.
288  if ( nOutput == 1 && ( !kapp || !kapp->guiEnabled()) ) {
289  nOutput = 2;
290  } else if ( nOutput == 4 && nLevel != KDEBUG_FATAL ) {
291  return;
292  }
293 
294  const int BUFSIZE = 4096;
295  char buf[BUFSIZE];
296  if ( !kDebug_data->aAreaName.isEmpty() ) {
297  strlcpy( buf, kDebug_data->aAreaName.data(), BUFSIZE );
298  strlcat( buf, ": ", BUFSIZE );
299  strlcat( buf, data, BUFSIZE );
300  }
301  else
302  strlcpy( buf, data, BUFSIZE );
303 
304 
305  // Output
306  switch( nOutput )
307  {
308  case 0: // File
309  {
310  const char* aKey;
311  switch( nLevel )
312  {
313  case KDEBUG_INFO:
314  aKey = "InfoFilename";
315  break;
316  case KDEBUG_WARN:
317  aKey = "WarnFilename";
318  break;
319  case KDEBUG_FATAL:
320  aKey = "FatalFilename";
321  break;
322  case KDEBUG_ERROR:
323  default:
324  aKey = "ErrorFilename";
325  break;
326  }
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 ) );
330  aOutputFile.close();
331  break;
332  }
333  case 1: // Message Box
334  {
335  // Since we are in tdecore here, we cannot use KMsgBox and use
336  // TQMessageBox instead
337  if ( !kDebug_data->aAreaName.isEmpty() )
338  aCaption += TQString("(%1)").arg( QString(kDebug_data->aAreaName) );
339  TQMessageBox::warning( 0L, aCaption, data, i18n("&OK") );
340  break;
341  }
342  case 2: // Shell
343  {
344  if (write( 2, buf, strlen( buf ) ) < 0) { //fputs( buf, stderr );
345  // ERROR
346  }
347  break;
348  }
349  case 3: // syslog
350  {
351  syslog( nPriority, "%s", buf);
352  break;
353  }
354  }
355 
356  // check if we should abort
357  if( ( nLevel == KDEBUG_FATAL )
358  && ( !kDebug_data->config || kDebug_data->config->readNumEntry( "AbortFatal", 1 ) ) )
359  abort();
360 }
361 
362 kdbgstream& perror( kdbgstream &s) { return s << TQString(TQString::fromLocal8Bit(strerror(errno))); }
363 kdbgstream kdDebug(int area) { return kdbgstream(area, KDEBUG_INFO); }
364 kdbgstream kdDebug(bool cond, int area) { if (cond) return kdbgstream(area, KDEBUG_INFO); else return kdbgstream(0, 0, false); }
365 
366 kdbgstream kdError(int area) { return kdbgstream("ERROR: ", area, KDEBUG_ERROR); }
367 kdbgstream kdError(bool cond, int area) { if (cond) return kdbgstream("ERROR: ", area, KDEBUG_ERROR); else return kdbgstream(0,0,false); }
368 kdbgstream kdWarning(int area) { return kdbgstream("WARNING: ", area, KDEBUG_WARN); }
369 kdbgstream kdWarning(bool cond, int area) { if (cond) return kdbgstream("WARNING: ", area, KDEBUG_WARN); else return kdbgstream(0,0,false); }
370 kdbgstream kdFatal(int area) { return kdbgstream("FATAL: ", area, KDEBUG_FATAL); }
371 kdbgstream kdFatal(bool cond, int area) { if (cond) return kdbgstream("FATAL: ", area, KDEBUG_FATAL); else return kdbgstream(0,0,false); }
372 
373 kdbgstream::kdbgstream(kdbgstream &str)
374  : output(str.output), area(str.area), level(str.level), print(str.print)
375 {
376  str.output.truncate(0);
377 }
378 
379 void kdbgstream::flush() {
380  if (output.isEmpty() || !print)
381  return;
382  kDebugBackend( level, area, output.local8Bit().data() );
383  output = TQString::null;
384 }
385 
386 kdbgstream &kdbgstream::form(const char *format, ...)
387 {
388  char buf[4096];
389  va_list arguments;
390  va_start( arguments, format );
391  vsnprintf( buf, sizeof(buf), format, arguments );
392  va_end(arguments);
393  *this << buf;
394  return *this;
395 }
396 
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());
403  }
404  *this << '\n';
405  }
406 }
407 
408 kdbgstream& kdbgstream::operator<< (char ch)
409 {
410  if (!print) return *this;
411  if (!isprint(ch))
412  output += "\\x" + TQString::number( static_cast<uint>( ch ), 16 ).rightJustify(2, '0');
413  else {
414  output += ch;
415  if (ch == '\n') flush();
416  }
417  return *this;
418 }
419 
420 kdbgstream& kdbgstream::operator<< (TQChar ch)
421 {
422  if (!print) return *this;
423  if (!ch.isPrint())
424  output += "\\x" + TQString::number( ch.unicode(), 16 ).rightJustify(2, '0');
425  else {
426  output += ch;
427  if (ch == QChar('\n')) flush();
428  }
429  return *this;
430 }
431 
432 kdbgstream& kdbgstream::operator<< (TQWidget* widget)
433 {
434  return *this << const_cast< const TQWidget* >( widget );
435 }
436 
437 kdbgstream& kdbgstream::operator<< (const TQWidget* widget)
438 {
439  TQString string, temp;
440  // -----
441  if(widget==0)
442  {
443  string=(TQString)"[Null pointer]";
444  } else {
445  temp.setNum((ulong)widget, 16);
446  string=(TQString)"["+widget->className()+" pointer "
447  + "(0x" + temp + ")";
448  if(widget->name(0)==0)
449  {
450  string += " to unnamed widget, ";
451  } else {
452  string += (TQString)" to widget " + widget->name() + ", ";
453  }
454  string += "geometry="
455  + TQString().setNum(widget->width())
456  + "x"+TQString().setNum(widget->height())
457  + "+"+TQString().setNum(widget->x())
458  + "+"+TQString().setNum(widget->y())
459  + "]";
460  }
461  if (!print)
462  {
463  return *this;
464  }
465  output += string;
466  if (output.at(output.length() -1 ) == QChar('\n'))
467  {
468  flush();
469  }
470  return *this;
471 }
472 /*
473  * either use 'output' directly and do the flush if needed
474  * or use the TQString operator which calls the char* operator
475  *
476  */
477 kdbgstream& kdbgstream::operator<<( const TQDateTime& time) {
478  *this << time.toString();
479  return *this;
480 }
481 kdbgstream& kdbgstream::operator<<( const TQDate& date) {
482  *this << TQString(date.toString());
483 
484  return *this;
485 }
486 kdbgstream& kdbgstream::operator<<( const TQTime& time ) {
487  *this << TQString(time.toString());
488  return *this;
489 }
490 kdbgstream& kdbgstream::operator<<( const TQPoint& p ) {
491  *this << "(" << p.x() << ", " << p.y() << ")";
492  return *this;
493 }
494 kdbgstream& kdbgstream::operator<<( const TQSize& s ) {
495  *this << "[" << s.width() << "x" << s.height() << "]";
496  return *this;
497 }
498 kdbgstream& kdbgstream::operator<<( const TQRect& r ) {
499  *this << "[" << r.x() << "," << r.y() << " - " << r.width() << "x" << r.height() << "]";
500  return *this;
501 }
502 kdbgstream& kdbgstream::operator<<( const TQRegion& reg ) {
503  *this<< "[ ";
504 
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() )) ;
508 
509  *this <<"]";
510  return *this;
511 }
512 kdbgstream& kdbgstream::operator<<( const KURL& u ) {
513  *this << u.prettyURL();
514  return *this;
515 }
516 kdbgstream& kdbgstream::operator<<( const TQStringList& l ) {
517  *this << "(";
518  *this << l.join(",");
519  *this << ")";
520 
521  return *this;
522 }
523 kdbgstream& kdbgstream::operator<<( const TQColor& c ) {
524  if ( c.isValid() )
525  *this << TQString(c.name());
526  else
527  *this << "(invalid/default)";
528  return *this;
529 }
530 kdbgstream& kdbgstream::operator<<( const TQPen& p ) {
531  static const char* const s_penStyles[] = {
532  "NoPen", "SolidLine", "DashLine", "DotLine", "DashDotLine",
533  "DashDotDotLine" };
534  static const char* const s_capStyles[] = {
535  "FlatCap", "SquareCap", "RoundCap" };
536  *this << "[ style:";
537  *this << s_penStyles[ p.style() ];
538  *this << " width:";
539  *this << p.width();
540  *this << " color:";
541  if ( p.color().isValid() )
542  *this << TQString(p.color().name());
543  else
544  *this <<"(invalid/default)";
545  if ( p.width() > 0 ) // cap style doesn't matter, otherwise
546  {
547  *this << " capstyle:";
548  *this << s_capStyles[ p.capStyle() >> 4 ];
549  // join style omitted
550  }
551  *this <<" ]";
552  return *this;
553 }
554 kdbgstream& kdbgstream::operator<<( const TQBrush& b) {
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" };
560 
561  *this <<"[ style: ";
562  *this <<s_brushStyles[ b.style() ];
563  *this <<" color: ";
564  // can't use operator<<(str, b.color()) because that terminates a kdbgstream (flushes)
565  if ( b.color().isValid() )
566  *this << TQString(b.color().name()) ;
567  else
568  *this <<"(invalid/default)";
569  if ( b.pixmap() )
570  *this <<" has a pixmap";
571  *this <<" ]";
572  return *this;
573 }
574 
575 kdbgstream& kdbgstream::operator<<( const TQVariant& v) {
576  *this << "[variant: ";
577  *this << v.typeName();
578  // For now we just attempt a conversion to string.
579  // Feel free to switch(v.type()) and improve the output.
580  *this << " toString=";
581  *this << v.toString();
582  *this << "]";
583  return *this;
584 }
585 
586 kdbgstream& kdbgstream::operator<<( const TQByteArray& data) {
587  if (!print) return *this;
588  output += '[';
589  unsigned int i = 0;
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');
593  if ( i < sz )
594  output += ' ';
595  }
596  if ( sz < data.size() )
597  output += "...";
598  output += ']';
599  return *this;
600 }
601 
602 #ifdef HAVE_BACKTRACE
603 struct BacktraceFunctionInfo {
604  const void *addr; //< the address of function returned by backtrace()
605  const char* fileName; //< the file of binary owning the function (e.g. shared library or current header)
606  const void *base; //< the base address there the binary is loaded to
607  uintptr_t offset; //< offset of the function in binary (base - address)
608  TQString functionName; //< mangled name of function
609  TQString prettyName; //< demangled name of function
610  TQString sourceName; //< name of source file function declared in
611  unsigned sourceLine; //< line where function defined
612 };
613 
614 #ifdef WITH_LIBBFD
615 
616 // load symbol table from file
617 asymbol** bfdLoadSymtab (bfd *abfd) {
618  long symCount; // count of entries in symbol table
619  long symtab_sz; // size of the table
620  asymbol** rv;
621  bfd_boolean dynamic = FALSE;
622 
623  // make shure the file has symbol table
624  if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
625  return 0;
626  }
627 
628  // determin the amount of space we'll need to store the table
629  symtab_sz = bfd_get_symtab_upper_bound (abfd);
630  if (symtab_sz == 0) {
631  symtab_sz = bfd_get_dynamic_symtab_upper_bound (abfd);
632  dynamic = TRUE;
633  }
634  if (symtab_sz < 0) {
635  return 0;
636  }
637 
638  // allocate memory
639  rv = (asymbol **) malloc(symtab_sz); // dunno, why not malloc
640  if ( !rv ) {
641  return 0;
642  }
643 
644  // actually load the table
645  if (dynamic) {
646  symCount = bfd_canonicalize_dynamic_symtab (abfd, rv);
647  } else {
648  symCount = bfd_canonicalize_symtab (abfd, rv);
649  }
650 
651  if (symCount < 0) {
652  if (rv) {
653  free(rv);
654  }
655  return 0;
656  }
657 
658  return rv;
659 }
660 
661 void bfdFillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
662  static bool inited=0;
663  if (!inited) {
664  bfd_init();
665  inited=1;
666  }
667 
668  bfd *abfd = bfd_openr(func.fileName, 0); // a bfd object
669  if( !abfd ) {
670  return;
671  }
672 
673  // check format of the object
674  if( !bfd_check_format(abfd, bfd_object) ) {
675  bfd_close(abfd);
676  return;
677  }
678 
679  // load symbol table
680  asymbol **syms= bfdLoadSymtab(abfd);
681  if(!syms) {
682  bfd_close(abfd);
683  return;
684  }
685 
686  // found source file and line for given address
687  for (asection *sect = abfd->sections; sect != NULL; sect = sect->next) {
688 
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;
696  unsigned sourceLine;
697  if (bfd_find_nearest_line(abfd, sect, syms, sectOffset,
698  &sourceName, &functionName, &sourceLine))
699  {
700  func.sourceName = sourceName;
701  func.sourceLine = sourceLine;
702  if(func.functionName.isEmpty()) {
703  func.functionName = TQString::fromAscii(functionName);
704  }
705  break;
706  }
707  }
708  }
709  }
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);
713  if (demangled) {
714  func.prettyName = demangled;
715  free(demangled);
716  }
717  }
718 #endif // HAVE_DEMANGLE_H
719 
720  if( syms ) {
721  free(syms);
722  }
723  bfd_close(abfd);
724 }
725 
726 #endif // WITH_LIBBFD
727 
728 void fillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
729 #ifdef WITH_LIBBFD
730  bfdFillAdditionalFunctionsInfo(func);
731 #endif // WITH_LIBBFD
732 
733 #ifdef HAVE_ABI_CXA_DEMANGLE
734  if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
735  int status=0;
736  char *demangled = abi::__cxa_demangle(func.functionName.ascii(), 0, 0, &status);
737  if (demangled) {
738  func.prettyName = demangled;
739  free(demangled);
740  }
741  }
742 #endif // HAVE_ABI_CXA_DEMANGLE
743 
744 }
745 
746 TQString formatBacktrace(void *addr) {
747  TQString rv;
748  BacktraceFunctionInfo func;
749  func.addr = addr;
750 
751  // NOTE: if somebody would compile for some non-linux-glibc platform
752  // check if dladdr function is avalible there
753  Dl_info info;
754  dladdr(func.addr, &info); // obtain information about the function.
755 
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);
760  func.sourceLine = 0;
761 
762  fillAdditionalFunctionsInfo(func);
763 
764  rv.sprintf("0x%0*lx", (int) sizeof(void*)*2, (uintptr_t) func.addr);
765 
766  rv += " in ";
767  if (!func.prettyName.isEmpty()) {
768  rv += func.prettyName;
769  } else if (!func.functionName.isEmpty()) {
770  rv += func.functionName;
771  } else {
772  rv += "??";
773  }
774 
775  if (!func.sourceName.isEmpty()) {
776  rv += " in ";
777  rv += func.sourceName;
778  rv += ":";
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);
782  } else {
783  rv += " from ??";
784  }
785 
786  return rv;
787 }
788 #endif // HAVE_BACKTRACE
789 
790 
791 TQString kdBacktrace(int levels)
792 {
793  TQString rv;
794 #ifdef HAVE_BACKTRACE
795  if (levels < 0 || levels > 256 ) {
796  levels = 256;
797  }
798 
799  rv = "[\n";
800 
801  if (levels) {
802 #ifdef HAVE_ALLOCA
803  void** trace = (void**)alloca(levels * sizeof(void*));
804 #else // HAVE_ALLOCA
805  void* trace[256];
806 #endif // HAVE_ALLOCA
807  levels = backtrace(trace, levels);
808 
809  if (levels) {
810  for (int i = 0; i < levels; ++i) {
811  rv += QString().sprintf("#%-2d ", i);
812  rv += formatBacktrace(trace[i]);
813  rv += '\n';
814  }
815  } else {
816  rv += "backtrace() failed\n";
817  }
818  }
819 
820  rv += "]\n";
821 #endif // HAVE_BACKTRACE
822  return rv;
823 }
824 
825 // Keep for ABI compatability for some time
826 // FIXME remove this (2013-08-18, 18:09, Fat-Zer)
827 TQString kdBacktrace()
828 {
829  return kdBacktrace(-1 /*all*/);
830 }
831 
832 void kdBacktraceFD(int fd) {
833 #ifdef HAVE_BACKTRACE
834  void *trace[256];
835  int levels;
836 
837  levels = backtrace(trace, 256);
838  if (levels) {
839  backtrace_symbols_fd(trace, levels, fd);
840  }
841 #endif // HAVE_BACKTRACE
842 }
843 void kdClearDebugConfig()
844 {
845  if (kDebug_data) {
846  delete kDebug_data->config;
847  kDebug_data->config = 0;
848  }
849 }
850 
851 
852 // Needed for --enable-final
853 #ifdef NDEBUG
854 #define kdDebug kndDebug
855 #endif

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.8.1.2
This website is maintained by Timothy Pearson.