예제 #1
0
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            int iiOffset             = _startOffset;
            int sizeOfInlineIndex    = NativeReader.ReadInt32(_r2r.Image, ref iiOffset);
            int inlineIndexEndOffset = iiOffset + sizeOfInlineIndex;

            while (iiOffset < inlineIndexEndOffset)
            {
                int inlineeRid     = NativeReader.ReadInt32(_r2r.Image, ref iiOffset);
                int inlinersOffset = NativeReader.ReadInt32(_r2r.Image, ref iiOffset);
                sb.AppendLine($"Inliners for inlinee {RidToMethodDef(inlineeRid):X8}:");
                var  inlinersReader  = new NibbleReader(_r2r.Image, inlineIndexEndOffset + inlinersOffset);
                uint sameModuleCount = inlinersReader.ReadUInt();

                int baseRid = 0;
                for (uint i = 0; i < sameModuleCount; i++)
                {
                    int currentRid = baseRid + (int)inlinersReader.ReadUInt();
                    sb.AppendLine($"  {RidToMethodDef(currentRid):X8}");
                    baseRid = currentRid;
                }
            }

            return(sb.ToString());
        }
예제 #2
0
        /// <summary>
        /// Parse core header fields common to global R2R file header and per assembly headers in composite R2R images.
        /// </summary>
        /// <param name="image">PE image</param>
        /// <param name="curOffset">Index in the image byte array to the start of the ReadyToRun core header</param>
        public void ParseCoreHeader(byte[] image, ref int curOffset)
        {
            Flags = NativeReader.ReadUInt32(image, ref curOffset);
            int nSections = NativeReader.ReadInt32(image, ref curOffset);

            Sections = new Dictionary <ReadyToRunSectionType, ReadyToRunSection>();

            for (int i = 0; i < nSections; i++)
            {
                int type        = NativeReader.ReadInt32(image, ref curOffset);
                var sectionType = (ReadyToRunSectionType)type;
                if (!Enum.IsDefined(typeof(ReadyToRunSectionType), type))
                {
                    Console.WriteLine("Warning: Invalid ReadyToRun section type");
                }
                int sectionStartRva = NativeReader.ReadInt32(image, ref curOffset);
                int sectionLength   = NativeReader.ReadInt32(image, ref curOffset);
                Sections[sectionType] = new ReadyToRunSection(sectionType, sectionStartRva, sectionLength);
            }
        }
예제 #3
0
        /// <summary>
        /// Initializes the fields of the R2RHeader
        /// </summary>
        /// <param name="image">PE image</param>
        /// <param name="rva">Relative virtual address of the ReadyToRun header</param>
        /// <param name="curOffset">Index in the image byte array to the start of the ReadyToRun header</param>
        /// <exception cref="BadImageFormatException">The signature must be 0x00525452</exception>
        public ReadyToRunHeader(byte[] image, int rva, int curOffset)
        {
            RelativeVirtualAddress = rva;
            int startOffset = curOffset;

            byte[] signature = new byte[sizeof(uint) - 1]; // -1 removes the null character at the end of the cstring
            Array.Copy(image, curOffset, signature, 0, sizeof(uint) - 1);
            SignatureString = Encoding.UTF8.GetString(signature);
            Signature       = NativeReader.ReadUInt32(image, ref curOffset);
            if (Signature != READYTORUN_SIGNATURE)
            {
                throw new System.BadImageFormatException("Incorrect R2R header signature: " + SignatureString);
            }

            MajorVersion = NativeReader.ReadUInt16(image, ref curOffset);
            MinorVersion = NativeReader.ReadUInt16(image, ref curOffset);
            Flags        = NativeReader.ReadUInt32(image, ref curOffset);
            int nSections = NativeReader.ReadInt32(image, ref curOffset);

            Sections = new Dictionary <ReadyToRunSection.SectionType, ReadyToRunSection>();

            for (int i = 0; i < nSections; i++)
            {
                int type        = NativeReader.ReadInt32(image, ref curOffset);
                var sectionType = (ReadyToRunSection.SectionType)type;
                if (!Enum.IsDefined(typeof(ReadyToRunSection.SectionType), type))
                {
                    // TODO (refactoring) - what should we do?
                    // R2RDump.WriteWarning("Invalid ReadyToRun section type");
                }
                Sections[sectionType] = new ReadyToRunSection(sectionType,
                                                              NativeReader.ReadInt32(image, ref curOffset),
                                                              NativeReader.ReadInt32(image, ref curOffset));
            }

            Size = curOffset - startOffset;
        }
