00001 // 00002 // Function to get a backtrace 00003 // 00004 // Fixed so that it correctly demangles the function names! 00005 // 00006 // See glibc documentation for backtrace 00007 // (http://www.gnu.org/software/libc/manual/html_node/Backtraces.html#Backtraces) 00008 // 00009 // This code comes from a mailing list discussion at: 00010 // http://lists.trolltech.com/qt-interest/2006-07/thread00444-0.html 00011 // I owe the author my eternal gratitude. 00012 00013 #include <QtCore/QObject> 00014 #include <QtCore/QString> 00015 #include <QtCore/QStringList> 00016 #include <QtCore/QRegExp> 00017 00018 #ifdef _HAVE_EXECINFO_H_ 00019 #include <execinfo.h> 00020 #include <cxxabi.h> 00021 #endif 00022 00023 00024 //need to extract the symbol from the output of 'backtrace_symbols' 00025 00026 //a typical output from backtrace_symbols will look like; 00027 //a.out(_ZNK1A12getBackTraceEv+0x12) [0x804ad36] 00028 00029 // This needs to be split into; 00030 // (1) The program or library containing the symbol (a.out) 00031 // (2) The symbol itself (_ZNK1A12getBackTraceEv) 00032 // (3) The offset? +0x12 00033 // (4) The symbol address ([0x804ad36]) 00034 00035 // This is achieved by the regexp below 00036 00037 // (unit ) (symbol) (offset) (address) 00038 QRegExp btregexp("([^(]+)\\(([^)^+]+)(\\+[^)]+)\\)\\s(\\[[^]]+\\])"); 00039 00040 00045 QStringList getBackTrace() 00046 { 00047 //now get the backtrace of the code at this point 00048 //(we can only do this if we have 'execinfo.h' 00049 #ifdef _HAVE_EXECINFO_H_ 00050 00051 //create a void* array to hold the function addresses. We will only go at most 25 deep 00052 const int maxdepth(25); 00053 00054 void *func_addresses[maxdepth]; 00055 int nfuncs = backtrace(func_addresses, maxdepth); 00056 00057 //now get the function names associated with these symbols. This should work for elf 00058 //binaries, though additional linker options may need to have been called 00059 //(e.g. -rdynamic for GNU ld. See the glibc documentation for 'backtrace') 00060 char **symbols = backtrace_symbols(func_addresses, nfuncs); 00061 00062 //save all of the function names onto the QStringList.... 00063 //(note that none of this will work if we have run out of memory) 00064 QStringList ret; 00065 00066 for (int i=0; i<nfuncs; i++) 00067 { 00068 if (btregexp.indexIn(symbols[i]) != -1) 00069 { 00070 //get the library or app that contains this symbol 00071 QString unit = btregexp.cap(1); 00072 //get the symbol 00073 QString symbol = btregexp.cap(2); 00074 //get the offset 00075 QString offset = btregexp.cap(3); 00076 //get the address 00077 QString address = btregexp.cap(4); 00078 00079 //now try and demangle the symbol 00080 int stat; 00081 char *demangled = 00082 abi::__cxa_demangle(qPrintable(symbol),0,0,&stat); 00083 00084 if (demangled) 00085 { 00086 symbol = demangled; 00087 delete demangled; 00088 } 00089 00090 //put this all together 00091 ret.append( QString("%1: %2 %3").arg(unit,symbol,address) ); 00092 } 00093 else 00094 { 00095 //I don't recognise this string - just add the raw 00096 //string to the backtrace 00097 ret.append(symbols[i]); 00098 } 00099 } 00100 00101 //we now need to release the memory of the symbols array. Since it was allocated using 00102 //malloc, we must release it using 'free' 00103 delete symbols; 00104 00105 return ret; 00106 00107 #else 00108 return QStringList( QObject::tr( 00109 "Backtrace is not available without execinfo.h") 00110 ); 00111 #endif 00112 00113 }