FpGdbmiDebugger: allow stepping to continue over exceptions / allow to step from excepitons (raise) to finally/except (include implicit finally)

git-svn-id: trunk@44769 -
This commit is contained in:
martin 2014-04-20 17:38:53 +00:00
parent e1881c3f4c
commit c1899b0b90

View File

@ -469,7 +469,7 @@ type
private private
FCanKillNow, FDidKillNow: Boolean; FCanKillNow, FDidKillNow: Boolean;
protected protected
function ProcessRunning(var AStoppedParams: String; out AResult: TGDBMIExecResult; ATimeOut: Integer = 0): Boolean; function ProcessRunning(out AStoppedParams: String; out AResult: TGDBMIExecResult; ATimeOut: Integer = 0): Boolean;
function ParseBreakInsertError(var AText: String; out AnId: Integer): Boolean; function ParseBreakInsertError(var AText: String; out AnId: Integer): Boolean;
function ProcessStopped(const {%H-}AParams: String; const {%H-}AIgnoreSigIntState: Boolean): Boolean; virtual; function ProcessStopped(const {%H-}AParams: String; const {%H-}AIgnoreSigIntState: Boolean): Boolean; virtual;
public public
@ -568,6 +568,7 @@ type
TGDBMIInternalBreakPoint = class TGDBMIInternalBreakPoint = class
private private
FEnabled: Boolean;
FLineOffsFunction: string; FLineOffsFunction: string;
// -break-insert name // -break-insert name
FNameBreakID: Integer; FNameBreakID: Integer;
@ -605,10 +606,14 @@ type
function ClearId(ACmd: TGDBMIDebuggerCommand; AnId: Integer): Boolean; function ClearId(ACmd: TGDBMIDebuggerCommand; AnId: Integer): Boolean;
function MatchAddr(AnAddr: TDBGPtr): boolean; function MatchAddr(AnAddr: TDBGPtr): boolean;
function MatchId(AnId: Integer): boolean; function MatchId(AnId: Integer): boolean;
function Enabled: boolean; function IsBreakSet: boolean;
procedure EnableOrSetByAddr(ACmd: TGDBMIDebuggerCommand; SetNamedOnFail: Boolean = False);
procedure Enable(ACmd: TGDBMIDebuggerCommand);
procedure Disable(ACmd: TGDBMIDebuggerCommand);
property MainAddrFound: TDBGPtr read FMainAddrFound; property MainAddrFound: TDBGPtr read FMainAddrFound;
property LineOffsFunction: string read FLineOffsFunction; property LineOffsFunction: string read FLineOffsFunction;
property UseForceFlag: Boolean read FUseForceFlag write FUseForceFlag; property UseForceFlag: Boolean read FUseForceFlag write FUseForceFlag;
property Enabled: Boolean read FEnabled;
end; end;
{ TGDBMIWatches } { TGDBMIWatches }
@ -656,7 +661,9 @@ type
FBreakErrorBreak: TGDBMIInternalBreakPoint; FBreakErrorBreak: TGDBMIInternalBreakPoint;
FRunErrorBreak: TGDBMIInternalBreakPoint; FRunErrorBreak: TGDBMIInternalBreakPoint;
FExceptionBreak: TGDBMIInternalBreakPoint; FExceptionBreak: TGDBMIInternalBreakPoint;
FPopExceptStack, FCatchesBreak, FReRaiseBreak: TGDBMIInternalBreakPoint;
FPauseWaitState: TGDBMIPauseWaitState; FPauseWaitState: TGDBMIPauseWaitState;
FStoppedReason: (srNone, srRaiseExcept, srReRaiseExcept, srPopExceptStack, srCatches);
FInExecuteCount: Integer; FInExecuteCount: Integer;
FInIdle: Boolean; FInIdle: Boolean;
FRunQueueOnUnlock: Boolean; FRunQueueOnUnlock: Boolean;
@ -1737,6 +1744,9 @@ begin
FTheDebugger.FExceptionBreak.Clear(Self); FTheDebugger.FExceptionBreak.Clear(Self);
FTheDebugger.FBreakErrorBreak.Clear(Self); FTheDebugger.FBreakErrorBreak.Clear(Self);
FTheDebugger.FRunErrorBreak.Clear(Self); FTheDebugger.FRunErrorBreak.Clear(Self);
FTheDebugger.FPopExceptStack.Clear(Self);
FTheDebugger.FCatchesBreak.Clear(Self);
FTheDebugger.FReRaiseBreak.Clear(Self);
if DebuggerState = dsError then Exit; if DebuggerState = dsError then Exit;
S := FTheDebugger.ConvertToGDBPath(UTF8ToSys(FTheDebugger.FileName), cgptExeName); S := FTheDebugger.ConvertToGDBPath(UTF8ToSys(FTheDebugger.FileName), cgptExeName);
@ -2396,7 +2406,7 @@ end;
{ TGDBMIDebuggerCommandExecuteBase } { TGDBMIDebuggerCommandExecuteBase }
function TGDBMIDebuggerCommandExecuteBase.ProcessRunning(var AStoppedParams: String; out function TGDBMIDebuggerCommandExecuteBase.ProcessRunning(out AStoppedParams: String; out
AResult: TGDBMIExecResult; ATimeOut: Integer): Boolean; AResult: TGDBMIExecResult; ATimeOut: Integer): Boolean;
var var
InLogWarning: Boolean; InLogWarning: Boolean;
@ -2597,6 +2607,7 @@ begin
InLogWarning := False; InLogWarning := False;
FGotStopped := False; FGotStopped := False;
FLogWarnings := ''; FLogWarnings := '';
AStoppedParams := '';
while FTheDebugger.DebugProcessRunning and not(FTheDebugger.State in [dsError, dsDestroying]) do while FTheDebugger.DebugProcessRunning and not(FTheDebugger.State in [dsError, dsDestroying]) do
begin begin
if ATimeOut > 0 then begin if ATimeOut > 0 then begin
@ -4814,7 +4825,7 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
mtEntry: FTheDebugger.FMainAddrBreak.SetAtCustomAddr(Self, StrToQWordDef(EntryPoint, 0)); mtEntry: FTheDebugger.FMainAddrBreak.SetAtCustomAddr(Self, StrToQWordDef(EntryPoint, 0));
mtAddZero: FTheDebugger.FMainAddrBreak.SetAtLineOffs(Self, 0); mtAddZero: FTheDebugger.FMainAddrBreak.SetAtLineOffs(Self, 0);
end; end;
Result := FTheDebugger.FMainAddrBreak.Enabled; Result := FTheDebugger.FMainAddrBreak.IsBreakSet;
end; end;
begin begin
case RunToMainState of case RunToMainState of
@ -4905,7 +4916,7 @@ function TGDBMIDebuggerCommandStartDebugging.DoExecute: Boolean;
FTheDebugger.FMainAddrBreak.Clear(Self); FTheDebugger.FMainAddrBreak.Clear(Self);
while true do begin while true do begin
SetMainBrk; SetMainBrk;
if not FTheDebugger.FMainAddrBreak.Enabled if not FTheDebugger.FMainAddrBreak.IsBreakSet
then begin then begin
(* TODO: (* TODO:
If no main break can be set, it may still be possible (desirable) to run If no main break can be set, it may still be possible (desirable) to run
@ -5556,6 +5567,7 @@ function TGDBMIDebuggerCommandExecute.ProcessStopped(const AParams: String;
ExceptInfo: TGDBMIExceptionInfo; ExceptInfo: TGDBMIExceptionInfo;
ExceptItem: TBaseException; ExceptItem: TBaseException;
begin begin
FTheDebugger.FStoppedReason := srRaiseExcept;
if (FTheDebugger.Exceptions = nil) or FTheDebugger.Exceptions.IgnoreAll if (FTheDebugger.Exceptions = nil) or FTheDebugger.Exceptions.IgnoreAll
then begin then begin
Result := True; //ExecuteCommand('-exec-continue') Result := True; //ExecuteCommand('-exec-continue')
@ -5863,6 +5875,7 @@ begin
*) *)
Result := False; Result := False;
FTheDebugger.FInProcessStopped := True; // paused, but maybe state run FTheDebugger.FInProcessStopped := True; // paused, but maybe state run
FTheDebugger.FStoppedReason := srNone;
List := TGDBMINameValueList.Create(AParams); List := TGDBMINameValueList.Create(AParams);
List2 := nil; List2 := nil;
@ -5971,6 +5984,27 @@ begin
Exit; Exit;
end; end;
if FTheDebugger.FPopExceptStack.MatchId(BreakID)
then begin
FTheDebugger.FStoppedReason := srPopExceptStack;
Result := True;
Exit;
end;
if FTheDebugger.FCatchesBreak.MatchId(BreakID)
then begin
FTheDebugger.FStoppedReason := srCatches;
Result := True;
Exit;
end;
if FTheDebugger.FReRaiseBreak.MatchId(BreakID)
then begin
FTheDebugger.FStoppedReason := srReRaiseExcept;
Result := True;
Exit;
end;
if (FStepBreakPoint > 0) and (BreakID = FStepBreakPoint) if (FStepBreakPoint > 0) and (BreakID = FStepBreakPoint)
then begin then begin
SetDebuggerState(dsPause); SetDebuggerState(dsPause);
@ -6054,6 +6088,8 @@ end;
{$ENDIF} {$ENDIF}
function TGDBMIDebuggerCommandExecute.DoExecute: Boolean; function TGDBMIDebuggerCommandExecute.DoExecute: Boolean;
var
RunMode: (rmNormal, rmStepToFinally);
const const
BreaKErrMsg = 'not insert breakpoint '; BreaKErrMsg = 'not insert breakpoint ';
WatchErrMsg = 'not insert hardware watchpoint '; WatchErrMsg = 'not insert hardware watchpoint ';
@ -6238,6 +6274,7 @@ const
var var
FP: TDBGPtr; FP: TDBGPtr;
CurThreadId: Integer;
function DoContinueStepping: Boolean; function DoContinueStepping: Boolean;
procedure DoEndStepping; procedure DoEndStepping;
@ -6258,6 +6295,33 @@ var
// TODO: the "break" breakpoint can stop on the current, instead of the next instruction // TODO: the "break" breakpoint can stop on the current, instead of the next instruction
Result := False; Result := False;
if RunMode = rmStepToFinally then begin
Result := FTheDebugger.FStoppedReason in [srPopExceptStack, srCatches];
if Result then
FCurrentExecCmd := ectStepOut;
exit;
end;
if FTheDebugger.FStoppedReason = srReRaiseExcept then begin
FTheDebugger.FPopExceptStack.EnableOrSetByAddr(Self, True);
FTheDebugger.FCatchesBreak.EnableOrSetByAddr(Self, True);
FCurrentExecCmd := ectContinue;
Result := True;
exit;
end;
if FTheDebugger.FStoppedReason in [srPopExceptStack, srCatches] then begin
FTheDebugger.FPopExceptStack.Disable(Self);
FTheDebugger.FCatchesBreak.Disable(Self);
i := FindStackFrame(Fp, 0, 1);
if (i in [0, 1]) or (i = -2) // -2 already stepped out of the desired frame, enter dsPause
then begin
FCurrentExecCmd := ectStepOut; // ecStepOut will not offer a change to ContinueStepping
Result := True;
exit;
end;
end;
case FExecType of case FExecType of
ectContinue, ectRun: ectContinue, ectRun:
begin begin
@ -6278,8 +6342,8 @@ var
ectStepOver, ectStepOverInstruction, ectStepOut, ectStepInto: ectStepOver, ectStepOverInstruction, ectStepOut, ectStepInto:
begin begin
Result := FStepBreakPoint > 0; Result := FStepBreakPoint > 0;
if Result if Result then
then exit; exit;
i := -1; i := -1;
if FP <> 0 then begin if FP <> 0 then begin
@ -6304,6 +6368,8 @@ var
FContext.ThreadContext := ccUseGlobal; FContext.ThreadContext := ccUseGlobal;
FTheDebugger.QueueExecuteLock; // force queue FTheDebugger.QueueExecuteLock; // force queue
try try
// This messes up the Stack context of the queue.
FTheDebugger.FInstructionQueue.InvalidateThredAndFrame;
if (not ExecuteCommand('frame %d', [i], R, [cfNoStackContext])) or (R.State = dsError) if (not ExecuteCommand('frame %d', [i], R, [cfNoStackContext])) or (R.State = dsError)
then i := -3; // error to user then i := -3; // error to user
if (i < 0) or (not ExecuteCommand('break', [i], R, [cfNoStackContext])) or (R.State = dsError) if (i < 0) or (not ExecuteCommand('break', [i], R, [cfNoStackContext])) or (R.State = dsError)
@ -6344,75 +6410,117 @@ var
end; end;
end; end;
function GetCurrentFp: TDBGPtr;
begin
FContext.ThreadContext := ccUseLocal;
FContext.StackContext := ccUseLocal;
FContext.StackFrame := 0;
FContext.ThreadId := CurThreadId;
Result := GetPtrValue('$fp', []);
FContext.ThreadContext := ccNotRequired;
FContext.StackContext := ccNotRequired;
end;
function DoExecCommand(AnExecCmd: TGDBMIExecCommandType; AnExecArg: String): Boolean;
var
UseMI: Boolean;
AFlags: TGDBMICommandFlags;
s: String;
begin
Result := False;
if AnExecCmd in [ectStepOut, ectReturn {, ectRunTo}] then begin
FContext.ThreadContext := ccUseLocal;
FContext.StackContext := ccUseLocal;
FContext.StackFrame := 0;
FContext.ThreadId := CurThreadId;
end
else begin
FContext.ThreadContext := ccNotRequired;
FContext.StackContext := ccNotRequired;
end;
UseMI := not FTheDebugger.FCommandNoneMiState[AnExecCmd];
if UseMI then
s := GDBMIExecCommandMap[AnExecCmd] + AnExecArg
else
s := GDBMIExecCommandMapNoneMI[AnExecCmd] + AnExecArg;
AFlags := [];
if FTheDebugger.FAsyncModeEnabled and FTheDebugger.FCommandAsyncState[AnExecCmd] then
AFlags := [cfTryAsync];
if (UseMI) and (cfTryAsync in AFlags) and (DebuggerProperties.UseNoneMiRunCommands = gdnmFallback)
then begin
if not ExecuteCommand(s + ' &', FResult, []) then // Try MI in async
exit;
if (FResult.State = dsError) then begin
// Retry none MI
FTheDebugger.FCommandNoneMiState[AnExecCmd] := True;
s := GDBMIExecCommandMapNoneMI[AnExecCmd] + AnExecArg;
if not ExecuteCommand(s, FResult, AFlags) then
exit;
end;
end
else begin
if not ExecuteCommand(s, FResult, AFlags) then
exit;
end;
if (cfTryAsync in AFlags) and (FResult.State <> dsError) then begin
if (rfAsyncFailed in FResult.Flags) then
FTheDebugger.FCommandAsyncState[AnExecCmd] := False
else
FTheDebugger.FCurrentCmdIsAsync := True;
end;
Result := True;
end;
var var
StoppedParams, RunWarnings: String; StoppedParams, RunWarnings: String;
ContinueExecution, ContinueStep, UseMI: Boolean; ContinueExecution, ContinueStep: Boolean;
NextExecCmdObj: TGDBMIDebuggerCommandExecute; NextExecCmdObj: TGDBMIDebuggerCommandExecute;
R: TGDBMIExecResult; R: TGDBMIExecResult;
s: String;
AFlags: TGDBMICommandFlags;
begin begin
Result := True; Result := True;
FCanKillNow := False; FCanKillNow := False;
FDidKillNow := False; FDidKillNow := False;
FNextExecQueued := False; FNextExecQueued := False;
FP := 0; FP := 0;
CurThreadId := FTheDebugger.FCurrentThreadId;
if not FTheDebugger.FCurrentThreadIdValid then CurThreadId := 1; // TODO, but we need something
ContinueStep := False; // A step command was interupted, and is continued on breakpoint ContinueStep := False; // A step command was interupted, and is continued on breakpoint
FStepBreakPoint := -1; FStepBreakPoint := -1;
RunMode := rmNormal;
if (FExecType in [ectStepOver, ectStepInto, ectStepOut]) and
(FTheDebugger.FStoppedReason = srRaiseExcept)
then begin
RunMode := rmStepToFinally;
FCurrentExecCmd := ectContinue;
FTheDebugger.FPopExceptStack.EnableOrSetByAddr(Self, True);
FTheDebugger.FCatchesBreak.EnableOrSetByAddr(Self, True);
end;
if (FExecType in [ectRunTo, ectStepOver{, ectStepInto}, ectStepOut, ectStepOverInstruction {, ectStepIntoInstruction}]) then
FTheDebugger.FReRaiseBreak.EnableOrSetByAddr(Self, True)
else
FTheDebugger.FReRaiseBreak.Disable(Self);
try try
repeat repeat
FTheDebugger.CancelBeforeRun; // TODO: see comment on top of TGDBMIDebugger.QueueCommand FTheDebugger.CancelBeforeRun; // TODO: see comment on top of TGDBMIDebugger.QueueCommand
FTheDebugger.QueueExecuteLock; // prevent other commands from executing FTheDebugger.QueueExecuteLock; // prevent other commands from executing
try try
if (not ContinueStep) and if (not ContinueStep) and (not (RunMode in [rmStepToFinally])) and
(FExecType in [ectStepOver, ectStepInto, ectStepOut, ectStepOverInstruction, ectStepIntoInstruction]) (FExecType in [ectStepOver, ectStepInto, ectStepOut, ectStepOverInstruction, ectStepIntoInstruction])
then begin then
FContext.ThreadContext := ccUseGlobal; FP := GetCurrentFp;
FContext.StackContext := ccUseLocal;
FContext.StackFrame := 0;
FP := GetPtrValue('$fp', []);
FContext.ThreadContext := ccNotRequired;
FContext.StackContext := ccNotRequired;
end;
FTheDebugger.FCurrentStackFrameValid := False; FTheDebugger.FCurrentStackFrameValid := False;
FTheDebugger.FCurrentThreadIdValid := False; FTheDebugger.FCurrentThreadIdValid := False;
FTheDebugger.FCurrentCmdIsAsync := False; FTheDebugger.FCurrentCmdIsAsync := False;
UseMI := not FTheDebugger.FCommandNoneMiState[FCurrentExecCmd]; if not DoExecCommand(FCurrentExecCmd, FCurrentExecArg) then
if UseMI then exit;
s := GDBMIExecCommandMap[FCurrentExecCmd] + FCurrentExecArg
else
s := GDBMIExecCommandMapNoneMI[FCurrentExecCmd] + FCurrentExecArg;
AFlags := [];
if FTheDebugger.FAsyncModeEnabled and FTheDebugger.FCommandAsyncState[FCurrentExecCmd] then
AFlags := [cfTryAsync];
if (UseMI) and (cfTryAsync in AFlags) and (DebuggerProperties.UseNoneMiRunCommands = gdnmFallback)
then begin
if not ExecuteCommand(s + ' &', FResult, []) then // Try MI in asynic
exit;
if (FResult.State = dsError) then begin
// Retry none MI
FTheDebugger.FCommandNoneMiState[FCurrentExecCmd] := True;
s := GDBMIExecCommandMapNoneMI[FCurrentExecCmd] + FCurrentExecArg;
if not ExecuteCommand(s, FResult, AFlags) then
exit;
end;
end
else begin
if not ExecuteCommand(s, FResult, AFlags) then
exit;
end;
if (cfTryAsync in AFlags) and (FResult.State <> dsError) then begin
if (rfAsyncFailed in FResult.Flags) then
FTheDebugger.FCommandAsyncState[FCurrentExecCmd] := False
else
FTheDebugger.FCurrentCmdIsAsync := True;
end;
if CheckResultForError(FResult) if CheckResultForError(FResult)
then exit; then exit;
@ -6446,6 +6554,7 @@ begin
ContinueStep := False; ContinueStep := False;
if StoppedParams <> '' if StoppedParams <> ''
then ContinueExecution := ProcessStopped(StoppedParams, FTheDebugger.PauseWaitState = pwsInternal); then ContinueExecution := ProcessStopped(StoppedParams, FTheDebugger.PauseWaitState = pwsInternal);
if ContinueExecution if ContinueExecution
then begin then begin
ContinueStep := DoContinueStepping; // will set dsPause, if step has finished ContinueStep := DoContinueStepping; // will set dsPause, if step has finished
@ -6470,6 +6579,8 @@ begin
if FStepBreakPoint > 0 if FStepBreakPoint > 0
then ExecuteCommand('-break-delete %d', [FStepBreakPoint], [cfNoThreadContext]); then ExecuteCommand('-break-delete %d', [FStepBreakPoint], [cfNoThreadContext]);
FStepBreakPoint := -1; FStepBreakPoint := -1;
FTheDebugger.FPopExceptStack.Disable(Self);
FTheDebugger.FCatchesBreak.Disable(Self);
end; end;
if (not ContinueExecution) and (DebuggerState = dsRun) and if (not ContinueExecution) and (DebuggerState = dsRun) and
@ -7203,6 +7314,9 @@ begin
FBreakErrorBreak := TGDBMIInternalBreakPoint.Create('FPC_BREAK_ERROR'); FBreakErrorBreak := TGDBMIInternalBreakPoint.Create('FPC_BREAK_ERROR');
FRunErrorBreak := TGDBMIInternalBreakPoint.Create('FPC_RUNERROR'); FRunErrorBreak := TGDBMIInternalBreakPoint.Create('FPC_RUNERROR');
FExceptionBreak := TGDBMIInternalBreakPoint.Create('FPC_RAISEEXCEPTION'); FExceptionBreak := TGDBMIInternalBreakPoint.Create('FPC_RAISEEXCEPTION');
FPopExceptStack := TGDBMIInternalBreakPoint.Create('FPC_POPADDRSTACK');
FCatchesBreak := TGDBMIInternalBreakPoint.Create('FPC_CATCHES');
FReRaiseBreak := TGDBMIInternalBreakPoint.Create('FPC_RERAISE');
{$IFdef WITH_GDB_FORCE_EXCEPTBREAK} {$IFdef WITH_GDB_FORCE_EXCEPTBREAK}
FBreakErrorBreak.UseForceFlag := True; FBreakErrorBreak.UseForceFlag := True;
FRunErrorBreak.UseForceFlag := True; FRunErrorBreak.UseForceFlag := True;
@ -7315,6 +7429,9 @@ begin
FreeAndNil(FBreakErrorBreak); FreeAndNil(FBreakErrorBreak);
FreeAndNil(FRunErrorBreak); FreeAndNil(FRunErrorBreak);
FreeAndNil(FExceptionBreak); FreeAndNil(FExceptionBreak);
FreeAndNil(FPopExceptStack);
FreeAndNil(FCatchesBreak);
FreeAndNil(FReRaiseBreak);
end; end;
procedure TGDBMIDebugger.Done; procedure TGDBMIDebugger.Done;
@ -7419,6 +7536,9 @@ begin
if not (State in [dsRun, dsPause, dsInit, dsInternalPause]) if not (State in [dsRun, dsPause, dsInit, dsInternalPause])
then FMaxLineForUnitCache.Clear; then FMaxLineForUnitCache.Clear;
if not (State in [dsPause, dsInternalPause]) then
FStoppedReason := srNone;;
if State in [dsStop, dsError] if State in [dsStop, dsError]
then begin then begin
ClearSourceInfo; ClearSourceInfo;
@ -11341,8 +11461,9 @@ var
R: TGDBMIExecResult; R: TGDBMIExecResult;
S: String; S: String;
begin begin
Result := 0; Result := FMainAddrFound;
FMainAddrFound := 0; if Result <> 0 then
exit;
if (not ACmd.ExecuteCommand('info address ' + FName, R)) or if (not ACmd.ExecuteCommand('info address ' + FName, R)) or
(R.State = dsError) (R.State = dsError)
then exit; then exit;
@ -11373,6 +11494,7 @@ end;
constructor TGDBMIInternalBreakPoint.Create(AName: string); constructor TGDBMIInternalBreakPoint.Create(AName: string);
begin begin
FMainAddrFound := 0;
FNameBreakID := -1; FNameBreakID := -1;
FNameBreakAddr := 0; FNameBreakAddr := 0;
FAddrBreakID := -1; FAddrBreakID := -1;
@ -11383,6 +11505,7 @@ begin
FLineOffsAddr := 0; FLineOffsAddr := 0;
FUseForceFlag := False; FUseForceFlag := False;
FName := AName; FName := AName;
FEnabled := True;
end; end;
(* Using -insert-break with a function name allows GDB to adjust the address (* Using -insert-break with a function name allows GDB to adjust the address
@ -11423,6 +11546,7 @@ var
A: TDBGPtr; A: TDBGPtr;
begin begin
if ACmd.DebuggerState = dsError then Exit; if ACmd.DebuggerState = dsError then Exit;
if FAddrBreakID >= 0 then exit; // already set
A := GetInfoAddr(ACmd); A := GetInfoAddr(ACmd);
InternalSetAddr(ACmd, A); InternalSetAddr(ACmd, A);
@ -11494,11 +11618,54 @@ begin
(AnId = FCustomID) or (AnId = FLineOffsID)); (AnId = FCustomID) or (AnId = FLineOffsID));
end; end;
function TGDBMIInternalBreakPoint.Enabled: boolean; function TGDBMIInternalBreakPoint.IsBreakSet: boolean;
begin begin
Result := (FNameBreakID >= 0) or (FAddrBreakID >= 0) or (FCustomID > 0) or (FLineOffsID > 0); Result := (FNameBreakID >= 0) or (FAddrBreakID >= 0) or (FCustomID > 0) or (FLineOffsID > 0);
end; end;
procedure TGDBMIInternalBreakPoint.EnableOrSetByAddr(ACmd: TGDBMIDebuggerCommand;
SetNamedOnFail: Boolean);
begin
if IsBreakSet then
Enable(ACmd)
else
SetByAddr(ACmd, SetNamedOnFail);
end;
procedure TGDBMIInternalBreakPoint.Enable(ACmd: TGDBMIDebuggerCommand);
var
R: TGDBMIExecResult;
begin
if FEnabled then exit;
FEnabled := True;
if FNameBreakID >= 0 then
ACmd.ExecuteCommand('-break-enable %d', [FNameBreakID], R);
if FAddrBreakID >= 0 then
ACmd.ExecuteCommand('-break-enable %d', [FAddrBreakID], R);
if FCustomID >= 0 then
ACmd.ExecuteCommand('-break-enable %d', [FCustomID], R);
if FLineOffsID >= 0 then
ACmd.ExecuteCommand('-break-enable %d', [FLineOffsID], R);
end;
procedure TGDBMIInternalBreakPoint.Disable(ACmd: TGDBMIDebuggerCommand);
var
R: TGDBMIExecResult;
begin
if not FEnabled then exit;
FEnabled := False;
if FNameBreakID >= 0 then
ACmd.ExecuteCommand('-break-disable %d', [FNameBreakID], R);
if FAddrBreakID >= 0 then
ACmd.ExecuteCommand('-break-disable %d', [FAddrBreakID], R);
if FCustomID >= 0 then
ACmd.ExecuteCommand('-break-disable %d', [FCustomID], R);
if FLineOffsID >= 0 then
ACmd.ExecuteCommand('-break-disable %d', [FLineOffsID], R);
end;
{ TGDBMIDebuggerSimpleCommand } { TGDBMIDebuggerSimpleCommand }
constructor TGDBMIDebuggerSimpleCommand.Create(AOwner: TGDBMIDebugger; constructor TGDBMIDebuggerSimpleCommand.Create(AOwner: TGDBMIDebugger;