mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-12 02:18:44 +02:00
DBG: fixed problem, when removing breakpoint at the wrong moment
git-svn-id: trunk@34973 -
This commit is contained in:
parent
bb50b6ec9c
commit
24b800d7f0
@ -530,7 +530,7 @@ begin
|
||||
end else begin
|
||||
if Ctrl
|
||||
then b.Enabled := not b.Enabled
|
||||
else b.Free;
|
||||
else b.ReleaseReference;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -501,7 +501,7 @@ begin
|
||||
if DebugBoss.ShowBreakPointProperties(NewBreakpoint) = mrOk then
|
||||
UpdateAll
|
||||
else
|
||||
NewBreakpoint.Free;
|
||||
ReleaseRefAndNil(NewBreakpoint);
|
||||
end;
|
||||
|
||||
procedure TBreakPointsDlg.actAddWatchPointExecute(Sender: TObject);
|
||||
@ -512,7 +512,7 @@ begin
|
||||
if DebugBoss.ShowBreakPointProperties(NewBreakpoint) = mrOk then
|
||||
UpdateAll
|
||||
else
|
||||
NewBreakpoint.Free;
|
||||
ReleaseRefAndNil(NewBreakpoint);
|
||||
end;
|
||||
|
||||
procedure TBreakPointsDlg.actAddAddressBPExecute(Sender: TObject);
|
||||
@ -523,7 +523,7 @@ begin
|
||||
if DebugBoss.ShowBreakPointProperties(NewBreakpoint) = mrOk then
|
||||
UpdateAll
|
||||
else
|
||||
NewBreakpoint.Free;
|
||||
ReleaseRefAndNil(NewBreakpoint);
|
||||
end;
|
||||
|
||||
procedure TBreakPointsDlg.lvBreakPointsClick(Sender: TObject);
|
||||
@ -630,7 +630,7 @@ begin
|
||||
Item := lvBreakPoints.Items[n];
|
||||
CurBreakPoint:=TIDEBreakPoint(Item.Data);
|
||||
if CompareFilenames(CurBreakPoint.Source,Filename)=0
|
||||
then CurBreakPoint.Free;
|
||||
then ReleaseRefAndNil(CurBreakPoint);
|
||||
end;
|
||||
finally
|
||||
lvBreakPointsSelectItem(nil, nil, False);
|
||||
@ -700,7 +700,7 @@ begin
|
||||
lvBreakPoints.BeginUpdate;
|
||||
try
|
||||
for n := lvBreakPoints.Items.Count - 1 downto 0 do
|
||||
TIDEBreakPoint(lvBreakPoints.Items[n].Data).Free;
|
||||
TIDEBreakPoint(lvBreakPoints.Items[n].Data).ReleaseReference;
|
||||
finally
|
||||
lvBreakPoints.EndUpdate;
|
||||
end;
|
||||
@ -955,7 +955,7 @@ begin
|
||||
|
||||
if lvBreakPoints.SelCount = 1
|
||||
then begin
|
||||
TObject(Item.Data).Free;
|
||||
TBaseBreakPoint(Item.Data).ReleaseReference;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
@ -970,7 +970,7 @@ begin
|
||||
lvBreakPoints.BeginUpdate;
|
||||
try
|
||||
for n := 0 to List.Count - 1 do
|
||||
TObject(List[n]).Free;
|
||||
TBaseBreakPoint(List[n]).ReleaseReference;
|
||||
finally
|
||||
lvBreakPoints.EndUpdate;
|
||||
end;
|
||||
|
@ -242,6 +242,21 @@ type
|
||||
procedure Notify(Ptr: Pointer; Action: TListNotification); override;
|
||||
end;
|
||||
|
||||
{ TRefCountedColectionItem }
|
||||
|
||||
TRefCountedColectionItem = class(TDelayedUdateItem)
|
||||
public
|
||||
constructor Create(ACollection: TCollection); override;
|
||||
destructor Destroy; override;
|
||||
procedure AddReference;
|
||||
procedure ReleaseReference;
|
||||
private
|
||||
FRefCount: Integer;
|
||||
protected
|
||||
procedure DoFree; virtual;
|
||||
property RefCount: Integer read FRefCount;
|
||||
end;
|
||||
|
||||
procedure ReleaseRefAndNil(var ARefCountedObject);
|
||||
|
||||
type
|
||||
@ -554,7 +569,7 @@ type
|
||||
|
||||
{ TBaseBreakPoint }
|
||||
|
||||
TBaseBreakPoint = class(TDelayedUdateItem)
|
||||
TBaseBreakPoint = class(TRefCountedColectionItem)
|
||||
private
|
||||
FAddress: TDBGPtr;
|
||||
FWatchData: String;
|
||||
@ -745,6 +760,8 @@ type
|
||||
protected
|
||||
public
|
||||
constructor Create(const ABreakPointClass: TBaseBreakPointClass);
|
||||
destructor Destroy; override;
|
||||
procedure Clear; reintroduce;
|
||||
function Add(const ASource: String; const ALine: Integer): TBaseBreakPoint; overload;
|
||||
function Add(const AAddress: TDBGPtr): TBaseBreakPoint; overload;
|
||||
function Add(const AData: String; const AScope: TDBGWatchPointScope;
|
||||
@ -3053,9 +3070,20 @@ end;
|
||||
|
||||
procedure ReleaseRefAndNil(var ARefCountedObject);
|
||||
begin
|
||||
Assert((Pointer(ARefCountedObject) = nil) or (TObject(ARefCountedObject) is TRefCountedObject), 'ReleaseRefAndNil requires TRefCountedObject');
|
||||
if Pointer(ARefCountedObject) <> nil
|
||||
then TRefCountedObject(ARefCountedObject).ReleaseReference;
|
||||
Assert( (Pointer(ARefCountedObject) = nil) or
|
||||
(TObject(ARefCountedObject) is TRefCountedObject) or
|
||||
(TObject(ARefCountedObject) is TRefCountedColectionItem),
|
||||
'ReleaseRefAndNil requires TRefCountedObject');
|
||||
|
||||
if Pointer(ARefCountedObject) = nil then
|
||||
exit;
|
||||
|
||||
if (TObject(ARefCountedObject) is TRefCountedObject) then
|
||||
TRefCountedObject(ARefCountedObject).ReleaseReference
|
||||
else
|
||||
if (TObject(ARefCountedObject) is TRefCountedColectionItem) then
|
||||
TRefCountedColectionItem(ARefCountedObject).ReleaseReference;
|
||||
|
||||
Pointer(ARefCountedObject) := nil;
|
||||
end;
|
||||
|
||||
@ -3535,17 +3563,6 @@ begin
|
||||
inherited Items[Index] := AValue;
|
||||
end;
|
||||
|
||||
{ TRefCntObjList }
|
||||
|
||||
procedure TRefCntObjList.Notify(Ptr: Pointer; Action: TListNotification);
|
||||
begin
|
||||
case Action of
|
||||
lnAdded: TRefCountedObject(Ptr).AddReference;
|
||||
lnExtracted,
|
||||
lnDeleted: TRefCountedObject(Ptr).ReleaseReference;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TDebuggerDataSnapShot }
|
||||
|
||||
destructor TDebuggerDataSnapShot.Destroy;
|
||||
@ -5931,6 +5948,48 @@ begin
|
||||
if FRefCount = 0 then DoFree;
|
||||
end;
|
||||
|
||||
{ TRefCntObjList }
|
||||
|
||||
procedure TRefCntObjList.Notify(Ptr: Pointer; Action: TListNotification);
|
||||
begin
|
||||
case Action of
|
||||
lnAdded: TRefCountedObject(Ptr).AddReference;
|
||||
lnExtracted,
|
||||
lnDeleted: TRefCountedObject(Ptr).ReleaseReference;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TRefCountedColectionItem }
|
||||
|
||||
constructor TRefCountedColectionItem.Create(ACollection: TCollection);
|
||||
begin
|
||||
FRefCount := 0;
|
||||
inherited Create(ACollection);
|
||||
end;
|
||||
|
||||
destructor TRefCountedColectionItem.Destroy;
|
||||
begin
|
||||
Assert(FRefcount = 0, 'Destroying referenced object');
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TRefCountedColectionItem.AddReference;
|
||||
begin
|
||||
Inc(FRefcount);
|
||||
end;
|
||||
|
||||
procedure TRefCountedColectionItem.ReleaseReference;
|
||||
begin
|
||||
Assert(FRefCount > 0, 'TRefCountedObject.ReleaseReference RefCount > 0');
|
||||
Dec(FRefCount);
|
||||
if FRefCount = 0 then DoFree;
|
||||
end;
|
||||
|
||||
procedure TRefCountedColectionItem.DoFree;
|
||||
begin
|
||||
Self.Free;
|
||||
end;
|
||||
|
||||
(******************************************************************************)
|
||||
(******************************************************************************)
|
||||
(** **)
|
||||
@ -6624,6 +6683,7 @@ begin
|
||||
FInitialEnabled := False;
|
||||
FKind := bpkSource;
|
||||
inherited Create(ACollection);
|
||||
AddReference;
|
||||
end;
|
||||
|
||||
procedure TBaseBreakPoint.DoBreakHitCountChange;
|
||||
@ -6932,7 +6992,7 @@ begin
|
||||
if FMaster <> nil
|
||||
then begin
|
||||
FMaster.Slave := nil;
|
||||
FreeAndNil(FMaster);
|
||||
ReleaseRefAndNil(FMaster);
|
||||
end;
|
||||
|
||||
if (TIDEBreakPoints(Collection) <> nil)
|
||||
@ -7461,7 +7521,7 @@ begin
|
||||
then begin
|
||||
// create without source. it will be set in assign (but during Begin/EndUpdate)
|
||||
BP := FMaster.Add('', 0);
|
||||
BP.Assign(ABreakPoint);
|
||||
BP.Assign(ABreakPoint); // will set ABreakPoint.FMaster := BP;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -7525,7 +7585,7 @@ begin
|
||||
end;
|
||||
|
||||
BreakPoint.Assign(LoadBreakPoint);
|
||||
FreeAndNil(LoadBreakPoint)
|
||||
ReleaseRefAndNil(LoadBreakPoint)
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -7672,6 +7732,17 @@ begin
|
||||
inherited Create(ABreakPointClass);
|
||||
end;
|
||||
|
||||
destructor TBaseBreakPoints.Destroy;
|
||||
begin
|
||||
Clear;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TBaseBreakPoints.Clear;
|
||||
begin
|
||||
while Count > 0 do TBaseBreakPoint(GetItem(0)).ReleaseReference;
|
||||
end;
|
||||
|
||||
function TBaseBreakPoints.Find(const ASource: String; const ALine: Integer): TBaseBreakPoint;
|
||||
begin
|
||||
Result := Find(ASource, ALine, nil);
|
||||
|
@ -4505,6 +4505,7 @@ function TGDBMIDebuggerCommandExecute.ProcessStopped(const AParams: String;
|
||||
BreakPoint: TGDBMIBreakPoint;
|
||||
CanContinue: Boolean;
|
||||
Location: TDBGLocationRec;
|
||||
BrkSlave: TBaseBreakPoint;
|
||||
begin
|
||||
BreakPoint := nil;
|
||||
if ABreakId >= 0 then
|
||||
@ -4516,48 +4517,60 @@ function TGDBMIDebuggerCommandExecute.ProcessStopped(const AParams: String;
|
||||
|
||||
if BreakPoint <> nil
|
||||
then begin
|
||||
CanContinue := False;
|
||||
FTheDebugger.QueueExecuteLock;
|
||||
try
|
||||
Location := FrameToLocation(List.Values['frame']);
|
||||
FTheDebugger.FCurrentLocation := Location;
|
||||
finally
|
||||
FTheDebugger.QueueExecuteUnlock;
|
||||
end;
|
||||
FTheDebugger.DoDbgBreakpointEvent(BreakPoint, Location, AReason, AOldVal, ANewVal);
|
||||
// Important: The Queue must be unlocked
|
||||
// BreakPoint.Hit may evaluate stack and expressions
|
||||
// SetDebuggerState may evaluate data for Snapshot
|
||||
BreakPoint.Hit(CanContinue);
|
||||
if CanContinue
|
||||
then begin
|
||||
// Important trigger State => as snapshot is taken in TDebugManager.DebuggerChangeState
|
||||
SetDebuggerState(dsInternalPause);
|
||||
Result := True;
|
||||
end
|
||||
else begin
|
||||
SetDebuggerState(dsPause);
|
||||
ProcessFrame(Location);
|
||||
// inform the user, why we stopped
|
||||
// TODO: Add a dedicated callback
|
||||
case AReason of
|
||||
gbrWatchTrigger: FTheDebugger.OnFeedback
|
||||
(self, Format('The Watchpoint for "%1:s" was triggered.%0:s%0:sOld value: %2:s%0:sNew value: %3:s',
|
||||
[LineEnding, BreakPoint.WatchData, AOldVal, ANewVal]),
|
||||
'', ftInformation, [frOk]);
|
||||
gbrWatchScope: FTheDebugger.OnFeedback
|
||||
(self, Format('The Watchpoint for "%s" went out of scope', [BreakPoint.WatchData]),
|
||||
'', ftInformation, [frOk]);
|
||||
(* - Breakpoint may not be destroyed, while in use
|
||||
- And it may not be destroyed, before state is set (otherwhise an InterupTarget is triggered)
|
||||
*)
|
||||
BreakPoint.AddReference;
|
||||
BrkSlave := BreakPoint.Slave;
|
||||
if BrkSlave <> nil then BrkSlave.AddReference;
|
||||
|
||||
CanContinue := False;
|
||||
FTheDebugger.QueueExecuteLock;
|
||||
try
|
||||
Location := FrameToLocation(List.Values['frame']);
|
||||
FTheDebugger.FCurrentLocation := Location;
|
||||
finally
|
||||
FTheDebugger.QueueExecuteUnlock;
|
||||
end;
|
||||
FTheDebugger.DoDbgBreakpointEvent(BreakPoint, Location, AReason, AOldVal, ANewVal);
|
||||
// Important: The Queue must be unlocked
|
||||
// BreakPoint.Hit may evaluate stack and expressions
|
||||
// SetDebuggerState may evaluate data for Snapshot
|
||||
BreakPoint.Hit(CanContinue);
|
||||
if CanContinue
|
||||
then begin
|
||||
// Important trigger State => as snapshot is taken in TDebugManager.DebuggerChangeState
|
||||
SetDebuggerState(dsInternalPause);
|
||||
Result := True;
|
||||
end
|
||||
else begin
|
||||
SetDebuggerState(dsPause);
|
||||
ProcessFrame(Location);
|
||||
// inform the user, why we stopped
|
||||
// TODO: Add a dedicated callback
|
||||
case AReason of
|
||||
gbrWatchTrigger: FTheDebugger.OnFeedback
|
||||
(self, Format('The Watchpoint for "%1:s" was triggered.%0:s%0:sOld value: %2:s%0:sNew value: %3:s',
|
||||
[LineEnding, BreakPoint.WatchData, AOldVal, ANewVal]),
|
||||
'', ftInformation, [frOk]);
|
||||
gbrWatchScope: FTheDebugger.OnFeedback
|
||||
(self, Format('The Watchpoint for "%s" went out of scope', [BreakPoint.WatchData]),
|
||||
'', ftInformation, [frOk]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
if AReason = gbrWatchScope
|
||||
then begin
|
||||
BreakPoint.ReleaseBreakPoint; // gdb should have released already => ignore error
|
||||
BreakPoint.Enabled := False;
|
||||
BreakPoint.FBreakID := 0; // removed by debugger, ID no longer exists
|
||||
end;
|
||||
if AReason = gbrWatchScope
|
||||
then begin
|
||||
BreakPoint.ReleaseBreakPoint; // gdb should have released already => ignore error
|
||||
BreakPoint.Enabled := False;
|
||||
BreakPoint.FBreakID := 0; // removed by debugger, ID no longer exists
|
||||
end;
|
||||
|
||||
finally
|
||||
if BrkSlave <> nil then BrkSlave.ReleaseReference;
|
||||
BreakPoint.ReleaseReference;
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
|
@ -58,7 +58,7 @@ function TTestBreakPoint.DoGetFeedBack(Sender: TObject; const AText, AInfo: St
|
||||
AType: TDBGFeedbackType; AButtons: TDBGFeedbackResults): TDBGFeedbackResult;
|
||||
begin
|
||||
Result := frOk;
|
||||
FreeAndNil(FBrkErr);
|
||||
ReleaseRefAndNil(FBrkErr);
|
||||
end;
|
||||
|
||||
function TTestBreakPoint.GdbClass: TGDBMIDebuggerClass;
|
||||
|
@ -438,7 +438,7 @@ begin
|
||||
if Watch = nil then Exit;
|
||||
NewBreakpoint := BreakPoints.Add(Watch.Expression, wpsGlobal, wpkWrite);
|
||||
if DebugBoss.ShowBreakPointProperties(NewBreakpoint) <> mrOk then
|
||||
NewBreakpoint.Free;
|
||||
ReleaseRefAndNil(NewBreakpoint);
|
||||
end;
|
||||
|
||||
procedure TWatchesDlg.popAddClick(Sender: TObject);
|
||||
|
@ -387,7 +387,7 @@ end;
|
||||
|
||||
procedure TManagedBreakPoint.OnDeleteMenuItemClick(Sender: TObject);
|
||||
begin
|
||||
Free;
|
||||
ReleaseReference;
|
||||
end;
|
||||
|
||||
procedure TManagedBreakPoint.OnViewPropertiesMenuItemClick(Sender: TObject);
|
||||
@ -720,7 +720,7 @@ var
|
||||
begin
|
||||
NewBreakpoint := BreakPoints.Add(0);
|
||||
if ShowBreakPointProperties(NewBreakpoint) <> mrOk then
|
||||
NewBreakpoint.Free;
|
||||
ReleaseRefAndNil(NewBreakpoint);
|
||||
end;
|
||||
|
||||
procedure TDebugManager.mnuAddBpSource(Sender: TObject);
|
||||
@ -734,7 +734,7 @@ begin
|
||||
else
|
||||
NewBreakpoint := BreakPoints.Add('', 0);
|
||||
if DebugBoss.ShowBreakPointProperties(NewBreakpoint) <> mrOk then
|
||||
NewBreakpoint.Free;
|
||||
ReleaseRefAndNil(NewBreakpoint);
|
||||
end;
|
||||
|
||||
procedure TDebugManager.mnuAddBpData(Sender: TObject);
|
||||
@ -745,7 +745,7 @@ begin
|
||||
if ShowBreakPointProperties(NewBreakpoint) = mrOk then
|
||||
ViewDebugDialog(ddtBreakpoints, False)
|
||||
else
|
||||
NewBreakpoint.Free;
|
||||
ReleaseRefAndNil(NewBreakpoint);
|
||||
end;
|
||||
|
||||
procedure TDebugManager.mnuAddBpDataAtCursor(Sender: TObject);
|
||||
@ -770,7 +770,7 @@ begin
|
||||
if ShowBreakPointProperties(NewBreakpoint) = mrOk then
|
||||
ViewDebugDialog(ddtBreakpoints, False)
|
||||
else
|
||||
NewBreakpoint.Free;
|
||||
NewBreakpoint.ReleaseReference;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
@ -2526,7 +2526,7 @@ var
|
||||
begin
|
||||
OldBreakPoint:=FBreakPoints.Find(AFilename,ALine);
|
||||
if OldBreakPoint=nil then exit(mrOk);
|
||||
OldBreakPoint.Free;
|
||||
ReleaseRefAndNil(OldBreakPoint);
|
||||
Project1.Modified:=true;
|
||||
Result := mrOK
|
||||
end;
|
||||
@ -2550,7 +2550,7 @@ begin
|
||||
DebugLn('TDebugManager.DoDeleteBreakPointAtMark B ',OldBreakPoint.ClassName,
|
||||
' ',OldBreakPoint.Source,' ',IntToStr(OldBreakPoint.Line));
|
||||
{$endif}
|
||||
OldBreakPoint.Free;
|
||||
ReleaseRefAndNil(OldBreakPoint);
|
||||
Project1.Modified:=true;
|
||||
Result := mrOK
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user