[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / utilcode / stacktrace.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //----------------------------------------------------------------------------- 
5
6 //----------------------------------------------------------------------------- 
7
8 #include "stdafx.h"
9
10 #include "stacktrace.h"
11 #include <imagehlp.h>
12 #include "corhlpr.h"
13 #include "utilcode.h"
14 #include "pedecoder.h" // for IMAGE_FILE_MACHINE_NATIVE
15
16 //This is a workaround. We need to work with the debugger team to figure
17 //out how the module handle of the CLR can be found in a SxS safe way.
18 HMODULE GetCLRModuleHack()
19 {
20     static HMODULE s_hModCLR = 0;
21     if (!s_hModCLR)
22     {
23         s_hModCLR = GetModuleHandleA(MAIN_CLR_DLL_NAME_A);
24     }
25     return s_hModCLR;
26 }
27
28 HINSTANCE LoadImageHlp()
29 {
30     STATIC_CONTRACT_NOTHROW;
31     STATIC_CONTRACT_GC_NOTRIGGER;
32     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
33     SCAN_IGNORE_FAULT; // Faults from Wsz funcs are handled.
34     
35     return LoadLibraryExA("imagehlp.dll", NULL, 0);
36 }
37
38 HINSTANCE LoadDbgHelp()
39 {
40     STATIC_CONTRACT_NOTHROW;
41     STATIC_CONTRACT_GC_NOTRIGGER;
42     SCAN_IGNORE_FAULT; // Faults from Wsz funcs are handled.
43     
44     return LoadLibraryExA("dbghelp.dll", NULL, 0);
45 }
46
47 /****************************************************************************
48 * SymCallback *
49 *---------------------*
50 *   Description:  
51 *       Callback for imghelp.
52 ****************************************************************************/
53 BOOL __stdcall SymCallback
54 (
55 HANDLE hProcess,
56 ULONG ActionCode,
57 PVOID CallbackData,
58 PVOID UserContext
59 )
60 {
61     WRAPPER_NO_CONTRACT;
62
63     switch (ActionCode)
64     {
65     case CBA_DEBUG_INFO:
66         OutputDebugStringA("IMGHLP: ");
67         OutputDebugStringA((LPCSTR) CallbackData);
68         OutputDebugStringA("\n");
69         break;
70
71     case CBA_DEFERRED_SYMBOL_LOAD_START:
72         OutputDebugStringA("IMGHLP: Deferred symbol load start ");
73         OutputDebugStringA(((IMAGEHLP_DEFERRED_SYMBOL_LOAD*)CallbackData)->FileName);
74         OutputDebugStringA("\n");
75         break;
76
77     case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
78         OutputDebugStringA("IMGHLP: Deferred symbol load complete ");
79         OutputDebugStringA(((IMAGEHLP_DEFERRED_SYMBOL_LOAD*)CallbackData)->FileName);
80         OutputDebugStringA("\n");
81         break;
82
83     case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
84         OutputDebugStringA("IMGHLP: Deferred symbol load failure ");
85         OutputDebugStringA(((IMAGEHLP_DEFERRED_SYMBOL_LOAD*)CallbackData)->FileName);
86         OutputDebugStringA("\n");
87         break;
88
89     case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
90         OutputDebugStringA("IMGHLP: Deferred symbol load partial ");
91         OutputDebugStringA(((IMAGEHLP_DEFERRED_SYMBOL_LOAD*)CallbackData)->FileName);
92         OutputDebugStringA("\n");
93         break;
94     }
95     
96     return FALSE;
97 }
98
99 // @TODO_IA64: all of this stack trace stuff is pretty much broken on 64-bit
100 // right now because this code doesn't use the new SymXxxx64 functions.
101
102 #define LOCAL_ASSERT(x)
103 //
104 //--- Macros ------------------------------------------------------------------
105 //
106
107 #define COUNT_OF(x)    (sizeof(x) / sizeof(x[0]))
108
109 //
110 // Types and Constants --------------------------------------------------------
111 //
112
113 struct SYM_INFO
114 {
115     DWORD_PTR   dwOffset;
116     char        achModule[cchMaxAssertModuleLen];
117     char        achSymbol[cchMaxAssertSymbolLen];
118 };
119
120 //--- Function Pointers to APIs in IMAGEHLP.DLL. Loaded dynamically. ---------
121
122 typedef LPAPI_VERSION (__stdcall *pfnImgHlp_ImagehlpApiVersionEx)(
123     LPAPI_VERSION AppVersion
124     );
125
126 typedef BOOL (__stdcall *pfnImgHlp_StackWalk)(
127     DWORD                             MachineType,
128     HANDLE                            hProcess,
129     HANDLE                            hThread,
130     LPSTACKFRAME                      StackFrame,
131     LPVOID                            ContextRecord,
132     PREAD_PROCESS_MEMORY_ROUTINE      ReadMemoryRoutine,
133     PFUNCTION_TABLE_ACCESS_ROUTINE    FunctionTableAccessRoutine,
134     PGET_MODULE_BASE_ROUTINE          GetModuleBaseRoutine,
135     PTRANSLATE_ADDRESS_ROUTINE        TranslateAddress
136     );
137
138 #ifdef _WIN64
139 typedef DWORD64 (__stdcall *pfnImgHlp_SymGetModuleBase64)(
140     IN  HANDLE          hProcess,
141     IN  DWORD64         dwAddr
142     );
143
144 typedef IMAGEHLP_SYMBOL64 PLAT_IMAGEHLP_SYMBOL;
145 typedef IMAGEHLP_MODULE64 PLAT_IMAGEHLP_MODULE;
146
147 #else
148 typedef IMAGEHLP_SYMBOL PLAT_IMAGEHLP_SYMBOL;
149 typedef IMAGEHLP_MODULE PLAT_IMAGEHLP_MODULE;
150 #endif
151
152 #undef IMAGEHLP_SYMBOL
153 #undef IMAGEHLP_MODULE
154
155     
156 typedef BOOL (__stdcall *pfnImgHlp_SymGetModuleInfo)(
157     IN  HANDLE                  hProcess,
158     IN  DWORD_PTR               dwAddr,
159     OUT PLAT_IMAGEHLP_MODULE*   ModuleInfo
160     );
161
162 typedef LPVOID (__stdcall *pfnImgHlp_SymFunctionTableAccess)(
163     HANDLE                  hProcess,
164     DWORD_PTR               AddrBase
165     );
166
167 typedef BOOL (__stdcall *pfnImgHlp_SymGetSymFromAddr)(
168     IN  HANDLE                  hProcess,
169     IN  DWORD_PTR               dwAddr,
170     OUT DWORD_PTR*              pdwDisplacement,
171     OUT PLAT_IMAGEHLP_SYMBOL*   Symbol
172     );
173
174 typedef BOOL (__stdcall *pfnImgHlp_SymInitialize)(
175     IN HANDLE   hProcess,
176     IN LPSTR    UserSearchPath,
177     IN BOOL     fInvadeProcess
178     );
179
180 typedef BOOL (__stdcall *pfnImgHlp_SymUnDName)(
181     IN  PLAT_IMAGEHLP_SYMBOL*   sym,               // Symbol to undecorate
182     OUT LPSTR                   UnDecName,         // Buffer to store undecorated name in
183     IN  DWORD                   UnDecNameLength    // Size of the buffer
184     );
185
186 typedef BOOL (__stdcall *pfnImgHlp_SymLoadModule)(
187     IN  HANDLE          hProcess,
188     IN  HANDLE          hFile,
189     IN  PSTR            ImageName,
190     IN  PSTR            ModuleName,
191     IN  DWORD_PTR       BaseOfDll,
192     IN  DWORD           SizeOfDll
193     );
194
195 typedef BOOL (_stdcall *pfnImgHlp_SymRegisterCallback)(
196     IN  HANDLE                          hProcess,
197     IN  PSYMBOL_REGISTERED_CALLBACK     CallbackFunction,
198     IN  PVOID                           UserContext
199     );
200
201 typedef DWORD (_stdcall *pfnImgHlp_SymSetOptions)(
202     IN  DWORD           SymOptions
203     );
204
205 typedef DWORD (_stdcall *pfnImgHlp_SymGetOptions)(
206     );
207
208
209 struct IMGHLPFN_LOAD
210 {
211     LPCSTR   pszFnName;
212     LPVOID * ppvfn;
213 };
214
215
216 #if defined(_WIN64)
217 typedef void (*pfn_GetRuntimeStackWalkInfo)(
218     IN  ULONG64   ControlPc,
219     OUT UINT_PTR* pModuleBase,
220     OUT UINT_PTR* pFuncEntry
221     );
222 #endif // _WIN64
223
224
225 //
226 // Globals --------------------------------------------------------------------
227 //
228
229 static BOOL      g_fLoadedImageHlp = FALSE;          // set to true on success
230 static BOOL      g_fLoadedImageHlpFailed = FALSE;    // set to true on failure
231 static HINSTANCE g_hinstImageHlp   = NULL;
232 static HINSTANCE g_hinstDbgHelp    = NULL;
233 static HANDLE    g_hProcess = NULL;
234
235 pfnImgHlp_ImagehlpApiVersionEx    _ImagehlpApiVersionEx;
236 pfnImgHlp_StackWalk               _StackWalk;
237 pfnImgHlp_SymGetModuleInfo        _SymGetModuleInfo;
238 pfnImgHlp_SymFunctionTableAccess  _SymFunctionTableAccess;
239 pfnImgHlp_SymGetSymFromAddr       _SymGetSymFromAddr;
240 pfnImgHlp_SymInitialize           _SymInitialize;
241 pfnImgHlp_SymUnDName              _SymUnDName;
242 pfnImgHlp_SymLoadModule           _SymLoadModule;
243 pfnImgHlp_SymRegisterCallback     _SymRegisterCallback;
244 pfnImgHlp_SymSetOptions           _SymSetOptions;
245 pfnImgHlp_SymGetOptions           _SymGetOptions;
246 #if defined(_WIN64)
247 pfn_GetRuntimeStackWalkInfo       _GetRuntimeStackWalkInfo;
248 #endif // _WIN64
249
250 IMGHLPFN_LOAD ailFuncList[] =
251 {
252     { "ImagehlpApiVersionEx",   (LPVOID*)&_ImagehlpApiVersionEx },
253     { "StackWalk",              (LPVOID*)&_StackWalk },
254     { "SymGetModuleInfo",       (LPVOID*)&_SymGetModuleInfo },
255     { "SymFunctionTableAccess", (LPVOID*)&_SymFunctionTableAccess },
256     { "SymGetSymFromAddr",      (LPVOID*)&_SymGetSymFromAddr },
257     { "SymInitialize",          (LPVOID*)&_SymInitialize },
258     { "SymUnDName",             (LPVOID*)&_SymUnDName },
259     { "SymLoadModule",          (LPVOID*)&_SymLoadModule },
260     { "SymRegisterCallback",    (LPVOID*)&_SymRegisterCallback },
261     { "SymSetOptions",          (LPVOID*)&_SymSetOptions },
262     { "SymGetOptions",          (LPVOID*)&_SymGetOptions },
263 };
264
265
266 /****************************************************************************
267 * FillSymbolSearchPath *
268 *----------------------*
269 *   Description:  
270 *       Manually pick out all the symbol path information we need for a real
271 *       stack trace to work.  This includes the default NT symbol paths and
272 *       places on a VBL build machine where they should live.
273 ****************************************************************************/
274 #define MAX_SYM_PATH        (1024*8)
275 #define DEFAULT_SYM_PATH    W("symsrv*symsrv.dll*\\\\symbols\\symbols;")
276 #define STR_ENGINE_NAME     MAIN_CLR_DLL_NAME_W
277 LPSTR FillSymbolSearchPathThrows(CQuickBytes &qb)
278 {
279     STATIC_CONTRACT_GC_NOTRIGGER;
280     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
281     SCAN_IGNORE_FAULT; // Faults from Wsz funcs are handled.
282
283 #ifndef DACCESS_COMPILE
284     // not allowed to do allocation if current thread suspends EE.
285     if (IsSuspendEEThread ())
286         return NULL;
287 #endif
288
289    InlineSString<MAX_SYM_PATH> rcBuff ; // Working buffer
290     int         chTotal = 0;                // How full is working buffer.
291     int         ch;
292
293     // If the NT symbol server path vars are there, then use those.
294     chTotal = WszGetEnvironmentVariable(W("_NT_SYMBOL_PATH"), rcBuff); 
295     if (chTotal + 1 < MAX_SYM_PATH)
296         rcBuff.Append(W(';'));
297     
298     // Copy the defacto NT symbol path as well.
299     size_t sympathLength = chTotal + NumItems(DEFAULT_SYM_PATH) + 1;
300                 // integer overflow occurred
301         if (sympathLength < (size_t)chTotal || sympathLength < NumItems(DEFAULT_SYM_PATH))
302         {
303                 return NULL;
304         }
305
306     if (sympathLength < MAX_SYM_PATH)
307     {
308         rcBuff.Append(DEFAULT_SYM_PATH);
309         chTotal = rcBuff.GetCount();
310     }
311
312     // Next, if there is a URTTARGET, add that since that is where ndpsetup places
313     // your symobls on an install.
314     PathString rcBuffTemp;
315     ch = WszGetEnvironmentVariable(W("URTTARGET"), rcBuffTemp);
316     rcBuff.Append(rcBuffTemp);
317     if (ch != 0 && (chTotal + ch + 1 < MAX_SYM_PATH))
318     {
319         size_t chNewTotal = chTotal + ch;
320                 if (chNewTotal < (size_t)chTotal || chNewTotal < (size_t)ch)
321                 { // integer overflow occurred
322                         return NULL;
323                 }
324         chTotal += ch;
325         rcBuff.Append(W(';'));
326     }
327
328 #ifndef SELF_NO_HOST
329     // Fetch the path location of the engine dll and add that path as well, just
330     // in case URTARGET didn't cut it either.
331     // For no-host builds of utilcode, we don't necessarily have an engine DLL in the 
332     // process, so skip this part.
333     
334     ch = WszGetModuleFileName(GetCLRModuleHack(), rcBuffTemp);
335     
336
337         size_t pathLocationLength = chTotal + ch + 1;
338                 // integer overflow occurred
339         if (pathLocationLength < (size_t)chTotal || pathLocationLength < (size_t)ch)
340         {
341                 return NULL;
342         }
343         
344     if (ch != 0 && (pathLocationLength < MAX_SYM_PATH))
345     {
346         chTotal = chTotal + ch - NumItems(STR_ENGINE_NAME);
347         rcBuff.Append(W(';'));
348     }
349 #endif
350
351     // Now we have a working buffer with a bunch of interesting stuff.  Time
352     // to convert it back to ansi for the imagehlp api's.  Allocate the buffer
353     // 2x bigger to handle worst case for MBCS.
354     ch = ::WszWideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, rcBuff, -1, 0, 0, 0, 0);
355     LPSTR szRtn = (LPSTR) qb.AllocNoThrow(ch + 1);
356     if (!szRtn)
357         return NULL;
358     WszWideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, rcBuff, -1, szRtn, ch+1, 0, 0);
359     return (szRtn);
360 }
361 LPSTR FillSymbolSearchPath(CQuickBytes &qb)
362 {
363     STATIC_CONTRACT_NOTHROW;
364     STATIC_CONTRACT_GC_NOTRIGGER;
365     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
366     SCAN_IGNORE_FAULT; // Faults from Wsz funcs are handled.
367     LPSTR retval;
368     HRESULT hr = S_OK;
369
370     EX_TRY
371     {
372         retval = FillSymbolSearchPathThrows(qb);
373     }
374     EX_CATCH_HRESULT(hr);
375
376     if (hr != S_OK)
377     {
378         SetLastError(hr);
379         retval = NULL;
380     }
381
382     return retval;
383 }
384
385 /****************************************************************************
386 * MagicInit *
387 *-----------*
388 *   Description:  
389 *       Initializes the symbol loading code. Currently called (if necessary)
390 *       at the beginning of each method that might need ImageHelp to be
391 *       loaded.
392 ****************************************************************************/
393 void MagicInit()
394 {
395     STATIC_CONTRACT_NOTHROW;
396     STATIC_CONTRACT_GC_NOTRIGGER;
397     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
398     
399     if (g_fLoadedImageHlp || g_fLoadedImageHlpFailed)
400     {
401         return;
402     }
403
404     g_hProcess = GetCurrentProcess();
405
406     if (g_hinstDbgHelp == NULL)
407     {
408         g_hinstDbgHelp = LoadDbgHelp();
409     }
410     if (NULL == g_hinstDbgHelp)
411     {
412         // Imagehlp.dll has dependency on dbghelp.dll through delay load.
413         // If dbghelp.dll is not available, Imagehlp.dll initializes API's like ImageApiVersionEx to
414         // some dummy function.  Then we AV when we use data from _ImagehlpApiVersionEx
415         g_fLoadedImageHlpFailed = TRUE;
416         return;
417     }
418
419     //
420     // Try to load imagehlp.dll
421     //
422     if (g_hinstImageHlp == NULL) {
423         g_hinstImageHlp = LoadImageHlp();
424     }
425     LOCAL_ASSERT(g_hinstImageHlp);
426
427     if (NULL == g_hinstImageHlp)
428     {
429         g_fLoadedImageHlpFailed = TRUE;
430         return;
431     }
432
433     //
434     // Try to get the API entrypoints in imagehlp.dll
435     //
436     for (int i = 0; i < COUNT_OF(ailFuncList); i++)
437     {
438         *(ailFuncList[i].ppvfn) = GetProcAddress(
439                 g_hinstImageHlp, 
440                 ailFuncList[i].pszFnName);
441         LOCAL_ASSERT(*(ailFuncList[i].ppvfn));
442         
443         if (!*(ailFuncList[i].ppvfn))
444         {
445             g_fLoadedImageHlpFailed = TRUE;
446             return;
447         }
448     }
449
450     API_VERSION AppVersion = { 4, 0, API_VERSION_NUMBER, 0 };
451     LPAPI_VERSION papiver = _ImagehlpApiVersionEx(&AppVersion);
452
453     //
454     // We assume any version 4 or greater is OK.
455     //
456     LOCAL_ASSERT(papiver->Revision >= 4);
457     if (papiver->Revision < 4)
458     {
459         g_fLoadedImageHlpFailed = TRUE;
460         return;
461     }
462
463     g_fLoadedImageHlp = TRUE;
464     
465     //
466     // Initialize imagehlp.dll.  A NULL search path is supposed to resolve
467     // symbols but never works.  So pull in everything and put some additional
468     // hints that might help out a dev box.
469     //
470
471     _SymSetOptions(_SymGetOptions() | SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);
472 #ifndef _WIN64
473     _SymRegisterCallback(g_hProcess, SymCallback, 0);
474 #endif
475
476     CQuickBytes qbSearchPath;
477     LPSTR szSearchPath = FillSymbolSearchPath(qbSearchPath);
478     _SymInitialize(g_hProcess, szSearchPath, TRUE);
479
480     return;
481 }
482
483
484 /****************************************************************************
485 * FillSymbolInfo *
486 *----------------*
487 *   Description:  
488 *       Fills in a SYM_INFO structure
489 ****************************************************************************/
490 void FillSymbolInfo
491 (
492 SYM_INFO *psi,
493 DWORD_PTR dwAddr
494 )
495 {
496     STATIC_CONTRACT_NOTHROW;
497     STATIC_CONTRACT_GC_NOTRIGGER;
498     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
499     
500     if (!g_fLoadedImageHlp)
501     {
502         return;
503     }
504
505     LOCAL_ASSERT(psi);
506     memset(psi, 0, sizeof(SYM_INFO));
507
508     PLAT_IMAGEHLP_MODULE  mi;
509     mi.SizeOfStruct = sizeof(mi);
510     
511     if (!_SymGetModuleInfo(g_hProcess, dwAddr, &mi))
512     {
513         strcpy_s(psi->achModule, _countof(psi->achModule), "<no module>");
514     }
515     else
516     {
517         strcpy_s(psi->achModule, _countof(psi->achModule), mi.ModuleName);
518         _strupr_s(psi->achModule, _countof(psi->achModule));
519     }
520
521     CHAR rgchUndec[256];
522     const CHAR * pszSymbol = NULL;
523
524     // Name field of IMAGEHLP_SYMBOL is dynamically sized.
525     // Pad with space for 255 characters.
526     union
527     {
528         CHAR rgchSymbol[sizeof(PLAT_IMAGEHLP_SYMBOL) + 255];
529         PLAT_IMAGEHLP_SYMBOL  sym;
530     };
531
532     __try
533     {
534         sym.SizeOfStruct = sizeof(PLAT_IMAGEHLP_SYMBOL);
535         sym.Address = dwAddr;
536         sym.MaxNameLength = 255;
537
538         if (_SymGetSymFromAddr(g_hProcess, dwAddr, &psi->dwOffset, &sym))
539         {
540             pszSymbol = sym.Name;
541
542             if (_SymUnDName(&sym, rgchUndec, COUNT_OF(rgchUndec)-1))
543             {
544                 pszSymbol = rgchUndec;
545             }
546         }
547         else
548         {
549             pszSymbol = "<no symbol>";
550         }
551     }
552     __except (EXCEPTION_EXECUTE_HANDLER)
553     {
554         pszSymbol = "<EX: no symbol>";
555         psi->dwOffset = dwAddr - mi.BaseOfImage;
556     }
557
558     strcpy_s(psi->achSymbol, _countof(psi->achSymbol), pszSymbol);
559 }
560
561 /****************************************************************************
562 * FunctionTableAccess *
563 *---------------------*
564 *   Description:  
565 *       Helper for imagehlp's StackWalk API.
566 ****************************************************************************/
567 LPVOID __stdcall FunctionTableAccess
568 (
569 HANDLE hProcess,
570 DWORD_PTR dwPCAddr
571 )
572 {
573     WRAPPER_NO_CONTRACT;
574     
575     HANDLE hFuncEntry = _SymFunctionTableAccess( hProcess, dwPCAddr );
576
577 #if defined(_WIN64)
578     if (hFuncEntry == NULL)
579     {
580         if (_GetRuntimeStackWalkInfo == NULL)
581         {
582             _GetRuntimeStackWalkInfo = (pfn_GetRuntimeStackWalkInfo)
583                                        GetProcAddress(GetCLRModuleHack(), "GetRuntimeStackWalkInfo");
584             if (_GetRuntimeStackWalkInfo == NULL)
585                 return NULL;
586         }
587
588         _GetRuntimeStackWalkInfo((ULONG64)dwPCAddr, NULL, (UINT_PTR*)(&hFuncEntry));
589     }
590 #endif // _WIN64
591
592     return hFuncEntry;
593 }
594
595 /****************************************************************************
596 * GetModuleBase *
597 *---------------*
598 *   Description:  
599 *       Helper for imagehlp's StackWalk API. Retrieves the base address of 
600 *       the module containing the giving virtual address.
601 *
602 *       NOTE: If the module information for the given module hasnot yet been
603 *       loaded, then it is loaded on this call.
604 *
605 *   Return:
606 *       Base virtual address where the module containing ReturnAddress is
607 *       loaded, or 0 if the address cannot be determined.
608 ****************************************************************************/
609 DWORD_PTR __stdcall GetModuleBase
610 (
611 HANDLE hProcess,
612 DWORD_PTR dwAddr
613 )
614 {
615     STATIC_CONTRACT_NOTHROW;
616     STATIC_CONTRACT_GC_NOTRIGGER;
617     
618     PLAT_IMAGEHLP_MODULE ModuleInfo;
619     ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
620     
621     if (_SymGetModuleInfo(hProcess, dwAddr, &ModuleInfo))
622     {
623         return ModuleInfo.BaseOfImage;       
624     }
625     else
626     {
627         MEMORY_BASIC_INFORMATION mbi;
628         
629         if (VirtualQueryEx(hProcess, (LPVOID)dwAddr, &mbi, sizeof(mbi)))
630         {
631             if (mbi.Type & MEM_IMAGE)
632             {
633                 char achFile[MAX_LONGPATH] = {0};
634                 DWORD cch;
635                 
636                 cch = GetModuleFileNameA(
637                         (HINSTANCE)mbi.AllocationBase,
638                         achFile,
639                         MAX_LONGPATH);
640
641                 // Ignore the return code since we can't do anything with it.
642                 _SymLoadModule(
643                     hProcess,
644                     NULL,
645                     ((cch) ? achFile : NULL),
646                     NULL,
647                     (DWORD_PTR)mbi.AllocationBase,
648                     0);
649
650                 return (DWORD_PTR)mbi.AllocationBase;
651             }
652         }
653     }
654
655 #if defined(_WIN64)
656     if (_GetRuntimeStackWalkInfo == NULL)
657     {
658         _GetRuntimeStackWalkInfo = (pfn_GetRuntimeStackWalkInfo)
659                                    GetProcAddress(GetCLRModuleHack(), "GetRuntimeStackWalkInfo");
660         if (_GetRuntimeStackWalkInfo == NULL)
661             return NULL;
662     }
663
664     DWORD_PTR moduleBase;
665     _GetRuntimeStackWalkInfo((ULONG64)dwAddr, (UINT_PTR*)&moduleBase, NULL);
666     if (moduleBase != NULL)
667         return moduleBase;
668 #endif // _WIN64
669
670     return 0;
671 }
672
673 #if !defined(DACCESS_COMPILE)
674 /****************************************************************************
675 * GetStackBacktrace *
676 *-------------------*
677 *   Description:  
678 *       Gets a stacktrace of the current stack, including symbols.
679 *
680 *   Return:
681 *       The number of elements actually retrieved.
682 ****************************************************************************/
683
684 UINT GetStackBacktrace
685 (
686 UINT ifrStart,          // How many stack elements to skip before starting. 
687 UINT cfrTotal,          // How many elements to trace after starting.
688 DWORD_PTR* pdwEip,      // Array to be filled with stack addresses.
689 SYM_INFO* psiSymbols,   // This array is filled with symbol information.
690                         // It should be big enough to hold cfrTotal elts.
691                         // If NULL, no symbol information is stored.
692 CONTEXT * pContext      // Context to use (or NULL to use current)
693 )
694 {
695     STATIC_CONTRACT_NOTHROW;
696     STATIC_CONTRACT_GC_NOTRIGGER;
697     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
698     
699     UINT        nElements   = 0;
700     DWORD_PTR*  pdw         = pdwEip;
701     SYM_INFO*   psi         = psiSymbols;
702
703     MagicInit();
704
705     memset(pdwEip, 0, cfrTotal*sizeof(DWORD_PTR));
706
707     if (psiSymbols)
708     {
709         memset(psiSymbols, 0, cfrTotal * sizeof(SYM_INFO));
710     }
711
712     if (!g_fLoadedImageHlp)
713     {
714         return 0;
715     }
716
717     CONTEXT context;
718     if (pContext == NULL)
719     {
720         ClrCaptureContext(&context);
721     }
722     else
723     {   
724         memcpy(&context, pContext, sizeof(CONTEXT));
725     }
726
727 #ifdef _WIN64
728     STACKFRAME64 stkfrm;
729     memset(&stkfrm, 0, sizeof(STACKFRAME64));
730 #else
731     STACKFRAME stkfrm;
732     memset(&stkfrm, 0, sizeof(STACKFRAME));
733 #endif
734
735     stkfrm.AddrPC.Mode      = AddrModeFlat;
736     stkfrm.AddrStack.Mode   = AddrModeFlat;
737     stkfrm.AddrFrame.Mode   = AddrModeFlat;
738 #if defined(_M_IX86)
739     stkfrm.AddrPC.Offset    = context.Eip;
740     stkfrm.AddrStack.Offset = context.Esp;
741     stkfrm.AddrFrame.Offset = context.Ebp;  // Frame Pointer
742 #endif
743
744 #ifndef _TARGET_X86_
745     // If we don't have a user-supplied context, then don't skip any frames.
746     // So ignore this function (GetStackBackTrace)
747     // ClrCaptureContext on x86 gives us the ESP/EBP/EIP of its caller's caller
748     // so we don't need to do this.
749     if (pContext == NULL)
750     {
751         ifrStart += 1;        
752     }
753 #endif // !_TARGET_X86_
754
755     for (UINT i = 0; i < ifrStart + cfrTotal; i++)
756     {
757         if (!_StackWalk(IMAGE_FILE_MACHINE_NATIVE,
758                         g_hProcess,
759                         GetCurrentThread(),
760                         &stkfrm,
761                         &context,
762                         NULL,
763                         (PFUNCTION_TABLE_ACCESS_ROUTINE)FunctionTableAccess,
764                         (PGET_MODULE_BASE_ROUTINE)GetModuleBase,
765                         NULL))
766         {
767             break;
768         }
769
770         if (i >= ifrStart)
771         {
772             *pdw++ = stkfrm.AddrPC.Offset;
773             nElements++;
774
775             if (psi)
776             {
777                 FillSymbolInfo(psi++, stkfrm.AddrPC.Offset);
778             }   
779         }
780     }
781
782     LOCAL_ASSERT(nElements == (UINT)(pdw - pdwEip));
783     return nElements;
784 }
785 #endif // !defined(DACCESS_COMPILE)
786
787 /****************************************************************************
788 * GetStringFromSymbolInfo *
789 *-------------------------*
790 *   Description:  
791 *       Actually prints the info into the string for the symbol.
792 ****************************************************************************/
793
794 #ifdef _WIN64
795     #define FMT_ADDR_BARE      "%08x`%08x"
796 #else
797     #define FMT_ADDR_BARE      "%08x"
798 #endif
799
800 void GetStringFromSymbolInfo
801 (
802 DWORD_PTR dwAddr,
803 SYM_INFO *psi,   // @parm Pointer to SYMBOL_INFO. Can be NULL.
804 __out_ecount (cchMaxAssertStackLevelStringLen) CHAR *pszString     // @parm Place to put string.
805 )
806 {
807     STATIC_CONTRACT_NOTHROW;
808     STATIC_CONTRACT_GC_NOTRIGGER;
809     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
810     
811     LOCAL_ASSERT(pszString);
812
813     // <module>! <symbol> + 0x<offset> 0x<addr>\n
814
815     if (psi)
816     {
817         sprintf_s(pszString,
818                   cchMaxAssertStackLevelStringLen,
819                   "%s! %s + 0x%X (0x" FMT_ADDR_BARE ")",
820                   (psi->achModule[0]) ? psi->achModule : "<no module>",
821                   (psi->achSymbol[0]) ? psi->achSymbol : "<no symbol>",
822                   psi->dwOffset,
823                   DBG_ADDR(dwAddr));
824     }
825     else
826     {
827
828         sprintf_s(pszString, cchMaxAssertStackLevelStringLen, "<symbols not available> (0x%p)", (void *)dwAddr);
829     }
830
831     LOCAL_ASSERT(strlen(pszString) < cchMaxAssertStackLevelStringLen);
832 }
833
834 #if !defined(DACCESS_COMPILE)
835
836 /****************************************************************************
837 * GetStringFromStackLevels *
838 *--------------------------*
839 *   Description:  
840 *       Retrieves a string from the stack frame. If more than one frame, they
841 *       are separated by newlines
842 ****************************************************************************/
843 void GetStringFromStackLevels
844 (
845 UINT ifrStart,      // @parm How many stack elements to skip before starting.
846 UINT cfrTotal,      // @parm How many elements to trace after starting.
847                     //  Can't be more than cfrMaxAssertStackLevels.
848 __out_ecount(cchMaxAssertStackLevelStringLen * cfrTotal) CHAR *pszString,    // @parm Place to put string.
849                     //  Max size will be cchMaxAssertStackLevelStringLen * cfrTotal.
850 CONTEXT * pContext  // @parm Context to start the stack trace at; null for current context.
851 )
852 {
853     STATIC_CONTRACT_NOTHROW;
854     STATIC_CONTRACT_GC_NOTRIGGER;
855     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
856     
857     LOCAL_ASSERT(pszString);
858     LOCAL_ASSERT(cfrTotal < cfrMaxAssertStackLevels);
859
860     *pszString = '\0';
861
862     if (cfrTotal == 0)
863     {
864         return;
865     }
866
867     DWORD_PTR rgdwStackAddrs[cfrMaxAssertStackLevels];
868     SYM_INFO rgsi[cfrMaxAssertStackLevels];
869
870     // Ignore this function (GetStringFromStackLevels) if we don't have a user-supplied context.
871     if (pContext == NULL)
872     {
873         ifrStart += 1;
874     }
875
876     UINT uiRetrieved =
877             GetStackBacktrace(ifrStart, cfrTotal, rgdwStackAddrs, rgsi, pContext);
878
879     // First level
880     CHAR aszLevel[cchMaxAssertStackLevelStringLen];
881     GetStringFromSymbolInfo(rgdwStackAddrs[0], &rgsi[0], aszLevel);
882
883     size_t bufSize = cchMaxAssertStackLevelStringLen * cfrTotal;
884
885     strcpy_s(pszString, bufSize, aszLevel);
886
887     // Additional levels
888     for (UINT i = 1; i < uiRetrieved; ++i)
889     {
890         strcat_s(pszString, bufSize, "\n");
891         GetStringFromSymbolInfo(rgdwStackAddrs[i],
892                         &rgsi[i], aszLevel);
893         strcat_s(pszString, bufSize, aszLevel);
894     }
895
896     LOCAL_ASSERT(strlen(pszString) <= cchMaxAssertStackLevelStringLen * cfrTotal);
897 }
898 #endif // !defined(DACCESS_COMPILE)
899
900 /****************************************************************************
901 * GetStringFromAddr *
902 *-------------------*
903 *   Description:  
904 *       Returns a string from an address.
905 ****************************************************************************/
906 void GetStringFromAddr
907 (
908 DWORD_PTR dwAddr,
909 __out_ecount(cchMaxAssertStackLevelStringLen) LPSTR szString // Place to put string.
910                 // Buffer must hold at least cchMaxAssertStackLevelStringLen.
911 )
912 {
913     STATIC_CONTRACT_NOTHROW;
914     STATIC_CONTRACT_GC_NOTRIGGER;
915     
916     LOCAL_ASSERT(szString);
917
918     SYM_INFO si;
919     FillSymbolInfo(&si, dwAddr);
920
921     sprintf_s(szString,
922               cchMaxAssertStackLevelStringLen,
923               "%s! %s + 0x%p (0x%p)",
924               (si.achModule[0]) ? si.achModule : "<no module>",
925               (si.achSymbol[0]) ? si.achSymbol : "<no symbol>",
926               (void*)si.dwOffset,
927               (void*)dwAddr);
928 }
929
930 /****************************************************************************
931 * MagicDeinit *
932 *-------------*
933 *   Description:  
934 *       Cleans up for the symbol loading code. Should be called before exit
935 *       to free the dynamically loaded imagehlp.dll.
936 ****************************************************************************/
937 void MagicDeinit(void)
938 {
939     STATIC_CONTRACT_NOTHROW;
940     STATIC_CONTRACT_GC_NOTRIGGER;
941     
942     if (g_hinstImageHlp)
943     {
944         FreeLibrary(g_hinstImageHlp);
945
946         g_hinstImageHlp   = NULL;
947         g_fLoadedImageHlp = FALSE;
948     }
949 }
950
951 #if defined(_TARGET_X86_)
952 /****************************************************************************
953 * ClrCaptureContext *
954 *-------------------*
955 *   Description:  
956 *       Exactly the contents of RtlCaptureContext for Win7 - Win2K doesn't
957 *       support this, so we need it for CoreCLR 4, if we require Win2K support
958 ****************************************************************************/
959 extern "C" __declspec(naked) void __stdcall
960 ClrCaptureContext(__out PCONTEXT ctx)
961 {
962     __asm {
963         push ebx;
964         mov  ebx,dword ptr [esp+8]
965         mov  dword ptr [ebx+0B0h],eax
966         mov  dword ptr [ebx+0ACh],ecx
967         mov  dword ptr [ebx+0A8h],edx
968         mov  eax,dword ptr [esp]
969         mov  dword ptr [ebx+0A4h],eax
970         mov  dword ptr [ebx+0A0h],esi
971         mov  dword ptr [ebx+09Ch],edi
972         mov  word ptr [ebx+0BCh],cs
973         mov  word ptr [ebx+098h],ds
974         mov  word ptr [ebx+094h],es
975         mov  word ptr [ebx+090h],fs
976         mov  word ptr [ebx+08Ch],gs
977         mov  word ptr [ebx+0C8h],ss
978         pushfd
979         pop  dword ptr [ebx+0C0h]
980         mov  eax,dword ptr [ebp+4]
981         mov  dword ptr [ebx+0B8h],eax
982         mov  eax,dword ptr [ebp]
983         mov  dword ptr [ebx+0B4h],eax
984         lea  eax,[ebp+8]
985         mov  dword ptr [ebx+0C4h],eax
986         mov  dword ptr [ebx],10007h
987         pop  ebx
988         ret  4
989     }
990 }
991 #endif // _TARGET_X86