diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
commit | ef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch) | |
tree | dee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/gcdump/i386 | |
download | coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2 coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip |
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/gcdump/i386')
-rw-r--r-- | src/gcdump/i386/.gitmirror | 1 | ||||
-rw-r--r-- | src/gcdump/i386/gcdumpx86.cpp | 1069 |
2 files changed, 1070 insertions, 0 deletions
diff --git a/src/gcdump/i386/.gitmirror b/src/gcdump/i386/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/gcdump/i386/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/gcdump/i386/gcdumpx86.cpp b/src/gcdump/i386/gcdumpx86.cpp new file mode 100644 index 0000000000..77419fe308 --- /dev/null +++ b/src/gcdump/i386/gcdumpx86.cpp @@ -0,0 +1,1069 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +/***************************************************************************** + * GCDumpX86.cpp + */ + +/*****************************************************************************/ +#ifdef _TARGET_X86_ +/*****************************************************************************/ + +#include "utilcode.h" // For _ASSERTE() +#include "gcdump.h" + + +/*****************************************************************************/ + +#define castto(var,typ) (*(typ *)&var) + +#define sizeto(typ,mem) (offsetof(typ, mem) + sizeof(((typ*)0)->mem)) + +#define CALLEE_SAVED_REG_MAXSZ (4*sizeof(int)) // EBX,ESI,EDI,EBP + +/*****************************************************************************/ + +const char * RegName(unsigned reg) +{ + static const char * const regNames[] = + { + "EAX", + "ECX", + "EDX", + "EBX", + + "ESP", + "EBP", + "ESI", + "EDI" + }; + + _ASSERTE(reg < (sizeof(regNames)/sizeof(regNames[0]))); + + return regNames[reg]; +} + +const char * CalleeSavedRegName(unsigned reg) +{ + static const char * const regNames[] = + { + "EDI", + "ESI", + "EBX", + "EBP" + }; + + _ASSERTE(reg < (sizeof(regNames)/sizeof(regNames[0]))); + + return regNames[reg]; +} + +/*****************************************************************************/ + +unsigned GCDump::DumpInfoHdr (PTR_CBYTE table, + InfoHdr* header, + unsigned * methodSize, + bool verifyGCTables) +{ + unsigned count; + PTR_CBYTE tableStart = table; + PTR_CBYTE bp = table; + + if (verifyGCTables) + _ASSERTE(*castto(table, unsigned short *)++ == 0xFEEF); + + /* Get the method size */ + + table += decodeUnsigned(table, methodSize); + + table = decodeHeader(table, header); + + BOOL hasArgTabOffset = FALSE; + if (header->untrackedCnt == HAS_UNTRACKED) + { + hasArgTabOffset = TRUE; + table += decodeUnsigned(table, &count); + header->untrackedCnt = count; + } + + if (header->varPtrTableSize == HAS_VARPTR) + { + hasArgTabOffset = TRUE; + table += decodeUnsigned(table, &count); + header->varPtrTableSize = count; + } + + if (header->gsCookieOffset == HAS_GS_COOKIE_OFFSET) + { + table += decodeUnsigned(table, &count); + header->gsCookieOffset = count; + } + + if (header->syncStartOffset == HAS_SYNC_OFFSET) + { + table += decodeUnsigned(table, &count); + header->syncStartOffset = count; + table += decodeUnsigned(table, &count); + header->syncEndOffset = count; + } + + // + // First print out all the basic information + // + + gcPrintf(" method size = %04X\n", *methodSize); + gcPrintf(" prolog size = %2u \n", header->prologSize); + gcPrintf(" epilog size = %2u \n", header->epilogSize); + gcPrintf(" epilog count = %2u \n", header->epilogCount); + gcPrintf(" epilog end = %s \n", header->epilogAtEnd ? "yes" : "no"); + + gcPrintf(" callee-saved regs = "); + if (header->ediSaved) gcPrintf("EDI "); + if (header->esiSaved) gcPrintf("ESI "); + if (header->ebxSaved) gcPrintf("EBX "); + if (header->ebpSaved) gcPrintf("EBP "); + gcPrintf("\n"); + + gcPrintf(" ebp frame = %s \n", header->ebpFrame ? "yes" : "no"); + gcPrintf(" fully interruptible= %s \n", header->interruptible ? "yes" : "no"); + gcPrintf(" double align = %s \n", header->doubleAlign ? "yes" : "no"); + gcPrintf(" arguments size = %2u DWORDs\n", header->argCount); + gcPrintf(" stack frame size = %2u DWORDs\n", header->frameSize); + gcPrintf(" untracked count = %2u \n", header->untrackedCnt); + gcPrintf(" var ptr tab count = %2u \n", header->varPtrTableSize); + + // + // Now display optional information + // + + if (header->security) gcPrintf(" security check obj = yes\n"); + if (header->handlers) gcPrintf(" exception handlers = yes\n"); + if (header->localloc) gcPrintf(" localloc = yes\n"); + if (header->editNcontinue) gcPrintf(" edit & continue = yes\n"); + if (header->profCallbacks) gcPrintf(" profiler callbacks = yes\n"); + if (header->varargs) gcPrintf(" varargs = yes\n"); + if (header->gsCookieOffset != INVALID_GS_COOKIE_OFFSET) + gcPrintf(" GuardStack cookie = [%s%u]\n", + header->ebpFrame ? "EBP-" : "ESP+", header->gsCookieOffset); + if (header->syncStartOffset != INVALID_SYNC_OFFSET) + gcPrintf(" Sync region = [%u,%u]\n", + header->syncStartOffset, header->syncEndOffset); + + if (header->epilogCount > 1 || (header->epilogCount != 0 && + header->epilogAtEnd == 0)) + { + if (verifyGCTables) + _ASSERTE(*castto(table, unsigned short *)++ == 0xFACE); + + unsigned offs = 0; + + for (unsigned i = 0; i < header->epilogCount; i++) + { + table += decodeUDelta(table, &offs, offs); + gcPrintf(" epilog #%2u at %04X\n", i, offs); + } + } + else + { + if (header->epilogCount) + gcPrintf(" epilog at %04X\n", (*methodSize - header->epilogSize)); + } + + if (hasArgTabOffset) + { + unsigned argTabOffset; + table += decodeUnsigned(table, &argTabOffset); + gcPrintf(" argTabOffset = %x \n", argTabOffset); + } + + { + unsigned cur = 0; + unsigned last = table-bp; + while (cur < last) + { + unsigned amount = last - cur; + if (amount>5) + amount = 5; + + DumpEncoding(bp+cur, amount); + gcPrintf("\n"); + + cur += amount; + } + } + + return (table - tableStart); +} + +/*****************************************************************************/ + +#ifdef _PREFAST_ +#pragma warning(push) +#pragma warning(disable:21000) // Suppress PREFast warning about overly large function +#endif +size_t GCDump::DumpGCTable(PTR_CBYTE table, + const InfoHdr& header, + unsigned methodSize, + bool verifyGCTables) +{ + int sz; + PTR_CBYTE tableStart = table; + PTR_CBYTE bp; + + unsigned count; + unsigned curOffs; + +//#if!TGT_x86 +// _ASSERTE(!"NYI"); +//#endif + + if (verifyGCTables) + _ASSERTE(*castto(table, unsigned short *)++ == 0xBEEF); + + unsigned calleeSavedRegs = 0; + if (header.doubleAlign) + { + calleeSavedRegs = 0; + if (header.ediSaved) calleeSavedRegs++; + if (header.esiSaved) calleeSavedRegs++; + if (header.ebxSaved) calleeSavedRegs++; + } + + /* Dump the untracked frame variable table */ + + count = header.untrackedCnt; + + int lastStkOffs = 0; + while (count-- > 0) + { + int stkOffsDelta; + unsigned lowBits; + + char reg = header.ebpFrame ? 'B' : 'S'; + + sz = (unsigned int)decodeSigned(table, &stkOffsDelta); + int stkOffs = lastStkOffs - stkOffsDelta; + lastStkOffs = stkOffs; + + table = DumpEncoding(table, sz); + + _ASSERTE(0 == ~OFFSET_MASK % sizeof(void*)); + + lowBits = OFFSET_MASK & stkOffs; + stkOffs &= ~OFFSET_MASK; + + assert(!header.doubleAlign || stkOffs >= 0); + + if (header.doubleAlign && + unsigned(stkOffs) >= sizeof(int)*(header.frameSize+calleeSavedRegs)) + { + reg = 'B'; + stkOffs -= sizeof(int)*(header.frameSize+calleeSavedRegs); + _ASSERTE(stkOffs >= (int) (2*sizeof(int))); + } + + if (stkOffs < 0) + gcPrintf(" [E%cP-%02XH] ", reg, -stkOffs); + else + gcPrintf(" [E%cP+%02XH] ", reg, +stkOffs); + + gcPrintf("an untracked %s%s local\n", + (lowBits & pinned_OFFSET_FLAG) ? "pinned " : "", + (lowBits & byref_OFFSET_FLAG) ? "byref" : "" + ); + } + + if (verifyGCTables) + _ASSERTE(*castto(table, unsigned short *)++ == 0xCAFE); + + /* Dump the frame variable lifetime table */ + + count = header.varPtrTableSize; + curOffs = 0; + + while (count-- > 0) + { + unsigned varOffs; + unsigned begOffs; + unsigned endOffs; + unsigned lowBits; + + bp = table; + + table += decodeUnsigned(table, &varOffs); + table += decodeUDelta (table, &begOffs, curOffs); + table += decodeUDelta (table, &endOffs, begOffs); + + DumpEncoding(bp, table-bp); + + _ASSERTE(0 == ~OFFSET_MASK % sizeof(void*)); + + lowBits = varOffs & 0x3; + varOffs &= ~OFFSET_MASK; + + // [EBP+0] is the return address - cant be a var + _ASSERTE(!header.ebpFrame || varOffs); + + curOffs = begOffs; + + DumpOffset(begOffs); + gcPrintf(".."); + DumpOffset(endOffs); + gcPrintf(" [E%s%02XH] a ", header.ebpFrame ? "BP-" : "SP+", + varOffs); + + gcPrintf("%s%s pointer\n", + (lowBits & byref_OFFSET_FLAG) ? "byref " : "", + (lowBits & this_OFFSET_FLAG) ? "this" : "" + ); + + _ASSERTE(endOffs <= methodSize); + } + + if (verifyGCTables) + _ASSERTE(*castto(table, unsigned short *)++ == 0xBABE); + + /* Dump the pointer table */ + + curOffs = 0; + bp = table; + + if (header.interruptible) + { + // + // Dump the Fully Interruptible pointer table + // + unsigned argCnt = 0; + bool isThis = false; + bool iptr = false; + + for (;;) + { + unsigned isPop; + unsigned argOffs; + unsigned val = *table++; + + _ASSERTE(curOffs <= methodSize); + + if (!(val & 0x80)) + { + /* A small 'regPtr' encoding */ + + curOffs += val & 0x7; + + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + gcPrintf(" reg %s becoming %s", RegName(((val >> 3) & 7)), + (val & 0x40) ? "live" + : "dead"); + if (isThis) + gcPrintf(" 'this'"); + if (iptr) + gcPrintf(" (iptr)"); + gcPrintf("\n"); + + isThis = false; + iptr = false; + continue; + } + + /* This is probably an argument push/pop */ + + argOffs = (val & 0x38) >> 3; + + /* 6 [110] and 7 [111] are reserved for other encodings */ + + if (argOffs < 6) + { + /* A small argument encoding */ + + curOffs += (val & 0x07); + isPop = (val & 0x40); + + ARG: + + if (isPop) + { + // A Pop of 0, means little-delta + + if (argOffs != 0) + { + _ASSERTE(header.ebpFrame || argOffs <= argCnt); + + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + + gcPrintf(" pop %2d ", argOffs); + if (!header.ebpFrame) + { + argCnt -= argOffs; + gcPrintf("args (%d)", argCnt); + } + else + gcPrintf("ptrs"); + + gcPrintf("\n"); + } + } + else + { + _ASSERTE(header.ebpFrame || argOffs >= argCnt); + + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + + gcPrintf(" push ptr %2d", argOffs); + if (!header.ebpFrame) + { + argCnt = argOffs+1; + gcPrintf(" (%d)", argCnt); + } + if (isThis) + gcPrintf(" 'this'"); + if (iptr) + gcPrintf(" (iptr)"); + gcPrintf("\n"); + + isThis = false; + iptr = false; + } + + continue; + } + else if (argOffs == 6) + { + if (val & 0x40) + { + /* Bigger delta 000=8,001=16,010=24,...,111=64 */ + + curOffs += (((val & 0x07) + 1) << 3); + } + else + { + /* non-ptr arg push */ + + curOffs += (val & 0x07); + _ASSERTE(!header.ebpFrame); + argCnt++; + + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + + gcPrintf(" push non-ptr (%d)\n", argCnt); + } + + continue; + } + + /* argOffs was 7 [111] which is reserved for the larger encodings */ + + _ASSERTE(argOffs==7); + + switch (val) + { + case 0xFF: + goto DONE_REGTAB; + + case 0xBC: + isThis = true; + break; + + case 0xBF: + iptr = true; + break; + + case 0xB8: + table += decodeUnsigned(table, &val); + curOffs += val; + break; + + case 0xF8: + case 0xFC: + isPop = val & 0x04; + table += decodeUnsigned(table, &argOffs); + goto ARG; + + case 0xFD: + table += decodeUnsigned(table, &argOffs); + assert(argOffs); + + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + + gcPrintf(" kill args %2d\n", argOffs); + break; + + case 0xF9: + table += decodeUnsigned(table, &argOffs); + argCnt += argOffs; + break; + + default: + gcPrintf("Unexpected special code %04X\n", val); + _ASSERTE(!""); + } + } + } + else if (header.ebpFrame) // interruptible is false + { + // + // Dump the Partially Interruptible, EBP-frame method, pointer table + // + + for (;;) + { + unsigned argMask = 0, byrefArgMask = 0; + unsigned regMask, byrefRegMask = 0; + + unsigned argCnt = 0; + PTR_CBYTE argTab = NULL; + unsigned argTabSize; + + unsigned val, nxt; + + /* Get the next byte and check for a 'special' entry */ + + unsigned encType = *table++; + + _ASSERTE(curOffs <= methodSize); + + switch (encType) + { + + default: + + /* A tiny or small call entry */ + + val = encType; + + if ((val & 0x80) == 0x00) + { + if (val & 0x0F) + { + /* A tiny call entry */ + + curOffs += (val & 0x0F); + regMask = (val & 0x70) >> 4; + argMask = 0; + } + else + { + DumpEncoding(bp, table-bp); bp = table; + + gcPrintf(" thisptr in "); + if (val & 0x10) + gcPrintf("EDI\n"); + else if (val & 0x20) + gcPrintf("ESI\n"); + else if (val & 0x40) + gcPrintf("EBX\n"); + else + _ASSERTE(!"Reserved GC encoding"); + + continue; + } + } + else + { + /* A small call entry */ + + curOffs += (val & 0x7F); + val = *table++; + regMask = val >> 5; + argMask = val & 0x1F; + } + break; + + case 0xFD: // medium encoding + + argMask = *table++; + val = *table++; + argMask |= (val & 0xF0) << 4; + nxt = *table++; + curOffs += (val & 0x0F) + ((nxt & 0x1F) << 4); + regMask = nxt >> 5; // EBX,ESI,EDI + + break; + + case 0xF9: // medium encoding with byrefs + + curOffs += *table++; + val = *table++; + argMask = val & 0x1F; + regMask = val >> 5; + val = *table++; + byrefArgMask = val & 0x1F; + byrefRegMask = val >> 5; + + break; + + case 0xFE: // large encoding + case 0xFA: // large encoding with byrefs + + val = *table++; + regMask = val & 0x7; + byrefRegMask= val >> 4; + curOffs += *PTR_DWORD(table); table += sizeof(DWORD); + argMask = *PTR_DWORD(table); table += sizeof(DWORD); + if (encType == 0xFA) // read byrefArgMask + {byrefArgMask = *PTR_DWORD(table); table += sizeof(DWORD);} + + break; + + case 0xFB: // huge encoding + + val = *table++; + regMask = val & 0x7; + byrefRegMask= val >> 4; + curOffs = *PTR_DWORD(table); table += sizeof(DWORD); + argCnt = *PTR_DWORD(table); table += sizeof(DWORD); + argTabSize = *PTR_DWORD(table); table += sizeof(DWORD); + argTab = table; table += argTabSize; + + break; + + case 0xFF: + goto DONE_REGTAB; + } + + /* + Here we have the following values: + + curOffs ... the code offset of the call + regMask ... mask of live pointer register variables + argMask ... bitmask of pushed pointer arguments + byrefRegMask ... byref qualifier for regMask + byrefArgMask ... byrer qualifier for argMask + */ + + _ASSERTE((byrefArgMask & argMask) == byrefArgMask); + _ASSERTE((byrefRegMask & regMask) == byrefRegMask); + + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + + gcPrintf(" call [ "); + + if (regMask & 1) + gcPrintf("EDI%c", (byrefRegMask & 1) ? '\'' : ' '); + if (regMask & 2) + gcPrintf("ESI%c", (byrefRegMask & 2) ? '\'' : ' '); + if (regMask & 4) + gcPrintf("EBX%c", (byrefRegMask & 4) ? '\'' : ' '); + + if (!header.ebpFrame) + { + if (regMask & 8) + gcPrintf("EBP "); + } + + if (argCnt) + { + gcPrintf("] ptrArgs=["); + + do + { + argTab += decodeUnsigned(argTab, &val); + + assert((val & this_OFFSET_FLAG) == 0); + unsigned stkOffs = val & ~byref_OFFSET_FLAG; + unsigned lowBit = val & byref_OFFSET_FLAG; + + gcPrintf("%u%s", stkOffs, lowBit ? "i" : ""); + if (argCnt > 1) + gcPrintf(" "); + } + while (--argCnt); + assert(argTab == table); + + gcPrintf("]"); + } + else + { + gcPrintf("] argMask=%02X", argMask); + + if (byrefArgMask) gcPrintf(" (iargs=%02X)", byrefArgMask); + } + + gcPrintf("\n"); + } + } + else // interruptible is false, ebpFrame is false + { + // + // Dump the Partially Interruptible, EBP-less method, pointer table + // + unsigned lastSkip = 0; + unsigned imask = 0; + + for (;;) + { + unsigned val = *table++; + + _ASSERTE(curOffs <= methodSize); + + if (!(val & 0x80)) + { + if (!(val & 0x40)) + { + if (!(val & 0x20)) + { + // + // push 000DDDDD push one item, 5-bit delta + // + + curOffs += val & 0x1F; + + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + + gcPrintf(" push\n"); + } + else + { + // + // push 00100000 [pushCount] ESP push multiple items + // + + unsigned pushCount; + + assert(val == 0x20); + table += decodeUnsigned(table, &pushCount); + + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + + gcPrintf(" push %d\n", pushCount); + } + } + else + { + unsigned popSize; + unsigned skip; + + if ((val & 0x3f) == 0) + { + // + // skip 01000000 [Delta] Skip arbitrary sized delta + // + + table += decodeUnsigned(table, &skip); + curOffs += skip; + lastSkip = skip; + } + else + { + // + // pop 01CCDDDD pop CC items, 4-bit delta + // + + popSize = (val & 0x30) >> 4; + skip = val & 0x0f; + curOffs += skip; + + if (popSize > 0) + { + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + + gcPrintf(" pop %d\n", popSize); + } + else + lastSkip = skip; + } + } + } + else + { + unsigned callArgCnt; + unsigned callRegMask; + bool callPndTab = false; + unsigned callPndMask = 0; + unsigned callPndTabCnt = 0, callPndTabSize = 0; + + switch ((val & 0x70) >> 4) + { + default: + // + // call 1PPPPPPP Call Pattern, P=[0..79] + // + decodeCallPattern((val & 0x7f), &callArgCnt, &callRegMask, + &callPndMask, &lastSkip); + curOffs += lastSkip; + + PRINT_CALL: + + DumpEncoding(bp, table-bp); bp = table; + DumpOffsetEx(curOffs); + + gcPrintf(" call %d [ ", callArgCnt); + + unsigned iregMask, iargMask; + + iregMask = imask & 0xF; + iargMask = imask >> 4; + + assert((callRegMask & 0x0F) == callRegMask); + if (callRegMask & 1) + gcPrintf("EDI%c", (iregMask & 1) ? '\'' : ' '); + if (callRegMask & 2) + gcPrintf("ESI%c", (iregMask & 2) ? '\'' : ' '); + if (callRegMask & 4) + gcPrintf("EBX%c", (iregMask & 4) ? '\'' : ' '); + if (callRegMask & 8) + gcPrintf("EBP%c", (iregMask & 8) ? '\'' : ' '); + gcPrintf("]"); + + if (callPndTab) + { +#if defined(_DEBUG) && !defined(STRIKE) + // note: _ASSERTE is a no-op for strike + PTR_CBYTE offsStart = table; +#endif + gcPrintf(" argOffs(%d) =", callPndTabCnt); + for (unsigned i=0; i < callPndTabCnt; i++) + { + unsigned pndOffs; + table += decodeUnsigned(table, &pndOffs); + gcPrintf(" %4X", pndOffs); + } + _ASSERTE(offsStart + callPndTabSize == table); + bp = table; + } + else + { + if (callPndMask) + gcPrintf(" argMask=%02X", callPndMask); + if (iargMask) + gcPrintf(" (iargs=%02X)", iargMask); + } + gcPrintf("\n"); + + imask = lastSkip = 0; + break; + + case 5: + // + // call 1101RRRR DDCCCMMM Call RegMask=RRRR,ArgCnt=CCC, + // ArgMask=MMM Delta=commonDelta[DD] + // + callRegMask = val & 0xf; // EBP,EBX,ESI,EDI + val = *table++; + callPndMask = (val & 0x7); + callArgCnt = (val >> 3) & 0x7; + lastSkip = callCommonDelta[val>>6]; + curOffs += lastSkip; + + goto PRINT_CALL; + + case 6: + // + // call 1110RRRR [ArgCnt] [ArgMask] + // Call ArgCnt,RegMask=RRR,ArgMask + // + callRegMask = val & 0xf; // EBP,EBX,ESI,EDI + table += decodeUnsigned(table, &callArgCnt); + table += decodeUnsigned(table, &callPndMask); + goto PRINT_CALL; + + case 7: + switch (val & 0x0C) + { + case 0x00: + assert(val == 0xF0); + /* iptr 11110000 [IPtrMask] Arbitrary Interior Pointer Mask */ + table += decodeUnsigned(table, &imask); + DumpEncoding(bp, table-bp); bp = table; + gcPrintf(" iptrMask = %02X\n", imask); + break; + + case 0x04: + DumpEncoding(bp, table-bp); bp = table; + gcPrintf(" thisptr in %s\n", CalleeSavedRegName(val&0x3)); + break; + + case 0x08: + val = *table++; + callRegMask = val & 0xF; + imask = val >> 4; + lastSkip = *PTR_DWORD(table); table += sizeof(DWORD); + curOffs += lastSkip; + callArgCnt = *PTR_DWORD(table); table += sizeof(DWORD); + callPndTabCnt = *PTR_DWORD(table); table += sizeof(DWORD); + callPndTabSize = *PTR_DWORD(table); table += sizeof(DWORD); + callPndTab = true; + goto PRINT_CALL; + + case 0x0C: + assert(val==0xff); + goto DONE_REGTAB; + break; + + default: + _ASSERTE(!"reserved GC encoding"); + break; + } + break; + } + } + } + } + +DONE_REGTAB: + + _ASSERTE(curOffs <= methodSize); + + if (verifyGCTables) + _ASSERTE(*castto(table, unsigned short *)++ == 0xBEEB); + + _ASSERTE(table > bp); + + DumpEncoding(bp, table-bp); +// gcPrintf(" "); + gcPrintf("\n"); + + return (table - tableStart); +} +#ifdef _PREFAST_ +#pragma warning(pop) +#endif + + +/*****************************************************************************/ + +void GCDump::DumpPtrsInFrame(PTR_CBYTE infoBlock, + PTR_CBYTE codeBlock, + unsigned offs, + bool verifyGCTables) +{ + PTR_CBYTE table = infoBlock; + + size_t methodSize; + size_t stackSize; + size_t prologSize; + size_t epilogSize; + unsigned epilogCnt; + BOOL epilogEnd; + size_t argSize; + BOOL secCheck; + BOOL dblAlign; + + if (verifyGCTables) + _ASSERTE(*castto(table, unsigned short *)++ == 0xFEEF); + + /* Get hold of the method size */ + + unsigned int methodSizeTemp; + table += decodeUnsigned(table, &methodSizeTemp); + methodSize = methodSizeTemp; + + // + // New style InfoBlk Header + // + // Typically only uses one-byte to store everything. + // + InfoHdr header; + table = decodeHeader(table, &header); + + if (header.untrackedCnt == HAS_UNTRACKED) + { + unsigned count; + table += decodeUnsigned(table, &count); + header.untrackedCnt = count; + } + if (header.varPtrTableSize == HAS_VARPTR) + { + unsigned count; + table += decodeUnsigned(table, &count); + header.varPtrTableSize = count; + } + if (header.gsCookieOffset == HAS_GS_COOKIE_OFFSET) + { + unsigned offset; + table += decodeUnsigned(table, &offset); + header.gsCookieOffset = offset; + _ASSERTE(offset != INVALID_GS_COOKIE_OFFSET); + } + if (header.syncStartOffset == HAS_SYNC_OFFSET) + { + unsigned offset; + table += decodeUnsigned(table, &offset); + header.syncStartOffset = offset; + _ASSERTE(offset != INVALID_SYNC_OFFSET); + table += decodeUnsigned(table, &offset); + header.syncEndOffset = offset; + _ASSERTE(offset != INVALID_SYNC_OFFSET); + } + + prologSize = header.prologSize; + epilogSize = header.epilogSize; + epilogCnt = header.epilogCount; + epilogEnd = header.epilogAtEnd; + secCheck = header.security; + dblAlign = header.doubleAlign; + argSize = header.argCount * 4; + stackSize = header.frameSize; + +#ifdef DEBUG + if (offs == 0) + { + gcPrintf(" method size = %04X\n", methodSize); + gcPrintf(" stack frame size = %3u \n", stackSize); + gcPrintf(" prolog size = %3u \n", prologSize); + gcPrintf(" epilog size = %3u \n", epilogSize); + gcPrintf(" epilog end = %s \n", epilogEnd ? "yes" : "no"); + gcPrintf(" epilog count = %3u \n", epilogCnt ); + gcPrintf(" security = %s \n", secCheck ? "yes" : "no"); + gcPrintf(" dblAlign = %s \n", dblAlign ? "yes" : "no"); + gcPrintf(" untracked count = %3u \n", header.untrackedCnt); + gcPrintf(" var ptr tab count= %3u \n", header.varPtrTableSize); + gcPrintf("\n"); + } +#endif + + /* Are we within the prolog of the method? */ + + if (offs < prologSize) + { + gcPrintf(" Offset %04X is within the method's prolog\n", offs); + return; + } + + /* Are we within an epilog of the method? */ + + if (epilogCnt) + { + unsigned eps; + + if (epilogCnt > 1 || !epilogEnd) + { + if (verifyGCTables) + _ASSERTE(*castto(table, unsigned short *)++ == 0xFACE); + + unsigned prevEps = 0; + for (unsigned i = 0; i < epilogCnt; i++) + { + table += decodeUDelta(table, &eps, prevEps); + + if ((offs >= eps) && (offs < eps + epilogSize)) + goto EPILOG_MSG; + } + } + else + { + eps = (int)(methodSize - epilogSize); + if ((offs >= eps) && (offs < eps + epilogSize)) + { +EPILOG_MSG: gcPrintf(" Offset %04X is within the method's epilog" + " (%02X bytes into it)\n", offs, offs - eps); + return; + } + } + } + gcPrintf(" Offset %04X is within the method's body\n", offs); +} + +/*****************************************************************************/ +#endif // _TARGET_X86_ +/*****************************************************************************/ |