gdbmiproc.pas 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. {
  2. Copyright (c) 2015 by Nikolay Nikolov
  3. This unit implements a class, which launches gdb in GDB/MI mode
  4. and allows sending textual commands to it and receiving the response
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit GDBMIProc;
  12. {$MODE objfpc}
  13. {$I globdir.inc}
  14. {$H+}
  15. interface
  16. uses
  17. SysUtils, Classes, Process;
  18. type
  19. TGDBProcess = class
  20. private
  21. FProcess: TProcess;
  22. FDebugLog: TextFile;
  23. function IsAlive: Boolean;
  24. procedure GDBWrite(const S: string);
  25. procedure DebugLn(const S: string);
  26. procedure DebugErrorLn(const S: string);
  27. public
  28. constructor Create;
  29. destructor Destroy; override;
  30. function GDBReadLn: string;
  31. procedure GDBWriteLn(const S: string);
  32. property Alive: Boolean read IsAlive;
  33. end;
  34. var
  35. GdbProgramName: string = 'gdb';
  36. implementation
  37. uses
  38. fputils;
  39. var
  40. DebugLogEnabled: Boolean = False;
  41. function TGDBProcess.IsAlive: Boolean;
  42. begin
  43. Result := Assigned(FProcess) and FProcess.Running;
  44. end;
  45. function TGDBProcess.GDBReadLn: string;
  46. var
  47. C: AnsiChar;
  48. begin
  49. Result := '';
  50. while FProcess.Running do
  51. begin
  52. FProcess.Output.Read(C, 1);
  53. {$ifdef windows}
  54. { On windows we expect both #13#10 and #10 }
  55. if C = #13 then
  56. begin
  57. FProcess.Output.Read(C, 1);
  58. if C <> #10 then
  59. { #13 not followed by #10, what should we do? }
  60. Result := Result + #13;
  61. end;
  62. {$endif windows}
  63. if C = #10 then
  64. begin
  65. DebugLn(Result);
  66. exit;
  67. end;
  68. Result := Result + C;
  69. end;
  70. end;
  71. constructor TGDBProcess.Create;
  72. begin
  73. if DebugLogEnabled then
  74. begin
  75. AssignFile(FDebugLog, 'gdblog.txt');
  76. Rewrite(FDebugLog);
  77. CloseFile(FDebugLog);
  78. end;
  79. FProcess := TProcess.Create(nil);
  80. FProcess.Options := [poUsePipes, poStdErrToOutput];
  81. if (ExeExt<>'') and (pos(ExeExt,LowerCaseStr(GdbProgramName))=0) then
  82. FProcess.Executable := GdbProgramName+ExeExt
  83. else
  84. FProcess.Executable := GdbProgramName;
  85. FProcess.Parameters.Add('--interpreter=mi');
  86. try
  87. FProcess.Execute;
  88. except
  89. on e: Exception do
  90. begin
  91. DebugErrorLn('Could not start GDB: ' + e.Message);
  92. FreeAndNil(FProcess);
  93. end;
  94. end;
  95. end;
  96. destructor TGDBProcess.Destroy;
  97. begin
  98. FProcess.Free;
  99. inherited Destroy;
  100. end;
  101. procedure TGDBProcess.DebugLn(const S: string);
  102. begin
  103. if DebugLogEnabled then
  104. begin
  105. Append(FDebugLog);
  106. Writeln(FDebugLog, S);
  107. CloseFile(FDebugLog);
  108. end;
  109. end;
  110. procedure TGDBProcess.DebugErrorLn(const S: string);
  111. begin
  112. DebugLn('ERROR: ' + S);
  113. end;
  114. procedure TGDBProcess.GDBWrite(const S: string);
  115. begin
  116. FProcess.Input.Write(S[1], Length(S));
  117. end;
  118. procedure TGDBProcess.GDBWriteln(const S: string);
  119. begin
  120. if not IsAlive then
  121. begin
  122. DebugErrorLn('Trying to send command to a dead GDB: ' + S);
  123. exit;
  124. end;
  125. DebugLn(S);
  126. GDBWrite(S + #10);
  127. end;
  128. begin
  129. if GetEnvironmentVariable('FPIDE_GDBLOG') = '1' then
  130. DebugLogEnabled := True;
  131. if GetEnvironmentVariable('FPIDE_GDBPROG') <> '' then
  132. GdbProgramName := GetEnvironmentVariable('FPIDE_GDBPROG');
  133. end.