/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file COPYING
$Log$
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
- 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(__solaris__)
#include
#endif
#if defined (__GLIBC__)
#include
#endif
#include
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
An idiot 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
# 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
namespace mrw {
//----------------------------------------------------------------------------
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
or the MS PE format. These formats have a number of leading '.'s
on at least some symbols, so we remove all dots to avoid
confusing the demangler. */
const char* p(name);
while (p && *p == '.') ++p;
Auto::Free res(cplus_demangle(p, DMGL_ANSI | DMGL_PARAMS));
if (res) {
/* Now put back any stripped dots. */
if (p==name) return static_cast(res);
std::string add_dots('.', p-name);
return add_dots+=static_cast(res);
}
return name;
}
//----------------------------------------------------------------------------
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<=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);
}
//----------------------------------------------------------------------------
bool StackTrace::createSymtable(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;
}
//----------------------------------------------------------------------------
std::string StackTrace::filename() throw(std::bad_exception) {
std::stringstream s;
s<<"/proc/"< StackTrace::_dic;
std::vector StackTrace::_addrs;
AutoBfd StackTrace::_bfd;
std::auto_ptr StackTrace::_syms;
}