First version with working support for shared libraries!

master
Marc Wäckerlin 20 years ago
parent 3e155bb303
commit bf87a8a514
  1. 166
      mrw/stacktrace.cpp
  2. 45
      mrw/stacktrace.hpp

@ -9,6 +9,9 @@
@license LGPL, see file <a href="license.html">COPYING</a>
$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 <mrw/stacktrace.hpp>
#include <sstream>
#include <mrw/exec.hpp>
#include <mrw/string.hpp>
#include <mrw/list.hpp>
#include <mrw/stdext.hpp>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -80,9 +86,8 @@ extern "C" {
#include <iomanip>
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,9 +106,10 @@ namespace mrw {
}
return name;
}
}
//----------------------------------------------------------------------------
StackTrace::StackTrace() throw(std::bad_exception) {
mrw::StackTrace::StackTrace() throw(std::bad_exception) {
// maximum trace level is limited here to 50, see below why
# if defined(__GLIBC__)
{
@ -134,9 +140,10 @@ namespace mrw {
}
//----------------------------------------------------------------------------
StackTrace::operator std::string() const throw(std::bad_exception) {
mrw::StackTrace::operator std::string() const throw(std::bad_exception) {
static const double LN10(log(10));
std::stringstream s;
std::string s;
s<<1;
bool first(true);
unsigned int lisz(0), fisz(0);
std::list<CodePos> l;
@ -152,42 +159,48 @@ namespace mrw {
<<it->file<<':'<<it->line
<<std::setw(fisz+lisz-it->file.size()-
(unsigned int)(log(it->line+1)/LN10)-1)
<<" "<<it->function<<std::endl;
return s.str();
<<" "<<it->function<<"\n";
return s;
}
//----------------------------------------------------------------------------
const StackTrace& StackTrace::print(std::ostream& os) const
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)
mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr)
throw(std::bad_exception) {
assert(sizeof(bfd_vma)>=sizeof(void*));
bfd_vma vma_addr(reinterpret_cast<bfd_vma>(addr));
if (!_dic.get()) return CodePos(addr, "????", "????", 0);
std::vector<Translator::key_type>::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);
std::map<Translator::key_type, std::string>::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<bfd*>(static_cast<const bfd*>(_bfd)),
(*_dic)[*it].second, _syms.get(),
vma_addr-*it, &file, &function, &line))
if (!bfd_find_nearest_line
(const_cast<bfd*>(static_cast<const bfd*>(_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, function), file?file:"????", line);
return CodePos(addr, mrw::demangle(_bfd[it->second], function),
file?file:"????", line);
}
//----------------------------------------------------------------------------
bool StackTrace::createSymtable(const std::string& fname)
bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs)
throw(std::bad_exception) {
if (_dic.get()) return true;
AutoBfd abfd(bfd_openr((fname!="" ? fname : filename()).c_str(), 0));
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<char**>::Free m(0);
if (!abfd || bfd_check_format(abfd, bfd_archive) ||
@ -197,88 +210,95 @@ namespace mrw {
(memsz=bfd_get_symtab_upper_bound
(const_cast<bfd*>(static_cast<const bfd*>(abfd))))<0)
return false;
std::auto_ptr<asymbol*> syms(new asymbol*[memsz]);
mrw::AutoPtr<asymbol*> syms(new asymbol*[memsz]);
if (bfd_canonicalize_symtab(const_cast<bfd*>(static_cast<const bfd*>(abfd)),
syms.get())<0)
syms)<0)
return false;
_bfd = abfd;
_syms = syms;
_dic = std::auto_ptr<Translator>(new Translator());
bfd_map_over_sections(_bfd, buildSectionMap, 0);
std::sort(_addrs.begin(), _addrs.end());
_bfd[fname] = abfd;
_syms[fname] = syms;
_dic[fname];
std::pair<std::string, void*> fileoffs = std::make_pair(fname, offs);
bfd_map_over_sections(_bfd[fname], buildSectionMap, &fileoffs);
return true;
}
//----------------------------------------------------------------------------
bool StackTrace::createSymtable(const std::list<std::string>& fnames)
bool mrw::StackTrace::createSymtable(const mrw::StackTrace::BinFiles& files)
throw(std::bad_exception) {
if (_dic.get()) return true;
for (std::list<std::string>::const_iterator it(fnames.begin());
it!=fnames.end(); ++it) {
AutoBfd abfd(bfd_openr(it->c_str(), 0));
long memsz(-1);
Auto<char**>::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<bfd*>(static_cast<const bfd*>(abfd)))
&HAS_SYMS) ||
(memsz=bfd_get_symtab_upper_bound
(const_cast<bfd*>(static_cast<const bfd*>(abfd))))<0)
return false;
std::auto_ptr<asymbol*> syms(new asymbol*[memsz]);
if (bfd_canonicalize_symtab(const_cast<bfd*>(static_cast<const bfd*>(abfd)),
syms.get())<0)
return false;
_bfd = abfd;
_syms = syms;
if (!_dic.get()) _dic = std::auto_ptr<Translator>(new Translator());
bfd_map_over_sections(_bfd, buildSectionMap, 0);
bool success(true);
for (BinFiles::const_iterator it(files.begin());
it!=files.end(); ++it) {
if (!createSymtable(it->first, it->second)) success=false;
}
std::sort(_addrs.begin(), _addrs.end());
return true;
return success;
}
//----------------------------------------------------------------------------
std::string StackTrace::filename() throw(std::bad_exception) {
std::stringstream s;
mrw::StackTrace::BinFiles mrw::StackTrace::filename()
throw(std::bad_exception) {
mrw::StackTrace::BinFiles res;
std::string s;
s<<"/proc/"<<getpid();
# if defined(__solaris__)
{
std::string res;
AutoFile fd(open(s.str().c_str(), O_RDONLY));
AutoFile fd(open(s.str(), O_RDONLY));
prpsinfo_t status;
if (fd==-1 || ioctl(fd, PIOCPSINFO, &status)==-1) return res;
res = status.pr_psargs;
res = res.substr(0, res.find(' '));
return res;
s = status.pr_psargs;
return res<<BinFiles::value_type(s.substr(0, s.find(' ')), 0);
}
# elif defined(__linux__)
{
s<<"/exe";
return s.str();
res<<BinFiles::value_type(s<<"/exe", 0);
try {
mrw::Exec ldd = (mrw::Cmd("/usr/bin/ldd"), s).execute();
for (std::string lddres(ldd.result());
lddres.size();
lddres.erase(0, min(lddres.find('\n')+1, std::string::npos))) {
std::string line(lddres.substr(0, lddres.find('\n')));
std::string::size_type pos = line.find(" => ");
if (pos<std::string::npos) {
pos += 4;
std::string file = line.substr(pos, (pos=line.find(' ', pos)-pos));
std::stringstream addr;
addr<<line.substr(++(pos=line.find('(', pos)),
line.find(')', pos)-pos);
void* address(0);
addr>>address;
if (file.size()) res<<BinFiles::value_type(file, address);
}
}
} catch (mrw::ExecutionFailedExc&) {}
return res;
}
# else
{
# warning "Don't know how to get executable file name in your system!"
# warning "Impossible to get function names in stack trace!"
# warning "Give the path to the executable to StackTrace::createSymtable!"
abort();
}
# endif
}
//----------------------------------------------------------------------------
void StackTrace::buildSectionMap(bfd* abfd, asection* section, void*)
void mrw::StackTrace::buildSectionMap(bfd* abfd, asection* section,
void* fileoffs)
throw(std::bad_exception) {
if (!abfd || !section) return;
if (!abfd || !section || !fileoffs) return;
if (!(bfd_get_section_flags(abfd, section)&SEC_ALLOC)) return;
bfd_vma vma(bfd_get_section_vma(abfd, section));
std::pair<std::string, void*> fileoffset =
*(std::pair<std::string, void*>*)fileoffs;
bfd_vma vma(bfd_get_section_vma(abfd, section)+
reinterpret_cast<bfd_vma>(fileoffset.second));
bfd_size_type sz(bfd_get_section_size_before_reloc(section));
(*_dic)[vma] = Translator::mapped_type(vma+sz, section);
_addrs.push_back(vma);
_dic[fileoffset.first][vma] = Translator::mapped_type(vma+sz, section);
_addrs[vma] = fileoffset.first;
}
//----------------------------------------------------------------------------
std::auto_ptr<StackTrace::Translator> StackTrace::_dic;
std::vector<StackTrace::Translator::key_type> StackTrace::_addrs;
AutoBfd StackTrace::_bfd;
std::auto_ptr<asymbol*> StackTrace::_syms;
}
std::map<std::string, mrw::StackTrace::Translator> mrw::StackTrace::_dic;
std::map<mrw::StackTrace::Translator::key_type, std::string>
mrw::StackTrace::_addrs;
std::map<std::string, mrw::AutoBfd> mrw::StackTrace::_bfd;
std::map<std::string, mrw::AutoPtr<asymbol*> > mrw::StackTrace::_syms;

