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()); }
/// <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); } }
/// <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; }
/// <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)); } }
/// <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)); } }
/// <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]); } }
/// <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; } }
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]); }
/// <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; }
/// <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; } }