Merge branch 'stackwalk-mingw'

Support wxStackWalker when using MinGW54 or TDM-GCC.
This commit is contained in:
Vadim Zeitlin
2016-03-16 02:20:15 +01:00
13 changed files with 263 additions and 120 deletions

90
configure vendored
View File

@@ -1195,6 +1195,7 @@ enable_protocol_http
enable_protocol_ftp
enable_protocol_file
enable_threads
enable_dbghelp
enable_iniconf
enable_regkey
enable_docview
@@ -2127,6 +2128,7 @@ Optional Features:
--enable-protocol-ftp FTP support in wxProtocol
--enable-protocol-file FILE support in wxProtocol
--enable-threads use threads
--enable-dbghelp use dbghelp.dll API (Win32 only)
--enable-iniconf use wxIniConfig (Win32 only)
--enable-regkey use wxRegKey class (Win32 only)
--enable-docview use document view architecture
@@ -7745,6 +7747,36 @@ fi
eval "$wx_cv_use_threads"
if test "$wxUSE_MSW" = 1 ; then
enablestring=disable
defaultval=
if test -z "$defaultval"; then
if test x"$enablestring" = xdisable; then
defaultval=yes
else
defaultval=no
fi
fi
# Check whether --enable-dbghelp was given.
if test "${enable_dbghelp+set}" = set; then :
enableval=$enable_dbghelp;
if test "$enableval" = yes; then
wx_cv_use_dbghelp='wxUSE_DBGHELP=yes'
else
wx_cv_use_dbghelp='wxUSE_DBGHELP=no'
fi
else
wx_cv_use_dbghelp='wxUSE_DBGHELP=${'DEFAULT_wxUSE_DBGHELP":-$defaultval}"
fi
eval "$wx_cv_use_dbghelp"
enablestring=
defaultval=
@@ -7803,6 +7835,7 @@ fi
eval "$wx_cv_use_regkey"
fi
if test "$wxUSE_GUI" = "yes"; then
@@ -35882,6 +35915,63 @@ if test "$wxUSE_AUTOID_MANAGEMENT" = "yes"; then
fi
if test "$USE_WIN32" = 1 ; then
if test "$wxUSE_DBGHELP" = "yes"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if debug help API is available" >&5
$as_echo_n "checking if debug help API is available... " >&6; }
if ${wx_cv_lib_debughlp+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <windows.h>
#include <imagehlp.h>
int
main ()
{
#ifndef API_VERSION_NUMBER
#error API_VERSION_NUMBER not defined!
#endif
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
wx_cv_lib_debughlp=yes
else
wx_cv_lib_debughlp=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $wx_cv_lib_debughlp" >&5
$as_echo "$wx_cv_lib_debughlp" >&6; }
if test "$wx_cv_lib_debughlp" = yes; then
$as_echo "#define wxUSE_DBGHELP 1" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Debug help API and wxStackWalker won't be available" >&5
$as_echo "$as_me: WARNING: Debug help API and wxStackWalker won't be available" >&2;}
fi
fi
if test "$wxUSE_INICONF" = "yes"; then
$as_echo "#define wxUSE_INICONF 1" >>confdefs.h

View File