@ -9,6 +9,9 @@
@license LGPL, see file <a href="license.html">COPYING</a>
$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,10 +146,10 @@ 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.
@ -154,7 +157,10 @@ namespace mrw {
class StackTrace {
public:
//............................................................... typedefs
typedef std::vector<void*> AddressTrace; ///< container for the adresses
/// container for the adresses
typedef std::vector<void*> AddressTrace;
/// binary file with offset (for shared libraries, 0 for executables)
typedef std::list< std::pair<std::string, void*> > 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
@ -229,7 +240,7 @@ namespace mrw {
are created only the first time, so you don't loose too much
time.
*/
static bool createSymtable(const std::list<std::string>& 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<Translator> _dic;
static std::vector<Translator::key_type> _addrs;
static AutoBfd _bfd;
static std::auto_ptr<asymbol*> _syms;
static std::map<std::string, Translator> _dic;
static std::map<Translator::key_type, std::string> _addrs;
static std::map<std::string, AutoBfd> _bfd;
static std::map<std::string, mrw::AutoPtr<asymbol*> > _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);
};
//@}
}
/** @addtogroup StackTrace */
//@{
/// evaluate a stack trace and shift it on a stream
inline std::ostream& operator<<(std::ostream& os, const StackTrace& st)
inline std::ostream& operator<<(std::ostream& os, const mrw::StackTrace& st)
throw(std::bad_exception) {
return os<<(std::string)st;
}
//@}
}
#endif

Loading…
Cancel
Save