- make it compilable with gcc 4.0.2
- improvements in error reporting, fixes for actual linux - only include libltdl if necessary
This commit is contained in:
		| @@ -8,61 +8,15 @@ | |||||||
|     @copy © Marc Wäckerlin |     @copy © Marc Wäckerlin | ||||||
|     @license LGPL, see file <a href="license.html">COPYING</a> |     @license LGPL, see file <a href="license.html">COPYING</a> | ||||||
|  |  | ||||||
|     $Log$ |  | ||||||
|     Revision 1.14  2005/03/11 23:22:58  marc |  | ||||||
|     It's multithreaded now, thanks to a boost mutex |  | ||||||
|  |  | ||||||
|     Revision 1.13  2005/02/28 07:28:37  marc |  | ||||||
|     typo |  | ||||||
|  |  | ||||||
|     Revision 1.12  2005/02/28 07:14:03  marc |  | ||||||
|     change in getting section size for SUN Solaris (old bfd.h) |  | ||||||
|  |  | ||||||
|     Revision 1.11  2005/02/18 15:48:56  marc |  | ||||||
|     Dynamic loading of libbfd, no more dependency on specific libbfd version! |  | ||||||
|  |  | ||||||
|     Revision 1.10  2005/01/28 07:51:24  marc |  | ||||||
|     improved and corrected trace formatting |  | ||||||
|  |  | ||||||
|     Revision 1.9  2005/01/07 00:34:38  marc |  | ||||||
|     some changes for solaris |  | ||||||
|  |  | ||||||
|     Revision 1.8  2004/12/20 13:22:25  marc |  | ||||||
|     mrw string now throws exceptions, catch needed |  | ||||||
|  |  | ||||||
|     Revision 1.7  2004/10/13 10:47:15  marc |  | ||||||
|     no more need for ldd in StackTrace, read from /proc/self/maps |  | ||||||
|  |  | ||||||
|     Revision 1.6  2004/10/11 15:58:51  marc |  | ||||||
|     First version with working support for shared libraries! |  | ||||||
|  |  | ||||||
|     Revision 1.5  2004/10/07 16:59:12  marc |  | ||||||
|     new method createSymtable that takes a list of arguments |  | ||||||
|      -> untested! |  | ||||||
|  |  | ||||||
|     Revision 1.4  2004/10/07 09:32:45  marc |  | ||||||
|     correction in parameter (const&) |  | ||||||
|  |  | ||||||
|     Revision 1.3  2004/08/28 16:21:25  marc |  | ||||||
|     mrw-c++-0.92 (mrw) |  | ||||||
|     - new file: version.cpp |  | ||||||
|     - new file header for all sources |  | ||||||
|     - work around warning in mrw::auto<T> |  | ||||||
|     - possibility to compile without log4cxx |  | ||||||
|     - work around bugs in demangle.h and libiberty.h |  | ||||||
|     - corrections in documentation |  | ||||||
|     - added simple tracing mechanism |  | ||||||
|     - more warnings |  | ||||||
|     - small corrections in Auto<>::Free and a new test for it |  | ||||||
|     - possibility to compile without stack trace |  | ||||||
|  |  | ||||||
| */ | */ | ||||||
| #include <mrw/stacktrace.hpp> | #include <mrw/stacktrace.hpp> | ||||||
| #include <mrw/exec.hpp> | #include <mrw/exec.hpp> | ||||||
| #include <mrw/string.hpp> | #include <mrw/string.hpp> | ||||||
| #include <mrw/list.hpp> | #include <mrw/list.hpp> | ||||||
| #include <mrw/stdext.hpp> | #include <mrw/stdext.hpp> | ||||||
| #include <mrw/dynamiclibrary.hpp> | #ifndef NO_LTDL | ||||||
|  | # include <mrw/dynamiclibrary.hpp> | ||||||
|  | #endif | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| @@ -80,36 +34,28 @@ | |||||||
| #include <execinfo.h> | #include <execinfo.h> | ||||||
| #endif | #endif | ||||||
| #include <bfd.h> | #include <bfd.h> | ||||||
| extern "C" { |  | ||||||
|  |  | ||||||
|   /// @bug redefined in libiberty.h |  | ||||||
| # define HAVE_DECL_BASENAME 1 |  | ||||||
|   /// @bug redefined in libiberty.h |  | ||||||
| # define HAVE_DECL_ASPRINTF 1 |  | ||||||
|   /// @bug redefined in libiberty.h |  | ||||||
| # define HAVE_DECL_VASPRINTF 1 |  | ||||||
| /** @bug |  | ||||||
|  |  | ||||||
|        - in file file: /usr/include/demangle.h |  | ||||||
|        - of package:   binutils-2.15.90.0.1.1-31 |  | ||||||
|  |  | ||||||
|       Someone unfortunately abused the C++ keyword @c typename as |  | ||||||
|       variable name to @c cplus_demangle_fill_builtin_type, so I have |  | ||||||
|       to work around it. |  | ||||||
|   */       |  | ||||||
| # define typename anotherNameThatsNotAKeyword |  | ||||||
| #   include <demangle.h> |  | ||||||
| # undef typename |  | ||||||
| //   // copied from demangle.h because of compiler warnings in libliberty.h |  | ||||||
| //   // (... throws different exception) |  | ||||||
| // #define DMGL_PARAMS	 (1 << 0)	/* Include function args */ |  | ||||||
| // #define DMGL_ANSI	 (1 << 1)	/* Include const, volatile, etc */ |  | ||||||
| //   /// @bug demangle.h includes libiberty.h which throws different |  | ||||||
| //   ///      exceptions for the same functions than other standard libraries, |  | ||||||
| //   ///      so I can't include demangle.h! |  | ||||||
| // extern char * cplus_demangle(const char *, int); |  | ||||||
| } |  | ||||||
| #include <iomanip> | #include <iomanip> | ||||||
|  | #if HAVE_DEMANGLE_H | ||||||
|  | /* the defines work around wrong definitions in libiberty.h */ | ||||||
|  | #define HAVE_DECL_BASENAME 1 | ||||||
|  | #define HAVE_DECL_FFS 1 | ||||||
|  | #define HAVE_DECL_ASPRINTF 1 | ||||||
|  | #define HAVE_DECL_VASPRINTF 1 | ||||||
|  | #define HAVE_DECL_SNPRINTF 1 | ||||||
|  | #define HAVE_DECL_VSNPRINTF 1 | ||||||
|  | #define HAVE_DECL_STRVERSCMP 1 | ||||||
|  | # include <demangle.h> | ||||||
|  | #else | ||||||
|  | # define DMGL_PARAMS	 (1 << 0)	/* Include function args */ | ||||||
|  | # define DMGL_ANSI	 (1 << 1)	/* Include const, volatile, etc */ | ||||||
|  |   extern "C" { | ||||||
|  |     extern char * cplus_demangle(const char *, int); | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if (__GNUC__==3 && __GNUC_MINOR__<4 || __GNUC__<3) && _REENTRANT && !_MT | ||||||
|  | #define _MT | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace mrw { | namespace mrw { | ||||||
|   //---------------------------------------------------------------------------- |   //---------------------------------------------------------------------------- | ||||||
| @@ -202,9 +148,10 @@ const mrw::StackTrace& mrw::StackTrace::print(std::ostream& os) const | |||||||
| //---------------------------------------------------------------------------- | //---------------------------------------------------------------------------- | ||||||
| mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) | mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) | ||||||
|   throw(std::bad_exception) { |   throw(std::bad_exception) { | ||||||
| #ifdef _REENTRANT | #ifdef _MT | ||||||
|   boost::recursive_mutex::scoped_lock lock(_mutex); |   boost::recursive_mutex::scoped_lock lock(_mutex); | ||||||
| #endif | #endif | ||||||
|  |   static const CodePos UNKNOWN(addr, "????", "????", 0); | ||||||
|   assert(sizeof(bfd_vma)>=sizeof(void*)); |   assert(sizeof(bfd_vma)>=sizeof(void*)); | ||||||
|   bfd_vma vma_addr(reinterpret_cast<bfd_vma>(addr)); |   bfd_vma vma_addr(reinterpret_cast<bfd_vma>(addr)); | ||||||
|   std::map<Translator::key_type, std::string>::iterator |   std::map<Translator::key_type, std::string>::iterator | ||||||
| @@ -212,7 +159,7 @@ mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) | |||||||
|   if (it==_addrs.begin() || (--it)->first > vma_addr || |   if (it==_addrs.begin() || (--it)->first > vma_addr || | ||||||
|       _dic.find(it->second)==_dic.end() || |       _dic.find(it->second)==_dic.end() || | ||||||
|       _dic[it->second][it->first].first <= vma_addr) |       _dic[it->second][it->first].first <= vma_addr) | ||||||
|     return CodePos(addr, "????", "????", 0); |     return UNKNOWN; | ||||||
|   static const char* file(0); |   static const char* file(0); | ||||||
|   static const char* function(0); |   static const char* function(0); | ||||||
|   unsigned int line; |   unsigned int line; | ||||||
| @@ -222,7 +169,7 @@ mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) | |||||||
|        _syms[it->second], |        _syms[it->second], | ||||||
|        vma_addr - it->first, |        vma_addr - it->first, | ||||||
|        &file, &function, &line)) |        &file, &function, &line)) | ||||||
|     return CodePos(addr, "????", "????", 0); |     return UNKNOWN; | ||||||
|   return CodePos(addr, mrw::demangle(_bfd[it->second], function), |   return CodePos(addr, mrw::demangle(_bfd[it->second], function), | ||||||
|                  file?file:"????", line); |                  file?file:"????", line); | ||||||
| } | } | ||||||
| @@ -230,11 +177,22 @@ mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) | |||||||
| //---------------------------------------------------------------------------- | //---------------------------------------------------------------------------- | ||||||
| bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) | bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) | ||||||
|     throw(std::bad_exception) { |     throw(std::bad_exception) { | ||||||
| #ifdef _REENTRANT | #ifdef _MT | ||||||
|   boost::recursive_mutex::scoped_lock lock(_mutex); |   boost::recursive_mutex::scoped_lock lock(_mutex); | ||||||
| #endif | #endif | ||||||
|   if (_dic.find(fname)!=_dic.end()) return true; // already loaded |   if (_dic.find(fname)!=_dic.end()) return true; // already loaded | ||||||
|   try { |   try { | ||||||
|  | #if NO_LTDL | ||||||
|  |     static bfd*(*bfd_openr)(const char*, const char*) = | ||||||
|  |       ::bfd_openr; | ||||||
|  |     static bfd_boolean(*bfd_check_format)(bfd*, bfd_format) = | ||||||
|  |       ::bfd_check_format; | ||||||
|  |     static bfd_boolean(*bfd_check_format_matches)(bfd*, bfd_format, char***) = | ||||||
|  |       ::bfd_check_format_matches; | ||||||
|  |     static void(*bfd_map_over_sections) | ||||||
|  |       (bfd*, void(*)(bfd*, asection*, void*), void*) = | ||||||
|  |       ::bfd_map_over_sections; | ||||||
|  | #else | ||||||
|     static DynamicLibrary lib("libbfd"); |     static DynamicLibrary lib("libbfd"); | ||||||
|     static bfd*(*bfd_openr)(const char*, const char*) = |     static bfd*(*bfd_openr)(const char*, const char*) = | ||||||
|       (bfd*(*)(const char*, const char*))lib.symbol("bfd_openr"); |       (bfd*(*)(const char*, const char*))lib.symbol("bfd_openr"); | ||||||
| @@ -247,6 +205,7 @@ bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) | |||||||
|       (bfd*, void(*)(bfd*, asection*, void*), void*) = |       (bfd*, void(*)(bfd*, asection*, void*), void*) = | ||||||
|       (void(*)(bfd*, void(*)(bfd*, asection*, void*), void*)) |       (void(*)(bfd*, void(*)(bfd*, asection*, void*), void*)) | ||||||
|       lib.symbol("bfd_map_over_sections"); |       lib.symbol("bfd_map_over_sections"); | ||||||
|  | #endif | ||||||
|     if (fname=="") return createSymtable(filename()); |     if (fname=="") return createSymtable(filename()); | ||||||
|     AutoBfd abfd((*bfd_openr)(fname.c_str(), 0)); |     AutoBfd abfd((*bfd_openr)(fname.c_str(), 0)); | ||||||
|     long memsz(-1); |     long memsz(-1); | ||||||
| @@ -256,19 +215,27 @@ bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) | |||||||
|         !(bfd_get_file_flags(const_cast<bfd*>(static_cast<const bfd*>(abfd))) |         !(bfd_get_file_flags(const_cast<bfd*>(static_cast<const bfd*>(abfd))) | ||||||
|           &HAS_SYMS) || |           &HAS_SYMS) || | ||||||
|         (memsz=bfd_get_symtab_upper_bound |         (memsz=bfd_get_symtab_upper_bound | ||||||
|          (const_cast<bfd*>(static_cast<const bfd*>(abfd))))<0) |          (const_cast<bfd*>(static_cast<const bfd*>(abfd))))<0) { | ||||||
|  |       _error = "cannot map bfd symbols - 'bfd_get_file_flags' failed " | ||||||
|  |         "for file: \""+fname+'"'; | ||||||
|       return false; |       return false; | ||||||
|  |     } | ||||||
|     mrw::AutoPtr<asymbol*> syms(new asymbol*[memsz]); |     mrw::AutoPtr<asymbol*> syms(new asymbol*[memsz]); | ||||||
|     if (bfd_canonicalize_symtab(const_cast<bfd*>(static_cast<const bfd*>(abfd)), |     if (bfd_canonicalize_symtab(const_cast<bfd*>(static_cast<const bfd*>(abfd)), | ||||||
|                                 syms)<0) |                                 syms)<0) { | ||||||
|  |       _error = "cannot map bfd symbols - 'bfd_canonicalize_symtab' failed" | ||||||
|  |         "for file: \""+fname+'"'; | ||||||
|       return false; |       return false; | ||||||
|  |     } | ||||||
|     _bfd[fname] = abfd; |     _bfd[fname] = abfd; | ||||||
|     _syms[fname] = syms; |     _syms[fname] = syms; | ||||||
|     _dic[fname]; |     _dic[fname]; | ||||||
|     std::pair<std::string, void*> fileoffs = std::make_pair(fname, offs); |     std::pair<std::string, void*> fileoffs = std::make_pair(fname, offs); | ||||||
|     (*bfd_map_over_sections)(_bfd[fname], buildSectionMap, &fileoffs); |     (*bfd_map_over_sections)(_bfd[fname], buildSectionMap, &fileoffs); | ||||||
|     return true; |     return true; | ||||||
|   } catch (...) { |   } catch (const std::exception& x) { | ||||||
|  |     _error = std::string("exception received: \"")+x.what()+"\", " | ||||||
|  |       "while processing file: \""+fname+'"'; | ||||||
|     return false; // shared library for bfd not found or similar |     return false; // shared library for bfd not found or similar | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -276,7 +243,7 @@ bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) | |||||||
| //---------------------------------------------------------------------------- | //---------------------------------------------------------------------------- | ||||||
| bool mrw::StackTrace::createSymtable(const mrw::StackTrace::BinFiles& files) | bool mrw::StackTrace::createSymtable(const mrw::StackTrace::BinFiles& files) | ||||||
|   throw(std::bad_exception) { |   throw(std::bad_exception) { | ||||||
| #ifdef _REENTRANT | #ifdef _MT | ||||||
|   boost::recursive_mutex::scoped_lock lock(_mutex); |   boost::recursive_mutex::scoped_lock lock(_mutex); | ||||||
| #endif | #endif | ||||||
|   bool success(true); |   bool success(true); | ||||||
| @@ -290,8 +257,12 @@ bool mrw::StackTrace::createSymtable(const mrw::StackTrace::BinFiles& files) | |||||||
| //---------------------------------------------------------------------------- | //---------------------------------------------------------------------------- | ||||||
| int mrw::StackTrace::bfdClose(bfd* abfd) throw() { | int mrw::StackTrace::bfdClose(bfd* abfd) throw() { | ||||||
|   try { |   try { | ||||||
|  | #if NO_LTDL | ||||||
|  |     static int(*bfd_close)(bfd*) = ::bfd_close; | ||||||
|  | #else | ||||||
|     static DynamicLibrary lib(""); |     static DynamicLibrary lib(""); | ||||||
|     static int(*bfd_close)(bfd*) = (int(*)(bfd*))lib.symbol("bfd_close"); |     static int(*bfd_close)(bfd*) = (int(*)(bfd*))lib.symbol("bfd_close"); | ||||||
|  | #endif | ||||||
|     return (*bfd_close)(abfd); |     return (*bfd_close)(abfd); | ||||||
|   } catch (...) { |   } catch (...) { | ||||||
|     return -1; // dynamic library loading problems |     return -1; // dynamic library loading problems | ||||||
| @@ -324,7 +295,11 @@ mrw::StackTrace::BinFiles mrw::StackTrace::filename() | |||||||
|       range.resize(range.find_first_not_of("0123456789abcdefABCDEF")); |       range.resize(range.find_first_not_of("0123456789abcdefABCDEF")); | ||||||
|       void* addr(0); |       void* addr(0); | ||||||
|       range>>addr; |       range>>addr; | ||||||
|       if (lib.size() && addr>0) res<<BinFiles::value_type(lib, addr); |       // added check: no names in brackets: [lib], because there are | ||||||
|  |       // [heap], [stack] and [vdso] that cannot be loaded | ||||||
|  |       // question: should only files with ending '.so' be loaded? | ||||||
|  |       if (lib.size() && lib[0]!='[' && lib[lib.size()-1]!=']' && addr>0) | ||||||
|  |         res<<BinFiles::value_type(lib, addr); | ||||||
|     } catch (...) {} // ignore non matching lines |     } catch (...) {} // ignore non matching lines | ||||||
|     return res; |     return res; | ||||||
|   } |   } | ||||||
| @@ -365,6 +340,7 @@ std::map<mrw::StackTrace::Translator::key_type, std::string> | |||||||
|   mrw::StackTrace::_addrs; |   mrw::StackTrace::_addrs; | ||||||
| std::map<std::string, mrw::StackTrace::AutoBfd> mrw::StackTrace::_bfd; | std::map<std::string, mrw::StackTrace::AutoBfd> mrw::StackTrace::_bfd; | ||||||
| std::map<std::string, mrw::AutoPtr<asymbol*> > mrw::StackTrace::_syms; | std::map<std::string, mrw::AutoPtr<asymbol*> > mrw::StackTrace::_syms; | ||||||
| #ifdef _REENTRANT | #ifdef _MT | ||||||
| boost::recursive_mutex mrw::StackTrace::_mutex; | boost::recursive_mutex mrw::StackTrace::_mutex; | ||||||
| #endif | #endif | ||||||
|  | std::string mrw::StackTrace::_error; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user