DBG: fixed problem, when removing breakpoint at the wrong moment

git-svn-id: trunk@34973 -
This commit is contained in:
martin 2012-01-27 11:48:04 +00:00
parent bb50b6ec9c
commit 24b800d7f0
7 changed files with 157 additions and 73 deletions

View File

@ -530,7 +530,7 @@ begin
end else begin
if Ctrl
then b.Enabled := not b.Enabled
else b.Free;
else b.ReleaseReference;
end;
end;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;