FpDebug: Detect internal forwarding jumps, and avoid stopping at them

git-svn-id: trunk@63033 -
This commit is contained in:
martin 2020-04-20 15:31:45 +00:00
parent 944fd0d817
commit ea30b6f6b9
3 changed files with 74 additions and 3 deletions

View File

@ -405,6 +405,7 @@ type
function IsCallInstruction: boolean; virtual;
function IsReturnInstruction: boolean; virtual;
function IsLeaveStackFrame: boolean; virtual;
function IsJumpInstruction(IncludeConditional: Boolean = True; IncludeUncoditional: Boolean = True): boolean; virtual;
function InstructionLength: Integer; virtual;
end;
@ -1294,6 +1295,12 @@ begin
Result := False;
end;
function TDbgAsmInstruction.IsJumpInstruction(IncludeConditional: Boolean;
IncludeUncoditional: Boolean): boolean;
begin
Result := False;
end;
function TDbgAsmInstruction.InstructionLength: Integer;
begin
Result := 0;

View File

@ -79,6 +79,8 @@ type
FIsSteppedOut: Boolean;
FHiddenBreakpoint: TFpInternalBreakpoint;
FHiddenBreakAddr, FHiddenBreakInstrPtr, FHiddenBreakFrameAddr, FHiddenBreakStackPtrAddr: TDBGPtr;
FWasAtJumpInstruction: Boolean;
FJumpPadCount: Integer;
function GetIsSteppedOut: Boolean;
protected
function IsAtHiddenBreak: Boolean; inline;
@ -88,6 +90,8 @@ type
procedure SetHiddenBreak(AnAddr: TDBGPtr);
procedure RemoveHiddenBreak;
function CheckForCallAndSetBreak: boolean; // True, if break is newly set
procedure StoreWasAtJumpInstruction;
function IsAtJumpPad: Boolean;
procedure Init; override;
procedure InternalContinue(AProcess: TDbgProcess; AThread: TDbgThread); virtual; abstract;
@ -477,6 +481,22 @@ begin
{$POP}
end;
procedure TDbgControllerHiddenBreakStepBaseCmd.StoreWasAtJumpInstruction;
begin
FWasAtJumpInstruction := NextInstruction.IsJumpInstruction;
end;
function TDbgControllerHiddenBreakStepBaseCmd.IsAtJumpPad: Boolean;
begin
Result := FWasAtJumpInstruction and
NextInstruction.IsJumpInstruction(False) and
not FController.FCurrentThread.IsAtStartOfLine; // TODO: check for lines with line=0
if Result then
inc(FJumpPadCount);
if FJumpPadCount > 2 then
Result := False;
end;
procedure TDbgControllerHiddenBreakStepBaseCmd.Init;
begin
FStoredStackPointer := FThread.GetStackPointerRegisterValue;
@ -499,6 +519,8 @@ begin
r := NextInstruction.IsReturnInstruction
else
r := False;
FWasAtJumpInstruction := False;
InternalContinue(AProcess, AThread);
if r and
(FHiddenBreakpoint = nil)
@ -621,6 +643,8 @@ begin
end;
end;
if FState <> siRunningStepOut then
StoreWasAtJumpInstruction;
FProcess.Continue(FProcess, FThread, FState <> siRunningStepOut);
end;
@ -644,6 +668,8 @@ begin
if (FState = siSteppingCurrent) then begin
Finished := HasSteppedAwayFromOriginLine;
if Finished then
Finished := not IsAtJumpPad;
end
else begin
// we stepped into
@ -689,6 +715,9 @@ begin
assert(FProcess=AProcess, 'TDbgControllerStepOverLineCmd.DoContinue: FProcess=AProcess');
if (AThread = FThread) then
CheckForCallAndSetBreak;
if FHiddenBreakpoint = nil then
StoreWasAtJumpInstruction;
FProcess.Continue(FProcess, FThread, FHiddenBreakpoint = nil);
end;
@ -710,10 +739,14 @@ begin
if IsAtOrOutOfHiddenBreakFrame then
RemoveHiddenBreak;
if FHiddenBreakpoint <> nil then
Finished := False
else
if FHiddenBreakpoint <> nil then begin
Finished := False;
end
else begin
Finished := HasSteppedAwayFromOriginLine;
if Finished then
Finished := not IsAtJumpPad;
end;
if Finished then
AnEvent := deFinishedStep

View File

@ -224,6 +224,7 @@ type
function IsCallInstruction: boolean; override;
function IsReturnInstruction: boolean; override;
function IsLeaveStackFrame: 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
@ -446,6 +447,36 @@ begin
Result := (FInstruction.OpCode = OPleave);
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;