/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/gcdump/i386/gcdumpx86.cpp">GCDump::DumpGCTable</a> /// </summary> private void SaveCallTransition(byte[] image, ref int offset, uint val, uint curOffs, uint callRegMask, bool callPndTab, uint callPndTabCnt, uint callPndMask, uint lastSkip, ref uint imask) { uint iregMask, iargMask; iregMask = imask & 0xF; iargMask = imask >> 4; GcTransitionCall transition = new GcTransitionCall((int)curOffs, Header.EbpFrame, callRegMask, iregMask); AddNewTransition(transition); if (callPndTab) { for (int i = 0; i < callPndTabCnt; i++) { uint pndOffs = NativeReader.DecodeUnsignedGc(image, ref offset); uint stkOffs = val & ~byref_OFFSET_FLAG; uint lowBit = val & byref_OFFSET_FLAG; transition.PtrArgs.Add(new GcTransitionCall.PtrArg(pndOffs, 0)); } } else { if (callPndMask != 0) { transition.ArgMask = callPndMask; } if (iargMask != 0) { transition.IArgs = iargMask; } } imask = lastSkip = 0; }
/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/gcdump/i386/gcdumpx86.cpp">GCDump::DumpGCTable</a> /// </summary> private void GetTransitionsEbpFrame(byte[] image, ref int offset) { while (true) { uint argMask = 0, byrefArgMask = 0; uint regMask, byrefRegMask = 0; uint argCnt = 0; int argOffset = offset; uint argTabSize; uint val, nxt; uint curOffs = 0; // Get the next byte and check for a 'special' entry uint encType = image[offset++]; GcTransitionCall transition = null; switch (encType) { default: // A tiny or small call entry val = encType; if ((val & 0x80) == 0x00) { if ((val & 0x0F) != 0) { // A tiny call entry curOffs += (val & 0x0F); regMask = (val & 0x70) >> 4; argMask = 0; } else { Registers reg; if ((val & 0x10) != 0) { reg = Registers.EDI; } else if ((val & 0x20) != 0) { reg = Registers.ESI; } else if ((val & 0x40) != 0) { reg = Registers.EBX; } else { throw new BadImageFormatException("Invalid register"); } transition = new GcTransitionCall((int)curOffs); transition.CallRegisters.Add(new GcTransitionCall.CallRegister(reg, false)); AddNewTransition(transition); continue; } } else { // A small call entry curOffs += (val & 0x7F); val = image[offset++]; regMask = val >> 5; argMask = val & 0x1F; } break; case 0xFD: // medium encoding argMask = image[offset++]; val = image[offset++]; argMask |= (val & 0xF0) << 4; nxt = image[offset++]; curOffs += (val & 0x0F) + ((nxt & 0x1F) << 4); regMask = nxt >> 5; // EBX,ESI,EDI break; case 0xF9: // medium encoding with byrefs curOffs += image[offset++]; val = image[offset++]; argMask = val & 0x1F; regMask = val >> 5; val = image[offset++]; byrefArgMask = val & 0x1F; byrefRegMask = val >> 5; break; case 0xFE: // large encoding case 0xFA: // large encoding with byrefs val = image[offset++]; regMask = val & 0x7; byrefRegMask = val >> 4; curOffs += NativeReader.ReadUInt32(image, ref offset); argMask = NativeReader.ReadUInt32(image, ref offset); if (encType == 0xFA) // read byrefArgMask { byrefArgMask = NativeReader.ReadUInt32(image, ref offset); } break; case 0xFB: // huge encoding val = image[offset++]; regMask = val & 0x7; byrefRegMask = val >> 4; curOffs = NativeReader.ReadUInt32(image, ref offset); argCnt = NativeReader.ReadUInt32(image, ref offset); argTabSize = NativeReader.ReadUInt32(image, ref offset); argOffset = offset; offset += (int)argTabSize; break; case 0xFF: return; } /* * 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 */ transition = new GcTransitionCall((int)curOffs, Header.EbpFrame, regMask, byrefRegMask); AddNewTransition(transition); if (argCnt != 0) { do { val = NativeReader.DecodeUnsignedGc(image, ref argOffset); uint stkOffs = val & ~byref_OFFSET_FLAG; uint lowBit = val & byref_OFFSET_FLAG; transition.PtrArgs.Add(new GcTransitionCall.PtrArg(stkOffs, lowBit)); }while (--argCnt > 0); } else { transition.ArgMask = argMask; if (byrefArgMask != 0) { transition.IArgs = byrefArgMask; } } } }