First version with working support for shared libraries!
This commit is contained in:
@@ -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,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<n; ++i)
|
||||
_trace.push_back(ba[i]);
|
||||
}
|
||||
{
|
||||
const int TRACE_LEVEL(50);
|
||||
void* ba[TRACE_LEVEL];
|
||||
for (int n(backtrace(ba, TRACE_LEVEL)), i(0); i<n; ++i)
|
||||
_trace.push_back(ba[i]);
|
||||
}
|
||||
# elif defined(__GNUG__)
|
||||
{
|
||||
# define push(i) \
|
||||
(__builtin_return_address(i) ? \
|
||||
(_trace.push_back(__builtin_return_address(i)), true) : false)
|
||||
push(0) && push(1) && push(2) && push(3) && push(4) && push(5) &&
|
||||
push(6) && push(7) && push(8) && push(9) && push(10) && push(11) &&
|
||||
push(12) && push(13) && push(14) && push(15) && push(16) && push(17)
|
||||
&& push(18) && push(19) && push(20) && push(21) && push(22) &&
|
||||
push(23) && push(24) && push(25) && push(26) && push(27) && push(28)
|
||||
&& push(29) && push(30) && push(31) && push(32) && push(33) &&
|
||||
push(34) && push(35) && push(36) && push(37) && push(38) && push(39)
|
||||
&& push(40) && push(41) && push(42) && push(43) && push(44) &&
|
||||
push(45) && push(46) && push(47) && push(48) && push(49);
|
||||
{
|
||||
# define push(i) \
|
||||
(__builtin_return_address(i) ? \
|
||||
(_trace.push_back(__builtin_return_address(i)), true) : false)
|
||||
push(0) && push(1) && push(2) && push(3) && push(4) && push(5) &&
|
||||
push(6) && push(7) && push(8) && push(9) && push(10) && push(11) &&
|
||||
push(12) && push(13) && push(14) && push(15) && push(16) && push(17)
|
||||
&& push(18) && push(19) && push(20) && push(21) && push(22) &&
|
||||
push(23) && push(24) && push(25) && push(26) && push(27) && push(28)
|
||||
&& push(29) && push(30) && push(31) && push(32) && push(33) &&
|
||||
push(34) && push(35) && push(36) && push(37) && push(38) && push(39)
|
||||
&& push(40) && push(41) && push(42) && push(43) && push(44) &&
|
||||
push(45) && push(46) && push(47) && push(48) && push(49);
|
||||
# undef push
|
||||
}
|
||||
}
|
||||
# else
|
||||
# warning "You need GNU gcc or GNU glibc to be able to use mrw::StackTrace"
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
StackTrace::operator std::string() const throw(std::bad_exception) {
|
||||
static const double LN10(log(10));
|
||||
std::stringstream s;
|
||||
bool first(true);
|
||||
unsigned int lisz(0), fisz(0);
|
||||
std::list<CodePos> 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<CodePos>::iterator it(l.begin()); it!=l.end(); ++it)
|
||||
s<<"["<<it->address<<"] "
|
||||
<<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();
|
||||
//----------------------------------------------------------------------------
|
||||
mrw::StackTrace::operator std::string() const throw(std::bad_exception) {
|
||||
static const double LN10(log(10));
|
||||
std::string s;
|
||||
s<<1;
|
||||
bool first(true);
|
||||
unsigned int lisz(0), fisz(0);
|
||||
std::list<CodePos> 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<CodePos>::iterator it(l.begin()); it!=l.end(); ++it)
|
||||
s<<"["<<it->address<<"] "
|
||||
<<it->file<<':'<<it->line
|
||||
<<std::setw(fisz+lisz-it->file.size()-
|
||||
(unsigned int)(log(it->line+1)/LN10)-1)
|
||||
<<" "<<it->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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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));
|
||||
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[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 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<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;
|
||||
mrw::AutoPtr<asymbol*> syms(new asymbol*[memsz]);
|
||||
if (bfd_canonicalize_symtab(const_cast<bfd*>(static_cast<const bfd*>(abfd)),
|
||||
syms)<0)
|
||||
return false;
|
||||
_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 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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
StackTrace::CodePos 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);
|
||||
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))
|
||||
return CodePos(addr, "????", "????", 0);
|
||||
return CodePos(addr, mrw::demangle(_bfd, 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<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;
|
||||
_dic = std::auto_ptr<Translator>(new Translator());
|
||||
bfd_map_over_sections(_bfd, buildSectionMap, 0);
|
||||
std::sort(_addrs.begin(), _addrs.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool StackTrace::createSymtable(const std::list<std::string>& fnames)
|
||||
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);
|
||||
}
|
||||
std::sort(_addrs.begin(), _addrs.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string StackTrace::filename() throw(std::bad_exception) {
|
||||
std::stringstream s;
|
||||
s<<"/proc/"<<getpid();
|
||||
//----------------------------------------------------------------------------
|
||||
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));
|
||||
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;
|
||||
}
|
||||
{
|
||||
AutoFile fd(open(s.str(), O_RDONLY));
|
||||
prpsinfo_t status;
|
||||
if (fd==-1 || ioctl(fd, PIOCPSINFO, &status)==-1) 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*)
|
||||
throw(std::bad_exception) {
|
||||
if (!abfd || !section) return;
|
||||
if (!(bfd_get_section_flags(abfd, section)&SEC_ALLOC)) return;
|
||||
bfd_vma vma(bfd_get_section_vma(abfd, section));
|
||||
bfd_size_type sz(bfd_get_section_size_before_reloc(section));
|
||||
(*_dic)[vma] = Translator::mapped_type(vma+sz, section);
|
||||
_addrs.push_back(vma);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::auto_ptr<StackTrace::Translator> StackTrace::_dic;
|
||||
std::vector<StackTrace::Translator::key_type> StackTrace::_addrs;
|
||||
AutoBfd StackTrace::_bfd;
|
||||
std::auto_ptr<asymbol*> 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<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[fileoffset.first][vma] = Translator::mapped_type(vma+sz, section);
|
||||
_addrs[vma] = fileoffset.first;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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,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<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
|
||||
@@ -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<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);
|
||||
};
|
||||
|
||||
/// 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
|
||||
|
Reference in New Issue
Block a user