/[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 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 11 months ago) by william
File size: 12308 byte(s)
committing r3113 initial commit again...
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    
213     // ----------------------------------------------------------------------------
214     // wxStackWalker
215     // ----------------------------------------------------------------------------
216    
217     void wxStackWalker::WalkFrom(const CONTEXT *pCtx, size_t skip)
218     {
219     if ( !wxDbgHelpDLL::Init() )
220     {
221     // don't log a user-visible error message here because the stack trace
222     // is only needed for debugging/diagnostics anyhow and we shouldn't
223     // confuse the user by complaining that we couldn't generate it
224     wxLogDebug(_T("Failed to get stack backtrace: %s"),
225     wxDbgHelpDLL::GetErrorMessage().c_str());
226     return;
227     }
228    
229     // according to MSDN, the first parameter should be just a unique value and
230     // not process handle (although the parameter is prototyped as "HANDLE
231     // hProcess") and actually it advises to use the process id and not handle
232     // for Win9x, but then we need to use the same value in StackWalk() call
233     // below which should be a real handle... so this is what we use
234     const HANDLE hProcess = ::GetCurrentProcess();
235    
236     if ( !wxDbgHelpDLL::SymInitialize
237     (
238     hProcess,
239     NULL, // use default symbol search path
240     TRUE // load symbols for all loaded modules
241     ) )
242     {
243     wxDbgHelpDLL::LogError(_T("SymInitialize"));
244    
245     return;
246     }
247    
248     CONTEXT ctx = *pCtx; // will be modified by StackWalk()
249    
250     DWORD dwMachineType;
251    
252     // initialize the initial frame: currently we can do it for x86 only
253     STACKFRAME sf;
254     wxZeroMemory(sf);
255    
256     #ifdef _M_IX86
257     sf.AddrPC.Offset = ctx.Eip;
258     sf.AddrPC.Mode = AddrModeFlat;
259     sf.AddrStack.Offset = ctx.Esp;
260     sf.AddrStack.Mode = AddrModeFlat;
261     sf.AddrFrame.Offset = ctx.Ebp;
262     sf.AddrFrame.Mode = AddrModeFlat;
263    
264     dwMachineType = IMAGE_FILE_MACHINE_I386;
265     #else
266     #error "Need to initialize STACKFRAME on non x86"
267     #endif // _M_IX86
268    
269     // iterate over all stack frames (but stop after 200 to avoid entering
270     // infinite loop if the stack is corrupted)
271     for ( size_t nLevel = 0; nLevel < 200; nLevel++ )
272     {
273     // get the next stack frame
274     if ( !wxDbgHelpDLL::StackWalk
275     (
276     dwMachineType,
277     hProcess,
278     ::GetCurrentThread(),
279     &sf,
280     &ctx,
281     NULL, // read memory function (default)
282     wxDbgHelpDLL::SymFunctionTableAccess,
283     wxDbgHelpDLL::SymGetModuleBase,
284     NULL // address translator for 16 bit
285     ) )
286     {
287     if ( ::GetLastError() )
288     wxDbgHelpDLL::LogError(_T("StackWalk"));
289    
290     break;
291     }
292    
293     // don't show this frame itself in the output
294     if ( nLevel >= skip )
295     {
296     wxStackFrame frame(nLevel - skip,
297     (void *)sf.AddrPC.Offset,
298     sf.AddrFrame.Offset);
299    
300     OnStackFrame(frame);
301     }
302     }
303    
304     // this results in crashes inside ntdll.dll when called from
305     // exception handler ...
306     #if 0
307     if ( !wxDbgHelpDLL::SymCleanup(hProcess) )
308     {
309     wxDbgHelpDLL::LogError(_T("SymCleanup"));
310     }
311     #endif
312     }
313    
314     void wxStackWalker::WalkFrom(const _EXCEPTION_POINTERS *ep, size_t skip)
315     {
316     WalkFrom(ep->ContextRecord, skip);
317     }
318    
319     void wxStackWalker::WalkFromException()
320     {
321     extern EXCEPTION_POINTERS *wxGlobalSEInformation;
322    
323     wxCHECK_RET( wxGlobalSEInformation,
324     _T("wxStackWalker::WalkFromException() can only be called from wxApp::OnFatalException()") );
325    
326     // don't skip any frames, the first one is where we crashed
327     WalkFrom(wxGlobalSEInformation, 0);
328     }
329    
330     void wxStackWalker::Walk(size_t skip, size_t WXUNUSED(maxDepth))
331     {
332     // to get a CONTEXT for the current location, simply force an exception and
333     // get EXCEPTION_POINTERS from it
334     //
335     // note:
336     // 1. we additionally skip RaiseException() and WalkFromException() frames
337     // 2. explicit cast to EXCEPTION_POINTERS is needed with VC7.1 even if it
338     // shouldn't have been according to the docs
339     __try
340     {
341     RaiseException(0x1976, 0, 0, NULL);
342     }
343     __except( WalkFrom((EXCEPTION_POINTERS *)GetExceptionInformation(),
344     skip + 2), EXCEPTION_CONTINUE_EXECUTION )
345     {
346     // never executed because of WalkFromException() return value
347     }
348     }
349    
350     #else // !wxUSE_DBGHELP
351    
352     // ============================================================================
353     // stubs
354     // ============================================================================
355    
356     // ----------------------------------------------------------------------------
357     // wxStackFrame
358     // ----------------------------------------------------------------------------
359    
360     void wxStackFrame::OnGetName()
361     {
362     }
363    
364     void wxStackFrame::OnGetLocation()
365     {
366     }
367    
368     bool
369     wxStackFrame::GetParam(size_t WXUNUSED(n),
370     wxString * WXUNUSED(type),
371     wxString * WXUNUSED(name),
372     wxString * WXUNUSED(value)) const
373     {
374     return false;
375     }
376    
377     void wxStackFrame::OnParam(_SYMBOL_INFO * WXUNUSED(pSymInfo))
378     {
379     }
380    
381     void wxStackFrame::OnGetParam()
382     {
383     }
384    
385     // ----------------------------------------------------------------------------
386     // wxStackWalker
387     // ----------------------------------------------------------------------------
388    
389     void
390     wxStackWalker::WalkFrom(const CONTEXT * WXUNUSED(pCtx), size_t WXUNUSED(skip))
391     {
392     }
393    
394     void
395     wxStackWalker::WalkFrom(const _EXCEPTION_POINTERS * WXUNUSED(ep),
396     size_t WXUNUSED(skip))
397     {
398     }
399    
400     void wxStackWalker::WalkFromException()
401     {
402     }
403    
404     void wxStackWalker::Walk(size_t WXUNUSED(skip), size_t WXUNUSED(maxDepth))
405     {
406     }
407    
408     #endif // wxUSE_DBGHELP/!wxUSE_DBGHELP
409    
410     #endif // wxUSE_STACKWALKER
411    

  ViewVC Help
Powered by ViewVC 1.1.22