mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-11 09:53:03 +01:00
FpDebugger (pure): Use a pseudo-terminal instead of pipes to read the debuggees out- and in-put
git-svn-id: trunk@46070 -
This commit is contained in:
parent
428a961779
commit
bdbccce289
@ -288,6 +288,7 @@ type
|
|||||||
|
|
||||||
function CheckForConsoleOutput(ATimeOutMs: integer): integer; virtual;
|
function CheckForConsoleOutput(ATimeOutMs: integer): integer; virtual;
|
||||||
function GetConsoleOutput: string; virtual;
|
function GetConsoleOutput: string; virtual;
|
||||||
|
procedure SendConsoleInput(AString: string); virtual;
|
||||||
|
|
||||||
function AddThread(AThreadIdentifier: THandle): TDbgThread;
|
function AddThread(AThreadIdentifier: THandle): TDbgThread;
|
||||||
procedure LoadInfo; override;
|
procedure LoadInfo; override;
|
||||||
@ -849,6 +850,11 @@ begin
|
|||||||
result := '';
|
result := '';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TDbgProcess.SendConsoleInput(AString: string);
|
||||||
|
begin
|
||||||
|
// Do nothing
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgProcess.AddThread(AThreadIdentifier: THandle): TDbgThread;
|
function TDbgProcess.AddThread(AThreadIdentifier: THandle): TDbgThread;
|
||||||
var
|
var
|
||||||
IsMainThread: boolean;
|
IsMainThread: boolean;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ uses
|
|||||||
Classes,
|
Classes,
|
||||||
SysUtils,
|
SysUtils,
|
||||||
BaseUnix,
|
BaseUnix,
|
||||||
|
termio,
|
||||||
process,
|
process,
|
||||||
FpDbgClasses,
|
FpDbgClasses,
|
||||||
FpDbgLoader,
|
FpDbgLoader,
|
||||||
@ -159,6 +160,8 @@ type
|
|||||||
u_debugreg : array[0..7] of longint;
|
u_debugreg : array[0..7] of longint;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function login_tty(__fd:longint):longint;cdecl;external 'c' name 'login_tty';
|
||||||
|
function openpty(__amaster:Plongint; __aslave:Plongint; __name:Pchar; __termp:pointer{Ptermios}; __winp:pointer{Pwinsize}):longint;cdecl;external 'util' name 'openpty';
|
||||||
|
|
||||||
const
|
const
|
||||||
R15 = 0;
|
R15 = 0;
|
||||||
@ -245,6 +248,7 @@ type
|
|||||||
FProcProcess: TProcess;
|
FProcProcess: TProcess;
|
||||||
FIsTerminating: boolean;
|
FIsTerminating: boolean;
|
||||||
FExceptionSignal: PtrUInt;
|
FExceptionSignal: PtrUInt;
|
||||||
|
FMasterPtyFd: cint;
|
||||||
{$ifndef VER2_6}
|
{$ifndef VER2_6}
|
||||||
procedure OnForkEvent(Sender : TObject);
|
procedure OnForkEvent(Sender : TObject);
|
||||||
{$endif}
|
{$endif}
|
||||||
@ -262,6 +266,7 @@ type
|
|||||||
|
|
||||||
function CheckForConsoleOutput(ATimeOutMs: integer): integer; override;
|
function CheckForConsoleOutput(ATimeOutMs: integer): integer; override;
|
||||||
function GetConsoleOutput: string; override;
|
function GetConsoleOutput: string; override;
|
||||||
|
procedure SendConsoleInput(AString: string); override;
|
||||||
|
|
||||||
function GetInstructionPointerRegisterValue: TDbgPtr; override;
|
function GetInstructionPointerRegisterValue: TDbgPtr; override;
|
||||||
function GetStackPointerRegisterValue: TDbgPtr; override;
|
function GetStackPointerRegisterValue: TDbgPtr; override;
|
||||||
@ -277,6 +282,9 @@ procedure RegisterDbgClasses;
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
var
|
||||||
|
GSlavePtyFd: cint;
|
||||||
|
|
||||||
procedure RegisterDbgClasses;
|
procedure RegisterDbgClasses;
|
||||||
begin
|
begin
|
||||||
OSDbgClasses.DbgProcessClass:=TDbgLinuxProcess;
|
OSDbgClasses.DbgProcessClass:=TDbgLinuxProcess;
|
||||||
@ -298,12 +306,19 @@ procedure OnForkEvent;
|
|||||||
var
|
var
|
||||||
e: integer;
|
e: integer;
|
||||||
begin
|
begin
|
||||||
|
login_tty(GSlavePtyFd);
|
||||||
|
e := fpgeterrno;
|
||||||
|
if e <> 0 then
|
||||||
|
begin
|
||||||
|
writeln('Failed to login to pty. Errcode: '+inttostr(e)+' - '+inttostr(GSlavePtyFd));
|
||||||
|
end;
|
||||||
|
|
||||||
fpPTrace(PTRACE_TRACEME, 0, nil, nil);
|
fpPTrace(PTRACE_TRACEME, 0, nil, nil);
|
||||||
e := fpgeterrno;
|
e := fpgeterrno;
|
||||||
if e <> 0 then
|
if e <> 0 then
|
||||||
begin
|
begin
|
||||||
writeln('Failed to start trace of process. Errcode: '+inttostr(e));
|
writeln('Failed to start trace of process. Errcode: '+inttostr(e));
|
||||||
end
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbgLinuxThread.GetDebugRegOffset(ind: byte): pointer;
|
function TDbgLinuxThread.GetDebugRegOffset(ind: byte): pointer;
|
||||||
@ -542,12 +557,15 @@ end;
|
|||||||
constructor TDbgLinuxProcess.Create(const AName: string; const AProcessID,
|
constructor TDbgLinuxProcess.Create(const AName: string; const AProcessID,
|
||||||
AThreadID: Integer; AOnLog: TOnLog);
|
AThreadID: Integer; AOnLog: TOnLog);
|
||||||
begin
|
begin
|
||||||
|
FMasterPtyFd:=-1;
|
||||||
inherited Create(AName, AProcessID, AThreadID, AOnLog);
|
inherited Create(AName, AProcessID, AThreadID, AOnLog);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TDbgLinuxProcess.Destroy;
|
destructor TDbgLinuxProcess.Destroy;
|
||||||
begin
|
begin
|
||||||
FProcProcess.Free;
|
FProcProcess.Free;
|
||||||
|
if FMasterPtyFd>-1 then
|
||||||
|
FpClose(FMasterPtyFd);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -555,6 +573,7 @@ class function TDbgLinuxProcess.StartInstance(AFileName: string; AParams, AnEnvi
|
|||||||
var
|
var
|
||||||
PID: TPid;
|
PID: TPid;
|
||||||
AProcess: TProcess;
|
AProcess: TProcess;
|
||||||
|
AMasterPtyFd: cint;
|
||||||
AnExecutabeFilename: string;
|
AnExecutabeFilename: string;
|
||||||
begin
|
begin
|
||||||
result := nil;
|
result := nil;
|
||||||
@ -579,12 +598,14 @@ begin
|
|||||||
AProcess.Parameters:=AParams;
|
AProcess.Parameters:=AParams;
|
||||||
AProcess.Environment:=AnEnvironment;
|
AProcess.Environment:=AnEnvironment;
|
||||||
AProcess.CurrentDirectory:=AWorkingDirectory;
|
AProcess.CurrentDirectory:=AWorkingDirectory;
|
||||||
AProcess.Options := AProcess.Options + [poUsePipes];
|
if openpty(@AMasterPtyFd, @GSlavePtyFd, nil, nil, nil) <> 0 then
|
||||||
|
AOnLog('Failed to open new pty. Errcode: '+inttostr(fpgeterrno), dllDebug);
|
||||||
AProcess.Execute;
|
AProcess.Execute;
|
||||||
PID:=AProcess.ProcessID;
|
PID:=AProcess.ProcessID;
|
||||||
|
|
||||||
sleep(100);
|
sleep(100);
|
||||||
result := TDbgLinuxProcess.Create(AFileName, Pid, -1, AOnLog);
|
result := TDbgLinuxProcess.Create(AFileName, Pid, -1, AOnLog);
|
||||||
|
TDbgLinuxProcess(result).FMasterPtyFd := AMasterPtyFd;
|
||||||
TDbgLinuxProcess(result).FProcProcess := AProcess;
|
TDbgLinuxProcess(result).FProcProcess := AProcess;
|
||||||
except
|
except
|
||||||
on E: Exception do
|
on E: Exception do
|
||||||
@ -714,24 +735,34 @@ begin
|
|||||||
sleepytime.tv_sec := ATimeOutMs div 1000;
|
sleepytime.tv_sec := ATimeOutMs div 1000;
|
||||||
sleepytime.tv_usec := (ATimeOutMs mod 1000)*1000;
|
sleepytime.tv_usec := (ATimeOutMs mod 1000)*1000;
|
||||||
FpFD_ZERO(f);
|
FpFD_ZERO(f);
|
||||||
fpFD_SET(FProcProcess.Output.Handle,f);
|
fpFD_SET(FMasterPtyFd,f);
|
||||||
result := fpselect(FProcProcess.Output.Handle+1,@f,nil,nil,@sleepytime);
|
result := fpselect(FMasterPtyFd+1,@f,nil,nil,@sleepytime);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDbgLinuxProcess.GetConsoleOutput: string;
|
function TDbgLinuxProcess.GetConsoleOutput: string;
|
||||||
var
|
var
|
||||||
ABytesAvailable: DWord;
|
ABytesAvailable: DWord;
|
||||||
|
ABytesRead: cint;
|
||||||
begin
|
begin
|
||||||
ABytesAvailable := FProcProcess.Output.NumBytesAvailable;
|
if fpioctl(FMasterPtyFd, FIONREAD, @ABytesAvailable)<0 then
|
||||||
|
ABytesAvailable := 0;
|
||||||
|
|
||||||
if ABytesAvailable>0 then
|
if ABytesAvailable>0 then
|
||||||
begin
|
begin
|
||||||
setlength(result, ABytesAvailable);
|
setlength(result, ABytesAvailable);
|
||||||
FProcProcess.Output.Read(result[1], ABytesAvailable);
|
ABytesRead := fpRead(FMasterPtyFd, result[1], ABytesAvailable);
|
||||||
|
SetLength(result, ABytesRead);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
result := '';
|
result := '';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TDbgLinuxProcess.SendConsoleInput(AString: string);
|
||||||
|
begin
|
||||||
|
if FpWrite(FMasterPtyFd, AString[1], length(AString)) <> Length(AString) then
|
||||||
|
Log('Failed to send input to console.', dllDebug);
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgLinuxProcess.GetInstructionPointerRegisterValue: TDbgPtr;
|
function TDbgLinuxProcess.GetInstructionPointerRegisterValue: TDbgPtr;
|
||||||
begin
|
begin
|
||||||
if Mode=dm32 then
|
if Mode=dm32 then
|
||||||
|
|||||||
@ -297,8 +297,8 @@ var
|
|||||||
begin
|
begin
|
||||||
if (Data=0) or assigned(TFpDebugDebugger(Data).FConsoleOutputThread) then
|
if (Data=0) or assigned(TFpDebugDebugger(Data).FConsoleOutputThread) then
|
||||||
begin
|
begin
|
||||||
RTLeventSetEvent(FHasConsoleOutputQueued);
|
|
||||||
s := FFpDebugDebugger.FDbgController.CurrentProcess.GetConsoleOutput;
|
s := FFpDebugDebugger.FDbgController.CurrentProcess.GetConsoleOutput;
|
||||||
|
RTLeventSetEvent(FHasConsoleOutputQueued);
|
||||||
FFpDebugDebugger.OnConsoleOutput(self, s);
|
FFpDebugDebugger.OnConsoleOutput(self, s);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -1482,6 +1482,10 @@ begin
|
|||||||
String(AParams[1].VPointer^), TDBGType(AParams[2].VPointer^),
|
String(AParams[1].VPointer^), TDBGType(AParams[2].VPointer^),
|
||||||
EvalFlags);
|
EvalFlags);
|
||||||
end;
|
end;
|
||||||
|
dcSendConsoleInput:
|
||||||
|
begin
|
||||||
|
FDbgController.CurrentProcess.SendConsoleInput(String(AParams[0].VAnsiString));
|
||||||
|
end;
|
||||||
end; {case}
|
end; {case}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1740,7 +1744,7 @@ end;
|
|||||||
function TFpDebugDebugger.GetSupportedCommands: TDBGCommands;
|
function TFpDebugDebugger.GetSupportedCommands: TDBGCommands;
|
||||||
begin
|
begin
|
||||||
Result:=[dcRun, dcStop, dcStepIntoInstr, dcStepOverInstr, dcStepOver,
|
Result:=[dcRun, dcStop, dcStepIntoInstr, dcStepOverInstr, dcStepOver,
|
||||||
dcRunTo, dcPause, dcStepOut, dcStepInto, dcEvaluate];
|
dcRunTo, dcPause, dcStepOut, dcStepInto, dcEvaluate, dcSendConsoleInput];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user