mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-19 22:49:30 +02:00
LazDebuggerFp: move breakpoints to thread worker queue
git-svn-id: trunk@64536 -
This commit is contained in:
parent
54bf4844fc
commit
2ae82698cb
@ -348,6 +348,8 @@ type
|
||||
{ TFpDbgBreakpoint }
|
||||
|
||||
TFpDbgBreakpoint = class(TObject)
|
||||
private
|
||||
FFreeByDbgProcess: Boolean;
|
||||
public
|
||||
function Hit(const AThreadID: Integer; ABreakpointAddress: TDBGPtr): Boolean; virtual; abstract;
|
||||
function HasLocation(const ALocation: TDBGPtr): Boolean; virtual; abstract;
|
||||
@ -358,6 +360,9 @@ type
|
||||
|
||||
procedure SetBreak; virtual; abstract;
|
||||
procedure ResetBreak; virtual; abstract;
|
||||
|
||||
// FreeByDbgProcess: The breakpoint will be freed by TDbgProcess.Destroy
|
||||
property FreeByDbgProcess: Boolean read FFreeByDbgProcess write FFreeByDbgProcess;
|
||||
end;
|
||||
|
||||
{ TFpInternalBreakBase }
|
||||
@ -1754,10 +1759,16 @@ begin
|
||||
FProcessID:=0;
|
||||
SetLastLibraryUnloaded(nil);
|
||||
|
||||
for i := 0 to FBreakpointList.Count - 1 do
|
||||
for i := 0 to FBreakpointList.Count - 1 do begin
|
||||
FBreakpointList[i].FProcess := nil;
|
||||
for i := 0 to FWatchPointList.Count - 1 do
|
||||
if FBreakpointList[i].FreeByDbgProcess then
|
||||
FBreakpointList[i].Free;
|
||||
end;
|
||||
for i := 0 to FWatchPointList.Count - 1 do begin
|
||||
FWatchPointList[i].FProcess := nil;
|
||||
if FWatchPointList[i].FreeByDbgProcess then
|
||||
FWatchPointList[i].Free;
|
||||
end;
|
||||
FreeAndNil(FBreakpointList);
|
||||
FreeAndNil(FWatchPointList);
|
||||
//Assert(FBreakMap.Count=0, 'No breakpoints left');
|
||||
|
@ -32,7 +32,7 @@ unit FpDebugDebugger;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, fgl, math, contnrs, process,
|
||||
Classes, SysUtils, fgl, math, process,
|
||||
Forms, Dialogs,
|
||||
Maps, LazLogger, LazUTF8,
|
||||
DbgIntfBaseTypes, DbgIntfDebuggerBase,
|
||||
@ -45,6 +45,7 @@ uses
|
||||
type
|
||||
|
||||
TFpDebugDebugger = class;
|
||||
TFPBreakpoint = class;
|
||||
|
||||
(* WorkerThreads:
|
||||
The below subclasses implement ONLY work that is done in the MAIN THREAD.
|
||||
@ -132,6 +133,28 @@ type
|
||||
constructor Create(ADebugger: TFpDebugDebuggerBase; AWatchValue: TWatchValue);
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPointSetUpdate }
|
||||
|
||||
TFpThreadWorkerBreakPointSetUpdate = class(TFpThreadWorkerBreakPointSet)
|
||||
private
|
||||
FDbgBreakPoint: TFPBreakpoint;
|
||||
protected
|
||||
procedure UpdateBrkPoint_DecRef(Data: PtrInt = 0); override;
|
||||
public
|
||||
constructor Create(ADebugger: TFpDebugDebuggerBase; ADbgBreakPoint: TFPBreakpoint); overload;
|
||||
procedure AbortSetBreak; override;
|
||||
procedure RemoveBreakPoint_DecRef; override;
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPointRemoveUpdate }
|
||||
|
||||
TFpThreadWorkerBreakPointRemoveUpdate = class(TFpThreadWorkerBreakPointRemove)
|
||||
protected
|
||||
procedure DoUnQueued; override;
|
||||
public
|
||||
constructor Create(ADebugger: TFpDebugDebuggerBase; ADbgBreakPoint: TFPBreakpoint); overload;
|
||||
end;
|
||||
|
||||
{ TDbgControllerStepOverOrFinallyCmd
|
||||
Step over with detection for finally blocks
|
||||
}
|
||||
@ -278,8 +301,6 @@ type
|
||||
FCacheLocation, FCacheLocation2: TDBGPtr;
|
||||
FCacheBoolean: boolean;
|
||||
FCachePointer: pointer;
|
||||
FCacheReadWrite: TDBGWatchPointKind;
|
||||
FCacheScope: TDBGWatchPointScope;
|
||||
FCacheThreadId, FCacheStackFrame: Integer;
|
||||
FCacheContext: TFpDbgSymbolScope;
|
||||
//
|
||||
@ -336,33 +357,22 @@ type
|
||||
function GetIsIdle: Boolean; override;
|
||||
function GetCommands: TDBGCommands; override;
|
||||
|
||||
procedure LockCommandProcessing; override;
|
||||
procedure UnLockCommandProcessing; override;
|
||||
protected
|
||||
// Helper vars to run in debug-thread
|
||||
FCallStackEntryListThread: TDbgThread;
|
||||
FCallStackEntryListFrameRequired: Integer;
|
||||
procedure DoAddBreakLine;
|
||||
procedure DoAddBreakFuncLib;
|
||||
procedure DoAddBreakLocation;
|
||||
procedure DoAddBWatch;
|
||||
procedure DoReadData;
|
||||
procedure DoReadPartialData;
|
||||
procedure DoPrepareCallStackEntryList;
|
||||
procedure DoFreeBreakpoint;
|
||||
procedure DoFindContext;
|
||||
procedure DoSetStackFrameForBasePtr;
|
||||
//
|
||||
function AddBreak(const ALocation: TDbgPtr; AnEnabled: Boolean = True): TFpDbgBreakpoint; overload;
|
||||
function AddBreak(const AFileName: String; ALine: Cardinal; AnEnabled: Boolean = True): TFpDbgBreakpoint; overload;
|
||||
function AddBreak(const AFuncName: String; ALib: TDbgLibrary = nil; AnEnabled: Boolean = True): TFpDbgBreakpoint; overload;
|
||||
function AddWatch(const ALocation: TDBGPtr; ASize: Cardinal; AReadWrite: TDBGWatchPointKind;
|
||||
AScope: TDBGWatchPointScope): TFpDbgBreakpoint;
|
||||
procedure FreeBreakpoint(const ABreakpoint: TFpDbgBreakpoint);
|
||||
function ReadData(const AAdress: TDbgPtr; const ASize: Cardinal; out AData): Boolean; inline;
|
||||
function ReadData(const AAdress: TDbgPtr; const ASize: Cardinal; out AData; out ABytesRead: Cardinal): Boolean; inline;
|
||||
function ReadAddress(const AAdress: TDbgPtr; out AData: TDBGPtr): Boolean;
|
||||
procedure PrepareCallStackEntryList(AFrameRequired: Integer = -1; AThread: TDbgThread = nil); inline;
|
||||
function SetStackFrameForBasePtr(ABasePtr: TDBGPtr; ASearchAssert: boolean = False;
|
||||
CurAddr: TDBGPtr = 0): TDBGPtr;
|
||||
function FindSymbolScope(AThreadId, AStackFrame: Integer): TFpDbgSymbolScope; inline;
|
||||
@ -373,6 +383,8 @@ type
|
||||
public
|
||||
constructor Create(const AExternalDebugger: String); override;
|
||||
destructor Destroy; override;
|
||||
procedure LockCommandProcessing; override;
|
||||
procedure UnLockCommandProcessing; override;
|
||||
function GetLocationRec(AnAddress: TDBGPtr=0; AnAddrOffset: Integer = 0): TDBGLocationRec;
|
||||
function GetLocation: TDBGLocationRec; override;
|
||||
class function Caption: String; override;
|
||||
@ -487,6 +499,7 @@ type
|
||||
|
||||
TFPBreakpoint = class(TDBGBreakPoint)
|
||||
private
|
||||
FThreadWorker: TFpThreadWorkerBreakPoint;
|
||||
FSetBreakFlag: boolean;
|
||||
FResetBreakFlag: boolean;
|
||||
FInternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint;
|
||||
@ -504,14 +517,7 @@ type
|
||||
{ TFPBreakpoints }
|
||||
|
||||
TFPBreakpoints = class(TDBGBreakPoints)
|
||||
private
|
||||
FDelayedRemoveBreakpointList: TObjectList;
|
||||
protected
|
||||
procedure DoStateChange(const AOldState: TDBGState); override;
|
||||
procedure AddBreakpointToDelayedRemoveList(ABreakpoint: FpDbgClasses.TFpDbgBreakpoint);
|
||||
public
|
||||
constructor Create(const ADebugger: TDebuggerIntf; const ABreakPointClass: TDBGBreakPointClass);
|
||||
destructor Destroy; override;
|
||||
function Find(AIntBReakpoint: FpDbgClasses.TFpDbgBreakpoint): TDBGBreakPoint;
|
||||
end;
|
||||
|
||||
@ -977,6 +983,89 @@ begin
|
||||
FWatchValue.DisplayFormat, FWatchValue.RepeatCount, FWatchValue.EvaluateFlags);
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPointSetUpdate }
|
||||
|
||||
procedure TFpThreadWorkerBreakPointSetUpdate.UpdateBrkPoint_DecRef(Data: PtrInt
|
||||
);
|
||||
var
|
||||
WorkItem: TFpThreadWorkerBreakPointRemoveUpdate;
|
||||
begin
|
||||
assert(system.ThreadID = classes.MainThreadID, 'TFpThreadWorkerBreakPointSetUpdate.UpdateBrkPoint_DecRef: system.ThreadID = classes.MainThreadID');
|
||||
|
||||
if FDbgBreakPoint <> nil then begin
|
||||
assert(FDbgBreakPoint.FThreadWorker = Self, 'TFpThreadWorkerBreakPointSetUpdate.UpdateBrkPoint_DecRef: FDbgBreakPoint.FThreadWorker = Self');
|
||||
FDbgBreakPoint.FThreadWorker := nil;
|
||||
DecRef;
|
||||
end
|
||||
else
|
||||
FResetBreakPoint := True;
|
||||
|
||||
if FResetBreakPoint then begin
|
||||
if InternalBreakpoint <> nil then begin
|
||||
WorkItem := TFpThreadWorkerBreakPointRemoveUpdate.Create(FDebugger, InternalBreakpoint);
|
||||
FpDebugger.FWorkQueue.PushItem(WorkItem);
|
||||
WorkItem.DecRef;
|
||||
end;
|
||||
end
|
||||
else
|
||||
if FDbgBreakPoint <> nil then begin
|
||||
assert(FDbgBreakPoint.FInternalBreakpoint = nil, 'TFpThreadWorkerBreakPointSetUpdate.UpdateBrkPoint_DecRef: FDbgBreakPoint.FInternalBreakpoint = nil');
|
||||
FDbgBreakPoint.FInternalBreakpoint := InternalBreakpoint;
|
||||
if not assigned(InternalBreakpoint) then
|
||||
FDbgBreakPoint.FValid:=vsInvalid // pending?
|
||||
else
|
||||
FDbgBreakPoint.FValid:=vsValid;
|
||||
end;
|
||||
|
||||
UnQueue_DecRef;
|
||||
end;
|
||||
|
||||
constructor TFpThreadWorkerBreakPointSetUpdate.Create(
|
||||
ADebugger: TFpDebugDebuggerBase; ADbgBreakPoint: TFPBreakpoint);
|
||||
var
|
||||
CurThreadId, CurStackFrame: Integer;
|
||||
begin
|
||||
FDbgBreakPoint := ADbgBreakPoint;
|
||||
case ADbgBreakPoint.Kind of
|
||||
bpkAddress: inherited Create(ADebugger, ADbgBreakPoint.Address);
|
||||
bpkSource: inherited Create(ADebugger, ADbgBreakPoint.Source, ADbgBreakPoint.Line);
|
||||
bpkData: begin
|
||||
TFpDebugDebugger(ADebugger).GetCurrentThreadAndStackFrame(CurThreadId, CurStackFrame);
|
||||
inherited Create(ADebugger, ADbgBreakPoint.WatchData, ADbgBreakPoint.WatchScope,
|
||||
ADbgBreakPoint.WatchKind, CurStackFrame, CurThreadId);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFpThreadWorkerBreakPointSetUpdate.AbortSetBreak;
|
||||
begin
|
||||
FResetBreakPoint := True;
|
||||
RequestStop;
|
||||
end;
|
||||
|
||||
procedure TFpThreadWorkerBreakPointSetUpdate.RemoveBreakPoint_DecRef;
|
||||
begin
|
||||
assert(system.ThreadID = classes.MainThreadID, 'TFpThreadWorkerBreakPointSetUpdate.RemoveBreakPoint_DecRef: system.ThreadID = classes.MainThreadID');
|
||||
FDbgBreakPoint := nil;
|
||||
UnQueue_DecRef;
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPointRemoveUpdate }
|
||||
|
||||
procedure TFpThreadWorkerBreakPointRemoveUpdate.DoUnQueued;
|
||||
begin
|
||||
if FInternalBreakpoint = nil then
|
||||
exit;
|
||||
FInternalBreakpoint.FreeByDbgProcess := True;
|
||||
inherited DoUnQueued;
|
||||
end;
|
||||
|
||||
constructor TFpThreadWorkerBreakPointRemoveUpdate.Create(
|
||||
ADebugger: TFpDebugDebuggerBase; ADbgBreakPoint: TFPBreakpoint);
|
||||
begin
|
||||
inherited Create(ADebugger, ADbgBreakPoint.FInternalBreakpoint);
|
||||
end;
|
||||
|
||||
{ TDbgControllerStepOverFirstFinallyLineCmd }
|
||||
|
||||
procedure TDbgControllerStepOverFirstFinallyLineCmd.DoResolveEvent(
|
||||
@ -1469,7 +1558,6 @@ end;
|
||||
|
||||
procedure TFPLocals.RequestData(ALocals: TLocals);
|
||||
var
|
||||
AController: TDbgController;
|
||||
WorkItem: TFpThreadWorkerLocalsUpdate;
|
||||
begin
|
||||
if not FpDebugger.IsPausedAndValid then begin
|
||||
@ -1484,48 +1572,6 @@ end;
|
||||
|
||||
{ TFPBreakpoints }
|
||||
|
||||
procedure TFPBreakpoints.DoStateChange(const AOldState: TDBGState);
|
||||
var
|
||||
ABrkPoint: FpDbgClasses.TFpDbgBreakpoint;
|
||||
i: Integer;
|
||||
begin
|
||||
inherited DoStateChange(AOldState);
|
||||
if (Debugger.State in [dsPause, dsInternalPause, dsStop]) or
|
||||
(TFpDebugDebugger(Debugger).FSendingEvents and (Debugger.State in [dsRun, dsInit]))
|
||||
then
|
||||
begin
|
||||
if FDelayedRemoveBreakpointList.Count>0 then begin
|
||||
debuglnEnter(DBG_BREAKPOINTS, ['TFPBreakpoints.DoStateChange REMOVE DELAYED']);
|
||||
for i := FDelayedRemoveBreakpointList.Count-1 downto 0 do
|
||||
begin
|
||||
ABrkPoint := FpDbgClasses.TFpDbgBreakpoint(FDelayedRemoveBreakpointList[i]);
|
||||
TFpDebugDebugger(Debugger).FDbgController.CurrentProcess.RemoveBreak(ABrkPoint);
|
||||
TFpDebugDebugger(Debugger).FreeBreakpoint(ABrkPoint);
|
||||
ABrkPoint := nil;
|
||||
FDelayedRemoveBreakpointList.Delete(i);
|
||||
end;
|
||||
debuglnExit(DBG_BREAKPOINTS, ['<< TFPBreakpoints.DoStateChange REMOVE DELAYED ' ]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFPBreakpoints.AddBreakpointToDelayedRemoveList(ABreakpoint: FpDbgClasses.TFpDbgBreakpoint);
|
||||
begin
|
||||
FDelayedRemoveBreakpointList.Add(ABreakpoint);
|
||||
end;
|
||||
|
||||
constructor TFPBreakpoints.Create(const ADebugger: TDebuggerIntf; const ABreakPointClass: TDBGBreakPointClass);
|
||||
begin
|
||||
inherited create(ADebugger, ABreakPointClass);
|
||||
FDelayedRemoveBreakpointList := TObjectList.Create(false);
|
||||
end;
|
||||
|
||||
destructor TFPBreakpoints.Destroy;
|
||||
begin
|
||||
FDelayedRemoveBreakpointList.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TFPBreakpoints.Find(AIntBReakpoint: FpDbgClasses.TFpDbgBreakpoint): TDBGBreakPoint;
|
||||
var
|
||||
i: integer;
|
||||
@ -1540,69 +1586,60 @@ begin
|
||||
end;
|
||||
|
||||
procedure TFPBreakpoint.SetBreak;
|
||||
var
|
||||
CurThreadId, CurStackFrame: Integer;
|
||||
CurContext: TFpDbgSymbolScope;
|
||||
WatchPasExpr: TFpPascalExpression;
|
||||
R: TFpValue;
|
||||
s: TFpDbgValueSize;
|
||||
begin
|
||||
assert(FInternalBreakpoint=nil);
|
||||
debuglnEnter(DBG_BREAKPOINTS, ['>> TFPBreakpoint.SetBreak ADD ',FSource,':',FLine,'/',dbghex(Address),' ' ]);
|
||||
case Kind of
|
||||
bpkAddress: FInternalBreakpoint := TFpDebugDebugger(Debugger).AddBreak(Address);
|
||||
bpkSource: FInternalBreakpoint := TFpDebugDebugger(Debugger).AddBreak(Source, cardinal(Line));
|
||||
bpkData: begin
|
||||
TFpDebugDebugger(Debugger).GetCurrentThreadAndStackFrame(CurThreadId, CurStackFrame);
|
||||
CurContext := TFpDebugDebugger(Debugger).GetContextForEvaluate(CurThreadId, CurStackFrame);
|
||||
if CurContext <> nil then begin
|
||||
WatchPasExpr := TFpPascalExpression.Create(WatchData, CurContext);
|
||||
R := WatchPasExpr.ResultValue; // Address and Size
|
||||
// TODO: Cache current value
|
||||
if WatchPasExpr.Valid and IsTargetNotNil(R.Address) and R.GetSize(s) then begin
|
||||
// pass context
|
||||
FInternalBreakpoint := TFpDebugDebugger(Debugger).AddWatch(R.Address.Address, SizeToFullBytes(s), WatchKind, WatchScope);
|
||||
end;
|
||||
WatchPasExpr.Free;
|
||||
CurContext.ReleaseReference;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
debuglnExit(DBG_BREAKPOINTS, ['<< TFPBreakpoint.SetBreak ' ]);
|
||||
assert(FThreadWorker = nil, 'TFPBreakpoint.SetBreak: FThreadWorker = nil');
|
||||
assert(FInternalBreakpoint=nil);
|
||||
|
||||
FThreadWorker := TFpThreadWorkerBreakPointSetUpdate.Create(TFpDebugDebugger(Debugger), Self);
|
||||
TFpDebugDebugger(Debugger).FWorkQueue.PushItem(FThreadWorker);
|
||||
|
||||
FIsSet:=true;
|
||||
if not assigned(FInternalBreakpoint) then
|
||||
FValid:=vsInvalid // pending?
|
||||
else
|
||||
FValid:=vsValid;
|
||||
debuglnExit(DBG_BREAKPOINTS, ['<< TFPBreakpoint.SetBreak ' ]);
|
||||
end;
|
||||
|
||||
procedure TFPBreakpoint.ResetBreak;
|
||||
var
|
||||
WorkItem: TFpThreadWorkerBreakPointRemoveUpdate;
|
||||
begin
|
||||
FIsSet:=false;
|
||||
if FThreadWorker <> nil then begin
|
||||
debugln(DBG_BREAKPOINTS, ['>> TFPBreakpoint.ResetBreak CANCEL / REMOVE ',FSource,':',FLine,'/',dbghex(Address),' ' ]);
|
||||
assert(FThreadWorker is TFpThreadWorkerBreakPointSetUpdate, 'TFPBreakpoint.ResetBreak: FThreadWorker is TFpThreadWorkerBreakPointSetUpdate');
|
||||
assert(FInternalBreakpoint = nil, 'TFPBreakpoint.ResetBreak: FInternalBreakpoint = nil');
|
||||
FThreadWorker.AbortSetBreak;
|
||||
FThreadWorker.RemoveBreakPoint_DecRef;
|
||||
FThreadWorker.DecRef;
|
||||
FThreadWorker := nil;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// If Debugger is not assigned, the Controller's currentprocess is already
|
||||
// freed. And so are the corresponding InternalBreakpoint's.
|
||||
if assigned(Debugger) and assigned(FInternalBreakpoint) then
|
||||
begin
|
||||
debuglnEnter(DBG_BREAKPOINTS, ['>> TFPBreakpoint.ResetBreak REMOVE ',FSource,':',FLine,'/',dbghex(Address),' ' ]);
|
||||
TFpDebugDebugger(Debugger).FDbgController.CurrentProcess.RemoveBreak(FInternalBreakpoint);
|
||||
TFpDebugDebugger(Debugger).FreeBreakpoint(FInternalBreakpoint);
|
||||
WorkItem := TFpThreadWorkerBreakPointRemoveUpdate.Create(TFpDebugDebugger(Debugger), Self);
|
||||
TFpDebugDebugger(Debugger).FWorkQueue.PushItem(WorkItem);
|
||||
WorkItem.DecRef;
|
||||
FInternalBreakpoint := nil;
|
||||
debuglnExit(DBG_BREAKPOINTS, ['<< TFPBreakpoint.ResetBreak ' ]);
|
||||
end;
|
||||
FIsSet:=false;
|
||||
end;
|
||||
|
||||
destructor TFPBreakpoint.Destroy;
|
||||
begin
|
||||
if assigned(Debugger) and
|
||||
( (Debugger.State = dsRun) and (not TFpDebugDebugger(Debugger).FSendingEvents) ) and
|
||||
assigned(FInternalBreakpoint) then
|
||||
begin
|
||||
TFPBreakpoints(Collection).AddBreakpointToDelayedRemoveList(FInternalBreakpoint);
|
||||
FInternalBreakpoint:=nil;
|
||||
// TFpDebugDebugger(Debugger).QuickPause;
|
||||
end
|
||||
else
|
||||
ResetBreak;
|
||||
(* No need to request a pause. This will run, as soon as the debugger gets to the next pause.
|
||||
If the next pause is a hit on this breakpoint, then it will be ignored
|
||||
*)
|
||||
ResetBreak;
|
||||
|
||||
if FThreadWorker <> nil then begin
|
||||
FThreadWorker.AbortSetBreak;
|
||||
FThreadWorker.RemoveBreakPoint_DecRef;
|
||||
FThreadWorker.DecRef;
|
||||
FThreadWorker := nil;
|
||||
end;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
@ -1625,11 +1662,7 @@ begin
|
||||
end
|
||||
else if Debugger.State = dsStop then
|
||||
begin
|
||||
debuglnEnter(DBG_BREAKPOINTS, ['>> TFPBreakpoint.DoStateChange REMOVE ',FSource,':',FLine,'/',dbghex(Address),' ' ]);
|
||||
TFpDebugDebugger(Debugger).FreeBreakpoint(FInternalBreakpoint);
|
||||
debuglnExit(DBG_BREAKPOINTS, ['<< TFPBreakpoint.DoStateChange ' ]);
|
||||
FInternalBreakpoint := nil;
|
||||
FIsSet:=false;
|
||||
ResetBreak;
|
||||
end;
|
||||
inherited DoStateChange(AOldState);
|
||||
end;
|
||||
@ -1646,7 +1679,7 @@ begin
|
||||
else if not Enabled and FIsSet then
|
||||
FResetBreakFlag := True;
|
||||
end
|
||||
else if (ADebugger.State = dsRun) and ((Enabled and not FIsSet) or (not Enabled and FIsSet)) then
|
||||
else if (ADebugger.State = dsRun) and (Enabled and not FIsSet) then
|
||||
ADebugger.QuickPause;
|
||||
inherited;
|
||||
end;
|
||||
@ -2894,8 +2927,6 @@ var
|
||||
Context: TFpDbgSymbolScope;
|
||||
PasExpr: TFpPascalExpression;
|
||||
Opts: TFpInt3DebugBreakOptions;
|
||||
StackEntry: TDbgCallstackEntry;
|
||||
s: String;
|
||||
begin
|
||||
// If a user single steps to an excepiton handler, do not open the dialog (there is no continue possible)
|
||||
if AnEventType = deBreakpoint then
|
||||
@ -2904,7 +2935,7 @@ begin
|
||||
|
||||
if assigned(Breakpoint) then begin
|
||||
ABreakPoint := TFPBreakpoints(BreakPoints).Find(Breakpoint);
|
||||
if ABreakPoint <> nil then begin
|
||||
if (ABreakPoint <> nil) and (ABreakPoint.Enabled) then begin
|
||||
|
||||
// TODO: parse expression when breakpoin is created / so invalid expressions do not need to be handled here
|
||||
if ABreakPoint.Expression <> '' then begin
|
||||
@ -2943,6 +2974,8 @@ begin
|
||||
'', ftInformation, [frOk]);
|
||||
end;
|
||||
end
|
||||
else
|
||||
continue := True; // removed or disabled breakpoint
|
||||
end
|
||||
else
|
||||
if (AnEventType = deHardCodedBreakpoint) and (FDbgController.CurrentThread <> nil) then begin
|
||||
@ -3033,7 +3066,6 @@ var
|
||||
EvalFlags: TDBGEvaluateFlags;
|
||||
AConsoleTty, ResText: string;
|
||||
addr: TDBGPtrArray;
|
||||
ResType: TDBGType;
|
||||
Cmd: TDBGCommand;
|
||||
WorkItem: TFpThreadWorkerControllerRun;
|
||||
AThreadId, AStackFrame: Integer;
|
||||
@ -3317,8 +3349,7 @@ end;
|
||||
procedure TFpDebugDebugger.RunQuickPauseTasks(AForce: Boolean);
|
||||
begin
|
||||
if AForce or
|
||||
FQuickPause or
|
||||
(TFPBreakpoints(Breakpoints).FDelayedRemoveBreakpointList.Count > 0)
|
||||
FQuickPause
|
||||
then
|
||||
TFPBreakpoints(Breakpoints).DoStateChange(dsRun);
|
||||
end;
|
||||
@ -3395,11 +3426,6 @@ begin
|
||||
Result := (FWorkQueue.Count = 0) or FIsIdle;
|
||||
end;
|
||||
|
||||
procedure TFpDebugDebugger.DoAddBreakLine;
|
||||
begin
|
||||
FCacheBreakpoint := TDbgInstance(FDbgController.CurrentProcess).AddBreak(FCacheFileName, FCacheLine, FCacheBoolean);
|
||||
end;
|
||||
|
||||
procedure TFpDebugDebugger.DoAddBreakFuncLib;
|
||||
begin
|
||||
if FCacheLib <> nil then
|
||||
@ -3416,11 +3442,6 @@ begin
|
||||
FCacheBreakpoint := FDbgController.CurrentProcess.AddBreak(FCacheLocation, FCacheBoolean);
|
||||
end;
|
||||
|
||||
procedure TFpDebugDebugger.DoAddBWatch;
|
||||
begin
|
||||
FCacheBreakpoint := FDbgController.CurrentProcess.AddWatch(FCacheLocation, FCacheLine, FCacheReadWrite, FCacheScope);
|
||||
end;
|
||||
|
||||
procedure TFpDebugDebugger.DoReadData;
|
||||
begin
|
||||
FCacheBoolean:=FDbgController.CurrentProcess.ReadData(FCacheLocation, FCacheLine, FCachePointer^);
|
||||
@ -3431,16 +3452,6 @@ begin
|
||||
FCacheBoolean:=FDbgController.CurrentProcess.ReadData(FCacheLocation, FCacheLine, FCachePointer^, FCacheBytesRead);
|
||||
end;
|
||||
|
||||
procedure TFpDebugDebugger.DoPrepareCallStackEntryList;
|
||||
begin
|
||||
FCallStackEntryListThread.PrepareCallStackEntryList(FCallStackEntryListFrameRequired);
|
||||
end;
|
||||
|
||||
procedure TFpDebugDebugger.DoFreeBreakpoint;
|
||||
begin
|
||||
FCacheBreakpoint.Free;
|
||||
end;
|
||||
|
||||
procedure TFpDebugDebugger.DoFindContext;
|
||||
begin
|
||||
FCacheContext := FDbgController.CurrentProcess.FindSymbolScope(FCacheThreadId, FCacheStackFrame);
|
||||
@ -3473,22 +3484,6 @@ begin
|
||||
result := FDbgController.CurrentProcess.AddBreak(ALocation, AnEnabled);
|
||||
end;
|
||||
|
||||
function TFpDebugDebugger.AddBreak(const AFileName: String; ALine: Cardinal;
|
||||
AnEnabled: Boolean): TFpDbgBreakpoint;
|
||||
begin
|
||||
if FDbgController.CurrentProcess.RequiresExecutionInDebuggerThread then
|
||||
begin
|
||||
FCacheFileName:=AFileName;
|
||||
FCacheLine:=ALine;
|
||||
FCacheBoolean:=AnEnabled;
|
||||
FCacheBreakpoint := nil;
|
||||
ExecuteInDebugThread(@DoAddBreakLine);
|
||||
result := FCacheBreakpoint;
|
||||
end
|
||||
else
|
||||
result := TDbgInstance(FDbgController.CurrentProcess).AddBreak(AFileName, ALine, AnEnabled);
|
||||
end;
|
||||
|
||||
function TFpDebugDebugger.AddBreak(const AFuncName: String; ALib: TDbgLibrary;
|
||||
AnEnabled: Boolean): TFpDbgBreakpoint;
|
||||
begin
|
||||
@ -3508,37 +3503,6 @@ begin
|
||||
result := TDbgInstance(FDbgController.CurrentProcess).AddBreak(AFuncName, AnEnabled);
|
||||
end;
|
||||
|
||||
function TFpDebugDebugger.AddWatch(const ALocation: TDBGPtr; ASize: Cardinal;
|
||||
AReadWrite: TDBGWatchPointKind; AScope: TDBGWatchPointScope
|
||||
): TFpDbgBreakpoint;
|
||||
begin
|
||||
if FDbgController.CurrentProcess.RequiresExecutionInDebuggerThread then
|
||||
begin
|
||||
FCacheLocation:=ALocation;
|
||||
FCacheLine:=ASize;
|
||||
FCacheReadWrite:=AReadWrite;
|
||||
FCacheScope:=AScope;
|
||||
FCacheBreakpoint := nil;
|
||||
ExecuteInDebugThread(@DoAddBWatch);
|
||||
result := FCacheBreakpoint;
|
||||
end
|
||||
else
|
||||
result := FDbgController.CurrentProcess.AddWatch(ALocation, ASize, AReadWrite, AScope);
|
||||
end;
|
||||
|
||||
procedure TFpDebugDebugger.FreeBreakpoint(
|
||||
const ABreakpoint: TFpDbgBreakpoint);
|
||||
begin
|
||||
if ABreakpoint = nil then exit;
|
||||
if FDbgController.CurrentProcess.RequiresExecutionInDebuggerThread then
|
||||
begin
|
||||
FCacheBreakpoint:=ABreakpoint;
|
||||
ExecuteInDebugThread(@DoFreeBreakpoint);
|
||||
end
|
||||
else
|
||||
ABreakpoint.Free;
|
||||
end;
|
||||
|
||||
function TFpDebugDebugger.ReadData(const AAdress: TDbgPtr; const ASize: Cardinal; out AData): Boolean;
|
||||
begin
|
||||
if FDbgController.CurrentProcess.RequiresExecutionInDebuggerThread then
|
||||
@ -3591,26 +3555,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFpDebugDebugger.PrepareCallStackEntryList(AFrameRequired: Integer;
|
||||
AThread: TDbgThread);
|
||||
begin
|
||||
if AThread = nil then
|
||||
AThread := FDbgController.CurrentThread;
|
||||
// In case of linux, check if required, before handind to other thread
|
||||
if (AFrameRequired >= 0) and
|
||||
(AThread.CallStackEntryList <> nil) and
|
||||
(AFrameRequired < AThread.CallStackEntryList.Count) then
|
||||
exit;
|
||||
if FDbgController.CurrentProcess.RequiresExecutionInDebuggerThread then
|
||||
begin
|
||||
FCallStackEntryListThread := AThread;
|
||||
FCallStackEntryListFrameRequired := AFrameRequired;
|
||||
ExecuteInDebugThread(@DoPrepareCallStackEntryList);
|
||||
end
|
||||
else
|
||||
AThread.PrepareCallStackEntryList(AFrameRequired);
|
||||
end;
|
||||
|
||||
function TFpDebugDebugger.SetStackFrameForBasePtr(ABasePtr: TDBGPtr;
|
||||
ASearchAssert: boolean; CurAddr: TDBGPtr): TDBGPtr;
|
||||
const
|
||||
|
@ -274,6 +274,51 @@ type
|
||||
procedure DoExecute; override;
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPoint }
|
||||
|
||||
TFpThreadWorkerBreakPoint = class(TFpDbgDebggerThreadWorkerItem)
|
||||
public
|
||||
procedure RemoveBreakPoint_DecRef; virtual;
|
||||
procedure AbortSetBreak; virtual;
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPointSet }
|
||||
|
||||
TFpThreadWorkerBreakPointSet = class(TFpThreadWorkerBreakPoint)
|
||||
private
|
||||
FInternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint;
|
||||
FKind: TDBGBreakPointKind;
|
||||
FAddress: TDBGPtr;
|
||||
FSource: String;
|
||||
FLine: Integer;
|
||||
FStackFrame, FThreadId: Integer;
|
||||
FWatchData: String;
|
||||
FWatchScope: TDBGWatchPointScope;
|
||||
FWatchKind: TDBGWatchPointKind;
|
||||
protected
|
||||
FResetBreakPoint: Boolean;
|
||||
procedure UpdateBrkPoint_DecRef(Data: PtrInt = 0); virtual; abstract;
|
||||
procedure DoExecute; override;
|
||||
public
|
||||
constructor Create(ADebugger: TFpDebugDebuggerBase; AnAddress: TDBGPtr);
|
||||
constructor Create(ADebugger: TFpDebugDebuggerBase; ASource: String; ALine: Integer);
|
||||
constructor Create(ADebugger: TFpDebugDebuggerBase;
|
||||
AWatchData: String; AWatchScope: TDBGWatchPointScope; AWatchKind: TDBGWatchPointKind;
|
||||
AStackFrame, AThreadId: Integer);
|
||||
property InternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint read FInternalBreakpoint;
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPointRemove }
|
||||
|
||||
TFpThreadWorkerBreakPointRemove = class(TFpThreadWorkerBreakPoint)
|
||||
protected
|
||||
FInternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint;
|
||||
procedure DoExecute; override;
|
||||
public
|
||||
constructor Create(ADebugger: TFpDebugDebuggerBase; AnInternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint);
|
||||
property InternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint read FInternalBreakpoint;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TFpDbgDebggerThreadWorkerItem }
|
||||
@ -818,5 +863,100 @@ begin
|
||||
Queue(@UpdateWatch_DecRef);
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPoint }
|
||||
|
||||
procedure TFpThreadWorkerBreakPoint.RemoveBreakPoint_DecRef;
|
||||
begin
|
||||
//
|
||||
end;
|
||||
|
||||
procedure TFpThreadWorkerBreakPoint.AbortSetBreak;
|
||||
begin
|
||||
//
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPointSet }
|
||||
|
||||
procedure TFpThreadWorkerBreakPointSet.DoExecute;
|
||||
var
|
||||
CurContext: TFpDbgSymbolScope;
|
||||
WatchPasExpr: TFpPascalExpression;
|
||||
R: TFpValue;
|
||||
s: TFpDbgValueSize;
|
||||
begin
|
||||
case FKind of
|
||||
bpkAddress:
|
||||
FInternalBreakpoint := FDebugger.FDbgController.CurrentProcess.AddBreak(FAddress, True);
|
||||
bpkSource:
|
||||
FInternalBreakpoint := FDebugger.FDbgController.CurrentProcess.AddBreak(FSource, FLine, True);
|
||||
bpkData: begin
|
||||
CurContext := FDebugger.FDbgController.CurrentProcess.FindSymbolScope(FThreadId, FStackFrame);
|
||||
if CurContext <> nil then begin
|
||||
WatchPasExpr := TFpPascalExpression.Create(FWatchData, CurContext);
|
||||
R := WatchPasExpr.ResultValue; // Address and Size
|
||||
// TODO: Cache current value
|
||||
if WatchPasExpr.Valid and IsTargetNotNil(R.Address) and R.GetSize(s) then begin
|
||||
// pass context
|
||||
FInternalBreakpoint := FDebugger.FDbgController.CurrentProcess.AddWatch(R.Address.Address, SizeToFullBytes(s), FWatchKind, FWatchScope);
|
||||
end;
|
||||
WatchPasExpr.Free;
|
||||
CurContext.ReleaseReference;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if FResetBreakPoint then begin
|
||||
FDebugger.FDbgController.CurrentProcess.RemoveBreak(FInternalBreakpoint);
|
||||
FreeAndNil(FInternalBreakpoint);
|
||||
end;
|
||||
Queue(@UpdateBrkPoint_DecRef);
|
||||
end;
|
||||
|
||||
constructor TFpThreadWorkerBreakPointSet.Create(ADebugger: TFpDebugDebuggerBase; AnAddress: TDBGPtr);
|
||||
begin
|
||||
FKind := bpkAddress;
|
||||
FAddress := AnAddress;
|
||||
inherited Create(ADebugger, twpUser);
|
||||
end;
|
||||
|
||||
constructor TFpThreadWorkerBreakPointSet.Create(
|
||||
ADebugger: TFpDebugDebuggerBase; ASource: String; ALine: Integer);
|
||||
begin
|
||||
FKind := bpkSource;
|
||||
FSource := ASource;
|
||||
FLine := ALine;
|
||||
inherited Create(ADebugger, twpUser);
|
||||
end;
|
||||
|
||||
constructor TFpThreadWorkerBreakPointSet.Create(
|
||||
ADebugger: TFpDebugDebuggerBase; AWatchData: String;
|
||||
AWatchScope: TDBGWatchPointScope; AWatchKind: TDBGWatchPointKind;
|
||||
AStackFrame, AThreadId: Integer);
|
||||
begin
|
||||
FKind := bpkData;
|
||||
FWatchData := AWatchData;
|
||||
FWatchScope := AWatchScope;
|
||||
FWatchKind := AWatchKind;
|
||||
FStackFrame := AStackFrame;
|
||||
FThreadId := AThreadId;
|
||||
inherited Create(ADebugger, twpUser);
|
||||
end;
|
||||
|
||||
{ TFpThreadWorkerBreakPointRemove }
|
||||
|
||||
procedure TFpThreadWorkerBreakPointRemove.DoExecute;
|
||||
begin
|
||||
if (FDebugger.FDbgController <> nil) and (FDebugger.FDbgController.CurrentProcess <> nil) then
|
||||
FDebugger.FDbgController.CurrentProcess.RemoveBreak(FInternalBreakpoint);
|
||||
FreeAndNil(FInternalBreakpoint);
|
||||
end;
|
||||
|
||||
constructor TFpThreadWorkerBreakPointRemove.Create(
|
||||
ADebugger: TFpDebugDebuggerBase;
|
||||
AnInternalBreakpoint: FpDbgClasses.TFpDbgBreakpoint);
|
||||
begin
|
||||
FInternalBreakpoint := AnInternalBreakpoint;
|
||||
inherited Create(ADebugger, twpUser);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user