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 = (Amd64Registers)(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; int alignmentPad = ((Size + sizeof(int) - 1) & ~(sizeof(int) - 1)) - Size; Size += (alignmentPad + sizeof(uint)); }
/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/zap/zapcode.cpp">ZapUnwindData::Save</a> /// </summary> 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 = (Registers)(frameRegisterAndOffset & 15); FrameOffset = (byte)(frameRegisterAndOffset >> 4); UnwindCodeArray = new UnwindCode[CountOfUnwindCodes]; UnwindCodes = new Dictionary <int, List <UnwindCode> >(); for (int i = 0; i < CountOfUnwindCodes; i++) { UnwindCodeArray[i] = new UnwindCode(image, i, ref offset); } for (int i = 0; i < CountOfUnwindCodes; i++) { ParseUnwindCode(ref i); if (!UnwindCodes.ContainsKey(UnwindCodeArray[i].CodeOffset)) { UnwindCodes[UnwindCodeArray[i].CodeOffset] = new List <UnwindCode>(); } UnwindCodes[UnwindCodeArray[i].CodeOffset].Add(UnwindCodeArray[i]); } Size = _offsetofUnwindCode + CountOfUnwindCodes * _sizeofUnwindCode; int alignmentPad = -Size & 3; Size += alignmentPad + sizeof(uint); // Personality routine RVA must be at 4-aligned address offset += alignmentPad; PersonalityRoutineRVA = NativeReader.ReadUInt32(image, ref offset); }
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); } }
public override string ToString() { StringBuilder sb = new StringBuilder(); sb.AppendLine($"Id: {Id}"); sb.AppendLine($"StartAddress: 0x{StartAddress:X8}"); if (Size == -1) { sb.AppendLine("Size: Unavailable"); } else { sb.AppendLine($"Size: {Size} bytes"); } sb.AppendLine($"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"; } sb.AppendLine($"Version: {amd64UnwindInfo.Version}"); sb.AppendLine($"Flags: 0x{amd64UnwindInfo.Flags:X2}{parsedFlags}"); sb.AppendLine($"SizeOfProlog: 0x{amd64UnwindInfo.SizeOfProlog:X4}"); sb.AppendLine($"CountOfUnwindCodes: {amd64UnwindInfo.CountOfUnwindCodes}"); sb.AppendLine($"FrameRegister: {amd64UnwindInfo.FrameRegister}"); sb.AppendLine($"FrameOffset: 0x{amd64UnwindInfo.FrameOffset}"); sb.AppendLine($"PersonalityRVA: 0x{amd64UnwindInfo.PersonalityRoutineRVA:X4}"); for (int unwindCodeIndex = 0; unwindCodeIndex < amd64UnwindInfo.CountOfUnwindCodes; unwindCodeIndex++) { Amd64.UnwindCode unwindCode = amd64UnwindInfo.UnwindCodeArray[unwindCodeIndex]; sb.Append($"UnwindCode[{unwindCode.Index}]: "); sb.Append($"CodeOffset 0x{unwindCode.CodeOffset:X4} "); sb.Append($"FrameOffset 0x{unwindCode.FrameOffset:X4} "); sb.Append($"NextOffset 0x{unwindCode.NextFrameOffset} "); sb.Append($"Op {unwindCode.OpInfoStr}"); sb.AppendLine(); } } sb.AppendLine(); if (DebugInfo != null) { sb.AppendLine(DebugInfo.ToString()); } return(sb.ToString()); }
/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/jit/unwindamd64.cpp">src\jit\unwindamd64.cpp</a> DumpUnwindInfo /// </summary> private void ParseUnwindCode(ref int i) { UnwindCode code = UnwindCodeArray[i]; code.IsOpInfo = true; switch (code.UnwindOp) { case UnwindOpCodes.UWOP_PUSH_NONVOL: code.OpInfoStr = $"{(Registers)code.OpInfo}({code.OpInfo})"; break; case UnwindOpCodes.UWOP_ALLOC_LARGE: code.OpInfoStr = $"{code.OpInfo} - "; if (code.OpInfo == 0) { i++; UnwindCodeArray[i].OpInfoStr += "Scaled small"; code.NextFrameOffset = (int)UnwindCodeArray[i].FrameOffset * 8; } else if (code.OpInfo == 1) { i++; UnwindCodeArray[i].OpInfoStr += "Unscaled large"; uint offset = UnwindCodeArray[i].FrameOffset; i++; offset = ((UnwindCodeArray[i].FrameOffset << 16) | offset); code.NextFrameOffset = (int)offset; } else { code.OpInfoStr += "Unknown"; } break; case UnwindOpCodes.UWOP_ALLOC_SMALL: int opInfo = code.OpInfo * 8 + 8; code.OpInfoStr = $"{opInfo}"; break; case UnwindOpCodes.UWOP_SET_FPREG: code.OpInfoStr = $"Unused({code.OpInfo})"; break; case UnwindOpCodes.UWOP_SET_FPREG_LARGE: { code.OpInfoStr = $"Unused({code.OpInfo})"; i++; uint offset = UnwindCodeArray[i].FrameOffset; i++; offset = ((UnwindCodeArray[i].FrameOffset << 16) | offset); code.NextFrameOffset = (int)offset * 16; if ((UnwindCodeArray[i].FrameOffset & 0xF0000000) != 0) { R2RDump.WriteWarning("Illegal unwindInfo unscaled offset: too large"); } } break; case UnwindOpCodes.UWOP_SAVE_NONVOL: { code.OpInfoStr = $"{(Registers)code.OpInfo}({code.OpInfo})"; i++; uint offset = UnwindCodeArray[i].FrameOffset * 8; code.NextFrameOffset = (int)offset; } break; case UnwindOpCodes.UWOP_SAVE_NONVOL_FAR: { code.OpInfoStr = $"{(Registers)code.OpInfo}({code.OpInfo})"; i++; uint offset = UnwindCodeArray[i].FrameOffset; i++; offset = ((UnwindCodeArray[i].FrameOffset << 16) | offset); code.NextFrameOffset = (int)offset; } break; case UnwindOpCodes.UWOP_SAVE_XMM128: { code.OpInfoStr = $"XMM{code.OpInfo}({code.OpInfo})"; i++; uint offset = UnwindCodeArray[i].FrameOffset * 16; code.NextFrameOffset = (int)offset; } break; case UnwindOpCodes.UWOP_SAVE_XMM128_FAR: { code.OpInfoStr = $"XMM{code.OpInfo}({code.OpInfo})"; i++; uint offset = UnwindCodeArray[i].FrameOffset; i++; offset = ((UnwindCodeArray[i].FrameOffset << 16) | offset); code.NextFrameOffset = (int)offset; } break; } }