lazarus/components/fpdebug/app/fpdserver/debugthreadcommand.pas

405 lines
11 KiB
ObjectPascal

unit DebugThreadCommand;
{$mode objfpc}{$H+}
interface
uses
Classes,
contnrs,
FPDbgController,
FpDbgClasses,
FpDbgUtil,
FpDbgInfo,
DbgIntfDebuggerBase,
DbgIntfBaseTypes,
strutils,
debugthread,
SysUtils;
type
{ TFpDebugThreadCommandList }
TFpDebugThreadCommandList = class(TFPList)
public
class function instance: TFpDebugThreadCommandList;
function GetCommandByName(ATextName: string): TFpDebugThreadCommandClass;
end;
{ TFpDebugThreadSetFilenameCommand }
TFpDebugThreadSetFilenameCommand = class(TFpDebugThreadCommand)
private
FFileName: string;
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
published
property Filename: string read FFileName write FFileName;
end;
{ TFpDebugThreadRunCommand }
TFpDebugThreadRunCommand = class(TFpDebugThreadCommand)
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
end;
{ TFpDebugThreadContinueCommand }
TFpDebugThreadContinueCommand = class(TFpDebugThreadCommand)
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
end;
{ TFpDebugThreadNextCommand }
TFpDebugThreadNextCommand = class(TFpDebugThreadCommand)
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
end;
{ TFpDebugThreadStepCommand }
TFpDebugThreadStepCommand = class(TFpDebugThreadCommand)
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
end;
{ TFpDebugThreadStepOutCommand }
TFpDebugThreadStepOutCommand = class(TFpDebugThreadCommand)
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
end;
{ TFpDebugThreadStepIntoInstrCommand }
TFpDebugThreadStepIntoInstrCommand = class(TFpDebugThreadCommand)
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
end;
{ TFpDebugThreadStepOverInstrCommand }
TFpDebugThreadStepOverInstrCommand = class(TFpDebugThreadCommand)
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
end;
{ TFpDebugThreadStopCommand }
TFpDebugThreadStopCommand = class(TFpDebugThreadCommand)
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
end;
{ TFpDebugThreadAddBreakpointCommand }
TFpDebugThreadAddBreakpointCommand = class(TFpDebugThreadCommand)
private
FFileName: string;
FLine: integer;
FBreakPoint: FpDbgClasses.TDbgBreakpoint;
public
procedure ComposeSuccessEvent(var AnEvent: TFpDebugEvent); override;
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
published
property Filename: string read FFileName write FFileName;
property Line: integer read FLine write FLine;
end;
{ TFpDebugThreadGetLocationInfoCommand }
TFpDebugThreadGetLocationInfoCommand = class(TFpDebugThreadCommand)
private
FLocationRec: TDBGLocationRec;
FAddressValue: TDBGPtr;
function GetAddress: string;
procedure SetAddress(AValue: string);
protected
procedure ComposeSuccessEvent(var AnEvent: TFpDebugEvent); override;
public
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
class function TextName: string; override;
published
property Address: string read GetAddress write SetAddress;
end;
implementation
{ TFpDebugThreadCommandList }
var
GFpDebugThreadCommandList: TFpDebugThreadCommandList = nil;
{ TFpDebugThreadStopCommand }
function TFpDebugThreadStopCommand.Execute(AController: TDbgController; out
DoProcessLoop: boolean): boolean;
begin
AController.Stop;
DoProcessLoop:=true;
result := true;
end;
class function TFpDebugThreadStopCommand.TextName: string;
begin
result := 'stop';
end;
{ TFpDebugThreadStepOutCommand }
function TFpDebugThreadStepOutCommand.Execute(AController: TDbgController; out
DoProcessLoop: boolean): boolean;
begin
AController.StepOut;
DoProcessLoop:=true;
result := true;
end;
class function TFpDebugThreadStepOutCommand.TextName: string;
begin
result := 'stepout';
end;
{ TFpDebugThreadStepOverInstrCommand }
function TFpDebugThreadStepOverInstrCommand.Execute(
AController: TDbgController; out DoProcessLoop: boolean): boolean;
begin
AController.StepOverInstr;
DoProcessLoop:=true;
result := true;
end;
class function TFpDebugThreadStepOverInstrCommand.TextName: string;
begin
result := 'stepoverinstr';
end;
{ TFpDebugThreadStepIntoInstrCommand }
function TFpDebugThreadStepIntoInstrCommand.Execute(
AController: TDbgController; out DoProcessLoop: boolean): boolean;
begin
AController.StepIntoInstr;
DoProcessLoop:=true;
result := true;
end;
class function TFpDebugThreadStepIntoInstrCommand.TextName: string;
begin
result := 'stepintoinstr';
end;
{ TFpDebugThreadStepCommand }
function TFpDebugThreadStepCommand.Execute(AController: TDbgController; out
DoProcessLoop: boolean): boolean;
begin
AController.Step;
DoProcessLoop:=true;
result := true;
end;
class function TFpDebugThreadStepCommand.TextName: string;
begin
result := 'step';
end;
{ TFpDebugThreadNextCommand }
function TFpDebugThreadNextCommand.Execute(AController: TDbgController; out
DoProcessLoop: boolean): boolean;
begin
AController.Next;
DoProcessLoop:=true;
result := true;
end;
class function TFpDebugThreadNextCommand.TextName: string;
begin
result := 'next';
end;
{ TFpDebugThreadGetLocationInfoCommand }
function TFpDebugThreadGetLocationInfoCommand.GetAddress: string;
begin
result := FormatAddress(FAddressValue);
end;
procedure TFpDebugThreadGetLocationInfoCommand.SetAddress(AValue: string);
begin
FAddressValue := Hex2Dec(AValue);
end;
procedure TFpDebugThreadGetLocationInfoCommand.ComposeSuccessEvent(var AnEvent: TFpDebugEvent);
begin
inherited ComposeSuccessEvent(AnEvent);
AnEvent.LocationRec:=FLocationRec;
end;
function TFpDebugThreadGetLocationInfoCommand.Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean;
var
sym, symproc: TFpDbgSymbol;
begin
DoProcessLoop:=false;
result := false;
if Assigned(AController.CurrentProcess) then
begin
FLocationRec.FuncName:='';
FLocationRec.SrcFile:='';
FLocationRec.SrcFullName:='';
FLocationRec.SrcLine:=0;
if FAddressValue=0 then
FLocationRec.Address := AController.CurrentProcess.GetInstructionPointerRegisterValue
else
FLocationRec.Address := FAddressValue;
sym := AController.CurrentProcess.FindSymbol(FLocationRec.Address);
if sym = nil then
Exit;
FLocationRec.SrcFile := ExtractFileName(sym.FileName);
FLocationRec.SrcLine := sym.Line;
FLocationRec.SrcFullName := sym.FileName;
symproc := sym;
while not (symproc.kind in [skProcedure, skFunction]) do
symproc := symproc.Parent;
if assigned(symproc) then
FLocationRec.FuncName:=symproc.Name;
sym.free;
result := true;
end;
end;
class function TFpDebugThreadGetLocationInfoCommand.TextName: string;
begin
result := 'getlocationinfo'
end;
{ TFpDebugThreadAddBreakpointCommand }
procedure TFpDebugThreadAddBreakpointCommand.ComposeSuccessEvent(var AnEvent: TFpDebugEvent);
begin
inherited ComposeSuccessEvent(AnEvent);
AnEvent.BreakpointAddr:=FBreakPoint.Location;
end;
function TFpDebugThreadAddBreakpointCommand.Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean;
begin
result := false;
DoProcessLoop:=false;
if not assigned(AController.CurrentProcess) then
begin
log('Failed to add breakpoint: No process', dllInfo);
exit;
end;
if (Filename<>'') and (line>-1) then
begin
FBreakPoint := AController.CurrentProcess.AddBreak(FileName, Line);
result := assigned(FBreakPoint);
end
else
log('Failed to add breakpoint: No filename and line-number given', dllInfo);
end;
class function TFpDebugThreadAddBreakpointCommand.TextName: string;
begin
result := 'breakpoint';
end;
class function TFpDebugThreadCommandList.instance: TFpDebugThreadCommandList;
begin
if not assigned(GFpDebugThreadCommandList) then
GFpDebugThreadCommandList := TFpDebugThreadCommandList.Create;
result := GFpDebugThreadCommandList;
end;
function TFpDebugThreadCommandList.GetCommandByName(ATextName: string): TFpDebugThreadCommandClass;
var
i: Integer;
begin
result := nil;
for i := 0 to count -1 do
begin
if TFpDebugThreadCommandClass(Items[i]).TextName=ATextName then
result := TFpDebugThreadCommandClass(Items[i]);
end;
end;
{ TFpDebugThreadContinueCommand }
function TFpDebugThreadContinueCommand.Execute(AController: TDbgController; out
DoProcessLoop: boolean): boolean;
begin
DoProcessLoop:=true;
result := true;
end;
class function TFpDebugThreadContinueCommand.TextName: string;
begin
result := 'continue';
end;
{ TFpDebugThreadRunCommand }
function TFpDebugThreadRunCommand.Execute(AController: TDbgController; out
DoProcessLoop: boolean): boolean;
begin
DoProcessLoop := AController.Run;
result := DoProcessLoop;
end;
class function TFpDebugThreadRunCommand.TextName: string;
begin
result := 'run';
end;
{ TFpDebugThreadSetFilenameCommand }
function TFpDebugThreadSetFilenameCommand.Execute(AController: TDbgController;
out DoProcessLoop: boolean): boolean;
begin
AController.ExecutableFilename:=FFileName;
DoProcessLoop:=false;
result:=true;
end;
class function TFpDebugThreadSetFilenameCommand.TextName: string;
begin
result := 'filename'
end;
initialization
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadSetFilenameCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadRunCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadContinueCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadStepOverInstrCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadStepIntoInstrCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadNextCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadStepCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadStepOutCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadStopCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadAddBreakpointCommand);
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadGetLocationInfoCommand);
finalization
GFpDebugThreadCommandList.Free;
end.