public GcSlotTable(byte[] image, InfoHdrSmall header, ref int offset) { GcSlots = new List <GcSlot>(); DecodeUntracked(image, header, ref offset); DecodeFrameVariableLifetimeTable(image, header, ref offset); }
/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/gcdump/i386/gcdumpx86.cpp">GCDump::DumpGCTable</a> /// </summary> private void DecodeUntracked(byte[] image, InfoHdrSmall header, ref int offset) { uint calleeSavedRegs = 0; if (header.DoubleAlign) { calleeSavedRegs = 0; if (header.EdiSaved) { calleeSavedRegs++; } if (header.EsiSaved) { calleeSavedRegs++; } if (header.EbxSaved) { calleeSavedRegs++; } } uint count = header.UntrackedCnt; int lastStkOffs = 0; while (count-- > 0) { int stkOffsDelta; int lowBits; char reg = header.EbpFrame ? 'B' : 'S'; stkOffsDelta = NativeReader.DecodeSignedGc(image, ref offset); int stkOffs = lastStkOffs - stkOffsDelta; lastStkOffs = stkOffs; lowBits = (int)OFFSET_MASK & stkOffs; stkOffs = (int)((uint)stkOffs & ~OFFSET_MASK); if (header.DoubleAlign && (uint)stkOffs >= sizeof(int) * (header.FrameSize + calleeSavedRegs)) { reg = 'B'; stkOffs -= sizeof(int) * (int)(header.FrameSize + calleeSavedRegs); } GcSlots.Add(new GcSlot(GcSlots.Count, $"E{reg}P", stkOffs, lowBits, GcSlotFlags.GC_SLOT_UNTRACKED)); } }
/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/gcdump/i386/gcdumpx86.cpp">GCDump::DumpGCTable</a> /// </summary> private void DecodeFrameVariableLifetimeTable(byte[] image, InfoHdrSmall header, ref int offset) { uint count = header.VarPtrTableSize; uint curOffs = 0; while (count-- > 0) { uint varOffs = NativeReader.DecodeUnsignedGc(image, ref offset); uint begOffs = NativeReader.DecodeUDelta(image, ref offset, curOffs); uint endOffs = NativeReader.DecodeUDelta(image, ref offset, begOffs); uint lowBits = varOffs & 0x3; varOffs &= ~OFFSET_MASK; curOffs = begOffs; string reg = header.EbpFrame ? "BP" : "SP"; GcSlots.Add(new GcSlot(GcSlots.Count, reg, (int)begOffs, (int)endOffs, (int)varOffs, (int)lowBits, GcSlotFlags.GC_SLOT_BASE)); } }
/// <summary> /// Initialize the GcInfo header /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/inc/gcdecoder.cpp">src\inc\gcdecoder.cpp</a> DecodeHeader and <a href="https://github.com/dotnet/coreclr/blob/master/src/gcdump/i386/gcdumpx86.cpp">GCDump::DumpInfoHdr</a> /// </summary> public static InfoHdrSmall DecodeHeader(byte[] image, ref int offset, int codeLength) { byte nextByte = image[offset++]; byte encoding = (byte)(nextByte & 0x7f); InfoHdrSmall header = GetInfoHdr(encoding); while ((nextByte & (uint)InfoHdrAdjustConstants.MORE_BYTES_TO_FOLLOW) != 0) { nextByte = image[offset++]; encoding = (byte)(nextByte & (uint)InfoHdrAdjustConstants.ADJ_ENCODING_MAX); if (encoding < (uint)InfoHdrAdjust.NEXT_FOUR_START) { if (encoding < (uint)InfoHdrAdjust.SET_ARGCOUNT) { header.FrameSize = (byte)(encoding - (uint)InfoHdrAdjust.SET_FRAMESIZE); } else if (encoding < (uint)InfoHdrAdjust.SET_PROLOGSIZE) { header.ArgCount = (byte)(encoding - (uint)InfoHdrAdjust.SET_ARGCOUNT); } else if (encoding < (uint)InfoHdrAdjust.SET_EPILOGSIZE) { header.PrologSize = (byte)(encoding - (uint)InfoHdrAdjust.SET_PROLOGSIZE); } else if (encoding < (uint)InfoHdrAdjust.SET_EPILOGCNT) { header.EpilogSize = (byte)(encoding - (uint)InfoHdrAdjust.SET_EPILOGSIZE); } else if (encoding < (uint)InfoHdrAdjust.SET_UNTRACKED) { header.EpilogCount = (byte)((encoding - (uint)InfoHdrAdjust.SET_EPILOGCNT) / 2); header.EpilogAtEnd = ((encoding - (uint)InfoHdrAdjust.SET_EPILOGCNT) & 1) == 1 ? true : false; } else if (encoding < (uint)InfoHdrAdjust.FIRST_FLIP) { header.UntrackedCnt = (byte)(encoding - (uint)InfoHdrAdjust.SET_UNTRACKED); } else { switch (encoding) { case (byte)InfoHdrAdjust.FLIP_EDI_SAVED: header.EdiSaved = !header.EdiSaved; break; case (byte)InfoHdrAdjust.FLIP_ESI_SAVED: header.EsiSaved = !header.EsiSaved; break; case (byte)InfoHdrAdjust.FLIP_EBX_SAVED: header.EbxSaved = !header.EbxSaved; break; case (byte)InfoHdrAdjust.FLIP_EBP_SAVED: header.EbpSaved = !header.EbpSaved; break; case (byte)InfoHdrAdjust.FLIP_EBP_FRAME: header.EbpFrame = !header.EbpFrame; break; case (byte)InfoHdrAdjust.FLIP_INTERRUPTIBLE: header.Interruptible = !header.Interruptible; break; case (byte)InfoHdrAdjust.FLIP_DOUBLE_ALIGN: header.DoubleAlign = !header.DoubleAlign; break; case (byte)InfoHdrAdjust.FLIP_SECURITY: header.Security = !header.Security; break; case (byte)InfoHdrAdjust.FLIP_HANDLERS: header.Handlers = !header.Handlers; break; case (byte)InfoHdrAdjust.FLIP_LOCALLOC: header.Localloc = !header.Localloc; break; case (byte)InfoHdrAdjust.FLIP_EDITnCONTINUE: header.EditNcontinue = !header.EditNcontinue; break; case (byte)InfoHdrAdjust.FLIP_VAR_PTR_TABLE_SZ: header.VarPtrTableSize ^= HAS_VARPTR; break; case (byte)InfoHdrAdjust.FFFF_UNTRACKED_CNT: header.UntrackedCnt = HAS_UNTRACKED; break; case (byte)InfoHdrAdjust.FLIP_VARARGS: header.Varargs = !header.Varargs; break; case (byte)InfoHdrAdjust.FLIP_PROF_CALLBACKS: header.ProfCallbacks = !header.ProfCallbacks; break; case (byte)InfoHdrAdjust.FLIP_HAS_GENERICS_CONTEXT: header.GenericsContext ^= 1; break; case (byte)InfoHdrAdjust.FLIP_GENERICS_CONTEXT_IS_METHODDESC: header.GenericsContextIsMethodDesc ^= 1; break; case (byte)InfoHdrAdjust.FLIP_HAS_GS_COOKIE: header.GsCookieOffset ^= HAS_GS_COOKIE_OFFSET; break; case (byte)InfoHdrAdjust.FLIP_SYNC: header.SyncStartOffset ^= HAS_SYNC_OFFSET; break; case (byte)InfoHdrAdjust.FLIP_REV_PINVOKE_FRAME: header.RevPInvokeOffset ^= HAS_REV_PINVOKE_FRAME_OFFSET; break; case (byte)InfoHdrAdjust.NEXT_OPCODE: encoding = (byte)(image[offset++] & (int)InfoHdrAdjustConstants.ADJ_ENCODING_MAX); // encoding here always corresponds to codes in InfoHdrAdjust2 set if (encoding < (int)InfoHdrAdjustConstants.SET_RET_KIND_MAX) { header.ReturnKind = (ReturnKinds)encoding; } else { throw new BadImageFormatException("Unexpected gcinfo header encoding"); } break; default: throw new BadImageFormatException("Unexpected gcinfo header encoding"); } } } else { byte lowBits; switch (encoding >> 4) { case 5: lowBits = (byte)(encoding & 0xf); header.FrameSize <<= 4; header.FrameSize += lowBits; break; case 6: lowBits = (byte)(encoding & 0xf); header.ArgCount <<= 4; header.ArgCount += lowBits; break; case 7: if ((encoding & 0x8) == 0) { lowBits = (byte)(encoding & 0x7); header.PrologSize <<= 3; header.PrologSize += lowBits; } else { lowBits = (byte)(encoding & 0x7); header.EpilogSize <<= 3; header.EpilogSize += lowBits; } break; default: throw new BadImageFormatException("Unexpected gcinfo header encoding"); } } } if (header.UntrackedCnt == HAS_UNTRACKED) { header.HasArgTabOffset = true; header.UntrackedCnt = NativeReader.DecodeUnsignedGc(image, ref offset); } if (header.VarPtrTableSize == HAS_VARPTR) { header.HasArgTabOffset = true; header.VarPtrTableSize = NativeReader.DecodeUnsignedGc(image, ref offset); } if (header.GsCookieOffset == HAS_GS_COOKIE_OFFSET) { header.GsCookieOffset = NativeReader.DecodeUnsignedGc(image, ref offset); } if (header.SyncStartOffset == HAS_SYNC_OFFSET) { header.SyncStartOffset = NativeReader.DecodeUnsignedGc(image, ref offset); header.SyncEndOffset = NativeReader.DecodeUnsignedGc(image, ref offset); } if (header.RevPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET) { header.RevPInvokeOffset = NativeReader.DecodeUnsignedGc(image, ref offset); } header.Epilogs = new List <int>(); if (header.EpilogCount > 1 || (header.EpilogCount != 0 && !header.EpilogAtEnd)) { uint offs = 0; for (int i = 0; i < header.EpilogCount; i++) { offs = NativeReader.DecodeUDelta(image, ref offset, offs); header.Epilogs.Add((int)offs); } } else { if (header.EpilogCount != 0) { header.Epilogs.Add(codeLength - (int)header.EpilogSize); } } if (header.HasArgTabOffset) { header.ArgTabOffset = NativeReader.DecodeUnsignedGc(image, ref offset); } return(header); }