@@ -743,8 +743,11 @@ WX_ARG_FEATURE(protocol_file, [ --enable-protocol-file FILE support in wxProto
WX_ARG_FEATURE(threads, [ --enable-threads use threads], wxUSE_THREADS)
if test "$wxUSE_MSW" = 1 ; then
WX_ARG_DISABLE(dbghelp, [ --enable-dbghelp use dbghelp.dll API (Win32 only)], wxUSE_DBGHELP)
WX_ARG_ENABLE(iniconf, [ --enable-iniconf use wxIniConfig (Win32 only)], wxUSE_INICONF)
WX_ARG_FEATURE(regkey, [ --enable-regkey use wxRegKey class (Win32 only)], wxUSE_REGKEY)
fi
if test "$wxUSE_GUI" = "yes"; then
@@ -7157,6 +7160,34 @@ if test "$wxUSE_AUTOID_MANAGEMENT" = "yes"; then
fi
if test "$USE_WIN32" = 1 ; then
if test "$wxUSE_DBGHELP" = "yes"; then
AC_CACHE_CHECK([if debug help API is available], wx_cv_lib_debughlp,
[
dnl we need just the header, not the library, as we load the
dnl DLL dynamically anyhow during run-time
AC_LANG_PUSH(C++)
AC_TRY_COMPILE(
[#include <windows.h>
#include <imagehlp.h>],
[
#ifndef API_VERSION_NUMBER
#error API_VERSION_NUMBER not defined!
#endif
],
wx_cv_lib_debughlp=yes,
wx_cv_lib_debughlp=no
)
AC_LANG_POP()
]
)
if test "$wx_cv_lib_debughlp" = yes; then
AC_DEFINE(wxUSE_DBGHELP)
else
AC_MSG_WARN([Debug help API and wxStackWalker won't be available])
fi
fi
if test "$wxUSE_INICONF" = "yes"; then
AC_DEFINE(wxUSE_INICONF)
fi

View File

@@ -75,6 +75,7 @@ wxGTK:
wxMSW:
- Enable wxStackWalker in MinGW64 builds.
- Fix crash when using wxCHMHelpController() in 64 bit builds (Xlord2).
- Fix MDI menu display after failure to create a child frame (troelsk).

View File

@@ -1668,6 +1668,18 @@
// Crash debugging helpers
// ----------------------------------------------------------------------------
// Set this to 1 to use dbghelp.dll for providing stack traces in crash
// reports.
//
// Default is 1 if the compiler supports it, 0 for old MinGW.
//
// Recommended setting: 1, there is not much gain in disabling this
#if defined(__VISUALC__) || defined(__MINGW64_TOOLCHAIN__)
#define wxUSE_DBGHELP 1
#else
#define wxUSE_DBGHELP 0
#endif
// Set this to 1 to be able to use wxCrashReport::Generate() to create mini
// dumps of your program when it crashes (or at any other moment)
//

View File

@@ -38,6 +38,14 @@
# endif
#endif /* !defined(wxUSE_CRASHREPORT) */
#ifndef wxUSE_DBGHELP
# ifdef wxABORT_ON_CONFIG_ERROR
# error "wxUSE_DBGHELP must be defined"
# else
# define wxUSE_DBGHELP 1
# endif
#endif /* wxUSE_DBGHELP */
#ifndef wxUSE_DC_CACHEING
# ifdef wxABORT_ON_CONFIG_ERROR
# error "wxUSE_DC_CACHEING must be defined"
@@ -146,9 +154,6 @@
# undef wxUSE_CRASHREPORT
# define wxUSE_CRASHREPORT 0
# undef wxUSE_STACKWALKER
# define wxUSE_STACKWALKER 0
#endif /* compiler doesn't support SEH */
#if defined(__GNUWIN32__)
@@ -292,6 +297,14 @@
#endif /* !wxUSE_DYNAMIC_LOADER */
#if !wxUSE_DYNLIB_CLASS
# if wxUSE_DBGHELP
# ifdef wxABORT_ON_CONFIG_ERROR
# error "wxUSE_DBGHELP requires wxUSE_DYNLIB_CLASS"
# else
# undef wxUSE_DBGHELP
# define wxUSE_DBGHELP 0
# endif
# endif
# if wxUSE_DC_TRANSFORM_MATRIX
# ifdef wxABORT_ON_CONFIG_ERROR
# error "wxUSE_DC_TRANSFORM_MATRIX requires wxUSE_DYNLIB_CLASS"
@@ -383,6 +396,22 @@
# endif
#endif /* wxUSE_ACTIVITYINDICATOR */
#if wxUSE_STACKWALKER && !wxUSE_DBGHELP
/*
Don't give an error in this case because wxUSE_DBGHELP could be 0
because the compiler just doesn't support it, there is really no other
choice than to disable wxUSE_STACKWALKER too in this case.
Unfortunately we can't distinguish between the missing compiler support
and explicitly disabling wxUSE_DBGHELP (which would ideally result in
an error if wxUSE_STACKWALKER is not disabled too), but it's better to
avoid giving a compiler error in the former case even if it means not
giving it neither in the latter one.
*/
#undef wxUSE_STACKWALKER
#define wxUSE_STACKWALKER 0
#endif /* wxUSE_STACKWALKER && !wxUSE_DBGHELP */
#if !wxUSE_THREADS
# if wxUSE_FSWATCHER
# ifdef wxABORT_ON_CONFIG_ERROR

View File

@@ -10,8 +10,11 @@
#ifndef _WX_MSW_DEBUGHLPH_H_
#define _WX_MSW_DEBUGHLPH_H_
#include "wx/dynlib.h"
#include "wx/defs.h"
#if wxUSE_DBGHELP
#include "wx/dynlib.h"
#include "wx/msw/wrapwin.h"
#ifdef __VISUALC__
@@ -31,26 +34,6 @@
#include "wx/msw/private.h"
// wxUSE_DBGHELP can be predefined on the compiler command line to force using
// dbghelp.dll even if it's not detected or, on the contrary, avoid using even
// if it's available.
#ifndef wxUSE_DBGHELP
// The only compiler which is known to have the necessary headers is MSVC.
#ifdef __VISUALC__
// MSVC7.1 shipped with API v9 and we don't support anything earlier
// anyhow.
#if API_VERSION_NUMBER >= 9
#define wxUSE_DBGHELP 1
#else
#define wxUSE_DBGHELP 0
#endif
#else
#define wxUSE_DBGHELP 0
#endif
#endif
#if wxUSE_DBGHELP
/*
The table below shows which functions are exported by dbghelp.dll.

View File

@@ -1560,7 +1560,7 @@
// SDK components manually, you need to change this setting.
//
// Recommended setting: 1
#if defined(_MSC_VER) && _MSC_VER >= 1700 && !defined(_USING_V110_SDK71_)
#if defined(_MSC_VER) && _MSC_VER >= 1700
#define wxUSE_WINRT 1
#else
#define wxUSE_WINRT 0
@@ -1668,6 +1668,18 @@
// Crash debugging helpers
// ----------------------------------------------------------------------------
// Set this to 1 to use dbghelp.dll for providing stack traces in crash
// reports.
//
// Default is 1 if the compiler supports it, 0 for old MinGW.
//
// Recommended setting: 1, there is not much gain in disabling this
#if defined(__VISUALC__) || defined(__MINGW64_TOOLCHAIN__)
#define wxUSE_DBGHELP 1
#else
#define wxUSE_DBGHELP 0
#endif
// Set this to 1 to be able to use wxCrashReport::Generate() to create mini
// dumps of your program when it crashes (or at any other moment)
//

View File

@@ -180,6 +180,18 @@
// Crash debugging helpers
// ----------------------------------------------------------------------------
// Set this to 1 to use dbghelp.dll for providing stack traces in crash
// reports.
//
// Default is 1 if the compiler supports it, 0 for old MinGW.
//
// Recommended setting: 1, there is not much gain in disabling this
#if defined(__VISUALC__) || defined(__MINGW64_TOOLCHAIN__)
#define wxUSE_DBGHELP 1
#else
#define wxUSE_DBGHELP 0
#endif
// Set this to 1 to be able to use wxCrashReport::Generate() to create mini
// dumps of your program when it crashes (or at any other moment)
//

View File

@@ -15,6 +15,8 @@
#if wxUSE_STACKWALKER
#include "wx/string.h"
class WXDLLIMPEXP_FWD_BASE wxStackFrame;
#define wxSTACKWALKER_MAX_DEPTH (200)

View File

@@ -25,13 +25,18 @@
class from it and override this method.
This class will not return anything except raw stack frame addresses if the
debug information is not available. Under Win32 this means that the PDB file
matching the program being executed should be present.
debug information is not available. Under Microsoft Windows this means that
the PDB file matching the program being executed should be present.
Note that if you use Microsoft Visual C++ compiler, you can create PDB files
even for the programs built in release mode and it doesn't affect the program
size (at least if you don't forget to add @c /opt:ref option which is suppressed
by using @c /debug linker option by default but should be always enabled for
release builds).
release builds). If your compiler doesn't provide a direct way of
generating PDB files but does produce debug information in the older "Code
View" format or compatible, which is the case for MinGW, you can use @c
cv2pdb tool available at https://github.com/rainers/cv2pdb to create PDB
for your binaries which will work well when using this class.
Under Unix, you need to compile your program with debugging information
(usually using @c -g compiler and linker options) to get the file and line
numbers information, however function names should be available even without it.

View File

@@ -691,6 +691,12 @@
#define wxUSE_TIMEPICKCTRL_GENERIC 0
#if defined(__VISUALC__) || defined(__MINGW64_TOOLCHAIN__)
#define wxUSE_DBGHELP 0
#else
#define wxUSE_DBGHELP 0
#endif
#define wxUSE_CRASHREPORT 0
/* --- end MSW options --- */

View File

@@ -24,6 +24,8 @@
#if wxUSE_DYNLIB_CLASS
#include "wx/dynlib.h"
#include "wx/msw/private.h"
#include "wx/msw/debughlp.h"
#include "wx/filename.h"

View File

@@ -31,8 +31,7 @@
#include "wx/stackwalk.h"
#include "wx/msw/debughlp.h"
#if wxUSE_DBGHELP
#include "wx/msw/seh.h"
// ============================================================================
// implementation
@@ -103,6 +102,8 @@ void wxStackFrame::OnParam(wxSYMBOL_INFO *pSymInfo)
m_paramTypes.Add(wxEmptyString);
m_paramNames.Add(pSymInfo->Name);
wxString value;
// if symbol information is corrupted and we crash, the exception is going
// to be ignored when we're called from WalkFromException() because of the
// exception handler there returning EXCEPTION_CONTINUE_EXECUTION, but we'd
@@ -111,22 +112,23 @@ void wxStackFrame::OnParam(wxSYMBOL_INFO *pSymInfo)
#ifdef _CPPUNWIND
try
#else
__try
wxSEH_TRY
#endif
{
// as it is a parameter (and not a global var), it is always offset by
// the frame address
DWORD_PTR pValue = m_addrFrame + pSymInfo->Address;
m_paramValues.Add(wxDbgHelpDLL::DumpSymbol(pSymInfo, (void *)pValue));
value = wxDbgHelpDLL::DumpSymbol(pSymInfo, (void *)pValue);
}
#ifdef _CPPUNWIND
catch ( ... )
#else
__except ( EXCEPTION_EXECUTE_HANDLER )
#endif
{
m_paramValues.Add(wxEmptyString);
}
#else
wxSEH_IGNORE
#endif
m_paramValues.Add(value);
}
BOOL CALLBACK
@@ -170,7 +172,7 @@ void wxStackFrame::OnGetParam()
if ( !wxDbgHelpDLL::CallSymEnumSymbols
(
::GetCurrentProcess(),
NULL, // DLL base: use current context
0, // DLL base: use current context
EnumSymbolsProc, // callback
this // data to pass to it
) )
@@ -304,91 +306,47 @@ void wxStackWalker::WalkFromException(size_t maxDepth)
#endif // wxUSE_ON_FATAL_EXCEPTION
void wxStackWalker::Walk(size_t skip, size_t WXUNUSED(maxDepth))
void wxStackWalker::Walk(size_t skip, size_t maxDepth)
{
// to get a CONTEXT for the current location, simply force an exception and
// get EXCEPTION_POINTERS from it
//
// note:
// 1. we additionally skip RaiseException() and WalkFrom() frames
// 2. explicit cast to EXCEPTION_POINTERS is needed with VC7.1 even if it
// shouldn't have been according to the docs
__try
{
RaiseException(0x1976, 0, 0, NULL);
}
__except( WalkFrom((EXCEPTION_POINTERS *)GetExceptionInformation(),
skip + 2), EXCEPTION_CONTINUE_EXECUTION )
{
// never executed because the above expression always evaluates to
// EXCEPTION_CONTINUE_EXECUTION
}
// This code is based on frames.cpp from Edd Dawson's dbg library
// (https://bitbucket.org/edd/dbg/) which is distributed under Boost
// Software License.
CONTEXT ctx;
#ifdef __WIN64__
RtlCaptureContext(&ctx);
#else // Win32
// RtlCaptureContext() is not implemented correctly for x86 and can even
// crash when frame pointer is omitted, don't use it.
wxZeroMemory(ctx);
ctx.ContextFlags = CONTEXT_CONTROL;
#ifdef __GNUC__
DWORD regEip, regEsp, regEbp;
asm volatile ("call 1f\n\t" "1: pop %0" : "=g"(regEip));
asm volatile ("movl %%esp, %0" : "=g"(regEsp));
asm volatile ("movl %%ebp, %0" : "=g"(regEbp));
ctx.Eip = regEip;
ctx.Esp = regEsp;
ctx.Ebp = regEbp;
#elif __VISUALC__
__asm
{
Here:
mov [ctx.Ebp], ebp
mov [ctx.Esp], esp
mov eax, [Here]
mov [ctx.Eip], eax
}
#else
#error Missing implementation of RtlCaptureContext()
#endif
#endif // Win64/32
WalkFrom(&ctx, skip, maxDepth);
}
#else // !wxUSE_DBGHELP
// ============================================================================
// stubs
// ============================================================================
// ----------------------------------------------------------------------------
// wxStackFrame
// ----------------------------------------------------------------------------
void wxStackFrame::OnGetName()
{
}
void wxStackFrame::OnGetLocation()
{
}
bool
wxStackFrame::GetParam(size_t WXUNUSED(n),
wxString * WXUNUSED(type),
wxString * WXUNUSED(name),
wxString * WXUNUSED(value)) const
{
return false;
}
void wxStackFrame::OnParam(wxSYMBOL_INFO * WXUNUSED(pSymInfo))
{
}
void wxStackFrame::OnGetParam()
{
}
// ----------------------------------------------------------------------------
// wxStackWalker
// ----------------------------------------------------------------------------
void
wxStackWalker::WalkFrom(const CONTEXT * WXUNUSED(pCtx),
size_t WXUNUSED(skip),
size_t WXUNUSED(maxDepth))
{
}
void
wxStackWalker::WalkFrom(const _EXCEPTION_POINTERS * WXUNUSED(ep),
size_t WXUNUSED(skip),
size_t WXUNUSED(maxDepth))
{
}
#if wxUSE_ON_FATAL_EXCEPTION
void wxStackWalker::WalkFromException(size_t WXUNUSED(maxDepth))
{
}
#endif // wxUSE_ON_FATAL_EXCEPTION
void wxStackWalker::Walk(size_t WXUNUSED(skip), size_t WXUNUSED(maxDepth))
{
}
#endif // wxUSE_DBGHELP/!wxUSE_DBGHELP
#endif // wxUSE_STACKWALKER