/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2006 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "SymbolInfo.hh" #include "Debug.hh" #include #define PACKAGE "libgrive" #include #include #include #include #include #include #include #include #include namespace gr { struct SymbolInfo::Impl { bfd *m_bfd ; asymbol **m_symbols ; long m_symbol_count ; } ; SymbolInfo::SymbolInfo( ) : m_impl( new Impl ) { m_impl->m_bfd = 0 ; m_impl->m_symbols = 0 ; m_impl->m_symbol_count = 0 ; bfd_init( ) ; // opening itself bfd *b = bfd_openr( "/proc/self/exe", 0 ) ; if ( b == NULL ) { std::cerr << "cannot open executable: " << bfd_errmsg( bfd_get_error() ) << std::endl ; return ; } if ( bfd_check_format( b, bfd_archive ) ) { bfd_close( b ) ; return ; } char **matching ; if ( !bfd_check_format_matches( b, bfd_object, &matching ) ) { std::cerr << "cannot read symbols from " << bfd_get_filename( b ) << ": " << bfd_errmsg( bfd_get_error() ) << std::endl ; if ( bfd_get_error( ) == bfd_error_file_ambiguously_recognized ) { std::cerr << bfd_get_filename( b ) << ": Matching formats: " ; for ( char **p = matching ; *p != 0 ; p++ ) std::cerr << " " << *p ; std::cerr << std::endl ; std::free( matching ) ; } bfd_close( b ) ; return ; } m_impl->m_bfd = b ; long storage_needed = bfd_get_symtab_upper_bound( m_impl->m_bfd ) ; m_impl->m_symbols = (asymbol**)std::malloc( storage_needed ) ; m_impl->m_symbol_count = bfd_canonicalize_symtab( b, m_impl->m_symbols ) ; } SymbolInfo::~SymbolInfo( ) { if ( m_impl->m_symbols != 0 ) std::free( m_impl->m_symbols ) ; } struct SymbolInfo::BacktraceInfo { const SymbolInfo *m_pthis ; void *m_addr ; const char *m_filename ; const char *m_func_name ; unsigned int m_lineno ; unsigned int m_is_found ; static void Callback( bfd *abfd, asection *section, void* addr ) ; } ; void SymbolInfo::BacktraceInfo::Callback( bfd *abfd, asection *section, void* data ) { BacktraceInfo *info = (BacktraceInfo *)data ; if ((section->flags & SEC_ALLOC) == 0) return ; // bfd_get_section_vma works up to 7b1cfbcf1a27951fb1b3a212995075dd6fdf985b, // removed in 7c13bc8c91abf291f0206b6608b31955c5ea70d8 (binutils 2.33.1 or so) // so it's substituted by its implementation to avoid checking for binutils // version (which at least on Debian SID it's not that easy because the // version.h is not included with the official package) bfd_vma vma = section->vma; unsigned long address = (unsigned long)(info->m_addr); if ( address < vma ) return; // bfd_section_size changed between the two objects described above, // same rationale applies bfd_size_type size = section->size; if ( address > (vma + size)) return ; const SymbolInfo *pthis = info->m_pthis ; info->m_is_found = bfd_find_nearest_line( abfd, section, pthis->m_impl->m_symbols, address - vma, &info->m_filename, &info->m_func_name, &info->m_lineno ) ; } std::size_t SymbolInfo::Backtrace( void **stack, std::size_t count ) { std::size_t a = ::backtrace( stack, count ) ; return a ; } void SymbolInfo::PrintTrace( void *addr, std::ostream& os, std::size_t idx ) { BacktraceInfo btinfo = { this, addr, 0, 0, 0, false } ; Dl_info sym ; bfd_map_over_sections( m_impl->m_bfd, &SymbolInfo::BacktraceInfo::Callback, &btinfo ) ; if ( btinfo.m_is_found ) { std::string filename = ( btinfo.m_filename == 0 ? std::string() : btinfo.m_filename ) ; #ifdef SRC_DIR std::size_t pos = filename.find( SRC_DIR ) ; if ( pos != std::string::npos ) filename.erase( pos, std::strlen( SRC_DIR ) ) ; #endif os << "#" << idx << " " << addr << " " << filename << ":" << btinfo.m_lineno << " " << (btinfo.m_func_name != 0 ? Demangle(btinfo.m_func_name) : "" ) << std::endl ; } else if ( dladdr( addr, &sym ) ) os << "#" << idx << " " << addr << " " << sym.dli_fname << " " << (sym.dli_sname != 0 ? Demangle( sym.dli_sname ) : "" ) << std::endl ; } SymbolInfo* SymbolInfo::Instance( ) { static SymbolInfo sthis ; return &sthis ; } } // end of namespace