// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Generic;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
+using System.Text;
namespace R2RDump
{
[DllImport("coredistools.dll")]
public static extern void FinishDisasm(IntPtr Disasm);
- public unsafe static string GetCodeBlock(IntPtr Disasm, int Address, int Offset, byte[] image, int Size)
+ public unsafe static string GetCodeBlock(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, byte[] image)
{
- int len;
- fixed (byte* p = image)
+ StringBuilder sb = new StringBuilder();
+
+ int rtfOffset = 0;
+ int codeOffset = rtf.CodeOffset;
+ Dictionary<int, GcInfo.GcTransition> transitions = rtf.Method.GcInfo.Transitions;
+ GcSlotTable slotTable = rtf.Method.GcInfo.SlotTable;
+ while (rtfOffset < rtf.Size)
{
- IntPtr ptr = (IntPtr)(p + Offset);
- len = DumpInstruction(Disasm, (ulong)Address, ptr, Size); //DumpCodeBlock(Disasm, (ulong)Address, ptr, Size);
+ int instrSize = 1;
+ fixed (byte* p = image)
+ {
+ IntPtr ptr = (IntPtr)(p + imageOffset + rtfOffset);
+ instrSize = DumpInstruction(Disasm, (ulong)(rtf.StartAddress + rtfOffset), ptr, rtf.Size);
+ }
+ IntPtr pBuffer = GetOutputBuffer();
+ string instr = Marshal.PtrToStringAnsi(pBuffer);
+
+ sb.Append(instr);
+ if (transitions.ContainsKey(codeOffset))
+ {
+ sb.AppendLine($"\t\t\t\t{transitions[codeOffset].GetSlotState(slotTable)}");
+ }
+
+ ClearOutputBuffer();
+ rtfOffset += instrSize;
+ codeOffset += instrSize;
}
- IntPtr pBuffer = GetOutputBuffer();
- string buffer = Marshal.PtrToStringAnsi(pBuffer);
- ClearOutputBuffer();
- return buffer;
+ return sb.ToString();
}
public static IntPtr GetDisasm(Machine machine)
public int SlotId { get; }
public bool IsLive { get; }
public int ChunkId { get; }
+
public GcTransition(int codeOffset, int slotId, bool isLive, int chunkId)
{
CodeOffset = codeOffset;
return sb.ToString();
}
+ public string GetSlotState(GcSlotTable slotTable)
+ {
+ GcSlotTable.GcSlot slot = slotTable.GcSlots[SlotId];
+ string slotStr = "";
+ if (slot.StackSlot == null)
+ {
+ slotStr = Enum.GetName(typeof(Amd64Registers), slot.RegisterNumber);
+ }
+ else
+ {
+ slotStr = $"sp{slot.StackSlot.SpOffset:+#;-#;+0}";
+ }
+ string isLiveStr = "live";
+ if (!IsLive)
+ isLiveStr = "dead";
+ return $"{slotStr} is {isLiveStr}";
+ }
}
private const int GCINFO_VERSION = 2;
public GcSlotTable SlotTable { get; }
public int Size { get; }
public int Offset { get; }
- public IList<GcTransition> Transitions { get; }
+ public Dictionary<int, GcTransition> Transitions { get; }
public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion)
{
sb.AppendLine($"{tab}SlotTable:");
sb.Append(SlotTable.ToString());
sb.AppendLine($"{tab}Transitions:");
- foreach (GcTransition trans in Transitions)
+ foreach (GcTransition trans in Transitions.Values)
{
sb.AppendLine(trans.ToString());
}
return (readyToRunMajorVersion == 1) ? 1 : GCINFO_VERSION;
}
- public IList<GcTransition> GetTranstions(byte[] image, ref int bitOffset)
+ public Dictionary<int, GcTransition> GetTranstions(byte[] image, ref int bitOffset)
{
int totalInterruptibleLength = 0;
if (NumInterruptibleRanges == 0)
int numBitsPerPointer = (int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.POINTER_SIZE_ENCBASE, ref bitOffset);
if (numBitsPerPointer == 0)
{
- return new List<GcTransition>();
+ return new Dictionary<int, GcTransition>();
}
int[] chunkPointers = new int[numChunks];
}
transitions.Sort((s1, s2) => s1.CodeOffset.CompareTo(s2.CodeOffset));
- UpdateTransitionCodeOffset(transitions);
- return transitions;
+ return UpdateTransitionCodeOffset(transitions);
}
private uint GetNumCouldBeLiveSlots(byte[] image, ref int bitOffset)
return slotId;
}
- private void UpdateTransitionCodeOffset(List<GcTransition> transitions)
+ private Dictionary<int, GcTransition> UpdateTransitionCodeOffset(List<GcTransition> transitions)
{
+ Dictionary<int, GcTransition> updatedTransitions = new Dictionary<int, GcTransition>();
int cumInterruptibleLength = 0;
using (IEnumerator<InterruptibleRange> interruptibleRangesIter = InterruptibleRanges.GetEnumerator())
{
codeOffset = transition.CodeOffset + (int)currentRange.StartOffset - cumInterruptibleLength;
}
transition.CodeOffset = codeOffset;
+ updatedTransitions[codeOffset] = transition;
}
}
+ return updatedTransitions;
}
}
}
/// </summary>
private void DumpRuntimeFunction(R2RReader r2r, RuntimeFunction rtf)
{
+ _writer.Write($"{rtf}");
if (_disasm)
{
- _writer.WriteLine($"Id: {rtf.Id}");
- _writer.Write(CoreDisTools.GetCodeBlock(_disassembler, rtf.StartAddress, r2r.GetOffset(rtf.StartAddress), r2r.Image, rtf.Size));
- }
- else
- {
- _writer.Write($"{rtf}");
+ _writer.Write(CoreDisTools.GetCodeBlock(_disassembler, rtf, r2r.GetOffset(rtf.StartAddress), r2r.Image));
}
+
if (_raw)
{
_writer.WriteLine("Raw Bytes:");
/// </summary>
public int UnwindRVA { get; }
+ public int CodeOffset { get; set; }
+
/// <summary>
/// The method that this runtime function belongs to
/// </summary>
public UnwindInfo UnwindInfo { get; }
- public RuntimeFunction(int id, int startRva, int endRva, int unwindRva, R2RMethod method, UnwindInfo unwindInfo, GcInfo gcInfo)
+ public RuntimeFunction(int id, int startRva, int endRva, int unwindRva, int codeOffset, R2RMethod method, UnwindInfo unwindInfo, GcInfo gcInfo)
{
Id = id;
StartAddress = startRva;
{
Size = gcInfo.CodeLength;
}
+ CodeOffset = codeOffset;
method.GcInfo = gcInfo;
}
continue;
curOffset = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize;
GcInfo gcInfo = null;
+ int codeOffset = 0;
do
{
int startRva = NativeReader.ReadInt32(Image, ref curOffset);
gcInfo = new GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, R2RHeader.MajorVersion);
}
- method.RuntimeFunctions.Add(new RuntimeFunction(runtimeFunctionId, startRva, endRva, unwindRva, method, unwindInfo, gcInfo));
+ RuntimeFunction rtf = new RuntimeFunction(runtimeFunctionId, startRva, endRva, unwindRva, codeOffset, method, unwindInfo, gcInfo);
+ method.RuntimeFunctions.Add(rtf);
runtimeFunctionId++;
+ codeOffset += rtf.Size;
}
while (runtimeFunctionId < isEntryPoint.Length && !isEntryPoint[runtimeFunctionId]);
}