fpdebug.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. {
  2. $Id$
  3. This file is part of the Free Pascal Integrated Development Environment
  4. Copyright (c) 1998 by Berczi Gabor
  5. Debugger call routines for the IDE
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit FPDebug;
  13. interface
  14. uses
  15. Views,Objects,GDBCon,GDBInt;
  16. type
  17. PDebugController=^TDebugController;
  18. TDebugController=object(TGDBController)
  19. InvalidSourceLine : boolean;
  20. LastFileName : string;
  21. LastSource : PView; {PsourceWindow !! }
  22. HiddenStepsCount : longint;
  23. constructor Init(const exefn:string);
  24. destructor Done;
  25. procedure DoSelectSourceline(const fn:string;line:longint);virtual;
  26. { procedure DoStartSession;virtual;
  27. procedure DoBreakSession;virtual;}
  28. procedure DoEndSession(code:longint);virtual;
  29. procedure AnnotateError;
  30. procedure InsertBreakpoints;
  31. procedure RemoveBreakpoints;
  32. procedure DoDebuggerScreen;virtual;
  33. procedure DoUserScreen;virtual;
  34. procedure Reset;virtual;
  35. procedure Run;virtual;
  36. procedure Continue;virtual;
  37. end;
  38. BreakpointType = (bt_function,bt_file_line,bt_watch,bt_awatch,bt_rwatch,bt_invalid);
  39. BreakpointState = (bs_enabled,bs_disabled,bs_deleted);
  40. PBreakpointCollection=^TBreakpointCollection;
  41. PBreakpoint=^TBreakpoint;
  42. TBreakpoint=object(TObject)
  43. typ : BreakpointType;
  44. state : BreakpointState;
  45. owner : PBreakpointCollection;
  46. Name : PString; { either function name or file name }
  47. Line : Longint; { only used for bt_file_line type }
  48. Conditions : PString; { conditions relative to that breakpoint }
  49. IgnoreCount : Longint; { how many counts should be ignored }
  50. Commands : pchar; { commands that should be executed on breakpoint }
  51. GDBIndex : longint;
  52. GDBState : BreakpointState;
  53. constructor Init_function(Const AFunc : String);
  54. constructor Init_file_line(AFile : String; ALine : longint);
  55. constructor Init_type(atyp : BreakpointType;Const AFunc : String);
  56. procedure Insert;
  57. procedure Remove;
  58. procedure Enable;
  59. procedure Disable;
  60. destructor Done;virtual;
  61. end;
  62. TBreakpointCollection=object(TCollection)
  63. function At(Index: Integer): PBreakpoint;
  64. function ToggleFileLine(Const FileName: String;LineNr : Longint) : boolean;
  65. procedure Update;
  66. procedure FreeItem(Item: Pointer); virtual;
  67. end;
  68. var
  69. Debugger : PDebugController;
  70. BreakpointCollection : PBreakpointCollection;
  71. procedure InitDebugger;
  72. procedure DoneDebugger;
  73. implementation
  74. uses
  75. Dos,Mouse,Video,
  76. App,Strings,
  77. FPViews,FPVars,FPUtils,FPConst,
  78. FPIntf,FPCompile,FPIde;
  79. {****************************************************************************
  80. TDebugController
  81. ****************************************************************************}
  82. constructor TDebugController.Init(const exefn:string);
  83. var f: string;
  84. begin
  85. inherited Init;
  86. f := exefn;
  87. LoadFile(f);
  88. SetArgs(GetRunParameters);
  89. Debugger:=@self;
  90. InsertBreakpoints;
  91. end;
  92. procedure TDebugController.InsertBreakpoints;
  93. procedure DoInsert(PB : PBreakpoint);
  94. begin
  95. PB^.Insert;
  96. end;
  97. begin
  98. BreakpointCollection^.ForEach(@DoInsert);
  99. end;
  100. procedure TDebugController.RemoveBreakpoints;
  101. procedure DoDelete(PB : PBreakpoint);
  102. begin
  103. PB^.Remove;
  104. end;
  105. begin
  106. BreakpointCollection^.ForEach(@DoDelete);
  107. end;
  108. destructor TDebugController.Done;
  109. begin
  110. { kill the program if running }
  111. Reset;
  112. RemoveBreakpoints;
  113. inherited Done;
  114. end;
  115. procedure TDebugController.Run;
  116. begin
  117. inherited Run;
  118. MyApp.SetCmdState([cmResetDebugger],true);
  119. end;
  120. procedure TDebugController.Continue;
  121. begin
  122. if not debugger_started then
  123. Run;
  124. inherited Continue;
  125. end;
  126. procedure TDebugController.Reset;
  127. var
  128. W : PSourceWindow;
  129. begin
  130. inherited Reset;
  131. MyApp.SetCmdState([cmResetDebugger],false);
  132. W:=PSourceWindow(LastSource);
  133. if assigned(W) then
  134. W^.Editor^.SetHighlightRow(-1);
  135. end;
  136. procedure TDebugController.AnnotateError;
  137. var errornb : longint;
  138. begin
  139. if error then
  140. begin
  141. errornb:=error_num;
  142. ErrorBox(#3'Error within GDB'#13#3'Error code = %d',@errornb);
  143. end;
  144. end;
  145. procedure TDebugController.DoSelectSourceLine(const fn:string;line:longint);
  146. var
  147. W: PSourceWindow;
  148. Found : boolean;
  149. begin
  150. Desktop^.Lock;
  151. if Line>0 then
  152. dec(Line);
  153. if (fn=LastFileName) then
  154. begin
  155. W:=PSourceWindow(LastSource);
  156. if assigned(W) then
  157. begin
  158. W^.Editor^.SetCurPtr(0,Line);
  159. W^.Editor^.TrackCursor(true);
  160. W^.Editor^.SetHighlightRow(Line);
  161. W^.Select;
  162. InvalidSourceLine:=false;
  163. end
  164. else
  165. InvalidSourceLine:=true;
  166. end
  167. else
  168. begin
  169. W:=TryToOpenFile(nil,fn,0,Line);
  170. if assigned(W) then
  171. begin
  172. W^.Editor^.SetHighlightRow(Line);
  173. W^.Editor^.TrackCursor(true);
  174. W^.Select;
  175. LastSource:=W;
  176. InvalidSourceLine:=false;
  177. end
  178. { only search a file once }
  179. else
  180. begin
  181. Desktop^.UnLock;
  182. Found:=MyApp.OpenSearch(fn);
  183. Desktop^.Lock;
  184. if not Found then
  185. begin
  186. InvalidSourceLine:=true;
  187. LastSource:=Nil;
  188. end
  189. else
  190. begin
  191. { should now be open }
  192. W:=TryToOpenFile(nil,fn,0,Line);
  193. W^.Editor^.SetHighlightRow(Line);
  194. W^.Editor^.TrackCursor(true);
  195. W^.Select;
  196. LastSource:=W;
  197. InvalidSourceLine:=false;
  198. end;
  199. end;
  200. end;
  201. LastFileName:=fn;
  202. Desktop^.UnLock;
  203. end;
  204. procedure TDebugController.DoEndSession(code:longint);
  205. var P :Array[1..2] of longint;
  206. W : PSourceWindow;
  207. begin
  208. MyApp.SetCmdState([cmResetDebugger],false);
  209. W:=PSourceWindow(LastSource);
  210. if assigned(W) then
  211. W^.Editor^.SetHighlightRow(-1);
  212. If HiddenStepsCount=0 then
  213. InformationBox(#3'Program exited with '#13#3'exitcode = %d',@code)
  214. else
  215. begin
  216. P[1]:=code;
  217. P[2]:=HiddenStepsCount;
  218. WarningBox(#3'Program exited with '#13+
  219. #3'exitcode = %d'#13+
  220. #3'hidden steps = %d',@P);
  221. end;
  222. end;
  223. procedure TDebugController.DoDebuggerScreen;
  224. begin
  225. MyApp.ShowIDEScreen;
  226. end;
  227. procedure TDebugController.DoUserScreen;
  228. begin
  229. MyApp.ShowUserScreen;
  230. end;
  231. {****************************************************************************
  232. TBreakpoint
  233. ****************************************************************************}
  234. constructor TBreakpoint.Init_function(Const AFunc : String);
  235. begin
  236. typ:=bt_function;
  237. state:=bs_enabled;
  238. GDBState:=bs_deleted;
  239. Name:=NewStr(AFunc);
  240. IgnoreCount:=0;
  241. Commands:=nil;
  242. Conditions:=nil;
  243. end;
  244. constructor TBreakpoint.Init_type(atyp : BreakpointType;Const AFunc : String);
  245. begin
  246. typ:=atyp;
  247. state:=bs_enabled;
  248. GDBState:=bs_deleted;
  249. Name:=NewStr(AFunc);
  250. IgnoreCount:=0;
  251. Commands:=nil;
  252. Conditions:=nil;
  253. end;
  254. constructor TBreakpoint.Init_file_line(AFile : String; ALine : longint);
  255. begin
  256. typ:=bt_file_line;
  257. state:=bs_enabled;
  258. GDBState:=bs_deleted;
  259. AFile:=NameAndExtOf(AFile);
  260. { d:test.pas:12 does not work !! }
  261. { I do not know how to solve this if
  262. if (Length(AFile)>1) and (AFile[2]=':') then
  263. AFile:=Copy(AFile,3,255);
  264. Only use base name for now !! PM }
  265. Name:=NewStr(AFile);
  266. Line:=ALine;
  267. IgnoreCount:=0;
  268. Commands:=nil;
  269. Conditions:=nil;
  270. end;
  271. procedure TBreakpoint.Insert;
  272. begin
  273. If not assigned(Debugger) then Exit;
  274. Remove;
  275. Debugger^.last_breakpoint_number:=0;
  276. if (GDBState=bs_deleted) and (state=bs_enabled) then
  277. begin
  278. if (typ=bt_file_line) then
  279. Debugger^.Command('break '+name^+':'+IntToStr(Line))
  280. else if typ=bt_function then
  281. Debugger^.Command('break '+name^)
  282. else if typ=bt_watch then
  283. Debugger^.Command('watch '+name^)
  284. else if typ=bt_awatch then
  285. Debugger^.Command('awatch '+name^)
  286. else if typ=bt_rwatch then
  287. Debugger^.Command('rwatch '+name^);
  288. if Debugger^.last_breakpoint_number<>0 then
  289. begin
  290. GDBIndex:=Debugger^.last_breakpoint_number;
  291. GDBState:=bs_enabled;
  292. Debugger^.Command('cond '+IntToStr(GDBIndex)+' '+GetStr(Conditions));
  293. Debugger^.Command('ignore '+IntToStr(GDBIndex)+' '+IntToStr(IgnoreCount));
  294. If Assigned(Commands) then
  295. begin
  296. {Commands are not handled yet }
  297. end;
  298. end
  299. else
  300. { Here there was a problem !! }
  301. begin
  302. GDBIndex:=0;
  303. state:=bs_disabled;
  304. end;
  305. end
  306. else if (GDBState=bs_disabled) and (state=bs_enabled) then
  307. Enable
  308. else if (GDBState=bs_enabled) and (state=bs_disabled) then
  309. Disable;
  310. end;
  311. procedure TBreakpoint.Remove;
  312. begin
  313. If not assigned(Debugger) then Exit;
  314. if GDBIndex>0 then
  315. Debugger^.Command('delete '+IntToStr(GDBIndex));
  316. GDBIndex:=0;
  317. GDBState:=bs_deleted;
  318. end;
  319. procedure TBreakpoint.Enable;
  320. begin
  321. If not assigned(Debugger) then Exit;
  322. if GDBIndex>0 then
  323. Debugger^.Command('enable '+IntToStr(GDBIndex));
  324. GDBState:=bs_enabled;
  325. end;
  326. procedure TBreakpoint.Disable;
  327. begin
  328. If not assigned(Debugger) then Exit;
  329. if GDBIndex>0 then
  330. Debugger^.Command('disable '+IntToStr(GDBIndex));
  331. GDBState:=bs_disabled;
  332. end;
  333. destructor TBreakpoint.Done;
  334. begin
  335. Remove;
  336. if assigned(Name) then
  337. DisposeStr(Name);
  338. if assigned(Conditions) then
  339. DisposeStr(Conditions);
  340. if assigned(Commands) then
  341. StrDispose(Commands);
  342. inherited Done;
  343. end;
  344. {****************************************************************************
  345. TBreakpointCollection
  346. ****************************************************************************}
  347. function TBreakpointCollection.At(Index: Integer): PBreakpoint;
  348. begin
  349. At:=inherited At(Index);
  350. end;
  351. procedure TBreakpointCollection.FreeItem(Item: Pointer);
  352. begin
  353. if Item<>nil then
  354. Dispose(PBreakpoint(Item),Done);
  355. end;
  356. procedure TBreakpointCollection.Update;
  357. begin
  358. if assigned(Debugger) then
  359. begin
  360. Debugger^.RemoveBreakpoints;
  361. Debugger^.InsertBreakpoints;
  362. end;
  363. end;
  364. function TBreakpointCollection.ToggleFileLine(Const FileName: String;LineNr : Longint) : boolean;
  365. var PB : PBreakpoint;
  366. function IsThere(P : PBreakpoint) : boolean;
  367. begin
  368. IsThere:=(P^.typ=bt_file_line) and (P^.Name^=FileName) and (P^.Line=LineNr);
  369. end;
  370. begin
  371. PB:=FirstThat(@IsThere);
  372. ToggleFileLine:=false;
  373. If Assigned(PB) then
  374. if PB^.state=bs_disabled then
  375. begin
  376. PB^.state:=bs_enabled;
  377. ToggleFileLine:=true;
  378. end
  379. else if PB^.state=bs_enabled then
  380. PB^.state:=bs_disabled;
  381. If not assigned(PB) then
  382. begin
  383. PB:= New(PBreakpoint,Init_file_line(FileName,LineNr));
  384. if assigned(PB) then
  385. Begin
  386. Insert(PB);
  387. ToggleFileLine:=true;
  388. End;
  389. end;
  390. Update;
  391. end;
  392. {****************************************************************************
  393. Initialize
  394. ****************************************************************************}
  395. procedure InitDebugger;
  396. begin
  397. Assign(gdb_file,'gdb$$$.out');
  398. Rewrite(gdb_file);
  399. Use_gdb_file:=true;
  400. if (not ExistsFile(ExeFile)) or (CompilationPhase<>cpDone) then
  401. DoCompile(cRun);
  402. if CompilationPhase<>cpDone then
  403. Exit;
  404. if (EXEFile='') then
  405. begin
  406. ErrorBox('Oooops, nothing to debug.',nil);
  407. Exit;
  408. end;
  409. { init debugcontroller }
  410. if assigned(Debugger) then
  411. dispose(Debugger,Done);
  412. new(Debugger,Init(ExeFile));
  413. end;
  414. procedure DoneDebugger;
  415. begin
  416. if assigned(Debugger) then
  417. dispose(Debugger,Done);
  418. Debugger:=nil;
  419. If Use_gdb_file then
  420. Close(GDB_file);
  421. Use_gdb_file:=false;
  422. end;
  423. begin
  424. New(BreakpointCollection,init(10,10));
  425. end.
  426. {
  427. $Log$
  428. Revision 1.9 1999-02-08 17:43:43 pierre
  429. * RestDebugger or multiple running of debugged program now works
  430. + added DoContToCursor(F4)
  431. * Breakpoints are now inserted correctly (was mainlyy a problem
  432. of directories)
  433. Revision 1.8 1999/02/05 17:21:52 pierre
  434. Invalid_line renamed InvalidSourceLine
  435. Revision 1.7 1999/02/05 13:08:41 pierre
  436. + new breakpoint types added
  437. Revision 1.6 1999/02/05 12:11:53 pierre
  438. + SourceDir that stores directories for sources that the
  439. compiler should not know about
  440. Automatically asked for addition when a new file that
  441. needed filedialog to be found is in an unknown directory
  442. Stored and retrieved from INIFile
  443. + Breakpoints conditions added to INIFile
  444. * Breakpoints insterted and removed at debin and end of debug session
  445. Revision 1.5 1999/02/04 17:54:22 pierre
  446. + several commands added
  447. Revision 1.4 1999/02/04 13:32:02 pierre
  448. * Several things added (I cannot commit them independently !)
  449. + added TBreakpoint and TBreakpointCollection
  450. + added cmResetDebugger,cmGrep,CmToggleBreakpoint
  451. + Breakpoint list in INIFile
  452. * Select items now also depend of SwitchMode
  453. * Reading of option '-g' was not possible !
  454. + added search for -Fu args pathes in TryToOpen
  455. + added code for automatic opening of FileDialog
  456. if source not found
  457. Revision 1.3 1999/02/02 16:41:38 peter
  458. + automatic .pas/.pp adding by opening of file
  459. * better debuggerscreen changes
  460. Revision 1.2 1999/01/22 18:14:09 pierre
  461. * adaptd to changes in gdbint and gdbcon for to /
  462. Revision 1.1 1999/01/22 10:24:03 peter
  463. * first debugger things
  464. }