/// <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); UnwindCodes = new List <UnwindCode>(CountOfUnwindCodes); CodeOffsetToUnwindCodeIndex = new Dictionary <int, int>(); int frameOffset = FrameOffset; int sizeOfUnwindCodes = CountOfUnwindCodes * _sizeofUnwindCode; int endOffset = offset + sizeOfUnwindCodes; while (offset < endOffset) { UnwindCode unwindCode = new UnwindCode(image, ref frameOffset, ref offset); CodeOffsetToUnwindCodeIndex.Add(unwindCode.CodeOffset, UnwindCodes.Count); UnwindCodes.Add(unwindCode); } Size = _offsetofUnwindCode + sizeOfUnwindCodes; 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); }
/// <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, 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); Debug.Assert(!UnwindCodes.ContainsKey(UnwindCodeArray[i].CodeOffset)); UnwindCodes.Add(UnwindCodeArray[i].CodeOffset, 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); }
/// <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) { // TODO (refactoring) - what should we do? // 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; } }