DBG: Watchpoints

git-svn-id: trunk@32423 -
This commit is contained in:
martin 2011-09-19 17:47:27 +00:00
parent f9df0a985f
commit 37fa512845
15 changed files with 368 additions and 111 deletions

View File

@ -138,6 +138,9 @@ inherited BreakpointsDlg: TBreakpointsDlg
object popAddAddressBP: TMenuItem
Action = actAddAddressBP
end
object popAddWatchPoint: TMenuItem
Action = actAddWatchPoint
end
end
object N1: TMenuItem
Caption = '-'
@ -178,8 +181,8 @@ inherited BreakpointsDlg: TBreakpointsDlg
end
end
object ActionList1: TActionList[3]
left = 108
top = 49
left = 96
top = 72
object actToggleCurrentEnable: TAction
Caption = 'actToggleCurrentEnable'
OnExecute = popEnabledClick
@ -238,6 +241,11 @@ inherited BreakpointsDlg: TBreakpointsDlg
Caption = 'actAddAddressBP'
OnExecute = actAddAddressBPExecute
end
object actAddWatchPoint: TAction
Category = 'Add'
Caption = 'actAddWatchPoint'
OnExecute = actAddWatchPointExecute
end
object actShow: TAction
Caption = 'actShow'
OnExecute = actShowExecute

View File

