diff options
Diffstat (limited to 'src/ToolBox/SOS/Strike/disasm.cpp')
-rw-r--r-- | src/ToolBox/SOS/Strike/disasm.cpp | 1123 |
1 files changed, 1123 insertions, 0 deletions
diff --git a/src/ToolBox/SOS/Strike/disasm.cpp b/src/ToolBox/SOS/Strike/disasm.cpp new file mode 100644 index 0000000000..b76a6c8ea7 --- /dev/null +++ b/src/ToolBox/SOS/Strike/disasm.cpp @@ -0,0 +1,1123 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// ==++== +// + +// +// ==--== + +#include "strike.h" +#include "util.h" +#include <dbghelp.h> +#include <limits.h> + +#include "sos_md.h" + +#ifdef SOS_TARGET_X86 +namespace X86GCDump +{ +#include "gcdump.h" +#undef assert +#define assert(a) +#define CONTRACTL +#define DAC_ARG(x) +#define CONTRACTL_END +#define LIMITED_METHOD_CONTRACT +#define NOTHROW +#define GC_NOTRIGGER +#define SUPPORTS_DAC +#define LIMITED_METHOD_DAC_CONTRACT +#include "gcdecoder.cpp" +#undef CONTRACTL +#undef CONTRACTL_END +#undef LIMITED_METHOD_CONTRACT +#undef NOTHROW +#undef GC_NOTRIGGER +#undef _ASSERTE +#define _ASSERTE(a) do {} while (0) + +#include "gcdump.cpp" +#include "i386/gcdumpx86.cpp" +} +#endif // SOS_TARGET_X86 + +#ifdef SOS_TARGET_AMD64 +#include "gcdump.h" +#define DAC_ARG(x) +#define SUPPORTS_DAC +#define LIMITED_METHOD_DAC_CONTRACT +#undef LIMITED_METHOD_CONTRACT +#undef PREGDISPLAY + #ifdef LOG + #undef LOG + #endif + #define LOG(x) ((void)0) +#include "gcdumpnonx86.cpp" +#endif // SOS_TARGET_AMD64 + +#include "disasm.h" + +#ifndef ERANGE +#define ERANGE 34 +#endif + +PVOID +GenOpenMapping( + PCSTR FilePath, + PULONG Size + ) +{ + HANDLE hFile; + HANDLE hMappedFile; + PVOID MappedFile; + + + hFile = CreateFileA( + FilePath, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); +#if 0 + if ( hFile == NULL || hFile == INVALID_HANDLE_VALUE ) { + + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + + // We're on an OS that doesn't support Unicode + // file operations. Convert to ANSI and see if + // that helps. + + CHAR FilePathA [ MAX_PATH + 10 ]; + + if (WideCharToMultiByte (CP_ACP, + 0, + FilePath, + -1, + FilePathA, + sizeof (FilePathA), + 0, + 0 + ) > 0) { + + hFile = CreateFileA(FilePathA, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + } + } + + if ( hFile == NULL || hFile == INVALID_HANDLE_VALUE ) { + return NULL; + } + } +#endif + + *Size = GetFileSize(hFile, NULL); + if (*Size == ULONG_MAX) { + CloseHandle( hFile ); + return FALSE; + } + + hMappedFile = CreateFileMapping ( + hFile, + NULL, + PAGE_READONLY, + 0, + 0, + NULL + ); + + if ( !hMappedFile ) { + CloseHandle ( hFile ); + return FALSE; + } + + MappedFile = MapViewOfFile ( + hMappedFile, + FILE_MAP_READ, + 0, + 0, + 0 + ); + + CloseHandle (hMappedFile); + CloseHandle (hFile); + + return MappedFile; +} + +char* PrintOneLine (__in_z char *begin, __in_z char *limit) +{ + if (begin == NULL || begin >= limit) { + return NULL; + } + char line[128]; + size_t length; + char *end; + while (1) { + if (IsInterrupt()) + return NULL; + length = strlen (begin); + end = strstr (begin, "\r\xa"); + if (end == NULL) { + ExtOut ("%s", begin); + end = begin+length+1; + if (end >= limit) { + return NULL; + } + } + else { + end += 2; + length = end-begin; + while (length) { + if (IsInterrupt()) + return NULL; + size_t n = length; + if (n > 127) { + n = 127; + } + strncpy_s (line,_countof(line), begin, n); + line[n] = '\0'; + ExtOut ("%s", line); + begin += n; + length -= n; + } + return end; + } + } +} + +void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines) +{ + char filename[MAX_PATH+1]; + char line[256]; + int lcount = 10; + + ULONG linenum = 0; + ULONG64 Displacement = 0; + BOOL fLineAvailable = FALSE; + ULONG64 vIP = 0; + + if (!bSuppressLines) + { + ReloadSymbolWithLineInfo(); + fLineAvailable = SUCCEEDED (g_ExtSymbols->GetLineByOffset (TO_CDADDR(IP), &linenum, + filename, + MAX_PATH+1, + NULL, + &Displacement)); + } + ULONG FileLines = 0; + ArrayHolder<ULONG64> Buffer = NULL; + + if (fLineAvailable) + { + g_ExtSymbols->GetSourceFileLineOffsets (filename, NULL, 0, &FileLines); + if (FileLines == 0xFFFFFFFF || FileLines == 0) + fLineAvailable = FALSE; + } + + if (fLineAvailable) + { + Buffer = new ULONG64[FileLines]; + if (Buffer == NULL) + fLineAvailable = FALSE; + } + + if (!fLineAvailable) + { + vIP = TO_CDADDR(IP); + // There is no line info. Just disasm the code. + while (lcount-- > 0) + { + if (IsInterrupt()) + return; + g_ExtControl->Disassemble (vIP, 0, line, 256, NULL, &vIP); + ExtOut (line); + } + return; + } + + g_ExtSymbols->GetSourceFileLineOffsets (filename, Buffer, FileLines, NULL); + + int beginLine = 0; + int endLine = 0; + int lastLine; + linenum --; + for (lastLine = linenum; lastLine >= 0; lastLine --) { + if (IsInterrupt()) + return; + if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) { + g_ExtSymbols->GetNameByOffset(Buffer[lastLine],NULL,0,NULL,&Displacement); + if (Displacement == 0) { + beginLine = lastLine; + break; + } + } + } + if (lastLine < 0) { + int n = lcount / 2; + lastLine = linenum-1; + beginLine = lastLine; + while (lastLine >= 0) { + if (IsInterrupt()) + return; + if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) { + beginLine = lastLine; + n --; + if (n == 0) { + break; + } + } + lastLine --; + } + } + while (beginLine > 0 && Buffer[beginLine-1] == DEBUG_INVALID_OFFSET) { + if (IsInterrupt()) + return; + beginLine --; + } + int endOfFunc = 0; + for (lastLine = linenum+1; (ULONG)lastLine < FileLines; lastLine ++) { + if (IsInterrupt()) + return; + if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) { + g_ExtSymbols->GetNameByOffset(Buffer[lastLine],NULL,0,NULL,&Displacement); + if (Displacement == 0) { + endLine = lastLine; + break; + } + endOfFunc = lastLine; + } + } + if ((ULONG)lastLine == FileLines) { + int n = lcount / 2; + lastLine = linenum+1; + endLine = lastLine; + while ((ULONG)lastLine < FileLines) { + if (IsInterrupt()) + return; + if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) { + endLine = lastLine; + n --; + if (n == 0) { + break; + } + } + lastLine ++; + } + } + + PVOID MappedBase = NULL; + ULONG MappedSize = 0; + + class ToUnmap + { + PVOID *m_Base; + public: + ToUnmap (PVOID *base) + :m_Base(base) + {} + ~ToUnmap () + { + if (*m_Base) { + UnmapViewOfFile (*m_Base); + *m_Base = NULL; + } + } + }; + ToUnmap toUnmap(&MappedBase); + +#define MAX_SOURCE_PATH 1024 + char Found[MAX_SOURCE_PATH]; + char *pFile; + if (g_ExtSymbols->FindSourceFile(0, filename, + DEBUG_FIND_SOURCE_BEST_MATCH | + DEBUG_FIND_SOURCE_FULL_PATH, + NULL, Found, sizeof(Found), NULL) != S_OK) + { + pFile = filename; + } + else + { + MappedBase = GenOpenMapping ( Found, &MappedSize ); + pFile = Found; + } + + lastLine = beginLine; + char *pFileCh = (char*)MappedBase; + if (MappedBase) { + ExtOut ("%s\n", pFile); + int n = beginLine; + while (n > 0) { + while (!(pFileCh[0] == '\r' && pFileCh[1] == 0xa)) { + if (IsInterrupt()) + return; + pFileCh ++; + } + pFileCh += 2; + n --; + } + } + + char filename1[MAX_PATH+1]; + for (lastLine = beginLine; lastLine < endLine; lastLine ++) { + if (IsInterrupt()) + return; + if (MappedBase) { + ExtOut ("%4d ", lastLine+1); + pFileCh = PrintOneLine (pFileCh, (char*)MappedBase+MappedSize); + } + if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) { + if (MappedBase == 0) { + ExtOut (">>> %s:%d\n", pFile, lastLine+1); + } + vIP = Buffer[lastLine]; + ULONG64 vNextLineIP; + int i; + for (i = lastLine + 1; (ULONG)i < FileLines && Buffer[i] == DEBUG_INVALID_OFFSET; i ++) { + if (IsInterrupt()) + return; + } + if ((ULONG)i == FileLines) { + vNextLineIP = 0; + } + else + vNextLineIP = Buffer[i]; + while (1) { + if (IsInterrupt()) + return; + g_ExtControl->Disassemble (vIP, 0, line, 256, NULL, &vIP); + ExtOut (line); + if (vIP > vNextLineIP || vNextLineIP - vIP > 40) { + if (FAILED (g_ExtSymbols->GetLineByOffset (vIP, &linenum, + filename1, + MAX_PATH+1, + NULL, + &Displacement))) { + if (lastLine != endOfFunc) { + break; + } + if (strstr (line, "ret") || strstr (line, "jmp")) { + break; + } + } + + if (linenum != (ULONG)lastLine+1 || strcmp (filename, filename1)) { + break; + } + } + else if (vIP == vNextLineIP) { + break; + } + } + } + } + +} + + +void DisasmAndClean (DWORD_PTR &IP, __out_ecount (length) __out_opt char *line, ULONG length) +{ + ULONG64 vIP = TO_CDADDR(IP); + g_ExtControl->Disassemble (vIP, 0, line, length, NULL, &vIP); + IP = (DWORD_PTR)vIP; + // remove the ending '\n' + char *ptr = strrchr (line, '\n'); + if (ptr != NULL) + ptr[0] = '\0'; + +} + +// If byref, move to pass the byref prefix +BOOL IsByRef (__deref_inout_z char *& ptr) +{ + BOOL bByRef = FALSE; + const char* qindirCh = "qword ptr ["; + const char* dindirCh = "dword ptr ["; + const char* qindirDsCh = "qword ptr ds:["; + const char* dindirDsCh = "dword ptr ds:["; + if (ptr[0] == '[') + { + bByRef = TRUE; + ptr ++; + } + else if (!IsDbgTargetArm() && !strncmp (ptr, IsDbgTargetWin64() ? qindirCh : dindirCh, 11)) + { + bByRef = TRUE; + ptr += 11; + } + // The new disassembly engine for windbg formats indirect calls + // slightly differently: + else if (!IsDbgTargetArm() && !strncmp (ptr, IsDbgTargetWin64() ? qindirDsCh : dindirDsCh, 14)) + { + bByRef = TRUE; + ptr += 14; + } + return bByRef; +} + +BOOL IsTermSep (char ch) +{ + return (ch == '\0' || isspace (ch) || ch == ',' || ch == '\n'); +} + +// Find next term. A term is seperated by space or , +void NextTerm (__deref_inout_z char *& ptr) +{ + // If we have a byref, skip to ']' + if (IsByRef (ptr)) + { + while (ptr[0] != ']' && ptr[0] != '\0') + { + if (IsInterrupt()) + return; + ptr ++; + } + if (ptr[0] == ']') + ptr ++; + } + + while (!IsTermSep (ptr[0])) + { + if (IsInterrupt()) + return; + ptr ++; + } + + while (IsTermSep(ptr[0]) && (*ptr != '\0')) + { + if (IsInterrupt()) + return; + ptr ++; + } +} + + +// Parses something like 6e24d310, 0x6e24d310, or 6e24d310h. +// On 64-bit, also parses things like 000006fb`f9b70f50 and +// 000006fbf9b70f50 (as well as their 0x-prefix, -h suffix variations). +INT_PTR ParseHexNumber (__in_z char *ptr, __out char **endptr) +{ + char *endptr1; + INT_PTR value1 = strtoul(ptr, &endptr1, 16); + +#ifdef _TARGET_WIN64_ + if ('`' == endptr1[0] && isxdigit(endptr1[1])) + { + char *endptr2; + INT_PTR value2 = strtoul(endptr1+1, &endptr2, 16); + + value1 = (value1 << 32) | value2; + endptr1 = endptr2; + } + // if the hex number was specified as 000006fbf9b70f50, an overflow occured + else if (ULONG_MAX == value1 && errno == ERANGE) + { + if (!strncmp(ptr, "0x", 2)) + ptr += 2; + + char savedigit = ptr[8]; + ptr[8] = '\0'; + + value1 = strtoul(ptr, &endptr1, 16); + + ptr[8] = savedigit; + + char *endptr2; + INT_PTR value2 = strtoul(ptr+8, &endptr2, 16); + + size_t ndigits2 = endptr2 - (ptr+8); + + value1 = (value1 << (ndigits2*4)) | value2; + endptr1 = endptr2; + } +#endif // _TARGET_WIN64_ + + // account for the possible 'h' suffix + if ((*endptr1 == 'h') || (*endptr1 == 'H')) + { + ++endptr1; + } + + *endptr = endptr1; + return value1; +} + + +// only handle pure value, or memory address +INT_PTR GetValueFromExpr(__in_z char *ptr, INT_PTR &value) +{ + BOOL bNegative = FALSE; + value = 0; + char *myPtr = ptr; + BOOL bByRef = IsByRef (myPtr); + + // ARM disassembly contains '#' prefixes for hex constants + if (*myPtr == '#') + ++myPtr; + + if (myPtr[0] == '-') + { + myPtr ++; + bNegative = TRUE; + } + if (!strncmp (myPtr, "0x", 2) || isxdigit (myPtr[0])) + { + char *endptr; + value = ParseHexNumber(myPtr, &endptr); + if (!bByRef && IsTermSep (endptr[0]) + || bByRef && endptr[0] == ']') + { + if (bNegative) + value = -value; + ptr = endptr; + if (bByRef) + { + ptr += 1; + SafeReadMemory (TO_TADDR(value), &value, 4, NULL); + } + return ptr - myPtr; + } + } + + // handle mscorlib+0xed310 (6e24d310) + if (!bByRef) + { + ptr = myPtr; + // handle 'offset ' before the expression: + if (strncmp(ptr, "offset ", 7) == 0) + { + ptr += 7; + } + while (ptr[0] != ' ' && ptr[0] != '+' && ptr[0] != '\0') + { + if (IsInterrupt()) + return 0; + ptr ++; + } + if (ptr[0] == '+') + { + NextTerm (ptr); + if (ptr[0] == '(') + { + ptr ++; + char *endptr; + value = ParseHexNumber(ptr, &endptr); + if (endptr[0] == ')') + { + ptr ++; + return ptr - myPtr; + } + } + } + } + if (bByRef) + { + // handle dword [mscorlib+0x2bd788 (02ead788)] + ptr = myPtr; + // handle 'offset ' before the expression: + if (strncmp(ptr, "offset ", 7) == 0) + { + ptr += 7; + } + while (ptr[0] != '(' && ptr[0] != '\0') + { + if (IsInterrupt()) + return 0; + ptr ++; + } + if (ptr[0] == '(') + { + ptr ++; + char *endptr; + value = ParseHexNumber(ptr, &endptr); + if (endptr[0] == ')' && endptr[1] == ']') + { + ptr = endptr + 2; + SafeReadMemory (TO_TADDR(value), &value, 4, NULL); + return ptr - myPtr; + } + } + } + +#ifdef _TARGET_WIN64_ + // handle CLRStub@7fffc8601cc (000007fffc8601cc) + if (!bByRef && !strncmp(myPtr, "CLRStub[", 8)) + { + ptr = myPtr; + while (ptr[0] != '(' && ptr[0] != '\0') + { + if (IsInterrupt()) + return 0; + ptr ++; + } + if (ptr[0] == '(') + { + ptr ++; + char *endptr; + value = ParseHexNumber(ptr, &endptr); + if (endptr[0] == ')') + { + ptr ++; + return ptr - myPtr; + } + } + } +#endif // _TARGET_WIN64_ + + return 0; +} + + +const char * HelperFuncName (size_t IP) +{ + static char s_szHelperName[100]; + if (S_OK == g_sos->GetJitHelperFunctionName(IP, sizeof(s_szHelperName), &s_szHelperName[0], NULL)) + return &s_szHelperName[0]; + else + return NULL; +} + + +// Returns: +// NULL if the EHInfo passed in does not refer to a Typed clause +// "..." if pEHInfo->isCatchAllHandler is TRUE +// "TypeName" if pEHInfo is a DACEHInfo*. +// Note: +// The return is a pointer to a global buffer, therefore this value must +// be consumed as soon as possible after a call to this function. +LPCWSTR EHTypedClauseTypeName(__in const DACEHInfo* pEHInfo) +{ + _ASSERTE(pEHInfo != NULL); + if ((pEHInfo->clauseType == EHTyped) && pEHInfo->isCatchAllHandler) + { + return L"..."; + } + + // is there a method table or a token to look at? + if (pEHInfo->clauseType == EHTyped) + { + TADDR mt; + if (pEHInfo->moduleAddr == 0) + { + mt = TO_TADDR(pEHInfo->mtCatch); + NameForMT_s(mt, g_mdName, mdNameLen); + } else { + PrettyPrintClassFromToken(TO_TADDR(pEHInfo->moduleAddr), pEHInfo->tokCatch, g_mdName, mdNameLen, FormatCSharp); + } + return g_mdName; + } + + return NULL; +} + +BOOL IsClonedFinally(DACEHInfo *pEHInfo) +{ + // This maybe should be determined in the VM and passed in the DACEHInfo struct. +#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) + return ((pEHInfo->tryStartOffset == pEHInfo->tryEndOffset) && + (pEHInfo->tryStartOffset == pEHInfo->handlerStartOffset) && + (pEHInfo->clauseType == EHFinally) && + pEHInfo->isDuplicateClause); +#else + return FALSE; +#endif +} + + +void SOSEHInfo::FormatForDisassembly(CLRDATA_ADDRESS offSet) +{ + LPCWSTR typeName = NULL; + // the order of printing and iterating will matter on the boundaries + + // Print END tags in forward order (most nested to least nested). However, cloned + // finally clauses are always at the end, but they should be considered most nested, + // so have a separate loop to output them first. + for (UINT i=0; i < EHCount; i++) + { + DACEHInfo *pCur = &m_pInfos[i]; + + if (IsClonedFinally(pCur) && + (offSet == pCur->handlerEndOffset)) + { + ExtOut ("EHHandler %d: CLONED FINALLY END\n", i); + } + } + + for (UINT i=0; i < EHCount; i++) + { + DACEHInfo *pCur = &m_pInfos[i]; + + if (pCur->isDuplicateClause) + { + // Don't print anything for duplicate clauses + continue; + } + + if (offSet == pCur->tryEndOffset) + { + ExtOut ("EHHandler %d: %s CLAUSE END\n", i, EHTypeName(pCur->clauseType)); + } + + if (offSet == pCur->handlerEndOffset) + { + ExtOut ("EHHandler %d: %s HANDLER END\n", i, EHTypeName(pCur->clauseType)); + } + } + + // Print BEGIN tags in reverse order (least nested to most nested). + for (UINT i=EHCount-1; i != (UINT)-1; --i) + { + DACEHInfo *pCur = &m_pInfos[i]; + + // Must do this before the isDuplicatedClause check, since these are marked as duplicated clauses. + if (IsClonedFinally(pCur) && + (offSet == pCur->handlerStartOffset)) + { + ExtOut ("EHHandler %d: CLONED FINALLY BEGIN\n", i); + } + + if (pCur->isDuplicateClause) + { + // Don't print anything for duplicate clauses + continue; + } + + if (offSet == pCur->tryStartOffset) + { + ExtOut ("EHHandler %d: %s CLAUSE BEGIN", i, EHTypeName(pCur->clauseType)); + typeName = EHTypedClauseTypeName(pCur); + if (typeName != NULL) + { + ExtOut(" catch(%S) ", typeName); + } + ExtOut ("\n"); + } + + if (offSet == pCur->handlerStartOffset) + { + ExtOut ("EHHandler %d: %s HANDLER BEGIN", i, EHTypeName(pCur->clauseType)); + typeName = EHTypedClauseTypeName(pCur); + if (typeName != NULL) + { + ExtOut(" catch(%S) ", typeName); + } + ExtOut ("\n"); + } + + if ((pCur->clauseType == EHFilter) && + (offSet == pCur->filterOffset)) + { + ExtOut ("EHHandler %d: %s FILTER BEGIN\n",i, EHTypeName(pCur->clauseType)); + } + } +} + + +// +// Implementation shared by X86, ARM, and X64 +// Any cross platform code should resolve through g_targetMachine or should +// use the IS_DBG_TARGET_XYZ macro. +// + + +// Return TRUE if we have printed something. +BOOL PrintCallInfo (DWORD_PTR vEBP, DWORD_PTR IP, + DumpStackFlag& DSFlag, + BOOL bSymbolOnly) +{ + char Symbol[1024]; + char filename[MAX_PATH+1]; + ULONG64 Displacement; + BOOL bOutput = FALSE; + + // degrade gracefully for debuggees that don't have a runtime loaded, or a DAC available + DWORD_PTR methodDesc = 0; + if (!g_bDacBroken) + { + methodDesc = FunctionType (IP); + } + + if (methodDesc > 1) + { + bOutput = TRUE; + if (!bSymbolOnly) + DMLOut("%p %s ", (ULONG64)vEBP, DMLIP(IP)); + DMLOut("(MethodDesc %s ", DMLMethodDesc(methodDesc)); + + // TODO: Microsoft, more checks to make sure method is not eeimpl, etc. Add this field to MethodDesc + + DacpCodeHeaderData codeHeaderData; + if (codeHeaderData.Request(g_sos, TO_CDADDR(IP)) == S_OK) + { + DWORD_PTR IPBegin = (DWORD_PTR) codeHeaderData.MethodStart; + methodDesc = (DWORD_PTR) codeHeaderData.MethodDescPtr; + Displacement = IP - IPBegin; + if (IP >= IPBegin && Displacement <= codeHeaderData.MethodSize) + ExtOut ("+%#x ", Displacement); + } + if (NameForMD_s(methodDesc, g_mdName, mdNameLen)) + { + ExtOut("%S)", g_mdName); + } + else + { + ExtOut("%s)", DMLIP(IP)); + } + } + else + { + if (!DSFlag.fEEonly) + { + bOutput = TRUE; + const char *name; + if (!bSymbolOnly) + DMLOut("%p %s ", (ULONG64)vEBP, DMLIP(IP)); + + // if AMD64 ever becomes a cross platform target this must be resolved through + // virtual dispatch rather than conditional compilation +#ifdef _TARGET_AMD64_ + // degrade gracefully for debuggees that don't have a runtime loaded, or a DAC available + eTargetType ett = ettUnk; + if (!g_bDacBroken) + { + DWORD_PTR finalMDorIP = 0; + ett = GetFinalTarget(IP, &finalMDorIP); + if (ett == ettNative || ett==ettJitHelp) + { + methodDesc = 0; + IP = finalMDorIP; + } + else + { + methodDesc = finalMDorIP; + } + } +#endif // _TARGET_AMD64_ + if (methodDesc == 0) { + HRESULT hr; + hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(IP), Symbol, 1024, NULL, &Displacement); + if (SUCCEEDED(hr) && Symbol[0] != '\0') + { + ExtOut ("%s", Symbol); + if (Displacement) + ExtOut ("+%#x", Displacement); + if (!DSFlag.fSuppressSrcInfo) + { + ULONG line; + hr = g_ExtSymbols->GetLineByOffset (TO_CDADDR(IP), &line, filename, + MAX_PATH+1, NULL, NULL); + if (SUCCEEDED (hr)) + ExtOut (" [%s:%d]", filename, line); + } + } + else + { + DMLOut(DMLIP(IP)); + } + } + else if (g_bDacBroken) + { + // degrade gracefully for debuggees that don't have a runtime loaded, or a DAC available + DMLOut(DMLIP(IP)); + } + else if (IsMethodDesc (IP)) + { + NameForMD_s(IP, g_mdName, mdNameLen); + ExtOut(" (stub for %S)", g_mdName); + } + else if (IsMethodDesc(IP+5)) { + NameForMD_s((DWORD_PTR)(IP+5), g_mdName, mdNameLen); + DMLOut("%s (MethodDesc %s %S)", DMLIP(IP), DMLMethodDesc(IP+5), g_mdName); + } + else if ((name = HelperFuncName(IP)) != NULL) { + ExtOut(" (JitHelp: %s)", name); + } +#ifdef _TARGET_AMD64_ + else if (ett == ettMD || ett == ettStub) + { + NameForMD_s(methodDesc, g_mdName,mdNameLen); + DMLOut("%s (stub for %S)", DMLIP(IP), g_mdName); + // fallthrough to return + } +#endif // _TARGET_AMD64_ + else + { + DMLOut(DMLIP(IP)); + } + } + } + return bOutput; +} + +void DumpStackWorker (DumpStackFlag &DSFlag) +{ + DWORD_PTR eip; + ULONG64 Offset; + g_ExtRegisters->GetInstructionOffset(&Offset); + eip = (DWORD_PTR)Offset; + + ExtOut("Current frame: "); + PrintCallInfo (0, eip, DSFlag, TRUE); + ExtOut ("\n"); + + // make certain dword/qword aligned + DWORD_PTR ptr = DSFlag.top & (~ALIGNCONST); + + ExtOut (g_targetMachine->GetDumpStackHeading()); + while (ptr < DSFlag.end) + { + if (IsInterrupt()) + return; + DWORD_PTR retAddr; + DWORD_PTR whereCalled; + move_xp(retAddr, ptr); + g_targetMachine->IsReturnAddress(retAddr, &whereCalled); + if (whereCalled) + { + BOOL bOutput = PrintCallInfo(ptr-sizeof(TADDR), retAddr, DSFlag, FALSE); + if (!DSFlag.fEEonly) + { + if (whereCalled != 0xFFFFFFFF) + { + ExtOut (", calling "); + PrintCallInfo (0, whereCalled, DSFlag, TRUE); + } + } + if (bOutput) + ExtOut ("\n"); + + DWORD_PTR cxrAddr; + CROSS_PLATFORM_CONTEXT cxr; + DWORD_PTR exrAddr; + EXCEPTION_RECORD exr; + + if (g_targetMachine->GetExceptionContext(ptr,retAddr,&cxrAddr,&cxr,&exrAddr,&exr)) + { + TADDR sp = g_targetMachine->GetSP(cxr); + TADDR ip = g_targetMachine->GetIP(cxr); + bOutput = PrintCallInfo(sp, ip, DSFlag, FALSE); + if (bOutput) + { + ExtOut(" ====> Exception "); + if (exrAddr) + ExtOut("Code %x ", exr.ExceptionCode); + ExtOut ("cxr@%p", (ULONG64)cxrAddr); + if (exrAddr) + ExtOut(" exr@%p", (ULONG64)exrAddr); + ExtOut("\n"); + } + } + } + ptr += sizeof (DWORD_PTR); + } +} + + +#ifdef SOS_TARGET_X86 +/// +/// X86Machine implementation +/// +LPCSTR X86Machine::s_DumpStackHeading = "ChildEBP RetAddr Caller, Callee\n"; +LPCSTR X86Machine::s_DSOHeading = "ESP/REG Object Name\n"; +LPCSTR X86Machine::s_GCRegs[7] = {"eax", "ebx", "ecx", "edx", "esi", "edi", "ebp"}; +LPCSTR X86Machine::s_SPName = "ESP"; + +void PrintNothing (const char *fmt, ...) +{ + // Do nothing. +} + +/// +/// Dump X86 GCInfo header and table +/// +void X86Machine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const +{ + X86GCDump::InfoHdr header; + X86GCDump::GCDump gcDump(encBytes, 5, true); + if (bPrintHeader) + { + gcDump.gcPrintf = gcPrintf; + gcPrintf("Method info block:\n"); + } + else + { + gcDump.gcPrintf = PrintNothing; + } + pTable += gcDump.DumpInfoHdr(pTable, &header, &methodSize, 0); + if (bPrintHeader) + { + gcPrintf("\n"); + gcPrintf("Pointer table:\n"); + } + gcDump.gcPrintf = gcPrintf; + gcDump.DumpGCTable(pTable, header, methodSize, 0); +} +#endif // SOS_TARGET_X86 + +#ifdef SOS_TARGET_ARM +/// +/// ARMMachine implementation +/// +LPCSTR ARMMachine::s_DumpStackHeading = "ChildFP RetAddr Caller, Callee\n"; +LPCSTR ARMMachine::s_DSOHeading = "SP/REG Object Name\n"; +LPCSTR ARMMachine::s_GCRegs[14] = {"r0", "r1", "r2", "r3", "r4", "r5", "r6", + "r7", "r8", "r9", "r10", "r11", "r12", "lr"}; +LPCSTR ARMMachine::s_SPName = "sp"; + +#endif // SOS_TARGET_ARM + +#ifdef SOS_TARGET_AMD64 +/// +/// AMD64Machine implementation +/// +LPCSTR AMD64Machine::s_DumpStackHeading = "Child-SP RetAddr Caller, Callee\n"; +LPCSTR AMD64Machine::s_DSOHeading = "RSP/REG Object Name\n"; +LPCSTR AMD64Machine::s_GCRegs[15] = {"rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; +LPCSTR AMD64Machine::s_SPName = "RSP"; + +/// +/// Dump AMD64 GCInfo table +/// +void AMD64Machine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const +{ + if (bPrintHeader) + { + ExtOut("Pointer table:\n"); + } + + GCDump gcDump(encBytes, 5, true); + gcDump.gcPrintf = gcPrintf; + + gcDump.DumpGCTable(pTable, methodSize, 0); +} +#endif // SOS_TARGET_AMD64 + +#ifdef SOS_TARGET_ARM64 +/// +/// ARM64Machine implementation +/// +LPCSTR ARM64Machine::s_DumpStackHeading = "ChildFP RetAddr Caller, Callee\n"; +LPCSTR ARM64Machine::s_DSOHeading = "SP/REG Object Name\n"; +// excluding x18, fp & lr as these will not contain object references +LPCSTR ARM64Machine::s_GCRegs[28] = {"x0", "x1", "x2", "x3", "x4", "x5", "x6", + "x7", "x8", "x9", "x10", "x11", "x12", "x13", + "x14", "x15", "x16", "x17", "x19", "x20","x21", + "x22", "x23", "x24", "x25", "x26", "x27", "x28"}; +LPCSTR ARM64Machine::s_SPName = "sp"; + +#endif // SOS_TARGET_ARM64 + + |