added backtrace

pull/40/head
Matchman Green 2012-05-13 14:08:04 +08:00
parent 9631031931
commit 66e7783a9c
13 changed files with 615 additions and 3 deletions

View File

@ -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 )

View File

@ -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
)

25
libgrive/src/bfd/Addr.hh Normal file
View File

@ -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 ;
}

View File

@ -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 <algorithm>
#include <cstring>
#include <sstream>
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

View File

@ -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 <iosfwd>
#include <string>
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

71
libgrive/src/bfd/Debug.cc Normal file
View File

@ -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 <cassert>
#ifdef __GNUC__
#include <cxxabi.h>
#endif
#include <cstdlib>
#include <ostream>
#include <iomanip>
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<const unsigned char*>( 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

32
libgrive/src/bfd/Debug.hh Normal file
View File

@ -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 <cstddef>
#include <iosfwd>
#include <string>
namespace gr {
std::string Demangle( const char *name ) ;
std::ostream& PrintHex( std::ostream& os, const void *buf, std::size_t size ) ;
} // end of namespace

View File

@ -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 <vector>
#include <bfd.h>
#include <execinfo.h>
#include <dlfcn.h>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <algorithm>
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

View File

@ -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 <memory>
#include <iosfwd>
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<Impl> m_impl ;
struct BacktraceInfo ;
friend struct BacktraceInfo ;
} ;
} // end of namespace

View File

@ -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 <cstddef>
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<int> 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 <typename T, std::size_t n>
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 <typename T, std::size_t n>
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 <typename T, std::size_t n>
std::size_t Count( T (&array)[n] )
{
return n ;
}
} // end of namespace

View File

@ -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<Node>(os, " ") ) ;
return os ;
}
} } // end of namespace

View File

@ -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() ) ;

View File

@ -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