123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- {
- Copyright (c) 2015 by Nikolay Nikolov
- This unit implements a class, which launches gdb in GDB/MI mode
- and allows sending textual commands to it and receiving the response
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit GDBMIProc;
- {$MODE objfpc}{$H+}
- {$I globdir.inc}
- interface
- uses
- SysUtils, Classes, Process;
- type
- TGDBProcess = class
- private
- FProcess: TProcess;
- FDebugLog: TextFile;
- function IsAlive: Boolean;
- procedure GDBWrite(const S: string);
- procedure DebugLn(const S: string);
- procedure DebugErrorLn(const S: string);
- public
- constructor Create;
- destructor Destroy; override;
- function GDBReadLn: string;
- procedure GDBWriteLn(const S: string);
- property Alive: Boolean read IsAlive;
- end;
- var
- GdbProgramName: string = 'gdb';
- implementation
- uses
- fputils;
- var
- DebugLogEnabled: Boolean = False;
- function TGDBProcess.IsAlive: Boolean;
- begin
- Result := Assigned(FProcess) and FProcess.Running;
- end;
- function TGDBProcess.GDBReadLn: string;
- var
- C: Char;
- begin
- Result := '';
- while FProcess.Running do
- begin
- FProcess.Output.Read(C, 1);
- {$ifdef windows}
- { On windows we expect both #13#10 and #10 }
- if C = #13 then
- begin
- FProcess.Output.Read(C, 1);
- if C <> #10 then
- { #13 not followed by #10, what should we do? }
- Result := Result + #13;
- end;
- {$endif windows}
- if C = #10 then
- begin
- DebugLn(Result);
- exit;
- end;
- Result := Result + C;
- end;
- end;
- constructor TGDBProcess.Create;
- begin
- if DebugLogEnabled then
- begin
- AssignFile(FDebugLog, 'gdblog.txt');
- Rewrite(FDebugLog);
- CloseFile(FDebugLog);
- end;
- FProcess := TProcess.Create(nil);
- FProcess.Options := [poUsePipes, poStdErrToOutput];
- if (ExeExt<>'') and (pos(ExeExt,LowerCaseStr(GdbProgramName))=0) then
- FProcess.Executable := GdbProgramName+ExeExt
- else
- FProcess.Executable := GdbProgramName;
- FProcess.Parameters.Add('--interpreter=mi');
- try
- FProcess.Execute;
- except
- on e: Exception do
- begin
- DebugErrorLn('Could not start GDB: ' + e.Message);
- FreeAndNil(FProcess);
- end;
- end;
- end;
- destructor TGDBProcess.Destroy;
- begin
- FProcess.Free;
- inherited Destroy;
- end;
- procedure TGDBProcess.DebugLn(const S: string);
- begin
- if DebugLogEnabled then
- begin
- Append(FDebugLog);
- Writeln(FDebugLog, S);
- CloseFile(FDebugLog);
- end;
- end;
- procedure TGDBProcess.DebugErrorLn(const S: string);
- begin
- DebugLn('ERROR: ' + S);
- end;
- procedure TGDBProcess.GDBWrite(const S: string);
- begin
- FProcess.Input.Write(S[1], Length(S));
- end;
- procedure TGDBProcess.GDBWriteln(const S: string);
- begin
- if not IsAlive then
- begin
- DebugErrorLn('Trying to send command to a dead GDB: ' + S);
- exit;
- end;
- DebugLn(S);
- GDBWrite(S + #10);
- end;
- begin
- if GetEnvironmentVariable('FPIDE_GDBLOG') = '1' then
- DebugLogEnabled := True;
- if GetEnvironmentVariable('FPIDE_GDBPROG') <> '' then
- GdbProgramName := GetEnvironmentVariable('FPIDE_GDBPROG');
- end.
|