lazarus/components/fpdebug/fpdbgdisasx86.pp

3884 lines
106 KiB
ObjectPascal
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ $Id$ }
{
---------------------------------------------------------------------------
fpdbgdisasx86.pp - Native Freepascal debugger - x86 Disassembler
---------------------------------------------------------------------------
This unit contains a x86 disassembler for the Native Freepascal debugger
---------------------------------------------------------------------------
@created(Mon Apr 22th WET 2006)
@lastmod($Date$)
@author(Marc Weustink <marc@@dommelstein.nl>)
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
* *
***************************************************************************
}
unit FpDbgDisasX86;
{$mode objfpc}{$H+}
interface
{.$define debug_OperandSize}
{.$define verbose_string_instructions}
uses
SysUtils, FpDbgUtil, FpDbgInfo, DbgIntfBaseTypes, FpdMemoryTools,
FpDbgClasses, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazClasses;
{
The function Disassemble decodes the instruction at the given address.
After decoding, the address increased to the next instruction.
The following chars are used to indicate problems with instruction
sequenses:
** invalid opcode
-- reserved opcode
() ignored opcode
?? unspecified
!! internal error, a group got called for an opcode which wasn't decoded there
The disassembler starts to decode the first byte according to
Intel(r) 64 and IA-32 Architectures Software Developers Manual Volume 2:
Table A-2. One-byte Opcode Map: (00H — F7H)
and
Table A-2. One-byte Opcode Map: (08H — FFH)
The 3DNow!(tm) instructions are decoded according to
AMD64 Architecture Programmers Manual Volume 3:
Table A-13. Immediate Byte for 3DNow!(tm) Opcodes, Low Nibble 07h
and
Table A-14. Immediate Byte for 3DNow!(tm) Opcodes, Low Nibble 8Fh
The routines Addxx use the same abbriviations as used in those tables
}
type
// rexB, rexX, rexR, rexW see
// Intel(r) 64 and IA-32 Architectures Software Developers Manual Volume 2:
// Table 2-4. REX Prefix Fields [BITS: 0100WRXB]
TFlag = (
flagRex, // $4x: set for any $4X
flagSib,
flagModRM,
rexB, // $4x bit 0: Extension of the ModR/M r/m field, SIB base field, or Opcode reg field
rexX, // $4x bit 1: Extension of the SIB index field
rexR, // $4x bit 2: Extension of the ModR/M reg field
rexW, // $4x bit 3: 64 Bit Operand Size
pre66, // $66: Operand-size override prefix (32 and 64 bit) or SIMD prefix
preAdr, // $67: Address-size override prefix
preLock,
preF2, // $F2: Repeat string/input/output or SIMD prefix
preF3, // $F3: Repeat string/input/output or SIMD prefix
oprDefault64, // In 64bit mode set default operand size to 64 (d64 note in Table A-x)
oprForce64, // In 64bit mode set operand size to 64 (f64 note in Table A-x)
flagVex,
vexL,
vexW,
vexX,
vexB
);
TFlags = set of TFlag;
// Keep 8,16,32,64 together
TOperandSize = (os8, os16, os32, os64, os48, os80, os128);
TAddressSize = (as16, as32, as64);
TRegisterType = (reg0, reg8, reg16, reg32, reg64, regMmx, regXmm, regSegment, regControl, regDebug, regX87);
TModRMType = (modReg, modMem);
TModRMTypes = set of TModRMType;
TSimdOpcode = (soInvalid, soNone, so66, soF2, soF3);
TInstructionFlag = (
ifOnly32, ifOnly64,
ifPrefixLock, ifPrefixRep, ifPrefixRepE, ifPrefixRepNe
);
TOpCode = (
OPX_InternalUnknown,
OPX_Invalid,
OPX_InvalidX87, OPX_ReservedX87, OPX_Not87,
OPX_3dnow,
OPX_Group1a, OPX_NotGroup1,
OPX_NotGroup2,
OPX_NotGroup3,
OPX_Group4, OPX_NotGroup4,
OPX_Group5, OPX_NotGroup5,
OPX_Group6, OPX_NotGroup6,
OPX_Group7, OPX_NotGroup7,
OPX_Group8, OPX_NotGroup8,
OPX_Group9, OPX_NotGroup9,
OPX_Group10, OPX_NotGroup10,
OPX_Group11, OPX_NotGroup11,
OPX_Group12, OPX_NotGroup12,
OPX_Group13, OPX_NotGroup13,
OPX_Group14, OPX_NotGroup14,
OPX_Group15, OPX_NotGroup15,
OPX_Group16, OPX_NotGroup16,
OPX_GroupP, OPX_NotGroupP,
OPXsysenter, OPXsysexit,
OPfadd, OPfmul, OPfcom, OPfcomp, OPfsub, OPfsubr, OPfdiv, OPfdivr,
OPfld, OPfxch, OPfst, OPfstp, OPfldenv, OPfldcw, OPfnstenv, OPfnstcw,
OPfchs, OPfabs, OPftst, OPfxam, OPfld1, OPfldl2t, OPfldl2e, OPfldpi, OPfldlg2, OPfldln2, OPfldz,
OPf2xm1, OPfyl2x, OPfptan, OPfpatan, OPfxtract, OPfprem1, OPfdecstp,
OPfincstp, OPfprem, OPfyl2xp1, OPfsqrt, OPfsincos, OPfrndint,
OPfscale, OPfsin, OPfcos, OPnop, OPfiadd, OPfimull,
OPficom, OPficomp, OPfisub, OPfisubr, OPfidiv, OPfidivr,
OPfcmovb, OPfcmove, OPfcmovbe, OPfcmovu, OPfucompp,
OPfild, OPfisttp, OPfist, OPfistp, OPfcmovnb, OPfcmovne, OPfcmovnbe, OPfcmovnu,
OPfucomi, OPfcomi, OPfnclex, OPfninit, OPfrstor, OPfnsave, OPfnstsw,
OPffree, OPfucomp, OPfaddp, OPfmullp, OPfsubrp, OPfsubp, OPfdivrp,
OPfdivp, OPfbld, OPfbstp, OPfcompp, OPfucomip, OPfcomip,
OPpi2fw, OPpi2fd, OPpf2iw, OPpf2id, OPpfnacc, OPpfpnacc, OPpfcmpge,
OPpfmin, OPpfrcp, OPpfrsqrt, OPpfsub, OPpfadd, OPpgcmpgt, OPpfmax,
OPpfrcpit1, OPpfrsqit1, OPpfsubr, OPpfacc, OPpfcmpeq, OPpfmul,
OPpfrcpit2, OPpmulhrw, OPpswapd, OPpavgusb,
OPadd, OPor, OPadc, OPsbb, OPand, OPsub, OPxor, OPcmp, OPpop,
OProl, OPror, OPrcl, OPrcr, OPshl, OPshr, OPsal, OPsar,
OPtest, OPnot, OPneg, OPmul, OPimul, OPdiv, OPidiv,
OPinc, OPdec,
OPcall, OPjmp, OPpush,
OPsldt, OPstr, OPlldt, OPltr, OPverr, OPverw,
OPvmrun, OPvmmcall, OPvmload, OPvmsave, OPstgi, OPclgi, OPskinit, OPinvlpga,
OPsgdt, OPsidt, OPlgdt, OPlidt, OPsmsw, OPlmsw, OPswapgs, OPrdtscp, OPinvlpg,
OPbts, OPbtr, OPbtc, OPbt,
OPcmpxchg16b, OPcmpxchg8b,
OPmov, OPpsrlw, OPpsraw, OPpsllw, OPpsrld, OPpsrad, OPpslld, OPpsrlq, OPpsrldq, OPpsllq,
OPfxsave, OPfxrstor, OPldmxcsr, OPstmxcsr, OPlfence, OPmfence, OPclflush,
OPprefetch_exclusive, OPprefetch_modified, OPX_prefetch,
OPpunpcklbw, OPpunpcklwd, OPpunpcklqd, OPpacksswb, OPpcmpgtb, OPpcmpgtw, OPpcmpgtd,
OPpackuswb, OPpunpkhbw, OPpunpkhwd, OPpunpkhdq, OPpackssdw, OPpunpcklqdq, OPpunpckhqdq,
OPpaddq, OPpmullw, OPpsubusb, OPpsubusw, OPpminub, OPpand, OPpaddusb, OPpaddusw, OPpmaxub, OPpandn,
OPpavgb, OPpavgw, OPpmulhuw, OPpmulhw, OPpsubsb, OPpsubsw, OPpminsw,
OPpor, OPpaddsb, OPpaddsw, OPpmaxsw, OPpxor, OPpmuludq, OPpmaddwd,
OPpsadbw, OPpsubb, OPpsubw, OPpsubd, OPpsubq, OPpaddb, OPpaddw, OPpaddd,
OPlar, OPlsl, OPsyscall, OPclts, OPsysret, OPinvd, OPwbinvd, OPud2,
OPfemms, OPmovups, OPmovss, OPmovupd, OPmovsd, OPmovhlps,
OPmovsldup, OPmovlpd, OPmovddup, OPmovlps, OPunpcklps, OPunpcklpd, OPunpckhps, OPunpckhpd, OPmovlhps,
OPmovshdup, OPmovhpd, OPmovhps, OPmovaps, OPmovapd,
OPcvtpi2ps, OPcvtsi2ss, OPcvtpi2pd, OPcvtsi2sd, OPmovntps, OPmovntpd,
OPcvttps2pi, OPcvttss2si, OPcvttpd2pi, OPcvttsd2si, OPcvtps2pi, OPcvtss2si, OPcvtpd2pi, OPcvtsd2si,
OPucomiss, OPucomissd, OPcomiss, OPcomissd, OPwrmsr, OPrdtsc, OPrdmsr, OPrdpmc,
OPcmov__, OPmovmskps, OPmovmskpd, OPsqrtps, OPsqrtss, OPsqrtpd, OPsqrtsd,
OPaddps, OPaddss, OPaddpd, OPaddsd, OPmulps, OPmulss, OPmulpd, OPmulsd,
OPsubps, OPsubss, OPsubpd, OPsubsd, OPminps, OPminss, OPminpd, OPminsd,
OPdivps, OPdivss, OPdivpd, OPdivsd, OPmaxps, OPmaxss, OPmaxpd, OPmaxsd,
OPrsqrtps, OPrsqrtss, OPrcpps, OPrcpss, OPandps, OPandpd, OPandnps, OPandnpd,
OPorps, OPorpd, OPxorps, OPxorpd,
OPcvtps2pd, OPcvtss2sd, OPcvtpd2ps, OPcvtsd2ss, OPcvtdq2ps, OPcvttps2dq, OPcvtps2dq,
OPmovd, OPmovq, OPmovdqu, OPmovdqa, OPpshufw, OPpshufhw, OPpshufd, OPpshuflw,
OPpcmpeqb, OPpcmpeqw, OPpcmpeqd, OPemms, OPhaddpd, OPhaddps, OPhsubpd, OPhsubps,
OPj__,
OPset__, OPcpuid, OPshld, OPrsm, OPshrd,
OPcmpxchg, OPlss, OPlfs, OPlgs, OPmovzx, OPbsf, OPbsr, OPmovsx, OPxadd,
OPcmpps, OPcmpss, OPcmppd, OPcmpsd, OPmovnti, OPpinsrw, OPpextrw, OPshufps, OPshufpd, OPbswp,
OPaddsubpd, OPaddsubps, OPmovq2dq, OPmovdq2q, OPpmovmskb, OPcvtdq2pd, OPcvttpd2dq, OPcvtpd2dq,
OPmovntq, OPmovntdqu, OPlddqu, OPmaskmovq, OPmaskmovdqu,
OPdaa, OPdas, OPaaa, OPaas, OPpusha, OPpushad, OPpopa, OPpopad, OPbound, OPmovsxd,
OParpl, OPinsb, OPinsw, OPinsd, OPoutsb, OPoutsw, OPoutsd,
OPxchg, OPlea, OPcdqe, OPcwde, OPcbw, OPcqo, OPcqd, OPcwd,
OPwait_fwait,
OPpushfq, OPpushfd, OPpushf, OPpopfq, OPpopfd, OPpopf, OPsahf, OPlahf,
OPmovsb, OPmovsq, OPmovsw, OPcmpsb, OPcmpsq, OPcmpsw,
OPstosb, OPstosq, OPstosd, OPstosw, OPlodsb, OPlodsq, OPlodsd, OPlodsw,
OPscasb, OPscasq, OPscasd, OPscasw, OPret, OPles, OPlds,
OPenter, OPleave, OPretf, OPint3, OPint, OPint0, OPiretq, OPiretd, OPiret,
OPaam, OPaad, OPsalc, OPxlat, OPloopne, OPloope, OPloop, OPjrcxz,
OPin, OPout, OPint1, OPhlt, OPcmc, OPclc, OPstc, OPcli, OPsti, OPcld, OPstd
);
TOpCodeSuffix = (
OPSx_none,
// Condition
OPSx_o, OPSx_no, OPSx_b, OPSx_nb, OPSx_z, OPSx_nz, OPSx_be, OPSx_nbe, OPSx_s, OPSx_ns, OPSx_p, OPSx_np, OPSx_l, OPSx_nl, OPSx_le, OPSx_nle
);
TOperandFlag = (ofMemory);
TOperandFlags = set of TOperandFlag;
TInstruction = record
OpCode: TOpCode;
OpCodeSuffix: TOpCodeSuffix;
Flags: set of TInstructionFlag;
Segment: String;
Operand: array[1..4] of record
CodeIndex: integer;
Value: String;
Size: TOperandSize;
ByteCount: Byte;
ByteCount2: Byte;
FormatFlags: THexValueFormatFlags;
Flags: TOperandFlags;
end;
OperCnt: Integer;
ParseFlags: TFlags;
end;
PInstruction = ^TInstruction;
{ TX86Disassembler }
TX86Disassembler = object
private
ProcessMode: TFPDMode;
Code: PByte;
CodeIdx: Byte;
OperIdx: Integer;
ModRMIdx: Byte;
Flags: TFlags;
SimdOpcode: TSimdOpcode;
//--- result ---
Instruction: PInstruction;
//--- add operands ---
// the the Zz as used in AddZz routines are encoded according to:
//
// Intel(r) 64 and IA-32 Architectures Software Developers Manual Volume 2:
// A.2 KEY TO ABBREVIATIONS
//
// and
//
// AMD64 Architecture Programmers Manual Volume 3:
// Appendix A Opcode and Operand Encodings
//
//---
procedure AddAp;
procedure AddCd_q;
procedure AddDd_q;
procedure AddEb;
procedure AddEd;
procedure AddEd_q;
procedure AddEv;
procedure AddEw;
procedure AddFv;
procedure AddGb;
procedure AddGd;
procedure AddGd_q;
procedure AddGv;
procedure AddGw;
procedure AddGz;
procedure AddIb;
procedure AddIv;
procedure AddIw;
procedure AddIz;
procedure AddJb;
procedure AddJz;
procedure AddM;
procedure AddMa;
procedure AddMb;
procedure AddMd;
procedure AddMdq;
procedure AddMd_q;
procedure AddMp;
procedure AddMq;
procedure AddMs;
procedure AddMw_Rv;
procedure AddOb;
procedure AddOv;
procedure AddPd_q;
procedure AddPq;
procedure AddPRq;
procedure AddQd;
procedure AddQq;
procedure AddRd_q;
procedure AddSw;
procedure AddVdq;
procedure AddVdq_sd;
procedure AddVdq_ss;
procedure AddVd_q;
procedure AddVpd;
procedure AddVps;
procedure AddVq;
procedure AddVRdq;
procedure AddVRpd;
procedure AddVRps;
procedure AddVRq;
procedure AddVsd;
procedure AddVss;
procedure AddWdq;
procedure AddWpd;
procedure AddWps;
procedure AddWq;
procedure AddWsd;
procedure AddWss;
{$ifdef verbose_string_instructions}
procedure AddXb;
procedure AddXv;
procedure AddXz;
procedure AddYb;
procedure AddYv;
procedure AddYz;
{$endif}
//---
procedure AddModReg;
procedure AddModReg(AType: TRegisterType);
procedure AddModReg(AType: TRegisterType; ASize: TOperandSize);
procedure AddModRM(AReqTypes: TModRMTypes; ASize: TOperandSize; AType: TRegisterType);
procedure AddOperand(const AValue: String; ASize: TOperandSize; AByteCount: Byte=0; AFormatFlags: THexValueFormatFlags=[]; AFlags: TOperandFlags=[]; AByteCount2: Byte=0);
procedure AddOperand(const AValue: String; AByteCount: Byte=0; AFormatFlags: THexValueFormatFlags=[]; AFlags: TOperandFlags=[]);
procedure AddStdOperands(AIndex: Byte);
procedure AddStdReg(AIndex: Byte);
procedure AddStdReg(AIndex: Byte; AType: TRegisterType);
procedure Check32;
procedure Check64;
procedure CheckLock;
procedure CheckRepeat;
procedure CheckRepeatX;
procedure CheckSIMD;
procedure Do2ByteOpcode;
procedure Do3DNow;
procedure DoDisassemble;
procedure DoGroup1;
procedure DoGroup2;
procedure DoGroup3;
procedure DoGroup4;
procedure DoGroup5;
procedure DoGroup6;
procedure DoGroup7;
procedure DoGroup8;
procedure DoGroup9;
procedure DoGroup10;
procedure DoGroup11;
procedure DoGroup12;
procedure DoGroup13;
procedure DoGroup14;
procedure DoGroup15;
procedure DoGroup16;
procedure DoGroupP;
procedure DoX87;
function AddressSize32: TAddressSize;
function DecodePrefix(AOpcode, AOpcode66, AOpcodeF2, AOpcodeF3: TOpCode): TSimdOpcode;
procedure Default64;
procedure Force64;
function Ignore64(s: String): String;
function OperandSize: TOperandSize;
function SizeReg32(const AReg: String): String;
function SizeReg32(const AReg: String; ASize: TOperandSize): String;
procedure StdCond(AIndex: Byte);
function StdReg(AIndex: Byte; AType: TRegisterType; AExtReg: Boolean): String;
function StdReg(AIndex: Byte): String;
public
procedure Disassemble(AMode: TFPDMode; var AAddress: Pointer; out AnInstruction: TInstruction);
end;
TX86AsmDecoder = class;
{ TX86AsmInstruction }
TX86AsmInstruction = class(TDbgAsmInstruction)
const
INSTR_CODEBIN_LEN = 16;
private
FProcess: TDbgProcess;
FAddress: TDBGPtr;
FCodeBin: array[0..INSTR_CODEBIN_LEN-1] of byte;
FInstruction: TInstruction;
FInstrLen: Integer;
FFlags: set of (diCodeRead, diCodeReadError, diDisAss);
protected
procedure ReadCode; inline;
procedure Disassemble; inline;
public
constructor Create(AProcess: TDbgProcess);
procedure SetAddress(AnAddress: TDBGPtr);
function IsCallInstruction: boolean; override;
function IsReturnInstruction: boolean; override;
function IsLeaveStackFrame: boolean; override;
//function ModifiesBasePointer: boolean; override;
function ModifiesStackPointer: boolean; override;
function IsJumpInstruction(IncludeConditional: Boolean = True; IncludeUncoditional: Boolean = True): boolean; override;
function InstructionLength: Integer; override;
function X86OpCode: TOpCode;
property X86Instruction: TInstruction read FInstruction; // only valid after call to X86OpCode
end;
{ TX86AsmDecoder }
TX86AsmDecoder = class(TDbgAsmDecoder)
private const
MAX_CODEBIN_LEN = 50;
//FMaxInstructionSize = 16;
//FMinInstructionSize = 1;
private
FProcess: TDbgProcess;
FLastErrWasMem: Boolean;
FCodeBin: array[0..MAX_CODEBIN_LEN-1] of byte;
FLastInstr: TX86AsmInstruction;
protected
function GetLastErrorWasMemReadErr: Boolean; override;
function GetMaxInstrSize: integer; override;
function GetMinInstrSize: integer; override;
function GetCanReverseDisassemble: boolean; override;
function ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal): Boolean; inline;
public
constructor Create(AProcess: TDbgProcess); override;
destructor Destroy; override;
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); override;
function GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; override;
function GetFunctionFrameInfo(AnAddress: TDBGPtr; out
AnIsOutsideFrame: Boolean): Boolean; override;
end;
implementation
var
DBG_WARNINGS: PLazLoggerLogGroup;
const
ADDRESS_BYTES: array[TAddressSize] of Byte = (2, 4, 8);
OPERAND_BYTES: array[TOperandSize] of Byte = (1, 2, 4, 8, 6, 10, 16);
OPERAND_REG: array[os8..os64] of TRegisterType = (reg8, reg16, reg32, reg64);
STD_REGS = [reg8..reg64];
ADDRESS_REG: array[TAddressSize] of TRegisterType = (reg16, reg32, reg64);
// reg8, reg16, reg32, reg64, regMmx, regXmm, regSegment, regControl, regDebug, regX87
REGISTER_SIZE: array[TFPDMode, reg8..High(TRegisterType)] of TOperandSize = (
{ dm32 } (os8, os16, os32, os64, os64, os128, os16, os32, os32, os80),
{ dm64 } (os8, os16, os32, os64, os64, os128, os16, os64, os64, os80)
);
OPCODE_NAME: array [TOpCode] of String = (
'???', // OPX_InternalUnknown
'???',
'**x87**', '-x87-', '!x87!',
'-3dnow-',
'**group1a**', '!group1!',
'!group2!',
'!group3!',
'**group4**', '!group4!',
'**group5**', '!group5!',
'**group6**', '!group6!',
'**group7**', '!group7!',
'**group8**', '!group8!',
'**group9**', '!group9!',
'**group10**', '!group10!',
'**group11**', '!group11!',
'**group12**', '!group12!',
'**group13**', '!group13!',
'**group14**', '!group14!',
'**group15**', '!group15!',
'**group16**', '!group16!',
'**groupp**', '!groupp!',
'**sysenter**', '**sysexit**',
'fadd', 'fmul', 'fcom', 'fcomp', 'fsub', 'fsubr', 'fdiv', 'fdivr',
'fld', 'fxch', 'fst', 'fstp', 'fldenv', 'fldcw', 'fnstenv', 'fnstcw',
'fchs', 'fabs', 'ftst', 'fxam', 'fld1', 'fldl2t', 'fldl2e', 'fldpi', 'fldlg2', 'fldln2', 'fldz',
'f2xm1', 'fyl2x', 'fptan', 'fpatan', 'fxtract', 'fprem1', 'fdecstp',
'fincstp', 'fprem', 'fyl2xp1', 'fsqrt', 'fsincos', 'frndint',
'fscale', 'fsin', 'fcos', 'nop', 'fiadd', 'fimull',
'ficom', 'ficomp', 'fisub', 'fisubr', 'fidiv', 'fidivr',
'fcmovb', 'fcmove', 'fcmovbe', 'fcmovu', 'fucompp',
'fild', 'fisttp', 'fist', 'fistp', 'fcmovnb', 'fcmovne', 'fcmovnbe', 'fcmovnu',
'fucomi', 'fcomi', 'fnclex', 'fninit', 'frstor', 'fnsave', 'fnstsw',
'ffree', 'fucomp', 'faddp', 'fmullp', 'fsubrp', 'fsubp', 'fdivrp',
'fdivp', 'fbld', 'fbstp', 'fcompp', 'fucomip', 'fcomip',
'pi2fw', 'pi2fd', 'pf2iw', 'pf2id', 'pfnacc', 'pfpnacc', 'pfcmpge',
'pfmin', 'pfrcp', 'pfrsqrt', 'pfsub', 'pfadd', 'pgcmpgt', 'pfmax',
'pfrcpit1', 'pfrsqit1', 'pfsubr', 'pfacc', 'pfcmpeq', 'pfmul',
'pfrcpit2', 'pmulhrw', 'pswapd', 'pavgusb',
'add', 'or', 'adc', 'sbb', 'and', 'sub', 'xor', 'cmp','pop',
'rol', 'ror', 'rcl', 'rcr', 'shl', 'shr', 'sal', 'sar',
'test', 'not', 'neg', 'mul', 'imul', 'div', 'idiv',
'inc', 'dec',
'call', 'jmp', 'push',
'sldt', 'str', 'lldt', 'ltr', 'verr', 'verw',
'vmrun', 'vmmcall', 'vmload', 'vmsave', 'stgi', 'clgi', 'skinit', 'invlpga',
'sgdt', 'sidt', 'lgdt', 'lidt', 'smsw', 'lmsw', 'swapgs', 'rdtscp', 'invlpg',
'bts', 'btr', 'btc', 'bt',
'cmpxchg16b', 'cmpxchg8b',
'mov', 'psrlw', 'psraw', 'psllw', 'psrld', 'psrad', 'pslld', 'psrlq', 'psrldq', 'psllq',
'fxsave', 'fxrstor', 'ldmxcsr', 'stmxcsr', 'lfence', 'mfence', 'clflush',
'prefetch exclusive', 'prefetch modified', '--prefetch--',
'punpcklbw', 'punpcklwd', 'punpcklqd', 'packsswb', 'pcmpgtb', 'pcmpgtw', 'pcmpgtd',
'packuswb', 'punpkhbw', 'punpkhwd', 'punpkhdq', 'packssdw', 'punpcklqdq', 'punpckhqdq',
'paddq', 'pmullw', 'psubusb', 'psubusw', 'pminub', 'pand', 'paddusb', 'paddusw', 'pmaxub', 'pandn',
'pavgb', 'pavgw', 'pmulhuw', 'pmulhw', 'psubsb', 'psubsw', 'pminsw',
'por', 'paddsb', 'paddsw', 'pmaxsw', 'pxor', 'pmuludq', 'pmaddwd',
'psadbw', 'psubb', 'psubw', 'psubd', 'psubq', 'paddb', 'paddw', 'paddd',
'lar', 'lsl', 'syscall', 'clts', 'sysret', 'invd', 'wbinvd', 'ud2',
'femms', 'movups', 'movss', 'movupd', 'movsd', 'movhlps',
'movsldup', 'movlpd', 'movddup', 'movlps', 'unpcklps', 'unpcklpd', 'unpckhps', 'unpckhpd', 'movlhps',
'movshdup', 'movhpd', 'movhps', 'movaps', 'movapd',
'cvtpi2ps', 'cvtsi2ss', 'cvtpi2pd', 'cvtsi2sd', 'movntps', 'movntpd',
'cvttps2pi', 'cvttss2si', 'cvttpd2pi', 'cvttsd2si', 'cvtps2pi', 'cvtss2si', 'cvtpd2pi', 'cvtsd2si',
'ucomiss', 'ucomissd', 'comiss', 'comissd', 'wrmsr', 'rdtsc', 'rdmsr', 'rdpmc',
'cmov', 'movmskps', 'movmskpd', 'sqrtps', 'sqrtss', 'sqrtpd', 'sqrtsd',
'addps', 'addss', 'addpd', 'addsd', 'mulps', 'mulss', 'mulpd', 'mulsd',
'subps', 'subss', 'subpd', 'subsd', 'minps', 'minss', 'minpd', 'minsd',
'divps', 'divss', 'divpd', 'divsd', 'maxps', 'maxss', 'maxpd', 'maxsd',
'rsqrtps', 'rsqrtss', 'rcpps', 'rcpss', 'andps', 'andpd', 'andnps', 'andnpd',
'orps', 'orpd', 'xorps', 'xorpd',
'cvtps2pd', 'cvtss2sd', 'cvtpd2ps', 'cvtsd2ss', 'cvtdq2ps', 'cvttps2dq', 'cvtps2dq',
'movd', 'movq', 'movdqu', 'movdqa', 'pshufw', 'pshufhw', 'pshufd', 'pshuflw',
'pcmpeqb', 'pcmpeqw', 'pcmpeqd', 'emms', 'haddpd', 'haddps', 'hsubpd', 'hsubps',
'j', // cond jump + suffix
'set', 'cpuid', 'shld', 'rsm', 'shrd',
'cmpxchg', 'lss', 'lfs', 'lgs', 'movzx', 'bsf', 'bsr', 'movsx', 'xadd',
'cmpps', 'cmpss', 'cmppd', 'cmpsd', 'movnti', 'pinsrw', 'pextrw', 'shufps', 'shufpd', 'bswp',
'addsubpd', 'addsubps', 'movq2dq', 'movdq2q', 'pmovmskb', 'cvtdq2pd', 'cvttpd2dq', 'cvtpd2dq',
'movntq', 'movntdqu', 'lddqu', 'maskmovq', 'maskmovdqu',
'daa', 'das', 'aaa', 'aas', 'pusha', 'pushad', 'popa', 'popad', 'bound', 'movsxd',
'arpl', 'insb', 'insw', 'insd', 'outsb', 'outsw', 'outsd',
'xchg', 'lea', 'cdqe', 'cwde', 'cbw', 'cqo', 'cqd', 'cwd',
'wait/fwait',
'pushfq', 'pushfd', 'pushf', 'popfq', 'popfd', 'popf', 'sahf', 'lahf',
'movsb', 'movsq', 'movsw', 'cmpsb', 'cmpsq', 'cmpsw',
'stosb', 'stosq', 'stosd', 'stosw', 'lodsb', 'lodsq', 'lodsd', 'lodsw',
'scasb', 'scasq', 'scasd', 'scasw', 'ret', 'les', 'lds',
'enter', 'leave', 'retf', 'int3', 'int', 'int0', 'iretq', 'iretd', 'iret',
'aam', 'aad', 'salc', 'xlat', 'loopne', 'loope', 'loop', 'jrcxz',
'in', 'out', 'int1', 'hlt', 'cmc', 'clc', 'stc', 'cli', 'sti', 'cld', 'std'
);
OPCODE_SUFFIX_NAME: array [TOpCodeSuffix] of String = (
'',
'o', 'no', 'b', 'nb', 'z', 'nz', 'be', 'nbe', 's', 'ns', 'p', 'np', 'l', 'nl', 'le', 'nle'
);
{ TX86Disassembler }
procedure TX86Disassembler.Check32;
begin
// only valid in 32-bit ProcessMode
if (ProcessMode = dm64) then
Include(Instruction^.Flags, ifOnly32);
end;
procedure TX86Disassembler.Check64;
begin
// only valid in 64-bit ProcessMode
if (ProcessMode = dm64) then
Include(Instruction^.Flags, ifOnly64);
end;
function TX86Disassembler.Ignore64(s: String): String;
begin
// ignored in 64-bit ProcessMode
if (ProcessMode = dm64) then
Result := '('+s+')'
else
Result := s;
end;
procedure TX86Disassembler.Default64;
begin
if ProcessMode = dm64 then
Include(Flags, oprDefault64);
end;
procedure TX86Disassembler.Force64;
begin
if ProcessMode = dm64 then
Include(Flags, oprForce64);
end;
procedure TX86Disassembler.CheckLock;
function CheckMem: boolean;
var
n: Byte;
begin
Result := True;
for n := 1 to OperIdx do
if ofMemory in Instruction^.Operand[n].Flags then Exit;
Result := False;
end;
begin
if (preLock in Flags) and CheckMem
then begin
Exclude(Flags, preLock);
Include(Instruction^.Flags, ifPrefixLock);
end;
end;
procedure TX86Disassembler.CheckRepeat;
begin
if preF3 in Flags
then begin
Exclude(Flags, preF3);
Include(Instruction^.Flags, ifPrefixRep);
end;
end;
procedure TX86Disassembler.CheckRepeatX;
begin
if preF3 in Flags
then begin
Exclude(Flags, preF3);
Include(Instruction^.Flags, ifPrefixRepE);
Exit;
end;
if preF2 in Flags
then begin
Exclude(Flags, preF2);
Include(Instruction^.Flags, ifPrefixRepNe);
Exit;
end;
end;
procedure TX86Disassembler.CheckSIMD;
var
check: TFlags;
begin
check := Flags * [pre66, preF3, preF2];
if check = []
then SimdOpcode := soNone
else if check - [preF3] = []
then SimdOpcode := soF3
else if check - [preF2] = []
then SimdOpcode := soF2
else if check - [pre66] = []
then SimdOpcode := so66
else SimdOpcode := soInvalid;
end;
function TX86Disassembler.DecodePrefix(AOpcode, AOpcode66, AOpcodeF2, AOpcodeF3: TOpCode): TSimdOpcode;
begin
CheckSIMD;
case SimdOpcode of
soNone: Instruction^.Opcode := AOpcode;
so66: Instruction^.Opcode := AOpcode66;
soF2: Instruction^.Opcode := AOpcodeF2;
soF3: Instruction^.Opcode := AOpcodeF3;
else
Instruction^.Opcode := OPX_Invalid;
end;
if Instruction^.Opcode = OPX_Invalid
then begin
Result := soInvalid;
end
else begin
Flags := Flags - [pre66, preF2, preF3];
Result := SimdOpcode;
end;
end;
function TX86Disassembler.AddressSize32: TAddressSize;
begin
// effective address size for default 32 AnInstruction.operand size
if (ProcessMode = dm64)
then begin
if preAdr in Flags
then Result := as32
else Result := as64;
end
else begin
if preAdr in Flags
then Result := as16
else Result := as32;
end;
end;
function TX86Disassembler.OperandSize: TOperandSize;
begin
// effective AnInstruction.operand size
// Intel(r) 64 and IA-32 Architectures Software Developers Manual Volume 1:
// 3.6 OPERAND-SIZE AND ADDRESS-SIZE ATTRIBUTES
//
// Table 3-3 D-flag = 1 for 32 bit processes ->
// default 32, prefix 16
//
// Table 3-4
// REX.W 64, default 32, prefix 16 (REX.W overrules prefix)
//
// So for both dm32 and dm64 the default size is 32 unless overridden by flags
// A.3 ONE, TWO, AND THREE-BYTE Instruction^.Opcode MAPS
// Some instructions default or force to 64bit in dm64
if [oprForce64, rexW] * Flags <> []
then begin
Result := os64;
end
else begin
if pre66 in Flags
then Result := os16
else if oprDefault64 in Flags
then Result := os64
else Result := os32;
end;
end;
procedure TX86Disassembler.AddOperand(const AValue: String; ASize: TOperandSize; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AFlags: TOperandFlags = []; AByteCount2: Byte = 0);
begin
Inc(OperIdx);
if OperIdx > High(Instruction^.Operand)
then begin
Debugln(DBG_WARNINGS, 'AddOperand: Only %d operands supported, got %d', [High(Instruction^.Operand), OperIdx]);
Exit;
end;
Instruction^.Operand[OperIdx].Size := ASize;
Instruction^.Operand[OperIdx].ByteCount := AByteCount;
Instruction^.Operand[OperIdx].ByteCount2 := AByteCount2;
Instruction^.Operand[OperIdx].FormatFlags := AFormatFlags;
Instruction^.Operand[OperIdx].Value := AValue;
Instruction^.Operand[OperIdx].Flags := AFlags;
end;
procedure TX86Disassembler.AddOperand(const AValue: String; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AFlags: TOperandFlags = []);
begin
AddOperand(AValue, OperandSize, AByteCount, AFormatFlags, AFlags);
end;
function TX86Disassembler.SizeReg32(const AReg: String; ASize: TOperandSize): String;
begin
// prefix a reg for default 32 AnInstruction.operand size
case ASize of
os64: Result := 'r' + AReg;
os32: Result := 'e' + AReg;
else
Result := AReg;
end;
end;
function TX86Disassembler.SizeReg32(const AReg: String): String;
begin
Result := SizeReg32(AReg, OperandSize);
end;
procedure TX86Disassembler.StdCond(AIndex: Byte);
const
COND: array[0..$F] of TOpCodeSuffix = (
OPSx_o, OPSx_no, OPSx_b, OPSx_nb, OPSx_z, OPSx_nz, OPSx_be, OPSx_nbe, OPSx_s, OPSx_ns, OPSx_p, OPSx_np, OPSx_l, OPSx_nl, OPSx_le, OPSx_nle
);
begin
Instruction^.OpCodeSuffix := COND[AIndex and $F];
end;
function TX86Disassembler.StdReg(AIndex: Byte; AType: TRegisterType; AExtReg: Boolean): String;
const
REGS: array[0..7] of string = ('ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di');
REG8_: array[0..7] of String = ('al', 'cl', 'dl', 'bl', 'ah', 'ch', 'dh', 'bh');
REG8r: array[0..7] of String = ('al', 'cl', 'dl', 'bl', 'spl', 'bpl', 'sil', 'dil');
SREG: array[0..7] of String = ('es', 'cs', 'ss', 'ds', 'fs', 'gs', '**', '**');
POSTFIX: array[reg16..reg64] of String = ('w', 'd', '');
OSMAP: array[reg8..reg64] of TOperandSize = (os8, os16, os32, os64);
begin
AIndex := AIndex and $7;
case AType of
reg8: begin
if AExtReg
then begin
Result := Format('r%db', [8 + AIndex]);
end
else begin
if flagRex in Flags
then Result := REG8r[AIndex]
else Result := REG8_[AIndex];
end;
end;
reg16..reg64: begin
if AExtReg
then Result := Format('r%d', [8 + AIndex]) + POSTFIX[AType]
else Result := SizeReg32(REGS[AIndex], OSMAP[AType]);
end;
regX87: begin
Result := Format('st(%d)', [AIndex]);
end;
regMmx: begin
Result := Format('mmx%d', [AIndex]);
end;
regXmm: begin
if AExtReg then Inc(AIndex, 8);
Result := Format('xmm%d', [AIndex]);
end;
regSegment: begin
Result := SREG[AIndex];
end;
regControl: begin
if AExtReg then Inc(AIndex, 8);
Result := Format('cr%d', [AIndex]);
end;
regDebug: begin
if AExtReg then Inc(AIndex, 8);
Result := Format('dr%d', [AIndex]);
end;
end;
end;
function TX86Disassembler.StdReg(AIndex: Byte): String;
begin
Result := StdReg(AIndex, OPERAND_REG[OperandSize], rexB in Flags);
end;
procedure TX86Disassembler.AddStdReg(AIndex: Byte; AType: TRegisterType);
begin
AddOperand(StdReg(AIndex, AType, rexB in Flags), REGISTER_SIZE[ProcessMode, AType]);
end;
procedure TX86Disassembler.AddStdReg(AIndex: Byte);
begin
AddOperand(StdReg(AIndex));
end;
procedure TX86Disassembler.AddModReg(AType: TRegisterType; ASize: TOperandSize);
begin
Include(Flags, flagModRM);
AddOperand(StdReg(Code[ModRMIdx] shr 3, AType, rexR in Flags), ASize);
end;
procedure TX86Disassembler.AddModReg(AType: TRegisterType);
begin
Include(Flags, flagModRM);
AddOperand(StdReg(Code[ModRMIdx] shr 3, AType, rexR in Flags), REGISTER_SIZE[ProcessMode, AType]);
end;
procedure TX86Disassembler.AddModReg;
begin
Include(Flags, flagModRM);
AddOperand(StdReg(Code[ModRMIdx] shr 3, OPERAND_REG[OperandSize], rexR in Flags));
end;
procedure TX86Disassembler.AddModRM(AReqTypes: TModRMTypes; ASize: TOperandSize; AType: TRegisterType);
var
Mode, Rm: Byte;
procedure Mem16;
const
REGS16: array[0..7] of string = ('bx+si', 'bx+di', 'bp+si', 'bp+di', 'si', 'di', 'bp', 'bx');
begin
case Mode of
0: begin
if rm = 6 // disp16 -> exception to the regs
then AddOperand('%s', ASize, 2, [hvfSigned, hvfIncludeHexchar], [ofMemory])
else AddOperand(REGS16[rm], ASize, 0, [], [ofMemory]);
end;
1: AddOperand(REGS16[rm] + '%s', ASize, 1, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], [ofMemory]);
2: AddOperand(REGS16[rm] + '%s', ASize, 2, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], [ofMemory]);
end;
end;
var
AddrSize: TAddressSize;
Sib: record
Scale, Index, Base: Byte;
end;
Oper: record
Size: Byte;
Flags: THexValueFormatFlags;
Value: String;
end;
begin
Include(Flags, flagModRM);
Mode := Code[ModRMIdx] shr 6;
Rm := Code[ModRMIdx] and $7;
// Check for reg (ProcessMode = 3) first;
if Mode = 3
then begin
if modReg in AReqTypes
then AddStdReg(rm, AType)
else AddOperand('**');
Exit;
end;
// Check if mem is allowed
if not (modMem in AReqTypes)
then begin
AddOperand('**', 0, [], [ofMemory]);
Exit;
end;
Oper.Size := 0;
Oper.Flags := [];
Oper.Value := '';
// Here only mem access
AddrSize := AddressSize32;
if AddrSize = as16
then begin
Mem16;
Exit;
end;
if rm = 4
then begin
// sib folows
Include(Flags, flagSib);
sib.Scale := Code[ModRMIdx+1] shr 6;
sib.Index := (Code[ModRMIdx+1] shr 3) and $7;
sib.Base := Code[ModRMIdx+1] and $7;
// base
if (Mode = 0) and (sib.Base = 5)
then begin
// disp32
Oper.Value := '%s';
Oper.Size := 4;
if (sib.Index <> 4) or (rexX in Flags)
then Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar] // [reg + base]
else Oper.Flags := [hvfSigned, hvfIncludeHexchar]; // [base]
end
else begin
Oper.Value := StdReg(sib.Base, ADDRESS_REG[AddrSize], rexB in Flags);
if (sib.Index <> 4) or (rexX in Flags)
then Oper.Value := '+' + Oper.Value; // [reg + base]
end;
// reg
if (rexX in Flags) or (sib.Index <> 4)
then begin
if sib.Scale > 0
then Oper.Value := Format('*%u', [1 shl sib.Scale]) + Oper.Value;
// get index
Oper.Value := StdReg(sib.Index, ADDRESS_REG[AddrSize], rexX in Flags) + Oper.Value
end;
end
else begin
// no sib
Oper.Value := StdReg(rm, ADDRESS_REG[AddrSize], rexB in Flags);
end;
case Mode of
0: begin
// exceptions to std encoding
if rm = 5
then begin
// disp32
if AddrSize = as64
then begin
Oper.Value := 'rip%s';
Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar];
end
else begin
Oper.Value := '%s';
Oper.Flags := [hvfSigned, hvfIncludeHexchar];
end;
Oper.Size := 4;
end;
end;
1: begin
Oper.Value := Oper.Value + '%s';
Oper.Size := 1;
Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar];
end;
2: begin
Oper.Value := Oper.Value + '%s';
Oper.Size := 4;
Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar];
end;
end;
AddOperand(Oper.Value, ASize, Oper.Size, Oper.Flags, [ofMemory]);
end;
procedure TX86Disassembler.AddAp;
begin
if OperandSize = os16 //XXXX:XXXX
then AddOperand('$%1:s:%0:s', os32, 2, [], [], 2)
else AddOperand('$%1:s:%0:s', os48, 4, [], [], 2)
end;
procedure TX86Disassembler.AddCd_q;
begin
AddModReg(regControl);
end;
procedure TX86Disassembler.AddDd_q;
begin
AddModReg(regDebug);
end;
procedure TX86Disassembler.AddEb;
begin
AddModRM([modReg, modMem], os8, reg8);
end;
procedure TX86Disassembler.AddEd;
begin
AddModRM([modReg, modMem], os32, reg32);
end;
procedure TX86Disassembler.AddEd_q;
begin
if flagRex in Flags
then AddModRM([modReg, modMem], os64, reg64)
else AddModRM([modReg, modMem], os32, reg32);
end;
procedure TX86Disassembler.AddEv;
begin
AddModRM([modReg, modMem], OperandSize, OPERAND_REG[OperandSize]);
end;
procedure TX86Disassembler.AddEw;
begin
AddModRM([modReg, modMem], os16, reg16);
end;
procedure TX86Disassembler.AddFv;
begin
case OperandSize of
os64: AddOperand('rflags');
os32: AddOperand('eflags');
else
AddOperand('flags');
end;
end;
procedure TX86Disassembler.AddGb;
begin
AddModReg(reg8);
end;
procedure TX86Disassembler.AddGd;
begin
AddModReg(reg32);
end;
procedure TX86Disassembler.AddGd_q;
begin
if flagRex in Flags
then AddModReg(reg64)
else AddModReg(reg32);
end;
procedure TX86Disassembler.AddGv;
begin
AddModReg;
end;
procedure TX86Disassembler.AddGw;
begin
AddModReg(reg16);
end;
procedure TX86Disassembler.AddGz;
begin
if OperandSize = os16
then AddModReg(reg16)
else AddModReg(reg32);
end;
procedure TX86Disassembler.AddIb;
begin
AddOperand('%s', os8, 1, [hvfIncludeHexchar]);
end;
procedure TX86Disassembler.AddIv;
begin
AddOperand('%s', OPERAND_BYTES[OperandSize], [hvfIncludeHexchar]);
end;
procedure TX86Disassembler.AddIw;
begin
AddOperand('%s', os16, 2, [hvfIncludeHexchar]);
end;
procedure TX86Disassembler.AddIz;
begin
if OperandSize = os16
then AddOperand('%s', os16, 2, [hvfIncludeHexchar])
else AddOperand('%s', os32, 4, [hvfIncludeHexchar]);
end;
procedure TX86Disassembler.AddJb;
begin
AddOperand('%s', os8, 1, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]);
end;
procedure TX86Disassembler.AddJz;
begin
if OperandSize = os16
then AddOperand('%s', os16, 2, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar])
else AddOperand('%s', os32, 4, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]);
end;
procedure TX86Disassembler.AddM;
begin
AddModRM([modMem], OperandSize, reg0 {do not care});
end;
procedure TX86Disassembler.AddMa;
begin
AddModRM([modMem], OperandSize, reg0 {do not care});
end;
procedure TX86Disassembler.AddMb;
begin
AddModRM([modMem], os8, reg0 {do not care});
end;
procedure TX86Disassembler.AddMd;
begin
AddModRM([modMem], os32, reg0 {do not care});
end;
procedure TX86Disassembler.AddMd_q;
begin
if flagRex in Flags
then AddModRM([modMem], os64, reg0 {do not care})
else AddModRM([modMem], os32, reg0 {do not care});
end;
procedure TX86Disassembler.AddMdq;
begin
AddModRM([modMem], os128, reg0 {do not care})
end;
procedure TX86Disassembler.AddMp;
begin
if OperandSize = os16 //XXXX:XXXX
then AddModRM([modMem], os32, reg0 {do not care})
else AddModRM([modMem], os48, reg0 {do not care});
end;
procedure TX86Disassembler.AddMq;
begin
AddModRM([modMem], os64, reg0 {do not care});
end;
procedure TX86Disassembler.AddMs;
begin
if (ProcessMode = dm64)
then AddModRM([modMem], os80, reg0 {do not care})
else AddModRM([modMem], os48, reg0 {do not care});
end;
procedure TX86Disassembler.AddMw_Rv;
begin
if Code[ModRMIdx] shr 6 = 3 // ProcessMode = 3 -> reg
then AddModRM([modReg], OperandSize, OPERAND_REG[OperandSize])
else AddModRM([modMem], os16, reg0 {do not care});
end;
procedure TX86Disassembler.AddOb;
begin
AddOperand('%s', os8, ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], [ofMemory])
end;
procedure TX86Disassembler.AddOv;
begin
AddOperand('%s', ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], [ofMemory])
end;
procedure TX86Disassembler.AddPd_q;
begin
if flagRex in Flags
then AddModReg(regMmx, os64)
else AddModReg(regMmx, os32);
end;
procedure TX86Disassembler.AddPq;
begin
AddModReg(regMmx);
end;
procedure TX86Disassembler.AddPRq;
begin
AddModRM([modReg], os64, regMmx);
end;
procedure TX86Disassembler.AddQd;
begin
AddModRM([modReg, modMem], os32, regMmx);
end;
procedure TX86Disassembler.AddQq;
begin
AddModRM([modReg, modMem], os64, regMmx);
end;
procedure TX86Disassembler.AddRd_q;
begin
if (ProcessMode = dm64)
then AddModRM([modReg], os64, reg64)
else AddModRM([modReg], os32, reg32);
end;
procedure TX86Disassembler.AddSw;
begin
AddModReg(regSegment);
end;
procedure TX86Disassembler.AddVd_q;
begin
if flagRex in Flags
then AddModReg(regXmm, os64)
else AddModReg(regXmm, os32);
end;
procedure TX86Disassembler.AddVdq;
begin
AddModReg(regXmm, os128);
end;
procedure TX86Disassembler.AddVdq_sd;
begin
AddModReg(regXmm, os64); // only lower 64 bit
end;
procedure TX86Disassembler.AddVdq_ss;
begin
AddModReg(regXmm, os32); // only lower 32 bit
end;
procedure TX86Disassembler.AddVpd;
begin
AddModReg(regXmm, os128);
end;
procedure TX86Disassembler.AddVps;
begin
AddModReg(regXmm, os128);
end;
procedure TX86Disassembler.AddVq;
begin
AddModReg(regXmm, os64);
end;
procedure TX86Disassembler.AddVsd;
begin
AddModReg(regXmm, os64);
end;
procedure TX86Disassembler.AddVss;
begin
AddModReg(regXmm, os32);
end;
procedure TX86Disassembler.AddVRdq;
begin
AddModRM([modReg], os128, regXmm);
end;
procedure TX86Disassembler.AddVRpd;
begin
AddModRM([modReg], os128, regXmm);
end;
procedure TX86Disassembler.AddVRps;
begin
AddModRM([modReg], os128, regXmm);
end;
procedure TX86Disassembler.AddVRq;
begin
AddModRM([modReg], os64, regXmm);
end;
procedure TX86Disassembler.AddWdq;
begin
AddModRM([modReg, modMem], os128, regXmm);
end;
procedure TX86Disassembler.AddWpd;
begin
AddModRM([modReg, modMem], os128, regXmm);
end;
procedure TX86Disassembler.AddWps;
begin
AddModRM([modReg, modMem], os128, regXmm);
end;
procedure TX86Disassembler.AddWq;
begin
AddModRM([modReg, modMem], os64, regXmm);
end;
procedure TX86Disassembler.AddWsd;
begin
AddModRM([modReg, modMem], os64, regXmm);
end;
procedure TX86Disassembler.AddWss;
begin
AddModRM([modReg, modMem], os32, regXmm);
end;
{$ifdef verbose_string_instructions}
procedure TX86Disassembler.AddXb;
begin
AddOperand('Xb');
end;
procedure TX86Disassembler.AddXv;
begin
AddOperand('Xv');
end;
procedure TX86Disassembler.AddXz;
begin
AddOperand('Xz');
end;
procedure TX86Disassembler.AddYb;
begin
AddOperand('Yb');
end;
procedure TX86Disassembler.AddYv;
begin
AddOperand('Yv');
end;
procedure TX86Disassembler.AddYz;
begin
AddOperand('Yz');
end;
{$endif}
procedure TX86Disassembler.AddStdOperands(AIndex: Byte);
begin
case AIndex and $7 of
0: begin AddEb; AddGb; end;
1: begin AddEv; AddGv; end;
2: begin AddGb; AddEb; end;
3: begin AddGv; AddEv; end;
4: begin AddOperand('al', os8); AddIb; end;
5: begin AddOperand(SizeReg32('ax')); AddIz; end;
else
AddOperand('!!');
end;
end;
procedure TX86Disassembler.DoX87;
var
Index: Byte;
ModRM: Byte;
procedure AddMem14_28Env;
begin
AddModRM([modMem], OperandSize, reg0 {do not care});
end;
procedure AddMem98_108Env;
begin
AddModRM([modMem], OperandSize, reg0 {do not care});
end;
procedure AddMem16;
begin
AddModRM([modMem], os16, reg0 {do not care});
end;
procedure AddMem32;
begin
AddModRM([modMem], os32, reg0 {do not care});
end;
procedure AddMem64;
begin
AddModRM([modMem], os64, reg0 {do not care});
end;
procedure AddMem80;
begin
AddModRM([modMem], os80, reg0 {do not care});
end;
procedure AddReg0;
begin
AddOperand('st(0)', os80);
end;
procedure AddRegN;
begin
AddOperand(Format('st(%u)', [Code[ModRMIdx] and $7]), os80);
end;
procedure DoD8;
const
OPC: array[0..7] of TOpCode = (OPfadd, OPfmul, OPfcom, OPfcomp, OPfsub, OPfsubr, OPfdiv, OPfdivr);
begin
Instruction^.Opcode := OPC[Index];
case ModRM of
$00..$BF: AddMem32
else
AddReg0; AddRegN;
end;
end;
procedure DoD9;
const
OPC: array[0..7] of TOpCode = (OPfld, OPfxch, OPfst, OPfstp, OPfldenv, OPfldcw, OPfnstenv, OPfnstcw);
OPCx: array[0..$1F] of TOpCode = (
OPfchs, OPfabs, OPX_InvalidX87, OPX_InvalidX87, OPftst, OPfxam, OPX_InvalidX87, OPX_InvalidX87,
OPfld1, OPfldl2t, OPfldl2e, OPfldpi, OPfldlg2, OPfldln2, OPfldz, OPX_InvalidX87,
OPf2xm1, OPfyl2x, OPfptan, OPfpatan, OPfxtract, OPfprem1, OPfdecstp, OPfincstp,
OPfprem, OPfyl2xp1, OPfsqrt, OPfsincos, OPfrndint, OPfscale, OPfsin, OPfcos
);
begin
case ModRM of
$00..$BF: begin
Instruction^.Opcode := OPC[Index];
case Index of
0, 2, 3: AddMem32;
1: Instruction^.Opcode := OPX_InvalidX87;
4, 6 : AddMem14_28Env;
5, 7: AddMem16;
end;
end;
$C0..$CF: begin Instruction^.Opcode := OPC[Index]; AddReg0; AddRegN; end;
$D0: begin Instruction^.Opcode := OPnop; end;
$D8..$DF: begin Instruction^.Opcode := OPX_ReservedX87; end;
$E0..$E1,
$E4..$E5,
$E8..$FF: begin Instruction^.Opcode := OPCx[ModRM and $1F]; end;
else
Instruction^.Opcode := OPX_InvalidX87;
end;
end;
procedure DoDA;
const
OPC: array[0..7] of TOpCode = (OPfiadd, OPfimull, OPficom, OPficomp, OPfisub, OPfisubr, OPfidiv, OPfidivr);
OPCx: array[0..3] of TOpCode = (OPfcmovb, OPfcmove, OPfcmovbe, OPfcmovu);
begin
case ModRM of
$00..$BF: begin Instruction^.Opcode := OPC[Index]; AddMem32; end;
$C0..$DF: begin Instruction^.Opcode := OPCx[Index]; AddReg0; AddRegN; end;
$E9: begin Instruction^.Opcode := OPfucompp; end;
else
Instruction^.Opcode := OPX_InvalidX87;
end;
end;
procedure DoDB;
const
OPC: array[0..7] of TOpCode = (OPfild, OPfisttp, OPfist, OPfistp, OPX_InvalidX87, OPfld, OPX_InvalidX87, OPfstp);
OPCx: array[0..7] of TOpCode = (OPfcmovnb, OPfcmovne, OPfcmovnbe, OPfcmovnu, OPX_InvalidX87, OPfucomi, OPfcomi, OPX_InvalidX87);
begin
case ModRM of
$00..$BF: begin
case Index of
0..3: begin Instruction^.Opcode := OPC[Index]; AddMem32; end;
5, 7: begin Instruction^.Opcode := OPC[Index]; AddMem80; end;
else
Instruction^.Opcode := OPX_InvalidX87;
end;
end;
$C0..$DF,
$E8..$F7: begin Instruction^.Opcode := OPCx[Index]; AddReg0; AddRegN; end;
$E0..$E1: begin Instruction^.Opcode := OPX_ReservedX87; end;
$E2: begin Instruction^.Opcode := OPfnclex; end;
$E3: begin Instruction^.Opcode := OPfninit; end;
$E4: begin Instruction^.Opcode := OPX_ReservedX87; end;
else
Instruction^.Opcode := OPX_InvalidX87;
end;
end;
procedure DoDC;
const
OPC: array[0..7] of TOpCode = (OPfadd, OPfmul, OPfcom, OPfcomp, OPfsub, OPfsubr, OPfdiv, OPfdivr);
OPCx: array[0..7] of TOpCode = (OPfadd, OPfmul, OPX_InvalidX87, OPX_InvalidX87, OPfsubr, OPfsub, OPfdivr, OPfdiv);
begin
case ModRM of
$00..$BF: begin Instruction^.Opcode := OPC[Index]; AddMem64; end;
$C0..$CF,
$E0..$FF: begin Instruction^.Opcode := OPCx[Index]; AddRegN; AddReg0; end;
else
Instruction^.Opcode := OPX_ReservedX87;
end;
end;
procedure DoDD;
const
OPC: array[0..7] of TOpCode = (OPfld, OPfisttp, OPfst, OPfstp, OPfrstor, OPX_InvalidX87, OPfnsave, OPfnstsw);
OPCx: array[0..7] of TOpCode = (OPffree, OPX_InvalidX87, OPfst, OPfstp, OPX_InvalidX87, OPfucomp, OPX_InvalidX87, OPX_InvalidX87);
begin
case ModRM of
$00..$BF: begin
case Index of
0..3: begin Instruction^.Opcode := OPC[Index]; AddMem64; end;
4, 6: begin Instruction^.Opcode := OPC[Index]; AddMem98_108Env; end;
5: Instruction^.Opcode := OPX_InvalidX87;
7: begin Instruction^.Opcode := OPC[Index]; AddMem16; end;
end;
end;
$C0..$C7,
$D0..$DF,
$E8..$EF: begin Instruction^.Opcode := OPCx[Index]; AddRegN; end;
$E0..$E7: begin Instruction^.Opcode := OPCx[Index]; AddRegN; AddReg0; end;
$C8..$CF: Instruction^.Opcode := OPX_ReservedX87;
else
Instruction^.Opcode := OPX_InvalidX87;
end;
end;
procedure DoDE;
const
OPC: array[0..7] of TOpCode = (OPfiadd, OPfimull, OPficom, OPficomp, OPfisub, OPfisubr, OPfidiv, OPfidivr);
OPCx: array[0..7] of TOpCode = (OPfaddp, OPfmullp, OPX_InvalidX87, OPX_InvalidX87, OPfsubrp, OPfsubp, OPfdivrp, OPfdivp);
begin
case ModRM of
$00..$BF: begin Instruction^.Opcode := OPC[Index]; AddMem16; end;
$C0..$CF,
$E0..$FF: begin Instruction^.Opcode := OPCx[Index]; AddRegN; AddReg0; end;
$D9: begin Instruction^.Opcode := OPfcompp; end;
$D0..$D7: Instruction^.Opcode := OPX_ReservedX87;
else
Instruction^.Opcode := OPX_InvalidX87;
end;
end;
procedure DoDF;
const
OPC: array[0..7] of TOpCode = (OPfild, OPfisttp, OPfist, OPfistp, OPfbld, OPfild, OPfbstp, OPfistp);
begin
case ModRM of
$00..$BF: begin
case Index of
0..3: begin Instruction^.Opcode := OPC[Index]; AddMem16; end;
4, 6: begin Instruction^.Opcode := OPC[Index]; AddMem80; end;
5, 7: begin Instruction^.Opcode := OPC[Index]; AddMem64; end;
end;
end;
$E0: begin Instruction^.Opcode := OPfnstsw; AddOperand('ax', os16); end;
$E8..$EF: begin Instruction^.Opcode := OPfucomip; AddReg0; AddRegN; end;
$F0..$F7: begin Instruction^.Opcode := OPfcomip; AddReg0; AddRegN; end;
$C0..$DF: Instruction^.Opcode := OPX_ReservedX87;
else
Instruction^.Opcode := OPX_InvalidX87;
end;
end;
begin
Include(Flags, flagModRM);
ModRM := Code[ModRMIdx];
Index := (ModRM shr 3) and $7;
case Code[CodeIdx] of
$D8: DoD8;
$D9: DoD9;
$DA: DoDA;
$DB: DoDB;
$DC: DoDC;
$DD: DoDD;
$DE: DoDE;
$DF: DoDF;
else
Instruction^.Opcode := OPX_Not87;
end;
end;
procedure TX86Disassembler.Do3DNow;
var
n, idx: Byte;
begin
// 0Fh 0Fh [ModRM] [SIB] [displacement] imm8_opcode
// sigh, we need to get the operands first, luckely they are all te same.
AddPq;
AddQq;
// to adjust the instruction length, add an empty AnInstruction.operand for the Instruction^.Opcode
AddOperand('', 1);
// calc index of imm_opcode
idx := 0;
if flagModRM in Flags then Inc(idx);
if flagSib in Flags then Inc(idx);
for n := 1 to OperIdx do
begin
Inc(idx, Instruction^.Operand[n].ByteCount);
Inc(idx, Instruction^.Operand[n].ByteCount2);
end;
// now we can lookup the Instruction^.Opcode
case Code[CodeIdx + idx] of
$0C: Instruction^.Opcode := OPpi2fw;
$0D: Instruction^.Opcode := OPpi2fd;
$1C: Instruction^.Opcode := OPpf2iw;
$1D: Instruction^.Opcode := OPpf2id;
$8A: Instruction^.Opcode := OPpfnacc;
$8E: Instruction^.Opcode := OPpfpnacc;
$90: Instruction^.Opcode := OPpfcmpge;
$94: Instruction^.Opcode := OPpfmin;
$96: Instruction^.Opcode := OPpfrcp;
$97: Instruction^.Opcode := OPpfrsqrt;
$9A: Instruction^.Opcode := OPpfsub;
$9E: Instruction^.Opcode := OPpfadd;
$A0: Instruction^.Opcode := OPpgcmpgt;
$A4: Instruction^.Opcode := OPpfmax;
$A6: Instruction^.Opcode := OPpfrcpit1;
$A7: Instruction^.Opcode := OPpfrsqit1;
$AA: Instruction^.Opcode := OPpfsubr;
$AE: Instruction^.Opcode := OPpfacc;
$B0: Instruction^.Opcode := OPpfcmpeq;
$B4: Instruction^.Opcode := OPpfmul;
$B6: Instruction^.Opcode := OPpfrcpit2;
$B7: Instruction^.Opcode := OPpmulhrw;
$BB: Instruction^.Opcode := OPpswapd;
$BF: Instruction^.Opcode := OPpavgusb;
else
Instruction^.Opcode := OPX_3dnow;
end;
end;
procedure TX86Disassembler.DoGroup1;
const
OPC: array[0..7] of TOpCode = (OPadd, OPor, OPadc, OPsbb, OPand, OPsub, OPxor, OPcmp);
var
Index: Byte;
begin
Include(Flags, flagModRM);
Index := (Code[ModRMIdx] shr 3) and 7;
// group 1a
if Code[CodeIdx] = $8F
then begin
if Index = 0
then begin
Instruction^.Opcode := OPpop;
AddEv;
end
else Instruction^.Opcode := OPX_group1a;
Exit;
end;
// Group 1
Instruction^.Opcode := OPC[Index];
case Code[CodeIdx] of
$80: begin AddEb; AddIb; end;
$81: begin AddEv; AddIz; end;
$82: begin AddEb; AddIb; Check32; end;
$83: begin AddEv; AddIb; end;
else
Instruction^.Opcode := OPX_NotGroup1;
Exit;
end;
if (Index <> 7)
then CheckLock;
end;
procedure TX86Disassembler.DoGroup2;
const
OPC: array[0..7] of TOpCode = (OProl, OPror, OPrcl, OPrcr, OPshl, OPshr, OPsal, OPsar);
var
Index: Byte;
begin
Include(Flags, flagModRM);
Index := (Code[ModRMIdx] shr 3) and 7;
Instruction^.Opcode := OPC[Index];
case Code[CodeIdx] of
$C0: begin AddEb; AddIb; end;
$C1: begin AddEv; AddIb; end;
$D0: begin AddEb; AddOperand('1', os8); end;
$D1: begin AddEv; AddOperand('1', os8); end;
$D2: begin AddEb; AddOperand('cl', os8); end;
$D3: begin AddEv; AddOperand('cl', os8); end;
else
Instruction^.Opcode := OPX_NotGroup2;
end;
end;
procedure TX86Disassembler.DoGroup3;
const
OPC: array[0..7] of TOpCode = (OPtest, OPtest, OPnot, OPneg, OPmul, OPimul, OPdiv, OPidiv);
var
Index: Byte;
begin
Include(Flags, flagModRM);
Index := (Code[ModRMIdx] shr 3) and 7;
Instruction^.Opcode := OPC[Index];
case Code[CodeIdx] of
$F6: begin
if (Index = 0) or (Index = 1)
then begin
AddEb; AddIb;
end
else begin
AddEb;
end;
end;
$F7: begin
if (Index = 0) or (Index = 1)
then begin
AddEv; AddIz;
end
else begin
AddEv;
end;
end;
else
Instruction^.Opcode := OPX_NotGroup3;
Exit;
end;
if (Index = 2) or (Index = 3)
then CheckLock;
end;
procedure TX86Disassembler.DoGroup4;
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $FE
then begin
Instruction^.Opcode := OPX_NotGroup4;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
case Index of
0: Instruction^.Opcode := OPinc;
1: Instruction^.Opcode := OPdec;
else
Instruction^.Opcode := OPX_Group4;
Exit;
end;
AddEb;
CheckLock;
end;
procedure TX86Disassembler.DoGroup5;
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $FF
then begin
Instruction^.Opcode := OPX_NotGroup5;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
case Index of
0: begin AddEv; Instruction^.Opcode := OPinc; end;
1: begin AddEv; Instruction^.Opcode := OPdec; end;
2: begin Force64; AddEv; Instruction^.Opcode := OPcall; end;
3: begin AddMp; Instruction^.Opcode := OPcall; end;
4: begin Force64; AddEv; Instruction^.Opcode := OPjmp; end;
5: begin AddMp; Instruction^.Opcode := OPjmp; end;
6: begin Default64; AddEv; Instruction^.Opcode := OPpush; end;
else
Instruction^.Opcode := OPX_Group5;
end;
if Index in [0,1] then
CheckLock;
end;
procedure TX86Disassembler.DoGroup6;
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $00
then begin
Instruction^.Opcode := OPX_NotGroup5;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
case Index of
0: begin AddMw_Rv; Instruction^.Opcode := OPsldt; end;
1: begin AddMw_Rv; Instruction^.Opcode := OPstr; end;
2: begin AddEw; Instruction^.Opcode := OPlldt; end;
3: begin AddEw; Instruction^.Opcode := OPltr; end;
4: begin AddEw; Instruction^.Opcode := OPverr; end;
5: begin AddEw; Instruction^.Opcode := OPverw; end;
else
Instruction^.Opcode := OPX_Group6;
end;
end;
procedure TX86Disassembler.DoGroup7;
const
RM3: array [0..7] of TOpCode = (OPvmrun, OPvmmcall, OPvmload, OPvmsave, OPstgi, OPclgi, OPskinit, OPinvlpga);
var
Mode: Byte;
Index: Byte;
RM: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $01
then begin
Instruction^.Opcode := OPX_NotGroup7;
Exit;
end;
Mode := (Code[ModRMIdx] shr 6) and 3;
Index := (Code[ModRMIdx] shr 3) and 7;
RM := (Code[ModRMIdx] ) and 7;
case Index of
0: begin AddMs; Instruction^.Opcode := OPsgdt; end;
1: begin AddMs; Instruction^.Opcode := OPsidt; end;
2: begin AddMs; Instruction^.Opcode := OPlgdt; end;
3: begin
if Mode = 3
then begin
Instruction^.Opcode := RM3[RM];
end
else begin
AddMs; Instruction^.Opcode := OPlidt;
end;
end;
4: begin AddMw_Rv; Instruction^.Opcode := OPsmsw; end;
//5 : invalid
6: begin AddEw; Instruction^.Opcode := OPlmsw; end;
7: begin
if Mode = 3
then begin
case RM of
0: Instruction^.Opcode := OPswapgs;
1: Instruction^.Opcode := OPrdtscp;
else
Instruction^.Opcode := OPX_Group7;
end;
end
else begin
AddMb; Instruction^.Opcode := OPinvlpg;
end;
end;
else
Instruction^.Opcode := OPX_Group7;
end;
end;
procedure TX86Disassembler.DoGroup8;
const
RM8: array [0..7] of TOpCode = (OPX_Group8, OPX_Group8, OPX_Group8, OPX_Group8, OPbt, OPbts, OPbtr, OPbtc);
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $BA
then begin
Instruction^.Opcode := OPX_NotGroup8;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
if Index < 4
then begin
Instruction^.Opcode := OPX_Group8;
Exit;
end;
AddEv; AddIb;
Instruction^.Opcode := RM8[Index];
if Index in [5..7] then
CheckLock;
end;
procedure TX86Disassembler.DoGroup9;
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $C7
then begin
Instruction^.Opcode := OPX_NotGroup9;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
if Index = 1
then begin
if OperandSize = os64
then begin
Instruction^.Opcode := OPcmpxchg16b;
AddMdq;
end
else begin
Instruction^.Opcode := OPcmpxchg8b;
AddMq;
end;
CheckLock;
end
else begin
Instruction^.Opcode := OPX_Group9;
end;
end;
procedure TX86Disassembler.DoGroup10;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $B9
then begin
Instruction^.Opcode := OPX_NotGroup10;
Exit;
end;
// whole goup is invalid ??
Instruction^.Opcode := OPX_Group10;
end;
procedure TX86Disassembler.DoGroup11;
var
Index: Byte;
begin
Include(Flags, flagModRM);
Index := (Code[ModRMIdx] shr 3) and 7;
if Index <> 0
then begin
Instruction^.Opcode := OPX_NotGroup11;
Exit;
end;
case Code[CodeIdx] of
$C6: begin AddEb; AddIb; end;
$C7: begin AddEv; AddIz; end;
else
Instruction^.Opcode := OPX_Group11;
Exit;
end;
Instruction^.Opcode := OPmov;
end;
procedure TX86Disassembler.DoGroup12;
const
OPC: array[0..7] of TOpCode = (OPX_Invalid, OPX_Invalid, OPpsrlw, OPX_Invalid, OPpsraw, OPX_Invalid, OPpsllw, OPX_Invalid);
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $71
then begin
Instruction^.Opcode := OPX_NotGroup12;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
case DecodePrefix(OPC[Index], OPC[Index], OPX_Invalid, OPX_Invalid) of
soNone: begin AddPRq; AddIb; end;
so66: begin AddVRdq; AddIb; end;
else
Instruction^.Opcode := OPX_Group12;
end;
end;
procedure TX86Disassembler.DoGroup13;
const
OPC: array[0..7] of TOpCode = (OPX_Invalid, OPX_Invalid, OPpsrld, OPX_Invalid, OPpsrad, OPX_Invalid, OPpslld, OPX_Invalid);
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $72
then begin
Instruction^.Opcode := OPX_NotGroup13;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
case DecodePrefix(OPC[Index], OPC[Index], OPX_Invalid, OPX_Invalid) of
soNone: begin AddPRq; AddIb; end;
so66: begin AddVRdq; AddIb; end;
else
Instruction^.Opcode := OPX_Group13;
end;
end;
procedure TX86Disassembler.DoGroup14;
const
OPC: array[0..7] of TOpCode = (OPX_Invalid, OPX_Invalid, OPpsrlq, OPpsrldq, OPX_Invalid, OPX_Invalid, OPpsllq, OPpsrldq);
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $73
then begin
Instruction^.Opcode := OPX_NotGroup14;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
case DecodePrefix(OPC[Index], OPC[Index], OPX_Invalid, OPX_Invalid) of
soNone: begin
if (Index = 3) or (Index = 7)
then Instruction^.Opcode := OPX_Group14
else begin AddPRq; AddIb; end;
end;
so66: begin AddVRdq; AddIb; end;
else
Instruction^.Opcode := OPX_Group14;
end;
end;
procedure TX86Disassembler.DoGroup15;
var
Index: Byte;
Mode: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $AE
then begin
Instruction^.Opcode := OPX_NotGroup15;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
if (Flags * [pre66, preF3, preF2] <> [])
or (Index = 4)
then begin
Instruction^.Opcode := OPX_Group15;
Exit;
end;
Mode := (Code[ModRMIdx] shr 6) and 3;
case Index of
0: begin Instruction^.Opcode := OPfxsave; AddM; end;
1: begin Instruction^.Opcode := OPfxrstor; AddM; end;
2: begin Instruction^.Opcode := OPldmxcsr; AddMd; end;
3: begin Instruction^.Opcode := OPstmxcsr; AddMd; end;
5: Instruction^.Opcode := OPlfence;
6: Instruction^.Opcode := OPmfence;
7: if Mode = 3 then Instruction^.Opcode := OPlfence
else begin Instruction^.Opcode := OPclflush; AddMb; end;
end;
end;
procedure TX86Disassembler.DoGroup16;
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $18
then begin
Instruction^.Opcode := OPX_NotGroup16;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
if Index=0 then ;
Instruction^.Opcode := OPX_Invalid;
end;
procedure TX86Disassembler.DoGroupP;
var
Index: Byte;
begin
Include(Flags, flagModRM);
if Code[CodeIdx] <> $0D
then begin
Instruction^.Opcode := OPX_NotGroupP;
Exit;
end;
Index := (Code[ModRMIdx] shr 3) and 7;
case Index of
0: Instruction^.Opcode := OPprefetch_exclusive;
1,3: Instruction^.Opcode := OPprefetch_modified;
else
Instruction^.Opcode := OPX_prefetch;
end;
end;
procedure TX86Disassembler.Do2ByteOpcode;
const
INVALID = '**2byte**';
const
OPR_6x: array[0..$F] of TOpCode = (
OPpunpcklbw, OPpunpcklwd, OPpunpcklqd, OPpacksswb,
OPpcmpgtb, OPpcmpgtw, OPpcmpgtd, OPpackuswb,
OPpunpkhbw, OPpunpkhwd, OPpunpkhdq, OPpackssdw,
OPpunpcklqdq, OPpunpckhqdq, OPX_Invalid, OPX_Invalid
);
OPR_Dx: array[0..$F] of TOpCode = (
OPX_Invalid, OPpsrlw, OPpsrld, OPpsrlq,
OPpaddq, OPpmullw, OPX_Invalid, OPX_Invalid,
OPpsubusb, OPpsubusw, OPpminub, OPpand,
OPpaddusb, OPpaddusw, OPpmaxub, OPpandn
);
OPR_Ex: array[0..$F] of TOpCode = (
OPpavgb, OPpsraw, OPpsrad, OPpavgw,
OPpmulhuw, OPpmulhw, OPX_Invalid, OPX_Invalid,
OPpsubsb, OPpsubsw, OPpminsw, OPpor,
OPpaddsb, OPpaddsw, OPpmaxsw, OPpxor
);
OPR_Fx: array[0..$F] of TOpCode = (
OPX_Invalid, OPpsllw, OPpslld, OPpsllq,
OPpmuludq, OPpmaddwd, OPpsadbw, OPX_Invalid,
OPpsubb, OPpsubw, OPpsubd, OPpsubq,
OPpaddb, OPpaddw, OPpaddd, OPX_Invalid
);
var
idx: Integer;
begin
Inc(CodeIdx);
Inc(ModRMIdx);
case Code[CodeIdx] of
$00: begin
DoGroup6;
end;
$01: begin
DoGroup7;
end;
$02: begin
Instruction^.Opcode := OPlar;
AddGv; AddEw;
end;
$03: begin
Instruction^.Opcode := OPlsl;
AddGv; AddEw;
end;
// $04: invalid
$05: begin
Instruction^.Opcode := OPsyscall;
end;
$06: begin
Instruction^.Opcode := OPclts;
end;
$07: begin
Instruction^.Opcode := OPsysret;
end;
$08: begin
Instruction^.Opcode := OPinvd;
end;
$09: begin
Instruction^.Opcode := OPwbinvd;
end;
// $0A: invalid
$0B: begin
Instruction^.Opcode := OPud2;
end;
// $0C: invalid
$0D: begin
DoGroupP;
end;
$0E: begin
Instruction^.Opcode := OPfemms;
end;
$0F: begin
Do3DNow;
end;
//---
$10: begin
case DecodePrefix(OPmovups, OPmovupd, OPmovsd, OPmovss) of
soNone: begin AddVps; AddWps; end;
so66: begin AddVpd; AddWpd; end;
soF2: begin AddVdq_sd; AddWsd; end;
soF3: begin AddVdq_ss; AddWss; end;
end;
end;
$11: begin
case DecodePrefix(OPmovups, OPmovupd, OPmovsd, OPmovss) of
soNone: begin AddWps; AddVps; end;
so66: begin AddWpd; AddVpd; end;
soF2: begin AddWsd; AddVsd; end;
soF3: begin AddWss; AddVss; end;
end;
end;
$12: begin
case DecodePrefix(OPmovhlps, OPmovlpd, OPmovddup, OPmovsldup) of
soNone: begin
// Instruction^.Opcode differs on type found
// it is specified as Mq or VRq
// So when getting Wq, we Add both and know the type
AddVps; AddWq;
if ofMemory in Instruction^.Operand[2].Flags
then Instruction^.Opcode := OPmovlps;
end;
so66: begin AddVsd; AddMq; end;
soF2: begin AddVpd; AddWsd; end;
soF3: begin AddVps; AddWps; end;
end;
end;
$13: begin
case DecodePrefix(OPmovlps, OPmovlpd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddMq; AddVps; end;
so66: begin AddMq; AddVsd; end;
end;
end;
$14: begin
case DecodePrefix(OPunpcklps, OPunpcklpd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddVps; AddWq; end;
so66: begin AddVpd; AddWq; end;
end;
end;
$15: begin
case DecodePrefix(OPunpckhps, OPunpckhpd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddVps; AddWq; end;
so66: begin AddVpd; AddWq; end;
end;
end;
$16: begin
case DecodePrefix(OPmovlhps, OPmovhpd, OPX_Invalid, OPmovshdup) of
soNone: begin
// Instruction^.Opcode differs on type found
// it is specified as Mq or VRq
// So when getting Wq, we Add both and know the type
AddVps; AddWq;
if ofMemory in Instruction^.Operand[2].Flags
then Instruction^.Opcode := OPmovhps;
end;
so66: begin AddVsd; AddMq; end;
soF3: begin AddVps; AddWps; end;
end;
end;
$17: begin
case DecodePrefix(OPmovhps, OPmovhpd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddMq; AddVps; end;
so66: begin AddMq; AddVsd; end;
end;
end;
$18: begin
DoGroup16;
end;
$19..$1F: begin
Instruction^.Opcode := OPnop;
AddEv;
end;
//---
$20: begin
Instruction^.Opcode := OPmov;
AddRd_q; AddCd_q;
end;
$21: begin
Instruction^.Opcode := OPmov;
AddRd_q; AddDd_q;
end;
$22: begin
Instruction^.Opcode := OPmov;
AddCd_q; AddRd_q;
end;
$23: begin
Instruction^.Opcode := OPmov;
AddDd_q; AddRd_q;
end;
// $24..$27: OPX_Invalid
$28: begin
case DecodePrefix(OPmovaps, OPmovapd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddVps; AddWps; end;
so66: begin AddVpd; AddWpd; end;
end;
end;
$29: begin
case DecodePrefix(OPmovaps, OPmovapd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddWps; AddVps; end;
so66: begin AddWpd; AddVpd; end;
end;
end;
$2A: begin
case DecodePrefix(OPcvtpi2ps, OPcvtpi2pd, OPcvtsi2sd, OPcvtsi2ss) of
soNone: begin AddVps; AddQq; end;
so66: begin AddVpd; AddQq; end;
soF2: begin AddVsd; AddEd_q; end;
soF3: begin AddVss; AddEd_q; end;
end;
end;
$2B: begin
case DecodePrefix(OPmovntps, OPmovntpd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddMdq; AddVps; end;
so66: begin AddMdq; AddVpd; end;
end;
end;
$2C: begin
case DecodePrefix(OPcvttps2pi, OPcvttpd2pi, OPcvttsd2si, OPcvttss2si) of
soNone: begin AddPq; AddWps; end;
so66: begin AddPq; AddWpd; end;
soF2: begin AddGd_q; AddWsd; end;
soF3: begin AddGd_q; AddWss; end;
end;
end;
$2D: begin
case DecodePrefix(OPcvtps2pi, OPcvtpd2pi, OPcvtsd2si, OPcvtss2si) of
soNone: begin AddPq; AddWps; end;
so66: begin AddPq; AddWpd; end;
soF2: begin AddGd_q; AddWsd; end;
soF3: begin AddGd_q; AddWss; end;
end;
end;
$2E: begin
case DecodePrefix(OPucomiss, OPucomissd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddVss; AddWss; end;
so66: begin AddVsd; AddWsd; end;
end;
end;
$2F: begin
case DecodePrefix(OPcomiss, OPcomissd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddVss; AddWss; end;
so66: begin AddVsd; AddWsd; end;
end;
end;
//---
$30: begin
Instruction^.Opcode := OPwrmsr;
end;
$31: begin
Instruction^.Opcode := OPrdtsc;
end;
$32: begin
Instruction^.Opcode := OPrdmsr;
end;
$33: begin
Instruction^.Opcode := OPrdpmc;
end;
$34: begin
Instruction^.Opcode := OPXsysenter;
end;
$35: begin
Instruction^.Opcode := OPXsysexit;
end;
// $36..$3F: OPX_Invalid
//---
$40..$4F: begin
Instruction^.Opcode := OPcmov__; StdCond(Code[CodeIdx]);
AddGv; AddEv;
end;
//---
$50: begin
case DecodePrefix(OPmovmskps, OPmovmskpd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddGd; AddVRps; end;
so66: begin AddGd; AddVRpd; end;
end;
end;
$51..$59, $5C..$5F: begin
case Code[CodeIdx] of
$51: DecodePrefix(OPsqrtps, OPsqrtpd, OPsqrtsd, OPsqrtss);
$52: DecodePrefix(OPrsqrtps, OPX_Invalid, OPX_Invalid, OPrsqrtss);
$53: DecodePrefix(OPrcpps, OPX_Invalid, OPX_Invalid, OPrcpss);
$54: DecodePrefix(OPandps, OPandpd, OPX_Invalid, OPX_Invalid);
$55: DecodePrefix(OPandnps, OPandnpd, OPX_Invalid, OPX_Invalid);
$56: DecodePrefix(OPorps, OPorpd, OPX_Invalid, OPX_Invalid);
$57: DecodePrefix(OPxorps, OPxorpd, OPX_Invalid, OPX_Invalid);
$58: DecodePrefix(OPaddps, OPaddpd, OPaddsd, OPaddss);
$59: DecodePrefix(OPmulps, OPmulpd, OPmulsd, OPmulss);
$5C: DecodePrefix(OPsubps, OPsubpd, OPsubsd, OPsubss);
$5D: DecodePrefix(OPminps, OPminpd, OPminsd, OPminss);
$5E: DecodePrefix(OPdivps, OPdivpd, OPdivsd, OPdivss);
$5F: DecodePrefix(OPmaxps, OPmaxpd, OPmaxsd, OPmaxss);
end;
case SimdOpcode of
soNone: begin AddVps; AddWps; end;
so66: begin AddVpd; AddWpd; end;
soF2: begin AddVsd; AddWsd; end;
soF3: begin AddVss; AddWss; end;
end;
end;
$5A: begin
case DecodePrefix(OPcvtps2pd, OPcvtpd2ps, OPcvtsd2ss, OPcvtss2sd) of
soNone: begin AddVpd; AddWps; end;
so66: begin AddVps; AddWpd; end;
soF2: begin AddVss; AddWsd; end;
soF3: begin AddVsd; AddWss; end;
end;
end;
$5B: begin
case DecodePrefix(OPcvtdq2ps, OPcvtps2dq, OPX_Invalid, OPcvttps2dq) of
soNone: begin AddVps; AddWdq; end;
so66: begin AddVdq; AddWps; end;
soF3: begin AddVdq; AddWps; end;
end;
end;
// $5C..$5F: see $51
//---
$60..$6D: begin
idx := Code[CodeIdx] and $F;
CheckSIMD;
case DecodePrefix(OPR_6x[idx], OPR_6x[idx], OPX_Invalid, OPX_Invalid) of
soNone: begin
if Code[CodeIdx] in [$6C, $6D]
then Instruction^.Opcode := OPX_Invalid
else begin AddPq; AddQd; end;
end;
so66: begin
AddVdq;
if Code[CodeIdx] = $6B then AddWdq else AddWq;
end;
end;
end;
$6E: begin
case DecodePrefix(OPmovd, OPmovd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddPq; AddEd_q; end;
so66: begin AddVdq; AddEd_q; end;
end;
end;
$6F: begin
case DecodePrefix(OPmovq, OPmovdqa, OPX_Invalid, OPmovdqu) of
soNone: begin AddPq; AddQq; end;
so66: begin AddVdq; AddWdq; end;
soF3: begin AddVdq; AddWdq; end;
end;
end;
//---
$70: begin
case DecodePrefix(OPpshufw, OPpshufd, OPpshuflw, OPpshufhw) of
soNone: begin AddPq; AddQq; AddIb; end;
so66: begin AddVdq; AddWdq; AddIb; end;
soF2: begin AddVq; AddWq; AddIb; end;
soF3: begin AddVq; AddWq; AddIb; end;
end;
end;
$71: begin
if Flags * [preF3, preF2] = []
then DoGroup12
else Instruction^.Opcode := OPX_Invalid;
end;
$72: begin
if Flags * [preF3, preF2] = []
then DoGroup13
else Instruction^.Opcode := OPX_Invalid;
end;
$73: begin
if Flags * [preF3, preF2] = []
then DoGroup14
else Instruction^.Opcode := OPX_Invalid;
end;
$74: begin
case DecodePrefix(OPpcmpeqb, OPpcmpeqb, OPX_Invalid, OPX_Invalid) of
soNone: begin AddPq; AddQq; end;
so66: begin AddVdq; AddWdq; end;
end;
end;
$75: begin
case DecodePrefix(OPpcmpeqw, OPpcmpeqw, OPX_Invalid, OPX_Invalid) of
soNone: begin AddPq; AddQq; end;
so66: begin AddVdq; AddWdq; end;
end;
end;
$76: begin
case DecodePrefix(OPpcmpeqd, OPpcmpeqd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddPq; AddQq; end;
so66: begin AddVdq; AddWdq; end;
end;
end;
$77: begin
if Flags * [preF3, preF2, pre66] = []
then Instruction^.Opcode := OPemms
else Instruction^.Opcode := OPX_Invalid;
end;
// $78..$7B: OPX_Invalid
$7C: begin
case DecodePrefix(OPX_Invalid, OPhaddpd, OPhaddps, OPX_Invalid) of
so66: begin AddVpd; AddWpd; end;
soF2: begin AddVps; AddWps; end;
end;
end;
$7D: begin
case DecodePrefix(OPX_Invalid, OPhsubpd, OPhsubps, OPX_Invalid) of
so66: begin AddVpd; AddWpd; end;
soF2: begin AddVps; AddWps; end;
end;
end;
$7E: begin
case DecodePrefix(OPmovd, OPmovd, OPX_Invalid, OPmovq) of
soNone: begin AddEd_q; AddPd_q; end;
so66: begin AddEd_q; AddVd_q; end;
soF3: begin AddVq; AddWq; end;
end;
end;
$7F: begin
case DecodePrefix(OPmovq, OPmovdqa, OPX_Invalid, OPmovdqu) of
soNone: begin AddQq; AddPq; end;
so66: begin AddWdq; AddVdq; end;
soF3: begin AddWdq; AddVdq; end;
end;
end;
//---
$80..$8F: begin
Force64;
Instruction^.Opcode := OPj__; StdCond(Code[CodeIdx]);
AddJz;
end;
//---
$90..$9F: begin
Instruction^.Opcode := OPset__; StdCond(Code[CodeIdx]);
AddEb;
end;
//---
$A0: begin
Default64;
Instruction^.Opcode := OPpush;
AddOperand('fs');
end;
$A1: begin
Default64;
Instruction^.Opcode := OPpop;
AddOperand('fs');
end;
$A2: begin
Instruction^.Opcode := OPcpuid;
end;
$A3: begin
Instruction^.Opcode := OPbt;
AddEv; AddGv;
end;
$A4: begin
Instruction^.Opcode := OPshld;
AddEv; AddGv; AddIb;
end;
$A5: begin
Instruction^.Opcode := OPshld;
AddEv; AddGv;
AddOperand('cl');
end;
// $A6..$A7: OPX_Invalid
$A8: begin
Default64;
Instruction^.Opcode := OPpush;
AddOperand('gs');
end;
$A9: begin
Default64;
Instruction^.Opcode := OPpop;
AddOperand('gs');
end;
$AA: begin
Instruction^.Opcode := OPrsm;
end;
$AB: begin
Instruction^.Opcode := OPbts;
AddEv; AddGv;
end;
$AC: begin
Instruction^.Opcode := OPshrd;
AddEv; AddGv; AddIb;
end;
$AD: begin
Instruction^.Opcode := OPshld;
AddEv; AddGv;
AddOperand('cl');
end;
$AE: begin
DoGroup15;
end;
$AF: begin
Instruction^.Opcode := OPimul;
AddGv; AddEv;
end;
//---
$B0: begin
AddEb; AddGb;
Instruction^.Opcode := OPcmpxchg; CheckLock;
end;
$B1: begin
AddEv; AddGv;
Instruction^.Opcode := OPcmpxchg; CheckLock;
end;
$B2: begin
Instruction^.Opcode := OPlss;
AddGz; AddMp;
end;
$B3: begin
Instruction^.Opcode := OPbtr;
AddEv; AddGv;
end;
$B4: begin
Instruction^.Opcode := OPlfs;
AddGz; AddMp;
end;
$B5: begin
Instruction^.Opcode := OPlgs;
AddGz; AddMp;
end;
$B6: begin
Instruction^.Opcode := OPmovzx;
AddGv; AddEb;
end;
$B7: begin
Instruction^.Opcode := Opmovzx;
AddGv; AddEw;
end;
// $B8: OPX_Invalid
$B9: begin
DoGroup10;
end;
$BA: begin
DoGroup8;
end;
$BB: begin
Instruction^.Opcode := OPbtc;
AddEv; AddGv;
end;
$BC: begin
Instruction^.Opcode := OPbsf;
AddGv; AddEv;
end;
$BD: begin
Instruction^.Opcode := OPbsr;
AddGv; AddEv;
end;
$BE: begin
Instruction^.Opcode := OPmovsx;
AddGv; AddEb;
end;
$BF: begin
Instruction^.Opcode := OPmovsx;
AddGv; AddEw;
end;
//---
$C0: begin
AddEb; AddGb;
Instruction^.Opcode := OPxadd; CheckLock;
end;
$C1: begin
AddEv; AddGv;
Instruction^.Opcode := OPxadd; CheckLock;
end;
$C2: begin
case DecodePrefix(OPcmpps, OPcmppd, OPcmpsd, OPcmpss) of
soNone: begin AddVps; AddWps; AddIb end;
so66: begin AddVpd; AddWpd; AddIb end;
soF2: begin AddVsd; AddWsd; AddIb end;
soF3: begin AddVss; AddWss; AddIb end;
end;
end;
$C3: begin
if Flags * [preF3, preF2, pre66] = []
then begin
Instruction^.Opcode := OPmovnti;
AddMd_q; AddGd_q;
end
else Instruction^.Opcode := OPX_Invalid;
end;
$C4: begin
case DecodePrefix(OPpinsrw, OPpinsrw, OPX_Invalid, OPX_Invalid) of
soNone: begin AddPq; AddEw; AddIb end;
so66: begin AddVdq; AddEw; AddIb end;
end;
end;
$C5: begin
case DecodePrefix(OPpextrw, OPpextrw, OPX_Invalid, OPX_Invalid) of
soNone: begin AddGd; AddPRq; AddIb end;
so66: begin AddGd; AddVRdq; AddIb end;
end;
end;
$C6: begin
case DecodePrefix(OPshufps, OPshufpd, OPX_Invalid, OPX_Invalid) of
soNone: begin AddVps; AddWps; AddIb end;
so66: begin AddVpd; AddWpd; AddIb end;
end;
end;
$C7: begin
DoGroup9;
end;
$C8..$CF: begin
Instruction^.Opcode := OPbswp;
AddStdReg(Code[CodeIdx]);
end;
//---
$D0: begin
case DecodePrefix(OPX_Invalid, OPaddsubpd, OPaddsubps, OPX_Invalid) of
so66: begin AddVpd; AddWpd; end;
soF2: begin AddVps; AddWps; end;
end;
end;
$D1..$D5, $D8..$DF: begin
idx := Code[CodeIdx] and $F;
case DecodePrefix(OPR_Dx[idx], OPR_Dx[idx], OPX_Invalid, OPX_Invalid) of
soNone: begin AddPq; AddQq; end;
so66: begin AddVdq; AddWdq; end;
end;
end;
$D6: begin
case DecodePrefix(OPX_Invalid, OPmovq, OPmovdq2q, OPmovq2dq) of
so66: begin AddWq; AddVq; end;
soF2: begin AddPq; AddVRq; end;
soF3: begin AddVdq; AddPRq; end;
end;
end;
$D7: begin
case DecodePrefix(OPpmovmskb, OPpmovmskb, OPX_Invalid, OPX_Invalid) of
soNone: begin AddGd; AddPRq; end;
so66: begin AddGd; AddVRdq; end;
end;
end;
// $D8..$DF: see $D1
//---
$E0..$E5, $E8..$EF: begin
idx := Code[CodeIdx] and $F;
case DecodePrefix(OPR_Ex[idx], OPR_Ex[idx], OPX_Invalid, OPX_Invalid) of
soNone: begin AddPq; AddQq; end;
so66: begin AddVdq; AddWdq; end;
end;
end;
$E6: begin
case DecodePrefix(OPX_Invalid, OPcvttpd2dq, OPcvtpd2dq, OPcvtdq2pd) of
so66: begin AddVq; AddWpd; end;
soF2: begin AddVq; AddWpd; end;
soF3: begin AddVpd; AddWq; end;
end;
end;
$E7: begin
case DecodePrefix(OPmovntq, OPmovntdqu, OPX_Invalid, OPX_Invalid) of
soNone: begin AddMq; AddPq; end;
so66: begin AddMdq; AddVdq; end;
end;
end;
// $E8..$EF: see $E0
$F0: begin
if preF2 in Flags
then begin
Instruction^.Opcode := OPlddqu;
AddVpd; AddMdq;
end
else Instruction^.Opcode := OPX_Invalid;
end;
$F1..$F6, $F8..$FE: begin
idx := Code[CodeIdx] and $F;
case DecodePrefix(OPR_Fx[idx], OPR_Fx[idx], OPX_Invalid, OPX_Invalid) of
soNone: begin AddPq; AddQq; end;
so66: begin AddVdq; AddWdq; end;
end;
end;
$F7: begin
case DecodePrefix(OPmaskmovq, OPmaskmovdqu, OPX_Invalid, OPX_Invalid) of
soNone: begin AddPq; AddPRq; end;
so66: begin AddVdq; AddVRdq; end;
end;
end;
// $F8..$FE: see $F1
// $FF: OPX_Invalid
else
Instruction^.Opcode := OPX_Invalid;
end;
end;
procedure TX86Disassembler.DoDisassemble;
begin
Instruction^.Opcode := OPX_InternalUnknown;
repeat
ModRMIdx := CodeIdx + 1;
case Code[CodeIdx] of
$00..$05: begin
AddStdOperands(Code[CodeIdx]);
Instruction^.Opcode := OPadd; CheckLock;
end;
$06: begin
Instruction^.Opcode := OPpush; Check32;
AddOperand('es');
end;
$07: begin
Instruction^.Opcode := OPpop; Check32;
AddOperand('es');
end;
$08..$0D: begin
AddStdOperands(Code[CodeIdx]);
Instruction^.Opcode := OPor; CheckLock;
end;
$0E: begin
Instruction^.Opcode := OPpush; Check32;
AddOperand('cs');
end;
$0F: begin
Do2ByteOpcode;
end;
//---
$10..$15: begin
AddStdOperands(Code[CodeIdx]);
Instruction^.Opcode := OPadc; CheckLock;
end;
$16: begin
Instruction^.Opcode := OPpush; Check32;
AddOperand('ss');
end;
$17: begin
Instruction^.Opcode := OPpop; Check32;
AddOperand('ss');
end;
$18..$1D: begin
AddStdOperands(Code[CodeIdx]);
Instruction^.Opcode := OPsbb; CheckLock;
end;
$1E: begin
Instruction^.Opcode := OPpush; Check32;
AddOperand('ds');
end;
$1F: begin
Instruction^.Opcode := OPpop; Check32;
AddOperand('ds');
end;
//---
$20..$25: begin
AddStdOperands(Code[CodeIdx]);
Instruction^.Opcode := OPand; CheckLock;
end;
$26: begin
Instruction^.Segment := Instruction^.Segment + Ignore64('es:');
end;
$27: begin
Instruction^.Opcode := OPdaa; Check32;
end;
$28..$2D: begin
AddStdOperands(Code[CodeIdx]);
Instruction^.Opcode := OPsub; CheckLock;
end;
$2E: begin
Instruction^.Segment := Instruction^.Segment + Ignore64('cs:');
end;
$2F: begin
Instruction^.Opcode := OPdas; Check32;
end;
//---
$30..$35: begin
AddStdOperands(Code[CodeIdx]);
Instruction^.Opcode := OPxor; CheckLock;
end;
$36: begin
Instruction^.Segment := Instruction^.Segment + Ignore64('ss:');
end;
$37: begin
Instruction^.Opcode := OPaaa; Check32;
end;
$38..$3D: begin
Instruction^.Opcode := OPcmp;
AddStdOperands(Code[CodeIdx]);
end;
$3E: begin
Instruction^.Segment := Instruction^.Segment + Ignore64('ds:');
end;
$3F: begin
Instruction^.Opcode := OPaas; Check32;
end;
//---
$40..$4F: begin
if (ProcessMode = dm64)
then begin
if (Code[CodeIdx] and 1) <> 0 then Include(Flags, rexB);
if (Code[CodeIdx] and 2) <> 0 then Include(Flags, rexX);
if (Code[CodeIdx] and 4) <> 0 then Include(Flags, rexR);
if (Code[CodeIdx] and 8) <> 0 then Include(Flags, rexW);
Include(Flags, flagRex);
end
else begin
AddStdReg(Code[CodeIdx]);
if Code[CodeIdx] <= $47
then Instruction^.Opcode := OPinc
else Instruction^.Opcode := OPdec;
CheckLock;
end;
end;
//---
$50..$57: begin
Default64;
Instruction^.Opcode := OPpush;
AddStdReg(Code[CodeIdx]);
end;
$58..$5F: begin
Default64;
Instruction^.Opcode := OPpop;
AddStdReg(Code[CodeIdx]);
end;
//---
$60: begin
if OperandSize = os16
then Instruction^.Opcode := OPpusha
else Instruction^.Opcode := OPpushad;
Check32;
end;
$61: begin
if OperandSize = os16
then Instruction^.Opcode := OPpopa
else Instruction^.Opcode := OPpopad;
Check32;
end;
$62: begin
Instruction^.Opcode := OPbound; Check32;
AddGv; AddMa;
end;
$63: begin
if (ProcessMode = dm64)
then begin
Instruction^.Opcode := (OPmovsxd);
AddGv; AddEd;
end
else begin
Instruction^.Opcode := OParpl; Check32;
AddEw; AddGw;
end;
end;
$64: begin
Instruction^.Segment := Instruction^.Segment + 'fs:';
end;
$65: begin
Instruction^.Segment := Instruction^.Segment + 'gs:';
end;
$66: begin
Include(FLags, pre66);
end;
$67: begin
Include(FLags, preAdr);
end;
$68: begin
Default64;
Instruction^.Opcode := OPpush;
AddIz;
end;
$69: begin
Instruction^.Opcode := OPimul;
AddGv; AddEv; AddIz;
end;
$6A: begin
Default64;
Instruction^.Opcode := OPpush;
AddIb;
end;
$6B: begin
Instruction^.Opcode := OPimul;
AddGv; AddEv; AddIb;
end;
$6C: begin
Instruction^.Opcode := OPinsb; CheckRepeat;
{$ifdef verbose_string_instructions}
AddYb;
AddOperand('dx', os16);
{$endif}
end;
$6D: begin
if OperandSize = os16
then Instruction^.Opcode := OPinsw
else Instruction^.Opcode := OPinsd;
CheckRepeat;
{$ifdef verbose_string_instructions}
AddYz;
AddOperand('dx', os16);
{$endif}
end;
$6E: begin
Instruction^.Opcode := OPoutsb; CheckRepeat;
{$ifdef verbose_string_instructions}
AddOperand('dx', os16);
AddXb;
{$endif}
end;
$6F: begin
if OperandSize = os16
then Instruction^.Opcode := OPoutsw
else Instruction^.Opcode := OPoutsd;
CheckRepeat;
{$ifdef verbose_string_instructions}
AddOperand('dx', os16);
AddXz;
{$endif}
end;
$70..$7F: begin
Force64;
Instruction^.Opcode := OPj__; StdCond(Code[CodeIdx]);
AddJb;
end;
//---
$80..$83: begin
DoGroup1;
end;
$84: begin
Instruction^.Opcode := OPtest;
AddEb; AddGb;
end;
$85: begin
Instruction^.Opcode := OPtest;
AddEv; AddGv;
end;
$86: begin
AddEb; AddGb;
Instruction^.Opcode := OPxchg; CheckLock;
end;
$87: begin
AddEv; AddGv;
Instruction^.Opcode := OPxchg; CheckLock;
end;
$88..$8B: begin
Instruction^.Opcode := OPmov;
AddStdOperands(Code[CodeIdx]);
end;
$8C: begin
Instruction^.Opcode := OPmov;
AddMw_Rv; AddSw;
end;
$8D: begin
Instruction^.Opcode := OPlea;
AddGv; AddM;
end;
$8E: begin
Instruction^.Opcode := OPmov;
AddSw; AddEw;
end;
$8F: begin
Default64;
DoGroup1;
end;
//---
$90..$97: begin
if (Code[CodeIdx] = $90) and not (rexB in Flags)
then Instruction^.Opcode := OPnop
else begin
Instruction^.Opcode := OPxchg;
AddStdReg(Code[CodeIdx]);
AddOperand(SizeReg32('ax'));
end;
end;
$98: begin
case OperandSize of
os64: Instruction^.Opcode := OPcdqe;
os32: Instruction^.Opcode := OPcwde;
else
Instruction^.Opcode := OPcbw;
end;
end;
$99: begin
case OperandSize of
os64: Instruction^.Opcode := OPcqo;
os32: Instruction^.Opcode := OPcqd;
else
Instruction^.Opcode := OPcwd;
end;
end;
$9A: begin
Instruction^.Opcode := OPcall; Check32;
AddAp;
end;
$9B: begin
Instruction^.Opcode := OPwait_fwait;
end;
$9C: begin
Default64;
case OperandSize of
os64: Instruction^.Opcode := OPpushfq;
os32: Instruction^.Opcode := OPpushfd;
else
Instruction^.Opcode := OPpushf;
end;
AddFv;
end;
$9D: begin
Default64;
case OperandSize of
os64: Instruction^.Opcode := OPpopfq;
os32: Instruction^.Opcode := OPpopfd;
else
Instruction^.Opcode := OPpopf;
end;
AddFv;
end;
$9E: begin
Instruction^.Opcode := OPsahf;
end;
$9F: begin
Instruction^.Opcode := OPlahf;
end;
//---
$A0: begin
Instruction^.Opcode := OPmov;
AddOperand('al', os8);
AddOb;
end;
$A1: begin
Instruction^.Opcode := OPmov;
AddOperand(SizeReg32('ax'));
AddOv;
end;
$A2: begin
Instruction^.Opcode := OPmov;
AddOb;
AddOperand('al', os8);
end;
$A3: begin
Instruction^.Opcode := OPmov;
AddOv;
AddOperand(SizeReg32('ax'));
end;
$A4: begin
Instruction^.Opcode := OPmovsb; CheckRepeat;
{$ifdef verbose_string_instructions}
AddYb; AddXb;
{$endif}
end;
$A5: begin
case OperandSize of
os64: Instruction^.Opcode := OPmovsq;
os32: Instruction^.Opcode := OPmovsd;
else
Instruction^.Opcode := OPmovsw;
end;
CheckRepeat;
{$ifdef verbose_string_instructions}
AddYv; AddXv;
{$endif}
end;
$A6: begin
Instruction^.Opcode := OPcmpsb; CheckRepeatX;
{$ifdef verbose_string_instructions}
AddXb; AddYb;
{$endif}
end;
$A7: begin
case OperandSize of
os64: Instruction^.Opcode := OPcmpsq;
os32: Instruction^.Opcode := OPcmpsd;
else
Instruction^.Opcode := OPcmpsw;
end;
CheckRepeatX;
{$ifdef verbose_string_instructions}
AddYv; AddXv;
{$endif}
end;
$A8: begin
Instruction^.Opcode := OPtest;
AddOperand('al', os8);
AddIb;
end;
$A9: begin
Instruction^.Opcode := OPtest;
AddOperand(SizeReg32('ax'));
AddIv;
end;
$AA: begin
Instruction^.Opcode := OPstosb; CheckRepeat;
{$ifdef verbose_string_instructions}
AddYb;
AddOperand('al', os8);
{$endif}
end;
$AB: begin
case OperandSize of
os64: Instruction^.Opcode := OPstosq;
os32: Instruction^.Opcode := OPstosd;
else
Instruction^.Opcode := OPstosw;
end;
CheckRepeat;;
{$ifdef verbose_string_instructions}
AddYv;
AddOperand(SizeReg32('ax'));
{$endif}
end;
$AC: begin
Instruction^.Opcode := OPlodsb; CheckRepeat;
{$ifdef verbose_string_instructions}
AddOperand('al', os8);
AddXb;
{$endif}
end;
$AD: begin
case OperandSize of
os64: Instruction^.Opcode := OPlodsq;
os32: Instruction^.Opcode := OPlodsd;
else
Instruction^.Opcode := OPlodsw;
end;
CheckRepeat;
{$ifdef verbose_string_instructions}
AddOperand(SizeReg32('ax'));
AddXv;
{$endif}
end;
$AE: begin
Instruction^.Opcode := OPscasb; CheckRepeatX;
{$ifdef verbose_string_instructions}
AddOperand('al', os8);
AddYb;
{$endif}
end;
$AF: begin
case OperandSize of
os64: Instruction^.Opcode := OPscasq;
os32: Instruction^.Opcode := OPscasd;
else
Instruction^.Opcode := OPscasw;
end;
CheckRepeatX;
{$ifdef verbose_string_instructions}
AddOperand(SizeReg32('ax'));
AddYv;
{$endif}
end;
//---
$B0..$B7: begin
Instruction^.Opcode := OPmov;
AddStdReg(Code[CodeIdx], reg8);
AddIb;
end;
$B8..$BF: begin
Instruction^.Opcode := OPmov;
AddStdReg(Code[CodeIdx]);
AddIv;
end;
//---
$C0..$C1: begin
DoGroup2;
end;
$C2: begin
Force64;
Instruction^.Opcode := OPret;
AddIw;
end;
$C3: begin
Force64;
Instruction^.Opcode := OPret;
end;
$C4: begin
Instruction^.Opcode := OPles;
AddGz; AddMp;
end;
$C5: begin
Instruction^.Opcode := OPlds;
AddGz; AddMp;
end;
$C6..$C7: begin
DoGroup11;
end;
$C8: begin
Instruction^.Opcode := OPenter;
AddIw; AddIb;
end;
$C9: begin
Default64;
Instruction^.Opcode := OPleave;
end;
$CA: begin
Instruction^.Opcode := OPretf;
AddIw;
end;
$CB: begin
Instruction^.Opcode := OPretf;
end;
$CC: begin
Instruction^.Opcode := OPint3;
end;
$CD: begin
Instruction^.Opcode := OPint;
AddIb;
end;
$CE: begin
Instruction^.Opcode := OPint0; Check32;
end;
$CF: begin
case OperandSize of
os64: Instruction^.Opcode := OPiretq;
os32: Instruction^.Opcode := OPiretd;
else
Instruction^.Opcode := OPiret;
end;
end;
//---
$D0..$D3: begin
DoGroup2;
end;
$D4: begin
Instruction^.Opcode := OPaam; Check32;
end;
$D5: begin
Instruction^.Opcode := OPaad; Check32;
end;
$D6: begin
Instruction^.Opcode := OPsalc; Check32;
end;
$D7: begin
Instruction^.Opcode := OPxlat;
end;
$D8..$DF: begin
DoX87;
end;
//---
$E0: begin
Force64;
Instruction^.Opcode := OPloopne;
AddJb;
end;
$E1: begin
Force64;
Instruction^.Opcode := OPloope;
AddJb;
end;
$E2: begin
Force64;
Instruction^.Opcode := OPloop;
AddJb;
end;
$E3: begin
Force64;
Instruction^.Opcode := OPjrcxz;
AddJb;
end;
$E4: begin
Instruction^.Opcode := OPin;
AddOperand('al', os8);
AddIb;
end;
$E5: begin
Instruction^.Opcode := OPin;
AddOperand(SizeReg32('ax'));
AddIb;
end;
$E6: begin
Instruction^.Opcode := OPout;
AddIb;
AddOperand('al', os8);
end;
$E7: begin
Instruction^.Opcode := OPout;
AddIb;
AddOperand(SizeReg32('ax'));
end;
$E8: begin
Force64;
Instruction^.Opcode := OPcall;
AddJz;
end;
$E9: begin
Force64;
Instruction^.Opcode := OPjmp;
AddJz;
end;
$EA: begin
Instruction^.Opcode := OPjmp; Check32;
AddAp;
end;
$EB: begin
Force64;
Instruction^.Opcode := OPjmp;
AddJb;
end;
$EC: begin
Instruction^.Opcode := OPin;
AddOperand('al', os8);
AddOperand('dx', os16);
end;
$ED: begin
Instruction^.Opcode := OPin;
AddOperand(SizeReg32('ax'));
AddOperand('dx', os16);
end;
$EE: begin
Instruction^.Opcode := OPout;
AddOperand('dx', os16);
AddOperand('al', os8);
end;
$EF: begin
Instruction^.Opcode := OPout;
AddOperand('dx', os16);
AddOperand(SizeReg32('ax'));
end;
$F0: begin
Include(Flags, preLock);
end;
$F1: begin
Instruction^.Opcode := OPint1;
end;
$F2: begin
Include(Flags, preF2);
end;
$F3: begin
Include(Flags, preF3);
end;
$F4: begin
Instruction^.Opcode := OPhlt;
end;
$F5: begin
Instruction^.Opcode := OPcmc;
end;
$F6..$F7: begin
DoGroup3;
end;
$F8: begin
Instruction^.Opcode := OPclc;
end;
$F9: begin
Instruction^.Opcode := OPstc;
end;
$FA: begin
Instruction^.Opcode := OPcli;
end;
$FB: begin
Instruction^.Opcode := OPsti;
end;
$FC: begin
Instruction^.Opcode := OPcld;
end;
$FD: begin
Instruction^.Opcode := OPstd;
end;
$FE: begin
DoGroup4;
end;
$FF: begin
DoGroup5;
end;
else
Instruction^.Opcode := OPX_Invalid; // HexValue(Code[CodeIdx], 1, []);
end;
Inc(CodeIdx);
if CodeIdx > 16 // max instruction length
then begin
Debugln(DBG_WARNINGS, 'Disassemble: instruction longer than 16 bytes');
Exit;
end;
until Instruction^.Opcode <> OPX_InternalUnknown;
end;
procedure TX86Disassembler.Disassemble(AMode: TFPDMode; var AAddress: Pointer; out AnInstruction: TInstruction);
var
n: Integer;
begin
ProcessMode := AMode;
Code := AAddress;
Instruction := @AnInstruction;
Instruction^.Opcode := OPX_Invalid;
Instruction^.OpCodeSuffix := OPSx_none;
Instruction^.Flags := [];
Instruction^.Segment := '';
Flags := [];
CodeIdx := 0;
OperIdx := 0;
SimdOpcode := soInvalid;
DoDisassemble;
Instruction^.OperCnt := OperIdx;
Instruction^.ParseFlags := Flags;
if flagModRM in Flags then Inc(CodeIdx);
if flagSib in Flags then Inc(CodeIdx);
for n := 1 to OperIdx do
begin
AnInstruction.Operand[n].CodeIndex := CodeIdx;
Inc(CodeIdx, AnInstruction.Operand[n].ByteCount);
Inc(CodeIdx, AnInstruction.Operand[n].ByteCount2);
end;
Inc(AAddress, CodeIdx);
end;
{ TX86AsmInstruction }
procedure TX86AsmInstruction.ReadCode;
begin
if not (diCodeRead in FFlags) then begin
if not FProcess.ReadData(FAddress, INSTR_CODEBIN_LEN, FCodeBin) then
Include(FFlags, diCodeReadError);
Include(FFlags, diCodeRead);
end;
end;
procedure TX86AsmInstruction.Disassemble;
var
a: PByte;
Disassembler: TX86Disassembler;
begin
if not (diDisAss in FFlags) then begin
ReadCode;
if diCodeReadError in FFlags then
exit;
a := @FCodeBin[0];
Disassembler.Disassemble(FProcess.Mode, a, FInstruction);
FInstrLen := a - @FCodeBin[0];
Include(FFlags, diDisAss);
end;
end;
constructor TX86AsmInstruction.Create(AProcess: TDbgProcess);
begin
FProcess := AProcess;
inherited Create;
AddReference;
end;
procedure TX86AsmInstruction.SetAddress(AnAddress: TDBGPtr);
begin
FAddress := AnAddress;
FFlags := [];
end;
function TX86AsmInstruction.IsCallInstruction: boolean;
var
a: PByte;
begin
Result := False;
ReadCode;
if diCodeReadError in FFlags then
exit;
a := @FCodeBin[0];
if (FProcess.Mode = dm64) then begin
while (a < @FCodeBin[0] + INSTR_CODEBIN_LEN) and (a^ in [$40..$4F, $64..$67]) do
inc(a);
if not (a^ in [$E8, $FF]) then
exit;
end
else begin
while (a < @FCodeBin[0] + INSTR_CODEBIN_LEN) and (a^ in [$26, $2E, $36, $3E, $64..$67]) do
inc(a);
if not (a^ in [$9A, $E8, $FF]) then
exit;
end;
Disassemble;
Result := FInstruction.OpCode = OPcall;
end;
function TX86AsmInstruction.IsReturnInstruction: boolean;
var
a: PByte;
begin
ReadCode;
if diCodeReadError in FFlags then
exit(False);
a := @FCodeBin[0];
// CF: IRET
Result := (a^ in [$C2, $C3, $CA, $CB, $CF]);
end;
function TX86AsmInstruction.IsLeaveStackFrame: boolean;
var
a: PByte;
begin
ReadCode;
if diCodeReadError in FFlags then
exit(False);
a := @FCodeBin[0];
// C9: leave
Result := (a^ = $C9);
if Result then
exit;
if (FProcess.Mode = dm64) then begin
Result :=
// 48 8D 65 00 / 5D: lea rsp,[rbp+$00] / pop ebp
( (a^ = $48) and (a[1] = $8D) and (a[2] = $65) and (a[3] = $00)
and (a[4] = $5D)
) or
// 48 89 ec / 5D: mov esp,ebp / pop ebp
( (a^ = $48) and (a[1] = $89) and (a[2] = $EC)
and (a[3] = $5D)
);
end
else begin
Result :=
// 8D 65 00 / 5D: lea rsp,[rbp+$00] / pop ebp
( (a[0] = $8D) and (a[1] = $65) and (a[2] = $00)
and (a[3] = $5D)
) or
// 89 ec / 5D: mov esp,ebp / pop ebp
( (a[0] = $89) and (a[1] = $EC)
and (a[2] = $5D)
);
end;
end;
function TX86AsmInstruction.ModifiesStackPointer: boolean;
var
a: PByte;
begin
(* Enter, Leave
mov sp, ...
lea sp, ...
pop / push
BUT NOT ret
*)
Result := False;
ReadCode;
if diCodeReadError in FFlags then
exit;
a := @FCodeBin[0];
if (FProcess.Mode = dm64) then begin
while (a < @FCodeBin[0] + INSTR_CODEBIN_LEN) and (a^ in [$40..$4F, $64..$67]) do
inc(a);
// Pop/Push
if (a^ in [$50..$61, $68, $8F, $9C, $9d])
then
exit(True);
end
else begin
while (a < @FCodeBin[0] + INSTR_CODEBIN_LEN) and (a^ in [$26, $2E, $36, $3E, $64..$67]) do
inc(a);
// Pop/Push
if (a^ in [$06, $07, $0E, $16, $17, $1E, $1F, $50..$61, $68, $6A, $8F, $9C, $9d])
then
exit(True);
end;
// Pop/Push
if (a^ in [$FF])
then begin
Disassemble;
exit(FInstruction.OpCode = OPpush);
end;
if (a^ = $0F) and (a[1] in [$A0, $A1, $A8, $A9]) then
exit(True);
// Enter/Leave
if (a^ in [$C8, $C9])
then
exit(True);
// Mov/Lea
if (a^ in [$89, $8B, $8D]) and
( ((a[1] and $38) = $20) or ((a[1] and $03) = $04) ) // SP is involved
then begin
//Disassemble;
exit(True); // does report some "false positives"
end;
end;
function TX86AsmInstruction.IsJumpInstruction(IncludeConditional: Boolean;
IncludeUncoditional: Boolean): boolean;
var
a: PByte;
begin
(* Excluding
E1, E2 loop
E3 JCXZ Jump short if eCX register is 0
*)
Result := False;
ReadCode;
if diCodeReadError in FFlags then
exit;
a := @FCodeBin[0];
if IncludeConditional and (a^ in [$70..$7F]) then
exit(True);
if IncludeConditional and (a^ = $0F) and (a[1] in [$80..$8F]) then
exit(True);
if IncludeUncoditional and (a^ in [$E9..$EB]) then
exit(True);
if IncludeUncoditional and (a^ in [$FF]) then begin
Disassemble;
exit(FInstruction.OpCode = OPjmp);
end;
end;
function TX86AsmInstruction.InstructionLength: Integer;
begin
Disassemble;
if diCodeReadError in FFlags then
exit(0);
Result := FInstrLen;
end;
function TX86AsmInstruction.X86OpCode: TOpCode;
begin
Disassemble;
if diCodeReadError in FFlags then
exit(OPX_Invalid);
Result := FInstruction.OpCode;
end;
procedure TX86AsmDecoder.Disassemble(var AAddress: Pointer;
out ACodeBytes: String; out ACode: String);
const
MEMPTR: array[TOperandSize] of string = ('byte ptr ', 'word ptr ', 'dword ptr ', 'qword ptr ', '', 'tbyte ptr ', '16byte ptr ');
{$ifdef debug_OperandSize}
OSTEXT: array[TOperandSize] of string = ('os8', 'os16', 'os32', 'os64', 'os48', 'os80', 'os128');
{$endif}
var
Disassembler: TX86Disassembler;
Instr: TInstruction;
S, Soper: String;
n, i: Integer;
HasMem: Boolean;
OpcodeName: String;
Code: PByte;
begin
Code := AAddress;
Disassembler.Disassemble(FProcess.Mode, AAddress, Instr);
Soper := '';
HasMem := False;
for n := 1 to Instr.OperCnt do
begin
if Instr.Operand[n].ByteCount = 0
then S := Instr.Operand[n].Value
else begin
i := Instr.Operand[n].CodeIndex;
if Instr.Operand[n].ByteCount2 = 0
then S := Format(Instr.Operand[n].Value, [HexValue(Code[i], Instr.Operand[n].ByteCount, Instr.Operand[n].FormatFlags)])
else S := Format(Instr.Operand[n].Value, [HexValue(Code[i], Instr.Operand[n].ByteCount, Instr.Operand[n].FormatFlags), HexValue(Code[i + Instr.Operand[n].ByteCount], Instr.Operand[n].ByteCount2, Instr.Operand[n].FormatFlags)])
end;
if Soper <> '' then Soper := Soper + ',';
if ofMemory in Instr.Operand[n].Flags
then begin
if (Instr.OperCnt = 1)
// or (Instr.Operand[n].Size <> os32)
or (Instr.Operand[1].Size <> Instr.Operand[2].Size)
then Soper := Soper + MEMPTR[Instr.Operand[n].Size];
Soper := Soper + Instr.Segment + '[' + S + ']';
HasMem := True;
end
else Soper := Soper + S;
end;
{$ifdef debug_OperandSize}
Soper := Soper + ' | ';
for n := 1 to OperIdx do
begin
Soper := Soper + ' ' + OSTEXT[Instr.Operand[n].Size];
end;
{$endif}
OpcodeName := OPCODE_NAME[Instr.OpCode];
OpcodeName := OpcodeName + OPCODE_SUFFIX_NAME[Instr.OpCodeSuffix];
if Instr.Flags * [ifOnly32, ifOnly64] <> [] then
OpcodeName := '**'+OpcodeName + '**';
if ifPrefixRep in Instr.Flags then
OpcodeName := 'rep '+OpcodeName ;
if ifPrefixRepE in Instr.Flags then
OpcodeName := 'repe '+OpcodeName ;
if ifPrefixRepNe in Instr.Flags then
OpcodeName := 'repne '+OpcodeName ;
if ifPrefixLock in Instr.Flags then
OpcodeName := 'lock '+OpcodeName ;
S := '';
if preLock in Instr.ParseFlags then S := S + '**lock**';
if preF3 in Instr.ParseFlags then S := S + '?rep?';
if preF2 in Instr.ParseFlags then S := S + '?repne?';
S := S + OpcodeName;
if not HasMem and (Instr.Segment <> '') then S := S + ' ?' + Instr.Segment + '?';
ACode := S + ' ' + Soper;
// memory
S := '';
while Code < AAddress do
begin
S := S + HexStr(Code^, 2);
inc(Code);
end;
ACodeBytes := S;
end;
function TX86AsmDecoder.GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction;
begin
if (FLastInstr = nil) or (FLastInstr.RefCount > 1) then begin
ReleaseRefAndNil(FLastInstr);
FLastInstr := TX86AsmInstruction.Create(FProcess);
end;
FLastInstr.SetAddress(AnAddress);
Result := FLastInstr;
end;
{ TX86AsmDecoder }
function TX86AsmDecoder.GetLastErrorWasMemReadErr: Boolean;
begin
Result := FLastErrWasMem;
end;
function TX86AsmDecoder.GetMaxInstrSize: integer;
begin
Result := 16;
end;
function TX86AsmDecoder.GetMinInstrSize: integer;
begin
Result := 1;
end;
function TX86AsmDecoder.GetCanReverseDisassemble: boolean;
begin
{$IFDEF FPDEBUG_WITH_REVERSE_DISASM}
Result := true;
{$ELSE}
Result := False;
{$ENDIF}
end;
function TX86AsmDecoder.ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal
): Boolean;
begin
Result := FProcess.ReadData(AnAddress, ALen, FCodeBin[0], ALen);
FLastErrWasMem := not Result;
end;
constructor TX86AsmDecoder.Create(AProcess: TDbgProcess);
begin
FProcess := AProcess;
end;
destructor TX86AsmDecoder.Destroy;
begin
ReleaseRefAndNil(FLastInstr);
inherited Destroy;
end;
function TX86AsmDecoder.GetFunctionFrameInfo(AnAddress: TDBGPtr; out
AnIsOutsideFrame: Boolean): Boolean;
var
ADataLen: Cardinal;
AData: PByte;
begin
ADataLen := MAX_CODEBIN_LEN;
Result := False;
if not ReadCodeAt(AnAddress, ADataLen) then
exit;
AData := @FCodeBin[0];
while (ADataLen > 0) and (AData^ = $90) do begin // nop
inc(AData);
dec(ADataLen);
end;
Result := ADataLen > 0;
if not Result then
exit;
AnIsOutsideFrame := False;
if AData^ = $55 then begin // push ebp
AnIsOutsideFrame := True;
exit;
end;
if AData^ = $C3 then begin // ret
AnIsOutsideFrame := True;
exit;
end;
if AData^ in [$50..$54, $56..$57] then begin // push
while (ADataLen > 1) and (AData^ in [$50..$57]) do begin
inc(AData);
dec(ADataLen);
end;
if AData^ = $55 then begin // push ebp
AnIsOutsideFrame := True;
exit;
end;
//48 8D A4 24 50FBFFFF lea rsp,[rsp-$000004B0]
//48 8D 64 24 C0 lea rsp,[rsp-$40]
//but NOT 48 8D A4 24 B040000 lea rsp,[rsp+$000004B0]
if (ADataLen >= 4) and (AData[0] = $48) and (AData[1] = $8D) and (AData[3] = $24) and (
( (AData[2] = $64) and ((AData[4] and $80) <> 0) ) or
( (ADataLen >= 8) and (AData[2] = $A4) and ((AData[7] and $80) <> 0) )
)
then begin // mov rbp,rsp // AFTER push ebp
AnIsOutsideFrame := True;
exit;
end;
end;
//if (ADataLen >= 2) and (AData[0] = $89) and (AData[1] = $E5) // 32 bit mov ebp, esp
if (ADataLen >= 3) and (AData[0] = $48) and (AData[1] = $89) and (AData[2] = $E5)
then begin // mov rbp,rsp // AFTER push ebp
// Need 1 byte before, to check for "push ebp"
exit;
end;
end;
initialization
DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
end.