Author: pluto Date: Wed Jul 11 15:07:46 2007 New Revision: 8669 Modified: backtracexx/README backtracexx/backtracexx.cpp backtracexx/backtracexx.hpp backtracexx/example.cpp backtracexx/makefile Log: - support windows.
Modified: backtracexx/README ============================================================================== --- backtracexx/README (original) +++ backtracexx/README Wed Jul 11 15:07:46 2007 @@ -1,7 +1,7 @@ A backtrace is a summary of how your program got where it is. Unfortunately glibc's backtrace() and gdb's (bt) produce an unwind -path instead of true backtrace. This small library uses an unwind -informations to produce true backtrace with optionally demangled symbols -and allows you to embed backtracing facility into your application. +path instead of true backtrace. This small library uses unwind +information and produces true backtrace with optionally demangled symbols. +it allows you to embed backtracing facility into your application. Sources available at: http://svn.pld-linux.org/cgi-bin/viewsvn/backtracexx/ Modified: backtracexx/backtracexx.cpp ============================================================================== --- backtracexx/backtracexx.cpp (original) +++ backtracexx/backtracexx.cpp Wed Jul 11 15:07:46 2007 @@ -1,104 +1,192 @@ #include "backtracexx.hpp" + +#if defined( __GNUC__ ) #include <cxxabi.h> #include <dlfcn.h> #include <unwind.h> -#include <iostream> -#include <iomanip> -#include <sstream> +#elif defined( _MSC_VER ) +#include <windows.h> +#include <dbghelp.h> +// +// please use a recent dbghelp.dll because older versions +// have unexpected problems with symbols resolving, e.g. +// ::SymGetSymFromAddr() produces ERROR_INVALID_ADDRESS. +// +// this code works fine with: +// - dbghelp.dll v5.1.2600.2180 from WinXP/SP2. +// - dbghelp.dll v6.5.0003.7 from Visual C++ 2005 Express Edition. +// +// this code doesn't work with: +// - dbghelp.dll v5.00.2195.6613 from Win2000/SP4. +// +#pragma comment( lib, "dbghelp" ) +#endif namespace backtracexx { namespace { - // extract caller's address from callee's return point. - unsigned char const* caller( unsigned char const* ip ) + // + // extract caller's address from callee's return point. + // + unsigned long caller( unsigned long ret ) { + unsigned char const* ip = reinterpret_cast< unsigned char const* >( ret ); #if defined( __powerpc__ ) && !defined( __powerpc64__ ) - // powerpc64 not tested. + // powerpc64 not tested. ip -= 4; #elif defined( __sparc__ ) - // the same for sparc v7/8/9. + // the same for sparc v7/8/9. ip -= 8; #elif defined( __alpha__ ) ip -= 4; #elif defined( __i386__ ) || defined( __x86_64__ ) // - // TODO: - // analysis of complex addressing forms (see intel/24319102.pdf). - // rework code to cover all cases. + // TODO: + // analysis of complex addressing forms (see intel/24319102.pdf). + // rework code to cover all cases. // - // call, near, relative + // call, near, relative if ( ip[ -5 ] == 0xe8 ) - return ( ip - 5 ); - // call, near, absolute indirect + return ( ret - 5 ); + // call, near, absolute indirect if ( ip[ -2 ] == 0xff ) { - if ( ( ip[ -1 ] & 0xf8 ) == 0xd0 ) // call *%reg - return ( ip - 2 ); - if ( ( ip[ -1 ] & 0xf8 ) == 0x10 ) // call *(%reg) - return ( ip - 2 ); + if ( ( ip[ -1 ] & 0xf8 ) == 0xd0 ) // call *%reg + return ( ret - 2 ); + if ( ( ip[ -1 ] & 0xf8 ) == 0x10 ) // call *(%reg) + return ( ret - 2 ); } #endif - return ip; - } - - _Unwind_Reason_Code helper( struct _Unwind_Context* ctx, void* arg ) - { - int beforeInsn = 0; - _Unwind_Ptr ip = _Unwind_GetIPInfo( ctx, &beforeInsn ); - unwind_point_type up( reinterpret_cast< unsigned char const* >( ip ), beforeInsn ); - if ( !beforeInsn ) - up.first = caller( reinterpret_cast< unsigned char const* >( up.first ) ); - reinterpret_cast< raw_backtrace_type* >( arg )->push_back( up ); - return _URC_NO_REASON; + return ret; } - } - raw_backtrace_type scan() - { - raw_backtrace_type trace; - _Unwind_Backtrace( helper, &trace ); - return trace; - } +#if defined( __GNUC__ ) - symbolic_backtrace_type symbols( raw_backtrace_type const& bt ) - { - std::ostringstream os; - os.setf( std::ios_base::hex, std::ios_base::basefield ); - os.setf( std::ios_base::showbase ); - symbolic_backtrace_type sbt; - for ( raw_backtrace_type::const_iterator i = bt.begin(), e = bt.end(); i != e; ++i ) + void lookupSymbol( Frame& frame ) { - os.str( std::string() ); Dl_info info; - unwind_point_type up = *i; - os << std::setw( 18 ) << up.first << " : "; - if ( dladdr( const_cast< void* >( up.first ), &info ) ) + if ( ::dladdr( reinterpret_cast< void* >( frame.address ), &info ) ) { - if ( !info.dli_saddr ) - // the image containing address is found, but no nearest symbol was found. - os << "??"; - else + if ( info.dli_fname && strlen( info.dli_fname ) ) + frame.module = info.dli_fname; + if ( info.dli_saddr ) { + frame.displacement = frame.address - reinterpret_cast< unsigned long >( info.dli_saddr ); int status; char* demangled = abi::__cxa_demangle( info.dli_sname, 0, 0, &status ); if ( status != -1 ) { - long offset = reinterpret_cast< long >( up.first ) - reinterpret_cast< long >( info.dli_saddr ); - os << ( ( status == 0 ) ? demangled : info.dli_sname ) << '+' << offset; if ( status == 0 ) + { + frame.symbol = demangled; free( demangled ); + } + else + frame.symbol = info.dli_sname; } } - if ( info.dli_fname && strlen( info.dli_fname ) ) - os << " from " << info.dli_fname; } + } + + _Unwind_Reason_Code helper( struct _Unwind_Context* ctx, Trace* trace ) + { + int beforeInsn; + _Unwind_Ptr ip = _Unwind_GetIPInfo( ctx, &beforeInsn ); + Frame frame; + frame.address = ip; + if ( beforeInsn ) + frame.signalTrampoline = true; else - os << "??"; - if ( up.second ) - os << " [signal frame]"; - sbt.push_back( os.str() ); + frame.address = caller( frame.address ); + lookupSymbol( frame ); + trace->push_back( frame ); + return _URC_NO_REASON; } - return sbt; + +#elif defined( _MSC_VER ) && defined( WIN32 ) + +#pragma warning( disable : 4312 ) // 'reinterpret_cast' : conversion from 'unsigned long' to 'LPCVOID' of greater size + + void lookupSymbol( Frame& frame ) + { + ::MEMORY_BASIC_INFORMATION mbi; + ::VirtualQuery( reinterpret_cast< ::LPCVOID >( frame.address ), &mbi, sizeof( mbi ) ); + ::CHAR moduleName[ MAX_PATH ]; + ::GetModuleFileNameA( reinterpret_cast< ::HMODULE >( mbi.AllocationBase ), moduleName, sizeof( moduleName ) ); + frame.module = moduleName; + int const MaxSymbolNameLength = 8192; + ::BYTE symbolBuffer[ sizeof( ::IMAGEHLP_SYMBOL64 ) + MaxSymbolNameLength ]; + ::PIMAGEHLP_SYMBOL64 symbol = reinterpret_cast< ::PIMAGEHLP_SYMBOL64 >( symbolBuffer ); + symbol->SizeOfStruct = sizeof( symbolBuffer ); + symbol->MaxNameLength = MaxSymbolNameLength - 1; + if ( ::SymLoadModule64( ::GetCurrentProcess(), 0, moduleName, 0, + reinterpret_cast< ::DWORD64 >( mbi.AllocationBase ), 0 ) ) + { + ::DWORD64 displacement; + if ( ::SymGetSymFromAddr64( ::GetCurrentProcess(), static_cast< ::DWORD64 >( frame.address ), + &displacement, symbol ) ) + { + frame.symbol = symbol->Name; + frame.displacement = static_cast< unsigned long >( displacement ); + } + ::SymUnloadModule64( ::GetCurrentProcess(), reinterpret_cast< ::DWORD64 >( mbi.AllocationBase ) ); + } + } + +#endif + } + + Frame::Frame() + : + address(), displacement(), signalTrampoline() + { + } + + Trace scan() + { + Trace trace; + +#if defined( __GNUC__ ) + + // + // libgcc takes care about proper stack walking. + // + _Unwind_Backtrace( reinterpret_cast< _Unwind_Trace_Fn >( helper ), &trace ); + +#elif defined( _MSC_VER ) && defined( WIN32 ) + + ::SymInitialize( ::GetCurrentProcess(), 0, FALSE ); + ::SymSetOptions( ::SymGetOptions() | SYMOPT_UNDNAME ); + struct StackFrame + { + StackFrame* previousFrame; + unsigned long returnAddress; + }; + StackFrame const* stackFrame; + __asm mov stackFrame, ebp; + // + // the deepest frame pointer and return address of the process + // call chain are zeroed by kernel32.dll during process startup: + // + // BaseProcessStartThunk: + // xor ebp,ebp + // push eax + // push 0x0 + // jmp KERNEL32!BaseProcessStart + // + while ( stackFrame->returnAddress ) + { + Frame frame; + frame.address = stackFrame->returnAddress; + lookupSymbol( frame ); + trace.push_back( frame ); + stackFrame = stackFrame->previousFrame; + } + ::SymCleanup( ::GetCurrentProcess() ); + +#endif + + return trace; } } Modified: backtracexx/backtracexx.hpp ============================================================================== --- backtracexx/backtracexx.hpp (original) +++ backtracexx/backtracexx.hpp Wed Jul 11 15:07:46 2007 @@ -1,20 +1,25 @@ #ifndef backtracexx_hpp #define backtracexx_hpp -#include <list> #include <string> -#include <utility> +#include <vector> namespace backtracexx { - typedef std::pair< void const*, - bool /* signal frame */ > unwind_point_type; + struct Frame + { + Frame(); - typedef std::list< unwind_point_type > raw_backtrace_type; - typedef std::list< std::string > symbolic_backtrace_type; + unsigned long address; + std::string symbol; + unsigned long displacement; + std::string module; + bool signalTrampoline; + }; - raw_backtrace_type scan(); - symbolic_backtrace_type symbols( raw_backtrace_type const& ); + typedef std::vector< Frame > Trace; + + Trace scan(); } #endif Modified: backtracexx/example.cpp ============================================================================== --- backtracexx/example.cpp (original) +++ backtracexx/example.cpp Wed Jul 11 15:07:46 2007 @@ -10,8 +10,14 @@ void signalHandler( int signalNumber ) { - backtracexx::symbolic_backtrace_type s = backtracexx::symbols( backtracexx::scan() ); - std::copy( s.begin(), s.end(), std::ostream_iterator< std::string >( std::cout, "\n" ) ); + backtracexx::Trace t = backtracexx::scan(); + for ( backtracexx::Trace::const_iterator i = t.begin(); i != t.end(); ++i ) + { + backtracexx::Frame const& f = *i; + std::printf( "0x%016lx : %s+0x%lx [%s]\n", f.address, + ( f.symbol.empty() ? "<unresolved symbol>" : f.symbol.c_str() ), + f.displacement, f.module.c_str() ); + } longjmp( context, 1 ); } Modified: backtracexx/makefile ============================================================================== --- backtracexx/makefile (original) +++ backtracexx/makefile Wed Jul 11 15:07:46 2007 @@ -1,15 +1,13 @@ CXX := g++ -CXXFLAGS += -Wall -Werror -pedantic +CXXFLAGS := -O1 -Wall -Werror -pedantic +LDXXFLAGS := -Wl,-export-dynamic -s -ldl -static-libgcc -all: libbacktracexx.so example +all: example -libbacktracexx.so: backtracexx.hpp backtracexx.cpp - $(CXX) backtracexx.cpp -o libbacktracexx.so -shared -ldl $(CXXFLAGS) \ - -O3 -fpic -funwind-tables -fno-exceptions -fno-rtti -s - -example: example.cpp libbacktracexx.so - $(CXX) example.cpp -o example ./libbacktracexx.so $(CXXFLAGS) \ - -O1 -Wl,-export-dynamic -s +example: example.cpp backtracexx.hpp backtracexx.cpp + $(CXX) $(CXXFLAGS) backtracexx.cpp -c + $(CXX) $(CXXFLAGS) example.cpp -c + $(CXX) example.o backtracexx.o -o example $(LDXXFLAGS) clean: - rm -f libbacktracexx.so example + rm -f *.o *.s *.ii example _______________________________________________ pld-cvs-commit mailing list [email protected] http://lists.pld-linux.org/mailman/listinfo/pld-cvs-commit
