public RuntimeFunction( int id, int startRva, int endRva, int unwindRva, int codeOffset, R2RMethod method, BaseUnwindInfo unwindInfo, BaseGcInfo gcInfo, EHInfo ehInfo, DebugInfo debugInfo) { Id = id; StartAddress = startRva; UnwindRVA = unwindRva; Method = method; UnwindInfo = unwindInfo; DebugInfo = debugInfo; if (endRva != -1) { Size = endRva - startRva; } else if (unwindInfo is x86.UnwindInfo) { 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; } else { Size = -1; } CodeOffset = codeOffset; method.GcInfo = gcInfo; EHInfo = ehInfo; }
public void WriteTo(TextWriter writer, DumpOptions options) { if (!options.Naked) { writer.WriteLine($"Id: {Id}"); writer.WriteLine($"StartAddress: 0x{StartAddress:X8}"); } if (Size == -1) { writer.WriteLine("Size: Unavailable"); } else { writer.WriteLine($"Size: {Size} bytes"); } if (!options.Naked) { writer.WriteLine($"UnwindRVA: 0x{UnwindRVA:X8}"); } if (UnwindInfo is Amd64.UnwindInfo amd64UnwindInfo) { string parsedFlags = ""; if ((amd64UnwindInfo.Flags & (int)Amd64.UnwindFlags.UNW_FLAG_EHANDLER) != 0) { parsedFlags += " EHANDLER"; } if ((amd64UnwindInfo.Flags & (int)Amd64.UnwindFlags.UNW_FLAG_UHANDLER) != 0) { parsedFlags += " UHANDLER"; } if ((amd64UnwindInfo.Flags & (int)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++) { 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 (Method.GcInfo is 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 (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 (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 (Amd64.GcSlotTable.GcSlot slot in gcInfo.SlotTable.GcSlots) { writer.WriteLine($@" Index: {slot.Index,2}; RegisterNumber: {slot.RegisterNumber,2}; Flags: {slot.Flags}"); } writer.WriteLine(); } if (EHInfo != null) { writer.WriteLine($@"EH info @ {EHInfo.EHInfoRVA:X4}, #clauses = {EHInfo.EHClauses.Length}"); EHInfo.WriteTo(writer); writer.WriteLine(); } if (DebugInfo != null) { DebugInfo.WriteTo(writer, options); } }
public void WriteTo(TextWriter writer, DumpOptions options) { writer.WriteLine($"Id: {Id}"); writer.WriteLine($"StartAddress: 0x{StartAddress:X8}"); if (Size == -1) { writer.WriteLine("Size: Unavailable"); } else { writer.WriteLine($"Size: {Size} bytes"); } writer.WriteLine($"UnwindRVA: 0x{UnwindRVA:X8}"); if (UnwindInfo is Amd64.UnwindInfo amd64UnwindInfo) { string parsedFlags = ""; if ((amd64UnwindInfo.Flags & (int)Amd64.UnwindFlags.UNW_FLAG_EHANDLER) != 0) { parsedFlags += " EHANDLER"; } if ((amd64UnwindInfo.Flags & (int)Amd64.UnwindFlags.UNW_FLAG_UHANDLER) != 0) { parsedFlags += " UHANDLER"; } if ((amd64UnwindInfo.Flags & (int)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}"); writer.WriteLine($"PersonalityRVA: 0x{amd64UnwindInfo.PersonalityRoutineRVA:X4}"); for (int unwindCodeIndex = 0; unwindCodeIndex < amd64UnwindInfo.CountOfUnwindCodes; unwindCodeIndex++) { 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 (EHInfo != null) { writer.WriteLine($@"EH info @ {EHInfo.EHInfoRVA:X4}, #clauses = {EHInfo.EHClauses.Length}"); EHInfo.WriteTo(writer); writer.WriteLine(); } if (DebugInfo != null) { DebugInfo.WriteTo(writer, options); } }
/// <summary> /// Get the RVAs of the runtime functions for each method /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/zap/zapcode.cpp">ZapUnwindInfo::Save</a> /// </summary> private void ParseRuntimeFunctions(bool[] isEntryPoint, int runtimeFunctionOffset, int runtimeFunctionSize) { int curOffset = 0; foreach (R2RMethod method in R2RMethods) { int runtimeFunctionId = method.EntryPointRuntimeFunctionId; if (runtimeFunctionId == -1) { continue; } curOffset = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize; BaseGcInfo gcInfo = null; int codeOffset = 0; do { int startRva = NativeReader.ReadInt32(Image, ref curOffset); int endRva = -1; if (Machine == Machine.Amd64) { endRva = NativeReader.ReadInt32(Image, ref curOffset); } int unwindRva = NativeReader.ReadInt32(Image, ref curOffset); int unwindOffset = GetOffset(unwindRva); BaseUnwindInfo unwindInfo = null; if (Machine == Machine.Amd64) { unwindInfo = new Amd64.UnwindInfo(Image, unwindOffset); if (isEntryPoint[runtimeFunctionId]) { gcInfo = new Amd64.GcInfo(Image, unwindOffset + unwindInfo.Size, Machine, R2RHeader.MajorVersion); } } else if (Machine == Machine.I386) { unwindInfo = new x86.UnwindInfo(Image, unwindOffset); if (isEntryPoint[runtimeFunctionId]) { 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); } } EHInfo ehInfo = null; EHInfoLocation ehInfoLocation; if (EHLookupTable != null && EHLookupTable.RuntimeFunctionToEHInfoMap.TryGetValue(startRva, out ehInfoLocation)) { ehInfo = new EHInfo(this, ehInfoLocation.EHInfoRVA, startRva, GetOffset(ehInfoLocation.EHInfoRVA), ehInfoLocation.ClauseCount); } RuntimeFunction rtf = new RuntimeFunction( runtimeFunctionId, startRva, endRva, unwindRva, codeOffset, method, unwindInfo, gcInfo, ehInfo, _runtimeFunctionToDebugInfo.GetValueOrDefault(runtimeFunctionId)); method.RuntimeFunctions.Add(rtf); runtimeFunctionId++; codeOffset += rtf.Size; }while (runtimeFunctionId < isEntryPoint.Length && !isEntryPoint[runtimeFunctionId]); } }