From ea30b6f6b9efd2e348687ddbaf5dd4d42309a0ad Mon Sep 17 00:00:00 2001 From: martin Date: Mon, 20 Apr 2020 15:31:45 +0000 Subject: [PATCH] FpDebug: Detect internal forwarding jumps, and avoid stopping at them git-svn-id: trunk@63033 - --- components/fpdebug/fpdbgclasses.pp | 7 +++++ components/fpdebug/fpdbgcontroller.pas | 39 ++++++++++++++++++++++++-- components/fpdebug/fpdbgdisasx86.pp | 31 ++++++++++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/components/fpdebug/fpdbgclasses.pp b/components/fpdebug/fpdbgclasses.pp index cd70b1b840..d2ec94132d 100644 --- a/components/fpdebug/fpdbgclasses.pp +++ b/components/fpdebug/fpdbgclasses.pp @@ -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; diff --git a/components/fpdebug/fpdbgcontroller.pas b/components/fpdebug/fpdbgcontroller.pas index 7e142cf014..3871207acb 100644 --- a/components/fpdebug/fpdbgcontroller.pas +++ b/components/fpdebug/fpdbgcontroller.pas @@ -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 diff --git a/components/fpdebug/fpdbgdisasx86.pp b/components/fpdebug/fpdbgdisasx86.pp index efb40f9970..42fccf982e 100644 --- a/components/fpdebug/fpdbgdisasx86.pp +++ b/components/fpdebug/fpdbgdisasx86.pp @@ -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;