LazDebuggerFp: Win64 -Monitor RtlRestoreContext to catch more unwind cases.

This commit is contained in:
Martin 2021-12-08 20:04:41 +01:00
parent 269079e11a
commit c90fb08f85

View File

@ -32,7 +32,7 @@ unit FpDebugDebugger;
interface
uses
Classes, SysUtils, fgl, math, process,
Classes, {$IfDef WIN64}windows,{$EndIf} SysUtils, fgl, math, process,
Forms, Dialogs, syncobjs,
Maps, LazLoggerBase, LazUTF8, lazCollections,
DbgIntfBaseTypes, DbgIntfDebuggerBase,
@ -216,8 +216,8 @@ type
TBreakPointLoc = (
bplRaise, bplReRaise, bplBreakError, bplRunError,
bplPopExcept, bplCatches,
bplRtlUnwind, bplFpcSpecific,
bplSehW64Finally, bplSehW64Except,
bplRtlUnwind, bplFpcSpecific, bplRtlRestoreContext,
bplSehW64Finally, bplSehW64Except, bplSehW64Unwound,
bplStepOut // Step out of Pop/Catches
);
TBreakPointLocs = set of TBreakPointLoc;
@ -2439,13 +2439,18 @@ begin
FBreakPoints[bplFpcSpecific] := FDebugger.AddBreak('__FPC_specific_handler', nil, False);
FBreakPoints[bplSehW64Except] := FDebugger.AddBreak(0, False);
FBreakPoints[bplSehW64Finally] := FDebugger.AddBreak(0, False);
FBreakPoints[bplSehW64Unwound] := FDebugger.AddBreak(0, False);
debuglnExit(DBG_BREAKPOINTS, ['<< TFpDebugDebugger.SetSoftwareExceptionBreakpoint ' ]);
end;
procedure TFpDebugExceptionStepping.DoNtDllLoaded(ALib: TDbgLibrary);
begin
debugln(DBG_BREAKPOINTS, ['SetSoftwareExceptionBreakpoint RtlUnwind']);
DisableBreaksDirect([bplRtlUnwind]);
DisableBreaksDirect([bplRtlUnwind, bplRtlRestoreContext]);
{$IfDef WIN64}
FreeAndNil(FBreakPoints[bplRtlRestoreContext]);
FBreakPoints[bplRtlRestoreContext] := FDebugger.AddBreak('RtlRestoreContext', ALib, False);
{$EndIf}
FBreakPoints[bplRtlUnwind].Free;
FBreakPoints[bplRtlUnwind] := FDebugger.AddBreak('RtlUnwindEx', ALib, False);
end;
@ -2465,6 +2470,8 @@ begin
// Running in debug thread
EnableBreaksDirect(FBreakNewEnabled - FBreakEnabled);
DisableBreaksDirect(FBreakEnabled - FBreakNewEnabled);
if assigned(FBreakPoints[bplSehW64Unwound]) then
FBreakPoints[bplSehW64Unwound].RemoveAllAddresses;
end;
procedure TFpDebugExceptionStepping.ThreadProcessLoopCycle(
@ -2552,6 +2559,18 @@ begin
exit;
FDebugger.FDbgController.DefaultContext; // Make sure it is avail and cached / so it can be called outside the thread
PC := CurrentThread.GetInstructionPointerRegisterValue;
if Assigned(FBreakPoints[bplSehW64Unwound]) and FBreakPoints[bplSehW64Unwound].HasLocation(PC)
then begin
FBreakPoints[bplSehW64Unwound].RemoveAllAddresses;
AFinishLoopAndSendEvents := AnIsFinished or (FState = esStepToFinally);
if AFinishLoopAndSendEvents then begin
AnEventType := deFinishedStep; // only step commands can end up here
exit;
end;
end;
if (FState = esSteppingFpcSpecialHandler) and
(ACurCommand is TDbgControllerStepThroughFpcSpecialHandler) and
(TDbgControllerStepThroughFpcSpecialHandler(ACurCommand).InteralFinished)
@ -2576,7 +2595,6 @@ begin
end;
DisableBreaksDirect([bplRtlUnwind, bplSehW64Finally]); // bplRtlUnwind must always be unset;
PC := CurrentThread.GetInstructionPointerRegisterValue;
SP := CurrentThread.GetStackPointerRegisterValue;
FAddressFrameListSehW64Except.RemoveOutOfScopeFrames(SP, FBreakPoints[bplSehW64Except]);
if ACurCommand is TDbgControllerStepOutCmd then
@ -2727,6 +2745,25 @@ begin
FBreakPoints[bplSehW64Finally].SetBreak;
end
else
// bplRtlRestoreContext
if assigned(FBreakPoints[bplRtlRestoreContext]) and FBreakPoints[bplRtlRestoreContext].HasLocation(PC) then begin
AFinishLoopAndSendEvents := False;
if (CurrentCommand <> nil) and (CurrentCommand.Thread <> CurrentThread) then
exit;
debugln(FPDBG_COMMANDS, ['@ bplRtlRestoreContext ', DbgSName(CurrentCommand)]);
{$IfDef WIN64}
// RCX = TContext
Rcx := CurrentThread.RegisterValueList.FindRegisterByDwarfIndex(2).NumValue; // rsp at target
if (Rcx <> 0) then begin
if (not CurrentProcess.ReadAddress(Rcx + PtrUInt(@PCONTEXT(nil)^.Rip), Addr)) or (Addr = 0) then
exit;
FBreakPoints[bplSehW64Unwound].AddAddress(Addr);
FBreakPoints[bplSehW64Unwound].SetBreak;
end;
{$EndIf}
end
else
// bplRtlUnwind
if assigned(FBreakPoints[bplRtlUnwind]) and FBreakPoints[bplRtlUnwind].HasLocation(PC) then begin
debugln(FPDBG_COMMANDS, ['@ bplRtlUnwind ', DbgSName(CurrentCommand)]);
@ -2832,11 +2869,11 @@ begin
st := FState;
FState := esNone;
DisableBreaks([bplPopExcept, bplCatches, bplFpcSpecific,
bplReRaise,
bplReRaise, bplRtlRestoreContext,
bplRtlUnwind, bplStepOut]);
if ACommand in [dcStepInto, dcStepOver, dcStepOut, dcStepTo, dcRunTo, dcStepOverInstr{, dcStepIntoInstr}] then
EnableBreaks([bplReRaise]);
EnableBreaks([bplReRaise, bplRtlRestoreContext]);
if ACommand in [dcStepOut] then
EnableBreaks([bplFpcSpecific]);