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