/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/msw/stackwalk.cpp
ViewVC logotype

Contents of /trunk/3rdparty/wxWidgets/src/msw/stackwalk.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22