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

Reply via email to