/// <summary> /// Unwinde code parsing is based on <a href="https://github.com/dotnet/coreclr/blob/master/src/jit/unwindamd64.cpp">src\jit\unwindamd64.cpp</a> DumpUnwindInfo /// </summary> public UnwindCode(byte[] image, ref int frameOffset, ref int offset) { CodeOffset = NativeReader.ReadByte(image, ref offset); byte op = NativeReader.ReadByte(image, ref offset); UnwindOp = (UnwindOpCodes)(op & 15); OpInfo = (byte)(op >> 4); OffsetLow = CodeOffset; OffsetHigh = OpInfo; FrameOffset = frameOffset; switch (UnwindOp) { case UnwindOpCodes.UWOP_PUSH_NONVOL: OpInfoStr = $"{(Registers)OpInfo}({OpInfo})"; break; case UnwindOpCodes.UWOP_ALLOC_LARGE: OpInfoStr = $"{OpInfo} - "; if (OpInfo == 0) { OpInfoStr += "Scaled small"; NextFrameOffset = 8 * NativeReader.ReadUInt16(image, ref offset); } else if (OpInfo == 1) { OpInfoStr += "Unscaled large"; uint nextOffset = NativeReader.ReadUInt16(image, ref offset); NextFrameOffset = (int)((uint)(NativeReader.ReadUInt16(image, ref offset) << 16) | nextOffset); } else { throw new BadImageFormatException(); } break; case UnwindOpCodes.UWOP_ALLOC_SMALL: int opInfo = OpInfo * 8 + 8; OpInfoStr = $"{opInfo}"; break; case UnwindOpCodes.UWOP_SET_FPREG: OpInfoStr = $"Unused({OpInfo})"; break; case UnwindOpCodes.UWOP_SET_FPREG_LARGE: { OpInfoStr = $"Unused({OpInfo})"; uint nextOffset = NativeReader.ReadUInt16(image, ref offset); nextOffset = ((uint)(NativeReader.ReadUInt16(image, ref offset) << 16) | nextOffset); NextFrameOffset = (int)nextOffset * 16; if ((NextFrameOffset & 0xF0000000) != 0) { throw new BadImageFormatException("Warning: Illegal unwindInfo unscaled offset: too large"); } } break; case UnwindOpCodes.UWOP_SAVE_NONVOL: { OpInfoStr = $"{(Registers)OpInfo}({OpInfo})"; NextFrameOffset = NativeReader.ReadUInt16(image, ref offset) * 8; } break; case UnwindOpCodes.UWOP_SAVE_NONVOL_FAR: { OpInfoStr = $"{(Registers)OpInfo}({OpInfo})"; uint nextOffset = NativeReader.ReadUInt16(image, ref offset); NextFrameOffset = (int)((uint)(NativeReader.ReadUInt16(image, ref offset) << 16) | nextOffset); } break; case UnwindOpCodes.UWOP_SAVE_XMM128: { OpInfoStr = $"XMM{OpInfo}({OpInfo})"; NextFrameOffset = (int)NativeReader.ReadUInt16(image, ref offset) * 16; } break; case UnwindOpCodes.UWOP_SAVE_XMM128_FAR: { OpInfoStr = $"XMM{OpInfo}({OpInfo})"; uint nextOffset = NativeReader.ReadUInt16(image, ref offset); NextFrameOffset = (int)((uint)(NativeReader.ReadUInt16(image, ref offset) << 16) | nextOffset); } break; default: throw new NotImplementedException(UnwindOp.ToString()); } NextFrameOffset = frameOffset; }
private static ushort PackUnwindOp(UnwindOp op, int prologOffset, int opInfo) { return((ushort)(prologOffset | ((int)op << 8) | (opInfo << 12))); }