private bool _diff = false;
private long _disassembler;
private bool _types = false;
+ private bool _unwind = false;
private TextWriter _writer;
private R2RDump()
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("diff", ref _diff, "Compare two R2R images (not yet implemented)"); // not yet implemented
});
{
DumpBytes(r2r, r2r.R2RHeader.RelativeVirtualAddress, (uint)r2r.R2RHeader.Size);
}
+ _writer.WriteLine();
if (dumpSections)
{
WriteDivider("R2R Sections");
DumpSection(r2r, section);
}
}
+ _writer.WriteLine();
}
/// <summary>
{
DumpBytes(r2r, rtf.StartAddress, (uint)rtf.Size);
}
+ if (_unwind)
+ {
+ _writer.WriteLine("UnwindInfo:");
+ _writer.Write(rtf.UnwindInfo);
+ }
_writer.WriteLine();
}
/// </summary>
public R2RMethod Method { get; }
- public RuntimeFunction(int id, int startRva, int endRva, int unwindRva, R2RMethod method)
+ public UnwindInfo UnwindInfo { get; }
+
+ public RuntimeFunction(int id, int startRva, int endRva, int unwindRva, R2RMethod method, UnwindInfo unwindInfo)
{
Id = id;
StartAddress = startRva;
Size = -1;
UnwindRVA = unwindRva;
Method = method;
+ UnwindInfo = unwindInfo;
}
public override string ToString()
/// <summary>
/// Maps all the generic parameters to the type in the instance
/// </summary>
- Dictionary<string, string> _genericParamInstanceMap;
+ private Dictionary<string, string> _genericParamInstanceMap;
[Flags]
public enum EncodeMethodSigFlags
/// <summary>
/// Extracts the method signature from the metadata by rid
/// </summary>
- public R2RMethod(byte[] image, MetadataReader mdReader, uint rid, int entryPointId, GenericElementTypes[] instanceArgs, uint[] tok)
+ public R2RMethod(MetadataReader mdReader, uint rid, int entryPointId, GenericElementTypes[] instanceArgs, uint[] tok)
{
Token = _mdtMethodDef | rid;
Rid = rid;
BlobReader signatureReader = mdReader.GetBlobReader(_methodDef.Signature);
TypeDefinitionHandle declaringTypeHandle = _methodDef.GetDeclaringType();
- TypeDefinition declaringTypeDef;
- do
- {
- declaringTypeDef = mdReader.GetTypeDefinition(declaringTypeHandle);
- DeclaringType = mdReader.GetString(declaringTypeDef.Name) + "." + DeclaringType;
- declaringTypeHandle = declaringTypeDef.GetDeclaringType();
- }
- while (!declaringTypeHandle.IsNil);
-
- NamespaceDefinitionHandle namespaceHandle = declaringTypeDef.NamespaceDefinition;
- while (!namespaceHandle.IsNil)
- {
- NamespaceDefinition namespaceDef = mdReader.GetNamespaceDefinition(namespaceHandle);
- DeclaringType = mdReader.GetString(namespaceDef.Name) + "." + DeclaringType;
- namespaceHandle = namespaceDef.Parent;
- }
+ DeclaringType = R2RReader.GetTypeDefFullName(mdReader, declaringTypeHandle);
SignatureHeader signatureHeader = signatureReader.ReadSignatureHeader();
IsGeneric = signatureHeader.IsGeneric;
{
StringBuilder sb = new StringBuilder();
- sb.AppendFormat($"{DeclaringType}{Name}");
+ sb.AppendFormat($"{DeclaringType}.{Name}");
if (IsGeneric)
{
int offset = 0;
if (methodEntryPoints.TryGetAt(Image, rid - 1, ref offset))
{
- R2RMethod method = new R2RMethod(Image, _mdReader, rid, GetEntryPointIdFromOffset(offset), null, null);
+ R2RMethod method = new R2RMethod(_mdReader, rid, GetEntryPointIdFromOffset(offset), null, null);
if (method.EntryPointRuntimeFunctionId < 0 || method.EntryPointRuntimeFunctionId >= isEntryPoint.Length)
{
uint id = curParser.GetUnsigned();
id = id >> 1;
- R2RMethod method = new R2RMethod(Image, _mdReader, rid, (int)id, args, tokens);
+ R2RMethod method = new R2RMethod(_mdReader, rid, (int)id, args, tokens);
if (method.EntryPointRuntimeFunctionId >= 0 && method.EntryPointRuntimeFunctionId < isEntryPoint.Length)
{
isEntryPoint[method.EntryPointRuntimeFunctionId] = true;
endRva = NativeReader.ReadInt32(Image, ref curOffset);
}
int unwindRva = NativeReader.ReadInt32(Image, ref curOffset);
+ int unwindOffset = GetOffset(unwindRva);
- method.RuntimeFunctions.Add(new RuntimeFunction(runtimeFunctionId, startRva, endRva, unwindRva, method));
+ method.RuntimeFunctions.Add(new RuntimeFunction(runtimeFunctionId, startRva, endRva, unwindRva, method, new UnwindInfo(Image, unwindOffset)));
runtimeFunctionId++;
}
while (runtimeFunctionId < isEntryPoint.Length && !isEntryPoint[runtimeFunctionId]);
uint rid = curParser.GetUnsigned();
rid = rid >> 1;
TypeDefinitionHandle typeDefHandle = MetadataTokens.TypeDefinitionHandle((int)rid);
-
- TypeDefinition typeDef = _mdReader.GetTypeDefinition(typeDefHandle);
- string name = _mdReader.GetString(typeDef.Name);
- if (!typeDef.Namespace.IsNil)
- {
- name = _mdReader.GetString(typeDef.Namespace) + "." + name;
- }
- AvailableTypes.Add(name);
+ AvailableTypes.Add(GetTypeDefFullName(_mdReader, typeDefHandle));
curParser = allEntriesEnum.GetNext();
}
}
}
/// <summary>
+ /// Get the full name of a type, including parent classes and namespace
+ /// </summary>
+ public static string GetTypeDefFullName(MetadataReader mdReader, TypeDefinitionHandle handle)
+ {
+ TypeDefinition typeDef;
+ string typeStr = "";
+ do
+ {
+ typeDef = mdReader.GetTypeDefinition(handle);
+ typeStr = "." + mdReader.GetString(typeDef.Name) + typeStr;
+ handle = typeDef.GetDeclaringType();
+ }
+ while (!handle.IsNil);
+
+ return mdReader.GetString(typeDef.Namespace) + typeStr;
+ }
+
+ /// <summary>
/// Reads the method entrypoint from the offset. Used for non-generic methods
/// </summary>
private int GetEntryPointIdFromOffset(int offset)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// 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
+{
+ struct UnwindCode
+ {
+ public byte CodeOffset { get; }
+ public byte UnwindOp { get; } //4 bits
+ public byte OpInfo { get; } //4 bits
+
+ public byte OffsetLow { get; }
+ public byte OffsetHigh { get; } //4 bits
+
+ public ushort FrameOffset { get; }
+
+ public UnwindCode(byte[] image, ref int offset)
+ {
+ int off = offset;
+ CodeOffset = NativeReader.ReadByte(image, ref off);
+ byte op = NativeReader.ReadByte(image, ref off);
+ UnwindOp = (byte)(op & 15);
+ OpInfo = (byte)(op >> 4);
+
+ OffsetLow = CodeOffset;
+ OffsetHigh = OpInfo;
+
+ FrameOffset = NativeReader.ReadUInt16(image, ref offset);
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ string tab2 = new string(' ', 8);
+ string tab3 = new string(' ', 12);
+
+ sb.AppendLine($"{tab2}{{");
+ sb.AppendLine($"{tab3}CodeOffset: {CodeOffset}");
+ sb.AppendLine($"{tab3}UnwindOp: {UnwindOp}");
+ sb.AppendLine($"{tab3}OpInfo: {OpInfo}");
+ sb.AppendLine($"{tab2}}}");
+ sb.AppendLine($"{tab2}{{");
+ sb.AppendLine($"{tab3}OffsetLow: {OffsetLow}");
+ sb.AppendLine($"{tab3}UnwindOp: {UnwindOp}");
+ sb.AppendLine($"{tab3}OffsetHigh: {OffsetHigh}");
+ sb.AppendLine($"{tab2}}}");
+ sb.AppendLine($"{tab2}FrameOffset: {FrameOffset}");
+ sb.AppendLine($"{tab2}------------------");
+
+ return sb.ToString();
+ }
+ }
+
+ struct UnwindInfo
+ {
+ private const int _sizeofUnwindCode = 2;
+ private const int _offsetofUnwindCode = 4;
+
+ public byte Version { get; } //3 bits
+ public byte Flags { get; } //5 bits
+ public byte SizeOfProlog { get; }
+ public byte CountOfUnwindCodes { get; }
+ public byte FrameRegister { get; } //4 bits
+ public byte FrameOffset { get; } //4 bits
+ public UnwindCode[] UnwindCode { get; }
+ public uint PersonalityRoutineRVA { get; }
+ public int Size { get; }
+
+ public UnwindInfo(byte[] image, int offset)
+ {
+ byte versionAndFlags = NativeReader.ReadByte(image, ref offset);
+ Version = (byte)(versionAndFlags & 7);
+ Flags = (byte)(versionAndFlags >> 3);
+ SizeOfProlog = NativeReader.ReadByte(image, ref offset);
+ CountOfUnwindCodes = NativeReader.ReadByte(image, ref offset);
+ byte frameRegisterAndOffset = NativeReader.ReadByte(image, ref offset);
+ FrameRegister = (byte)(frameRegisterAndOffset & 15);
+ FrameOffset = (byte)(frameRegisterAndOffset >> 4);
+
+ UnwindCode = new UnwindCode[CountOfUnwindCodes];
+ for (int i = 0; i < CountOfUnwindCodes; i++)
+ {
+ UnwindCode[i] = new UnwindCode(image, ref offset);
+ }
+
+ PersonalityRoutineRVA = NativeReader.ReadUInt32(image, ref offset);
+
+ Size = _offsetofUnwindCode + CountOfUnwindCodes * _sizeofUnwindCode + sizeof(uint);
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ string tab = " ";
+
+ sb.AppendLine($"{tab}Version: {Version}");
+ sb.AppendLine($"{tab}Flags: 0x{Flags:X8}");
+ sb.AppendLine($"{tab}SizeOfProlog: {SizeOfProlog}");
+ sb.AppendLine($"{tab}CountOfUnwindCodes: {CountOfUnwindCodes}");
+ sb.AppendLine($"{tab}FrameRegister: {FrameRegister}");
+ sb.AppendLine($"{tab}FrameOffset: {FrameOffset}");
+ sb.AppendLine($"{tab}Unwind Codes:");
+ sb.AppendLine($"{tab}{tab}------------------");
+ for (int i = 0; i < CountOfUnwindCodes; i++)
+ {
+ sb.Append(UnwindCode[i].ToString());
+ }
+ sb.AppendLine($"{tab}PersonalityRoutineRVA: 0x{PersonalityRoutineRVA:X8}");
+ sb.AppendLine($"{tab}Size: {Size}");
+
+ return sb.ToString();
+ }
+ }
+}