예제 #4
0
        /// <summary>
        /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/zap/zapimport.cpp">ZapImportSectionsTable::Save</a>
        /// </summary>
        private void EnsureImportSections()
        {
            if (_importSections != null)
            {
                return;
            }
            _importSections   = new List <ReadyToRunImportSection>();
            _importCellNames  = new Dictionary <int, string>();
            _importSignatures = new Dictionary <int, ReadyToRunSignature>();
            if (!ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.ImportSections, out ReadyToRunSection importSectionsSection))
            {
                return;
            }
            int offset    = GetOffset(importSectionsSection.RelativeVirtualAddress);
            int endOffset = offset + importSectionsSection.Size;

            while (offset < endOffset)
            {
                int rva                     = NativeReader.ReadInt32(Image, ref offset);
                int sectionOffset           = GetOffset(rva);
                int startOffset             = sectionOffset;
                int size                    = NativeReader.ReadInt32(Image, ref offset);
                CorCompileImportFlags flags = (CorCompileImportFlags)NativeReader.ReadUInt16(Image, ref offset);
                byte type                   = NativeReader.ReadByte(Image, ref offset);
                byte entrySize              = NativeReader.ReadByte(Image, ref offset);
                if (entrySize == 0)
                {
                    switch (Machine)
                    {
                    case Machine.I386:
                    case Machine.ArmThumb2:
                        entrySize = 4;
                        break;

                    case Machine.Amd64:
                    case Machine.Arm64:
                        entrySize = 8;
                        break;

                    default:
                        throw new NotImplementedException(Machine.ToString());
                    }
                }
                int entryCount = 0;
                if (entrySize != 0)
                {
                    entryCount = size / entrySize;
                }
                int signatureRVA = NativeReader.ReadInt32(Image, ref offset);

                int signatureOffset = 0;
                if (signatureRVA != 0)
                {
                    signatureOffset = GetOffset(signatureRVA);
                }
                List <ReadyToRunImportSection.ImportSectionEntry> entries = new List <ReadyToRunImportSection.ImportSectionEntry>();
                for (int i = 0; i < entryCount; i++)
                {
                    int  entryOffset = sectionOffset - startOffset;
                    long section     = NativeReader.ReadInt64(Image, ref sectionOffset);
                    uint sigRva      = NativeReader.ReadUInt32(Image, ref signatureOffset);
                    int  sigOffset   = GetOffset((int)sigRva);
                    ReadyToRunSignature signature;
                    string cellName = MetadataNameFormatter.FormatSignature(_assemblyResolver, this, sigOffset, out signature);
                    entries.Add(new ReadyToRunImportSection.ImportSectionEntry(entries.Count, entryOffset, entryOffset + rva, section, sigRva, cellName));
                    _importCellNames.Add(rva + entrySize * i, cellName);
                    _importSignatures.Add(rva + entrySize * i, signature);
                }

                int auxDataRVA    = NativeReader.ReadInt32(Image, ref offset);
                int auxDataOffset = 0;
                if (auxDataRVA != 0)
                {
                    auxDataOffset = GetOffset(auxDataRVA);
                }
                _importSections.Add(new ReadyToRunImportSection(_importSections.Count, this, rva, size, flags, type, entrySize, signatureRVA, entries, auxDataRVA, auxDataOffset, Machine, ReadyToRunHeader.MajorVersion));
            }
        }
