Example #1
0
        public GcSlotTable(byte[] image, InfoHdrSmall header, ref int offset)
        {
            GcSlots = new List <GcSlot>();

            DecodeUntracked(image, header, ref offset);
            DecodeFrameVariableLifetimeTable(image, header, ref offset);
        }
Example #2
0
        /// <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));
            }
        }
Example #3
0
        /// <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));
            }
        }
Example #4
0
        /// <summary>
        /// Initialize the GcInfo header
        /// based on <a href="https://github.com/dotnet/runtime/blob/main/src/coreclr/inc/gcdecoder.cpp">src\inc\gcdecoder.cpp</a> DecodeHeader and <a href="https://github.com/dotnet/runtime/blob/main/src/coreclr/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:
                            nextByte = image[offset++];
                            encoding = (byte)(nextByte & (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);
        }