コード例 #1
0
        /// <summary>
        /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/gcdump/i386/gcdumpx86.cpp">GCDump::DumpGCTable</a>
        /// </summary>
        public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion)
        {
            Offset = offset;

            CodeLength = (int)NativeReader.DecodeUnsignedGc(image, ref offset);

            Header = InfoHdrDecoder.DecodeHeader(image, ref offset, CodeLength);

            SlotTable = new GcSlotTable(image, Header, ref offset);

            Transitions = new Dictionary <int, List <BaseGcTransition> >();
            if (Header.Interruptible)
            {
                GetTransitionsFullyInterruptible(image, ref offset);
            }
            else if (Header.EbpFrame)
            {
                GetTransitionsEbpFrame(image, ref offset);
            }
            else
            {
                GetTransitionsNoEbp(image, ref offset);
            }

            Size = offset - Offset;
        }
コード例 #2
0
        public UnwindInfo(byte[] image, int offset)
        {
            int startOffset = offset;

            FunctionLength = NativeReader.DecodeUnsignedGc(image, ref offset);
            Size           = offset - startOffset;
        }
コード例 #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));
            }
        }
コード例 #4
0
        /// <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;
        }
コード例 #5
0
ファイル: UnwindInfo.cs プロジェクト: xwjonas/coreclr
 public UnwindInfo(byte[] image, int offset)
 {
     FunctionLength = NativeReader.DecodeUnsignedGc(image, ref offset);
     Size           = sizeof(int);
 }
コード例 #6
0
        private void GetTransitionsNoEbp(byte[] image, ref int offset)
        {
            uint curOffs  = 0;
            uint lastSkip = 0;
            uint imask    = 0;

            for (; ;)
            {
                uint val = image[offset++];

                if ((val & 0x80) == 0)
                {
                    if ((val & 0x40) == 0)
                    {
                        if ((val & 0x20) == 0)
                        {
                            // push    000DDDDD          push one item, 5-bit delta
                            curOffs += val & 0x1F;
                            AddNewTransition(new GcTransitionRegister((int)curOffs, Registers.ESP, Action.PUSH));
                        }
                        else
                        {
                            // push    00100000 [pushCount]     ESP push multiple items
                            uint pushCount = NativeReader.DecodeUnsignedGc(image, ref offset);
                            AddNewTransition(new GcTransitionRegister((int)curOffs, Registers.ESP, Action.PUSH, false, false, (int)pushCount));
                        }
                    }
                    else
                    {
                        uint popSize;
                        uint skip;

                        if ((val & 0x3f) == 0)
                        {
                            //
                            // skip    01000000 [Delta]  Skip arbitrary sized delta
                            //
                            skip     = NativeReader.DecodeUnsignedGc(image, ref offset);
                            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)
                            {
                                AddNewTransition(new GcTransitionRegister((int)curOffs, Registers.ESP, Action.POP, false, false, (int)popSize));
                            }
                            else
                            {
                                lastSkip = skip;
                            }
                        }
                    }
                }
                else
                {
                    uint callArgCnt;
                    uint callRegMask;
                    bool callPndTab = false;
                    uint callPndMask = 0;
                    uint callPndTabCnt = 0, callPndTabSize = 0;

                    switch ((val & 0x70) >> 4)
                    {
                    default:
                        //
                        // call    1PPPPPPP          Call Pattern, P=[0..79]
                        //
                        CallPattern.DecodeCallPattern((val & 0x7f), out callArgCnt, out callRegMask, out callPndMask, out lastSkip);
                        curOffs += lastSkip;
                        SaveCallTransition(image, ref offset, val, curOffs, callRegMask, callPndTab, callPndTabCnt, callPndMask, lastSkip, ref imask);
                        break;

                    case 5:
                        //
                        // call    1101RRRR DDCCCMMM  Call RegMask=RRRR,ArgCnt=CCC,
                        //                        ArgMask=MMM Delta=commonDelta[DD]
                        //
                        callRegMask = val & 0xf;        // EBP,EBX,ESI,EDI
                        val         = image[offset++];
                        callPndMask = (val & 0x7);
                        callArgCnt  = (val >> 3) & 0x7;
                        lastSkip    = CallPattern.callCommonDelta[val >> 6];
                        curOffs    += lastSkip;
                        SaveCallTransition(image, ref offset, val, curOffs, callRegMask, callPndTab, callPndTabCnt, callPndMask, lastSkip, ref imask);
                        break;

                    case 6:
                        //
                        // call    1110RRRR [ArgCnt] [ArgMask]
                        //                          Call ArgCnt,RegMask=RRR,ArgMask
                        //
                        callRegMask = val & 0xf;        // EBP,EBX,ESI,EDI
                        callArgCnt  = NativeReader.DecodeUnsignedGc(image, ref offset);
                        callPndMask = NativeReader.DecodeUnsignedGc(image, ref offset);
                        SaveCallTransition(image, ref offset, val, curOffs, callRegMask, callPndTab, callPndTabCnt, callPndMask, lastSkip, ref imask);
                        break;

                    case 7:
                        switch (val & 0x0C)
                        {
                        case 0x00:
                            //  iptr 11110000 [IPtrMask] Arbitrary Interior Pointer Mask
                            imask = NativeReader.DecodeUnsignedGc(image, ref offset);
                            AddNewTransition(new IPtrMask((int)curOffs, imask));
                            break;

                        case 0x04:
                            AddNewTransition(new CalleeSavedRegister((int)curOffs, (CalleeSavedRegisters)(val & 0x3)));
                            break;

                        case 0x08:
                            val            = image[offset++];
                            callRegMask    = val & 0xF;
                            imask          = val >> 4;
                            lastSkip       = NativeReader.ReadUInt32(image, ref offset);
                            curOffs       += lastSkip;
                            callArgCnt     = NativeReader.ReadUInt32(image, ref offset);
                            callPndTabCnt  = NativeReader.ReadUInt32(image, ref offset);
                            callPndTabSize = NativeReader.ReadUInt32(image, ref offset);
                            callPndTab     = true;
                            SaveCallTransition(image, ref offset, val, curOffs, callRegMask, callPndTab, callPndTabCnt, callPndMask, lastSkip, ref imask);
                            break;

                        case 0x0C:
                            return;

                        default:
                            throw new BadImageFormatException("Invalid GC encoding");
                        }
                        break;
                    }
                }
            }
        }
