]> git.saurik.com Git - wxWidgets.git/blame - src/msw/stackwalk.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / msw / stackwalk.cpp
CommitLineData
7beafee9 1/////////////////////////////////////////////////////////////////////////////
80fdcdb9 2// Name: src/msw/stackwalk.cpp
7beafee9
VZ
3// Purpose: wxStackWalker implementation for Win32
4// Author: Vadim Zeitlin
7dbb4353 5// Modified by: Artur Bac 2010-10-01 AMD64 Port
7beafee9 6// Created: 2005-01-08
7beafee9
VZ
7// Copyright: (c) 2003-2005 Vadim Zeitlin <vadim@wxwindows.org>
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19#include "wx/wxprec.h"
20
21#ifdef __BORLANDC__
22 #pragma hdrstop
23#endif
24
25#if wxUSE_STACKWALKER
26
60431236
WS
27#ifndef WX_PRECOMP
28 #include "wx/string.h"
29#endif
30
7beafee9
VZ
31#include "wx/stackwalk.h"
32
33#include "wx/msw/debughlp.h"
34
35#if wxUSE_DBGHELP
36
37// ============================================================================
38// implementation
39// ============================================================================
40
41// ----------------------------------------------------------------------------
42// wxStackFrame
43// ----------------------------------------------------------------------------
44
45void wxStackFrame::OnGetName()
46{
47 if ( m_hasName )
48 return;
49
50 m_hasName = true;
51
52 // get the name of the function for this stack frame entry
53 static const size_t MAX_NAME_LEN = 1024;
7dbb4353 54 BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_NAME_LEN];
7beafee9
VZ
55 wxZeroMemory(symbolBuffer);
56
7dbb4353
VZ
57 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;
58 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
7beafee9
VZ
59 pSymbol->MaxNameLen = MAX_NAME_LEN;
60
61 DWORD64 symDisplacement = 0;
7dbb4353 62 if ( !wxDbgHelpDLL::SymFromAddr
7beafee9
VZ
63 (
64 ::GetCurrentProcess(),
65 GetSymAddr(),
66 &symDisplacement,
67 pSymbol
68 ) )
69 {
7dbb4353 70 wxDbgHelpDLL::LogError(wxT("SymFromAddr"));
7beafee9
VZ
71 return;
72 }
7dbb4353
VZ
73
74 m_name = wxString::FromAscii(pSymbol->Name);
7beafee9
VZ
75 m_offset = symDisplacement;
76}
77
78void wxStackFrame::OnGetLocation()
79{
80 if ( m_hasLocation )
81 return;
82
83 m_hasLocation = true;
84
85 // get the source line for this stack frame entry
7dbb4353 86 IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) };
7beafee9 87 DWORD dwLineDisplacement;
7dbb4353 88 if ( !wxDbgHelpDLL::SymGetLineFromAddr
7beafee9
VZ
89 (
90 ::GetCurrentProcess(),
91 GetSymAddr(),
92 &dwLineDisplacement,
93 &lineInfo
94 ) )
95 {
96 // it is normal that we don't have source info for some symbols,
97 // notably all the ones from the system DLLs...
7dbb4353 98 //wxDbgHelpDLL::LogError(wxT("SymGetLineFromAddr"));
7beafee9
VZ
99 return;
100 }
7dbb4353
VZ
101
102 m_filename = wxString::FromAscii(lineInfo.FileName);
7beafee9
VZ
103 m_line = lineInfo.LineNumber;
104}
105
106bool
107wxStackFrame::GetParam(size_t n,
108 wxString *type,
109 wxString *name,
110 wxString *value) const
111{
112 if ( !DoGetParamCount() )
113 ConstCast()->OnGetParam();
114
115 if ( n >= DoGetParamCount() )
116 return false;
117
118 if ( type )
119 *type = m_paramTypes[n];
120 if ( name )
121 *name = m_paramNames[n];
122 if ( value )
123 *value = m_paramValues[n];
124
125 return true;
126}
127
7dbb4353 128void wxStackFrame::OnParam(PSYMBOL_INFO pSymInfo)
7beafee9 129{
f31a4098 130 m_paramTypes.Add(wxEmptyString);
7beafee9 131
7dbb4353 132 m_paramNames.Add(wxString::FromAscii(pSymInfo->Name));
7beafee9
VZ
133
134 // if symbol information is corrupted and we crash, the exception is going
135 // to be ignored when we're called from WalkFromException() because of the
3103e8a9
JS
136 // exception handler there returning EXCEPTION_CONTINUE_EXECUTION, but we'd
137 // be left in an inconsistent state, so deal with it explicitly here (even
138 // if normally we should never crash, of course...)
7beafee9
VZ
139#ifdef _CPPUNWIND
140 try
141#else
142 __try
143#endif
144 {
145 // as it is a parameter (and not a global var), it is always offset by
146 // the frame address
147 DWORD_PTR pValue = m_addrFrame + pSymInfo->Address;
148 m_paramValues.Add(wxDbgHelpDLL::DumpSymbol(pSymInfo, (void *)pValue));
149 }
150#ifdef _CPPUNWIND
151 catch ( ... )
152#else
153 __except ( EXCEPTION_EXECUTE_HANDLER )
154#endif
155 {
f31a4098 156 m_paramValues.Add(wxEmptyString);
7beafee9
VZ
157 }
158}
159
160BOOL CALLBACK
7dbb4353 161EnumSymbolsProc(PSYMBOL_INFO pSymInfo, ULONG WXUNUSED(SymSize), PVOID data)
7beafee9 162{
5c33522f 163 wxStackFrame *frame = static_cast<wxStackFrame *>(data);
7beafee9
VZ
164
165 // we're only interested in parameters
166 if ( pSymInfo->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER )
167 {
168 frame->OnParam(pSymInfo);
169 }
60431236 170
7beafee9
VZ
171 // return true to continue enumeration, false would have stopped it
172 return TRUE;
173}
174
175void wxStackFrame::OnGetParam()
176{
177 // use SymSetContext to get just the locals/params for this frame
178 IMAGEHLP_STACK_FRAME imagehlpStackFrame;
179 wxZeroMemory(imagehlpStackFrame);
180 imagehlpStackFrame.InstructionOffset = GetSymAddr();
181 if ( !wxDbgHelpDLL::SymSetContext
182 (
183 ::GetCurrentProcess(),
184 &imagehlpStackFrame,
185 0 // unused
186 ) )
187 {
188 // for symbols from kernel DLL we might not have access to their
189 // address, this is not a real error
190 if ( ::GetLastError() != ERROR_INVALID_ADDRESS )
191 {
9a83f860 192 wxDbgHelpDLL::LogError(wxT("SymSetContext"));
7beafee9
VZ
193 }
194
195 return;
196 }
197
7dbb4353 198 if ( !wxDbgHelpDLL::SymEnumSymbols
7beafee9
VZ
199 (
200 ::GetCurrentProcess(),
201 NULL, // DLL base: use current context
202 NULL, // no mask, get all symbols
203 EnumSymbolsProc, // callback
204 this // data to pass to it
205 ) )
206 {
7dbb4353 207 wxDbgHelpDLL::LogError(wxT("SymEnumSymbols"));
7beafee9
VZ
208 }
209}
210
211
212// ----------------------------------------------------------------------------
213// wxStackWalker
214// ----------------------------------------------------------------------------
215
ef81fe8b 216void wxStackWalker::WalkFrom(const CONTEXT *pCtx, size_t skip, size_t maxDepth)
7beafee9
VZ
217{
218 if ( !wxDbgHelpDLL::Init() )
219 {
b3a6d269
VZ
220 // don't log a user-visible error message here because the stack trace
221 // is only needed for debugging/diagnostics anyhow and we shouldn't
222 // confuse the user by complaining that we couldn't generate it
9a83f860 223 wxLogDebug(wxT("Failed to get stack backtrace: %s"),
7beafee9 224 wxDbgHelpDLL::GetErrorMessage().c_str());
1d7ea62e 225 return;
7beafee9
VZ
226 }
227
228 // according to MSDN, the first parameter should be just a unique value and
229 // not process handle (although the parameter is prototyped as "HANDLE
230 // hProcess") and actually it advises to use the process id and not handle
231 // for Win9x, but then we need to use the same value in StackWalk() call
232 // below which should be a real handle... so this is what we use
233 const HANDLE hProcess = ::GetCurrentProcess();
234
7dbb4353 235 if ( !wxDbgHelpDLL::SymInitialize
7beafee9
VZ
236 (
237 hProcess,
238 NULL, // use default symbol search path
239 TRUE // load symbols for all loaded modules
240 ) )
241 {
7dbb4353 242 wxDbgHelpDLL::LogError(wxT("SymInitialize"));
7beafee9
VZ
243
244 return;
245 }
246
247 CONTEXT ctx = *pCtx; // will be modified by StackWalk()
248
249 DWORD dwMachineType;
250
251 // initialize the initial frame: currently we can do it for x86 only
252 STACKFRAME sf;
253 wxZeroMemory(sf);
254
603c73db
VZ
255#if defined(_M_AMD64)
256 sf.AddrPC.Offset = ctx.Rip;
257 sf.AddrPC.Mode = AddrModeFlat;
258 sf.AddrStack.Offset = ctx.Rsp;
259 sf.AddrStack.Mode = AddrModeFlat;
260 sf.AddrFrame.Offset = ctx.Rbp;
261 sf.AddrFrame.Mode = AddrModeFlat;
262
263 dwMachineType = IMAGE_FILE_MACHINE_AMD64;
264#elif defined(_M_IX86)
7beafee9
VZ
265 sf.AddrPC.Offset = ctx.Eip;
266 sf.AddrPC.Mode = AddrModeFlat;
267 sf.AddrStack.Offset = ctx.Esp;
268 sf.AddrStack.Mode = AddrModeFlat;
269 sf.AddrFrame.Offset = ctx.Ebp;
270 sf.AddrFrame.Mode = AddrModeFlat;
271
272 dwMachineType = IMAGE_FILE_MACHINE_I386;
273#else
274 #error "Need to initialize STACKFRAME on non x86"
275#endif // _M_IX86
276
277 // iterate over all stack frames
ef81fe8b 278 for ( size_t nLevel = 0; nLevel < maxDepth; nLevel++ )
7beafee9
VZ
279 {
280 // get the next stack frame
281 if ( !wxDbgHelpDLL::StackWalk
282 (
283 dwMachineType,
284 hProcess,
285 ::GetCurrentThread(),
286 &sf,
287 &ctx,
288 NULL, // read memory function (default)
289 wxDbgHelpDLL::SymFunctionTableAccess,
290 wxDbgHelpDLL::SymGetModuleBase,
291 NULL // address translator for 16 bit
292 ) )
293 {
294 if ( ::GetLastError() )
9a83f860 295 wxDbgHelpDLL::LogError(wxT("StackWalk"));
7beafee9
VZ
296
297 break;
298 }
299
300 // don't show this frame itself in the output
301 if ( nLevel >= skip )
302 {
303 wxStackFrame frame(nLevel - skip,
3f49efdb 304 wxUIntToPtr(sf.AddrPC.Offset),
7beafee9
VZ
305 sf.AddrFrame.Offset);
306
307 OnStackFrame(frame);
308 }
309 }
310
7beafee9
VZ
311 if ( !wxDbgHelpDLL::SymCleanup(hProcess) )
312 {
9a83f860 313 wxDbgHelpDLL::LogError(wxT("SymCleanup"));
7beafee9 314 }
7beafee9
VZ
315}
316
ef81fe8b 317void wxStackWalker::WalkFrom(const _EXCEPTION_POINTERS *ep, size_t skip, size_t maxDepth)
7beafee9 318{
ef81fe8b 319 WalkFrom(ep->ContextRecord, skip, maxDepth);
7beafee9
VZ
320}
321
4db307e1
VZ
322#if wxUSE_ON_FATAL_EXCEPTION
323
ef81fe8b 324void wxStackWalker::WalkFromException(size_t maxDepth)
7beafee9
VZ
325{
326 extern EXCEPTION_POINTERS *wxGlobalSEInformation;
327
328 wxCHECK_RET( wxGlobalSEInformation,
9a83f860 329 wxT("wxStackWalker::WalkFromException() can only be called from wxApp::OnFatalException()") );
7beafee9
VZ
330
331 // don't skip any frames, the first one is where we crashed
ef81fe8b 332 WalkFrom(wxGlobalSEInformation, 0, maxDepth);
7beafee9
VZ
333}
334
4db307e1
VZ
335#endif // wxUSE_ON_FATAL_EXCEPTION
336
a82c2299 337void wxStackWalker::Walk(size_t skip, size_t WXUNUSED(maxDepth))
7beafee9
VZ
338{
339 // to get a CONTEXT for the current location, simply force an exception and
340 // get EXCEPTION_POINTERS from it
341 //
342 // note:
4db307e1 343 // 1. we additionally skip RaiseException() and WalkFrom() frames
7beafee9
VZ
344 // 2. explicit cast to EXCEPTION_POINTERS is needed with VC7.1 even if it
345 // shouldn't have been according to the docs
346 __try
347 {
348 RaiseException(0x1976, 0, 0, NULL);
349 }
350 __except( WalkFrom((EXCEPTION_POINTERS *)GetExceptionInformation(),
351 skip + 2), EXCEPTION_CONTINUE_EXECUTION )
352 {
4db307e1
VZ
353 // never executed because the above expression always evaluates to
354 // EXCEPTION_CONTINUE_EXECUTION
7beafee9
VZ
355 }
356}
357
358#else // !wxUSE_DBGHELP
359
2289dcea
VZ
360// ============================================================================
361// stubs
362// ============================================================================
363
364// ----------------------------------------------------------------------------
365// wxStackFrame
366// ----------------------------------------------------------------------------
367
368void wxStackFrame::OnGetName()
369{
370}
371
372void wxStackFrame::OnGetLocation()
373{
374}
375
376bool
377wxStackFrame::GetParam(size_t WXUNUSED(n),
378 wxString * WXUNUSED(type),
379 wxString * WXUNUSED(name),
380 wxString * WXUNUSED(value)) const
381{
382 return false;
383}
384
7dbb4353 385void wxStackFrame::OnParam(_SYMBOL_INFO * WXUNUSED(pSymInfo))
2289dcea
VZ
386{
387}
388
389void wxStackFrame::OnGetParam()
390{
391}
392
393// ----------------------------------------------------------------------------
394// wxStackWalker
395// ----------------------------------------------------------------------------
396
397void
057bf0be
VZ
398wxStackWalker::WalkFrom(const CONTEXT * WXUNUSED(pCtx),
399 size_t WXUNUSED(skip),
400 size_t WXUNUSED(maxDepth))
2289dcea
VZ
401{
402}
403
404void
405wxStackWalker::WalkFrom(const _EXCEPTION_POINTERS * WXUNUSED(ep),
057bf0be
VZ
406 size_t WXUNUSED(skip),
407 size_t WXUNUSED(maxDepth))
2289dcea
VZ
408{
409}
410
4db307e1 411#if wxUSE_ON_FATAL_EXCEPTION
ef81fe8b 412void wxStackWalker::WalkFromException(size_t WXUNUSED(maxDepth))
2289dcea
VZ
413{
414}
4db307e1 415#endif // wxUSE_ON_FATAL_EXCEPTION
2289dcea 416
0034bd13 417void wxStackWalker::Walk(size_t WXUNUSED(skip), size_t WXUNUSED(maxDepth))
2289dcea
VZ
418{
419}
7beafee9
VZ
420
421#endif // wxUSE_DBGHELP/!wxUSE_DBGHELP
422
423#endif // wxUSE_STACKWALKER
424