* finished disassembler

git-svn-id: trunk@9238 -
This commit is contained in:
marc 2006-05-04 00:35:45 +00:00
parent d14455fdbc
commit 6aae9024cc
4 changed files with 269 additions and 170 deletions

View File

@ -36,7 +36,7 @@ unit FPWDGlobal;
interface interface
uses uses
SysUtils, Windows, FPWDType, Maps, WinDebugger; SysUtils, Windows, FPWDType, Maps, WinDebugger, WinDExtra;
type type
TMWDState = (dsStop, dsRun, dsPause, dsQuit, dsEvent); TMWDState = (dsStop, dsRun, dsPause, dsQuit, dsEvent);
@ -60,6 +60,7 @@ var
function GetProcess(const AID: Integer; var AProcess: TDbgProcess): Boolean; function GetProcess(const AID: Integer; var AProcess: TDbgProcess): Boolean;
function FormatAddress(const AAddress): String;
implementation implementation
@ -70,6 +71,13 @@ begin
// then Log('Unknown Process ID %u', [AID]); // then Log('Unknown Process ID %u', [AID]);
end; end;
function FormatAddress(const AAddress): String;
const
SIZE: array[TMWDMode] of Integer = (4, 8);
begin
Result := HexValue(AAddress, SIZE[GMode], [hvfIncludeHexchar]);
end;
var var
_UnAligendContext: record _UnAligendContext: record

View File

@ -263,7 +263,7 @@ end;
function TDbgProcess.AddLib(const AInfo: TLoadDLLDebugInfo): TDbgLibrary; function TDbgProcess.AddLib(const AInfo: TLoadDLLDebugInfo): TDbgLibrary;
begin begin
Result := TDbgLibrary.Create(Self, FormatAddress(AInfo.lpBaseOfDll), AInfo); Result := TDbgLibrary.Create(Self, HexValue(AInfo.lpBaseOfDll, SizeOf(Pointer), [hvfIncludeHexchar]), AInfo);
FLibMap.Add(TDbgPtr(AInfo.lpBaseOfDll), Result); FLibMap.Add(TDbgPtr(AInfo.lpBaseOfDll), Result);
end; end;
@ -660,7 +660,7 @@ begin
Context^.ContextFlags := CONTEXT_CONTROL; Context^.ContextFlags := CONTEXT_CONTROL;
if not GetThreadContext(Thread.Handle, Context^) if not GetThreadContext(Thread.Handle, Context^)
then begin then begin
Log('Break $s: Unable to get context', [FormatAddress(FLocation)]); Log('Break $s: Unable to get context', [HexValue(FLocation, SizeOf(Pointer), [hvfIncludeHexchar])]);
Exit; Exit;
end; end;
@ -673,7 +673,7 @@ begin
if not SetThreadContext(Thread.Handle, Context^) if not SetThreadContext(Thread.Handle, Context^)
then begin then begin
Log('Break %s: Unable to set context', [FormatAddress(FLocation)]); Log('Break %s: Unable to set context', [HexValue(FLocation, SizeOf(Pointer), [hvfIncludeHexchar])]);
Exit; Exit;
end; end;
Result := True; Result := True;

View File

@ -43,11 +43,16 @@ uses
type type
TDbgPtr = PtrUInt; TDbgPtr = PtrUInt;
type
THexValueFormatFlag = (hvfSigned, hvfPrefixPositive, hvfIncludeHexchar);
THexValueFormatFlags = set of THexValueFormatFlag;
function GetLastErrorText(AErrorCode: Cardinal): String; {$IFNDEF FPC} overload; {$ENDIF} function GetLastErrorText(AErrorCode: Cardinal): String; {$IFNDEF FPC} overload; {$ENDIF}
function GetLastErrorText: String; {$IFNDEF FPC} overload; {$ENDIF} function GetLastErrorText: String; {$IFNDEF FPC} overload; {$ENDIF}
function FormatAddress(const P): String;
function AlignPtr(Src: Pointer; Alignment: Byte): Pointer; function AlignPtr(Src: Pointer; Alignment: Byte): Pointer;
function HexValue(const AValue; ASize: Byte; AFlags: THexValueFormatFlags): String;
procedure Log(const AText: String; const AParams: array of const); overload; procedure Log(const AText: String; const AParams: array of const); overload;
procedure Log(const AText: String); overload; procedure Log(const AText: String); overload;
@ -59,23 +64,53 @@ procedure Log(const AText: String); overload;
implementation implementation
uses uses
SysUtils, FPWDGLobal; SysUtils;
//function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall; external 'kernel32'; //function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall; external 'kernel32';
//function Wow64GetThreadContext(hThread: THandle; var lpContext: TContext): BOOL; stdcall; external 'kernel32'; //function Wow64GetThreadContext(hThread: THandle; var lpContext: TContext): BOOL; stdcall; external 'kernel32';
function FormatAddress(const P): String; function HexValue(const AValue; ASize: Byte; AFlags: THexValueFormatFlags): String;
var
i: Int64;
p: PByte;
begin begin
case GMode of if ASize > 8
dm32: Result := '$' + IntToHex(DWord(p), 8); then begin
dm64: Result := '$' + IntToHex(int64(p), 16); Result := 'HexValue: size to large';
else Exit;
Result := 'Unknown mode'; end;
if ASize = 0
then begin
Result := '';
Exit;
end; end;
p := @AValue;
if p[ASize - 1] < $80
then Exclude(AFlags, hvfSigned);
if hvfSigned in AFlags
then i := -1
else i := 0;
Move(AValue, i, ASize);
if hvfSigned in AFlags
then begin
i := not i + 1;
Result := '-';
end
else begin
if hvfPrefixPositive in AFlags
then Result := '+';
end;
if hvfIncludeHexchar in AFlags
then Result := Result + '$';
Result := Result + HexStr(i, ASize * 2);
end; end;
function GetLastErrorText: String; function GetLastErrorText: String;
begin begin
Result := GetLastErrorText(GetLastError); Result := GetLastErrorText(GetLastError);

