From bf87a8a5142f7ee4d06397e4eb11068ad604a659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Mon, 11 Oct 2004 15:58:51 +0000 Subject: [PATCH] First version with working support for shared libraries! --- mrw/stacktrace.cpp | 340 ++++++++++++++++++++++++--------------------- mrw/stacktrace.hpp | 57 +++++--- 2 files changed, 217 insertions(+), 180 deletions(-) diff --git a/mrw/stacktrace.cpp b/mrw/stacktrace.cpp index 047b29a..15fb4a9 100644 --- a/mrw/stacktrace.cpp +++ b/mrw/stacktrace.cpp @@ -9,6 +9,9 @@ @license LGPL, see file COPYING $Log$ + 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! @@ -31,7 +34,10 @@ */ #include -#include +#include +#include +#include +#include #include #include #include @@ -80,9 +86,8 @@ extern "C" { #include namespace mrw { - //---------------------------------------------------------------------------- - std::string demangle(bfd* abfd, const char* name) { + static std::string demangle(bfd* abfd, const char* name) { if (bfd_get_symbol_leading_char(abfd) == name[0]) ++name; /* This is a hack for better error reporting on XCOFF, PowerPC64-ELF @@ -101,184 +106,199 @@ namespace mrw { } return name; } +} - //---------------------------------------------------------------------------- - StackTrace::StackTrace() throw(std::bad_exception) { - // maximum trace level is limited here to 50, see below why +//---------------------------------------------------------------------------- +mrw::StackTrace::StackTrace() throw(std::bad_exception) { + // maximum trace level is limited here to 50, see below why # if defined(__GLIBC__) - { - const int TRACE_LEVEL(50); - void* ba[TRACE_LEVEL]; - for (int n(backtrace(ba, TRACE_LEVEL)), i(0); i l; - for (AddressTrace::const_reverse_iterator it(_trace.rbegin()); - it!=_trace.rend(); ++it, first=false) { - CodePos c(translate(*it)); - if (log(c.line+1)/LN10 > lisz) lisz = (unsigned int)(log(c.line+1)/LN10); - if (c.file.size() > fisz) fisz = c.file.size(); - l.push_back(c); - } - for (std::list::iterator it(l.begin()); it!=l.end(); ++it) - s<<"["<address<<"] " - <file<<':'<line - <file.size()- - (unsigned int)(log(it->line+1)/LN10)-1) - <<" "<function< l; + for (AddressTrace::const_reverse_iterator it(_trace.rbegin()); + it!=_trace.rend(); ++it, first=false) { + CodePos c(translate(*it)); + if (log(c.line+1)/LN10 > lisz) lisz = (unsigned int)(log(c.line+1)/LN10); + if (c.file.size() > fisz) fisz = c.file.size(); + l.push_back(c); } + for (std::list::iterator it(l.begin()); it!=l.end(); ++it) + s<<"["<address<<"] " + <file<<':'<line + <file.size()- + (unsigned int)(log(it->line+1)/LN10)-1) + <<" "<function<<"\n"; + return s; +} - //---------------------------------------------------------------------------- - const StackTrace& StackTrace::print(std::ostream& os) const - throw(std::bad_exception) { - os<<(std::string)*this; - return *this; - } +//---------------------------------------------------------------------------- +const mrw::StackTrace& mrw::StackTrace::print(std::ostream& os) const + throw(std::bad_exception) { + os<<(std::string)*this; + return *this; +} - //---------------------------------------------------------------------------- - StackTrace::CodePos StackTrace::translate(void* addr) - throw(std::bad_exception) { - assert(sizeof(bfd_vma)>=sizeof(void*)); - bfd_vma vma_addr(reinterpret_cast(addr)); - if (!_dic.get()) return CodePos(addr, "????", "????", 0); - std::vector::iterator - it(std::lower_bound(_addrs.begin(), _addrs.end(), vma_addr)); - if (it--==_addrs.begin() || *it > vma_addr || - (*_dic)[*it].first <= vma_addr) return CodePos(addr, "????", "????", 0); - static const char* file(0); - static const char* function(0); - unsigned int line; - if (!bfd_find_nearest_line(const_cast(static_cast(_bfd)), - (*_dic)[*it].second, _syms.get(), - vma_addr-*it, &file, &function, &line)) - return CodePos(addr, "????", "????", 0); - return CodePos(addr, mrw::demangle(_bfd, function), file?file:"????", line); - } +//---------------------------------------------------------------------------- +mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) + throw(std::bad_exception) { + assert(sizeof(bfd_vma)>=sizeof(void*)); + bfd_vma vma_addr(reinterpret_cast(addr)); + std::map::iterator + it(_addrs.lower_bound(vma_addr)); + if (it==_addrs.begin() || (--it)->first > vma_addr || + _dic.find(it->second)==_dic.end() || + _dic[it->second][it->first].first <= vma_addr) + return CodePos(addr, "????", "????", 0); + static const char* file(0); + static const char* function(0); + unsigned int line; + if (!bfd_find_nearest_line + (const_cast(static_cast(_bfd[it->second])), + _dic[it->second][it->first].second, + _syms[it->second], + vma_addr - it->first, + &file, &function, &line)) + return CodePos(addr, "????", "????", 0); + return CodePos(addr, mrw::demangle(_bfd[it->second], function), + file?file:"????", line); +} - //---------------------------------------------------------------------------- - bool StackTrace::createSymtable(const std::string& fname) - throw(std::bad_exception) { - if (_dic.get()) return true; - AutoBfd abfd(bfd_openr((fname!="" ? fname : filename()).c_str(), 0)); - long memsz(-1); - Auto::Free m(0); - if (!abfd || bfd_check_format(abfd, bfd_archive) || - !bfd_check_format_matches(abfd, bfd_object, &(m.getClean())) || - !(bfd_get_file_flags(const_cast(static_cast(abfd))) - &HAS_SYMS) || - (memsz=bfd_get_symtab_upper_bound - (const_cast(static_cast(abfd))))<0) - return false; - std::auto_ptr syms(new asymbol*[memsz]); - if (bfd_canonicalize_symtab(const_cast(static_cast(abfd)), - syms.get())<0) - return false; - _bfd = abfd; - _syms = syms; - _dic = std::auto_ptr(new Translator()); - bfd_map_over_sections(_bfd, buildSectionMap, 0); - std::sort(_addrs.begin(), _addrs.end()); - return true; - } +//---------------------------------------------------------------------------- +bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) + throw(std::bad_exception) { + if (_dic.find(fname)!=_dic.end()) return true; // already loaded + if (fname=="") return createSymtable(filename()); + AutoBfd abfd(bfd_openr(fname.c_str(), 0)); + long memsz(-1); + Auto::Free m(0); + if (!abfd || bfd_check_format(abfd, bfd_archive) || + !bfd_check_format_matches(abfd, bfd_object, &(m.getClean())) || + !(bfd_get_file_flags(const_cast(static_cast(abfd))) + &HAS_SYMS) || + (memsz=bfd_get_symtab_upper_bound + (const_cast(static_cast(abfd))))<0) + return false; + mrw::AutoPtr syms(new asymbol*[memsz]); + if (bfd_canonicalize_symtab(const_cast(static_cast(abfd)), + syms)<0) + return false; + _bfd[fname] = abfd; + _syms[fname] = syms; + _dic[fname]; + std::pair fileoffs = std::make_pair(fname, offs); + bfd_map_over_sections(_bfd[fname], buildSectionMap, &fileoffs); + return true; +} - //---------------------------------------------------------------------------- - bool StackTrace::createSymtable(const std::list& fnames) - throw(std::bad_exception) { - if (_dic.get()) return true; - for (std::list::const_iterator it(fnames.begin()); - it!=fnames.end(); ++it) { - AutoBfd abfd(bfd_openr(it->c_str(), 0)); - long memsz(-1); - Auto::Free m(0); - if (!abfd || bfd_check_format(abfd, bfd_archive) || - !bfd_check_format_matches(abfd, bfd_object, &(m.getClean())) || - !(bfd_get_file_flags(const_cast(static_cast(abfd))) - &HAS_SYMS) || - (memsz=bfd_get_symtab_upper_bound - (const_cast(static_cast(abfd))))<0) - return false; - std::auto_ptr syms(new asymbol*[memsz]); - if (bfd_canonicalize_symtab(const_cast(static_cast(abfd)), - syms.get())<0) - return false; - _bfd = abfd; - _syms = syms; - if (!_dic.get()) _dic = std::auto_ptr(new Translator()); - bfd_map_over_sections(_bfd, buildSectionMap, 0); - } - std::sort(_addrs.begin(), _addrs.end()); - return true; +//---------------------------------------------------------------------------- +bool mrw::StackTrace::createSymtable(const mrw::StackTrace::BinFiles& files) + throw(std::bad_exception) { + bool success(true); + for (BinFiles::const_iterator it(files.begin()); + it!=files.end(); ++it) { + if (!createSymtable(it->first, it->second)) success=false; } + return success; +} - //---------------------------------------------------------------------------- - std::string StackTrace::filename() throw(std::bad_exception) { - std::stringstream s; - s<<"/proc/"< "); + if (pos>address; + if (file.size()) res< StackTrace::_dic; - std::vector StackTrace::_addrs; - AutoBfd StackTrace::_bfd; - std::auto_ptr StackTrace::_syms; - +//---------------------------------------------------------------------------- +void mrw::StackTrace::buildSectionMap(bfd* abfd, asection* section, + void* fileoffs) + throw(std::bad_exception) { + if (!abfd || !section || !fileoffs) return; + if (!(bfd_get_section_flags(abfd, section)&SEC_ALLOC)) return; + std::pair fileoffset = + *(std::pair*)fileoffs; + bfd_vma vma(bfd_get_section_vma(abfd, section)+ + reinterpret_cast(fileoffset.second)); + bfd_size_type sz(bfd_get_section_size_before_reloc(section)); + _dic[fileoffset.first][vma] = Translator::mapped_type(vma+sz, section); + _addrs[vma] = fileoffset.first; } + +//---------------------------------------------------------------------------- +std::map mrw::StackTrace::_dic; +std::map + mrw::StackTrace::_addrs; +std::map mrw::StackTrace::_bfd; +std::map > mrw::StackTrace::_syms; diff --git a/mrw/stacktrace.hpp b/mrw/stacktrace.hpp index 116c967..23fdd5e 100644 --- a/mrw/stacktrace.hpp +++ b/mrw/stacktrace.hpp @@ -9,6 +9,9 @@ @license LGPL, see file COPYING $Log$ + Revision 1.7 2004/10/11 15:58:51 marc + First version with working support for shared libraries! + Revision 1.6 2004/10/07 16:59:12 marc new method createSymtable that takes a list of arguments -> untested! @@ -143,18 +146,21 @@ namespace mrw { ger symbolic information from libraries linked to the executable. Perhaps it could be possible, if I'd add a possibility to read and evaluate these libraries, but that's for - a future release. + a future release. (Now, 10/08/2004, I am working on it) @todo Add support to read debugging information from libraries - that are linked to the executable. + that are linked to the executable. (soon) @todo Add support for alternative symbol evaluation using @c backtrace_symbols. */ class StackTrace { - public: + public: //............................................................... typedefs - typedef std::vector AddressTrace; ///< container for the adresses + /// container for the adresses + typedef std::vector AddressTrace; + /// binary file with offset (for shared libraries, 0 for executables) + typedef std::list< std::pair > BinFiles; /// structure to store all evaluated information struct CodePos { CodePos(void* a, std::string fn, std::string fi, unsigned int l) @@ -187,6 +193,9 @@ namespace mrw { and Solaris, this can be evaluated automatically, so the parameter is optional. + @param offs Offset of the address space. It is 0 for + executables, but must be given for shared libraries. + @return @c true in case of success. If @c false is returned, the symbol table was not read and the evaluation cannot be done. Printing then only prints the raw addresses, without @@ -203,15 +212,17 @@ namespace mrw { are created only the first time, so you don't loose too much time. */ - static bool createSymtable(const std::string& fname="") + static bool createSymtable(const std::string& fname="", void* offs=0) throw(std::bad_exception); /** @brief read the symbol table from a list of an executable file and shared libraries - @param fnames The list of file names that must contain the + @param files The list of file names that must contain the executable plus all shared libraries that should be included - in stack traces. + in stack traces. Every file name has an offset address as + second parameter. This offset must be given for shared + libraries and can be retrieved using the program @c ldd. @return @c true in case of success. If @c false is returned, the symbol table was not completely read and the evaluation @@ -228,8 +239,8 @@ namespace mrw { @note If this method is called more than once, the symbols are created only the first time, so you don't loose too much time. - */ - static bool createSymtable(const std::list& fnames) throw(std::bad_exception); + */ + static bool createSymtable(const BinFiles& files) throw(std::bad_exception); private: //............................................................... typedefs @@ -237,22 +248,28 @@ namespace mrw { Translator; //.............................................................. variables AddressTrace _trace; - static std::auto_ptr _dic; - static std::vector _addrs; - static AutoBfd _bfd; - static std::auto_ptr _syms; + static std::map _dic; + static std::map _addrs; + static std::map _bfd; + static std::map > _syms; //................................................................ methods - static std::string filename() throw(std::bad_exception); + static BinFiles filename() throw(std::bad_exception); static void buildSectionMap(bfd*, asection*, void*) throw(std::bad_exception); }; - /// evaluate a stack trace and shift it on a stream - inline std::ostream& operator<<(std::ostream& os, const StackTrace& st) - throw(std::bad_exception) { - return os<<(std::string)st; - } - //@} } + +/** @addtogroup StackTrace */ +//@{ + +/// evaluate a stack trace and shift it on a stream +inline std::ostream& operator<<(std::ostream& os, const mrw::StackTrace& st) + throw(std::bad_exception) { + return os<<(std::string)st; +} + +//@} + #endif