mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-17 08:51:17 +02:00
FpDebugServer: Added basic "evaluate" command
git-svn-id: trunk@49166 -
This commit is contained in:
parent
81be2b6595
commit
8d4b6344c0
@ -146,6 +146,16 @@ type
|
|||||||
(* TValidState: State for breakpoints *)
|
(* TValidState: State for breakpoints *)
|
||||||
TValidState = (vsUnknown, vsValid, vsInvalid);
|
TValidState = (vsUnknown, vsValid, vsInvalid);
|
||||||
|
|
||||||
|
const
|
||||||
|
DebuggerDataStateStr : array[TDebuggerDataState] of string = (
|
||||||
|
'Unknown',
|
||||||
|
'Requested',
|
||||||
|
'Evaluating',
|
||||||
|
'Valid',
|
||||||
|
'Invalid',
|
||||||
|
'Error');
|
||||||
|
|
||||||
|
type
|
||||||
TDBGEvaluateFlag =
|
TDBGEvaluateFlag =
|
||||||
(defNoTypeInfo, // No Typeinfo object will be returned
|
(defNoTypeInfo, // No Typeinfo object will be returned
|
||||||
defSimpleTypeInfo, // Returns: Kind (skSimple, skClass, ..); TypeName (but does make no attempt to avoid an alias)
|
defSimpleTypeInfo, // Returns: Kind (skSimple, skClass, ..); TypeName (but does make no attempt to avoid an alias)
|
||||||
|
@ -80,9 +80,6 @@ type
|
|||||||
TPDDbgMemReader = class(TDbgMemReader)
|
TPDDbgMemReader = class(TDbgMemReader)
|
||||||
protected
|
protected
|
||||||
function GetDbgProcess: TDbgProcess; override;
|
function GetDbgProcess: TDbgProcess; override;
|
||||||
public
|
|
||||||
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
|
|
||||||
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -98,16 +95,6 @@ begin
|
|||||||
result := GController.CurrentProcess;
|
result := GController.CurrentProcess;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPDDbgMemReader.ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean;
|
|
||||||
begin
|
|
||||||
result := GetDbgProcess.ReadData(AnAddress, ASize, ADest^);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TPDDbgMemReader.ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean;
|
|
||||||
begin
|
|
||||||
result := GetDbgProcess.ReadData(AnAddress, ASize, ADest^);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TFPDLoop }
|
{ TFPDLoop }
|
||||||
|
|
||||||
procedure TFPDLoop.GControllerExceptionEvent(var continue: boolean; const ExceptionClass, ExceptionMessage: string);
|
procedure TFPDLoop.GControllerExceptionEvent(var continue: boolean; const ExceptionClass, ExceptionMessage: string);
|
||||||
|
@ -10,6 +10,7 @@ uses
|
|||||||
fpjson,
|
fpjson,
|
||||||
FpDbgUtil,
|
FpDbgUtil,
|
||||||
DebugThreadCommand,
|
DebugThreadCommand,
|
||||||
|
DbgIntfDebuggerBase,
|
||||||
debugthread,
|
debugthread,
|
||||||
FpDbgClasses,
|
FpDbgClasses,
|
||||||
typinfo,
|
typinfo,
|
||||||
@ -149,6 +150,8 @@ begin
|
|||||||
JSonEvent.Add('breakpointLocation', FormatAddress(AnEvent.BreakpointAddr));
|
JSonEvent.Add('breakpointLocation', FormatAddress(AnEvent.BreakpointAddr));
|
||||||
if AnEvent.SendByConnectionIdentifier>0 then
|
if AnEvent.SendByConnectionIdentifier>0 then
|
||||||
JSonEvent.Add('connIdentifier', AnEvent.SendByConnectionIdentifier);
|
JSonEvent.Add('connIdentifier', AnEvent.SendByConnectionIdentifier);
|
||||||
|
if AnEvent.Validity<>ddsUnknown then
|
||||||
|
JSonEvent.Add('validity', DebuggerDataStateStr[AnEvent.Validity]);
|
||||||
if AnEvent.LocationRec.Address <> 0 then
|
if AnEvent.LocationRec.Address <> 0 then
|
||||||
begin
|
begin
|
||||||
JSonLocationRec := TJSONObject.Create;
|
JSonLocationRec := TJSONObject.Create;
|
||||||
|
@ -9,6 +9,8 @@ uses
|
|||||||
Classes,
|
Classes,
|
||||||
SysUtils,
|
SysUtils,
|
||||||
FPDbgController,
|
FPDbgController,
|
||||||
|
FpDbgDwarfDataClasses,
|
||||||
|
FpdMemoryTools,
|
||||||
DbgIntfBaseTypes,
|
DbgIntfBaseTypes,
|
||||||
DbgIntfDebuggerBase,
|
DbgIntfDebuggerBase,
|
||||||
lazCollections,
|
lazCollections,
|
||||||
@ -51,6 +53,7 @@ type
|
|||||||
AnUID: variant;
|
AnUID: variant;
|
||||||
BreakpointAddr: TDBGPtr;
|
BreakpointAddr: TDBGPtr;
|
||||||
LocationRec: TDBGLocationRec;
|
LocationRec: TDBGLocationRec;
|
||||||
|
Validity: TDebuggerDataState;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Each listener should implement this interface.
|
// Each listener should implement this interface.
|
||||||
@ -109,11 +112,15 @@ type
|
|||||||
FCommandQueue: TFpDebugThreadCommandQueue;
|
FCommandQueue: TFpDebugThreadCommandQueue;
|
||||||
FController: TDbgController;
|
FController: TDbgController;
|
||||||
FListenerList: TThreadList;
|
FListenerList: TThreadList;
|
||||||
|
FMemConverter: TFpDbgMemConvertorLittleEndian;
|
||||||
|
FMemReader: TDbgMemReader;
|
||||||
|
FMemManager: TFpDbgMemManager;
|
||||||
protected
|
protected
|
||||||
// Handlers for the FController-events
|
// Handlers for the FController-events
|
||||||
procedure FControllerHitBreakpointEvent(var continue: boolean; const Breakpoint: TDbgBreakpoint);
|
procedure FControllerHitBreakpointEvent(var continue: boolean; const Breakpoint: TDbgBreakpoint);
|
||||||
procedure FControllerProcessExitEvent(ExitCode: DWord);
|
procedure FControllerProcessExitEvent(ExitCode: DWord);
|
||||||
procedure FControllerCreateProcessEvent(var continue: boolean);
|
procedure FControllerCreateProcessEvent(var continue: boolean);
|
||||||
|
procedure FControllerDebugInfoLoaded(Sender: TObject);
|
||||||
// Main debug thread-loop
|
// Main debug thread-loop
|
||||||
procedure Execute; override;
|
procedure Execute; override;
|
||||||
// Send an event to all listeners
|
// Send an event to all listeners
|
||||||
@ -155,6 +162,32 @@ implementation
|
|||||||
var
|
var
|
||||||
FFpDebugThread: TFpDebugThread;
|
FFpDebugThread: TFpDebugThread;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TFpDbgMemReader }
|
||||||
|
|
||||||
|
TFpDbgMemReader = class(TDbgMemReader)
|
||||||
|
private
|
||||||
|
FDebugThread: TFpDebugThread;
|
||||||
|
protected
|
||||||
|
function GetDbgProcess: TDbgProcess; override;
|
||||||
|
public
|
||||||
|
constructor create(ADebugThread: TFpDebugThread);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TFpDbgMemReader }
|
||||||
|
|
||||||
|
function TFpDbgMemReader.GetDbgProcess: TDbgProcess;
|
||||||
|
begin
|
||||||
|
result := FDebugThread.FController.CurrentProcess;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TFpDbgMemReader.create(ADebugThread: TFpDebugThread);
|
||||||
|
begin
|
||||||
|
Inherited Create;
|
||||||
|
FDebugThread:=ADebugThread;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TFpDebugThreadCommand }
|
{ TFpDebugThreadCommand }
|
||||||
|
|
||||||
procedure TFpDebugThreadCommand.Log(const AString: string; const ALogLevel: TFPDLogLevel);
|
procedure TFpDebugThreadCommand.Log(const AString: string; const ALogLevel: TFPDLogLevel);
|
||||||
@ -228,6 +261,12 @@ begin
|
|||||||
AnEvent.InstructionPointerRegValue:=0;
|
AnEvent.InstructionPointerRegValue:=0;
|
||||||
AnEvent.BreakpointAddr:=0;
|
AnEvent.BreakpointAddr:=0;
|
||||||
AnEvent.LocationRec.Address:=0;
|
AnEvent.LocationRec.Address:=0;
|
||||||
|
AnEvent.Validity:=ddsUnknown;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFpDebugThread.FControllerDebugInfoLoaded(Sender: TObject);
|
||||||
|
begin
|
||||||
|
TFpDwarfInfo(FController.CurrentProcess.DbgInfo).MemManager := FMemManager;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFpDebugThread.FControllerHitBreakpointEvent(var continue: boolean; const Breakpoint: TDbgBreakpoint);
|
procedure TFpDebugThread.FControllerHitBreakpointEvent(var continue: boolean; const Breakpoint: TDbgBreakpoint);
|
||||||
@ -280,6 +319,7 @@ begin
|
|||||||
FController.OnCreateProcessEvent:=@FControllerCreateProcessEvent;
|
FController.OnCreateProcessEvent:=@FControllerCreateProcessEvent;
|
||||||
FController.OnProcessExitEvent:=@FControllerProcessExitEvent;
|
FController.OnProcessExitEvent:=@FControllerProcessExitEvent;
|
||||||
FController.OnHitBreakpointEvent:=@FControllerHitBreakpointEvent;
|
FController.OnHitBreakpointEvent:=@FControllerHitBreakpointEvent;
|
||||||
|
FController.OnDebugInfoLoaded:=@FControllerDebugInfoLoaded;
|
||||||
FController.OnLog:=@SendLogMessage;
|
FController.OnLog:=@SendLogMessage;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -348,6 +388,10 @@ begin
|
|||||||
inherited create(false);
|
inherited create(false);
|
||||||
FCommandQueue := TFpDebugThreadCommandQueue.create(100, INFINITE, 100);
|
FCommandQueue := TFpDebugThreadCommandQueue.create(100, INFINITE, 100);
|
||||||
FListenerList:=TThreadList.Create;
|
FListenerList:=TThreadList.Create;
|
||||||
|
|
||||||
|
FMemReader := TFpDbgMemReader.Create(self);
|
||||||
|
FMemConverter := TFpDbgMemConvertorLittleEndian.Create;
|
||||||
|
FMemManager := TFpDbgMemManager.Create(FMemReader, FMemConverter);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TFpDebugThread.Destroy;
|
destructor TFpDebugThread.Destroy;
|
||||||
@ -355,6 +399,9 @@ begin
|
|||||||
FListenerList.Free;
|
FListenerList.Free;
|
||||||
FCommandQueue.Free;
|
FCommandQueue.Free;
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
|
FMemManager.Free;
|
||||||
|
FMemConverter.Free;
|
||||||
|
FMemReader.Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TFpDebugThread.Instance: TFpDebugThread;
|
class function TFpDebugThread.Instance: TFpDebugThread;
|
||||||
|
@ -11,6 +11,9 @@ uses
|
|||||||
FpDbgClasses,
|
FpDbgClasses,
|
||||||
FpDbgUtil,
|
FpDbgUtil,
|
||||||
FpDbgInfo,
|
FpDbgInfo,
|
||||||
|
FpPascalParser,
|
||||||
|
FpPascalBuilder,
|
||||||
|
FpErrorMessages,
|
||||||
DbgIntfDebuggerBase,
|
DbgIntfDebuggerBase,
|
||||||
DbgIntfBaseTypes,
|
DbgIntfBaseTypes,
|
||||||
strutils,
|
strutils,
|
||||||
@ -160,6 +163,21 @@ type
|
|||||||
property Address: string read GetAddress write SetAddress;
|
property Address: string read GetAddress write SetAddress;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TFpDebugThreadEvaluateCommand }
|
||||||
|
|
||||||
|
TFpDebugThreadEvaluateCommand = class(TFpDebugThreadCommand)
|
||||||
|
private
|
||||||
|
FExpression: string;
|
||||||
|
FResText: string;
|
||||||
|
FValidity: TDebuggerDataState;
|
||||||
|
public
|
||||||
|
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
|
||||||
|
class function TextName: string; override;
|
||||||
|
procedure ComposeSuccessEvent(var AnEvent: TFpDebugEvent); override;
|
||||||
|
published
|
||||||
|
property Expression: string read FExpression write FExpression;
|
||||||
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
{ TFpDebugThreadCommandList }
|
{ TFpDebugThreadCommandList }
|
||||||
@ -167,6 +185,75 @@ implementation
|
|||||||
var
|
var
|
||||||
GFpDebugThreadCommandList: TFpDebugThreadCommandList = nil;
|
GFpDebugThreadCommandList: TFpDebugThreadCommandList = nil;
|
||||||
|
|
||||||
|
{ TFpDebugThreadEvaluateCommand }
|
||||||
|
|
||||||
|
procedure TFpDebugThreadEvaluateCommand.ComposeSuccessEvent(var AnEvent: TFpDebugEvent);
|
||||||
|
begin
|
||||||
|
inherited ComposeSuccessEvent(AnEvent);
|
||||||
|
AnEvent.Message:=FResText;
|
||||||
|
AnEvent.Validity:=FValidity;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFpDebugThreadEvaluateCommand.Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean;
|
||||||
|
var
|
||||||
|
AContext: TFpDbgInfoContext;
|
||||||
|
APasExpr: TFpPascalExpression;
|
||||||
|
ADbgInfo: TDbgInfo;
|
||||||
|
Res: Boolean;
|
||||||
|
APrettyPrinter: TFpPascalPrettyPrinter;
|
||||||
|
ATypeInfo: TDBGType;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
ADbgInfo := AController.CurrentProcess.DbgInfo;
|
||||||
|
AContext := ADbgInfo.FindContext(AController.CurrentThread.ID, 0, AController.CurrentProcess.GetInstructionPointerRegisterValue);
|
||||||
|
if AContext = nil then
|
||||||
|
begin
|
||||||
|
FValidity:=ddsInvalid;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := True;
|
||||||
|
AContext.MemManager.DefaultContext := AContext;
|
||||||
|
APasExpr := TFpPascalExpression.Create(FExpression, AContext);
|
||||||
|
try
|
||||||
|
APasExpr.ResultValue; // trigger full validation
|
||||||
|
if not APasExpr.Valid then
|
||||||
|
begin
|
||||||
|
FResText := ErrorHandler.ErrorAsString(APasExpr.Error);
|
||||||
|
FValidity := ddsError;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
APrettyPrinter := TFpPascalPrettyPrinter.Create(sizeof(pointer));
|
||||||
|
try
|
||||||
|
APrettyPrinter.AddressSize:=AContext.SizeOfAddress;
|
||||||
|
APrettyPrinter.MemManager := AContext.MemManager;
|
||||||
|
Res := APrettyPrinter.PrintValue(FResText, ATypeInfo, APasExpr.ResultValue);
|
||||||
|
if Res then
|
||||||
|
begin
|
||||||
|
FValidity:=ddsValid;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
FResText := 'Error';
|
||||||
|
FValidity:=ddsValid;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
APrettyPrinter.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
APasExpr.Free;
|
||||||
|
AContext.ReleaseReference;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TFpDebugThreadEvaluateCommand.TextName: string;
|
||||||
|
begin
|
||||||
|
result := 'evaluate';
|
||||||
|
end;
|
||||||
|
|
||||||
{ TFpDebugThreadQuitDebugServerCommand }
|
{ TFpDebugThreadQuitDebugServerCommand }
|
||||||
|
|
||||||
function TFpDebugThreadQuitDebugServerCommand.PreExecute(AController: TDbgController; out DoQueueCommand: boolean): boolean;
|
function TFpDebugThreadQuitDebugServerCommand.PreExecute(AController: TDbgController; out DoQueueCommand: boolean): boolean;
|
||||||
@ -474,6 +561,7 @@ initialization
|
|||||||
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadAddBreakpointCommand);
|
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadAddBreakpointCommand);
|
||||||
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadRemoveBreakpointCommand);
|
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadRemoveBreakpointCommand);
|
||||||
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadGetLocationInfoCommand);
|
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadGetLocationInfoCommand);
|
||||||
|
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadEvaluateCommand);
|
||||||
finalization
|
finalization
|
||||||
GFpDebugThreadCommandList.Free;
|
GFpDebugThreadCommandList.Free;
|
||||||
end.
|
end.
|
||||||
|
@ -119,6 +119,8 @@ type
|
|||||||
protected
|
protected
|
||||||
function GetDbgProcess: TDbgProcess; virtual; abstract;
|
function GetDbgProcess: TDbgProcess; virtual; abstract;
|
||||||
public
|
public
|
||||||
|
function ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
|
||||||
|
function ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean; override;
|
||||||
function ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr; AContext: TFpDbgAddressContext): Boolean; override;
|
function ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr; AContext: TFpDbgAddressContext): Boolean; override;
|
||||||
function RegisterSize(ARegNum: Cardinal): Integer; override;
|
function RegisterSize(ARegNum: Cardinal): Integer; override;
|
||||||
end;
|
end;
|
||||||
@ -439,6 +441,17 @@ end;
|
|||||||
|
|
||||||
{ TDbgMemReader }
|
{ TDbgMemReader }
|
||||||
|
|
||||||
|
function TDbgMemReader.ReadMemory(AnAddress: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean;
|
||||||
|
begin
|
||||||
|
result := GetDbgProcess.ReadData(AnAddress, ASize, ADest^);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDbgMemReader.ReadMemoryEx(AnAddress, AnAddressSpace: TDbgPtr; ASize: Cardinal; ADest: Pointer): Boolean;
|
||||||
|
begin
|
||||||
|
Assert(AnAddressSpace>0,'TDbgMemReader.ReadMemoryEx ignores AddressSpace');
|
||||||
|
result := GetDbgProcess.ReadData(AnAddress, ASize, ADest^);
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgMemReader.ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr; AContext: TFpDbgAddressContext): Boolean;
|
function TDbgMemReader.ReadRegister(ARegNum: Cardinal; out AValue: TDbgPtr; AContext: TFpDbgAddressContext): Boolean;
|
||||||
var
|
var
|
||||||
ARegister: TDbgRegisterValue;
|
ARegister: TDbgRegisterValue;
|
||||||
|
Loading…
Reference in New Issue
Block a user