/** @file $Id$ $Date$ $Author$ @copy © Marc Wäckerlin @license LGPL, see file COPYING $Log$ 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 - 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(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 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; } //---------------------------------------------------------------------------- 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; }