/// <summary> /// Dumps disassembly and register liveness /// </summary> internal override void DumpDisasm(RuntimeFunction rtf, int imageOffset) { string indentString = new string(' ', _disassembler.MnemonicIndentation); int codeOffset = rtf.CodeOffset; int rtfOffset = 0; while (rtfOffset < rtf.Size) { string instr; int instrSize = _disassembler.GetInstruction(rtf, imageOffset, rtfOffset, out instr); if (_r2r.Machine == Machine.Amd64 && ((ILCompiler.Reflection.ReadyToRun.Amd64.UnwindInfo)rtf.UnwindInfo).CodeOffsetToUnwindCodeIndex.TryGetValue(codeOffset, out int unwindCodeIndex)) { ILCompiler.Reflection.ReadyToRun.Amd64.UnwindCode code = ((ILCompiler.Reflection.ReadyToRun.Amd64.UnwindInfo)rtf.UnwindInfo).UnwindCodes[unwindCodeIndex]; _writer.Write($"{indentString}{code.UnwindOp} {code.OpInfoStr}"); if (code.NextFrameOffset != -1) { _writer.WriteLine($"{indentString}{code.NextFrameOffset}"); } _writer.WriteLine(); } BaseGcInfo gcInfo = (_options.HideTransitions ? null : rtf.Method?.GcInfo); if (gcInfo != null && gcInfo.Transitions.TryGetValue(codeOffset, out List <BaseGcTransition> transitionsForOffset)) { string[] formattedTransitions = new string[transitionsForOffset.Count]; for (int transitionIndex = 0; transitionIndex < formattedTransitions.Length; transitionIndex++) { formattedTransitions[transitionIndex] = transitionsForOffset[transitionIndex].ToString(); } if (_options.Normalize) { Array.Sort(formattedTransitions); } foreach (string transition in formattedTransitions) { _writer.WriteLine($"{indentString}{transition}"); } } /* 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); rtfOffset += instrSize; codeOffset += instrSize; } }
public static void WriteTo(this RuntimeFunction theThis, TextWriter writer, DumpOptions options) { if (!options.Naked) { writer.WriteLine($"Id: {theThis.Id}"); writer.WriteLine($"StartAddress: 0x{theThis.StartAddress:X8}"); } if (theThis.Size == -1) { writer.WriteLine("Size: Unavailable"); } else { writer.WriteLine($"Size: {theThis.Size} bytes"); } if (!options.Naked) { writer.WriteLine($"UnwindRVA: 0x{theThis.UnwindRVA:X8}"); } if (theThis.UnwindInfo is ILCompiler.Reflection.ReadyToRun.Amd64.UnwindInfo amd64UnwindInfo) { string parsedFlags = ""; if ((amd64UnwindInfo.Flags & (int)ILCompiler.Reflection.ReadyToRun.Amd64.UnwindFlags.UNW_FLAG_EHANDLER) != 0) { parsedFlags += " EHANDLER"; } if ((amd64UnwindInfo.Flags & (int)ILCompiler.Reflection.ReadyToRun.Amd64.UnwindFlags.UNW_FLAG_UHANDLER) != 0) { parsedFlags += " UHANDLER"; } if ((amd64UnwindInfo.Flags & (int)ILCompiler.Reflection.ReadyToRun.Amd64.UnwindFlags.UNW_FLAG_CHAININFO) != 0) { parsedFlags += " CHAININFO"; } if (parsedFlags.Length == 0) { parsedFlags = " NHANDLER"; } writer.WriteLine($"Version: {amd64UnwindInfo.Version}"); writer.WriteLine($"Flags: 0x{amd64UnwindInfo.Flags:X2}{parsedFlags}"); writer.WriteLine($"SizeOfProlog: 0x{amd64UnwindInfo.SizeOfProlog:X4}"); writer.WriteLine($"CountOfUnwindCodes: {amd64UnwindInfo.CountOfUnwindCodes}"); writer.WriteLine($"FrameRegister: {((amd64UnwindInfo.FrameRegister == 0) ? "None" : amd64UnwindInfo.FrameRegister.ToString())}"); writer.WriteLine($"FrameOffset: 0x{amd64UnwindInfo.FrameOffset}"); if (!options.Naked) { writer.WriteLine($"PersonalityRVA: 0x{amd64UnwindInfo.PersonalityRoutineRVA:X4}"); } for (int unwindCodeIndex = 0; unwindCodeIndex < amd64UnwindInfo.CountOfUnwindCodes; unwindCodeIndex++) { ILCompiler.Reflection.ReadyToRun.Amd64.UnwindCode unwindCode = amd64UnwindInfo.UnwindCodeArray[unwindCodeIndex]; writer.Write($"UnwindCode[{unwindCode.Index}]: "); writer.Write($"CodeOffset 0x{unwindCode.CodeOffset:X4} "); writer.Write($"FrameOffset 0x{unwindCode.FrameOffset:X4} "); writer.Write($"NextOffset 0x{unwindCode.NextFrameOffset} "); writer.Write($"Op {unwindCode.OpInfoStr}"); writer.WriteLine(); } } writer.WriteLine(); if (theThis.EHInfo != null) { writer.WriteLine($@"EH info @ {theThis.EHInfo.RelativeVirtualAddress:X4}, #clauses = {theThis.EHInfo.EHClauses.Count}"); theThis.EHInfo.WriteTo(writer); writer.WriteLine(); } if (theThis.DebugInfo != null) { theThis.DebugInfo.WriteTo(writer, options); } }
public static void WriteTo(this RuntimeFunction theThis, TextWriter writer, DumpOptions options) { if (!options.Naked) { writer.WriteLine($"Id: {theThis.Id}"); writer.WriteLine($"StartAddress: 0x{theThis.StartAddress:X8}"); } if (theThis.Size == -1) { writer.WriteLine("Size: Unavailable"); } else { writer.WriteLine($"Size: {theThis.Size} bytes"); } if (!options.Naked) { writer.WriteLine($"UnwindRVA: 0x{theThis.UnwindRVA:X8}"); } if (theThis.UnwindInfo is ILCompiler.Reflection.ReadyToRun.Amd64.UnwindInfo amd64UnwindInfo) { string parsedFlags = ""; if ((amd64UnwindInfo.Flags & (int)ILCompiler.Reflection.ReadyToRun.Amd64.UnwindFlags.UNW_FLAG_EHANDLER) != 0) { parsedFlags += " EHANDLER"; } if ((amd64UnwindInfo.Flags & (int)ILCompiler.Reflection.ReadyToRun.Amd64.UnwindFlags.UNW_FLAG_UHANDLER) != 0) { parsedFlags += " UHANDLER"; } if ((amd64UnwindInfo.Flags & (int)ILCompiler.Reflection.ReadyToRun.Amd64.UnwindFlags.UNW_FLAG_CHAININFO) != 0) { parsedFlags += " CHAININFO"; } if (parsedFlags.Length == 0) { parsedFlags = " NHANDLER"; } writer.WriteLine($"Version: {amd64UnwindInfo.Version}"); writer.WriteLine($"Flags: 0x{amd64UnwindInfo.Flags:X2}{parsedFlags}"); writer.WriteLine($"SizeOfProlog: 0x{amd64UnwindInfo.SizeOfProlog:X4}"); writer.WriteLine($"CountOfUnwindCodes: {amd64UnwindInfo.CountOfUnwindCodes}"); writer.WriteLine($"FrameRegister: {amd64UnwindInfo.FrameRegister}"); writer.WriteLine($"FrameOffset: 0x{amd64UnwindInfo.FrameOffset}"); if (!options.Naked) { writer.WriteLine($"PersonalityRVA: 0x{amd64UnwindInfo.PersonalityRoutineRVA:X4}"); } for (int unwindCodeIndex = 0; unwindCodeIndex < amd64UnwindInfo.CountOfUnwindCodes; unwindCodeIndex++) { ILCompiler.Reflection.ReadyToRun.Amd64.UnwindCode unwindCode = amd64UnwindInfo.UnwindCodeArray[unwindCodeIndex]; writer.Write($"UnwindCode[{unwindCode.Index}]: "); writer.Write($"CodeOffset 0x{unwindCode.CodeOffset:X4} "); writer.Write($"FrameOffset 0x{unwindCode.FrameOffset:X4} "); writer.Write($"NextOffset 0x{unwindCode.NextFrameOffset} "); writer.Write($"Op {unwindCode.OpInfoStr}"); writer.WriteLine(); } } writer.WriteLine(); if (theThis.Method.GcInfo is ILCompiler.Reflection.ReadyToRun.Amd64.GcInfo gcInfo) { writer.WriteLine("GC info:"); writer.WriteLine($@" Version: {gcInfo.Version}"); writer.WriteLine($@" ReturnKind: {gcInfo.ReturnKind}"); writer.WriteLine($@" ValidRangeStart: 0x{gcInfo.ValidRangeStart:X4}"); writer.WriteLine($@" ValidRangeEnd: 0x{gcInfo.ValidRangeEnd:X4}"); writer.WriteLine($@" SecurityObjectStackSlot: 0x{gcInfo.SecurityObjectStackSlot:X4}"); writer.WriteLine($@" GSCookieStackSlot: 0x{gcInfo.GSCookieStackSlot:X4}"); writer.WriteLine($@" PSPSymStackSlot: 0x{gcInfo.PSPSymStackSlot:X4}"); writer.WriteLine($@" GenericsInstContextStackSlot: 0x{gcInfo.GenericsInstContextStackSlot:X4}"); writer.WriteLine($@" StackBaseRegister: {gcInfo.StackBaseRegister}"); writer.WriteLine($@" SizeOfENCPreservedArea: 0x{gcInfo.SizeOfEditAndContinuePreservedArea:X4}"); writer.WriteLine($@" ReversePInvokeFrameStackSlot: 0x{gcInfo.ReversePInvokeFrameStackSlot:X4}"); writer.WriteLine($@" SizeOfStackOutgoingAndScratchArea: 0x{gcInfo.SizeOfStackOutgoingAndScratchArea:X4}"); writer.WriteLine($@" NumSafePoints: {gcInfo.NumSafePoints}"); writer.WriteLine($@" NumInterruptibleRanges: {gcInfo.NumInterruptibleRanges}"); writer.WriteLine($@" SafePointOffsets: {gcInfo.SafePointOffsets.Count}"); foreach (ILCompiler.Reflection.ReadyToRun.Amd64.GcInfo.SafePointOffset safePoint in gcInfo.SafePointOffsets) { writer.WriteLine($@" Index: {safePoint.Index,2}; Value: 0x{safePoint.Value:X4}"); if (gcInfo.LiveSlotsAtSafepoints != null) { writer.WriteLine($@" Live slots: {String.Join(", ", gcInfo.LiveSlotsAtSafepoints[safePoint.Index])}"); } } writer.WriteLine($@" InterruptibleRanges: {gcInfo.InterruptibleRanges.Count}"); foreach (ILCompiler.Reflection.ReadyToRun.Amd64.InterruptibleRange range in gcInfo.InterruptibleRanges) { writer.WriteLine($@" Index: {range.Index,2}; StartOffset: 0x{range.StartOffset:X4}; StopOffset: 0x{range.StopOffset:X4}"); } writer.WriteLine(" SlotTable:"); writer.WriteLine($@" NumRegisters: {gcInfo.SlotTable.NumRegisters}"); writer.WriteLine($@" NumStackSlots: {gcInfo.SlotTable.NumStackSlots}"); writer.WriteLine($@" NumUntracked: {gcInfo.SlotTable.NumUntracked}"); writer.WriteLine($@" NumSlots: {gcInfo.SlotTable.NumSlots}"); writer.WriteLine($@" GcSlots: {gcInfo.SlotTable.GcSlots.Count}"); foreach (ILCompiler.Reflection.ReadyToRun.Amd64.GcSlotTable.GcSlot slot in gcInfo.SlotTable.GcSlots) { writer.WriteLine($@" Index: {slot.Index,2}; RegisterNumber: {slot.RegisterNumber,2}; Flags: {slot.Flags}"); } writer.WriteLine(); } if (theThis.EHInfo != null) { writer.WriteLine($@"EH info @ {theThis.EHInfo.EHInfoRVA:X4}, #clauses = {theThis.EHInfo.EHClauses.Length}"); theThis.EHInfo.WriteTo(writer); writer.WriteLine(); } if (theThis.DebugInfo != null) { theThis.DebugInfo.WriteTo(writer, options); } }