예제 #5
0
        /// <summary>
        /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/zap/zapimport.cpp">ZapImportSectionsTable::Save</a>
        /// </summary>
        private void ParseImportSections()
        {
            if (!R2RHeader.Sections.ContainsKey(R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS))
            {
                return;
            }
            R2RSection importSectionsSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_IMPORT_SECTIONS];
            int        offset    = GetOffset(importSectionsSection.RelativeVirtualAddress);
            int        endOffset = offset + importSectionsSection.Size;

            while (offset < endOffset)
            {
                int rva                     = NativeReader.ReadInt32(Image, ref offset);
                int sectionOffset           = GetOffset(rva);
                int startOffset             = sectionOffset;
                int size                    = NativeReader.ReadInt32(Image, ref offset);
                CorCompileImportFlags flags = (CorCompileImportFlags)NativeReader.ReadUInt16(Image, ref offset);
                byte type                   = NativeReader.ReadByte(Image, ref offset);
                byte entrySize              = NativeReader.ReadByte(Image, ref offset);
                if (entrySize == 0)
                {
                    switch (Machine)
                    {
                    case Machine.I386:
                    case Machine.ArmThumb2:
                        entrySize = 4;
                        break;

                    case Machine.Amd64:
                    case Machine.Arm64:
                        entrySize = 8;
                        break;

                    default:
                        throw new NotImplementedException(Machine.ToString());
                    }
                }
                int entryCount = 0;
                if (entrySize != 0)
                {
                    entryCount = size / entrySize;
                }
                int signatureRVA = NativeReader.ReadInt32(Image, ref offset);

                int signatureOffset = 0;
                if (signatureRVA != 0)
                {
                    signatureOffset = GetOffset(signatureRVA);
                }
                List <R2RImportSection.ImportSectionEntry> entries = new List <R2RImportSection.ImportSectionEntry>();
                for (int i = 0; i < entryCount; i++)
                {
                    int    entryOffset = sectionOffset - startOffset;
                    long   section     = NativeReader.ReadInt64(Image, ref sectionOffset);
                    uint   sigRva      = NativeReader.ReadUInt32(Image, ref signatureOffset);
                    int    sigOffset   = GetOffset((int)sigRva);
                    string cellName    = MetadataNameFormatter.FormatSignature(_assemblyResolver, this, sigOffset);
                    entries.Add(new R2RImportSection.ImportSectionEntry(entries.Count, entryOffset, entryOffset + rva, section, sigRva, cellName));
                    ImportCellNames.Add(rva + entrySize * i, cellName);
                }

                int auxDataRVA    = NativeReader.ReadInt32(Image, ref offset);
                int auxDataOffset = 0;
                if (auxDataRVA != 0)
                {
                    auxDataOffset = GetOffset(auxDataRVA);
                }
                ImportSections.Add(new R2RImportSection(ImportSections.Count, this, rva, size, flags, type, entrySize, signatureRVA, entries, auxDataRVA, auxDataOffset, Machine, R2RHeader.MajorVersion));
            }
        }