View File

@ -36,6 +36,7 @@ unit WinDisas;
interface interface
{.$define debug_OperandSize} {.$define debug_OperandSize}
{.$define verbose_string_instructions}
uses uses
SysUtils, Windows, WindExtra; SysUtils, Windows, WindExtra;
@ -53,8 +54,9 @@ uses
} }
procedure Disassemble(const AProcess: Handle; const A64Bit: Boolean; var Address: TDbgPtr; out ACodeBytes: String; out ACode: String); procedure Disassemble(var AAddress: Pointer; const A64Bit: Boolean; out ACodeBytes: String; out ACode: String);
function Disassemble(const AProcess: Handle; const A64Bit: Boolean; var Address: TDbgPtr): String; procedure Disassemble(const AProcess: Handle; const A64Bit: Boolean; var AAddress: TDbgPtr; out ACodeBytes: String; out ACode: String);
function Disassemble(const AProcess: Handle; const A64Bit: Boolean; var AAddress: TDbgPtr): String;
implementation implementation
@ -62,76 +64,64 @@ type
TFlag = (flagRex, flagSib, flagModRM, rexB, rexX, rexR, rexW, preOpr, preAdr, preLock, preRep{N}, preRepNE); TFlag = (flagRex, flagSib, flagModRM, rexB, rexX, rexR, rexW, preOpr, preAdr, preLock, preRep{N}, preRepNE);
TFlags = set of TFlag; TFlags = set of TFlag;
TOperandSize = (os8, os16, os32, os64, os80); // Keep 8,16,32,64 together
TOperandSize = (os8, os16, os32, os64, os48, os80, os128);
TAddressSize = (as16, as32, as64); TAddressSize = (as16, as32, as64);
TRegisterType = (reg8, reg16, reg32, reg64, regMmx, regXmm, regSegment, regControl, regDebug); TRegisterType = (reg0, reg8, reg16, reg32, reg64, regMmx, regXmm, regSegment, regControl, regDebug, regX87);
TModRMType = (modReg, modMem);
TModRMTypes = set of TModRMType;
const const
ADDRESS_BYTES: array[TAddressSize] of Byte = (2, 4, 8); ADDRESS_BYTES: array[TAddressSize] of Byte = (2, 4, 8);
OPERAND_BYTES: array[TOperandSize] of Byte = (1, 2, 4, 8, 10); OPERAND_BYTES: array[TOperandSize] of Byte = (1, 2, 4, 8, 6, 10, 16);
OPERAND_REG: array[os8..os64] of TRegisterType = (reg8, reg16, reg32, reg64); OPERAND_REG: array[os8..os64] of TRegisterType = (reg8, reg16, reg32, reg64);
STD_REGS = [reg8..reg64];
type type
THexValueFormatFlag = (hvfSigned, hvfPrefixPositive, hvfIncludeHexchar); TOperandFlag = (ofMemory);
THexValueFormatFlags = set of THexValueFormatFlag; TOperandFlags = set of TOperandFlag;
function HexValue(const AValue; ASize: Byte; AFlags: THexValueFormatFlags): String; function Disassemble(const AProcess: Handle; const A64Bit: Boolean; var AAddress: TDbgPtr): String;
var
i: Int64;
p: PByte;
begin
if ASize > 8
then begin
Result := 'HexValue: size to large';
Exit;
end;
if ASize = 0
then begin
Result := '';
Exit;
end;
p := @AValue;
if p[ASize - 1] < $80
then Exclude(AFlags, hvfSigned);
if hvfSigned in AFlags
then i := -1
else i := 0;
Move(AValue, i, ASize);
if hvfSigned in AFlags
then begin
i := not i + 1;
Result := '-';
end
else begin
if hvfPrefixPositive in AFlags
then Result := '+';
end;
if hvfIncludeHexchar in AFlags
then Result := Result + '$';
Result := Result + HexStr(i, ASize * 2);
end;
function Disassemble(const AProcess: Handle; const A64Bit: Boolean; var Address: TDbgPtr): String;
var var
S: String; S: String;
begin begin
Disassemble(AProcess, A64bit, Address, S, Result); Disassemble(AProcess, A64bit, AAddress, S, Result);
end; end;
procedure Disassemble(const AProcess: Handle; const A64Bit: Boolean; var Address: TDbgPtr; out ACodeBytes: String; out ACode: String); procedure Disassemble(const AProcess: Handle; const A64Bit: Boolean; var AAddress: TDbgPtr; out ACodeBytes: String; out ACode: String);
const
PTRSIZE: array[Boolean] of Byte = (4, 8);
var var
BytesRead: Cardinal;
Code: array[0..20] of Byte; Code: array[0..20] of Byte;
p: Pointer;
begin
BytesRead := 0;
if not ReadProcessMemory(AProcess, Pointer(AAddress), @Code, SizeOf(Code), BytesRead) and (BytesRead = SizeOf(Code))
then begin
Log('Disassemble: Failed to read memory at %s, got %u bytes', [HexValue(AAddress, PTRSIZE[A64Bit], [hvfIncludeHexchar]), BytesRead]);
ACode := '??';
ACodeBytes := '??';
Inc(AAddress);
Exit;
end;
p := @Code;
Disassemble(p, A64Bit, ACodeBytes, ACode);
Inc(AAddress, PtrUInt(p) - PtrUInt(@Code));
end;
procedure Disassemble(var AAddress: Pointer; const A64Bit: Boolean; out ACodeBytes: String; out ACode: String);
var
Code: PByte;
CodeIdx: Byte; CodeIdx: Byte;
Operand: array[1..4] of record Operand: array[1..4] of record
Value: String; Value: String;
Size: TOperandSize; Size: TOperandSize;
ByteCount: Byte; ByteCount: Byte;
ByteCount2: Byte;
FormatFlags: THexValueFormatFlags; FormatFlags: THexValueFormatFlags;
IsMemory: Boolean; Flags: TOperandFlags;
end; end;
OperIdx: Byte; OperIdx: Byte;
ModRMIdx: Byte; ModRMIdx: Byte;
@ -170,14 +160,14 @@ var
begin begin
Result := True; Result := True;
for n := 1 to OperIdx do for n := 1 to OperIdx do
if Operand[n].IsMemory then Exit; if ofMemory in Operand[n].Flags then Exit;
Result := False; Result := False;
end; end;
begin begin
if (preLock in Flags) and CheckMem if (preLock in Flags) and CheckMem
then begin then begin
Exclude(Flags, preLock); Exclude(Flags, preLock);
Result := 'lock: ' + AOpcode; Result := 'lock ' + AOpcode;
Exit; Exit;
end; end;
Result := AOpcode; Result := AOpcode;
@ -188,7 +178,7 @@ var
if preRep in Flags if preRep in Flags
then begin then begin
Exclude(Flags, preRep); Exclude(Flags, preRep);
Result := 'rep: ' + AOpcode; Result := 'rep ' + AOpcode;
Exit; Exit;
end; end;
Result := AOpcode; Result := AOpcode;
@ -199,13 +189,13 @@ var
if preRep in Flags if preRep in Flags
then begin then begin
Exclude(Flags, preRep); Exclude(Flags, preRep);
Result := 'repe: ' + AOpcode; Result := 'repe ' + AOpcode;
Exit; Exit;
end; end;
if preRepNE in Flags if preRepNE in Flags
then begin then begin
Exclude(Flags, preRepNE); Exclude(Flags, preRepNE);
Result := 'repe: ' + AOpcode; Result := 'repne ' + AOpcode;
Exit; Exit;
end; end;
Result := AOpcode; Result := AOpcode;
@ -274,7 +264,7 @@ var
end; end;
end; end;
procedure AddOperand(const AValue: String; ASize: TOperandSize; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AIsMemory: Boolean = False); procedure AddOperand(const AValue: String; ASize: TOperandSize; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AFlags: TOperandFlags = []; AByteCount2: Byte = 0);
begin begin
Inc(OperIdx); Inc(OperIdx);
if OperIdx > High(Operand) if OperIdx > High(Operand)
@ -285,14 +275,15 @@ var
Operand[OperIdx].Size := ASize; Operand[OperIdx].Size := ASize;
Operand[OperIdx].ByteCount := AByteCount; Operand[OperIdx].ByteCount := AByteCount;
Operand[OperIdx].ByteCount2 := AByteCount2;
Operand[OperIdx].FormatFlags := AFormatFlags; Operand[OperIdx].FormatFlags := AFormatFlags;
Operand[OperIdx].Value := AValue; Operand[OperIdx].Value := AValue;
Operand[OperIdx].IsMemory := AIsMemory; Operand[OperIdx].Flags := AFlags;
end; end;
procedure AddOperand(const AValue: String; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AIsMemory: Boolean = False); procedure AddOperand(const AValue: String; AByteCount: Byte = 0; AFormatFlags: THexValueFormatFlags = []; AFlags: TOperandFlags = []);
begin begin
AddOperand(AValue, OperandSize32, AByteCount, AFormatFlags, AIsMemory); AddOperand(AValue, OperandSize32, AByteCount, AFormatFlags, AFlags);
end; end;
function SizeReg32(const AReg: String; ASize: TOperandSize): String; function SizeReg32(const AReg: String; ASize: TOperandSize): String;
@ -345,6 +336,9 @@ var
then Result := Format('r%d', [8 + AIndex]) + POSTFIX[AType] then Result := Format('r%d', [8 + AIndex]) + POSTFIX[AType]
else Result := SizeReg32(REGS[AIndex], OSMAP[AType]); else Result := SizeReg32(REGS[AIndex], OSMAP[AType]);
end; end;
regX87: begin
Result := Format('st(%d)', [AIndex]);
end;
regMmx: begin regMmx: begin
Result := Format('mmx%d', [AIndex]); Result := Format('mmx%d', [AIndex]);
end; end;
@ -370,22 +364,42 @@ var
begin begin
Result := StdReg(AIndex, OPERAND_REG[OperandSize32], rexR in Flags); Result := StdReg(AIndex, OPERAND_REG[OperandSize32], rexR in Flags);
end; end;
procedure AddStdReg(AIndex: Byte; AType: TRegisterType; AExtReg: Boolean);
const
// reg8, reg16, reg32, reg64, regMmx, regXmm, regSegment, regControl, regDebug, regX87
REGSIZE: array[Boolean, reg8..High(TRegisterType)] of TOperandSize = (
{32}(os8, os16, os32, os64, os64, os128, os16, os32, os32, os80),
{64}(os8, os16, os32, os64, os64, os128, os16, os64, os64, os80)
);
begin
AddOperand(StdReg(AIndex, AType, AExtReg), REGSIZE[A64Bit, AType]);
end;
procedure AddStdReg(AIndex: Byte);
begin
AddOperand(StdReg(AIndex, OPERAND_REG[OperandSize32], rexR in Flags));
end;
procedure AddModReg(AType: TRegisterType; ASize: TOperandSize);
begin
Include(Flags, flagModRM);
AddOperand(StdReg(Code[ModRMIdx] shr 3, AType, False), ASize);
end;
procedure AddModReg(AType: TRegisterType; AExtReg: Boolean); procedure AddModReg(AType: TRegisterType; AExtReg: Boolean);
begin begin
Include(Flags, flagModRM); Include(Flags, flagModRM);
AddOperand(StdReg((Code[ModRMIdx] shr 3), AType, AExtReg)); AddStdReg(Code[ModRMIdx] shr 3, AType, AExtReg);
end; end;
procedure AddModReg; procedure AddModReg;
begin begin
Include(Flags, flagModRM); Include(Flags, flagModRM);
AddOperand(StdReg((Code[ModRMIdx] shr 3), OPERAND_REG[OperandSize32], rexR in Flags)); AddStdReg(Code[ModRMIdx] shr 3);
end; end;
procedure AddModRM(AReqTypes: TModRMTypes; ASize: TOperandSize; AType: TRegisterType);
procedure AddModRM(AAllowReg, AAllowMem: Boolean; ASize: TOperandSize);
var var
Mode, Rm: Byte; Mode, Rm: Byte;
procedure Mem16; procedure Mem16;
@ -395,11 +409,11 @@ var
case Mode of case Mode of
0: begin 0: begin
if rm = 6 // disp16 -> exeption to the regs if rm = 6 // disp16 -> exeption to the regs
then AddOperand('%s', ASize, 2, [hvfSigned, hvfIncludeHexchar], True) then AddOperand('%s', ASize, 2, [hvfSigned, hvfIncludeHexchar], [ofMemory])
else AddOperand(REGS16[rm], ASize, 0, [], True); else AddOperand(REGS16[rm], ASize, 0, [], [ofMemory]);
end; end;
1: AddOperand(REGS16[rm] + '%s', ASize, 1, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], True); 1: AddOperand(REGS16[rm] + '%s', ASize, 1, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], [ofMemory]);
2: AddOperand(REGS16[rm] + '%s', ASize, 2, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], True); 2: AddOperand(REGS16[rm] + '%s', ASize, 2, [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar], [ofMemory]);
end; end;
end; end;
@ -421,16 +435,16 @@ var
// Check for reg (mode = 3) first; // Check for reg (mode = 3) first;
if mode = 3 if mode = 3
then begin then begin
if not AAllowReg if modReg in AReqTypes
then AddOperand('**') then AddStdReg(rm, AType, False)
else AddOperand(StdReg(rm, OPERAND_REG[ASize], False), ASize); else AddOperand('**');
Exit; Exit;
end; end;
// Check if mem is allowed // Check if mem is allowed
if not AAllowMem if not (modMem in AReqTypes)
then begin then begin
AddOperand('**', 0, [], True); AddOperand('**', 0, [], [ofMemory]);
Exit; Exit;
end; end;
@ -520,13 +534,15 @@ var
Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar]; Oper.Flags := [hvfSigned, hvfPrefixPositive, hvfIncludeHexchar];
end; end;
end; end;
AddOperand(Oper.Value, ASize, Oper.Size, Oper.Flags, True); AddOperand(Oper.Value, ASize, Oper.Size, Oper.Flags, [ofMemory]);
end; end;
//=================== //===================
procedure AddAp; procedure AddAp;
begin begin
AddOperand('Ap'); if OperandSize32 = os16 //XXXX:XXXX
then AddOperand('$%1:s:%0:s', os32, 2, [], [], 2)
else AddOperand('$%1:s:%0:s', os48, 4, [], [], 2)
end; end;
procedure AddCd_q; procedure AddCd_q;
@ -541,29 +557,29 @@ var
procedure AddEb; procedure AddEb;
begin begin
AddModRM(True, True, os8); AddModRM([modReg, modMem], os8, reg8);
end; end;
procedure AddEd; procedure AddEd;
begin begin
AddModRM(True, True, os32); AddModRM([modReg, modMem], os32, reg32);
end; end;
procedure AddEd_q; procedure AddEd_q;
begin begin
if flagRex in Flags if flagRex in Flags
then AddModRM(True, True, os64) then AddModRM([modReg, modMem], os64, reg64)
else AddModRM(True, True, os32); else AddModRM([modReg, modMem], os32, reg32);
end; end;
procedure AddEv; procedure AddEv;
begin begin
AddModRM(True, True, OperandSize32); AddModRM([modReg, modMem], OperandSize32, OPERAND_REG[OperandSize32]);
end; end;
procedure AddEw; procedure AddEw;
begin begin
AddModRM(True, True, os16); AddModRM([modReg, modMem], os16, reg16);
end; end;
procedure AddFv; procedure AddFv;
@ -646,92 +662,104 @@ var
procedure AddM; procedure AddM;
begin begin
AddModRM(False, True, OperandSize32); AddModRM([modMem], OperandSize32, reg0 {dont care});
end; end;
procedure AddMa; procedure AddMa;
begin begin
AddOperand('Ma'); AddModRM([modMem], OperandSize32, reg0 {dont care});
end; end;
procedure AddMb; procedure AddMb;
begin begin
AddOperand('Ma'); AddModRM([modMem], os8, reg0 {dont care});
end; end;
procedure AddMd; procedure AddMd;
begin begin
AddOperand('Md'); AddModRM([modMem], os32, reg0 {dont care});
end; end;
procedure AddMd_q; procedure AddMd_q;
begin begin
AddOperand('Md/q'); if flagRex in Flags
then AddModRM([modMem], os64, reg0 {dont care})
else AddModRM([modMem], os32, reg0 {dont care});
end; end;
procedure AddMdq; procedure AddMdq;
begin begin
AddOperand('Mdq'); AddModRM([modMem], os128, reg0 {dont care})
end; end;
procedure AddMp; procedure AddMp;
begin begin
AddOperand('Mp'); if OperandSize32 = os16 //XXXX:XXXX
then AddModRM([modMem], os32, reg0 {dont care})
else AddModRM([modMem], os48, reg0 {dont care});
end; end;
procedure AddMq; procedure AddMq;
begin begin
AddOperand('Mq'); AddModRM([modMem], os64, reg0 {dont care});
end; end;
procedure AddMs; procedure AddMs;
begin begin
AddOperand('Ms'); if A64Bit
then AddModRM([modMem], os80, reg0 {dont care})
else AddModRM([modMem], os48, reg0 {dont care});
end; end;
procedure AddMw_Rv; procedure AddMw_Rv;
begin begin
AddOperand('Mw/Rv'); if Code[ModRMIdx] shr 6 = 3 // mode = 3 -> reg
then AddModRM([modReg], OperandSize32, OPERAND_REG[OperandSize32])
else AddModRM([modMem], os16, reg0 {dont care});
end; end;
procedure AddOb; procedure AddOb;
begin begin
AddOperand('%s', os8, ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], True) AddOperand('%s', os8, ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], [ofMemory])
end; end;
procedure AddOv; procedure AddOv;
begin begin
AddOperand('%s', ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], True) AddOperand('%s', ADDRESS_BYTES[AddressSize32], [hvfIncludeHexchar], [ofMemory])
end; end;
procedure AddPd_q; procedure AddPd_q;
begin begin
AddOperand('Pd/q'); if flagRex in Flags
then AddModReg(regMmx, os64)
else AddModReg(regMmx, os32);
end; end;
procedure AddPq; procedure AddPq;
begin begin
AddOperand('Pq'); AddModReg(regMmx, False);
end; end;
procedure AddPRq; procedure AddPRq;
begin begin
AddOperand('PRq'); AddModRM([modReg], os64, regMmx);
end; end;
procedure AddQd; procedure AddQd;
begin begin
AddOperand('Qd'); AddModRM([modReg, modMem], os32, regMmx);
end; end;
procedure AddQq; procedure AddQq;
begin begin
AddOperand('Qq'); AddModRM([modReg, modMem], os64, regMmx);
end; end;
procedure AddRd_q; procedure AddRd_q;
begin begin
AddModRM(True, False, OperandSize32); if A64Bit
then AddModRM([modReg], os64, reg64)
else AddModRM([modReg], os32, reg32);
end; end;
procedure AddSw; procedure AddSw;
@ -741,99 +769,102 @@ var
procedure AddVd_q; procedure AddVd_q;
begin begin
AddOperand('Vd/q'); if flagRex in Flags
then AddModReg(regXmm, os64)
else AddModReg(regXmm, os32);
end; end;
procedure AddVdq; procedure AddVdq;
begin begin
AddOperand('Vdq'); AddModReg(regXmm, os128);
end; end;
procedure AddVdq_sd; procedure AddVdq_sd;
begin begin
AddOperand('Vdq/sd'); AddModReg(regXmm, os64); // only lower 64 bit
end; end;
procedure AddVdq_ss; procedure AddVdq_ss;
begin begin
AddOperand('Vdq/ss'); AddModReg(regXmm, os32); // only lower 32 bit
end; end;
procedure AddVpd; procedure AddVpd;
begin begin
AddOperand('Vsd'); AddModReg(regXmm, os128);
end; end;
procedure AddVps; procedure AddVps;
begin begin
AddOperand('Vps'); AddModReg(regXmm, os128);
end; end;
procedure AddVq; procedure AddVq;
begin begin
AddOperand('Vq'); AddModReg(regXmm, os64);
end; end;
procedure AddVsd; procedure AddVsd;
begin begin
AddOperand('Vsd'); AddModReg(regXmm, os64);
end; end;
procedure AddVss; procedure AddVss;
begin begin
AddOperand('Vss'); AddModReg(regXmm, os32);
end; end;
procedure AddVRdq; procedure AddVRdq;
begin begin
AddOperand('VRdq'); AddModRM([modReg], os128, regXmm);
end; end;
procedure AddVRpd; procedure AddVRpd;
begin begin
AddOperand('VRpd'); AddModRM([modReg], os128, regXmm);
end; end;
procedure AddVRps; procedure AddVRps;
begin begin
AddOperand('VRps'); AddModRM([modReg], os128, regXmm);
end; end;
procedure AddVRq; procedure AddVRq;
begin begin
AddOperand('VRq'); AddModRM([modReg], os64, regXmm);
end; end;
procedure AddWdq; procedure AddWdq;
begin begin
AddOperand('Wdq'); AddModRM([modReg, modMem], os128, regXmm);
end; end;
procedure AddWpd; procedure AddWpd;
begin begin
AddOperand('Wpd'); AddModRM([modReg, modMem], os128, regXmm);
end; end;
procedure AddWps; procedure AddWps;
begin begin
AddOperand('Wps'); AddModRM([modReg, modMem], os128, regXmm);
end; end;
procedure AddWq; procedure AddWq;
begin begin
AddOperand('Wq'); AddModRM([modReg, modMem], os64, regXmm);
end; end;
procedure AddWsd; procedure AddWsd;
begin begin
AddOperand('Wsd'); AddModRM([modReg, modMem], os64, regXmm);
end; end;
procedure AddWss; procedure AddWss;
begin begin
AddOperand('Wss'); AddModRM([modReg, modMem], os32, regXmm);
end; end;
{$ifdef verbose_string_instructions}
procedure AddXb; procedure AddXb;
begin begin
AddOperand('Xb'); AddOperand('Xb');
@ -863,7 +894,7 @@ var
begin begin
AddOperand('Yz'); AddOperand('Yz');
end; end;
{$endif}
//=================== //===================
procedure AddStdOperands(AIndex: Byte); procedure AddStdOperands(AIndex: Byte);
@ -892,32 +923,32 @@ var
procedure AddMem14_28Env; procedure AddMem14_28Env;
begin begin
AddModRM(False, True, OperandSize32); AddModRM([modMem], OperandSize32, reg0 {dont care});
end; end;
procedure AddMem98_108Env; procedure AddMem98_108Env;
begin begin
AddModRM(False, True, OperandSize32); AddModRM([modMem], OperandSize32, reg0 {dont care});
end; end;
procedure AddMem16; procedure AddMem16;
begin begin
AddModRM(False, True, os16); AddModRM([modMem], os16, reg0 {dont care});
end; end;
procedure AddMem32; procedure AddMem32;
begin begin
AddModRM(False, True, os32); AddModRM([modMem], os32, reg0 {dont care});
end; end;
procedure AddMem64; procedure AddMem64;
begin begin
AddModRM(False, True, os64); AddModRM([modMem], os64, reg0 {dont care});
end; end;
procedure AddMem80; procedure AddMem80;
begin begin
AddModRM(False, True, os80); AddModRM([modMem], os80, reg0 {dont care});
end; end;
procedure AddReg(AIndex: Byte); procedure AddReg(AIndex: Byte);
@ -1128,6 +1159,7 @@ var
for n := 1 to OperIdx do for n := 1 to OperIdx do
begin begin
Inc(idx, Operand[n].ByteCount); Inc(idx, Operand[n].ByteCount);
Inc(idx, Operand[n].ByteCount2);
end; end;
// now we can lookup the opcode // now we can lookup the opcode
case Code[CodeIdx + idx] of case Code[CodeIdx + idx] of
@ -1701,7 +1733,7 @@ var
// it is specified as Mq or VRq // it is specified as Mq or VRq
// So when getting Wq, we Add both and know the type // So when getting Wq, we Add both and know the type
AddVps; AddWq; AddVps; AddWq;
if Operand[2].IsMemory if ofMemory in Operand[2].Flags
then Opcode := 'movlps'; then Opcode := 'movlps';
end; end;
1: begin AddVps; AddWps; end; 1: begin AddVps; AddWps; end;
@ -1738,7 +1770,7 @@ var
// it is specified as Mq or VRq // it is specified as Mq or VRq
// So when getting Wq, we Add both and know the type // So when getting Wq, we Add both and know the type
AddVps; AddWq; AddVps; AddWq;
if Operand[2].IsMemory if ofMemory in Operand[2].Flags
then Opcode := 'movhps'; then Opcode := 'movhps';
end; end;
1: begin AddVps; AddWps; end; 1: begin AddVps; AddWps; end;
@ -2271,7 +2303,7 @@ var
end; end;
$C8..$CF: begin $C8..$CF: begin
Opcode := 'bswp'; Opcode := 'bswp';
AddOperand(StdReg(Code[CodeIdx])); AddStdReg(Code[CodeIdx]);
end; end;
//--- //---
$D0: begin $D0: begin
@ -2481,7 +2513,7 @@ var
Include(Flags, flagRex); Include(Flags, flagRex);
end end
else begin else begin
AddOperand(StdReg(Code[CodeIdx])); AddStdReg(Code[CodeIdx]);
if Code[CodeIdx] <= $47 if Code[CodeIdx] <= $47
then Opcode := CheckLock('inc') then Opcode := CheckLock('inc')
else Opcode := CheckLock('dec'); else Opcode := CheckLock('dec');
@ -2490,11 +2522,11 @@ var
//--- //---
$50..$57: begin $50..$57: begin
Opcode := 'push'; Opcode := 'push';
AddOperand(StdReg(Code[CodeIdx])); AddStdReg(Code[CodeIdx]);
end; end;
$58..$5F: begin $58..$5F: begin
Opcode := 'pop'; Opcode := 'pop';
AddOperand(StdReg(Code[CodeIdx])); AddStdReg(Code[CodeIdx]);
end; end;
//--- //---
$60: begin $60: begin
@ -2552,27 +2584,35 @@ var
end; end;
$6C: begin $6C: begin
Opcode := CheckRepeat('insb'); Opcode := CheckRepeat('insb');
{$ifdef verbose_string_instructions}
AddYb; AddYb;
AddOperand('dx', os16); AddOperand('dx', os16);
{$endif}
end; end;
$6D: begin $6D: begin
if OperandSize32 = os16 if OperandSize32 = os16
then Opcode := CheckRepeat('insw') then Opcode := CheckRepeat('insw')
else Opcode := CheckRepeat('insd'); else Opcode := CheckRepeat('insd');
{$ifdef verbose_string_instructions}
AddYz; AddYz;
AddOperand('dx', os16); AddOperand('dx', os16);
{$endif}
end; end;
$6E: begin $6E: begin
Opcode := CheckRepeat('outsb'); Opcode := CheckRepeat('outsb');
{$ifdef verbose_string_instructions}
AddOperand('dx', os16); AddOperand('dx', os16);
AddXb; AddXb;
{$endif}
end; end;
$6F: begin $6F: begin
if OperandSize32 = os16 if OperandSize32 = os16
then Opcode := CheckRepeat('outsw') then Opcode := CheckRepeat('outsw')
else Opcode := CheckRepeat('outsd'); else Opcode := CheckRepeat('outsd');
{$ifdef verbose_string_instructions}
AddOperand('dx', os16); AddOperand('dx', os16);
AddXz; AddXz;
{$endif}
end; end;
$70..$7F: begin $70..$7F: begin
Opcode := 'j' + StdCond(Code[CodeIdx]); Opcode := 'j' + StdCond(Code[CodeIdx]);
@ -2623,7 +2663,7 @@ var
then Opcode := 'nop' then Opcode := 'nop'
else begin else begin
Opcode := 'xchg'; Opcode := 'xchg';
AddOperand(StdReg(Code[CodeIdx])); AddStdReg(Code[CodeIdx]);
AddOperand(SizeReg32('ax')); AddOperand(SizeReg32('ax'));
end; end;
end; end;
@ -2697,7 +2737,9 @@ var
end; end;
$A4: begin $A4: begin
Opcode := CheckRepeat('movsb'); Opcode := CheckRepeat('movsb');
{$ifdef verbose_string_instructions}
AddYb; AddXb; AddYb; AddXb;
{$endif}
end; end;
$A5: begin $A5: begin
case OperandSize32 of case OperandSize32 of
@ -2706,12 +2748,15 @@ var
else else
Opcode := CheckRepeat('movsw'); Opcode := CheckRepeat('movsw');
end; end;
AddYv; {$ifdef verbose_string_instructions}
AddXv; AddYv; AddXv;
{$endif}
end; end;
$A6: begin $A6: begin
Opcode := CheckRepeatX('cmpsb'); Opcode := CheckRepeatX('cmpsb');
{$ifdef verbose_string_instructions}
AddXb; AddYb; AddXb; AddYb;
{$endif}
end; end;
$A7: begin $A7: begin
case OperandSize32 of case OperandSize32 of
@ -2720,7 +2765,9 @@ var
else else
Opcode := CheckRepeatX('cmpsw'); Opcode := CheckRepeatX('cmpsw');
end; end;
{$ifdef verbose_string_instructions}
AddYv; AddXv; AddYv; AddXv;
{$endif}
end; end;
$A8: begin $A8: begin
Opcode := 'test'; Opcode := 'test';
@ -2734,8 +2781,10 @@ var
end; end;
$AA: begin $AA: begin
Opcode := CheckRepeat('stosb'); Opcode := CheckRepeat('stosb');
{$ifdef verbose_string_instructions}
AddYb; AddYb;
AddOperand('al', os8); AddOperand('al', os8);
{$endif}
end; end;
$AB: begin $AB: begin
case OperandSize32 of case OperandSize32 of
@ -2744,13 +2793,17 @@ var
else else
Opcode := CheckRepeat('stosw'); Opcode := CheckRepeat('stosw');
end; end;
{$ifdef verbose_string_instructions}
AddYv; AddYv;
AddOperand(SizeReg32('ax')); AddOperand(SizeReg32('ax'));
{$endif}
end; end;
$AC: begin $AC: begin
Opcode := CheckRepeat('lodsb'); Opcode := CheckRepeat('lodsb');
{$ifdef verbose_string_instructions}
AddOperand('al', os8); AddOperand('al', os8);
AddXb; AddXb;
{$endif}
end; end;
$AD: begin $AD: begin
case OperandSize32 of case OperandSize32 of
@ -2759,13 +2812,17 @@ var
else else
Opcode := CheckRepeat('lodsw'); Opcode := CheckRepeat('lodsw');
end; end;
{$ifdef verbose_string_instructions}
AddOperand(SizeReg32('ax')); AddOperand(SizeReg32('ax'));
AddXv; AddXv;
{$endif}
end; end;
$AE: begin $AE: begin
Opcode := CheckRepeatX('scasb'); Opcode := CheckRepeatX('scasb');
{$ifdef verbose_string_instructions}
AddOperand('al', os8); AddOperand('al', os8);
AddYb; AddYb;
{$endif}
end; end;
$AF: begin $AF: begin
case OperandSize32 of case OperandSize32 of
@ -2774,18 +2831,20 @@ var
else else
Opcode := CheckRepeatX('scasw'); Opcode := CheckRepeatX('scasw');
end; end;
{$ifdef verbose_string_instructions}
AddOperand(SizeReg32('ax')); AddOperand(SizeReg32('ax'));
AddYv; AddYv;
{$endif}
end; end;
//--- //---
$B0..$B7: begin $B0..$B7: begin
Opcode := 'mov'; Opcode := 'mov';
AddOperand(StdReg(Code[CodeIdx], reg8, rexR in Flags), os8); AddStdReg(Code[CodeIdx], reg8, rexR in Flags);
AddIb; AddIb;
end; end;
$B8..$BF: begin $B8..$BF: begin
Opcode := 'mov'; Opcode := 'mov';
AddOperand(StdReg(Code[CodeIdx])); AddStdReg(Code[CodeIdx]);
AddIv; AddIv;
end; end;
//--- //---
@ -2984,33 +3043,25 @@ var
end; end;
Inc(CodeIdx); Inc(CodeIdx);
if CodeIdx > High(Code) if CodeIdx > 16 // max instruction length
then begin then begin
Log('Disassemble: instruction longer than %d bytes', [SizeOf(Code)]); Log('Disassemble: instruction longer than 16 bytes');
Exit; Exit;
end; end;
until Opcode <> ''; until Opcode <> '';
end; end;
const const
MEMPTR: array[TOperandSize] of string = ('byte ptr ', 'word ptr ', 'dword ptr ', 'qword ptr ', 'tbyte ptr '); MEMPTR: array[TOperandSize] of string = ('byte ptr ', 'word ptr ', 'dword ptr ', 'qword ptr ', '', 'tbyte ptr ', '16byte ptr ');
OSTEXT: array[TOperandSize] of string = ('os8', 'os16', 'os32', 'os64', 'os80'); {$ifdef debug_OperandSize}
OSTEXT: array[TOperandSize] of string = ('os8', 'os16', 'os32', 'os64', 'os48', 'os80', 'os128');
{$endif}
var var
BytesRead: Cardinal;
S, Soper: String; S, Soper: String;
n: Integer; n: Integer;
HasMem: Boolean; HasMem: Boolean;
begin begin
BytesRead := 0; Code := AAddress;
if not ReadProcessMemory(AProcess, Pointer(Address), @Code, SizeOf(Code), BytesRead) and (BytesRead = SizeOf(Code))
then begin
Log('Disassemble: Failed to read memory at %s, got %u bytes', [FormatAddress(Address), BytesRead]);
ACode := '??';
ACodeBytes := '??';
Inc(Address);
Exit;
end;
Segment := ''; Segment := '';
Opcode := ''; Opcode := '';
@ -3028,10 +3079,14 @@ begin
begin begin
if Operand[n].ByteCount = 0 if Operand[n].ByteCount = 0
then S := Operand[n].Value then S := Operand[n].Value
else S := Format(Operand[n].Value, [HexValue(Code[CodeIdx], Operand[n].ByteCount, Operand[n].FormatFlags)]); else begin
if Operand[n].ByteCount2 = 0
then S := Format(Operand[n].Value, [HexValue(Code[CodeIdx], Operand[n].ByteCount, Operand[n].FormatFlags)])
else S := Format(Operand[n].Value, [HexValue(Code[CodeIdx], Operand[n].ByteCount, Operand[n].FormatFlags), HexValue(Code[CodeIdx + Operand[n].ByteCount], Operand[n].ByteCount2, Operand[n].FormatFlags)])
end;
if Soper <> '' then Soper := Soper + ','; if Soper <> '' then Soper := Soper + ',';
if Operand[n].IsMemory if ofMemory in Operand[n].Flags
then begin then begin
if (OperIdx = 1) if (OperIdx = 1)
// or (Operand[n].Size <> os32) // or (Operand[n].Size <> os32)
@ -3042,6 +3097,7 @@ begin
end end
else Soper := Soper + S; else Soper := Soper + S;
Inc(CodeIdx, Operand[n].ByteCount); Inc(CodeIdx, Operand[n].ByteCount);
Inc(CodeIdx, Operand[n].ByteCount2);
end; end;
{$ifdef debug_OperandSize} {$ifdef debug_OperandSize}
Soper := Soper + ' | '; Soper := Soper + ' | ';
@ -3052,9 +3108,9 @@ begin
{$endif} {$endif}
S := ''; S := '';
if preLock in Flags then S := S + '**lock:**'; if preLock in Flags then S := S + '**lock**';
if preRep in Flags then S := S + '?rep:?'; if preRep in Flags then S := S + '?rep?';
if preRepNE in Flags then S := S + '?repne:?'; if preRepNE in Flags then S := S + '?repne?';
S := S + Opcode; S := S + Opcode;
if not HasMem and (Segment <> '') then S := S + ' ?' + Segment + '?'; if not HasMem and (Segment <> '') then S := S + ' ?' + Segment + '?';
ACode := S + ' ' + Soper; ACode := S + ' ' + Soper;
@ -3066,7 +3122,7 @@ begin
S := S + HexStr(Code[n], 2); S := S + HexStr(Code[n], 2);
end; end;
ACodeBytes := S; ACodeBytes := S;
Inc(Address, CodeIdx); Inc(AAddress, CodeIdx);
end; end;