コード例 #7
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;
                    }
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/gcdump/i386/gcdumpx86.cpp">GCDump::DumpGCTable</a>
        /// </summary>
        private void GetTransitionsFullyInterruptible(byte[] image, ref int offset)
        {
            uint argCnt  = 0;
            bool isThis  = false;
            bool iptr    = false;
            uint curOffs = 0;

            while (true)
            {
                uint isPop;
                uint argOffs;
                uint val = image[offset++];

                if ((val & 0x80) == 0)
                {
                    /* A small 'regPtr' encoding */

                    curOffs += val & 0x7;

                    Action isLive = Action.LIVE;
                    if ((val & 0x40) == 0)
                    {
                        isLive = Action.DEAD;
                    }
                    AddNewTransition(new GcTransitionRegister((int)curOffs, (Registers)((val >> 3) & 7), isLive, isThis, iptr));

                    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);

                    ArgEncoding(image, ref isPop, ref argOffs, ref argCnt, ref curOffs, ref isThis, ref iptr);

                    continue;
                }
                else if (argOffs == 6)
                {
                    if ((val & 0x40) != 0)
                    {
                        curOffs += (((val & 0x07) + 1) << 3);
                    }
                    else
                    {
                        // non-ptr arg push

                        curOffs += (val & 0x07);
                        argCnt++;
                        AddNewTransition(new GcTransitionPointer((int)curOffs, argOffs, argCnt, Action.PUSH, Header.EbpFrame, false, false, false));
                    }

                    continue;
                }

                // argOffs was 7 [111] which is reserved for the larger encodings
                switch (val)
                {
                case 0xFF:
                    return;

                case 0xBC:
                    isThis = true;
                    break;

                case 0xBF:
                    iptr = true;
                    break;

                case 0xB8:
                    val      = NativeReader.DecodeUnsignedGc(image, ref offset);
                    curOffs += val;
                    break;

                case 0xF8:
                case 0xFC:
                    isPop   = val & 0x04;
                    argOffs = NativeReader.DecodeUnsignedGc(image, ref offset);
                    ArgEncoding(image, ref isPop, ref argOffs, ref argCnt, ref curOffs, ref isThis, ref iptr);
                    break;

                case 0xFD:
                    argOffs = NativeReader.DecodeUnsignedGc(image, ref offset);
                    AddNewTransition(new GcTransitionPointer((int)curOffs, argOffs, argCnt, Action.KILL, Header.EbpFrame));
                    break;

                case 0xF9:
                    argOffs = NativeReader.DecodeUnsignedGc(image, ref offset);
                    argCnt += argOffs;
                    break;

                default:
                    throw new BadImageFormatException($"Unexpected special code {val}");
                }
            }
        }
コード例 #9
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);
        }