예제 #6
0
        /// <summary>
        /// Get the RVAs of the runtime functions for each method
        /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/zap/zapcode.cpp">ZapUnwindInfo::Save</a>
        /// </summary>
        private void ParseRuntimeFunctions(bool[] isEntryPoint, int runtimeFunctionOffset, int runtimeFunctionSize)
        {
            int curOffset = 0;

            foreach (R2RMethod method in R2RMethods)
            {
                int runtimeFunctionId = method.EntryPointRuntimeFunctionId;
                if (runtimeFunctionId == -1)
                {
                    continue;
                }
                curOffset = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize;
                BaseGcInfo gcInfo     = null;
                int        codeOffset = 0;
                do
                {
                    int startRva = NativeReader.ReadInt32(Image, ref curOffset);
                    int endRva   = -1;
                    if (Machine == Machine.Amd64)
                    {
                        endRva = NativeReader.ReadInt32(Image, ref curOffset);
                    }
                    int unwindRva    = NativeReader.ReadInt32(Image, ref curOffset);
                    int unwindOffset = GetOffset(unwindRva);

                    BaseUnwindInfo unwindInfo = null;
                    if (Machine == Machine.Amd64)
                    {
                        unwindInfo = new Amd64.UnwindInfo(Image, unwindOffset);
                        if (isEntryPoint[runtimeFunctionId])
                        {
                            gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, R2RHeader.MajorVersion);
                        }
                    }
                    else if (Machine == Machine.I386)
                    {
                        unwindInfo = new x86.UnwindInfo(Image, unwindOffset);
                        if (isEntryPoint[runtimeFunctionId])
                        {
                            gcInfo = new x86.GcInfo(Image, unwindOffset, Machine, R2RHeader.MajorVersion);
                        }
                    }
                    else if (Machine == Machine.ArmThumb2)
                    {
                        unwindInfo = new Arm.UnwindInfo(Image, unwindOffset);
                        if (isEntryPoint[runtimeFunctionId])
                        {
                            gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, R2RHeader.MajorVersion); // Arm and Arm64 use the same GcInfo format as x64
                        }
                    }
                    else if (Machine == Machine.Arm64)
                    {
                        unwindInfo = new Arm64.UnwindInfo(Image, unwindOffset);
                        if (isEntryPoint[runtimeFunctionId])
                        {
                            gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, R2RHeader.MajorVersion);
                        }
                    }

                    EHInfo         ehInfo = null;
                    EHInfoLocation ehInfoLocation;
                    if (EHLookupTable != null && EHLookupTable.RuntimeFunctionToEHInfoMap.TryGetValue(startRva, out ehInfoLocation))
                    {
                        ehInfo = new EHInfo(this, ehInfoLocation.EHInfoRVA, startRva, GetOffset(ehInfoLocation.EHInfoRVA), ehInfoLocation.ClauseCount);
                    }

                    DebugInfo debugInfo;
                    _runtimeFunctionToDebugInfo.TryGetValue(runtimeFunctionId, out debugInfo);

                    RuntimeFunction rtf = new RuntimeFunction(
                        runtimeFunctionId,
                        startRva,
                        endRva,
                        unwindRva,
                        codeOffset,
                        method,
                        unwindInfo,
                        gcInfo,
                        ehInfo,
                        debugInfo);

                    method.RuntimeFunctions.Add(rtf);
                    runtimeFunctionId++;
                    codeOffset += rtf.Size;
                }while (runtimeFunctionId < isEntryPoint.Length && !isEntryPoint[runtimeFunctionId]);
            }
        }
예제 #7
0
        /// <summary>
        /// Get the RVAs of the runtime functions for each method
        /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/zap/zapcode.cpp">ZapUnwindInfo::Save</a>
        /// </summary>
        private void ParseRuntimeFunctions()
        {
            int runtimeFunctionId     = EntryPointRuntimeFunctionId;
            int runtimeFunctionSize   = _readyToRunReader.CalculateRuntimeFunctionSize();
            int runtimeFunctionOffset = _readyToRunReader.CompositeReader.GetOffset(_readyToRunReader.ReadyToRunHeader.Sections[ReadyToRunSectionType.RuntimeFunctions].RelativeVirtualAddress);
            int curOffset             = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize;
            Func <BaseGcInfo> gcInfo  = default(Func <BaseGcInfo>);
            int codeOffset            = 0;

            for (int i = 0; i < RuntimeFunctionCount; i++)
            {
                int startRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset);
                if (_readyToRunReader.Machine == Machine.ArmThumb2)
                {
                    // The low bit of this address is set since the function contains thumb code.
                    // Clear this bit in order to get the "real" RVA of the start of the function.
                    startRva = (int)(startRva & ~1);
                }
                int endRva = -1;
                if (_readyToRunReader.Machine == Machine.Amd64)
                {
                    endRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset);
                }
                int unwindRva    = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset);
                int unwindOffset = _readyToRunReader.CompositeReader.GetOffset(unwindRva);

                BaseUnwindInfo unwindInfo = null;
                if (_readyToRunReader.Machine == Machine.Amd64)
                {
                    unwindInfo = new Amd64.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                    if (i == 0)
                    {
                        gcInfo = new Func <BaseGcInfo>(() => new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion));
                    }
                }
                else if (_readyToRunReader.Machine == Machine.I386)
                {
                    unwindInfo = new x86.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                    if (i == 0)
                    {
                        gcInfo = new Func <BaseGcInfo>(() => new x86.GcInfo(_readyToRunReader.Image, unwindOffset, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion));
                    }
                }
                else if (_readyToRunReader.Machine == Machine.ArmThumb2)
                {
                    unwindInfo = new Arm.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                    if (i == 0)
                    {
                        gcInfo = new Func <BaseGcInfo>(() => new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion)); // Arm and Arm64 use the same GcInfo format as x6
                    }
                }
                else if (_readyToRunReader.Machine == Machine.Arm64)
                {
                    unwindInfo = new Arm64.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                    if (i == 0)
                    {
                        gcInfo = new Func <BaseGcInfo>(() => new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion));
                    }
                }

                RuntimeFunction rtf = new RuntimeFunction(
                    _readyToRunReader,
                    runtimeFunctionId,
                    startRva,
                    endRva,
                    unwindRva,
                    codeOffset,
                    this,
                    unwindInfo,
                    gcInfo);

                _runtimeFunctions.Add(rtf);
                runtimeFunctionId++;
                codeOffset += rtf.Size;
            }
        }
