FpDebug: improve TX86AsmDecoder.UnwindFrame

This commit is contained in:
Martin 2023-10-09 18:58:54 +02:00
parent 8e2532bdfc
commit ac1a3e6fd2

View File

@ -5536,51 +5536,174 @@ var
const const
MAX_SEARCH_ADDR = 8000; MAX_SEARCH_ADDR = 8000;
MAX_SEARCH_CNT = 400; MAX_SEARCH_CNT = 400;
MAX_ADDR_DONE_BLOCKS = 10;
MAX_FORWARD_ADDR = 5;
var var
MaxAddr, MaxAddr2, StartAddr, StartStack, Tmp: TDBGPtr; AddressDoneBlocks: array [0..MAX_ADDR_DONE_BLOCKS] of record
ConditionalForwardAddr, BackwardJumpAddress: TDBGPtr; First, Last: TDBGPtr;
end;
CurAddressDoneBlock: integer;
MaxAddrCurrentBlock: TDBGPtr;
ConditionalForwardAddr: array [0..MAX_FORWARD_ADDR+1] of TDBGPtr;
CurConditionalForwardAddr: integer;
function AddrWasDone(AnAddr: TDBGPtr): boolean; inline;
var
i: Integer;
begin
i := CurAddressDoneBlock;
Result := (AnAddr >= AddressDoneBlocks[i].First) and (AnAddr < NewAddr);
while (not Result) and (i > 0) do begin
dec(i);
Result := (AnAddr >= AddressDoneBlocks[i].First) and (AnAddr < AddressDoneBlocks[i].Last);
end;
end;
function NextDoneAddrFor(AnAddr: TDBGPtr): TDBGPtr; inline;
var
i: Integer;
begin
Result := high(TDBGPtr);
i := CurAddressDoneBlock - 1;
while (i >= 0) do begin
if (AnAddr < AddressDoneBlocks[i].First) and
(Result > AddressDoneBlocks[i].First)
then
Result := AddressDoneBlocks[i].First;
dec(i);
end;
end;
procedure FinishCurAddrBlock; inline;
begin
if CurAddressDoneBlock < MAX_ADDR_DONE_BLOCKS then begin
AddressDoneBlocks[CurAddressDoneBlock].Last := NewAddr;
inc(CurAddressDoneBlock);
AddressDoneBlocks[CurAddressDoneBlock].First := high(TDBGPtr);
end
else
if NewAddr > AddressDoneBlocks[CurAddressDoneBlock].Last then begin
AddressDoneBlocks[CurAddressDoneBlock].Last := NewAddr;
end;
end;
procedure StartNextAddrBlock; inline;
begin
if CurAddressDoneBlock < MAX_ADDR_DONE_BLOCKS then
AddressDoneBlocks[CurAddressDoneBlock].First := NewAddr
else
if NewAddr < AddressDoneBlocks[CurAddressDoneBlock].First then
AddressDoneBlocks[CurAddressDoneBlock].First := NewAddr;
MaxAddrCurrentBlock := NextDoneAddrFor(NewAddr);
end;
procedure CheckConditionalForwAddr; inline;
var
j, i: Integer;
begin
j := 0;
for i := 0 to CurConditionalForwardAddr do
if (ConditionalForwardAddr[i] >= NewAddr) or
(ConditionalForwardAddr[i] < AddressDoneBlocks[CurAddressDoneBlock].First)
then begin
ConditionalForwardAddr[j] := ConditionalForwardAddr[i];
inc(j);
end;
CurConditionalForwardAddr := j - 1;
end;
procedure AddConditionalForwAddr(AnAddr: TDBGPtr); inline;
var
i, j: Integer;
begin
i := CurConditionalForwardAddr;
while (i >= 0) and (AnAddr <> ConditionalForwardAddr[i]) do
dec(i);
if i >= 0 then
exit;
if CurConditionalForwardAddr < MAX_FORWARD_ADDR then begin
inc(CurConditionalForwardAddr);
ConditionalForwardAddr[CurConditionalForwardAddr] := AnAddr;
end
else begin
j := 0;
for i := 0 to CurConditionalForwardAddr do
if (ConditionalForwardAddr[i] >= NewAddr) or
(ConditionalForwardAddr[i] < AddressDoneBlocks[CurAddressDoneBlock].First)
then begin
ConditionalForwardAddr[j] := ConditionalForwardAddr[i];
inc(j);
end;
CurConditionalForwardAddr := j - 1;
if CurConditionalForwardAddr < MAX_FORWARD_ADDR then
inc(CurConditionalForwardAddr);
ConditionalForwardAddr[CurConditionalForwardAddr] := AnAddr;
end;
end;
var
MaxAddr, StartStack, Tmp: TDBGPtr;
BackwardJumpAddress: TDBGPtr;
Cnt: Integer; Cnt: Integer;
instr: TX86AsmInstruction; instr: TX86AsmInstruction;
RSize: Cardinal; RSize: Cardinal;
Val: Int64; Val: Int64;
ClearRecValList: Boolean; ClearRecValList, ForceDifferentBranch: Boolean;
FullName: String; FullName: String;
begin begin
Result := False; Result := False;
NewAddr := AnAddress; NewAddr := AnAddress;
NewStack := AStackPtr; NewStack := AStackPtr;
NewFrame := AFramePtr; NewFrame := AFramePtr;
StartAddr := AnAddress;
StartStack := AStackPtr; StartStack := AStackPtr;
ConditionalForwardAddr := 0; CurConditionalForwardAddr := -1;
BackwardJumpAddress := 0; BackwardJumpAddress := 0;
{$PUSH}{$R-}{$Q-} {$PUSH}{$R-}{$Q-}
MaxAddr := AnAddress + MAX_SEARCH_ADDR; MaxAddr := AnAddress + MAX_SEARCH_ADDR;
{$POP} {$POP}
MaxAddr2 := MaxAddr;
Cnt := MAX_SEARCH_CNT; Cnt := MAX_SEARCH_CNT;
if AQuick then Cnt := 10; if AQuick then Cnt := 10;
CurAddressDoneBlock := 0;
AddressDoneBlocks[CurAddressDoneBlock].First := AnAddress;
MaxAddrCurrentBlock := MaxAddr;
ClearRecValList := False; ClearRecValList := False;
while (NewAddr < MaxAddr) and (Cnt > 0) do begin ForceDifferentBranch := False;
while (Cnt > 0) do begin
if ClearRecValList then ARegisterValueList.Clear; if ClearRecValList then ARegisterValueList.Clear;
if NewAddr > MaxAddr2 then begin if ForceDifferentBranch or (NewAddr >= MaxAddr) or( NewAddr > MaxAddrCurrentBlock) then begin
if (ConditionalForwardAddr > 0) and (BackwardJumpAddress > 0) and CheckConditionalForwAddr;
(ConditionalForwardAddr >= BackwardJumpAddress) FinishCurAddrBlock;
then begin while (CurConditionalForwardAddr >= 0) and
NewAddr := ConditionalForwardAddr; AddrWasDone(ConditionalForwardAddr[CurConditionalForwardAddr])
MaxAddr2 := MaxAddr; do
dec(CurConditionalForwardAddr);
if (CurConditionalForwardAddr >= 0) then begin
NewAddr := ConditionalForwardAddr[CurConditionalForwardAddr];
dec(CurConditionalForwardAddr);
end
else
if (BackwardJumpAddress > 0) and (not AddrWasDone(BackwardJumpAddress)) then begin
NewAddr := BackwardJumpAddress;
BackwardJumpAddress := 0;
end end
else else
exit; exit;
StartNextAddrBlock;
ARegisterValueList.Clear;
end; end;
ForceDifferentBranch := False;
dec(Cnt); dec(Cnt);
instr := TX86AsmInstruction(GetInstructionInfo(NewAddr)); instr := TX86AsmInstruction(GetInstructionInfo(NewAddr));
if instr.InstructionLength <= 0 then if instr.InstructionLength <= 0 then begin
exit; ForceDifferentBranch := True;
continue;
end;
{$PUSH}{$R-}{$Q-} {$PUSH}{$R-}{$Q-}
NewAddr := NewAddr + instr.InstructionLength; NewAddr := NewAddr + instr.InstructionLength;
{$POP} {$POP}
@ -5624,7 +5747,8 @@ begin
IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') or IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') or
IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
then begin then begin
exit; // false ForceDifferentBranch := True;
continue;
end; end;
{$PUSH}{$R-}{$Q-} {$PUSH}{$R-}{$Q-}
NewStack := NewStack - RegisterSize(instr.X86Instruction.Operand[1].Value); NewStack := NewStack - RegisterSize(instr.X86Instruction.Operand[1].Value);
@ -5633,8 +5757,10 @@ begin
OPpusha: OPpusha:
begin begin
ClearRecValList := False; ClearRecValList := False;
if (FProcess.Mode <> dm32) or (instr.X86Instruction.OpCode.Suffix <> OPSx_d) then if (FProcess.Mode <> dm32) or (instr.X86Instruction.OpCode.Suffix <> OPSx_d) then begin
exit; ForceDifferentBranch := True;
continue;
end;
// push 8 registers // push 8 registers
{$PUSH}{$R-}{$Q-} {$PUSH}{$R-}{$Q-}
NewStack := NewStack - (8*4); NewStack := NewStack - (8*4);
@ -5643,19 +5769,28 @@ begin
OPpushf: OPpushf:
begin begin
ClearRecValList := False; ClearRecValList := False;
exit; // false ForceDifferentBranch := True;
continue;
end; end;
OPpopa, OPpopad: OPpopa, OPpopad:
exit; // false begin
ClearRecValList := False;
ForceDifferentBranch := True;
continue;
end;
OPpop: OPpop:
begin begin
if instr.X86Instruction.OperCnt <> 1 then if instr.X86Instruction.OperCnt <> 1 then begin
exit; ForceDifferentBranch := True;
continue;
end;
ClearRecValList := False; ClearRecValList := False;
ClearRegister(instr.X86Instruction.Operand[1].Value); ClearRegister(instr.X86Instruction.Operand[1].Value);
if not(instr.X86Instruction.Operand[1].Value[1] in ['e', 'r']) if not(instr.X86Instruction.Operand[1].Value[1] in ['e', 'r'])
then then begin
exit; // false ForceDifferentBranch := True;
continue;
end;
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp')
then begin then begin
if NewStack < StartStack then if NewStack < StartStack then
@ -5696,15 +5831,19 @@ begin
end; end;
OPmov: OPmov:
begin begin
if instr.X86Instruction.OperCnt <> 2 then if instr.X86Instruction.OperCnt <> 2 then begin
exit; ForceDifferentBranch := True;
continue;
end;
ClearRecValList := False; ClearRecValList := False;
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') and if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') and
not(ofMemory in Instr.X86Instruction.Operand[1].Flags) not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
then begin then begin
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
exit; ForceDifferentBranch := True;
continue;
end;
NewStack := Tmp; NewStack := Tmp;
end end
else else
@ -5728,16 +5867,20 @@ begin
end; end;
OPlea: OPlea:
begin begin
if instr.X86Instruction.OperCnt <> 2 then if instr.X86Instruction.OperCnt <> 2 then begin
exit; ForceDifferentBranch := True;
continue;
end;
ClearRecValList := False; ClearRecValList := False;
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp')
then begin then begin
if (Instr.X86Instruction.Operand[2].ByteCount = 0) or if (Instr.X86Instruction.Operand[2].ByteCount = 0) or
(Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or (Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or
not(ofMemory in Instr.X86Instruction.Operand[2].Flags) not(ofMemory in Instr.X86Instruction.Operand[2].Flags)
then then begin
exit; ForceDifferentBranch := True;
continue;
end;
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags); Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags);
if (IsRegister(instr.X86Instruction.Operand[2].Value, 'sp%s')) then begin if (IsRegister(instr.X86Instruction.Operand[2].Value, 'sp%s')) then begin
@ -5762,8 +5905,10 @@ begin
if (Instr.X86Instruction.Operand[2].ByteCount = 0) or if (Instr.X86Instruction.Operand[2].ByteCount = 0) or
(Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or (Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or
not(ofMemory in Instr.X86Instruction.Operand[2].Flags) not(ofMemory in Instr.X86Instruction.Operand[2].Flags)
then then begin
exit; ForceDifferentBranch := True;
continue;
end;
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags); Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags);
if (IsRegister(instr.X86Instruction.Operand[2].Value, 'sp%s')) then begin if (IsRegister(instr.X86Instruction.Operand[2].Value, 'sp%s')) then begin
@ -5781,8 +5926,10 @@ begin
if ValueFromOperand(instr.X86Instruction.Operand[2], Tmp, True) then begin if ValueFromOperand(instr.X86Instruction.Operand[2], Tmp, True) then begin
NewStack := Tmp; NewStack := Tmp;
end end
else else begin
exit; ForceDifferentBranch := True;
continue;
end;
end end
else begin else begin
FullName := LowerCase(FullRegisterName(instr.X86Instruction.Operand[1].Value)); FullName := LowerCase(FullRegisterName(instr.X86Instruction.Operand[1].Value));
@ -5803,16 +5950,20 @@ begin
end; end;
OPadd: OPadd:
begin begin
if instr.X86Instruction.OperCnt <> 2 then if instr.X86Instruction.OperCnt <> 2 then begin
exit; ForceDifferentBranch := True;
continue;
end;
ClearRecValList := False; ClearRecValList := False;
ClearRegister(instr.X86Instruction.Operand[1].Value); ClearRegister(instr.X86Instruction.Operand[1].Value);
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') and if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') and
not(ofMemory in Instr.X86Instruction.Operand[1].Flags) not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
then begin then begin
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
exit; ForceDifferentBranch := True;
continue;
end;
{$PUSH}{$R-}{$Q-} {$PUSH}{$R-}{$Q-}
NewStack := NewStack + int64(Tmp); NewStack := NewStack + int64(Tmp);
{$POP} {$POP}
@ -5820,8 +5971,10 @@ begin
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') and if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') and
not(ofMemory in Instr.X86Instruction.Operand[1].Flags) not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
then begin then begin
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
exit; ForceDifferentBranch := True;
continue;
end;
{$PUSH}{$R-}{$Q-} {$PUSH}{$R-}{$Q-}
NewFrame := NewFrame + int64(Tmp); NewFrame := NewFrame + int64(Tmp);
{$POP} {$POP}
@ -5829,16 +5982,20 @@ begin
end; end;
OPsub: OPsub:
begin begin
if instr.X86Instruction.OperCnt <> 2 then if instr.X86Instruction.OperCnt <> 2 then begin
exit; ForceDifferentBranch := True;
continue;
end;
ClearRecValList := False; ClearRecValList := False;
ClearRegister(instr.X86Instruction.Operand[1].Value); ClearRegister(instr.X86Instruction.Operand[1].Value);
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') and if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') and
not(ofMemory in Instr.X86Instruction.Operand[1].Flags) not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
then begin then begin
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
exit; ForceDifferentBranch := True;
continue;
end;
{$PUSH}{$R-}{$Q-} {$PUSH}{$R-}{$Q-}
NewStack := NewStack - int64(Tmp); NewStack := NewStack - int64(Tmp);
{$POP} {$POP}
@ -5846,8 +6003,10 @@ begin
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') and if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') and
not(ofMemory in Instr.X86Instruction.Operand[1].Flags) not(ofMemory in Instr.X86Instruction.Operand[1].Flags)
then begin then begin
if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then if not ValueFromOperand(instr.X86Instruction.Operand[2], Tmp) then begin
exit; ForceDifferentBranch := True;
continue;
end;
{$PUSH}{$R-}{$Q-} {$PUSH}{$R-}{$Q-}
NewFrame := NewFrame - int64(Tmp); NewFrame := NewFrame - int64(Tmp);
{$POP} {$POP}
@ -5862,47 +6021,74 @@ begin
then then
begin begin
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[1].CodeIndex], Instr.X86Instruction.Operand[1].ByteCount, Instr.X86Instruction.Operand[1].FormatFlags); Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[1].CodeIndex], Instr.X86Instruction.Operand[1].ByteCount, Instr.X86Instruction.Operand[1].FormatFlags);
{$PUSH}{$R-}{$Q-}
Tmp := NewAddr + Val;
{$POP}
if Val > 0 then begin if Val > 0 then begin
{$PUSH}{$R-}{$Q-} if (Tmp < MaxAddr) and (not AddrWasDone(Tmp)) then
Tmp := NewAddr + Val; AddConditionalForwAddr(Tmp);
{$POP} end
if (Tmp > ConditionalForwardAddr) and (Tmp < MaxAddr) then else begin
ConditionalForwardAddr := Tmp; if ((BackwardJumpAddress = 0) or (Tmp < BackwardJumpAddress)) and
(not AddrWasDone(Tmp))
then
BackwardJumpAddress := Tmp;
end; end;
end; end;
OPjmp: OPjmp:
begin begin
if AQuick then if AQuick then
exit; exit;
if instr.X86Instruction.OperCnt <> 1 then if instr.X86Instruction.OperCnt <> 1 then begin
exit; ForceDifferentBranch := True;
if (instr.X86Instruction.Operand[1].Value <> '%s') then continue;
exit; // false end;
if (instr.X86Instruction.Operand[1].Value <> '%s') then begin
ForceDifferentBranch := True;
continue;
end;
if (Instr.X86Instruction.Operand[1].ByteCount = 0) or if (Instr.X86Instruction.Operand[1].ByteCount = 0) or
(Instr.X86Instruction.Operand[1].ByteCount2 <> 0) (Instr.X86Instruction.Operand[1].ByteCount2 <> 0)
then then begin
exit; ForceDifferentBranch := True;
continue;
end;
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[1].CodeIndex], Instr.X86Instruction.Operand[1].ByteCount, Instr.X86Instruction.Operand[1].FormatFlags); Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[1].CodeIndex], Instr.X86Instruction.Operand[1].ByteCount, Instr.X86Instruction.Operand[1].FormatFlags);
{$PUSH}{$R-}{$Q-} {$PUSH}{$R-}{$Q-}
Tmp := NewAddr + Val; Tmp := NewAddr + Val;
{$POP} {$POP}
if (Val < 0) then begin if (Val < 0) then begin
if ConditionalForwardAddr >= NewAddr then begin CheckConditionalForwAddr;
NewAddr := ConditionalForwardAddr; if (CurConditionalForwardAddr >= 0) then begin
FinishCurAddrBlock;
NewAddr := ConditionalForwardAddr[CurConditionalForwardAddr];
dec(CurConditionalForwardAddr);
StartNextAddrBlock;
ClearRecValList := True;
if ((BackwardJumpAddress = 0) or (Tmp < BackwardJumpAddress)) and
(not AddrWasDone(Tmp))
then
BackwardJumpAddress := Tmp;
continue; continue;
end; end;
if (Tmp > StartAddr) or (Tmp < StartAddr - MAX_SEARCH_ADDR) then
exit;
MaxAddr2 := StartAddr;
BackwardJumpAddress := NewAddr;
end; end;
if AddrWasDone(Tmp) then begin
ForceDifferentBranch := True;
continue;
end;
FinishCurAddrBlock;
NewAddr := Tmp; NewAddr := Tmp;
StartNextAddrBlock;
end;
OPjmpe, OPint, OPint1, OPint3: begin
ForceDifferentBranch := True;
continue;
end; end;
OPjmpe, OPint, OPint1, OPint3:
exit; // false
OPtest, OPtpause, OPnop, OPcmp, OPcmps: OPtest, OPtpause, OPnop, OPcmp, OPcmps:
ClearRecValList := False; ClearRecValList := False;
else else
@ -5913,7 +6099,8 @@ begin
IsRegister(instr.X86Instruction.Operand[1].Value, 'sp') IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
) )
then begin then begin
exit; // false ForceDifferentBranch := True;
continue;
end; end;
end; end;
end; end;