diff options
Diffstat (limited to 'src/ToolBox/SOS/Strike/disasmX86.cpp')
-rw-r--r-- | src/ToolBox/SOS/Strike/disasmX86.cpp | 1707 |
1 files changed, 0 insertions, 1707 deletions
diff --git a/src/ToolBox/SOS/Strike/disasmX86.cpp b/src/ToolBox/SOS/Strike/disasmX86.cpp deleted file mode 100644 index 0934a824ea..0000000000 --- a/src/ToolBox/SOS/Strike/disasmX86.cpp +++ /dev/null @@ -1,1707 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// ==++== -// - -// -// ==--== -#include "strike.h" -#include "util.h" -#include "disasm.h" -#include <dbghelp.h> - -#include "../../../inc/corhdr.h" -#include "../../../inc/cor.h" -#include "../../../inc/dacprivate.h" - - -#if defined(SOS_TARGET_X86) && defined(SOS_TARGET_AMD64) -#error This file does not support SOS targeting both X86 and AMD64 debuggees -#endif - -#if !defined(SOS_TARGET_X86) && !defined(SOS_TARGET_AMD64) -#error This file should be used to support SOS targeting either X86 or AMD64 debuggees -#endif - - -// These must be in the same order as they are used in the instruction -// encodings/same as the CONTEXT field order. -enum RegIndex -{ - EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, - -#ifdef _TARGET_AMD64_ - R8, R9, R10, R11, R12, R13, R14, R15, -#endif // _TARGET_AMD64_ - - EIP, NONE -}; - -const int NumReg = NONE; -struct Register -{ - TADDR value; - BOOL bValid; - TADDR stack; - BOOL bOnStack; -}; - -// Find the index for a register name -inline RegIndex FindReg (___in __in_z char *ptr, __out_opt int *plen = NULL, __out_opt int *psize = NULL) -{ - struct RegName - { - RegIndex index; - PCSTR pszName; - int cchName; - int size; - }; - - static RegName rgRegNames[] = { - -#define REG(index, reg, size) { index, #reg, sizeof(#reg)-1, size } -#define REG8(index, reg) REG(index, reg, 1) -#define REG16(index, reg) REG(index, reg, 2) -#define REG32(index, reg) REG(index, reg, 4) -#define REG64(index, reg) REG(index, reg, 8) - - REG8(EAX, al), - REG8(EAX, ah), - REG8(EBX, bl), - REG8(EBX, bh), - REG8(ECX, cl), - REG8(ECX, ch), - REG8(EDX, dl), - REG8(EDX, dh), - - REG16(EAX, ax), - REG16(EBX, bx), - REG16(ECX, cx), - REG16(EDX, dx), - REG16(ESI, si), - REG16(EDI, di), - REG16(EBP, bp), - REG16(ESP, sp), - - REG32(EAX, eax), - REG32(EBX, ebx), - REG32(ECX, ecx), - REG32(EDX, edx), - REG32(ESI, esi), - REG32(EDI, edi), - REG32(EBP, ebp), - REG32(ESP, esp), - -#ifdef _TARGET_AMD64_ - - REG8(R8, r8b), - REG8(R9, r9b), - REG8(R10, r10b), - REG8(R11, r11b), - REG8(R12, r12b), - REG8(R13, r13b), - REG8(R14, r14b), - REG8(R15, r15b), - - REG16(R8, r8w), - REG16(R9, r9w), - REG16(R10, r10w), - REG16(R11, r11w), - REG16(R12, r12w), - REG16(R13, r13w), - REG16(R14, r14w), - REG16(R15, r15w), - - REG32(R8, r8d), - REG32(R9, r9d), - REG32(R10, r10d), - REG32(R11, r11d), - REG32(R12, r12d), - REG32(R13, r13d), - REG32(R14, r14d), - REG32(R15, r15d), - - REG64(EAX, rax), - REG64(EBX, rbx), - REG64(ECX, rcx), - REG64(EDX, rdx), - REG64(ESI, rsi), - REG64(EDI, rdi), - REG64(EBP, rbp), - REG64(ESP, rsp), - REG64(R8, r8), - REG64(R9, r9), - REG64(R10, r10), - REG64(R11, r11), - REG64(R12, r12), - REG64(R13, r13), - REG64(R14, r14), - REG64(R15, r15), - -#endif // _TARGET_AMD64_ - -#undef REG -#undef REG8 -#undef REG16 -#undef REG32 -#undef REG64 - - }; - - for (size_t i = 0; i < sizeof(rgRegNames)/sizeof(rgRegNames[0]); i++) - { - if (!strncmp(ptr, rgRegNames[i].pszName, rgRegNames[i].cchName)) - { - if (psize) - *psize = rgRegNames[i].size; - - if (plen) - *plen = rgRegNames[i].cchName; - - return rgRegNames[i].index; - } - } - - return NONE; -} - -// Find the value of an expression. -inline BOOL FindSrc (__in_z char *ptr, ___in Register *reg, INT_PTR &value, BOOL &bDigit) -{ - if (GetValueFromExpr (ptr, value)) - { - bDigit = TRUE; - return TRUE; - } - - BOOL bValid = FALSE; - BOOL bByRef = IsByRef (ptr); - bDigit = FALSE; - - int regnamelen; - RegIndex index = FindReg (ptr, ®namelen); - if (index != NONE) - { - if (reg[index].bValid) - { - value = reg[index].value; - ptr += regnamelen; - // TODO: consider ecx+edi*4+0x4 - if ((IsTermSep (ptr[0]) && !bByRef) - || (ptr[0] == ']' && bByRef)) - { - bValid = TRUE; - if (bByRef) - SafeReadMemory (TO_TADDR(value), &value, sizeof(void*), NULL); - } - } - } - return bValid; -} - -enum ADDRESSMODE {REG, DATA, INDIRECT, NODATA, BAD}; - -struct RegState -{ - RegIndex reg; - BOOL bFullReg; - char scale; - int namelen; -}; - -struct InstData -{ - ADDRESSMODE mode; - RegState reg[2]; - INT_PTR value; -}; - -void FindMainReg (___in __in_z char *ptr, RegState ®) -{ - int size = 0; - - reg.reg = FindReg(ptr, ®.namelen, &size); - - reg.bFullReg = (reg.reg!=NONE && sizeof(void*)==size) ? TRUE : FALSE; -} - -static void DecodeAddressIndirect (___in __in_z char *term, InstData& arg) -{ - arg.mode = BAD; - arg.value = 0; - arg.reg[0].scale = 0; - arg.reg[1].scale = 0; - - if (!IsByRef (term)) - { - return; - } - - // first part must be a reg - arg.reg[0].scale = 1; - if (term[0] == '+') - term ++; - else if (term[0] == '-') - { - term ++; - arg.reg[0].scale = -1; - } - if (isdigit(term[0])) - { - arg.reg[0].scale *= term[0]-'0'; - term ++; - } - - FindMainReg (term, arg.reg[0]); - if (arg.reg[0].reg == NONE) - return; - term += arg.reg[0].namelen; - - if (term[0] == ']') - { - // It is [reg] - arg.mode = INDIRECT; - arg.value = 0; - return; - } - - char sign = (char)((term[0] == '+')?1:-1); - term ++; - FindMainReg (term, arg.reg[1]); - if (arg.reg[1].reg != NONE) - { - // It is either [reg+reg*c] or [reg+reg*c+c] - - term += arg.reg[1].namelen; - - if (term[0] == '*') - { - term ++; - arg.reg[1].scale = sign*(term[0]-'0'); - term ++; - } - else - arg.reg[1].scale = sign; - - if (term[0] == ']') - { - // It is [reg+reg*c] - arg.mode = INDIRECT; - arg.value = 0; - return; - } - sign = (char)((term[0] == '+')?1:-1); - term ++; - } - - char *endptr; - arg.value = strtoul(term, &endptr, 16); - if (endptr[0] == ']') - { - // It is [reg+reg*c+c] - arg.value *= sign; - arg.mode = INDIRECT; - } -} - -void DecodeAddressTerm (___in __in_z char *term, InstData& arg) -{ - arg.mode = BAD; - arg.reg[0].scale = 0; - arg.reg[1].scale = 0; - arg.value = 0; - INT_PTR value; - - if (GetValueFromExpr (term, value)) - { - arg.value = value; - arg.mode = DATA; - } - else - { - FindMainReg (term, arg.reg[0]); - if (arg.reg[0].reg != NONE) - { - arg.mode = REG; - } - else - { - DecodeAddressIndirect (term, arg); - } - } -} - -// Return 0 for non-managed call. Otherwise return MD address. -TADDR MDForCall (TADDR callee) -{ - // call managed code? - JITTypes jitType; - TADDR methodDesc; - TADDR IP = callee; - TADDR gcinfoAddr; - - if (!GetCalleeSite (callee, IP)) - return 0; - - IP2MethodDesc (IP, methodDesc, jitType, gcinfoAddr); - if (methodDesc) - { - return methodDesc; - } - - // jmp stub - char line[256]; - DisasmAndClean (IP, line, 256); - char *ptr = line; - NextTerm (ptr); - NextTerm (ptr); - if (!strncmp (ptr, "jmp ", 4)) - { - // jump thunk - NextTerm (ptr); - INT_PTR value; - methodDesc = 0; - if (GetValueFromExpr (ptr, value)) - { - IP2MethodDesc (value, methodDesc, jitType, gcinfoAddr); - } - return methodDesc; - } - return 0; -} - -// Handle a call instruction. -void HandleCall(TADDR callee, Register *reg) -{ - // call managed code? - TADDR methodDesc = MDForCall (callee); - if (methodDesc) - { - DacpMethodDescData MethodDescData; - if (MethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK) - { - NameForMD_s(methodDesc, g_mdName,mdNameLen); - ExtOut(" (%S, mdToken: %p)", g_mdName, SOS_PTR(MethodDescData.MDToken)); - return; - } - } - -#ifdef _TARGET_AMD64_ - // A jump thunk? - - CONTEXT ctx = {0}; - - ctx.ContextFlags = (CONTEXT_AMD64 | CONTEXT_CONTROL | CONTEXT_INTEGER); - - for (unsigned ireg = 0; ireg < 16; ireg++) - { - if (reg[ireg].bValid) - { - *(&ctx.Rax + ireg) = reg[ireg].value; - } - } - - ctx.Rip = callee; - - CLRDATA_ADDRESS ip = 0, md = 0; - if (S_OK == g_sos->GetJumpThunkTarget(&ctx, &ip, &md)) - { - if (md) - { - DacpMethodDescData MethodDescData; - if (MethodDescData.Request(g_sos, md) == S_OK) - { - NameForMD_s(md, g_mdName,mdNameLen); - ExtOut(" (%S, mdToken: %p)", g_mdName, SOS_PTR(MethodDescData.MDToken)); - return; - } - } - - if (ip != callee) - { - return HandleCall(ip, reg); - } - } -#endif // _TARGET_AMD64_ - - // A JitHelper? - const char* name = HelperFuncName(callee); - if (name) { - ExtOut (" (JitHelp: %s)", name); - return; - } - - // call unmanaged code? - char Symbol[1024]; - if (SUCCEEDED(g_ExtSymbols->GetNameByOffset(TO_CDADDR(callee), Symbol, 1024, - NULL, NULL))) - { - if (Symbol[0] != '\0') - { - ExtOut (" (%s)", Symbol); - return; - } - } -} - -// Determine if a value is MT/MD/Obj -void HandleValue(TADDR value) -{ - // A MethodTable? - if (IsMethodTable(value)) - { - NameForMT_s (value, g_mdName,mdNameLen); - ExtOut (" (MT: %S)", g_mdName); - return; - } - - // A Managed Object? - TADDR dwMTAddr; - move_xp (dwMTAddr, value); - if (IsStringObject(value)) - { - ExtOut (" (\""); - StringObjectContent (value, TRUE); - ExtOut ("\")"); - return; - } - else if (IsMethodTable(dwMTAddr)) - { - NameForMT_s (dwMTAddr, g_mdName,mdNameLen); - ExtOut (" (Object: %S)", g_mdName); - return; - } - - // A MethodDesc? - if (IsMethodDesc(value)) - { - NameForMD_s (value, g_mdName,mdNameLen); - ExtOut (" (MD: %S)", g_mdName); - return; - } - - // A JitHelper? - const char* name = HelperFuncName(value); - if (name) { - ExtOut (" (JitHelp: %s)", name); - return; - } -} - -/**********************************************************************\ -* Routine Description: * -* * -* Unassembly a managed code. Translating managed object, * -* call. * -* * -\**********************************************************************/ -void -#ifdef _TARGET_X86_ - X86Machine::Unassembly -#elif defined(_TARGET_AMD64_) - AMD64Machine::Unassembly -#endif - (TADDR IPBegin, - TADDR IPEnd, - TADDR IPAskedFor, - TADDR GCStressCodeCopy, - GCEncodingInfo *pGCEncodingInfo, - SOSEHInfo *pEHInfo, - BOOL bSuppressLines, - BOOL bDisplayOffsets) const -{ - ULONG_PTR IP = IPBegin; - char line[1024]; - Register reg [NumReg]; - ZeroMemory (reg, sizeof(reg)); - RegIndex dest; - INT_PTR value; - BOOL bDigit; - char *ptr; - - ULONG curLine = -1; - WCHAR filename[MAX_LONGPATH]; - ULONG linenum; - - while (IP < IPEnd) - { - if (IsInterrupt()) - return; - - // Print out line numbers if needed - if (!bSuppressLines - && SUCCEEDED(GetLineByOffset(TO_CDADDR(IP), &linenum, filename, MAX_LONGPATH))) - { - if (linenum != curLine) - { - curLine = linenum; - ExtOut("\n%S @ %d:\n", filename, linenum); - } - } - - // - // Print out any GC information corresponding to the current instruction offset. - // - -#ifndef FEATURE_PAL - if (pGCEncodingInfo) - { - SIZE_T curOffset = (IP - IPBegin) + pGCEncodingInfo->hotSizeToAdd; - while ( !pGCEncodingInfo->fDoneDecoding - && pGCEncodingInfo->ofs <= curOffset) - { - ExtOut(pGCEncodingInfo->buf); - ExtOut("\n"); - SwitchToFiber(pGCEncodingInfo->pvGCTableFiber); - } - } -#endif // FEATURE_PAL - - ULONG_PTR InstrAddr = IP; - - // - // Print out any EH info corresponding to the current offset - // - if (pEHInfo) - { - pEHInfo->FormatForDisassembly(IP - IPBegin); - } - - if (IP == IPAskedFor) - { - ExtOut (">>> "); - } - - // - // Print offsets, in addition to actual address. - // - if (bDisplayOffsets) - { - ExtOut("%04x ", IP - IPBegin); - } - - DisasmAndClean (IP, line, _countof(line)); - - // look at key word - ptr = line; - NextTerm (ptr); - NextTerm (ptr); - - // - // If there is gcstress info for this method, and this is a 'hlt' - // instruction, then gcstress probably put the 'hlt' there. Look - // up the original instruction and print it instead. - // - - SSIZE_T cbIPOffset = 0; - - if ( GCStressCodeCopy - && ( !strncmp (ptr, "hlt", 3) - || !strncmp (ptr, "cli", 3) - || !strncmp (ptr, "sti", 3))) - { - // - // Compute address into saved copy of the code, and - // disassemble the original instruction - // - - ULONG_PTR OrigInstrAddr = GCStressCodeCopy + (InstrAddr - IPBegin); - ULONG_PTR OrigIP = OrigInstrAddr; - - DisasmAndClean(OrigIP, line, _countof(line)); - - // - // Increment the real IP based on the size of the unmodifed - // instruction - // - - IP = InstrAddr + (OrigIP - OrigInstrAddr); - - cbIPOffset = IP - OrigIP; - - // - // Print out real code address in place of the copy address - // - -#ifdef _WIN64 - ExtOut("%08x`%08x ", (ULONG)(InstrAddr >> 32), (ULONG)InstrAddr); -#else - ExtOut("%08x ", (ULONG)InstrAddr); -#endif - - ptr = line; - NextTerm (ptr); - - // - // Print out everything after the code address, and skip the - // instruction bytes - // - - ExtOut(ptr); - - NextTerm (ptr); - - // - // Add an indicator that this address has not executed yet - // - - ExtOut(" (gcstress)"); - } - else - { - ExtOut (line); - } - - if (!strncmp (ptr, "mov ", 4)) - { - NextTerm (ptr); - - dest = FindReg(ptr); - if (dest != NONE) - { - NextTerm (ptr); - - if (FindSrc (ptr, reg, value, bDigit)) - { - reg[dest].bValid = TRUE; - reg[dest].value = value; - // Is it a managed obj - if (bDigit) - HandleValue (reg[dest].value); - } - else - { - reg[dest].bValid = FALSE; - } - } - } - else if (!strncmp (ptr, "call ", 5)) - { - NextTerm (ptr); - if (FindSrc (ptr, reg, value, bDigit)) - { - if (bDigit) - value += cbIPOffset; - - HandleCall (value, reg); - } - - // trash EAX, ECX, EDX - reg[EAX].bValid = FALSE; - reg[ECX].bValid = FALSE; - reg[EDX].bValid = FALSE; - -#ifdef _TARGET_AMD64_ - reg[R8].bValid = FALSE; - reg[R9].bValid = FALSE; - reg[R10].bValid = FALSE; - reg[R11].bValid = FALSE; -#endif // _TARGET_AMD64_ - } - else if (!strncmp (ptr, "lea ", 4)) - { - NextTerm (ptr); - dest = FindReg(ptr); - if (dest != NONE) - { - NextTerm (ptr); - if (FindSrc (ptr, reg, value, bDigit)) - { - reg[dest].bValid = TRUE; - reg[dest].value = value; - } - else - { - reg[dest].bValid = FALSE; - } - } - } - else if (!strncmp (ptr, "push ", 5)) - { - // do not do anything - NextTerm (ptr); - if (FindSrc (ptr, reg, value, bDigit)) - { - if (bDigit) - { - HandleValue (value); - } - } - } - else - { - // assume this instruction will trash dest reg - NextTerm (ptr); - dest = FindReg(ptr); - if (dest != NONE) - reg[dest].bValid = FALSE; - } - ExtOut ("\n"); - } - - // - // Print out any "end" EH info (where the end address is the byte immediately following the last instruction) - // - if (pEHInfo) - { - pEHInfo->FormatForDisassembly(IP - IPBegin); - } -} - -// Find the real callee site. Handle JMP instruction. -// Return TRUE if we get the address, FALSE if not. -BOOL GetCalleeSite (TADDR IP, TADDR &IPCallee) -{ - while (TRUE) { - unsigned char inst[2]; - if (g_ExtData->ReadVirtual(TO_CDADDR(IP), inst, sizeof(inst), NULL) != S_OK) - { - return FALSE; - } - if (inst[0] == 0xEB) { - IP += 2+(char)inst[1]; - } - else if (inst[0] == 0xE9) { - int displace; - if (g_ExtData->ReadVirtual(TO_CDADDR(IP+1), &displace, sizeof(displace), NULL) != S_OK) - { - return FALSE; - } - else - { - IP += 5+displace; - } - } - else if (inst[0] == 0xFF && (inst[1] & 070) == 040) { - if (inst[1] == 0x25) { - DWORD displace; - if (g_ExtData->ReadVirtual(TO_CDADDR(IP+2), &displace, sizeof(displace), NULL) != S_OK) - { - return FALSE; - } - if (g_ExtData->ReadVirtual(TO_CDADDR(displace), &displace, sizeof(displace), NULL) != S_OK) - { - return FALSE; - } - else - { - IP = displace; - } - } - else - // Target for jmp is determined from register values. - return FALSE; - } - else - { - IPCallee = IP; - return TRUE; - } - } -} - -// GetFinalTarget is based on HandleCall, but avoids printing anything to the output. -// This is currently only called on x64 -eTargetType GetFinalTarget(TADDR callee, TADDR* finalMDorIP) -{ - // call managed code? - TADDR methodDesc = MDForCall (callee); - if (methodDesc) - { - DacpMethodDescData MethodDescData; - if (MethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK) - { - *finalMDorIP = methodDesc; - return ettMD; - } - } - -#ifdef _TARGET_AMD64_ - // A jump thunk? - - CONTEXT ctx = {0}; - ctx.ContextFlags = (CONTEXT_AMD64 | CONTEXT_CONTROL | CONTEXT_INTEGER); - ctx.Rip = callee; - - CLRDATA_ADDRESS ip = 0, md = 0; - if (S_OK == g_sos->GetJumpThunkTarget(&ctx, &ip, &md)) - { - if (md) - { - DacpMethodDescData MethodDescData; - if (MethodDescData.Request(g_sos, md) == S_OK) - { - *finalMDorIP = md; - return ettStub; - } - } - - if (ip != callee) - { - return GetFinalTarget(ip, finalMDorIP); - } - } -#endif // _TARGET_AMD64_ - - // A JitHelper? - const char* name = HelperFuncName(callee); - if (name) { - *finalMDorIP = callee; - return ettJitHelp; - } - - // call unmanaged code? - *finalMDorIP = callee; - return ettNative; -} - -#ifndef FEATURE_PAL - -void ExpFuncStateInit (TADDR *IPRetAddr) -{ - ULONG64 offset; - if (FAILED(g_ExtSymbols->GetOffsetByName("ntdll!KiUserExceptionDispatcher", &offset))) { - return; - } - - // test if we have a minidump for which the image is not cached anymore. this avoids - // the having the while loop below spin forever (or a very long time)... - // (Watson backend hit this a few times, and they had to institute a timeout policy - // to work around this) - SIZE_T instrs; - if (FAILED(g_ExtData->ReadVirtual(offset, &instrs, sizeof(instrs), NULL)) || instrs == 0) { - return; - } - - char line[256]; - int i = 0; - int cnt = 0; -#ifdef SOS_TARGET_X86 - // On x86 and x64 the last 3 "call" instructions in ntdll!KiUserExceptionDispatcher - // are making calls to OS APIs that take as argument the context record (and some - // of them the exception record as well) - const int cCallInstrs = 3; -#elif defined(SOS_TARGET_AMD64) - // On x64 the first "call" instruction should be considered, as well - const int cCallInstrs = 4; -#endif - - while (i < cCallInstrs) { - g_ExtControl->Disassemble (offset, 0, line, 256, NULL, &offset); - if (strstr (line, "call")) { - IPRetAddr[i++] = (TADDR)offset; - } - // if we didn't find at least one "call" in the first 500 instructions give up... - if (++cnt >= 500 && IPRetAddr[0] == 0) - break; - } -} - -#endif // FEATURE_PAL - - -/**********************************************************************\ -* Routine Description: * -* * -* This function is called to fill in a cross platform context * -* struct by looking on the stack for return addresses into * -* KiUserExceptionDispatcher * -* * -\**********************************************************************/ -BOOL -#ifdef SOS_TARGET_X86 - X86Machine::GetExceptionContext -#elif defined(SOS_TARGET_AMD64) - AMD64Machine::GetExceptionContext -#endif - (TADDR stack, - TADDR IP, - TADDR * cxrAddr, - CROSS_PLATFORM_CONTEXT * pcxr, - TADDR * exrAddr, - PEXCEPTION_RECORD exr) const -{ -#ifndef FEATURE_PAL -#ifdef SOS_TARGET_X86 - X86_CONTEXT * cxr = &pcxr->X86Context; - size_t contextSize = offsetof(CONTEXT, ExtendedRegisters); -#elif defined(SOS_TARGET_AMD64) - AMD64_CONTEXT * cxr = &pcxr->Amd64Context; - size_t contextSize = offsetof(CONTEXT, FltSave); -#endif - - static TADDR IPRetAddr[4] = {0, 0, 0, 0}; - - if (IPRetAddr[0] == 0) { - ExpFuncStateInit (IPRetAddr); - } - *cxrAddr = 0; - *exrAddr = 0; - -#ifdef SOS_TARGET_X86 - - if (IP == IPRetAddr[0]) { - *exrAddr = stack + sizeof(TADDR); - *cxrAddr = stack + 2*sizeof(TADDR); - } - else if (IP == IPRetAddr[1]) { - *cxrAddr = stack + sizeof(TADDR); - } - else if (IP == IPRetAddr[2]) { - *exrAddr = stack + sizeof(TADDR); - *cxrAddr = stack + 2*sizeof(TADDR); - } - else - return FALSE; - - if (FAILED (g_ExtData->ReadVirtual(TO_CDADDR(*cxrAddr), &stack, sizeof(stack), NULL))) - return FALSE; - *cxrAddr = stack; - - //if ((pContext->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS) - // contextSize += sizeof(pContext->ExtendedRegisters); - if (FAILED (g_ExtData->ReadVirtual(TO_CDADDR(stack), cxr, (ULONG)contextSize, NULL))) { - return FALSE; - } - - if (*exrAddr) { - if (FAILED (g_ExtData->ReadVirtual(TO_CDADDR(*exrAddr), &stack, sizeof(stack), NULL))) - { - *exrAddr = 0; - return TRUE; - } - *exrAddr = stack; - size_t erSize = offsetof (EXCEPTION_RECORD, ExceptionInformation); - if (FAILED (g_ExtData->ReadVirtual(TO_CDADDR(stack), exr, (ULONG)erSize, NULL))) { - *exrAddr = 0; - return TRUE; - } - } - -#elif defined(SOS_TARGET_AMD64) - - if (IP == IPRetAddr[0] || IP == IPRetAddr[1] || IP == IPRetAddr[3]) { - *exrAddr = stack + sizeof(TADDR) + 0x4F0; - *cxrAddr = stack + sizeof(TADDR); - } else if (IP == IPRetAddr[2]) { - *cxrAddr = stack + sizeof(TADDR); - } - else { - return FALSE; - } - - if (FAILED (g_ExtData->ReadVirtual(TO_CDADDR(*cxrAddr), cxr, (ULONG)contextSize, NULL))) { - return FALSE; - } - - if (*exrAddr) { - size_t erSize = offsetof (EXCEPTION_RECORD, ExceptionInformation); - if (FAILED (g_ExtData->ReadVirtual(TO_CDADDR(*exrAddr), exr, (ULONG)erSize, NULL))) { - *exrAddr = 0; - return TRUE; - } - } - -#endif - return TRUE; -#else - return FALSE; -#endif // FEATURE_PAL -} - - -/**********************************************************************\ -* Routine Description: * -* * -* This function is called to determine if a DWORD on the stack is * -* a return address. * -* It does this by checking several bytes before the DWORD to see if * -* there is a call instruction. * -* * -\**********************************************************************/ - -void -#ifdef _TARGET_X86_ - X86Machine::IsReturnAddress -#elif defined(_TARGET_AMD64_) - AMD64Machine::IsReturnAddress -#endif - (TADDR retAddr, TADDR* whereCalled) const -{ - *whereCalled = 0; - - unsigned char spotend[6]; - move_xp (spotend, retAddr-6); - unsigned char *spot = spotend+6; - TADDR addr; - - // Note this is possible to be spoofed, but pretty unlikely - // call XXXXXXXX - if (spot[-5] == 0xE8) { - DWORD offs = 0; - move_xp (offs, retAddr-4); - *whereCalled = retAddr + (ULONG64)(LONG)(offs); - //*whereCalled = *((int*) (retAddr-4)) + retAddr; - // on WOW64 the range valid for code is almost the whole 4GB address space - if (g_ExtData->ReadVirtual(TO_CDADDR(*whereCalled), &addr, sizeof(addr), NULL) == S_OK) - { - TADDR callee; - if (GetCalleeSite(*whereCalled, callee)) { - *whereCalled = callee; - } - return; - } - else - *whereCalled = 0; - } - - // call [XXXXXXXX] - if (spot[-6] == 0xFF && (spot[-5] == 025)) { - DWORD offs = 0; - move_xp (offs, retAddr-4); -#ifdef _TARGET_AMD64_ - // on x64 this 32-bit is an RIP offset - addr = retAddr + (ULONG64)(LONG)(offs); -#elif defined (_TARGET_X86_) - addr = offs; -#endif - if (g_ExtData->ReadVirtual(TO_CDADDR(addr), whereCalled, sizeof(*whereCalled), NULL) == S_OK) { - move_xp (*whereCalled, addr); - //*whereCalled = **((unsigned**) (retAddr-4)); - // on WOW64 the range valid for code is almost the whole 4GB address space - if (g_ExtData->ReadVirtual(TO_CDADDR(*whereCalled), &addr, sizeof(addr), NULL) == S_OK) - { - TADDR callee; - if (GetCalleeSite(*whereCalled,callee)) { - *whereCalled = callee; - } - return; - } - else - *whereCalled = 0; - } - else - *whereCalled = 0; - } - - // call [REG+XX] - if (spot[-3] == 0xFF && (spot[-2] & ~7) == 0120 && (spot[-2] & 7) != 4) - { - *whereCalled = 0xFFFFFFFF; - return; - } - if (spot[-4] == 0xFF && spot[-3] == 0124) - { - *whereCalled = 0xFFFFFFFF; - return; - } - - // call [REG+XXXX] - if (spot[-6] == 0xFF && (spot[-5] & ~7) == 0220 && (spot[-5] & 7) != 4) - { - *whereCalled = 0xFFFFFFFF; - return; - } - if (spot[-7] == 0xFF && spot[-6] == 0224) - { - *whereCalled = 0xFFFFFFFF; - return; - } - - // call [REG] - if (spot[-2] == 0xFF && (spot[-1] & ~7) == 0020 && (spot[-1] & 7) != 4 && (spot[-1] & 7) != 5) - { - *whereCalled = 0xFFFFFFFF; - return; - } - - // call REG - if (spot[-2] == 0xFF && (spot[-1] & ~7) == 0320 && (spot[-1] & 7) != 4) - { - *whereCalled = 0xFFFFFFFF; - return; - } - - // There are other cases, but I don't believe they are used. - return; -} - - -#ifdef _X86_ - -/// -/// This is dead code, not called from anywhere, not linked in the final product. -/// -static BOOL DecodeLine (___in __in_z char *line, ___in __in_z const char *const inst, InstData& arg1, InstData& arg2) -{ - char *ptr = line; - if (inst[0] == '*' || !strncmp (ptr, inst, strlen (inst))) - { - arg1.mode = BAD; - arg2.mode = BAD; - NextTerm (ptr); - if (*ptr == '\0') - { - arg1.mode = NODATA; - return TRUE; - } - - DecodeAddressTerm (ptr, arg1); - NextTerm (ptr); - if (*ptr == '\0') - { - return TRUE; - } - DecodeAddressTerm (ptr, arg2); - return TRUE; - } - else - return FALSE; -} - -void PrintReg (Register *reg) -{ - ExtOut ("[EBX=%08x ESI=%08x EDI=%08x EBP=%08x ESP=%08x]\n", - reg[EBX].value, reg[ESI].value, reg[EDI].value, reg[EBP].value, - reg[ESP].value); -} - - -struct CallInfo -{ - DWORD_PTR stackPos; - DWORD_PTR retAddr; - DWORD_PTR whereCalled; -}; - -// Search for a Return address on stack. -BOOL GetNextRetAddr (DWORD_PTR stackBegin, DWORD_PTR stackEnd, - CallInfo &callInfo) -{ - for (callInfo.stackPos = stackBegin; - callInfo.stackPos <= stackEnd; - callInfo.stackPos += 4) - { - if (!SafeReadMemory (callInfo.stackPos, &callInfo.retAddr, 4, NULL)) - continue; - - g_targetMachine->IsReturnAddress(callInfo.retAddr, &callInfo.whereCalled); - if (callInfo.whereCalled) - { - return TRUE; - } - } - - return FALSE; -} - -struct FrameInfo -{ - DWORD_PTR IPStart; - DWORD_PTR Prolog; - DWORD_PTR FrameBase; // The value of ESP at the entry. - DWORD_PTR StackEnd; - DWORD_PTR argCount; - BOOL bEBPFrame; -}; - -// if a EBP frame, return TRUE if EBP has been setup -void GetFrameBaseHelper (DWORD_PTR IPBegin, DWORD_PTR IPEnd, - INT_PTR &StackChange) -{ - char line[256]; - char *ptr; - InstData arg1; - InstData arg2; - DWORD_PTR IP = IPBegin; - StackChange = 0; - while (IP < IPEnd) - { - DisasmAndClean (IP, line, 256); - ptr = line; - NextTerm (ptr); - NextTerm (ptr); - if (DecodeLine (ptr, "push ", arg1, arg2)) - { - StackChange += 4; - } - else if (DecodeLine (ptr, "pop ", arg1, arg2)) - { - StackChange -= 4; - } - else if (DecodeLine (ptr, "sub ", arg1, arg2)) - { - if (arg1.mode == REG && arg1.reg[0].reg == ESP) - { - if (arg2.mode == DATA) - StackChange -= arg2.value; - } - } - else if (DecodeLine (ptr, "add ", arg1, arg2)) - { - if (arg1.mode == REG && arg1.reg[0].reg == ESP) - { - if (arg2.mode == DATA) - StackChange += arg2.value; - } - } - else if (!strncmp (ptr, "ret", 3)) { - return; - } - } -} - -enum IPSTATE {IPPROLOG1 /*Before EBP set*/, IPPROLOG2 /*After EBP set*/, IPCODE, IPEPILOG, IPEND}; - -IPSTATE GetIpState (DWORD_PTR IP, FrameInfo* pFrame) -{ - char line[256]; - char *ptr; - - if (IP >= pFrame->IPStart && IP < pFrame->IPStart + pFrame->Prolog) - { - if (pFrame->bEBPFrame) { - DWORD_PTR pIP = pFrame->IPStart; - while (pIP < IP) { - DisasmAndClean (IP,line, 256); - ptr = line; - NextTerm (ptr); - NextTerm (ptr); - if (!strncmp (ptr, "mov ", 4)) { - NextTerm (ptr); - if (!strncmp (ptr, "ebp", 3)) { - NextTerm (ptr); - if (!strncmp (ptr, "esp", 3)) { - return IPPROLOG2; - } - } - } - else if (!strncmp (ptr, "call ", 5)) { - NextTerm (ptr); - if (strstr (ptr, "__EH_prolog")) { - return IPPROLOG2; - } - } - } - pIP = IP; - while (pIP < pFrame->IPStart + pFrame->Prolog) { - DisasmAndClean (IP,line, 256); - ptr = line; - NextTerm (ptr); - NextTerm (ptr); - if (!strncmp (ptr, "mov ", 4)) { - NextTerm (ptr); - if (!strncmp (ptr, "ebp", 3)) { - NextTerm (ptr); - if (!strncmp (ptr, "esp", 3)) { - return IPPROLOG1; - } - } - } - else if (!strncmp (ptr, "call ", 5)) { - NextTerm (ptr); - if (strstr (ptr, "__EH_prolog")) { - return IPPROLOG1; - } - } - } - - ExtOut ("Fail to find where EBP is saved\n"); - return IPPROLOG2; - } - else - { - return IPPROLOG1; - } - } - - int nline = 0; - while (1) { - DisasmAndClean (IP,line, 256); - nline ++; - ptr = line; - NextTerm (ptr); - NextTerm (ptr); - if (!strncmp (ptr, "ret", 3)) { - return (nline==1)?IPEND:IPEPILOG; - } - else if (!strncmp (ptr, "leave", 5)) { - return IPEPILOG; - } - else if (!strncmp (ptr, "call", 4)) { - return IPCODE; - } - else if (ptr[0] == 'j') { - return IPCODE; - } - } -} - -// FrameBase is the ESP value at the entry of a function. -BOOL GetFrameBase (Register callee[], FrameInfo* pFrame) -{ - //char line[256]; - //char *ptr; - INT_PTR dwpushed = 0; - //DWORD_PTR IP; - - IPSTATE IpState = GetIpState (callee[EIP].value, pFrame); - - if (pFrame->bEBPFrame) - { - if (IpState == IPEND || IpState == IPPROLOG1) { - pFrame->FrameBase = callee[ESP].value; - } - else - { - pFrame->FrameBase = callee[EBP].value+4; - } - return TRUE; - } - else - { - if (IpState == IPEND) { - pFrame->FrameBase = callee[ESP].value; - return TRUE; - } - - DWORD_PTR IPBegin, IPEnd; - if (IpState == IPEPILOG) { - IPBegin = callee[EIP].value; - IPEnd = ~0ul; - } - else if (IpState == IPPROLOG1) { - IPBegin = pFrame->IPStart; - IPEnd = callee[EIP].value; - } - else - { - IPBegin = pFrame->IPStart; - IPEnd = IPBegin + pFrame->Prolog; - } - GetFrameBaseHelper (IPBegin, IPEnd, dwpushed); - - if (IpState == IPEPILOG) { - ExtOut ("stack %d\n", dwpushed); - pFrame->FrameBase = callee[ESP].value - dwpushed; - return TRUE; - } - - CallInfo callInfo; - if (GetNextRetAddr (callee[ESP].value + dwpushed, - pFrame->StackEnd, callInfo)) - { - pFrame->FrameBase = callInfo.stackPos; - return TRUE; - } - - return FALSE; - } -} - -// caller[ESP]: the ESP value when we return to caller. -void RestoreCallerRegister (Register callee[], Register caller[], - FrameInfo *pFrame) -{ - if (pFrame->bEBPFrame) - { - if (callee[ESP].value < pFrame->FrameBase) - { - SafeReadMemory (pFrame->FrameBase-4, &caller[EBP].value, 4, NULL); - } - else - caller[EBP].value = callee[EBP].value; - } - else - caller[EBP].value = callee[EBP].value; - - caller[EBP].bValid = TRUE; - caller[ESP].value = pFrame->FrameBase + 4 + pFrame->argCount; - callee[EBP].value = pFrame->FrameBase - sizeof(void*); - SafeReadMemory (pFrame->FrameBase, &caller[EIP].value, 4, NULL); -} - -BOOL GetFrameInfoHelper (Register callee[], Register caller[], - FrameInfo *pFrame) -{ - if (GetFrameBase (callee, pFrame)) - { - RestoreCallerRegister (callee, caller, pFrame); - return TRUE; - } - else - return FALSE; -} - -// Return TRUE if Frame Info is OK, otherwise FALSE. -BOOL GetUnmanagedFrameInfo (Register callee[], Register caller[], - DumpStackFlag &DSFlag, PFPO_DATA data) -{ - FrameInfo Frame; - ULONG64 base; - g_ExtSymbols->GetModuleByOffset (callee[EIP].value, 0, NULL, &base); - Frame.IPStart = data->ulOffStart + (ULONG_PTR)base; - Frame.Prolog = data->cbProlog; - // Why do we have to do this to make it work? - if (Frame.Prolog == 1) { - Frame.Prolog = 0; - } - Frame.bEBPFrame = (data->cbFrame == FRAME_NONFPO); - Frame.StackEnd = DSFlag.end; - Frame.argCount = data->cdwParams*4; - - return GetFrameInfoHelper (callee, caller, &Frame); -} - -// offsetEBP: offset of stack position where EBP is saved. -// If EBP is not saved, *offsetEBP = -1 (~0ul); -BOOL IPReachable (DWORD_PTR IPBegin, DWORD_PTR IP, DWORD *offsetEBP) -{ - *offsetEBP = ~0ul; - return FALSE; -} - -BOOL HandleEEStub (Register callee[], Register caller[], - DumpStackFlag &DSFlag) -{ - // EEStub can only be called by IP directory. Let's look for possible caller. - CallInfo callInfo; - DWORD_PTR stackPos = callee[ESP].value; - while (stackPos < DSFlag.end) { - if (GetNextRetAddr (stackPos, - DSFlag.end, callInfo)) - { - if (callInfo.whereCalled != ~0ul) { - DWORD offsetEBP; - if (IPReachable (callInfo.whereCalled, callee[EIP].value, &offsetEBP)) { - caller[EIP].value = callInfo.retAddr; - // TODO: We may have saved EBP. - if (offsetEBP == ~0ul) { - caller[EBP].value = callee[EBP].value; - } - else - { - TADDR offs = TO_TADDR(callInfo.stackPos)-sizeof(PVOID)-offsetEBP; - SafeReadMemory (offs, &caller[EBP].value, sizeof(PVOID), NULL); - } - caller[ESP].value = callInfo.stackPos+sizeof(PVOID); - return TRUE; - } - } - stackPos = callInfo.stackPos+sizeof(PVOID); - } - else - return FALSE; - } - - return FALSE; -} - - -BOOL HandleByEpilog (Register callee[], Register caller[], - DumpStackFlag &DSFlag) -{ - return FALSE; -} - -#ifndef FEATURE_PAL -void RestoreFrameUnmanaged (Register *reg, DWORD_PTR CurIP) -{ - char line[256]; - char *ptr; - DWORD_PTR IP = CurIP; - INT_PTR value; - BOOL bDigit; - BOOL bGoodESP = true; - RegIndex dest; - - ULONG64 base; - g_ExtSymbols->GetModuleByOffset (TO_CDADDR(CurIP), 0, NULL, &base); - ULONG64 handle; - g_ExtSystem->GetCurrentProcessHandle(&handle); - PFPO_DATA data = - (PFPO_DATA)SymFunctionTableAccess((HANDLE)handle, CurIP); - DWORD_PTR IPBegin = data->ulOffStart + (ULONG_PTR)base; - - if (CurIP - IPBegin <= data->cbProlog) - { - // We are inside a prolog. - // See where we save the callee saved register. - // Also how many DWORD's we pushd - IP = IPBegin; - reg[ESP].stack = 0; - reg[ESP].bOnStack = FALSE; - reg[EBP].stack = 0; - reg[EBP].bOnStack = FALSE; - reg[ESI].stack = 0; - reg[ESI].bOnStack = FALSE; - reg[EDI].stack = 0; - reg[EDI].bOnStack = FALSE; - reg[EBX].stack = 0; - reg[EBX].bOnStack = FALSE; - - while (IP < CurIP) - { - DisasmAndClean (IP, line, 256); - ptr = line; - NextTerm (ptr); - NextTerm (ptr); - if (!strncmp (ptr, "push ", 5)) - { - reg[ESP].stack += 4; - NextTerm (ptr); - dest = FindReg(ptr); - if (dest == EBP || dest == EBX || dest == ESI || dest == EDI) - { - reg[dest].bOnStack = TRUE; - reg[dest].stack = reg[ESP].stack; - } - } - else if (!strncmp (ptr, "sub ", 4)) - { - NextTerm (ptr); - dest = FindReg(ptr); - if (dest == ESP) - { - NextTerm (ptr); - char *endptr; - reg[ESP].stack += strtoul(ptr, &endptr, 16);; - } - } - } - - DWORD_PTR baseESP = reg[ESP].value + reg[ESP].stack; - if (reg[EBP].bOnStack) - { - move_xp (reg[EBP].value, baseESP-reg[EBP].stack); - } - if (reg[EBX].bOnStack) - { - move_xp (reg[EBX].value, baseESP-reg[EBX].stack); - } - if (reg[ESI].bOnStack) - { - move_xp (reg[ESI].value, baseESP-reg[ESI].stack); - } - if (reg[EDI].bOnStack) - { - move_xp (reg[EDI].value, baseESP-reg[EDI].stack); - } - move_xp (reg[EIP].value, baseESP); - reg[ESP].value = baseESP + 4; - return; - } - - if (data->cbFrame == FRAME_NONFPO) - { - // EBP Frame - } - - // Look for epilog - while (1) - { - DisasmAndClean (IP, line, 256); - ptr = line; - NextTerm (ptr); - NextTerm (ptr); - if (!strncmp (ptr, "mov ", 4)) - { - NextTerm (ptr); - dest = FindReg(ptr); - if (dest == ESP) - { - NextTerm (ptr); - if (FindReg(ptr) == EBP) - { - // We have a EBP frame - bGoodESP = true; - reg[ESP].value = reg[EBP].value; - } - } - } - else if (!strncmp (ptr, "ret", 3)) - { - NextTerm (ptr); - // check the value on stack is a return address. - DWORD_PTR retAddr; - DWORD_PTR whereCalled; - move_xp (retAddr, reg[ESP].value); - int ESPAdjustCount = 0; - while (1) - { - g_targetMachine->IsReturnAddress(retAddr, &whereCalled); - if (whereCalled) - break; - ESPAdjustCount ++; - reg[ESP].value += 4; - move_xp (retAddr, reg[ESP].value); - } - reg[EIP].value = retAddr; - if (ESPAdjustCount) - { - ESPAdjustCount *= 4; - } - if (reg[EBX].bOnStack) - { - reg[EBX].stack += ESPAdjustCount; - move_xp (reg[EBX].value, reg[EBX].stack); - } - if (reg[ESI].bOnStack) - { - reg[ESI].stack += ESPAdjustCount; - move_xp (reg[ESI].value, reg[EBX].stack); - } - if (reg[EDI].bOnStack) - { - reg[EDI].stack += ESPAdjustCount; - move_xp (reg[EDI].value, reg[EBX].stack); - } - - reg[ESP].value += 4; - if (ptr[0] != '\0') - { - FindSrc (ptr, reg, value, bDigit); - reg[ESP].value += value; - } - break; - } - else if (!strncmp (ptr, "pop ", 4)) - { - NextTerm (ptr); - dest = FindReg(ptr); - if (dest == EBP || dest == EBX || dest == ESI || dest == EDI) - { - reg[dest].stack = reg[ESP].value; - reg[dest].bOnStack = TRUE; - } - reg[ESP].value += 4; - } - else if (!strncmp (ptr, "add ", 4)) - { - NextTerm (ptr); - dest = FindReg(ptr); - if (dest == ESP) - { - NextTerm (ptr); - FindSrc (ptr, reg, value, bDigit); - reg[ESP].value += value; - } - } - else if (!strncmp (ptr, "call ", 5)) - { - // assume we do not have a good value on ESP. - // We could go into the call and find out number of pushed args. - bGoodESP = FALSE; - } - } - - // Look for prolog -} -#endif // !FEATURE_PAL - -#elif defined(_AMD64_) - - -#endif // !_X86_ |