@ -53,6 +53,7 @@ type
TBreakPointsDlg = class(TDebuggerDlg)
actAddSourceBP: TAction;
actAddAddressBP: TAction;
actAddWatchPoint: TAction;
actShow: TAction;
actProperties: TAction;
actToggleCurrentEnable: TAction;
@ -67,6 +68,7 @@ type
actDisableAllInSrc: TAction;
ActionList1: TActionList;
lvBreakPoints: TListView;
popAddWatchPoint: TMenuItem;
popAddAddressBP: TMenuItem;
N0: TMenuItem;
popShow: TMenuItem;
@ -97,6 +99,7 @@ type
ToolButtonTrashAll: TToolButton;
procedure actAddAddressBPExecute(Sender: TObject);
procedure actAddSourceBPExecute(Sender: TObject);
procedure actAddWatchPointExecute(Sender: TObject);
procedure actDisableSelectedExecute(Sender: TObject);
procedure actEnableSelectedExecute(Sender: TObject);
procedure actShowExecute(Sender: TObject);
@ -307,6 +310,7 @@ begin
popAdd.Caption:= lisLazBuildAdd;
actAddSourceBP.Caption := lisSourceBreakpoint;
actAddAddressBP.Caption := lisAddressBreakpoint;
actAddWatchPoint.Caption := lisWatchPoint;
end;
procedure TBreakPointsDlg.actEnableSelectedExecute(Sender: TObject);
@ -366,6 +370,17 @@ begin
NewBreakpoint.Free;
end;
procedure TBreakPointsDlg.actAddWatchPointExecute(Sender: TObject);
var
NewBreakpoint: TIDEBreakPoint;
begin
NewBreakpoint := BreakPoints.Add('', wpsGlobal, wpkWrite);
if DebugBoss.ShowBreakPointProperties(NewBreakpoint) = mrOk then
UpdateAll
else
NewBreakpoint.Free;
end;
procedure TBreakPointsDlg.actAddAddressBPExecute(Sender: TObject);
var
NewBreakpoint: TIDEBreakPoint;
@ -640,6 +655,7 @@ begin
(ActionList1.Actions[i] as TAction).Enabled := False;
actAddSourceBP.Enabled := True;
actAddAddressBP.Enabled := True;
actAddWatchPoint.Enabled := True;
end;
procedure TBreakPointsDlg.UpdateItem(const AnItem: TListItem;

View File

@ -655,6 +655,7 @@ type
function GetDebugger: TDebugger;
procedure SetSlave(const ASlave : TBaseBreakPoint);
protected
procedure SetEnabled(const AValue: Boolean); override;
procedure DoChanged; override;
procedure DoStateChange(const AOldState: TDBGState); virtual;
procedure DoLogMessage(const AMessage: String); virtual;
@ -2590,7 +2591,7 @@ type
True: (Ptr: Pointer);
end;
TDBGFeedbackType = (ftWarning, ftError);
TDBGFeedbackType = (ftInformation, ftWarning, ftError);
TDBGFeedbackResult = (frOk, frStop);
TDBGFeedbackResults = set of TDBGFeedbackResult;
@ -6214,6 +6215,7 @@ begin
if Dest is TBaseBreakPoint
then begin
DestBreakPoint.SetKind(FKind);
DestBreakPoint.SetWatch(FWatchData, FWatchScope, FWatchKind);
DestBreakPoint.SetAddress(FAddress);
AssignLocationTo(DestBreakPoint);
DestBreakPoint.SetBreakHitCount(FBreakHitCount);
@ -6590,6 +6592,7 @@ begin
then FMaster.DoLogMessage(FLogMessage);
if bpaLogCallStack in Actions
then FMaster.DoLogCallStack(FLogCallStackLimit);
// SnapShot is taken in TDebugManager.DebuggerChangeState
if bpaEnableGroup in Actions
then EnableGroups;
if bpaDisableGroup in Actions
@ -6648,15 +6651,24 @@ begin
FLoading:=true;
try
Kind:=TDBGBreakPointKind(GetEnumValueDef(TypeInfo(TDBGBreakPointKind),XMLConfig.GetValue(Path+'Kind/Value',''),0));
Address:=XMLConfig.GetValue(Path+'Address/Value',0);
GroupName:=XMLConfig.GetValue(Path+'Group/Name','');
Group:=OnGetGroup(GroupName);
Expression:=XMLConfig.GetValue(Path+'Expression/Value','');
AutoContinueTime:=XMLConfig.GetValue(Path+'AutoContinueTime/Value',0);
BreakHitCount := XMLConfig.GetValue(Path+'BreakHitCount/Value',0);
Address:=XMLConfig.GetValue(Path+'Address/Value',0);
FWatchData := XMLConfig.GetValue(Path+'WatchData/Value', '');
try ReadStr(XMLConfig.GetValue(Path+'WatchScope/Value', 'wpsGlobal'), FWatchScope);
except FWatchScope := wpsGlobal; end;
try ReadStr(XMLConfig.GetValue(Path+'WatchKind/Value', 'wpkWrite'), FWatchKind);
except FWatchKind:= wpkWrite; end;
Filename:=XMLConfig.GetValue(Path+'Source/Value','');
if Assigned(OnLoadFilename) then OnLoadFilename(Filename);
FSource:=Filename;
InitialEnabled:=XMLConfig.GetValue(Path+'InitialEnabled/Value',true);
Enabled:=FInitialEnabled;
FLine:=XMLConfig.GetValue(Path+'Line/Value',-1);
@ -6712,11 +6724,18 @@ procedure TIDEBreakPoint.SaveToXMLConfig(const AConfig: TXMLConfig;
end;
var
Filename: String;
s, Filename: String;
CurAction: TIDEBreakPointAction;
begin
AConfig.SetDeleteValue(APath+'Kind/Value',GetEnumName(TypeInfo(TDBGBreakPointKind), Ord(Kind)), '');
AConfig.SetDeleteValue(APath+'Address/Value',Address,0);
AConfig.SetDeleteValue(APath+'WatchData/Value', FWatchData, '');
WriteStr(s, FWatchScope);
AConfig.SetDeleteValue(APath+'WatchScope/Value', s, '');
WriteStr(s, FWatchKind);
AConfig.SetDeleteValue(APath+'WatchKind/Value', s, '');
if Group <> nil
then AConfig.SetDeleteValue(APath+'Group/Name',Group.Name,'');
@ -6935,6 +6954,14 @@ begin
FSlave := ASlave;
end;
procedure TDBGBreakPoint.SetEnabled(const AValue: Boolean);
begin
if Enabled = AValue then exit;
inherited SetEnabled(AValue);
// feedback to IDEBreakPoint
if FSlave <> nil then FSlave.Enabled := AValue;
end;
{ =========================================================================== }
{ TIDEBreakPoints }
{ =========================================================================== }
@ -7116,6 +7143,12 @@ begin
if BreakPoint = nil then
BreakPoint := Add(LoadBreakPoint.Address);
end;
bpkData:
begin
BreakPoint := Find(LoadBreakPoint.WatchData, LoadBreakPoint.WatchScope, LoadBreakPoint.WatchKind, LoadBreakPoint);
if BreakPoint = nil then
BreakPoint := Add(LoadBreakPoint.WatchData, LoadBreakPoint.WatchScope, LoadBreakPoint.WatchKind);
end;
end;
BreakPoint.Assign(LoadBreakPoint);

View File

@ -65,6 +65,9 @@ function TDbgFeedbackDlg.Execute(const AText, AInfo: String; AType: TDBGFeedback
AButtons: TDBGFeedbackResults): TDBGFeedbackResult;
begin
case AType of
ftInformation: begin
Caption := lisDebuggerFeedbackInformation;
end;
ftWarning: begin
Caption := lisDebuggerFeedbackWarning;
end;

View File

@ -179,6 +179,8 @@ type
ectReturn // -exec-return (step out immediately, skip execution)
);
TGDBMIBreakpointReason = (gbrBreak, gbrWatchTrigger, gbrWatchScope);
TGDBMIDebuggerCommand = class(TRefCountedObject)
private
FDefaultTimeOut: Integer;
@ -421,7 +423,9 @@ type
procedure DoRelease; override; // Destroy self (or schedule)
procedure DoNotifyAsync(Line: String);
procedure DoDbgBreakpointEvent(ABreakpoint: TDBGBreakPoint; Location: TDBGLocationRec);
procedure DoDbgBreakpointEvent(ABreakpoint: TDBGBreakPoint; Location: TDBGLocationRec;
AReason: TGDBMIBreakpointReason;
AOldVal: String = ''; ANewVal: String = '');
procedure AddThreadGroup(const S: String);
procedure RemoveThreadGroup(const S: String);
function ParseLibraryLoaded(const S: String): String;
@ -471,10 +475,17 @@ resourcestring
gdbmiErrorStateInfoFailedWrite = '%0:sCould not send a command to GDB.%0:s';
gdbmiErrorStateInfoFailedRead = '%0:sCould not read output from GDB.%0:s';
gdbmiErrorStateInfoGDBGone = '%0:sThe GDB process is no longer running.%0:s';
gdbmiWarningUnknowBreakPoint = 'The debugger reached an unexpected %1:s%0:s%0:s'
+ 'Press "Ok" to continue debugging (paused).%0:s'
+ 'Press "Stop" to end the debug session.';
implementation
const
GDBMIBreakPointReasonNames: Array[TGDBMIBreakpointReason] of string =
('Breakpoint', 'Watchpoint', 'Watchpoint (scope)');
type
THackDBGType = class(TGDBType) end;
@ -4301,24 +4312,39 @@ function TGDBMIDebuggerCommandExecute.ProcessStopped(const AParams: String;
end;
end;
procedure ProcessException(AInfo: TGDBMIExceptionInfo);
procedure ProcessException;
var
ExceptionMessage: String;
CanContinue: Boolean;
Location: TDBGLocationRec;
ExceptInfo: TGDBMIExceptionInfo;
begin
if FTheDebugger.Exceptions.IgnoreAll
then begin
Result := True; //ExecuteCommand('-exec-continue')
exit;
end;
ExceptInfo := GetExceptionInfo;
// check if we should ignore this exception
if (FTheDebugger.Exceptions.Find(ExceptInfo.Name) <> nil)
then begin
Result := True; //ExecuteCommand('-exec-continue')
exit;
end;
FTheDebugger.QueueExecuteLock;
try
if (dfImplicidTypes in FTheDebugger.DebuggerFlags)
then begin
if (tfFlagHasTypeException in TargetInfo^.TargetFlags) then begin
if tfExceptionIsPointer in TargetInfo^.TargetFlags
then ExceptionMessage := GetText('Exception(%s).FMessage', [AInfo.ObjAddr])
else ExceptionMessage := GetText('^Exception(%s)^.FMessage', [AInfo.ObjAddr]);
then ExceptionMessage := GetText('Exception(%s).FMessage', [ExceptInfo.ObjAddr])
else ExceptionMessage := GetText('^Exception(%s)^.FMessage', [ExceptInfo.ObjAddr]);
//ExceptionMessage := GetText('^^Exception($fp+8)^^.FMessage', []);
end else begin
// Only works if Exception class is not changed. FMessage must be first member
ExceptionMessage := GetText('^^char(^%s(%s)+1)^', [PointerTypeCast, AInfo.ObjAddr]);
ExceptionMessage := GetText('^^char(^%s(%s)+1)^', [PointerTypeCast, ExceptInfo.ObjAddr]);
end;
end
else ExceptionMessage := '### Not supported on GDB < 5.3 ###';
@ -4328,7 +4354,7 @@ function TGDBMIDebuggerCommandExecute.ProcessStopped(const AParams: String;
FTheDebugger.QueueExecuteUnlock;
end;
FTheDebugger.DoException(deInternal, AInfo.Name, Location, ExceptionMessage, CanContinue);
FTheDebugger.DoException(deInternal, ExceptInfo.Name, Location, ExceptionMessage, CanContinue);
if CanContinue
then begin
//ExecuteCommand('-exec-continue')
@ -4446,20 +4472,111 @@ function TGDBMIDebuggerCommandExecute.ProcessStopped(const AParams: String;
end;
end;
procedure ProcessBreakPoint(ABreakId: Integer; const List: TGDBMINameValueList;
AReason: TGDBMIBreakpointReason; AOldVal: String = ''; ANewVal: String = '');
var
BreakPoint: TGDBMIBreakPoint;
CanContinue: Boolean;
Location: TDBGLocationRec;
begin
BreakPoint := nil;
if ABreakId >= 0 then
BreakPoint := TGDBMIBreakPoint(FTheDebugger.FindBreakpoint(ABreakID));
if (BreakPoint <> nil) and (BreakPoint.Kind <> bpkData) and
(AReason in [gbrWatchScope, gbrWatchTrigger])
then BreakPoint := nil;
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]);
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;
exit;
end;
// The temp-at-start breakpoint is not checked. Ignore it
if (DebuggerState = dsRun) and (FTheDebugger.TargetPID <> 0) // not in startup
then begin
debugln(['********** WARNING: breakpoint hit, but nothing known about it ABreakId=', ABreakID, ' brbtno=', List.Values['bkptno'] ]);
{$IFDEF DBG_VERBOSE_BRKPOINT}
debugln(['-*- List of breakpoints Cnt=', FTheDebugger.Breakpoints.Count]);
for ABreakID := 0 to FTheDebugger.Breakpoints.Count - 1 do
debugln(['* ',Dbgs(FTheDebugger.Breakpoints[ABreakID]), ':', DbgsName(FTheDebugger.Breakpoints[ABreakID]), ' ABreakId=',TGDBMIBreakPoint(FTheDebugger.Breakpoints[ABreakID]).FBreakID, ' Source=', FTheDebugger.Breakpoints[ABreakID].Source, ' Line=', FTheDebugger.Breakpoints[ABreakID].Line ]);
debugln(['************************************************************************ ']);
debugln(['************************************************************************ ']);
debugln(['************************************************************************ ']);
{$ENDIF}
case FTheDebugger.OnFeedback
(self, Format(gdbmiWarningUnknowBreakPoint,
[LineEnding, GDBMIBreakPointReasonNames[AReason]]),
List.Text, ftWarning, [frOk, frStop]
)
of
frOk: begin
SetDebuggerState(dsPause);
ProcessFrame(List.Values['frame']); // and jump to it
end;
frStop: begin
FTheDebugger.Stop;
end;
end;
end;
end;
var
List: TGDBMINameValueList;
List, List2: TGDBMINameValueList;
Reason: String;
BreakID: Integer;
BreakPoint: TGDBMIBreakPoint;
CanContinue: Boolean;
ExceptionInfo: TGDBMIExceptionInfo;
Location: TDBGLocationRec;
begin
(* The Queue is not locked / This code can be interupted
Therefore all calls to ExecuteCommand (gdb cmd) must be wrapped in QueueExecuteLock
*)
Result := False;
List := TGDBMINameValueList.Create(AParams);
List2 := nil;
FTheDebugger.FCurrentStackFrame := 0;
FTheDebugger.FInternalStackFrame := 0;
@ -4498,13 +4615,30 @@ begin
Exit;
end;
if Reason = 'watchpoint-trigger'
then begin
List2 := TGDBMINameValueList.Create(List.Values['wpt']);
BreakID := StrToIntDef(List2.Values['number'], -1);
// Use List2.Values['exp'] ? It may contain globalized expression
List2.Init(List.Values['value']);
ProcessBreakPoint(BreakID, List, gbrWatchTrigger, List2.Values['old'], List2.Values['new']);
exit;
end;
if Reason = 'watchpoint-scope'
then begin
BreakID := StrToIntDef(List.Values['wpnum'], -1);
ProcessBreakPoint(BreakID, List, gbrWatchScope);
exit;
end;
if Reason = 'breakpoint-hit'
then begin
BreakID := StrToIntDef(List.Values['bkptno'], -1);
if BreakID = -1
then begin
ProcessBreakPoint(BreakID, List, gbrBreak);
SetDebuggerState(dsError);
// ???
Exit;
end;
@ -4522,59 +4656,12 @@ begin
if BreakID = FTheDebugger.FExceptionBreakID
then begin
ExceptionInfo := GetExceptionInfo;
// check if we should ignore this exception
if FTheDebugger.Exceptions.IgnoreAll
or (FTheDebugger.Exceptions.Find(ExceptionInfo.Name) <> nil)
then
Result := True //ExecuteCommand('-exec-continue')
else
ProcessException(ExceptionInfo); // will set dsPause / unless CanCuntinue
ProcessException; // will set dsPause / unless CanCuntinue
Exit;
end;
BreakPoint := TGDBMIBreakPoint(FTheDebugger.FindBreakpoint(BreakID));
if BreakPoint <> nil
then begin
CanContinue := False;
FTheDebugger.QueueExecuteLock;
try
Location := FrameToLocation(List.Values['frame']);
finally
FTheDebugger.QueueExecuteUnlock;
end;
FTheDebugger.FCurrentLocation := Location;
FTheDebugger.DoDbgBreakpointEvent(BreakPoint, Location);
BreakPoint.Hit(CanContinue);
if CanContinue
then begin
SetDebuggerState(dsInternalPause);
//ExecuteCommand('-exec-continue');
Result := True;
exit;
end
else begin
SetDebuggerState(dsPause);
ProcessFrame(Location);
end;
end;
// The temp-at-start breakpoint is not checked. Ignore it
if (DebuggerState = dsRun) and (FTheDebugger.TargetPID <> 0) // not in startup
then begin
debugln(['********** WARNING: breakpoint hit, but nothing known about it BreakId=', BreakID, ' brbtno=', List.Values['bkptno'] ]);
{$IFDEF DBG_VERBOSE_BRKPOINT}
debugln(['-*- List of breakpoints Cnt=', FTheDebugger.Breakpoints.Count]);
for BreakID := 0 to FTheDebugger.Breakpoints.Count - 1 do
debugln(['* ',Dbgs(FTheDebugger.Breakpoints[BreakID]), ':', DbgsName(FTheDebugger.Breakpoints[BreakID]), ' BreakId=',TGDBMIBreakPoint(FTheDebugger.Breakpoints[BreakID]).FBreakID, ' Source=', FTheDebugger.Breakpoints[BreakID].Source, ' Line=', FTheDebugger.Breakpoints[BreakID].Line ]);
debugln(['************************************************************************ ']);
debugln(['************************************************************************ ']);
debugln(['************************************************************************ ']);
{$ENDIF}
SetDebuggerState(dsPause);
ProcessFrame(List.Values['frame']); // and jump to it
end;
Exit;
ProcessBreakPoint(BreakID, List, gbrBreak);
exit;
end;
if Reason = 'function-finished'
@ -4608,6 +4695,7 @@ begin
end;
finally
List.Free;
list2.Free;
end;
end;
@ -5826,25 +5914,52 @@ begin
end;
end;
procedure TGDBMIDebugger.DoDbgBreakpointEvent(ABreakpoint: TDBGBreakPoint; Location: TDBGLocationRec);
procedure TGDBMIDebugger.DoDbgBreakpointEvent(ABreakpoint: TDBGBreakPoint;
Location: TDBGLocationRec; AReason: TGDBMIBreakpointReason;
AOldVal: String = ''; ANewVal: String = '');
var
SrcName: String;
SrcName, Msg: String;
SrcLine: Integer;
begin
case ABreakPoint.Kind of
bpkSource:
begin
SrcName := Location.SrcFullName;
if SrcName = '' then
SrcName := Location.SrcFile;
if SrcName = '' then
SrcName := ABreakpoint.Source;
DoDbgEvent(ecBreakpoint, etBreakpointHit, Format('Source Breakpoint at $%.' + IntToStr(TargetPtrSize * 2) + 'x: %s line %d', [Location.Address, SrcName, Location.SrcLine]));
end;
bpkAddress:
begin
DoDbgEvent(ecBreakpoint, etBreakpointHit, Format('Address Breakpoint at $%.' + IntToStr(TargetPtrSize * 2) + 'x', [Location.Address]));
end;
SrcName := Location.SrcFullName;
if SrcName = '' then
SrcName := Location.SrcFile;
if (SrcName = '') and (ABreakPoint <> nil) and (ABreakPoint.Kind = bpkSource) then
SrcName := ABreakpoint.Source;
SrcLine := Location.SrcLine;
if (SrcLine < 1) and (ABreakPoint <> nil) and (ABreakPoint.Kind = bpkSource) then
SrcLine := ABreakpoint.Line;
if ABreakpoint = nil then begin
Msg := Format('Unknown %s', [GDBMIBreakPointReasonNames[AReason]]);
if AReason = gbrWatchTrigger then
Msg := Msg + Format(' changed from "%s" to "%s"', [AOldVal, ANewVal]);
end
else begin
case ABreakPoint.Kind of
bpkSource: Msg := 'Source Breakpoint';
bpkAddress: Msg := 'Address Breakpoint';
bpkData:
begin
if AReason = gbrWatchScope then
Msg := Format('Watchpoint for "%s" out of scope', [ABreakpoint.WatchData])
else
Msg := Format('Watchpoint for "%s" was triggered. Old value "%s", New Value "%s"', [ABreakpoint.WatchData, AOldVal, ANewVal]);
end;
end;
end;
if SrcName <> '' then begin
DoDbgEvent(ecBreakpoint, etBreakpointHit,
Format('%s at $%.' + IntToStr(TargetPtrSize * 2) + 'x: %s line %d',
[Msg, Location.Address, SrcName, SrcLine]));
end
else begin
DoDbgEvent(ecBreakpoint, etBreakpointHit,
Format('%s at $%.' + IntToStr(TargetPtrSize * 2) + 'x',
[Msg, Location.Address]));
end;
end;
function TGDBMIDebugger.ExecuteCommand(const ACommand: String;
@ -7061,9 +7176,11 @@ begin
WatchExpr := WatchData;
if FWatchScope = wpsGlobal then begin
Result := ExecuteCommand('ptype %s', [WatchExpr], R);
Result := Result and (R.State <> dsError);
if not Result then exit;
WatchDecl := PCLenToString(ParseTypeFromGdb(R.Values).Name);
Result := ExecuteCommand('-data-evaluate-expression @%s', [WatchExpr], R);
Result := Result and (R.State <> dsError);
if not Result then exit;
WatchAddr := StripLN(GetPart('value="', '"', R.Values));
WatchExpr := WatchDecl+'(' + WatchAddr + '^)';
@ -7073,6 +7190,7 @@ begin
wpkRead: Result := ExecuteCommand('-break-watch -r %s', [WatchExpr], R);
wpkReadWrite: Result := ExecuteCommand('-break-watch -a %s', [WatchExpr], R);
end;
Result := Result and (R.State <> dsError);
GdbRes := 'wpt';
end;
end;
@ -7153,7 +7271,14 @@ end;
function TGDBMIDebuggerCommandBreakInsert.DebugText: String;
begin
Result := Format('%s: Source=%s, Line=%d, Enabled=%s', [ClassName, FSource, FLine, dbgs(FEnabled)]);
case FKind of
bpkAddress:
Result := Format('%s: Address=%x, Enabled=%s', [ClassName, FAddress, dbgs(FEnabled)]);
bpkData:
Result := Format('%s: Data=%s, Enabled=%s', [ClassName, FWatchData, dbgs(FEnabled)]);
else
Result := Format('%s: Source=%s, Line=%d, Enabled=%s', [ClassName, FSource, FLine, dbgs(FEnabled)]);
end;
end;
{ TGDBMIDebuggerCommandBreakRemove }
@ -7259,7 +7384,12 @@ end;
procedure TGDBMIBreakPoint.DoEnableChange;
begin
UpdateProperties([bufEnabled]);
if (FBreakID = 0) and Enabled and
(TGDBMIDebugger(Debugger).State in [dsPause, dsInternalPause, dsRun])
then
SetBreakPoint
else
UpdateProperties([bufEnabled]);
inherited;
end;
@ -7271,7 +7401,12 @@ begin
if TGDBMIDebugger(Debugger).ConvertPascalExpression(S)
then FParsedExpression := S
else FParsedExpression := Expression;
UpdateProperties([bufCondition]);
if (FBreakID = 0) and Enabled and
(TGDBMIDebugger(Debugger).State in [dsPause, dsInternalPause, dsRun])
then
SetBreakPoint
else
UpdateProperties([bufCondition]);
inherited;
end;
@ -7404,10 +7539,22 @@ begin
if (Sender is TGDBMIDebuggerCommandBreakInsert)
then begin
// Check Insert Result
BeginUpdate;
if TGDBMIDebuggerCommandBreakInsert(Sender).Valid
then SetValid(vsValid)
else SetValid(vsInvalid);
else begin
if (TGDBMIDebuggerCommandBreakInsert(Sender).Kind = bpkData) and
(TGDBMIDebugger(Debugger).State = dsInit)
then begin
// disable data breakpoint, if unable to set (only at startup)
SetValid(vsValid);
SetEnabled(False);
end
else SetValid(vsInvalid);
end;
FBreakID := TGDBMIDebuggerCommandBreakInsert(Sender).BreakID;
SetHitCount(TGDBMIDebuggerCommandBreakInsert(Sender).HitCnt);

View File

@ -63,13 +63,16 @@ type
TGDBMINameValueList = class(TObject)
private
FDataLen: Integer;
FText: String;
FData: PChar;
FCount: Integer;
FIndex: array of TGDBMINameValue;
FUseTrim: Boolean;
function Find(const AName : string): PGDBMINameValue;
function GetItem(const AIndex: Integer): PGDBMINameValue;
function GetText: String;
function GetValue(const AName : string): string;
function GetValuePtr(const AName: string): TPCharWithLen;
public
@ -92,6 +95,9 @@ type
property Values[const AName: string]: string read GetValue;
property ValuesPtr[const AName: string]: TPCharWithLen read GetValuePtr;
property UseTrim: Boolean read FUseTrim write FUseTrim;
property Data: PChar read FData;
property DataLen: Integer read FDataLen;
property Text: String read GetText;
end;
{$IFDEF DBG_ENABLE_TERMINAL}
@ -180,6 +186,11 @@ begin
Result := @FIndex[AIndex];
end;
function TGDBMINameValueList.GetText: String;
begin
Result := copy(FData, 1, FDataLen);
end;
function TGDBMINameValueList.GetString(const AIndex : Integer) : string;
var
len: Integer;
@ -337,6 +348,8 @@ var
begin
// clear
FCount := 0;
FData := AResultValues;
FDataLen := ALength;
if AResultValues = nil then Exit;
if ALength <= 0 then Exit;

View File

@ -57,61 +57,61 @@ inherited WatchesDlg: TWatchesDlg
object ToolButton2: TToolButton
Left = 24
Top = 2
Width = 4
Width = 5
Caption = 'ToolButton2'
Style = tbsDivider
end
object ToolButtonEnable: TToolButton
Left = 51
Left = 52
Top = 2
Action = actEnableSelected
end
object ToolButtonDisable: TToolButton
Left = 74
Left = 75
Top = 2
Action = actDisableSelected
end
object ToolButtonTrash: TToolButton
Left = 97
Left = 98
Top = 2
Action = actDeleteSelected
end
object ToolButton6: TToolButton
Left = 120
Left = 121
Top = 2
Width = 4
Width = 5
Caption = 'ToolButton6'
Style = tbsDivider
end
object ToolButtonEnableAll: TToolButton
Left = 124
Left = 126
Top = 2
Action = actEnableAll
end
object ToolButtonDisableAll: TToolButton
Left = 147
Left = 149
Top = 2
Action = actDisableAll
end
object ToolButtonTrashAll: TToolButton
Left = 170
Left = 172
Top = 2
Action = actDeleteAll
end
object ToolButton10: TToolButton
Left = 193
Left = 195
Top = 2
Width = 4
Width = 5
Caption = 'ToolButton10'
Style = tbsDivider
end
object ToolButtonAdd: TToolButton
Left = 28
Left = 29
Top = 2
Action = actAddWatch
end
object ToolButtonProperties: TToolButton
Left = 197
Left = 200
Top = 2
Action = actProperties
end
@ -146,6 +146,12 @@ inherited WatchesDlg: TWatchesDlg
object popDeleteAll: TMenuItem
Action = actDeleteAll
end
object N3: TMenuItem
Caption = '-'
end
object popAddWatchPoint: TMenuItem
Action = actAddWatchPoint
end
end
object ActionList1: TActionList[3]
left = 184
@ -203,5 +209,9 @@ inherited WatchesDlg: TWatchesDlg
)
ShortCut = 16453
end
object actAddWatchPoint: TAction
Caption = 'actAddWatchPoint'
OnExecute = actAddWatchPointExecute
end
end
end

View File

@ -60,11 +60,14 @@ type
actEnableAll: TAction;
actEnableSelected: TAction;
actAddWatch: TAction;
actAddWatchPoint: TAction;
actToggleCurrentEnable: TAction;
actPower: TAction;
ActionList1: TActionList;
actProperties: TAction;
lvWatches: TListView;
N3: TMenuItem;
popAddWatchPoint: TMenuItem;
mnuPopup: TPopupMenu;
popAdd: TMenuItem;
N1: TMenuItem; //--------------
@ -88,6 +91,7 @@ type
ToolButtonEnableAll: TToolButton;
ToolButtonDisableAll: TToolButton;
ToolButtonTrashAll: TToolButton;
procedure actAddWatchPointExecute(Sender: TObject);
procedure actDisableSelectedExecute(Sender: TObject);
procedure actEnableSelectedExecute(Sender: TObject);
procedure actPowerExecute(Sender: TObject);
@ -135,6 +139,7 @@ type
property WatchesMonitor;
property ThreadsMonitor;
property CallStackMonitor;
property BreakPoints;
property SnapshotManager;
end;
@ -200,6 +205,8 @@ begin
actProperties.Caption:= liswlProperties;
actProperties.ImageIndex := IDEImages.LoadImage(16, 'menu_environment_options');
actAddWatchPoint.Caption := lisWatchToWatchPoint;
Caption:=liswlWatchList;
lvWatches.Columns[0].Caption:=liswlExpression;
@ -287,6 +294,7 @@ begin
actProperties.Enabled := False;
actAddWatch.Enabled := False;
actPower.Enabled := False;
actAddWatchPoint.Enabled := False;
exit;
end;
@ -317,6 +325,8 @@ begin
actDisableSelected.Enabled := SelCanDisable;
actDeleteSelected.Enabled := ItemSelected;
actAddWatchPoint.Enabled := ItemSelected;
actEnableAll.Enabled := AllCanEnable;
actDisableAll.Enabled := AllCanDisable;
actDeleteAll.Enabled := lvWatches.Items.Count > 0;
@ -420,6 +430,18 @@ begin
end;
end;
procedure TWatchesDlg.actAddWatchPointExecute(Sender: TObject);
var
NewBreakpoint: TIDEBreakPoint;
Watch: TCurrentWatch;
begin
Watch := GetSelected;
if Watch = nil then Exit;
NewBreakpoint := BreakPoints.Add(Watch.Expression, wpsGlobal, wpkWrite);
if DebugBoss.ShowBreakPointProperties(NewBreakpoint) <> mrOk then
NewBreakpoint.Free;
end;
procedure TWatchesDlg.popAddClick(Sender: TObject);
begin
try

View File

@ -977,6 +977,7 @@ begin
then FCurrentBreakpoint := nil;
// Notify FSnapshots of new state (while dialogs still in updating)
// TODO: Maybe move to TIDEBreakPoint.DoHit
if (FCurrentBreakpoint <> nil) and (bpaTakeSnapshot in FCurrentBreakpoint.Actions) and
(State in [dsPause, dsInternalPause])
then begin
@ -1372,6 +1373,7 @@ begin
TheDialog.WatchesMonitor := FWatches;
TheDialog.ThreadsMonitor := FThreads;
TheDialog.CallStackMonitor := FCallStack;
TheDialog.BreakPoints := FBreakPoints;
TheDialog.SnapshotManager := FSnapshots;
end;
@ -1598,9 +1600,7 @@ begin
itmRunMenuAddBpSource.OnClick := @mnuAddBpSource;
itmRunMenuAddBpAddress.OnClick := @mnuAddBpAddress;
{$IFDEF DBG_WITH_WATCHPOINT}
itmRunMenuAddBpWatchPoint.OnClick := @mnuAddBpData;
{$ENDIF}
// TODO: add capacibilities to DebuggerClass
// and disable unsuported items
@ -1648,9 +1648,7 @@ begin
itmRunMenuAddWatch.Command:=GetCommand(ecAddWatch);
itmRunMenuAddBpSource.Command:=GetCommand(ecAddBpSource);
itmRunMenuAddBpAddress.Command:=GetCommand(ecAddBpAddress);
{$IFDEF DBG_WITH_WATCHPOINT}
//itmRunMenuAddBpWatchPoint.Command:=GetCommand(ecAddBpAddress);
{$ENDIF}
itmRunMenuAddBpWatchPoint.Command:=GetCommand(ecAddBpDataWatch);
end;
end;
@ -1736,9 +1734,7 @@ begin
// Add Breakpoint
itmRunMenuAddBpSource.Enabled := True;
itmRunMenuAddBpAddress.Enabled := True;
{$IFDEF DBG_WITH_WATCHPOINT}
itmRunMenuAddBpWatchPoint.Enabled := True;
{$ENDIF}
// TODO: add capacibilities to DebuggerClass
// menu view

View File

@ -959,7 +959,6 @@ var
end;
var
CurDebuggerClass: String;
Path: String;
CurPath: String;
i, j: Integer;

View File

@ -579,6 +579,7 @@ begin
ecAddWatch: SetResult(VK_F5,[ssCtrl],VK_UNKNOWN,[]);
ecAddBpSource: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecAddBpAddress: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecAddBpDataWatch: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
// components menu
ecNewPackage: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
@ -1030,6 +1031,7 @@ begin
ecAddWatch: SetSingle(VK_F7,[ssCtrl],VK_UNKNOWN,[]);
ecAddBpSource: SetSingle(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecAddBpAddress: SetSingle(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecAddBpDataWatch: SetSingle(VK_UNKNOWN,[],VK_UNKNOWN,[]);
// components menu
ecNewPackage: SetSingle(VK_UNKNOWN,[],VK_UNKNOWN,[]);
@ -1664,6 +1666,7 @@ begin
ecAddWatch: SetSingle(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecAddBpSource: SetSingle(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecAddBpAddress: SetSingle(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecAddBpDataWatch: SetSingle(VK_UNKNOWN,[],VK_UNKNOWN,[]);
// components menu
ecNewPackage: SetSingle(VK_UNKNOWN,[],VK_UNKNOWN,[]);
@ -1832,6 +1835,7 @@ begin
ecAddWatch: SetResult(VK_F5,[ssCtrl],VK_F5,[ssCtrl,ssMeta]);
ecAddBpSource: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecAddBpAddress: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecAddBpDataWatch: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
end;
end;
@ -2211,6 +2215,7 @@ begin
ecAddWatch : Result:= srkmecAddWatch;
ecAddBpSource : Result:= srkmecAddBpSource;
ecAddBpAddress : Result:= srkmecAddBpAddress;
ecAddBpDataWatch : Result:= srkmecAddBpWatchPoint;
// components menu
ecNewPackage : Result:= lisKMNewPackage;
@ -2866,6 +2871,7 @@ begin
AddDefault(C, 'Add watch', lisKMAddWatch, ecAddWatch);
AddDefault(C, 'Add source breakpoint', lisKMAddBpSource, ecAddBpSource);
AddDefault(C, 'Add address breakpoint', lisKMAddBpAddress, ecAddBpAddress);
AddDefault(C, 'Add data watchpoint', lisKMAddBpWatchPoint, ecAddBpDataWatch);
// components menu
C:=Categories[AddCategory('Components',srkmCatPackageMenu,nil)];

View File

@ -379,6 +379,7 @@ resourcestring
lisKMAddWatch = 'Add watch';
lisKMAddBpSource = 'Add source breakpoint';
lisKMAddBpAddress = 'Add address breakpoint';
lisKMAddBpWatchPoint = 'Add data/watchPoint';
lisMenuConfigBuildFile = 'Configure Build+Run File ...';
lisMenuInspect = '&Inspect ...';
lisMenuEvaluate = 'E&valuate/Modify ...';
@ -2697,6 +2698,7 @@ resourcestring
srkmecAddWatch = 'add watch';
srkmecAddBpSource = 'add source breakpoint';
srkmecAddBpAddress = 'add address breakpoint';
srkmecAddBpWatchPoint = 'add data/watchpoint';
// tools menu
srkmecExtToolSettings = 'External tools settings';
@ -4627,6 +4629,7 @@ resourcestring
lisGroup = 'Group';
lisSourceBreakpoint = '&Source Breakpoint ...';
lisAddressBreakpoint = '&Address Breakpoint ...';
lisWatchPoint = '&Data/Watch Breakpoint ...';
lisWatchPointBreakpoint = '&Data/watch Breakpoint ...';
lisEnableAll = '&Enable All';
lisDeleteAll = '&Delete All';
@ -4687,6 +4690,9 @@ resourcestring
lisShrinkToSmal = 'Shrink to smallest';
lisGrowToLarges = 'Grow to Largest';
// Watch Dialog
lisWatchToWatchPoint = 'Create &Data/Watch Breakpoint ...';
// Watch Property Dialog
lisWatchPropert = 'Watch Properties';
lisExpression = 'Expression:';
@ -5346,6 +5352,7 @@ resourcestring
lisFileNotFound3 = 'file %s not found';
lisFileNotFound4 = 'file not found';
lisISDDirectoryNotFound = 'directory not found';
lisDebuggerFeedbackInformation = 'Debugger Information';
lisDebuggerFeedbackWarning = 'Debugger Warning';
lisDebuggerFeedbackError = 'Debugger Error';
lisDebuggerFeedbackStop = 'Stop';

View File

@ -302,9 +302,7 @@ type
//itmRunMenuAddBreakpoint: TIDEMenuSection;
itmRunMenuAddBpSource: TIDEMenuCommand;
itmRunMenuAddBpAddress: TIDEMenuCommand;
{$IFDEF DBG_WITH_WATCHPOINT}
itmRunMenuAddBpWatchPoint: TIDEMenuCommand;
{$ENDIF}
// components menu
//mnuComponents: TIDEMenuSection;

View File

@ -697,9 +697,7 @@ begin
CreateMenuSubSection(ParentMI,itmRunMenuAddBreakpoint,'itmRunMenuAddBreakpoint',lisMenuAddBreakpoint, '');
CreateMenuItem(itmRunMenuAddBreakpoint,itmRunMenuAddBPSource,'itmRunMenuAdddBPSource',lisSourceBreakpoint, '', False);
CreateMenuItem(itmRunMenuAddBreakpoint,itmRunMenuAddBPAddress,'itmRunMenuAddBPAddress',lisAddressBreakpoint, '', False);
{$IFDEF DBG_WITH_WATCHPOINT}
CreateMenuItem(itmRunMenuAddBreakpoint,itmRunMenuAddBpWatchPoint,'itmRunMenuAddBpWatchPoint',lisWatchPointBreakpoint, '', False);
{$ENDIF}
end;
end;

View File

@ -259,6 +259,7 @@ const
ecStepOverContext = ecFirstLazarus + 448;
ecAddBpSource = ecFirstLazarus + 449;
ecAddBpAddress = ecFirstLazarus + 450;
ecAddBpDataWatch = ecFirstLazarus + 451;
// 460++ : used for ecViewHistory (debugger)