/** @file $Id$ $Date$ $Author$ @copy © Marc Wäckerlin @license LGPL, see file COPYING $Log$ 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 - 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 #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 { //---------------------------------------------------------------------------- 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 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; } } //---------------------------------------------------------------------------- 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 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<<"\n"; return s; } //---------------------------------------------------------------------------- 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(addr)); std::map::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(static_cast(_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::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; mrw::AutoPtr syms(new asymbol*[memsz]); if (bfd_canonicalize_symtab(const_cast(static_cast(abfd)), syms)<0) return false; _bfd[fname] = abfd; _syms[fname] = syms; _dic[fname]; std::pair 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; } //---------------------------------------------------------------------------- mrw::StackTrace::BinFiles mrw::StackTrace::filename() throw(std::bad_exception) { mrw::StackTrace::BinFiles res; # if defined(__solaris__) { std::string s; s<<"/proc/"<>range>>perm>>x1>>x2>>size>>lib; range.resize(range.find_first_not_of("0123456789abcdefABCDEF")); void* addr(0); range>>addr; if (lib.size() && addr>0) res< fileoffset = *(std::pair*)fileoffs; bfd_vma vma(bfd_get_section_vma(abfd, section)+ reinterpret_cast(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 mrw::StackTrace::_dic; std::map mrw::StackTrace::_addrs; std::map mrw::StackTrace::_bfd; std::map > mrw::StackTrace::_syms;