// 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
private uint _baseOffset;
private uint _nElements;
private byte _entryIndexSize;
+ private byte[] _image;
public NativeArray(byte[] image, uint offset)
{
_baseOffset = NativeReader.DecodeUnsigned(image, offset, ref val);
_nElements = (val >> 2);
_entryIndexSize = (byte)(val & 3);
+ _image = image;
}
public uint GetCount()
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)
// 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
/// The current index of the image byte array
/// </summary>
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;
}
public NativeParser GetParserFromRelativeOffset()
{
- return new NativeParser(_image, GetRelativeOffset());
+ byte lowHashcode = GetByte();
+ return new NativeParser(_image, GetRelativeOffset(), lowHashcode);
}
public byte GetByte()
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;
if (entryIndexSize > 2)
throw new System.BadImageFormatException();
_entryIndexSize = entryIndexSize;
+
+ _endOffset = endOffset;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ SortedDictionary<uint, byte> entries = new SortedDictionary<uint, byte>();
+ 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<uint, byte> 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();
}
//
{
while (_parser.Offset < _endOffset)
{
- byte lowHashcode = _parser.GetByte();
return _parser.GetParserFromRelativeOffset();
}
private IReadOnlyList<string> _sections = Array.Empty<string>();
private bool _diff;
private IntPtr _disassembler;
- private bool _types;
private bool _unwind;
private bool _gc;
+ private bool _sectionContents;
private TextWriter _writer;
+ private Dictionary<R2RSection.SectionType, bool> _selectedSections = new Dictionary<R2RSection.SectionType, bool>();
private 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)");
});
_disasm = true;
_unwind = true;
_gc = true;
- _types = true;
+ _sectionContents = true;
}
return argSyntax;
{
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;
+ }
}
}
{
DumpHeader(r2r, false);
}
- if (_types)
- {
- DumpSection(r2r, r2r.R2RHeader.Sections[R2RSection.SectionType.READYTORUN_SECTION_AVAILABLE_TYPES]);
- }
QuerySection(r2r, _sections);
QueryRuntimeFunction(r2r, _runtimeFunctions);
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())
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())