sb.AppendLine($"\tGenericsInstContextStackSlot: caller.sp{GenericsInstContextStackSlot:+#;-#;+0}");
}
- if (StackBaseRegister != 0xffffffff)
- sb.AppendLine($"\tStackBaseRegister: {(Registers)StackBaseRegister}");
if (_machine == Machine.Amd64)
{
+ if (StackBaseRegister != 0xffffffff)
+ sb.AppendLine($"\tStackBaseRegister: {(Amd64.Registers)StackBaseRegister}");
sb.AppendLine($"\tWants Report Only Leaf: {_wantsReportOnlyLeaf}");
}
- else if (_machine == Machine.Arm || _machine == Machine.Arm64)
+ else if (_machine == Machine.ArmThumb2 || _machine == Machine.Arm64)
{
+ if (StackBaseRegister != 0xffffffff)
+ {
+ if (_machine == Machine.ArmThumb2)
+ {
+ sb.AppendLine($"\tStackBaseRegister: {(Arm.Registers)StackBaseRegister}");
+ }
+ else
+ {
+ sb.AppendLine($"\tStackBaseRegister: {(Arm64.Registers)StackBaseRegister}");
+ }
+ }
+
sb.AppendLine($"\tHas Tailcalls: {_wantsReportOnlyLeaf}");
}
while (NativeReader.ReadBits(image, 1, ref bitOffset) != 0)
{
int transitionOffset = NativeReader.ReadBits(image, _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2, ref bitOffset) + normChunkBaseCodeOffset;
- transitions.Add(new GcTransition(transitionOffset, slotId, isLive, currentChunk, SlotTable));
+ transitions.Add(new GcTransition(transitionOffset, slotId, isLive, currentChunk, SlotTable, _machine));
isLive = !isLive;
}
slotId++;
currentRangeLength = (int)(currentRange.StopOffset - currentRange.StartOffset);
codeOffset = transition.CodeOffset + (int)currentRange.StartOffset - cumInterruptibleLength;
}
+
transition.CodeOffset = codeOffset;
if (!updatedTransitions.ContainsKey(codeOffset))
{
using System;
using System.Collections.Generic;
+using System.Reflection.PortableExecutable;
using System.Text;
using System.Xml.Serialization;
public GcTransition() { }
- public GcTransition(int codeOffset, int slotId, bool isLive, int chunkId, GcSlotTable slotTable)
+ public GcTransition(int codeOffset, int slotId, bool isLive, int chunkId, GcSlotTable slotTable, Machine machine)
{
CodeOffset = codeOffset;
SlotId = slotId;
IsLive = isLive;
ChunkId = chunkId;
- SlotState = GetSlotState(slotTable);
+ SlotState = GetSlotState(slotTable, machine);
}
public override string ToString()
return SlotState;
}
- public string GetSlotState(GcSlotTable slotTable)
+ public string GetSlotState(GcSlotTable slotTable, Machine machine)
{
GcSlotTable.GcSlot slot = slotTable.GcSlots[SlotId];
string slotStr = "";
if (slot.StackSlot == null)
{
- slotStr = Enum.GetName(typeof(Registers), slot.RegisterNumber);
+ Type regType = typeof(Amd64.Registers);
+ if (machine == Machine.ArmThumb2)
+ {
+ regType = typeof(Arm.Registers);
+ }
+ else
+ {
+ regType = typeof(Arm64.Registers);
+ }
+ slotStr = Enum.GetName(regType, slot.RegisterNumber);
}
else
{
--- /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;
+using System.Collections.Generic;
+using System.Text;
+
+namespace R2RDump.Arm
+{
+ /// <summary>
+ /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/jit/unwindarm.cpp">src/jit/unwindarm.cpp</a> mapRegNumToDwarfReg
+ /// </summary>
+ public enum Registers
+ {
+ R0,
+ R1,
+ R2,
+ R3,
+ R4,
+ R5,
+ R6,
+ R7,
+ R8,
+ R9,
+ R10,
+ R11,
+ R12,
+ R13,
+ R14,
+ R15,
+ F0,
+ F1,
+ F2,
+ F3,
+ F4,
+ F5,
+ F6,
+ F7,
+ F8,
+ F9,
+ F10,
+ F11,
+ F12,
+ F13,
+ F14,
+ F15,
+ F16,
+ F17,
+ F18,
+ F19,
+ F20,
+ F21,
+ F22,
+ F23,
+ F24,
+ F25,
+ F26,
+ F27,
+ F28,
+ F29,
+ F30,
+ F31,
+ }
+}
--- /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;
+using System.Xml.Serialization;
+
+namespace R2RDump.Arm
+{
+ public class Epilog
+ {
+ [XmlAttribute("Index")]
+ public int Index { get; set; }
+
+ public uint EpilogStartOffset { get; set; }
+ public uint Res { get; set; }
+ public uint Condition { get; set; }
+ public uint EpilogStartIndex { get; set; }
+ public uint EpilogStartOffsetFromMainFunctionBegin { get; set; }
+
+ public Epilog() { }
+
+ public Epilog(int index, int dw, uint startOffset)
+ {
+ Index = index;
+
+ EpilogStartOffset = UnwindInfo.ExtractBits(dw, 0, 18);
+ Res = UnwindInfo.ExtractBits(dw, 18, 2);
+ Condition = UnwindInfo.ExtractBits(dw, 20, 4);
+ EpilogStartIndex = UnwindInfo.ExtractBits(dw, 24, 8);
+
+ // Note that epilogStartOffset for a funclet is the offset from the beginning
+ // of the current funclet, not the offset from the beginning of the main function.
+ // To help find it when looking through JitDump output, also show the offset from
+ // the beginning of the main function.
+ EpilogStartOffsetFromMainFunctionBegin = EpilogStartOffset * 2 + startOffset;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.AppendLine($"\t\tEpilog Start Offset: 0x{EpilogStartOffset:X5} Actual offset = 0x{EpilogStartOffset * 2:X5} Offset from main function begin = 0x{EpilogStartOffsetFromMainFunctionBegin:X6}");
+ sb.AppendLine($"\t\tCondition: {Condition} (0x{Condition:X})" + ((Condition == 0xE) ? " (always)" : ""));
+ sb.Append($"\t\tEpilog Start Index: {EpilogStartIndex} (0x{EpilogStartIndex:X})");
+ return sb.ToString();
+ }
+ }
+
+ public class UnwindCode
+ {
+ [XmlAttribute("Index")]
+ public int Index { get; set; }
+
+ public UnwindCode() { }
+
+ public UnwindCode(int index)
+ {
+ Index = index;
+ }
+ }
+
+ /// <summary>
+ /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/jit/unwindarm.cpp">src/jit/unwindarm.cpp</a> DumpUnwindInfo
+ /// </summary>
+ public class UnwindInfo : BaseUnwindInfo
+ {
+ public uint CodeWords { get; set; }
+ public uint EpilogCount { get; set; }
+ public uint FBit { get; set; }
+ public uint EBit { get; set; }
+ public uint XBit { get; set; }
+ public uint Vers { get; set; }
+ public uint FunctionLength { get; set; }
+
+ public uint ExtendedCodeWords { get; set; }
+ public uint ExtendedEpilogCount { get; set; }
+
+ public Epilog[] Epilogs { get; set; }
+
+ public UnwindInfo() { }
+
+ public UnwindInfo(byte[] image, int offset)
+ {
+ uint startOffset = (uint)offset;
+
+ int dw = NativeReader.ReadInt32(image, ref offset);
+ CodeWords = ExtractBits(dw, 28, 4);
+ EpilogCount = ExtractBits(dw, 23, 5);
+ FBit = ExtractBits(dw, 22, 1);
+ EBit = ExtractBits(dw, 21, 1);
+ XBit = ExtractBits(dw, 20, 1);
+ Vers = ExtractBits(dw, 18, 2);
+ FunctionLength = ExtractBits(dw, 0, 18) * 2;
+
+ if (CodeWords == 0 && EpilogCount == 0)
+ {
+ // We have an extension word specifying a larger number of Code Words or Epilog Counts
+ // than can be specified in the header word.
+ dw = NativeReader.ReadInt32(image, ref offset);
+ ExtendedCodeWords = ExtractBits(dw, 16, 8);
+ ExtendedEpilogCount = ExtractBits(dw, 0, 16);
+ }
+
+ bool[] epilogStartAt = new bool[256]; // One byte per possible epilog start index; initialized to false
+
+ if (EBit == 0)
+ {
+ Epilogs = new Epilog[EpilogCount];
+ if (EpilogCount != 0)
+ {
+ for (int scope = 0; scope < EpilogCount; scope++)
+ {
+ dw = NativeReader.ReadInt32(image, ref offset);
+ Epilogs[scope] = new Epilog(scope, dw, startOffset);
+ epilogStartAt[Epilogs[scope].EpilogStartIndex] = true; // an epilog starts at this offset in the unwind codes
+ }
+ }
+ }
+ else
+ {
+ Epilogs = new Epilog[0];
+ epilogStartAt[EpilogCount] = true; // the one and only epilog starts its unwind codes at this offset
+ }
+
+ Size = offset - (int)startOffset + (int)CodeWords * 4;
+ int alignmentPad = ((Size + sizeof(int) - 1) & ~(sizeof(int) - 1)) - Size;
+ Size += (alignmentPad + sizeof(uint));
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.AppendLine($"\tCodeWords: {CodeWords}");
+ sb.AppendLine($"\tEpilogCount: {EpilogCount}");
+ sb.AppendLine($"\tFBit: {FBit}");
+ sb.AppendLine($"\tEBit: {EBit}");
+ sb.AppendLine($"\tXBit: {XBit}");
+ sb.AppendLine($"\tVers: {Vers}");
+ sb.AppendLine($"\tFunctionLength: {FunctionLength}");
+ if (CodeWords == 0 && EpilogCount == 0)
+ {
+ sb.AppendLine("\t---- Extension word ----");
+ sb.AppendLine($"\tExtended Code Words: {CodeWords}");
+ sb.AppendLine($"\tExtended Epilog Count: {EpilogCount}");
+ }
+ if (EpilogCount == 0)
+ {
+ sb.AppendLine("\tNo epilogs");
+ }
+ else
+ {
+ for (int i = 0; i < Epilogs.Length; i++)
+ {
+ sb.AppendLine("\t\t-------------------------");
+ sb.AppendLine(Epilogs[i].ToString());
+ sb.AppendLine("\t\t-------------------------");
+ }
+ }
+ return sb.ToString();
+ }
+
+ internal static uint ExtractBits(int dw, int start, int length)
+ {
+ return (uint)((dw >> start) & ((1 << length) - 1));
+ }
+ }
+}
--- /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;
+using System.Collections.Generic;
+using System.Text;
+
+namespace R2RDump.Arm64
+{
+ public enum Registers
+ {
+ X0,
+ X1,
+ X2,
+ X3,
+ X4,
+ X5,
+ X6,
+ X7,
+ X8,
+ X9,
+ X10,
+ X11,
+ X12,
+ X13,
+ X14,
+ X15,
+ X16,
+ X17,
+ X18,
+ X19,
+ X20,
+ X21,
+ X22,
+ X23,
+ X24,
+ X25,
+ X26,
+ X27,
+ X28,
+ X29,
+ X30,
+ }
+}
--- /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;
+using System.Xml.Serialization;
+
+namespace R2RDump.Arm64
+{
+ public class Epilog
+ {
+ [XmlAttribute("Index")]
+ public int Index { get; set; }
+
+ public uint EpilogStartOffset { get; set; }
+ public uint Res { get; set; }
+ public uint Condition { get; set; }
+ public uint EpilogStartIndex { get; set; }
+ public uint EpilogStartOffsetFromMainFunctionBegin { get; set; }
+
+ public Epilog() { }
+
+ public Epilog(int index, int dw, uint startOffset)
+ {
+ Index = index;
+
+ EpilogStartOffset = UnwindInfo.ExtractBits(dw, 0, 18);
+ Res = UnwindInfo.ExtractBits(dw, 18, 4);
+ Condition = UnwindInfo.ExtractBits(dw, 20, 4);
+ EpilogStartIndex = UnwindInfo.ExtractBits(dw, 22, 10);
+
+ // Note that epilogStartOffset for a funclet is the offset from the beginning
+ // of the current funclet, not the offset from the beginning of the main function.
+ // To help find it when looking through JitDump output, also show the offset from
+ // the beginning of the main function.
+ EpilogStartOffsetFromMainFunctionBegin = EpilogStartOffset * 4 + startOffset;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.AppendLine($"\t\tEpilog Start Offset: 0x{EpilogStartOffset:X5} Actual offset = 0x{EpilogStartOffset * 4:X5} Offset from main function begin = 0x{EpilogStartOffsetFromMainFunctionBegin:X6}");
+ sb.AppendLine($"\t\tCondition: {Condition} (0x{Condition:X})" + ((Condition == 0xE) ? " (always)" : ""));
+ sb.Append($"\t\tEpilog Start Index: {EpilogStartIndex} (0x{EpilogStartIndex:X})");
+ return sb.ToString();
+ }
+ }
+
+ public class UnwindCode
+ {
+ [XmlAttribute("Index")]
+ public int Index { get; set; }
+
+ public UnwindCode() { }
+
+ public UnwindCode(int index)
+ {
+ Index = index;
+
+ }
+ }
+
+ /// <summary>
+ /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/jit/unwindarm.cpp">src/jit/unwindarm.cpp</a> DumpUnwindInfo
+ /// </summary>
+ public class UnwindInfo : BaseUnwindInfo
+ {
+ public uint CodeWords { get; set; }
+ public uint EpilogCount { get; set; }
+ public uint EBit { get; set; }
+ public uint XBit { get; set; }
+ public uint Vers { get; set; }
+ public uint FunctionLength { get; set; }
+
+ public uint ExtendedCodeWords { get; set; }
+ public uint ExtendedEpilogCount { get; set; }
+
+ public Epilog[] Epilogs { get; set; }
+
+ public UnwindInfo() { }
+
+ public UnwindInfo(byte[] image, int offset)
+ {
+ uint startOffset = (uint)offset;
+
+ int dw = NativeReader.ReadInt32(image, ref offset);
+ CodeWords = ExtractBits(dw, 27, 5);
+ EpilogCount = ExtractBits(dw, 22, 5);
+ EBit = ExtractBits(dw, 21, 1);
+ XBit = ExtractBits(dw, 20, 1);
+ Vers = ExtractBits(dw, 18, 2);
+ FunctionLength = ExtractBits(dw, 0, 18) * 4;
+
+ if (CodeWords == 0 && EpilogCount == 0)
+ {
+ // We have an extension word specifying a larger number of Code Words or Epilog Counts
+ // than can be specified in the header word.
+ dw = NativeReader.ReadInt32(image, ref offset);
+ ExtendedCodeWords = ExtractBits(dw, 16, 8);
+ ExtendedEpilogCount = ExtractBits(dw, 0, 16);
+ }
+
+ bool[] epilogStartAt = new bool[1024]; // One byte per possible epilog start index; initialized to false
+
+ if (EBit == 0)
+ {
+ Epilogs = new Epilog[EpilogCount];
+ if (EpilogCount != 0)
+ {
+ for (int scope = 0; scope < EpilogCount; scope++)
+ {
+ dw = NativeReader.ReadInt32(image, ref offset);
+ Epilogs[scope] = new Epilog(scope, dw, startOffset);
+ epilogStartAt[Epilogs[scope].EpilogStartIndex] = true; // an epilog starts at this offset in the unwind codes
+ }
+ }
+ }
+ else
+ {
+ Epilogs = new Epilog[0];
+ epilogStartAt[EpilogCount] = true; // the one and only epilog starts its unwind codes at this offset
+ }
+
+
+
+ Size = offset - (int)startOffset + (int)CodeWords * 4;
+ int alignmentPad = ((Size + sizeof(int) - 1) & ~(sizeof(int) - 1)) - Size;
+ Size += (alignmentPad + sizeof(uint));
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.AppendLine($"\tCodeWords: {CodeWords}");
+ sb.AppendLine($"\tEpilogCount: {EpilogCount}");
+ sb.AppendLine($"\tEBit: {EBit}");
+ sb.AppendLine($"\tXBit: {XBit}");
+ sb.AppendLine($"\tVers: {Vers}");
+ sb.AppendLine($"\tFunctionLength: {FunctionLength}");
+ if (CodeWords == 0 && EpilogCount == 0)
+ {
+ sb.AppendLine("\t---- Extension word ----");
+ sb.AppendLine($"\tExtended Code Words: {CodeWords}");
+ sb.AppendLine($"\tExtended Epilog Count: {EpilogCount}");
+ }
+ if (EpilogCount == 0)
+ {
+ sb.AppendLine("\tNo epilogs");
+ }
+ else
+ {
+ for (int i = 0; i < Epilogs.Length; i++)
+ {
+ sb.AppendLine("\t\t-------------------------");
+ sb.AppendLine(Epilogs[i].ToString());
+ sb.AppendLine("\t\t-------------------------");
+ }
+ }
+ return sb.ToString();
+ }
+
+ internal static uint ExtractBits(int dw, int start, int length)
+ {
+ return (uint)((dw >> start) & ((1 << length) - 1));
+ }
+ }
+}
case Machine.ArmThumb2:
target = TargetArch.Target_Thumb;
break;
+ default:
+ R2RDump.WriteWarning($"{machine} not supported on CoreDisTools");
+ return IntPtr.Zero;
}
return InitBufferedDisasm(target);
}
public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, out string instruction)
{
+ if (_disasm == IntPtr.Zero)
+ {
+ instruction = "";
+ return rtf.Size;
+ }
+
int instrSize = CoreDisTools.GetInstruction(_disasm, rtf, imageOffset, rtfOffset, _image, out instruction);
switch (_machine)
SIZE_OF_RETURN_KIND_FAT = 4;
NUM_SAFE_POINTS_ENCBASE = 2;
break;
- case Machine.Arm:
+ case Machine.ArmThumb2:
CODE_LENGTH_ENCBASE = 7;
SECURITY_OBJECT_STACK_SLOT_ENCBASE = 5;
GS_COOKIE_STACK_SLOT_ENCBASE = 5;
{
switch (_target)
{
- case Machine.Arm:
+ case Machine.ArmThumb2:
return (x << 1);
case Machine.Arm64:
return (x << 2);
{
case Machine.Amd64:
return (x << 3);
- case Machine.Arm:
+ case Machine.ArmThumb2:
return (x << 2);
case Machine.Arm64:
return (x << 3);
{
case Machine.Amd64:
return (x ^ 5);
- case Machine.Arm:
+ case Machine.ArmThumb2:
return ((x ^ 7) + 4);
case Machine.Arm64:
return (x ^ 29);
{
case Machine.Amd64:
return (x << 3);
- case Machine.Arm:
+ case Machine.ArmThumb2:
return (x << 2);
case Machine.Arm64:
return (x << 3);
{
Size = (int)((x86.UnwindInfo)unwindInfo).FunctionLength;
}
+ else if (unwindInfo is Arm.UnwindInfo)
+ {
+ Size = (int)((Arm.UnwindInfo)unwindInfo).FunctionLength;
+ }
+ else if (unwindInfo is Arm64.UnwindInfo)
+ {
+ Size = (int)((Arm64.UnwindInfo)unwindInfo).FunctionLength;
+ }
else if (gcInfo != null)
{
Size = gcInfo.CodeLength;
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);
+ }
+ }
RuntimeFunction rtf = new RuntimeFunction(runtimeFunctionId, startRva, endRva, unwindRva, codeOffset, method, unwindInfo, gcInfo);
method.RuntimeFunctions.Add(rtf);
### READYTORUN_SECTION_IMPORT_SECTIONS
-A struct described in [READYTORUN_IMPORT_SECTION](../../inc/readytorun.h)
+A struct described in [READYTORUN_IMPORT_SECTION](../../inc/readytorun.h). Currently not parsed correctly
### READYTORUN_SECTION_RUNTIME_FUNCTIONS
-A array of RVAs. For x64, each RuntimeFunction has RVAs to the start of the assembly, end of the assembly, and start of the UnwindInfo. For x86, each RuntimeFunction has RVAs to the start of the assembly, and start of the UnwindInfo.
+A array of RVAs. For x64, each RuntimeFunction has RVAs to the start of the assembly, end of the assembly, and start of the UnwindInfo. For x86/Arm/Arm64, each RuntimeFunction has RVAs to the start of the assembly, and start of the UnwindInfo.
### READYTORUN_SECTION_METHODDEF_ENTRYPOINTS
For x86, it contains only an encoded function length
-For x64, it contains a bit field followed by an array of unwind codes ([_UNWIND_CODE](../../inc/win64unwind.h)) and finally padding to make it byte aligned
+For x64, Arm and Arm64, it contains a bit field followed by an array of unwind codes ([_UNWIND_CODE](../../inc/win64unwind.h)) and finally padding to make it byte aligned
The unwind data info structure is used to record the effects a function has on the stack pointer and where the nonvolatile registers are saved on the stack (see https://msdn.microsoft.com/en-us/library/0kd71y96.aspx)
Written into the ReadyToRun image right after UnwindInfo. Contains a header, GcSlots and GcTransitions (register liveness).
-The x64 GcInfo is written in crossgen by [GcInfoEncoder::Build](../../gcinfo/gcinfoencoder.cpp) and decoded similar to [GcInfoDecoder::EnumerateLiveSlots](../../vm/gcinfodecoder.cpp). The x86 gcInfo is written by [GCInfo::gcMakeRegPtrTable](../../jit/gcencode.cpp) and decoded similar to [GCDump::DumpGCTable](../../gcdump/i386/gcdumpx86.cpp)
+The x64/Arm/Arm64 GcInfo is written in crossgen by [GcInfoEncoder::Build](../../gcinfo/gcinfoencoder.cpp) and decoded similar to [GcInfoDecoder::EnumerateLiveSlots](../../vm/gcinfodecoder.cpp). The x86 gcInfo is written by [GCInfo::gcMakeRegPtrTable](../../jit/gcencode.cpp) and decoded similar to [GCDump::DumpGCTable](../../gcdump/i386/gcdumpx86.cpp)
Contains the code length followed by the header, GcSlots, and finally GcTransitions
The header contains flags indicating which properties are in the GcInfo. GcSlots gives details on the registers or stack pointer offsets that are used in the method. GcTransitions give the CodeOffsets (which line in the assembly code) where GcSlots (excluding untracked slots) become live or dead
-In x64, GcTransitions are grouped into chunks where each chunk covers NUM_NORM_CODE_OFFSETS_PER_CHUNK lines of assembly code. The following format is used:
+In x64/Arm/Arm64, GcTransitions are grouped into chunks where each chunk covers NUM_NORM_CODE_OFFSETS_PER_CHUNK lines of assembly code. The following format is used:
> Array of offsets pointing to each chunk
> Padding to make it byte aligned
* Support R2RDump on ARM and ARM64 (https://github.com/dotnet/coreclr/issues/19089)
-* Parse R2RSections: READYTORUN_SECTION_EXCEPTION_INFO, READYTORUN_SECTION_DEBUG_INFO, READYTORUN_SECTION_DELAYLOAD_METHODCALL_THUNKS, READYTORUN_SECTION_INLINING_INFO, READYTORUN_SECTION_PROFILEDATA_INFO
+* Fix issue with invalid machine type in COFF header (https://github.com/dotnet/coreclr/issues/19592)
+
+* Parse R2RSections: READYTORUN_SECTION_EXCEPTION_INFO, READYTORUN_SECTION_DEBUG_INFO, READYTORUN_SECTION_DELAYLOAD_METHODCALL_THUNKS, READYTORUN_SECTION_INLINING_INFO, READYTORUN_SECTION_PROFILEDATA_INFO (https://github.com/dotnet/coreclr/issues/19616)
* Reenable R2RDumpTests after making it less fragile
+
+* Fix issue with disasm on Arm (https://github.com/dotnet/coreclr/issues/19637)
WriteSubDivider();
_writer.WriteLine(method.ToString());
- if (_gc)
+ if (_gc && method.GcInfo != null)
{
_writer.WriteLine("GcInfo:");
_writer.Write(method.GcInfo);
string instr;
int instrSize = _disassembler.GetInstruction(rtf, imageOffset, rtfOffset, out instr);
- _writer.Write(instr);
-
if (_r2r.Machine == Machine.Amd64 && ((Amd64.UnwindInfo)rtf.UnwindInfo).UnwindCodes.ContainsKey(codeOffset))
{
List<Amd64.UnwindCode> codes = ((Amd64.UnwindInfo)rtf.UnwindInfo).UnwindCodes[codeOffset];
}
}
+ /* According to https://msdn.microsoft.com/en-us/library/ck9asaa9.aspx and src/vm/gcinfodecoder.cpp
+ * UnwindCode and GcTransition CodeOffsets are encoded with a -1 adjustment (that is, it's the offset of the start of the next instruction)
+ */
+ _writer.Write(instr);
+
CoreDisTools.ClearOutputBuffer();
rtfOffset += instrSize;
codeOffset += instrSize;
_writer.WriteLine("Signature Bytes:");
DumpBytes(importSection.SignatureRVA, (uint)importSection.Entries.Count * sizeof(int));
}
- if (importSection.AuxiliaryDataRVA != 0)
+ if (importSection.AuxiliaryDataRVA != 0 && importSection.AuxiliaryData != null)
{
_writer.WriteLine("AuxiliaryData Bytes:");
DumpBytes(importSection.AuxiliaryDataRVA, (uint)importSection.AuxiliaryData.Size);