#include #include #include #include #include #include #include #include #include #include #include #if defined(__solaris__) #include #endif #if defined (__GLIBC__) #include #endif #include extern "C" { #include } #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; mrw::AutoFree res(cplus_demangle(p, DMGL_ANSI | DMGL_PARAMS)); if (res) { /* Now put back any stripped dots. */ if (p==name) return (char*)res; std::string add_dots('.', p-name); return add_dots+=(char*)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(_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); AutoFree m(0); if (!abfd || bfd_check_format(abfd, bfd_archive) || !bfd_check_format_matches(abfd, bfd_object, m) || !(bfd_get_file_flags(abfd)&HAS_SYMS) || (memsz=bfd_get_symtab_upper_bound(abfd))<0) return false; std::auto_ptr syms(new asymbol*[memsz]); if (bfd_canonicalize_symtab(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; }