예제 #8
0
        private void ParseRuntimeFunctionsForMethod(bool[] isEntryPoint, int curOffset, ReadyToRunMethod method, int runtimeFunctionId)
        {
            BaseGcInfo gcInfo     = null;
            int        codeOffset = 0;

            do
            {
                int startRva = NativeReader.ReadInt32(Image, ref curOffset);
                int endRva   = -1;
                if (Machine == Machine.Amd64)
                {
                    endRva = NativeReader.ReadInt32(Image, ref curOffset);
                }
                int unwindRva    = NativeReader.ReadInt32(Image, ref curOffset);
                int unwindOffset = GetOffset(unwindRva);

                BaseUnwindInfo unwindInfo = null;
                if (Machine == Machine.Amd64)
                {
                    unwindInfo = new Amd64.UnwindInfo(Image, unwindOffset);
                    if (isEntryPoint[runtimeFunctionId])
                    {
                        gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, ReadyToRunHeader.MajorVersion);
                    }
                }
                else if (Machine == Machine.I386)
                {
                    unwindInfo = new x86.UnwindInfo(Image, unwindOffset);
                    if (isEntryPoint[runtimeFunctionId])
                    {
                        gcInfo = new x86.GcInfo(Image, unwindOffset, Machine, ReadyToRunHeader.MajorVersion);
                    }
                }
                else if (Machine == Machine.ArmThumb2)
                {
                    unwindInfo = new Arm.UnwindInfo(Image, unwindOffset);
                    if (isEntryPoint[runtimeFunctionId])
                    {
                        gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, ReadyToRunHeader.MajorVersion); // Arm and Arm64 use the same GcInfo format as x64
                    }
                }
                else if (Machine == Machine.Arm64)
                {
                    unwindInfo = new Arm64.UnwindInfo(Image, unwindOffset);
                    if (isEntryPoint[runtimeFunctionId])
                    {
                        gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, ReadyToRunHeader.MajorVersion);
                    }
                }

                RuntimeFunction rtf = new RuntimeFunction(
                    this,
                    runtimeFunctionId,
                    startRva,
                    endRva,
                    unwindRva,
                    codeOffset,
                    method,
                    unwindInfo,
                    gcInfo);

                method.RuntimeFunctions.Add(rtf);
                runtimeFunctionId++;
                codeOffset += rtf.Size;
            }while (runtimeFunctionId < isEntryPoint.Length && !isEntryPoint[runtimeFunctionId]);
        }
