gdbcon.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. {
  2. Copyright (c) 1998 by Peter Vreman
  3. Lowlevel GDB interface which communicates directly with libgdb
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$IFNDEF FPC_DOTTEDUNITS}
  11. unit GDBCon;
  12. {$ENDIF FPC_DOTTEDUNITS}
  13. {$ifdef USE_GDBLIBINC}
  14. {$i gdblib.inc}
  15. {$else not USE_GDBLIBINC}
  16. {$i gdbver.inc}
  17. {$endif not USE_GDBLIBINC}
  18. interface
  19. {$IFDEF FPC_DOTTEDUNITS}
  20. uses
  21. Api.Gdbint;
  22. {$ELSE FPC_DOTTEDUNITS}
  23. uses
  24. GDBInt;
  25. {$ENDIF FPC_DOTTEDUNITS}
  26. type
  27. TBreakpointFlags = set of (bfTemporary, bfHardware);
  28. TWatchpointType = (wtWrite, wtReadWrite, wtRead);
  29. TPrintFormatType = (pfbinary, pfdecimal, pfhexadecimal, pfoctal, pfnatural);
  30. PGDBController=^TGDBController;
  31. TGDBController=object(TGDBInterface)
  32. private
  33. SavedWindowWidth : longint;
  34. { width }
  35. procedure MaxWidth;
  36. procedure NormWidth;
  37. { print }
  38. function InternalGetValue(Const expr : ShortString) : AnsiString;
  39. public
  40. progname,
  41. progdir,
  42. progargs : PAnsiChar;
  43. TBreakNumber,
  44. start_break_number,
  45. in_command,
  46. init_count : longint;
  47. constructor Init;
  48. destructor Done;
  49. procedure CommandBegin(const s:ShortString);virtual;
  50. procedure Command(const s:ShortString);
  51. procedure CommandEnd(const s:ShortString);virtual;
  52. procedure Reset;virtual;
  53. { tracing }
  54. procedure StartTrace;
  55. procedure Run;virtual;
  56. procedure TraceStep;virtual;
  57. procedure TraceNext;virtual;
  58. procedure TraceStepI;virtual;
  59. procedure TraceNextI;virtual;
  60. procedure Continue;virtual;
  61. procedure UntilReturn;virtual;
  62. { registers }
  63. function GetIntRegister(const RegName: ShortString; var Value: UInt64): Boolean;
  64. function GetIntRegister(const RegName: ShortString; var Value: Int64): Boolean;
  65. function GetIntRegister(const RegName: ShortString; var Value: UInt32): Boolean;
  66. function GetIntRegister(const RegName: ShortString; var Value: Int32): Boolean;
  67. function GetIntRegister(const RegName: ShortString; var Value: UInt16): Boolean;
  68. function GetIntRegister(const RegName: ShortString; var Value: Int16): Boolean;
  69. { set command }
  70. function SetCommand(Const SetExpr : ShortString) : boolean;
  71. { print }
  72. function PrintCommand(const expr : ShortString): AnsiString;
  73. function PrintFormattedCommand(const expr : ShortString; Format : TPrintFormatType): AnsiString;
  74. { breakpoints }
  75. function BreakpointInsert(const location: ShortString; BreakpointFlags: TBreakpointFlags): LongInt;
  76. function WatchpointInsert(const location: ShortString; WatchpointType: TWatchpointType): LongInt;
  77. function BreakpointDelete(BkptNo: LongInt): Boolean;
  78. function BreakpointEnable(BkptNo: LongInt): Boolean;
  79. function BreakpointDisable(BkptNo: LongInt): Boolean;
  80. function BreakpointCondition(BkptNo: LongInt; const ConditionExpr: ShortString): Boolean;
  81. function BreakpointSetIgnoreCount(BkptNo: LongInt; const IgnoreCount: LongInt): Boolean;
  82. procedure SetTBreak(tbreakstring : ShortString);
  83. { frame commands }
  84. procedure Backtrace;
  85. function SelectFrameCommand(level :longint) : boolean;
  86. { needed for dos because newlines are only #10 (PM) }
  87. procedure WriteErrorBuf;
  88. procedure WriteOutputBuf;
  89. function GetOutput : PAnsiChar;
  90. function GetError : PAnsiChar;
  91. function LoadFile(var fn:ShortString):boolean;
  92. procedure SetDir(const s : ShortString);
  93. procedure SetArgs(const s : ShortString);
  94. procedure ClearSymbols;
  95. end;
  96. procedure UnixDir(var s : ShortString);
  97. implementation
  98. {$IFDEF FPC_DOTTEDUNITS}
  99. uses
  100. {$ifdef win32}
  101. WinApi.Windows,
  102. {$endif win32}
  103. TP.DOS,
  104. System.Strings;
  105. {$ELSE FPC_DOTTEDUNITS}
  106. uses
  107. {$ifdef win32}
  108. windows,
  109. {$endif win32}
  110. dos,
  111. strings;
  112. {$ENDIF FPC_DOTTEDUNITS}
  113. {$ifdef win32}
  114. const
  115. CygDrivePrefixKey1 = 'Software';
  116. CygDrivePrefixKey2 = 'Cygnus Solutions';
  117. CygDrivePrefixKey3 = 'Cygwin';
  118. CygDrivePrefixKey4 = 'mounts v2';
  119. CygDrivePrefixKey = 'cygdrive prefix';
  120. function CygDrivePrefix : ShortString;
  121. var
  122. i : longint;
  123. length : dword;
  124. Value : PAnsiChar;
  125. _type : dword;
  126. Key,NKey : HKey;
  127. begin
  128. Length:=0;
  129. Key:=HKEY_CURRENT_USER;
  130. i := RegOpenKeyEx(Key, CygDrivePrefixKey1, 0, KEY_ENUMERATE_SUB_KEYS, @NKey);
  131. if i=ERROR_SUCCESS then
  132. begin
  133. Key:=NKey;
  134. i := RegOpenKeyEx(Key, CygDrivePrefixKey2, 0, KEY_ENUMERATE_SUB_KEYS, @NKey);
  135. end;
  136. if i=ERROR_SUCCESS then
  137. begin
  138. RegCloseKey(Key);
  139. Key:=NKey;
  140. i := RegOpenKeyEx(Key, CygDrivePrefixKey3, 0, KEY_ENUMERATE_SUB_KEYS, @NKey);
  141. end;
  142. if i=ERROR_SUCCESS then
  143. begin
  144. RegCloseKey(Key);
  145. Key:=NKey;
  146. i := RegOpenKeyEx(Key, CygDrivePrefixKey4, 0, KEY_ENUMERATE_SUB_KEYS, @NKey);
  147. end;
  148. if i=ERROR_SUCCESS then
  149. begin
  150. RegCloseKey(Key);
  151. Key:=NKey;
  152. i := RegQueryValueEx( Key, CygDrivePrefixKey, nil, @_type, nil, @length);
  153. end;
  154. if i<>ERROR_SUCCESS then
  155. CygDrivePrefix:='/cygdrive'
  156. else
  157. Begin
  158. GetMem(Value,Length);
  159. i := RegQueryValueEx( Key, CygDrivePrefixKey, nil, @_type, LPByte(Value), @length);
  160. if i<>ERROR_SUCCESS then
  161. CygDrivePrefix:='/cygdrive'
  162. else
  163. CygDrivePrefix:=StrPas(Value);
  164. FreeMem(Value,Length);
  165. End;
  166. if Key<>HKEY_CURRENT_USER then
  167. RegCloseKey(Key);
  168. end;
  169. {$endif win32}
  170. procedure UnixDir(var s : ShortString);
  171. var i : longint;
  172. begin
  173. for i:=1 to length(s) do
  174. if s[i]='\' then
  175. {$ifdef win32}
  176. { Don't touch at '\ ' used to escapes spaces in windows file names PM }
  177. if (i=length(s)) or (s[i+1]<>' ') then
  178. {$endif win32}
  179. s[i]:='/';
  180. {$ifdef win32}
  181. {$ifndef USE_MINGW_GDB}
  182. { for win32 we should convert e:\ into //e/ PM }
  183. if (length(s)>2) and (s[2]=':') and (s[3]='/') then
  184. s:=CygDrivePrefix+'/'+s[1]+copy(s,3,length(s));
  185. {$endif USE_MINGW_GDB}
  186. {$endif win32}
  187. end;
  188. constructor TGDBController.Init;
  189. begin
  190. inherited init;
  191. end;
  192. destructor TGDBController.Done;
  193. begin
  194. if assigned(progname) then
  195. strdispose(progname);
  196. if assigned(progdir) then
  197. strdispose(progdir);
  198. if assigned(progargs) then
  199. strdispose(progargs);
  200. inherited done;
  201. end;
  202. procedure TGDBController.Command(const s:ShortString);
  203. begin
  204. inc(in_command);
  205. CommandBegin(s);
  206. gdboutputbuf.reset;
  207. gdberrorbuf.reset;
  208. gdb_command(s);
  209. {
  210. What is that for ?? PM
  211. I had to comment it because
  212. it resets the debuggere after each command !!
  213. Maybe it can happen on errors ??
  214. if in_command<0 then
  215. begin
  216. in_command:=0;
  217. inc(in_command);
  218. Reset;
  219. dec(in_command);
  220. end; }
  221. CommandEnd(s);
  222. dec(in_command);
  223. end;
  224. procedure TGDBController.CommandBegin(const s:ShortString);
  225. begin
  226. end;
  227. procedure TGDBController.CommandEnd(const s:ShortString);
  228. begin
  229. end;
  230. function TGDBController.LoadFile(var fn:ShortString):boolean;
  231. var
  232. cmd : ShortString;
  233. begin
  234. getdir(0,cmd);
  235. UnixDir(cmd);
  236. cmd:='cd '+cmd;
  237. Command(cmd);
  238. GDB__Init;
  239. UnixDir(fn);
  240. if assigned(progname) then
  241. strdispose(progname);
  242. getmem(progname,length(fn)+1);
  243. strpcopy(progname,fn);
  244. if fn<>'' then
  245. Command('file '+fn);
  246. LoadFile:=true;
  247. end;
  248. procedure TGDBController.SetDir(const s : ShortString);
  249. var
  250. hs : ShortString;
  251. begin
  252. hs:=s;
  253. UnixDir(hs);
  254. if assigned(progdir) then
  255. strdispose(progdir);
  256. getmem(progdir,length(hs)+1);
  257. strpcopy(progdir,hs);
  258. command('cd '+hs);
  259. end;
  260. procedure TGDBController.SetArgs(const s : ShortString);
  261. begin
  262. if assigned(progargs) then
  263. strdispose(progargs);
  264. getmem(progargs,length(s)+1);
  265. strpcopy(progargs,s);
  266. command('set args '+s);
  267. end;
  268. procedure TGDBController.Reset;
  269. begin
  270. call_reset:=false;
  271. { DeleteBreakPoints(); }
  272. if debuggee_started then
  273. begin
  274. reset_command:=true;
  275. BreakSession;
  276. Command('kill');
  277. reset_command:=false;
  278. debuggee_started:=false;
  279. end;
  280. end;
  281. procedure TGDBController.StartTrace;
  282. begin
  283. Command('tbreak PASCALMAIN');
  284. start_break_number:=last_breakpoint_number;
  285. Run;
  286. end;
  287. procedure TGDBController.Run;
  288. begin
  289. Command('run');
  290. inc(init_count);
  291. end;
  292. procedure TGDBController.TraceStep;
  293. begin
  294. Command('step');
  295. end;
  296. procedure TGDBController.TraceNext;
  297. begin
  298. Command('next');
  299. end;
  300. procedure TGDBController.TraceStepI;
  301. begin
  302. Command('stepi');
  303. end;
  304. procedure TGDBController.TraceNextI;
  305. begin
  306. Command('nexti');
  307. end;
  308. procedure TGDBController.Continue;
  309. begin
  310. Command('continue');
  311. end;
  312. procedure TGDBController.UntilReturn;
  313. begin
  314. Command('finish');
  315. end;
  316. { Register functions }
  317. function TGDBController.GetIntRegister(const RegName: ShortString; var Value: UInt64): Boolean;
  318. var
  319. RegValueStr: ShortString;
  320. Code: LongInt;
  321. p, po, p1: PAnsiChar;
  322. buffer: array [0..255] of AnsiChar;
  323. begin
  324. GetIntRegister := False;
  325. Value := 0;
  326. Command('info registers ' + RegName);
  327. if Error then
  328. exit;
  329. po:=StrNew(GetOutput);
  330. p:=po;
  331. if not assigned(p) then
  332. exit;
  333. p1:=strscan(p,' ');
  334. if not assigned(p1) then
  335. begin
  336. StrDispose(po);
  337. exit;
  338. end;
  339. p1:=strscan(p,'$');
  340. { some targets use 0x instead of $ }
  341. if p1=nil then
  342. p:=strpos(p,'0x')
  343. else
  344. p:=p1;
  345. p1:=strscan(p,#9);
  346. if p1=nil then
  347. begin
  348. StrDispose(po);
  349. exit;
  350. end;
  351. strlcopy(buffer,p,p1-p);
  352. RegValueStr:=strpas(buffer);
  353. StrDispose(po);
  354. { replace the $? }
  355. if copy(RegValueStr,1,2)='0x' then
  356. RegValueStr:='$'+copy(RegValueStr,3,length(RegValueStr)-2);
  357. Val(RegValueStr, Value, Code);
  358. if Code <> 0 then
  359. exit;
  360. GetIntRegister := True;
  361. end;
  362. function TGDBController.GetIntRegister(const RegName: ShortString; var Value: Int64): Boolean;
  363. var
  364. U64Value: UInt64;
  365. begin
  366. GetIntRegister := GetIntRegister(RegName, U64Value);
  367. Value := Int64(U64Value);
  368. end;
  369. function TGDBController.GetIntRegister(const RegName: ShortString; var Value: UInt32): Boolean;
  370. var
  371. U64Value: UInt64;
  372. begin
  373. GetIntRegister := GetIntRegister(RegName, U64Value);
  374. Value := UInt32(U64Value);
  375. if (U64Value shr 32) <> 0 then
  376. GetIntRegister := False;
  377. end;
  378. function TGDBController.GetIntRegister(const RegName: ShortString; var Value: Int32): Boolean;
  379. var
  380. U32Value: UInt32;
  381. begin
  382. GetIntRegister := GetIntRegister(RegName, U32Value);
  383. Value := Int32(U32Value);
  384. end;
  385. function TGDBController.GetIntRegister(const RegName: ShortString; var Value: UInt16): Boolean;
  386. var
  387. U64Value: UInt64;
  388. begin
  389. GetIntRegister := GetIntRegister(RegName, U64Value);
  390. Value := UInt16(U64Value);
  391. if (U64Value shr 16) <> 0 then
  392. GetIntRegister := False;
  393. end;
  394. function TGDBController.GetIntRegister(const RegName: ShortString; var Value: Int16): Boolean;
  395. var
  396. U16Value: UInt16;
  397. begin
  398. GetIntRegister := GetIntRegister(RegName, U16Value);
  399. Value := Int16(U16Value);
  400. end;
  401. { set command }
  402. function TGDBController.SetCommand(Const SetExpr : ShortString) : boolean;
  403. begin
  404. SetCommand:=false;
  405. Command('set '+SetExpr);
  406. if error then
  407. exit;
  408. SetCommand:=true;
  409. end;
  410. { width }
  411. procedure TGDBController.MaxWidth;
  412. var
  413. p,p2,p3 : PAnsiChar;
  414. begin
  415. Command('show width');
  416. p:=GetOutput;
  417. p3:=nil;
  418. if assigned(p) and (p[strlen(p)-1]=#10) then
  419. begin
  420. p3:=p+strlen(p)-1;
  421. p3^:=#0;
  422. end;
  423. if assigned(p) then
  424. p2:=strpos(p,' in a line is ')
  425. else
  426. p2:=nil;
  427. if assigned(p2) then
  428. p:=p2+length(' in a line is ');
  429. while p^ in [' ',#9] do
  430. inc(p);
  431. p3:=strpos(p,'.');
  432. if assigned(p3) then
  433. p3^:=#0;
  434. SavedWindowWidth:=-1;
  435. val(strpas(p),SavedWindowWidth);
  436. if SavedWindowWidth<>-1 then
  437. Command('set width 0');
  438. end;
  439. procedure TGDBController.NormWidth;
  440. var
  441. st : ShortString;
  442. saved_got_error : boolean;
  443. begin
  444. saved_got_error:=got_error;
  445. if SavedWindowWidth<>-1 then
  446. begin
  447. str(SavedWindowWidth,st);
  448. Command('set width '+St);
  449. end;
  450. got_error:=saved_got_error;
  451. end;
  452. { print }
  453. function TrimEnd(s: AnsiString): AnsiString;
  454. var
  455. I: LongInt;
  456. begin
  457. if (s<>'') and (s[Length(s)]=#10) then
  458. begin
  459. I:=Length(s);
  460. while (i>1) and ((s[i-1]=' ') or (s[i-1]=#9)) do
  461. dec(i);
  462. delete(s,i,Length(s)-i+1);
  463. end;
  464. TrimEnd:=s;
  465. end;
  466. function TGDBController.InternalGetValue(Const expr : ShortString) : AnsiString;
  467. var
  468. p,p2 : PAnsiChar;
  469. begin
  470. MaxWidth;
  471. Command('p '+expr);
  472. p:=GetOutput;
  473. if assigned(p) then
  474. p2:=strpos(p,'=')
  475. else
  476. p2:=nil;
  477. if assigned(p2) then
  478. p:=p2+1;
  479. while p^ in [' ',#9] do
  480. inc(p);
  481. { get rid of type }
  482. if p^ = '(' then
  483. p:=strpos(p,')')+1;
  484. while p^ in [' ',#9] do
  485. inc(p);
  486. if assigned(p) and not got_error then
  487. InternalGetValue:=TrimEnd(AnsiString(p))
  488. else
  489. InternalGetValue:=TrimEnd(AnsiString(GetError));
  490. NormWidth;
  491. end;
  492. function TGDBController.PrintCommand(const expr : ShortString): AnsiString;
  493. begin
  494. PrintCommand:=InternalGetValue(expr);
  495. end;
  496. const
  497. PrintFormatName : Array[TPrintFormatType] of String[11] =
  498. (' /b ', ' /d ', ' /x ', ' /o ', '');
  499. function TGDBController.PrintFormattedCommand(const expr : ShortString; Format : TPrintFormatType): AnsiString;
  500. begin
  501. PrintFormattedCommand:=InternalGetValue(PrintFormatName[Format]+expr);
  502. end;
  503. function TGDBController.BreakpointInsert(const location: ShortString; BreakpointFlags: TBreakpointFlags): LongInt;
  504. var
  505. Prefix: ShortString = '';
  506. begin
  507. if bfTemporary in BreakpointFlags then
  508. Prefix:=Prefix+'t';
  509. if bfHardware in BreakpointFlags then
  510. Prefix:=Prefix+'h';
  511. Last_breakpoint_number:=0;
  512. Command(Prefix+'break '+location);
  513. BreakpointInsert:=Last_breakpoint_number;
  514. end;
  515. function TGDBController.WatchpointInsert(const location: ShortString; WatchpointType: TWatchpointType): LongInt;
  516. begin
  517. Last_breakpoint_number:=0;
  518. case WatchpointType of
  519. wtWrite:
  520. Command('watch ' + location);
  521. wtReadWrite:
  522. Command('awatch ' + location);
  523. wtRead:
  524. Command('rwatch ' + location);
  525. end;
  526. WatchpointInsert:=Last_breakpoint_number;
  527. end;
  528. function TGDBController.BreakpointDelete(BkptNo: LongInt): Boolean;
  529. var
  530. BkptNoStr: ShortString;
  531. begin
  532. Str(BkptNo, BkptNoStr);
  533. Command('delete ' + BkptNoStr);
  534. BreakpointDelete := not Error;
  535. end;
  536. function TGDBController.BreakpointEnable(BkptNo: LongInt): Boolean;
  537. var
  538. BkptNoStr: ShortString;
  539. begin
  540. Str(BkptNo, BkptNoStr);
  541. Command('enable ' + BkptNoStr);
  542. BreakpointEnable := not Error;
  543. end;
  544. function TGDBController.BreakpointDisable(BkptNo: LongInt): Boolean;
  545. var
  546. BkptNoStr: ShortString;
  547. begin
  548. Str(BkptNo, BkptNoStr);
  549. Command('disable ' + BkptNoStr);
  550. BreakpointDisable := not Error;
  551. end;
  552. function TGDBController.BreakpointCondition(BkptNo: LongInt; const ConditionExpr: ShortString): Boolean;
  553. var
  554. BkptNoStr: ShortString;
  555. begin
  556. Str(BkptNo, BkptNoStr);
  557. Command('condition ' + BkptNoStr + ' ' + ConditionExpr);
  558. BreakpointCondition := not Error;
  559. end;
  560. function TGDBController.BreakpointSetIgnoreCount(BkptNo: LongInt; const IgnoreCount: LongInt): Boolean;
  561. var
  562. BkptNoStr, IgnoreCountStr: ShortString;
  563. begin
  564. Str(BkptNo, BkptNoStr);
  565. Str(IgnoreCount, IgnoreCountStr);
  566. Command('ignore ' + BkptNoStr + ' ' + IgnoreCountStr);
  567. BreakpointSetIgnoreCount := not Error;
  568. end;
  569. procedure TGDBController.SetTBreak(tbreakstring : ShortString);
  570. begin
  571. Last_breakpoint_number:=0;
  572. Command('tbreak '+tbreakstring);
  573. TBreakNumber:=Last_breakpoint_number;
  574. end;
  575. procedure TGDBController.Backtrace;
  576. begin
  577. { forget all old frames }
  578. clear_frames;
  579. MaxWidth;
  580. Command('backtrace');
  581. NormWidth;
  582. end;
  583. function TGDBController.SelectFrameCommand(level :longint) : boolean;
  584. var
  585. LevelStr : ShortString;
  586. begin
  587. Str(Level, LevelStr);
  588. Command('frame '+LevelStr);
  589. SelectFrameCommand:=not error;
  590. end;
  591. procedure TGDBController.ClearSymbols;
  592. begin
  593. if debuggee_started then
  594. Reset;
  595. if init_count>0 then
  596. Command('file');
  597. end;
  598. procedure BufWrite(Buf : PAnsiChar);
  599. var p,pe : PAnsiChar;
  600. begin
  601. p:=buf;
  602. While assigned(p) do
  603. begin
  604. pe:=strscan(p,#10);
  605. if pe<>nil then
  606. pe^:=#0;
  607. Writeln(p);
  608. { restore for dispose }
  609. if pe<>nil then
  610. pe^:=#10;
  611. if pe=nil then
  612. p:=nil
  613. else
  614. begin
  615. p:=pe;
  616. inc(p);
  617. end;
  618. end;
  619. end;
  620. function TGDBController.GetOutput : PAnsiChar;
  621. begin
  622. GetOutput:=gdboutputbuf.buf;
  623. end;
  624. function TGDBController.GetError : PAnsiChar;
  625. var p : PAnsiChar;
  626. begin
  627. p:=gdberrorbuf.buf;
  628. if (p^=#0) and got_error then
  629. GetError:=PAnsiChar(ptrint(gdboutputbuf.buf)+gdboutputbuf.idx)
  630. else
  631. GetError:=p;
  632. end;
  633. procedure TGDBController.WriteErrorBuf;
  634. begin
  635. BufWrite(gdberrorbuf.buf);
  636. end;
  637. procedure TGDBController.WriteOutputBuf;
  638. begin
  639. BufWrite(gdboutputbuf.buf);
  640. end;
  641. end.