gdbmiproc.pas 3.1 KB

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