From 10cfcbabc62b95a67d3ace771600ee20889333bd Mon Sep 17 00:00:00 2001 From: Amy Yu Date: Thu, 7 Jun 2018 13:40:37 -0700 Subject: [PATCH] Dump contents of NativeArray and NativeHashtable --- src/tools/r2rdump/NativeArray.cs | 22 +++++++++++++++ src/tools/r2rdump/NativeHashtable.cs | 54 +++++++++++++++++++++++++++++++++--- src/tools/r2rdump/R2RDump.cs | 47 ++++++++++++++++++++++++------- src/tools/r2rdump/R2RReader.cs | 4 +-- 4 files changed, 111 insertions(+), 16 deletions(-) diff --git a/src/tools/r2rdump/NativeArray.cs b/src/tools/r2rdump/NativeArray.cs index 41042ff..bb0c746 100644 --- a/src/tools/r2rdump/NativeArray.cs +++ b/src/tools/r2rdump/NativeArray.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text; + namespace R2RDump { class NativeArray @@ -10,6 +12,7 @@ namespace R2RDump private uint _baseOffset; private uint _nElements; private byte _entryIndexSize; + private byte[] _image; public NativeArray(byte[] image, uint offset) { @@ -17,6 +20,7 @@ namespace R2RDump _baseOffset = NativeReader.DecodeUnsigned(image, offset, ref val); _nElements = (val >> 2); _entryIndexSize = (byte)(val & 3); + _image = image; } public uint GetCount() @@ -24,6 +28,24 @@ namespace R2RDump return _nElements; } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + sb.AppendLine($"NativeArray Size: {_nElements}"); + sb.AppendLine($"EntryIndexSize: {_entryIndexSize}"); + for (uint i = 0; i < _nElements; i++) + { + int val = 0; + if (TryGetAt(_image, i, ref val)) + { + sb.AppendLine($"{i}: {val}"); + } + } + + return sb.ToString(); + } + public bool TryGetAt(byte[] image, uint index, ref int pOffset) { if (index >= _nElements) diff --git a/src/tools/r2rdump/NativeHashtable.cs b/src/tools/r2rdump/NativeHashtable.cs index b596622..62ee755 100644 --- a/src/tools/r2rdump/NativeHashtable.cs +++ b/src/tools/r2rdump/NativeHashtable.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; +using System.Text; + namespace R2RDump { struct NativeParser @@ -10,12 +13,14 @@ namespace R2RDump /// The current index of the image byte array /// public uint Offset { get; set; } + public byte LowHashcode { get; } byte[] _image; - public NativeParser(byte[] image, uint offset) + public NativeParser(byte[] image, uint offset, byte lowHashcode = 0) { Offset = offset; + LowHashcode = lowHashcode; _image = image; } @@ -36,7 +41,8 @@ namespace R2RDump public NativeParser GetParserFromRelativeOffset() { - return new NativeParser(_image, GetRelativeOffset()); + byte lowHashcode = GetByte(); + return new NativeParser(_image, GetRelativeOffset(), lowHashcode); } public byte GetByte() @@ -76,8 +82,9 @@ namespace R2RDump private uint _baseOffset; private uint _bucketMask; private byte _entryIndexSize; + private uint _endOffset; - public NativeHashtable(byte[] image, NativeParser parser) + public NativeHashtable(byte[] image, NativeParser parser, uint endOffset) { uint header = parser.GetByte(); _baseOffset = parser.Offset; @@ -92,6 +99,46 @@ namespace R2RDump if (entryIndexSize > 2) throw new System.BadImageFormatException(); _entryIndexSize = entryIndexSize; + + _endOffset = endOffset; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + SortedDictionary entries = new SortedDictionary(); + AllEntriesEnumerator allEntriesEnum = EnumerateAllEntries(); + NativeParser curParser = allEntriesEnum.GetNext(); + while (!curParser.IsNull()) + { + entries[curParser.Offset] = curParser.LowHashcode; + curParser = allEntriesEnum.GetNext(); + } + entries[_endOffset] = 0; + + sb.AppendLine($"NativeHashtable Size: {entries.Count - 1}"); + sb.AppendLine($"EntryIndexSize: {_entryIndexSize}"); + int curOffset = -1; + foreach (KeyValuePair entry in entries) + { + int nextOffset = (int)entry.Key; + if (curOffset != -1) + { + for (int i = curOffset; i < nextOffset; i++) + { + sb.Append($"{_image[i]:X2} "); + } + sb.AppendLine(); + } + if (nextOffset != _endOffset) + { + sb.Append($"0x{entry.Value:X2} -> "); + } + curOffset = nextOffset; + } + + return sb.ToString(); } // @@ -132,7 +179,6 @@ namespace R2RDump { while (_parser.Offset < _endOffset) { - byte lowHashcode = _parser.GetByte(); return _parser.GetParserFromRelativeOffset(); } diff --git a/src/tools/r2rdump/R2RDump.cs b/src/tools/r2rdump/R2RDump.cs index fce9fbd..22967ba 100644 --- a/src/tools/r2rdump/R2RDump.cs +++ b/src/tools/r2rdump/R2RDump.cs @@ -23,10 +23,11 @@ namespace R2RDump private IReadOnlyList _sections = Array.Empty(); private bool _diff; private IntPtr _disassembler; - private bool _types; private bool _unwind; private bool _gc; + private bool _sectionContents; private TextWriter _writer; + private Dictionary _selectedSections = new Dictionary(); private R2RDump() { @@ -51,9 +52,9 @@ namespace R2RDump syntax.DefineOptionList("k|keyword", ref _keywords, "Search method by keyword"); syntax.DefineOptionList("r|runtimefunction", ref _runtimeFunctions, ArgStringToInt, "Get one runtime function by id or relative virtual address"); syntax.DefineOptionList("s|section", ref _sections, "Get section by keyword"); - syntax.DefineOption("types", ref _types, "Dump available types"); syntax.DefineOption("unwind", ref _unwind, "Dump unwindInfo"); syntax.DefineOption("gc", ref _gc, "Dump gcInfo and slot table"); + syntax.DefineOption("sc", ref _sectionContents, "Dump section contents"); syntax.DefineOption("v|verbose", ref verbose, "Dump raw bytes, disassembly, unwindInfo, gcInfo and section contents"); syntax.DefineOption("diff", ref _diff, "Compare two R2R images (not yet implemented)"); }); @@ -64,7 +65,7 @@ namespace R2RDump _disasm = true; _unwind = true; _gc = true; - _types = true; + _sectionContents = true; } return argSyntax; @@ -148,10 +149,40 @@ namespace R2RDump { DumpBytes(r2r, section.RelativeVirtualAddress, (uint)section.Size); } - if (_types) + + if (_sectionContents) { - _writer.WriteLine(); - DumpAvailableTypes(r2r); + switch (section.Type) + { + case R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES: + uint availableTypesSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); + NativeParser availableTypesParser = new NativeParser(r2r.Image, availableTypesSectionOffset); + NativeHashtable availableTypes = new NativeHashtable(r2r.Image, availableTypesParser, (uint)(availableTypesSectionOffset + section.Size)); + _writer.WriteLine(availableTypes.ToString()); + DumpAvailableTypes(r2r); + break; + case R2RSection.SectionType.READYTORUN_SECTION_METHODDEF_ENTRYPOINTS: + NativeArray methodEntryPoints = new NativeArray(r2r.Image, (uint)r2r.GetOffset(section.RelativeVirtualAddress)); + _writer.WriteLine(methodEntryPoints.ToString()); + break; + case R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS: + uint instanceSectionOffset = (uint)r2r.GetOffset(section.RelativeVirtualAddress); + NativeParser instanceParser = new NativeParser(r2r.Image, instanceSectionOffset); + NativeHashtable instMethodEntryPoints = new NativeHashtable(r2r.Image, instanceParser, (uint)(instanceSectionOffset + section.Size)); + _writer.WriteLine(instMethodEntryPoints.ToString()); + break; + case R2RSection.SectionType.READYTORUN_SECTION_RUNTIME_FUNCTIONS: + int offset = r2r.GetOffset(section.RelativeVirtualAddress); + int endOffset = offset + section.Size; + int rtfIndex = 0; + while (offset < endOffset) + { + uint rva = NativeReader.ReadUInt32(r2r.Image, ref offset); + _writer.WriteLine($"{rtfIndex}: 0x{rva:X8}"); + rtfIndex++; + } + break; + } } } @@ -358,10 +389,6 @@ namespace R2RDump { DumpHeader(r2r, false); } - if (_types) - { - DumpSection(r2r, r2r.R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES]); - } QuerySection(r2r, _sections); QueryRuntimeFunction(r2r, _runtimeFunctions); diff --git a/src/tools/r2rdump/R2RReader.cs b/src/tools/r2rdump/R2RReader.cs index dab31ea..97fe57c 100644 --- a/src/tools/r2rdump/R2RReader.cs +++ b/src/tools/r2rdump/R2RReader.cs @@ -180,7 +180,7 @@ namespace R2RDump R2RSection instMethodEntryPointSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS]; int instMethodEntryPointsOffset = GetOffset(instMethodEntryPointSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(Image, (uint)instMethodEntryPointsOffset); - NativeHashtable instMethodEntryPoints = new NativeHashtable(Image, parser); + NativeHashtable instMethodEntryPoints = new NativeHashtable(Image, parser, (uint)(instMethodEntryPointsOffset + instMethodEntryPointSection.Size)); NativeHashtable.AllEntriesEnumerator allEntriesEnum = instMethodEntryPoints.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) @@ -259,7 +259,7 @@ namespace R2RDump R2RSection availableTypesSection = R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES]; int availableTypesOffset = GetOffset(availableTypesSection.RelativeVirtualAddress); NativeParser parser = new NativeParser(Image, (uint)availableTypesOffset); - NativeHashtable availableTypes = new NativeHashtable(Image, parser); + NativeHashtable availableTypes = new NativeHashtable(Image, parser, (uint)(availableTypesOffset + availableTypesSection.Size)); NativeHashtable.AllEntriesEnumerator allEntriesEnum = availableTypes.EnumerateAllEntries(); NativeParser curParser = allEntriesEnum.GetNext(); while (!curParser.IsNull()) -- 2.7.4