예제 #9
0
        /// <summary>
        /// Get the RVAs of the runtime functions for each method
        /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/zap/zapcode.cpp">ZapUnwindInfo::Save</a>
        /// </summary>
        private void ParseRuntimeFunctions(bool partial)
        {
            int runtimeFunctionId     = EntryPointRuntimeFunctionId;
            int runtimeFunctionSize   = _readyToRunReader.CalculateRuntimeFunctionSize();
            int runtimeFunctionOffset = _readyToRunReader.CompositeReader.GetOffset(_readyToRunReader.ReadyToRunHeader.Sections[ReadyToRunSectionType.RuntimeFunctions].RelativeVirtualAddress);
            int curOffset             = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize;
            int codeOffset            = 0;

            for (int i = 0; i < RuntimeFunctionCount; i++)
            {
                int startRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset);
                if (_readyToRunReader.Machine == Machine.ArmThumb2)
                {
                    // The low bit of this address is set since the function contains thumb code.
                    // Clear this bit in order to get the "real" RVA of the start of the function.
                    startRva = (int)(startRva & ~1);
                }
                int endRva = -1;
                if (_readyToRunReader.Machine == Machine.Amd64)
                {
                    endRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset);
                }
                int unwindRva    = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset);
                int unwindOffset = _readyToRunReader.CompositeReader.GetOffset(unwindRva);

                BaseUnwindInfo unwindInfo = null;
                if (_readyToRunReader.Machine == Machine.I386)
                {
                    unwindInfo = new x86.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                }
                else if (_readyToRunReader.Machine == Machine.Amd64)
                {
                    unwindInfo = new Amd64.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                }
                else if (_readyToRunReader.Machine == Machine.ArmThumb2)
                {
                    unwindInfo = new Arm.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                }
                else if (_readyToRunReader.Machine == Machine.Arm64)
                {
                    unwindInfo = new Arm64.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                }

                if (i == 0 && unwindInfo != null)
                {
                    if (_readyToRunReader.Machine == Machine.I386)
                    {
                        GcInfoRva = unwindRva;
                    }
                    else
                    {
                        GcInfoRva = unwindRva + unwindInfo.Size;
                    }
                }

                if (partial)
                {
                    return;
                }

                RuntimeFunction rtf = new RuntimeFunction(
                    _readyToRunReader,
                    runtimeFunctionId,
                    startRva,
                    endRva,
                    unwindRva,
                    codeOffset,
                    this,
                    unwindInfo);

                _runtimeFunctions.Add(rtf);
                runtimeFunctionId++;
                codeOffset += rtf.Size;
            }

            _size = codeOffset;
        }
예제 #10
0
        /// <summary>
        /// Get the RVAs of the runtime functions for each method
        /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/zap/zapcode.cpp">ZapUnwindInfo::Save</a>
        /// </summary>
        private void ParseRuntimeFunctions()
        {
            int        runtimeFunctionId     = EntryPointRuntimeFunctionId;
            int        runtimeFunctionSize   = _readyToRunReader.CalculateRuntimeFunctionSize();
            int        runtimeFunctionOffset = _readyToRunReader.CompositeReader.GetOffset(_readyToRunReader.ReadyToRunHeader.Sections[ReadyToRunSectionType.RuntimeFunctions].RelativeVirtualAddress);
            int        curOffset             = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize;
            BaseGcInfo gcInfo     = null;
            int        codeOffset = 0;

            for (int i = 0; i < RuntimeFunctionCount; i++)
            {
                int startRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset);
                int endRva   = -1;
                if (_readyToRunReader.Machine == Machine.Amd64)
                {
                    endRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset);
                }
                int unwindRva    = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset);
                int unwindOffset = _readyToRunReader.CompositeReader.GetOffset(unwindRva);

                BaseUnwindInfo unwindInfo = null;
                if (_readyToRunReader.Machine == Machine.Amd64)
                {
                    unwindInfo = new Amd64.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                    if (i == 0)
                    {
                        gcInfo = new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion);
                    }
                }
                else if (_readyToRunReader.Machine == Machine.I386)
                {
                    unwindInfo = new x86.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                    if (i == 0)
                    {
                        gcInfo = new x86.GcInfo(_readyToRunReader.Image, unwindOffset, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion);
                    }
                }
                else if (_readyToRunReader.Machine == Machine.ArmThumb2)
                {
                    unwindInfo = new Arm.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                    if (i == 0)
                    {
                        gcInfo = new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion); // Arm and Arm64 use the same GcInfo format as x64
                    }
                }
                else if (_readyToRunReader.Machine == Machine.Arm64)
                {
                    unwindInfo = new Arm64.UnwindInfo(_readyToRunReader.Image, unwindOffset);
                    if (i == 0)
                    {
                        gcInfo = new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion);
                    }
                }

                RuntimeFunction rtf = new RuntimeFunction(
                    _readyToRunReader,
                    runtimeFunctionId,
                    startRva,
                    endRva,
                    unwindRva,
                    codeOffset,
                    this,
                    unwindInfo,
                    gcInfo);

                _runtimeFunctions.Add(rtf);
                runtimeFunctionId++;
                codeOffset += rtf.Size;
            }
        }