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 //-----------------------------------------------------------------------------
6 //-----------------------------------------------------------------------------
10 #include "stacktrace.h"
14 #include "pedecoder.h" // for IMAGE_FILE_MACHINE_NATIVE
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()
20 static HMODULE s_hModCLR = 0;
23 s_hModCLR = GetModuleHandleA(MAIN_CLR_DLL_NAME_A);
28 HINSTANCE LoadImageHlp()
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.
35 return LoadLibraryExA("imagehlp.dll", NULL, 0);
38 HINSTANCE LoadDbgHelp()
40 STATIC_CONTRACT_NOTHROW;
41 STATIC_CONTRACT_GC_NOTRIGGER;
42 SCAN_IGNORE_FAULT; // Faults from Wsz funcs are handled.
44 return LoadLibraryExA("dbghelp.dll", NULL, 0);
47 /****************************************************************************
49 *---------------------*
51 * Callback for imghelp.
52 ****************************************************************************/
53 BOOL __stdcall SymCallback
66 OutputDebugStringA("IMGHLP: ");
67 OutputDebugStringA((LPCSTR) CallbackData);
68 OutputDebugStringA("\n");
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");
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");
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");
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");
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.
102 #define LOCAL_ASSERT(x)
104 //--- Macros ------------------------------------------------------------------
107 #define COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
110 // Types and Constants --------------------------------------------------------
116 char achModule[cchMaxAssertModuleLen];
117 char achSymbol[cchMaxAssertSymbolLen];
120 //--- Function Pointers to APIs in IMAGEHLP.DLL. Loaded dynamically. ---------
122 typedef LPAPI_VERSION (__stdcall *pfnImgHlp_ImagehlpApiVersionEx)(
123 LPAPI_VERSION AppVersion
126 typedef BOOL (__stdcall *pfnImgHlp_StackWalk)(
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
139 typedef DWORD64 (__stdcall *pfnImgHlp_SymGetModuleBase64)(
144 typedef IMAGEHLP_SYMBOL64 PLAT_IMAGEHLP_SYMBOL;
145 typedef IMAGEHLP_MODULE64 PLAT_IMAGEHLP_MODULE;
148 typedef IMAGEHLP_SYMBOL PLAT_IMAGEHLP_SYMBOL;
149 typedef IMAGEHLP_MODULE PLAT_IMAGEHLP_MODULE;
152 #undef IMAGEHLP_SYMBOL
153 #undef IMAGEHLP_MODULE
156 typedef BOOL (__stdcall *pfnImgHlp_SymGetModuleInfo)(
159 OUT PLAT_IMAGEHLP_MODULE* ModuleInfo
162 typedef LPVOID (__stdcall *pfnImgHlp_SymFunctionTableAccess)(
167 typedef BOOL (__stdcall *pfnImgHlp_SymGetSymFromAddr)(
170 OUT DWORD_PTR* pdwDisplacement,
171 OUT PLAT_IMAGEHLP_SYMBOL* Symbol
174 typedef BOOL (__stdcall *pfnImgHlp_SymInitialize)(
176 IN LPSTR UserSearchPath,
177 IN BOOL fInvadeProcess
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
186 typedef BOOL (__stdcall *pfnImgHlp_SymLoadModule)(
191 IN DWORD_PTR BaseOfDll,
195 typedef BOOL (_stdcall *pfnImgHlp_SymRegisterCallback)(
197 IN PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
201 typedef DWORD (_stdcall *pfnImgHlp_SymSetOptions)(
205 typedef DWORD (_stdcall *pfnImgHlp_SymGetOptions)(
217 typedef void (*pfn_GetRuntimeStackWalkInfo)(
218 IN ULONG64 ControlPc,
219 OUT UINT_PTR* pModuleBase,
220 OUT UINT_PTR* pFuncEntry
226 // Globals --------------------------------------------------------------------
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;
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;
247 pfn_GetRuntimeStackWalkInfo _GetRuntimeStackWalkInfo;
250 IMGHLPFN_LOAD ailFuncList[] =
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 },
266 /****************************************************************************
267 * FillSymbolSearchPath *
268 *----------------------*
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)
279 STATIC_CONTRACT_GC_NOTRIGGER;
280 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
281 SCAN_IGNORE_FAULT; // Faults from Wsz funcs are handled.
283 #ifndef DACCESS_COMPILE
284 // not allowed to do allocation if current thread suspends EE.
285 if (IsSuspendEEThread ())
289 InlineSString<MAX_SYM_PATH> rcBuff ; // Working buffer
290 int chTotal = 0; // How full is working buffer.
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(';'));
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))
306 if (sympathLength < MAX_SYM_PATH)
308 rcBuff.Append(DEFAULT_SYM_PATH);
309 chTotal = rcBuff.GetCount();
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))
319 size_t chNewTotal = chTotal + ch;
320 if (chNewTotal < (size_t)chTotal || chNewTotal < (size_t)ch)
321 { // integer overflow occurred
325 rcBuff.Append(W(';'));
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.
334 ch = WszGetModuleFileName(GetCLRModuleHack(), rcBuffTemp);
337 size_t pathLocationLength = chTotal + ch + 1;
338 // integer overflow occurred
339 if (pathLocationLength < (size_t)chTotal || pathLocationLength < (size_t)ch)
344 if (ch != 0 && (pathLocationLength < MAX_SYM_PATH))
346 chTotal = chTotal + ch - NumItems(STR_ENGINE_NAME);
347 rcBuff.Append(W(';'));
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);
358 WszWideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, rcBuff, -1, szRtn, ch+1, 0, 0);
361 LPSTR FillSymbolSearchPath(CQuickBytes &qb)
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.
372 retval = FillSymbolSearchPathThrows(qb);
374 EX_CATCH_HRESULT(hr);
385 /****************************************************************************
389 * Initializes the symbol loading code. Currently called (if necessary)
390 * at the beginning of each method that might need ImageHelp to be
392 ****************************************************************************/
395 STATIC_CONTRACT_NOTHROW;
396 STATIC_CONTRACT_GC_NOTRIGGER;
397 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
399 if (g_fLoadedImageHlp || g_fLoadedImageHlpFailed)
404 g_hProcess = GetCurrentProcess();
406 if (g_hinstDbgHelp == NULL)
408 g_hinstDbgHelp = LoadDbgHelp();
410 if (NULL == g_hinstDbgHelp)
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;
420 // Try to load imagehlp.dll
422 if (g_hinstImageHlp == NULL) {
423 g_hinstImageHlp = LoadImageHlp();
425 LOCAL_ASSERT(g_hinstImageHlp);
427 if (NULL == g_hinstImageHlp)
429 g_fLoadedImageHlpFailed = TRUE;
434 // Try to get the API entrypoints in imagehlp.dll
436 for (int i = 0; i < COUNT_OF(ailFuncList); i++)
438 *(ailFuncList[i].ppvfn) = GetProcAddress(
440 ailFuncList[i].pszFnName);
441 LOCAL_ASSERT(*(ailFuncList[i].ppvfn));
443 if (!*(ailFuncList[i].ppvfn))
445 g_fLoadedImageHlpFailed = TRUE;
450 API_VERSION AppVersion = { 4, 0, API_VERSION_NUMBER, 0 };
451 LPAPI_VERSION papiver = _ImagehlpApiVersionEx(&AppVersion);
454 // We assume any version 4 or greater is OK.
456 LOCAL_ASSERT(papiver->Revision >= 4);
457 if (papiver->Revision < 4)
459 g_fLoadedImageHlpFailed = TRUE;
463 g_fLoadedImageHlp = TRUE;
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.
471 _SymSetOptions(_SymGetOptions() | SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);
473 _SymRegisterCallback(g_hProcess, SymCallback, 0);
476 CQuickBytes qbSearchPath;
477 LPSTR szSearchPath = FillSymbolSearchPath(qbSearchPath);
478 _SymInitialize(g_hProcess, szSearchPath, TRUE);
484 /****************************************************************************
488 * Fills in a SYM_INFO structure
489 ****************************************************************************/
496 STATIC_CONTRACT_NOTHROW;
497 STATIC_CONTRACT_GC_NOTRIGGER;
498 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
500 if (!g_fLoadedImageHlp)
506 memset(psi, 0, sizeof(SYM_INFO));
508 PLAT_IMAGEHLP_MODULE mi;
509 mi.SizeOfStruct = sizeof(mi);
511 if (!_SymGetModuleInfo(g_hProcess, dwAddr, &mi))
513 strcpy_s(psi->achModule, _countof(psi->achModule), "<no module>");
517 strcpy_s(psi->achModule, _countof(psi->achModule), mi.ModuleName);
518 _strupr_s(psi->achModule, _countof(psi->achModule));
522 const CHAR * pszSymbol = NULL;
524 // Name field of IMAGEHLP_SYMBOL is dynamically sized.
525 // Pad with space for 255 characters.
528 CHAR rgchSymbol[sizeof(PLAT_IMAGEHLP_SYMBOL) + 255];
529 PLAT_IMAGEHLP_SYMBOL sym;
534 sym.SizeOfStruct = sizeof(PLAT_IMAGEHLP_SYMBOL);
535 sym.Address = dwAddr;
536 sym.MaxNameLength = 255;
538 if (_SymGetSymFromAddr(g_hProcess, dwAddr, &psi->dwOffset, &sym))
540 pszSymbol = sym.Name;
542 if (_SymUnDName(&sym, rgchUndec, COUNT_OF(rgchUndec)-1))
544 pszSymbol = rgchUndec;
549 pszSymbol = "<no symbol>";
552 __except (EXCEPTION_EXECUTE_HANDLER)
554 pszSymbol = "<EX: no symbol>";
555 psi->dwOffset = dwAddr - mi.BaseOfImage;
558 strcpy_s(psi->achSymbol, _countof(psi->achSymbol), pszSymbol);
561 /****************************************************************************
562 * FunctionTableAccess *
563 *---------------------*
565 * Helper for imagehlp's StackWalk API.
566 ****************************************************************************/
567 LPVOID __stdcall FunctionTableAccess
575 HANDLE hFuncEntry = _SymFunctionTableAccess( hProcess, dwPCAddr );
578 if (hFuncEntry == NULL)
580 if (_GetRuntimeStackWalkInfo == NULL)
582 _GetRuntimeStackWalkInfo = (pfn_GetRuntimeStackWalkInfo)
583 GetProcAddress(GetCLRModuleHack(), "GetRuntimeStackWalkInfo");
584 if (_GetRuntimeStackWalkInfo == NULL)
588 _GetRuntimeStackWalkInfo((ULONG64)dwPCAddr, NULL, (UINT_PTR*)(&hFuncEntry));
595 /****************************************************************************
599 * Helper for imagehlp's StackWalk API. Retrieves the base address of
600 * the module containing the giving virtual address.
602 * NOTE: If the module information for the given module hasnot yet been
603 * loaded, then it is loaded on this call.
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
615 STATIC_CONTRACT_NOTHROW;
616 STATIC_CONTRACT_GC_NOTRIGGER;
618 PLAT_IMAGEHLP_MODULE ModuleInfo;
619 ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
621 if (_SymGetModuleInfo(hProcess, dwAddr, &ModuleInfo))
623 return ModuleInfo.BaseOfImage;
627 MEMORY_BASIC_INFORMATION mbi;
629 if (VirtualQueryEx(hProcess, (LPVOID)dwAddr, &mbi, sizeof(mbi)))
631 if (mbi.Type & MEM_IMAGE)
633 char achFile[MAX_LONGPATH] = {0};
636 cch = GetModuleFileNameA(
637 (HINSTANCE)mbi.AllocationBase,
641 // Ignore the return code since we can't do anything with it.
645 ((cch) ? achFile : NULL),
647 (DWORD_PTR)mbi.AllocationBase,
650 return (DWORD_PTR)mbi.AllocationBase;
656 if (_GetRuntimeStackWalkInfo == NULL)
658 _GetRuntimeStackWalkInfo = (pfn_GetRuntimeStackWalkInfo)
659 GetProcAddress(GetCLRModuleHack(), "GetRuntimeStackWalkInfo");
660 if (_GetRuntimeStackWalkInfo == NULL)
664 DWORD_PTR moduleBase;
665 _GetRuntimeStackWalkInfo((ULONG64)dwAddr, (UINT_PTR*)&moduleBase, NULL);
666 if (moduleBase != NULL)
673 #if !defined(DACCESS_COMPILE)
674 /****************************************************************************
675 * GetStackBacktrace *
676 *-------------------*
678 * Gets a stacktrace of the current stack, including symbols.
681 * The number of elements actually retrieved.
682 ****************************************************************************/
684 UINT GetStackBacktrace
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)
695 STATIC_CONTRACT_NOTHROW;
696 STATIC_CONTRACT_GC_NOTRIGGER;
697 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
700 DWORD_PTR* pdw = pdwEip;
701 SYM_INFO* psi = psiSymbols;
705 memset(pdwEip, 0, cfrTotal*sizeof(DWORD_PTR));
709 memset(psiSymbols, 0, cfrTotal * sizeof(SYM_INFO));
712 if (!g_fLoadedImageHlp)
718 if (pContext == NULL)
720 ClrCaptureContext(&context);
724 memcpy(&context, pContext, sizeof(CONTEXT));
729 memset(&stkfrm, 0, sizeof(STACKFRAME64));
732 memset(&stkfrm, 0, sizeof(STACKFRAME));
735 stkfrm.AddrPC.Mode = AddrModeFlat;
736 stkfrm.AddrStack.Mode = AddrModeFlat;
737 stkfrm.AddrFrame.Mode = AddrModeFlat;
739 stkfrm.AddrPC.Offset = context.Eip;
740 stkfrm.AddrStack.Offset = context.Esp;
741 stkfrm.AddrFrame.Offset = context.Ebp; // Frame Pointer
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)
753 #endif // !_TARGET_X86_
755 for (UINT i = 0; i < ifrStart + cfrTotal; i++)
757 if (!_StackWalk(IMAGE_FILE_MACHINE_NATIVE,
763 (PFUNCTION_TABLE_ACCESS_ROUTINE)FunctionTableAccess,
764 (PGET_MODULE_BASE_ROUTINE)GetModuleBase,
772 *pdw++ = stkfrm.AddrPC.Offset;
777 FillSymbolInfo(psi++, stkfrm.AddrPC.Offset);
782 LOCAL_ASSERT(nElements == (UINT)(pdw - pdwEip));
785 #endif // !defined(DACCESS_COMPILE)
787 /****************************************************************************
788 * GetStringFromSymbolInfo *
789 *-------------------------*
791 * Actually prints the info into the string for the symbol.
792 ****************************************************************************/
795 #define FMT_ADDR_BARE "%08x`%08x"
797 #define FMT_ADDR_BARE "%08x"
800 void GetStringFromSymbolInfo
803 SYM_INFO *psi, // @parm Pointer to SYMBOL_INFO. Can be NULL.
804 __out_ecount (cchMaxAssertStackLevelStringLen) CHAR *pszString // @parm Place to put string.
807 STATIC_CONTRACT_NOTHROW;
808 STATIC_CONTRACT_GC_NOTRIGGER;
809 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
811 LOCAL_ASSERT(pszString);
813 // <module>! <symbol> + 0x<offset> 0x<addr>\n
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>",
828 sprintf_s(pszString, cchMaxAssertStackLevelStringLen, "<symbols not available> (0x%p)", (void *)dwAddr);
831 LOCAL_ASSERT(strlen(pszString) < cchMaxAssertStackLevelStringLen);
834 #if !defined(DACCESS_COMPILE)
836 /****************************************************************************
837 * GetStringFromStackLevels *
838 *--------------------------*
840 * Retrieves a string from the stack frame. If more than one frame, they
841 * are separated by newlines
842 ****************************************************************************/
843 void GetStringFromStackLevels
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.
853 STATIC_CONTRACT_NOTHROW;
854 STATIC_CONTRACT_GC_NOTRIGGER;
855 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
857 LOCAL_ASSERT(pszString);
858 LOCAL_ASSERT(cfrTotal < cfrMaxAssertStackLevels);
867 DWORD_PTR rgdwStackAddrs[cfrMaxAssertStackLevels];
868 SYM_INFO rgsi[cfrMaxAssertStackLevels];
870 // Ignore this function (GetStringFromStackLevels) if we don't have a user-supplied context.
871 if (pContext == NULL)
877 GetStackBacktrace(ifrStart, cfrTotal, rgdwStackAddrs, rgsi, pContext);
880 CHAR aszLevel[cchMaxAssertStackLevelStringLen];
881 GetStringFromSymbolInfo(rgdwStackAddrs[0], &rgsi[0], aszLevel);
883 size_t bufSize = cchMaxAssertStackLevelStringLen * cfrTotal;
885 strcpy_s(pszString, bufSize, aszLevel);
888 for (UINT i = 1; i < uiRetrieved; ++i)
890 strcat_s(pszString, bufSize, "\n");
891 GetStringFromSymbolInfo(rgdwStackAddrs[i],
893 strcat_s(pszString, bufSize, aszLevel);
896 LOCAL_ASSERT(strlen(pszString) <= cchMaxAssertStackLevelStringLen * cfrTotal);
898 #endif // !defined(DACCESS_COMPILE)
900 /****************************************************************************
901 * GetStringFromAddr *
902 *-------------------*
904 * Returns a string from an address.
905 ****************************************************************************/
906 void GetStringFromAddr
909 __out_ecount(cchMaxAssertStackLevelStringLen) LPSTR szString // Place to put string.
910 // Buffer must hold at least cchMaxAssertStackLevelStringLen.
913 STATIC_CONTRACT_NOTHROW;
914 STATIC_CONTRACT_GC_NOTRIGGER;
916 LOCAL_ASSERT(szString);
919 FillSymbolInfo(&si, dwAddr);
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>",
930 /****************************************************************************
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)
939 STATIC_CONTRACT_NOTHROW;
940 STATIC_CONTRACT_GC_NOTRIGGER;
944 FreeLibrary(g_hinstImageHlp);
946 g_hinstImageHlp = NULL;
947 g_fLoadedImageHlp = FALSE;
951 #if defined(_TARGET_X86_)
952 /****************************************************************************
953 * ClrCaptureContext *
954 *-------------------*
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)
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
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
985 mov dword ptr [ebx+0C4h],eax
986 mov dword ptr [ebx],10007h
991 #endif // _TARGET_X86