From 66e7783a9c31308c91a70302409d9dce3629a1bf Mon Sep 17 00:00:00 2001 From: Matchman Green Date: Sun, 13 May 2012 14:08:04 +0800 Subject: [PATCH] added backtrace --- cmake/Modules/FindBFD.cmake | 13 +++ libgrive/CMakeLists.txt | 12 +- libgrive/src/bfd/Addr.hh | 25 ++++ libgrive/src/bfd/Backtrace.cc | 72 ++++++++++++ libgrive/src/bfd/Backtrace.hh | 56 +++++++++ libgrive/src/bfd/Debug.cc | 71 ++++++++++++ libgrive/src/bfd/Debug.hh | 32 ++++++ libgrive/src/bfd/SymbolInfo.cc | 191 +++++++++++++++++++++++++++++++ libgrive/src/bfd/SymbolInfo.hh | 63 ++++++++++ libgrive/src/util/CArray.hh | 78 +++++++++++++ libgrive/src/xml/NodeSet.cc | 1 + libgrive/test/drive/EntryTest.cc | 2 +- libgrive/test/xml/NodeTest.cc | 2 +- 13 files changed, 615 insertions(+), 3 deletions(-) create mode 100644 cmake/Modules/FindBFD.cmake create mode 100644 libgrive/src/bfd/Addr.hh create mode 100644 libgrive/src/bfd/Backtrace.cc create mode 100644 libgrive/src/bfd/Backtrace.hh create mode 100644 libgrive/src/bfd/Debug.cc create mode 100644 libgrive/src/bfd/Debug.hh create mode 100644 libgrive/src/bfd/SymbolInfo.cc create mode 100644 libgrive/src/bfd/SymbolInfo.hh create mode 100644 libgrive/src/util/CArray.hh diff --git a/cmake/Modules/FindBFD.cmake b/cmake/Modules/FindBFD.cmake new file mode 100644 index 0000000..785e29b --- /dev/null +++ b/cmake/Modules/FindBFD.cmake @@ -0,0 +1,13 @@ +find_library( DL_LIBRARY NAMES dl PATH /usr/lib /usr/lib64 ) +find_library( BFD_LIBRARY NAMES bfd PATH /usr/lib /usr/lib64 ) + +if ( DL_LIBRARY AND BFD_LIBRARY ) + set( BFD_FOUND TRUE ) +endif (DL_LIBRARY AND BFD_LIBRARY) + +if ( BFD_FOUND ) + + message( STATUS "Found libbfd: ${BFD_LIBRARY}") + + +endif ( BFD_FOUND ) diff --git a/libgrive/CMakeLists.txt b/libgrive/CMakeLists.txt index d8c000d..1ddbe84 100644 --- a/libgrive/CMakeLists.txt +++ b/libgrive/CMakeLists.txt @@ -8,11 +8,20 @@ find_package(CURL REQUIRED) find_package(EXPAT REQUIRED) find_package(CppUnit) find_package(Boost REQUIRED) +find_package(BFD) IF ( CPPUNIT_FOUND ) set( OPT_INCS ${CPPUNIT_INCLUDE_DIR} ) ENDIF ( CPPUNIT_FOUND ) +if ( BFD_FOUND ) + set( OPT_LIBS ${DL_LIBRARY} ${BFD_LIBRARY} ) + file( GLOB OPT_SRC + src/bfd/*.cc + ) + +endif ( BFD_FOUND ) + include_directories( ${libgrive_SOURCE_DIR}/src ${libgrive_SOURCE_DIR}/test @@ -45,12 +54,13 @@ file (GLOB LIBGRIVE_SRC add_definitions( -DVERSION="${GRIVE_VERSION}" -DTEST_DATA="${libgrive_SOURCE_DIR}/test/data/" ) -add_library( grive SHARED ${LIBGRIVE_SRC} ) +add_library( grive SHARED ${LIBGRIVE_SRC} ${OPT_SRC} ) target_link_libraries( grive ${CURL_LIBRARIES} ${JSONC_LIBRARY} ${OPENSSL_LIBRARIES} + ${OPT_LIBS} expat ) diff --git a/libgrive/src/bfd/Addr.hh b/libgrive/src/bfd/Addr.hh new file mode 100644 index 0000000..724b561 --- /dev/null +++ b/libgrive/src/bfd/Addr.hh @@ -0,0 +1,25 @@ +/* + 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. +*/ + +#pragma once + +namespace gr +{ + typedef void* addr_t ; +} diff --git a/libgrive/src/bfd/Backtrace.cc b/libgrive/src/bfd/Backtrace.cc new file mode 100644 index 0000000..6ce45fb --- /dev/null +++ b/libgrive/src/bfd/Backtrace.cc @@ -0,0 +1,72 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 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 "Backtrace.hh" + +#include "SymbolInfo.hh" +#include "util/CArray.hh" + +#include +#include +#include + +namespace gr { + +Backtrace::Backtrace( std::size_t skip ) : + m_count( SymbolInfo::Instance()->Backtrace(m_stack, Count(m_stack) )), + m_skip( std::min( skip, m_count ) ) +{ +} + +Backtrace::Backtrace( const Backtrace& bt ) : + m_count( bt.m_count ), + m_skip( bt.m_skip ) +{ + std::memcpy( m_stack, bt.m_stack, m_count * sizeof(m_stack[0]) ) ; +} + +/*! \brief operator<< for printing backtraces + \internal + + This function will call SymbolInfo::PrintTrace() to print out a backtrace + to the stream. It will use the SymbolInfo::Instance() singleton to get + the symbol information. + \param os The output stream. + \param b The backtrace information. + \sa SymbolInfo::Backtrace(), SymbolInfo::Instance() +*/ +std::ostream& operator<<( std::ostream& os, const gr::Backtrace& b ) +{ + // the 1st function in the stack is SymbolInfo::Backtrace() + // the 2nd one is the Backtrace() constructor + // both are not interesting to user + for ( std::size_t i = b.m_skip ; i < b.m_count ; i++ ) + SymbolInfo::Instance()->PrintTrace( b.m_stack[i], os, i - b.m_skip ) ; + + return os ; +} + +std::string Backtrace::ToString( ) const +{ + std::ostringstream oss ; + oss << *this ; + return oss.str( ) ; +} + +} // end of namespace diff --git a/libgrive/src/bfd/Backtrace.hh b/libgrive/src/bfd/Backtrace.hh new file mode 100644 index 0000000..aab906d --- /dev/null +++ b/libgrive/src/bfd/Backtrace.hh @@ -0,0 +1,56 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 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. +*/ + +#pragma once + +#include "Addr.hh" + +#include +#include + +namespace gr { + +/// A shortcut to print out backtrace information +/** \internal + The sole reason for this class to exists is to provide the + operator<< overload to allow: + +\code +std::cout << Backtrace() << std::endl ; +\endcode + + \sa SymbolInfo +*/ +class Backtrace +{ +public : + explicit Backtrace( std::size_t skip = 2 ) ; + Backtrace( const Backtrace& bt ) ; + + friend std::ostream& operator<<( std::ostream& os, + const gr::Backtrace& bt ) ; + + std::string ToString( ) const ; + +private : + addr_t m_stack[100] ; + std::size_t m_count, m_skip ; +} ; + +} // end of namespace diff --git a/libgrive/src/bfd/Debug.cc b/libgrive/src/bfd/Debug.cc new file mode 100644 index 0000000..f00c482 --- /dev/null +++ b/libgrive/src/bfd/Debug.cc @@ -0,0 +1,71 @@ +/* + 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 "Debug.hh" + +#include + +#ifdef __GNUC__ +#include +#endif + +#include +#include +#include + +namespace gr { + +std::string Demangle( const char *name ) +{ +#ifdef __GNUC__ + assert( name != 0 ) ; + + char *cname = abi::__cxa_demangle( name, 0, 0, 0 ) ; + std::string result( name ) ; + if ( cname != 0 ) + { + result = cname ; + std::free( cname ) ; + } + return result ; +#else + return std::string( ) ; +#endif +} + +std::ostream& PrintHex( std::ostream& os, const void *buf, std::size_t size ) +{ + const unsigned char *raw = static_cast( buf ) ; + + for ( std::size_t i = 0 ; i < size ; i++ ) + { + if ( i % 8 == 0 && i > 0 ) + os << std::endl ; + + if ( i % 8 == 0 ) + os << std::hex << std::setw(8) << std::setfill('0') << i << " " ; + + os << "0x" << std::hex << std::setw(2) << std::setfill('0') + << (int)raw[i] << ", " ; + } + os << std::endl ; + return os ; +} + +} // end of namespace diff --git a/libgrive/src/bfd/Debug.hh b/libgrive/src/bfd/Debug.hh new file mode 100644 index 0000000..76b8617 --- /dev/null +++ b/libgrive/src/bfd/Debug.hh @@ -0,0 +1,32 @@ +/* + 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. +*/ + +#pragma once + +#include +#include +#include + +namespace gr { + +std::string Demangle( const char *name ) ; + +std::ostream& PrintHex( std::ostream& os, const void *buf, std::size_t size ) ; + +} // end of namespace diff --git a/libgrive/src/bfd/SymbolInfo.cc b/libgrive/src/bfd/SymbolInfo.cc new file mode 100644 index 0000000..c3fe2b2 --- /dev/null +++ b/libgrive/src/bfd/SymbolInfo.cc @@ -0,0 +1,191 @@ +/* + 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 + +#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_vma vma = bfd_get_section_vma(abfd, section); + + unsigned long address = (unsigned long)(info->m_addr); + if ( address < vma ) + return; + + bfd_size_type size = bfd_section_size(abfd, section); + 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::cerr << "begin backtrace" << std::endl ; + std::size_t a = ::backtrace( stack, count ) ; +std::cerr << "end backtrace" << std::endl ; + + return a ; +} + +void SymbolInfo::PrintTrace( void *addr, std::ostream& os, std::size_t idx ) +{ + BacktraceInfo btinfo = + { + this, addr, 0, 0, 0, false + } ; + +std::cerr << "begin bfd" << std::endl ; + Dl_info sym ; + bfd_map_over_sections( m_impl->m_bfd, + &SymbolInfo::BacktraceInfo::Callback, + &btinfo ) ; +std::cerr << "end bfd" << std::endl ; + +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 diff --git a/libgrive/src/bfd/SymbolInfo.hh b/libgrive/src/bfd/SymbolInfo.hh new file mode 100644 index 0000000..bcbc3b1 --- /dev/null +++ b/libgrive/src/bfd/SymbolInfo.hh @@ -0,0 +1,63 @@ +/* + 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. +*/ + +#pragma once + +#include "Addr.hh" + +#include +#include + +namespace gr { + +/// ource code symbolic information +/** \internal + + This class represents symbolic information about the source code, + e.g. function names and line numbers. It provides an interface to + lookup these informations by address. +*/ +class SymbolInfo +{ +public : + SymbolInfo( ) ; + ~SymbolInfo( ) ; + + /*! \brief singleton function + \internal + + Returns the SymbolInfo singleton. Normally only one object + of SymbolInfo is enough for one application, so a singleton + is enough. This function will create the SymbolInfo object + in the first call. + */ + static SymbolInfo* Instance( ) ; + + std::size_t Backtrace( addr_t *stack, std::size_t count ) ; + void PrintTrace( addr_t addr, std::ostream& os, std::size_t idx = 0 ) ; + +private : + struct Impl ; + const std::auto_ptr m_impl ; + + struct BacktraceInfo ; + friend struct BacktraceInfo ; +} ; + +} // end of namespace diff --git a/libgrive/src/util/CArray.hh b/libgrive/src/util/CArray.hh new file mode 100644 index 0000000..d48e89b --- /dev/null +++ b/libgrive/src/util/CArray.hh @@ -0,0 +1,78 @@ +/* + grive: an GPL program to sync a local directory with Google Drive + Copyright (C) 2012 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. +*/ + +#pragma once + +#include + +namespace gr { + +/*! \brief get the begin iterator from an array + \internal + + This function returns the begin "iterator" of an array. It is useful to + treat an array like an STL container. + + For example: +\code +int array[10] = { 1, 2, 3, 4, 5 } ; +std::vector v ; +std::copy( Begin(array), End(array), std::back_inserter( v ) ; +\endcode + + \param array reference to the array + \return the begin iterator of the array. i.e. \a array itself + \sa End(), Count() +*/ +template +T* Begin( T (&array)[n] ) +{ + return array ; +} + +/*! \brief get the end iterator from an array + \internal + + This function returns the end "iterator" of an array. It is useful to + treat an array like an STL container. + + \param array reference to the array + \return the end iterator of the array. i.e. \a array+n + \sa Begin(), Count() +*/ +template +T* End( T (&array)[n] ) +{ + return array + n ; +} + +/*! \brief get the number of elements in the array + \internal + + This function will return the number of elements in the array. + \return the number of elements in the array + \sa Begin(), End() +*/ +template +std::size_t Count( T (&array)[n] ) +{ + return n ; +} + +} // end of namespace diff --git a/libgrive/src/xml/NodeSet.cc b/libgrive/src/xml/NodeSet.cc index 21e9572..3cd2d98 100644 --- a/libgrive/src/xml/NodeSet.cc +++ b/libgrive/src/xml/NodeSet.cc @@ -151,6 +151,7 @@ std::size_t NodeSet::size() const std::ostream& operator<<( std::ostream& os, const NodeSet& node ) { std::copy( node.begin(), node.end(), std::ostream_iterator(os, " ") ) ; + return os ; } } } // end of namespace diff --git a/libgrive/test/drive/EntryTest.cc b/libgrive/test/drive/EntryTest.cc index 66d052c..8289961 100644 --- a/libgrive/test/drive/EntryTest.cc +++ b/libgrive/test/drive/EntryTest.cc @@ -48,7 +48,7 @@ void EntryTest::TestXml( ) GRUT_ASSERT_EQUAL( "https://docs.google.com/feeds/default/private/full/folder%3A0B5KhdsbryVeGMl83OEV1ZVc3cUE", subject.SelfHref() ) ; - GRUT_ASSERT_EQUAL( 1, subject.ParentHrefs().size() ) ; + GRUT_ASSERT_EQUAL( 1U, subject.ParentHrefs().size() ) ; GRUT_ASSERT_EQUAL( "https://docs.google.com/feeds/default/private/full/folder%3A0B5KhdsbryVeGNEZjdUxzZHl3Sjg", subject.ParentHrefs().front() ) ; diff --git a/libgrive/test/xml/NodeTest.cc b/libgrive/test/xml/NodeTest.cc index d942ffb..14e973b 100644 --- a/libgrive/test/xml/NodeTest.cc +++ b/libgrive/test/xml/NodeTest.cc @@ -78,7 +78,7 @@ void NodeTest::TestParseFile( ) } NodeSet r = n["entry"]["link"] ; - GRUT_ASSERT_EQUAL( 2, r.size() ) ; + GRUT_ASSERT_EQUAL( 2U, r.size() ) ; } } // end of namespace grut