private string GetUnwindCode(ref int i) { StringBuilder sb = new StringBuilder(); string tab2 = new string(' ', 8); sb.AppendLine($"{tab2}CodeOffset: 0x{UnwindCode[i].CodeOffset:X2}"); sb.AppendLine($"{tab2}UnwindOp: {UnwindCode[i].UnwindOp}({(byte)UnwindCode[i].UnwindOp})"); switch (UnwindCode[i].UnwindOp) { case UnwindOpCodes.UWOP_PUSH_NONVOL: sb.AppendLine($"{tab2}OpInfo: {(Amd64Registers)UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})"); break; case UnwindOpCodes.UWOP_ALLOC_LARGE: sb.Append($"{tab2}OpInfo: {UnwindCode[i].OpInfo} - "); if (UnwindCode[i].OpInfo == 0) { i++; sb.AppendLine("Scaled small"); uint frameOffset = UnwindCode[i].FrameOffset * 8; sb.AppendLine($"{tab2}FrameOffset: {UnwindCode[i].FrameOffset} * 8 = {frameOffset} = 0x{frameOffset:X5})"); } else if (UnwindCode[i].OpInfo == 1) { i++; sb.AppendLine("Unscaled large"); uint offset = UnwindCode[i].FrameOffset; i++; offset = ((UnwindCode[i].FrameOffset << 16) | offset); sb.AppendLine($"{tab2}FrameOffset: 0x{offset:X8})"); } else { sb.AppendLine("Unknown"); } break; case UnwindOpCodes.UWOP_ALLOC_SMALL: int opInfo = UnwindCode[i].OpInfo * 8 + 8; sb.AppendLine($"{tab2}OpInfo: {UnwindCode[i].OpInfo} * 8 + 8 = {opInfo} = 0x{opInfo:X2}"); break; case UnwindOpCodes.UWOP_SET_FPREG: sb.AppendLine($"{tab2}OpInfo: Unused({UnwindCode[i].OpInfo})"); break; case UnwindOpCodes.UWOP_SET_FPREG_LARGE: { sb.AppendLine($"{tab2}OpInfo: Unused({UnwindCode[i].OpInfo})"); i++; uint offset = UnwindCode[i].FrameOffset; i++; offset = ((UnwindCode[i].FrameOffset << 16) | offset); sb.AppendLine($"{tab2}Scaled Offset: {offset} * 16 = {offset * 16} = 0x{(offset * 16):X8}"); if ((UnwindCode[i].FrameOffset & 0xF0000000) != 0) { R2RDump.WriteWarning("Illegal unwindInfo unscaled offset: too large"); } } break; case UnwindOpCodes.UWOP_SAVE_NONVOL: { sb.AppendLine($"{tab2}OpInfo: {(Amd64Registers)UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})"); i++; uint offset = UnwindCode[i].FrameOffset * 8; sb.AppendLine($"{tab2}Scaled Offset: {UnwindCode[i].FrameOffset} * 8 = {offset} = 0x{offset:X5}"); } break; case UnwindOpCodes.UWOP_SAVE_NONVOL_FAR: { sb.AppendLine($"{tab2}OpInfo: {(Amd64Registers)UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})"); i++; uint offset = UnwindCode[i].FrameOffset; i++; offset = ((UnwindCode[i].FrameOffset << 16) | offset); sb.AppendLine($"{tab2}Unscaled Large Offset: 0x{offset:X8}"); } break; case UnwindOpCodes.UWOP_SAVE_XMM128: { sb.AppendLine($"{tab2}OpInfo: XMM{UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})"); i++; uint offset = UnwindCode[i].FrameOffset * 16; sb.AppendLine($"{tab2}Scaled Offset: {UnwindCode[i].FrameOffset} * 16 = {offset} = 0x{offset:X5}"); } break; case UnwindOpCodes.UWOP_SAVE_XMM128_FAR: { sb.AppendLine($"{tab2}OpInfo: XMM{UnwindCode[i].OpInfo}({UnwindCode[i].OpInfo})"); i++; uint offset = UnwindCode[i].FrameOffset; i++; offset = ((UnwindCode[i].FrameOffset << 16) | offset); sb.AppendLine($"{tab2}Unscaled Large Offset: 0x{offset:X8}"); } break; case UnwindOpCodes.UWOP_EPILOG: case UnwindOpCodes.UWOP_SPARE_CODE: case UnwindOpCodes.UWOP_PUSH_MACHFRAME: default: sb.AppendLine($"{tab2}OpInfo: {UnwindCode[i].OpInfo}"); sb.AppendLine(); sb.AppendLine($"{tab2}OffsetLow: {UnwindCode[i].OffsetLow}"); sb.AppendLine($"{tab2}OffsetHigh: {UnwindCode[i].OffsetHigh}"); sb.AppendLine(); sb.AppendLine($"{tab2}FrameOffset: {FrameOffset}"); break; } 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; } }