2
0

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