SVN: backtracexx: README backtracexx.cpp backtracexx.hpp example.cpp makefile
pluto
pluto at pld-linux.org
Wed Jul 11 15:07:46 CEST 2007
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
More information about the pld-cvs-commit
mailing list