gdbmiproc.pas 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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}{$H+}
  13. {$I globdir.inc}
  14. interface
  15. uses
  16. SysUtils, Classes, Process;
  17. type
  18. TGDBProcess = class
  19. private
  20. FProcess: TProcess;
  21. FDebugLog: TextFile;
  22. function IsAlive: Boolean;
  23. procedure GDBWrite(const S: string);
  24. procedure DebugLn(const S: string);
  25. procedure DebugErrorLn(const S: string);
  26. public
  27. constructor Create;
  28. destructor Destroy; override;
  29. function GDBReadLn: string;
  30. procedure GDBWriteLn(const S: string);
  31. property Alive: Boolean read IsAlive;
  32. end;
  33. var
  34. GdbProgramName: string = 'gdb';
  35. implementation
  36. var
  37. DebugLogEnabled: Boolean = False;
  38. function TGDBProcess.IsAlive: Boolean;
  39. begin
  40. Result := Assigned(FProcess) and FProcess.Running;
  41. end;
  42. function TGDBProcess.GDBReadLn: string;
  43. var
  44. C: Char;
  45. begin
  46. Result := '';
  47. while FProcess.Running do
  48. begin
  49. FProcess.Output.Read(C, 1);
  50. {$ifdef windows}
  51. { On windows we expect both #13#10 and #10 }
  52. if C = #13 then
  53. begin
  54. FProcess.Output.Read(C, 1);
  55. if C <> #10 then
  56. { #13 not followed by #10, what should we do? }
  57. Result := Result + #13;
  58. end;
  59. {$endif windows}
  60. if C = #10 then
  61. begin
  62. DebugLn(Result);
  63. exit;
  64. end;
  65. Result := Result + C;
  66. end;
  67. end;
  68. constructor TGDBProcess.Create;
  69. begin
  70. if DebugLogEnabled then
  71. begin
  72. AssignFile(FDebugLog, 'gdblog.txt');
  73. Rewrite(FDebugLog);
  74. CloseFile(FDebugLog);
  75. end;
  76. FProcess := TProcess.Create(nil);
  77. FProcess.Options := [poUsePipes, poStdErrToOutput];
  78. FProcess.Executable := GdbProgramName;
  79. FProcess.Parameters.Add('--interpreter=mi');
  80. try
  81. FProcess.Execute;
  82. except
  83. on e: Exception do
  84. begin
  85. DebugErrorLn('Could not start GDB: ' + e.Message);
  86. FreeAndNil(FProcess);
  87. end;
  88. end;
  89. end;
  90. destructor TGDBProcess.Destroy;
  91. begin
  92. FProcess.Free;
  93. inherited Destroy;
  94. end;
  95. procedure TGDBProcess.DebugLn(const S: string);
  96. begin
  97. if DebugLogEnabled then
  98. begin
  99. Append(FDebugLog);
  100. Writeln(FDebugLog, S);
  101. CloseFile(FDebugLog);
  102. end;
  103. end;
  104. procedure TGDBProcess.DebugErrorLn(const S: string);
  105. begin
  106. DebugLn('ERROR: ' + S);
  107. end;
  108. procedure TGDBProcess.GDBWrite(const S: string);
  109. begin
  110. FProcess.Input.Write(S[1], Length(S));
  111. end;
  112. procedure TGDBProcess.GDBWriteln(const S: string);
  113. begin
  114. if not IsAlive then
  115. begin
  116. DebugErrorLn('Trying to send command to a dead GDB: ' + S);
  117. exit;
  118. end;
  119. DebugLn(S);
  120. GDBWrite(S + #10);
  121. end;
  122. begin
  123. if GetEnvironmentVariable('FPIDE_GDBLOG') = '1' then
  124. DebugLogEnabled := True;
  125. if GetEnvironmentVariable('FPIDE_GDBPROG') <> '' then
  126. GdbProgramName := GetEnvironmentVariable('FPIDE_GDBPROG');
  127. end.