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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 11 months ago) by william
File size: 12461 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 william 31 /////////////////////////////////////////////////////////////////////////////
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 william 62 #if wxUSE_THREADS
213     static wxMutex s_mtx_StackWalker;
214     #endif
215 william 31
216     // ----------------------------------------------------------------------------
217     // wxStackWalker
218     // ----------------------------------------------------------------------------
219    
220     void wxStackWalker::WalkFrom(const CONTEXT *pCtx, size_t skip)
221     {
222 william 62 #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 william 31 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 william 62 if ( !wxDbgHelpDLL::RefreshModuleList(hProcess) ) return;
248 william 31
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 william 62 // PCSX2 : Added wxUSE_ON_FATAL_EXCEPTION check, which was missing. --air
323     #if wxUSE_ON_FATAL_EXCEPTION
324 william 31 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 william 62 #endif
332 william 31 }
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