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