|
|
@ -8,61 +8,15 @@ |
|
|
|
@copy © Marc Wäckerlin |
|
|
|
@copy © Marc Wäckerlin |
|
|
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
|
|
|
|
|
|
|
|
$Log$ |
|
|
|
|
|
|
|
Revision 1.14 2005/03/11 23:22:58 marc |
|
|
|
|
|
|
|
It's multithreaded now, thanks to a boost mutex |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision 1.13 2005/02/28 07:28:37 marc |
|
|
|
|
|
|
|
typo |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision 1.12 2005/02/28 07:14:03 marc |
|
|
|
|
|
|
|
change in getting section size for SUN Solaris (old bfd.h) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision 1.11 2005/02/18 15:48:56 marc |
|
|
|
|
|
|
|
Dynamic loading of libbfd, no more dependency on specific libbfd version! |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision 1.10 2005/01/28 07:51:24 marc |
|
|
|
|
|
|
|
improved and corrected trace formatting |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision 1.9 2005/01/07 00:34:38 marc |
|
|
|
|
|
|
|
some changes for solaris |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision 1.8 2004/12/20 13:22:25 marc |
|
|
|
|
|
|
|
mrw string now throws exceptions, catch needed |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision 1.7 2004/10/13 10:47:15 marc |
|
|
|
|
|
|
|
no more need for ldd in StackTrace, read from /proc/self/maps |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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! |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision 1.4 2004/10/07 09:32:45 marc |
|
|
|
|
|
|
|
correction in parameter (const&) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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<T> |
|
|
|
|
|
|
|
- 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 <mrw/stacktrace.hpp> |
|
|
|
#include <mrw/stacktrace.hpp> |
|
|
|
#include <mrw/exec.hpp> |
|
|
|
#include <mrw/exec.hpp> |
|
|
|
#include <mrw/string.hpp> |
|
|
|
#include <mrw/string.hpp> |
|
|
|
#include <mrw/list.hpp> |
|
|
|
#include <mrw/list.hpp> |
|
|
|
#include <mrw/stdext.hpp> |
|
|
|
#include <mrw/stdext.hpp> |
|
|
|
#include <mrw/dynamiclibrary.hpp> |
|
|
|
#ifndef NO_LTDL |
|
|
|
|
|
|
|
# include <mrw/dynamiclibrary.hpp> |
|
|
|
|
|
|
|
#endif |
|
|
|
#include <unistd.h> |
|
|
|
#include <unistd.h> |
|
|
|
#include <sys/types.h> |
|
|
|
#include <sys/types.h> |
|
|
|
#include <sys/stat.h> |
|
|
|
#include <sys/stat.h> |
|
|
@ -80,36 +34,28 @@ |
|
|
|
#include <execinfo.h> |
|
|
|
#include <execinfo.h> |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
#include <bfd.h> |
|
|
|
#include <bfd.h> |
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Someone 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 <demangle.h> |
|
|
|
|
|
|
|
# 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 <iomanip> |
|
|
|
#include <iomanip> |
|
|
|
|
|
|
|
#if HAVE_DEMANGLE_H |
|
|
|
|
|
|
|
/* the defines work around wrong definitions in libiberty.h */ |
|
|
|
|
|
|
|
#define HAVE_DECL_BASENAME 1 |
|
|
|
|
|
|
|
#define HAVE_DECL_FFS 1 |
|
|
|
|
|
|
|
#define HAVE_DECL_ASPRINTF 1 |
|
|
|
|
|
|
|
#define HAVE_DECL_VASPRINTF 1 |
|
|
|
|
|
|
|
#define HAVE_DECL_SNPRINTF 1 |
|
|
|
|
|
|
|
#define HAVE_DECL_VSNPRINTF 1 |
|
|
|
|
|
|
|
#define HAVE_DECL_STRVERSCMP 1 |
|
|
|
|
|
|
|
# include <demangle.h> |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
# define DMGL_PARAMS (1 << 0) /* Include function args */ |
|
|
|
|
|
|
|
# define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ |
|
|
|
|
|
|
|
extern "C" { |
|
|
|
|
|
|
|
extern char * cplus_demangle(const char *, int); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if (__GNUC__==3 && __GNUC_MINOR__<4 || __GNUC__<3) && _REENTRANT && !_MT |
|
|
|
|
|
|
|
#define _MT |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
namespace mrw { |
|
|
|
namespace mrw { |
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
@ -202,9 +148,10 @@ const mrw::StackTrace& mrw::StackTrace::print(std::ostream& os) const |
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) |
|
|
|
mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) |
|
|
|
throw(std::bad_exception) { |
|
|
|
throw(std::bad_exception) { |
|
|
|
#ifdef _REENTRANT |
|
|
|
#ifdef _MT |
|
|
|
boost::recursive_mutex::scoped_lock lock(_mutex); |
|
|
|
boost::recursive_mutex::scoped_lock lock(_mutex); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
static const CodePos UNKNOWN(addr, "????", "????", 0); |
|
|
|
assert(sizeof(bfd_vma)>=sizeof(void*)); |
|
|
|
assert(sizeof(bfd_vma)>=sizeof(void*)); |
|
|
|
bfd_vma vma_addr(reinterpret_cast<bfd_vma>(addr)); |
|
|
|
bfd_vma vma_addr(reinterpret_cast<bfd_vma>(addr)); |
|
|
|
std::map<Translator::key_type, std::string>::iterator |
|
|
|
std::map<Translator::key_type, std::string>::iterator |
|
|
@ -212,7 +159,7 @@ mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) |
|
|
|
if (it==_addrs.begin() || (--it)->first > vma_addr || |
|
|
|
if (it==_addrs.begin() || (--it)->first > vma_addr || |
|
|
|
_dic.find(it->second)==_dic.end() || |
|
|
|
_dic.find(it->second)==_dic.end() || |
|
|
|
_dic[it->second][it->first].first <= vma_addr) |
|
|
|
_dic[it->second][it->first].first <= vma_addr) |
|
|
|
return CodePos(addr, "????", "????", 0); |
|
|
|
return UNKNOWN; |
|
|
|
static const char* file(0); |
|
|
|
static const char* file(0); |
|
|
|
static const char* function(0); |
|
|
|
static const char* function(0); |
|
|
|
unsigned int line; |
|
|
|
unsigned int line; |
|
|
@ -222,7 +169,7 @@ mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) |
|
|
|
_syms[it->second], |
|
|
|
_syms[it->second], |
|
|
|
vma_addr - it->first, |
|
|
|
vma_addr - it->first, |
|
|
|
&file, &function, &line)) |
|
|
|
&file, &function, &line)) |
|
|
|
return CodePos(addr, "????", "????", 0); |
|
|
|
return UNKNOWN; |
|
|
|
return CodePos(addr, mrw::demangle(_bfd[it->second], function), |
|
|
|
return CodePos(addr, mrw::demangle(_bfd[it->second], function), |
|
|
|
file?file:"????", line); |
|
|
|
file?file:"????", line); |
|
|
|
} |
|
|
|
} |
|
|
@ -230,11 +177,22 @@ mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr) |
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) |
|
|
|
bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) |
|
|
|
throw(std::bad_exception) { |
|
|
|
throw(std::bad_exception) { |
|
|
|
#ifdef _REENTRANT |
|
|
|
#ifdef _MT |
|
|
|
boost::recursive_mutex::scoped_lock lock(_mutex); |
|
|
|
boost::recursive_mutex::scoped_lock lock(_mutex); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
if (_dic.find(fname)!=_dic.end()) return true; // already loaded
|
|
|
|
if (_dic.find(fname)!=_dic.end()) return true; // already loaded
|
|
|
|
try { |
|
|
|
try { |
|
|
|
|
|
|
|
#if NO_LTDL |
|
|
|
|
|
|
|
static bfd*(*bfd_openr)(const char*, const char*) = |
|
|
|
|
|
|
|
::bfd_openr; |
|
|
|
|
|
|
|
static bfd_boolean(*bfd_check_format)(bfd*, bfd_format) = |
|
|
|
|
|
|
|
::bfd_check_format; |
|
|
|
|
|
|
|
static bfd_boolean(*bfd_check_format_matches)(bfd*, bfd_format, char***) = |
|
|
|
|
|
|
|
::bfd_check_format_matches; |
|
|
|
|
|
|
|
static void(*bfd_map_over_sections) |
|
|
|
|
|
|
|
(bfd*, void(*)(bfd*, asection*, void*), void*) = |
|
|
|
|
|
|
|
::bfd_map_over_sections; |
|
|
|
|
|
|
|
#else |
|
|
|
static DynamicLibrary lib("libbfd"); |
|
|
|
static DynamicLibrary lib("libbfd"); |
|
|
|
static bfd*(*bfd_openr)(const char*, const char*) = |
|
|
|
static bfd*(*bfd_openr)(const char*, const char*) = |
|
|
|
(bfd*(*)(const char*, const char*))lib.symbol("bfd_openr"); |
|
|
|
(bfd*(*)(const char*, const char*))lib.symbol("bfd_openr"); |
|
|
@ -247,6 +205,7 @@ bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) |
|
|
|
(bfd*, void(*)(bfd*, asection*, void*), void*) = |
|
|
|
(bfd*, void(*)(bfd*, asection*, void*), void*) = |
|
|
|
(void(*)(bfd*, void(*)(bfd*, asection*, void*), void*)) |
|
|
|
(void(*)(bfd*, void(*)(bfd*, asection*, void*), void*)) |
|
|
|
lib.symbol("bfd_map_over_sections"); |
|
|
|
lib.symbol("bfd_map_over_sections"); |
|
|
|
|
|
|
|
#endif |
|
|
|
if (fname=="") return createSymtable(filename()); |
|
|
|
if (fname=="") return createSymtable(filename()); |
|
|
|
AutoBfd abfd((*bfd_openr)(fname.c_str(), 0)); |
|
|
|
AutoBfd abfd((*bfd_openr)(fname.c_str(), 0)); |
|
|
|
long memsz(-1); |
|
|
|
long memsz(-1); |
|
|
@ -256,19 +215,27 @@ bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) |
|
|
|
!(bfd_get_file_flags(const_cast<bfd*>(static_cast<const bfd*>(abfd))) |
|
|
|
!(bfd_get_file_flags(const_cast<bfd*>(static_cast<const bfd*>(abfd))) |
|
|
|
&HAS_SYMS) || |
|
|
|
&HAS_SYMS) || |
|
|
|
(memsz=bfd_get_symtab_upper_bound |
|
|
|
(memsz=bfd_get_symtab_upper_bound |
|
|
|
(const_cast<bfd*>(static_cast<const bfd*>(abfd))))<0) |
|
|
|
(const_cast<bfd*>(static_cast<const bfd*>(abfd))))<0) { |
|
|
|
|
|
|
|
_error = "cannot map bfd symbols - 'bfd_get_file_flags' failed " |
|
|
|
|
|
|
|
"for file: \""+fname+'"'; |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
mrw::AutoPtr<asymbol*> syms(new asymbol*[memsz]); |
|
|
|
mrw::AutoPtr<asymbol*> syms(new asymbol*[memsz]); |
|
|
|
if (bfd_canonicalize_symtab(const_cast<bfd*>(static_cast<const bfd*>(abfd)), |
|
|
|
if (bfd_canonicalize_symtab(const_cast<bfd*>(static_cast<const bfd*>(abfd)), |
|
|
|
syms)<0) |
|
|
|
syms)<0) { |
|
|
|
|
|
|
|
_error = "cannot map bfd symbols - 'bfd_canonicalize_symtab' failed" |
|
|
|
|
|
|
|
"for file: \""+fname+'"'; |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
_bfd[fname] = abfd; |
|
|
|
_bfd[fname] = abfd; |
|
|
|
_syms[fname] = syms; |
|
|
|
_syms[fname] = syms; |
|
|
|
_dic[fname]; |
|
|
|
_dic[fname]; |
|
|
|
std::pair<std::string, void*> fileoffs = std::make_pair(fname, offs); |
|
|
|
std::pair<std::string, void*> fileoffs = std::make_pair(fname, offs); |
|
|
|
(*bfd_map_over_sections)(_bfd[fname], buildSectionMap, &fileoffs); |
|
|
|
(*bfd_map_over_sections)(_bfd[fname], buildSectionMap, &fileoffs); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} catch (...) { |
|
|
|
} catch (const std::exception& x) { |
|
|
|
|
|
|
|
_error = std::string("exception received: \"")+x.what()+"\", " |
|
|
|
|
|
|
|
"while processing file: \""+fname+'"'; |
|
|
|
return false; // shared library for bfd not found or similar
|
|
|
|
return false; // shared library for bfd not found or similar
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -276,7 +243,7 @@ bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs) |
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
bool mrw::StackTrace::createSymtable(const mrw::StackTrace::BinFiles& files) |
|
|
|
bool mrw::StackTrace::createSymtable(const mrw::StackTrace::BinFiles& files) |
|
|
|
throw(std::bad_exception) { |
|
|
|
throw(std::bad_exception) { |
|
|
|
#ifdef _REENTRANT |
|
|
|
#ifdef _MT |
|
|
|
boost::recursive_mutex::scoped_lock lock(_mutex); |
|
|
|
boost::recursive_mutex::scoped_lock lock(_mutex); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
bool success(true); |
|
|
|
bool success(true); |
|
|
@ -290,8 +257,12 @@ bool mrw::StackTrace::createSymtable(const mrw::StackTrace::BinFiles& files) |
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
int mrw::StackTrace::bfdClose(bfd* abfd) throw() { |
|
|
|
int mrw::StackTrace::bfdClose(bfd* abfd) throw() { |
|
|
|
try { |
|
|
|
try { |
|
|
|
|
|
|
|
#if NO_LTDL |
|
|
|
|
|
|
|
static int(*bfd_close)(bfd*) = ::bfd_close; |
|
|
|
|
|
|
|
#else |
|
|
|
static DynamicLibrary lib(""); |
|
|
|
static DynamicLibrary lib(""); |
|
|
|
static int(*bfd_close)(bfd*) = (int(*)(bfd*))lib.symbol("bfd_close"); |
|
|
|
static int(*bfd_close)(bfd*) = (int(*)(bfd*))lib.symbol("bfd_close"); |
|
|
|
|
|
|
|
#endif |
|
|
|
return (*bfd_close)(abfd); |
|
|
|
return (*bfd_close)(abfd); |
|
|
|
} catch (...) { |
|
|
|
} catch (...) { |
|
|
|
return -1; // dynamic library loading problems
|
|
|
|
return -1; // dynamic library loading problems
|
|
|
@ -324,7 +295,11 @@ mrw::StackTrace::BinFiles mrw::StackTrace::filename() |
|
|
|
range.resize(range.find_first_not_of("0123456789abcdefABCDEF")); |
|
|
|
range.resize(range.find_first_not_of("0123456789abcdefABCDEF")); |
|
|
|
void* addr(0); |
|
|
|
void* addr(0); |
|
|
|
range>>addr; |
|
|
|
range>>addr; |
|
|
|
if (lib.size() && addr>0) res<<BinFiles::value_type(lib, addr); |
|
|
|
// added check: no names in brackets: [lib], because there are
|
|
|
|
|
|
|
|
// [heap], [stack] and [vdso] that cannot be loaded
|
|
|
|
|
|
|
|
// question: should only files with ending '.so' be loaded?
|
|
|
|
|
|
|
|
if (lib.size() && lib[0]!='[' && lib[lib.size()-1]!=']' && addr>0) |
|
|
|
|
|
|
|
res<<BinFiles::value_type(lib, addr); |
|
|
|
} catch (...) {} // ignore non matching lines
|
|
|
|
} catch (...) {} // ignore non matching lines
|
|
|
|
return res; |
|
|
|
return res; |
|
|
|
} |
|
|
|
} |
|
|
@ -365,6 +340,7 @@ std::map<mrw::StackTrace::Translator::key_type, std::string> |
|
|
|
mrw::StackTrace::_addrs; |
|
|
|
mrw::StackTrace::_addrs; |
|
|
|
std::map<std::string, mrw::StackTrace::AutoBfd> mrw::StackTrace::_bfd; |
|
|
|
std::map<std::string, mrw::StackTrace::AutoBfd> mrw::StackTrace::_bfd; |
|
|
|
std::map<std::string, mrw::AutoPtr<asymbol*> > mrw::StackTrace::_syms; |
|
|
|
std::map<std::string, mrw::AutoPtr<asymbol*> > mrw::StackTrace::_syms; |
|
|
|
#ifdef _REENTRANT |
|
|
|
#ifdef _MT |
|
|
|
boost::recursive_mutex mrw::StackTrace::_mutex; |
|
|
|
boost::recursive_mutex mrw::StackTrace::_mutex; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
std::string mrw::StackTrace::_error; |
|
|
|