browser.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by the FPC development team
  4. Support routines for the browser
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {$ifdef TP}
  19. {$N+,E+}
  20. {$endif}
  21. unit browser;
  22. interface
  23. uses
  24. cobjects,files;
  25. const
  26. {$ifdef TP}
  27. logbufsize = 1024;
  28. {$else}
  29. logbufsize = 16384;
  30. {$endif}
  31. type
  32. pref = ^tref;
  33. tref = object
  34. nextref : pref;
  35. posinfo : tfileposinfo;
  36. moduleindex : word;
  37. is_written : boolean;
  38. constructor init(ref:pref;pos:pfileposinfo);
  39. destructor done; virtual;
  40. function get_file_line : string;
  41. end;
  42. pbrowser=^tbrowser;
  43. tbrowser=object
  44. fname : string;
  45. logopen : boolean;
  46. stderrlog : boolean;
  47. f : file;
  48. elements_to_list : pstringqueue;
  49. buf : pchar;
  50. bufidx : longint;
  51. identidx : longint;
  52. constructor init;
  53. destructor done;
  54. procedure setfilename(const fn:string);
  55. procedure createlog;
  56. procedure flushlog;
  57. procedure addlog(const s:string);
  58. procedure addlogrefs(p:pref);
  59. procedure closelog;
  60. procedure ident;
  61. procedure unident;
  62. procedure browse_symbol(const sr : string);
  63. procedure list_elements;
  64. procedure list_debug_infos;
  65. end;
  66. var
  67. browse : tbrowser;
  68. procedure InitBrowser;
  69. procedure DoneBrowser;
  70. function get_source_file(moduleindex,fileindex : word) : pinputfile;
  71. implementation
  72. uses
  73. comphook,globals,symtable,systems,verbose;
  74. {****************************************************************************
  75. TRef
  76. ****************************************************************************}
  77. constructor tref.init(ref :pref;pos : pfileposinfo);
  78. begin
  79. nextref:=nil;
  80. if assigned(pos) then
  81. posinfo:=pos^;
  82. if assigned(current_module) then
  83. moduleindex:=current_module^.unit_index;
  84. if assigned(ref) then
  85. ref^.nextref:=@self;
  86. is_written:=false;
  87. end;
  88. destructor tref.done;
  89. var
  90. inputfile : pinputfile;
  91. begin
  92. inputfile:=get_source_file(moduleindex,posinfo.fileindex);
  93. if inputfile<>nil then
  94. dec(inputfile^.ref_count);
  95. if assigned(nextref) then
  96. dispose(nextref,done);
  97. nextref:=nil;
  98. end;
  99. function tref.get_file_line : string;
  100. var
  101. inputfile : pinputfile;
  102. begin
  103. get_file_line:='';
  104. inputfile:=get_source_file(moduleindex,posinfo.fileindex);
  105. if assigned(inputfile) then
  106. if status.use_gccoutput then
  107. { for use with rhide
  108. add warning so that it does not interpret
  109. this as an error !! }
  110. get_file_line:=lower(inputfile^.name^)
  111. +':'+tostr(posinfo.line)+': warning: '+tostr(posinfo.column)+':'
  112. else
  113. get_file_line:=inputfile^.name^
  114. +'('+tostr(posinfo.line)+','+tostr(posinfo.column)+')'
  115. else
  116. if status.use_gccoutput then
  117. get_file_line:='file_unknown:'
  118. +tostr(posinfo.line)+': warning: '+tostr(posinfo.column)+':'
  119. else
  120. get_file_line:='file_unknown('
  121. +tostr(posinfo.line)+','+tostr(posinfo.column)+')'
  122. end;
  123. {****************************************************************************
  124. TBrowser
  125. ****************************************************************************}
  126. constructor tbrowser.init;
  127. begin
  128. fname:=FixFileName('browser.log');
  129. logopen:=false;
  130. elements_to_list:=new(pstringqueue,init);
  131. end;
  132. destructor tbrowser.done;
  133. begin
  134. if logopen then
  135. closelog;
  136. dispose(elements_to_list,done);
  137. end;
  138. procedure tbrowser.setfilename(const fn:string);
  139. begin
  140. fname:=FixFileName(fn);
  141. end;
  142. procedure tbrowser.createlog;
  143. begin
  144. if logopen then
  145. closelog;
  146. assign(f,fname);
  147. {$I-}
  148. rewrite(f,1);
  149. {$I+}
  150. if ioresult<>0 then
  151. exit;
  152. logopen:=true;
  153. getmem(buf,logbufsize);
  154. bufidx:=0;
  155. identidx:=0;
  156. end;
  157. procedure tbrowser.flushlog;
  158. begin
  159. if logopen then
  160. if not stderrlog then
  161. blockwrite(f,buf^,bufidx)
  162. else
  163. begin
  164. buf[bufidx]:=#0;
  165. {$ifndef TP}
  166. write(stderr,buf);
  167. {$else TP}
  168. write(buf);
  169. {$endif TP}
  170. end;
  171. bufidx:=0;
  172. end;
  173. procedure tbrowser.closelog;
  174. begin
  175. if logopen then
  176. begin
  177. flushlog;
  178. close(f);
  179. freemem(buf,logbufsize);
  180. logopen:=false;
  181. end;
  182. end;
  183. procedure tbrowser.list_elements;
  184. begin
  185. stderrlog:=true;
  186. getmem(buf,logbufsize);
  187. logopen:=true;
  188. while not elements_to_list^.empty do
  189. browse_symbol(elements_to_list^.get);
  190. flushlog;
  191. logopen:=false;
  192. freemem(buf,logbufsize);
  193. stderrlog:=false;
  194. end;
  195. procedure tbrowser.list_debug_infos;
  196. {$ifndef debug}
  197. begin
  198. end;
  199. {$else debug}
  200. var
  201. hp : pmodule;
  202. ff : pinputfile;
  203. begin
  204. hp:=pmodule(loaded_units.first);
  205. while assigned(hp) do
  206. begin
  207. addlog('Unit '+hp^.modulename^+' has index '+tostr(hp^.unit_index));
  208. ff:=hp^.sourcefiles^.files;
  209. while assigned(ff) do
  210. begin
  211. addlog('File '+ff^.name^+' index '+tostr(ff^.ref_index));
  212. ff:=ff^.ref_next;
  213. end;
  214. hp:=pmodule(hp^.next);
  215. end;
  216. end;
  217. {$endif debug}
  218. procedure tbrowser.addlog(const s:string);
  219. begin
  220. if not logopen then
  221. exit;
  222. { add ident }
  223. if (identidx>0) and not stderrlog then
  224. begin
  225. if bufidx+identidx>logbufsize then
  226. flushlog;
  227. fillchar(buf[bufidx],identidx,' ');
  228. inc(bufidx,identidx);
  229. end;
  230. { add text }
  231. if bufidx+length(s)>logbufsize-2 then
  232. flushlog;
  233. move(s[1],buf[bufidx],length(s));
  234. inc(bufidx,length(s));
  235. { add crlf }
  236. buf[bufidx]:=target_os.newline[1];
  237. inc(bufidx);
  238. if length(target_os.newline)=2 then
  239. begin
  240. buf[bufidx]:=target_os.newline[2];
  241. inc(bufidx);
  242. end;
  243. end;
  244. procedure tbrowser.addlogrefs(p:pref);
  245. var
  246. ref : pref;
  247. begin
  248. ref:=p;
  249. Ident;
  250. while assigned(ref) do
  251. begin
  252. Browse.AddLog(ref^.get_file_line);
  253. ref:=ref^.nextref;
  254. end;
  255. Unident;
  256. end;
  257. procedure tbrowser.browse_symbol(const sr : string);
  258. var
  259. sym,symb : psym;
  260. symt : psymtable;
  261. hp : pmodule;
  262. s,ss : string;
  263. p : byte;
  264. procedure next_substring;
  265. begin
  266. p:=pos('.',s);
  267. if p>0 then
  268. begin
  269. ss:=copy(s,1,p-1);
  270. s:=copy(s,p+1,255);
  271. end
  272. else
  273. begin
  274. ss:=s;
  275. s:='';
  276. end;
  277. addlog('substring : '+ss);
  278. end;
  279. begin
  280. { don't create a new reference when
  281. looking for the symbol !! }
  282. make_ref:=false;
  283. s:=sr;
  284. symt:=symtablestack;
  285. next_substring;
  286. if assigned(symt) then
  287. begin
  288. sym:=symt^.search(ss);
  289. if sym=nil then
  290. sym:=symt^.search(upper(ss));
  291. end
  292. else
  293. sym:=nil;
  294. if assigned(sym) and (sym^.typ=unitsym) and (s<>'') then
  295. begin
  296. addlog('Unitsym found !');
  297. symt:=punitsym(sym)^.unitsymtable;
  298. if assigned(symt) then
  299. begin
  300. next_substring;
  301. sym:=symt^.search(ss);
  302. end
  303. else
  304. sym:=nil;
  305. end;
  306. if not assigned(sym) then
  307. begin
  308. symt:=nil;
  309. { try all loaded_units }
  310. hp:=pmodule(loaded_units.first);
  311. while assigned(hp) do
  312. begin
  313. if hp^.modulename^=upper(ss) then
  314. begin
  315. symt:=hp^.globalsymtable;
  316. break;
  317. end;
  318. hp:=pmodule(hp^.next);
  319. end;
  320. if not assigned(symt) then
  321. begin
  322. addlog('!!!Symbol '+ss+' not found !!!');
  323. make_ref:=true;
  324. exit;
  325. end
  326. else
  327. begin
  328. next_substring;
  329. sym:=symt^.search(ss);
  330. if sym=nil then
  331. sym:=symt^.search(upper(ss));
  332. end;
  333. end;
  334. while assigned(sym) and (s<>'') do
  335. begin
  336. next_substring;
  337. case sym^.typ of
  338. typesym :
  339. begin
  340. if ptypesym(sym)^.definition^.deftype in [recorddef,objectdef] then
  341. begin
  342. if ptypesym(sym)^.definition^.deftype=recorddef then
  343. symt:=precdef(ptypesym(sym)^.definition)^.symtable
  344. else
  345. symt:=pobjectdef(ptypesym(sym)^.definition)^.publicsyms;
  346. sym:=symt^.search(ss);
  347. if sym=nil then
  348. sym:=symt^.search(upper(ss));
  349. end;
  350. end;
  351. varsym :
  352. begin
  353. if pvarsym(sym)^.definition^.deftype in [recorddef,objectdef] then
  354. begin
  355. if pvarsym(sym)^.definition^.deftype=recorddef then
  356. symt:=precdef(pvarsym(sym)^.definition)^.symtable
  357. else
  358. symt:=pobjectdef(pvarsym(sym)^.definition)^.publicsyms;
  359. sym:=symt^.search(ss);
  360. if sym=nil then
  361. sym:=symt^.search(upper(ss));
  362. end;
  363. end;
  364. procsym :
  365. begin
  366. symt:=pprocsym(sym)^.definition^.parast;
  367. symb:=symt^.search(ss);
  368. if symb=nil then
  369. symb:=symt^.search(upper(ss));
  370. if not assigned(symb) then
  371. begin
  372. symt:=pprocsym(sym)^.definition^.parast;
  373. sym:=symt^.search(ss);
  374. if symb=nil then
  375. symb:=symt^.search(upper(ss));
  376. end
  377. else
  378. sym:=symb;
  379. end;
  380. {else
  381. sym^.add_to_browserlog;}
  382. end;
  383. end;
  384. if assigned(sym) then
  385. sym^.add_to_browserlog
  386. else
  387. addlog('!!!Symbol '+ss+' not found !!!');
  388. make_ref:=true;
  389. end;
  390. procedure tbrowser.ident;
  391. begin
  392. inc(identidx,2);
  393. end;
  394. procedure tbrowser.unident;
  395. begin
  396. dec(identidx,2);
  397. end;
  398. {****************************************************************************
  399. Helpers
  400. ****************************************************************************}
  401. function get_source_file(moduleindex,fileindex : word) : pinputfile;
  402. var
  403. hp : pmodule;
  404. f : pinputfile;
  405. begin
  406. hp:=pmodule(loaded_units.first);
  407. while assigned(hp) and (hp^.unit_index<>moduleindex) do
  408. hp:=pmodule(hp^.next);
  409. get_source_file:=nil;
  410. if not assigned(hp) then
  411. exit;
  412. f:=pinputfile(hp^.sourcefiles^.files);
  413. while assigned(f) do
  414. begin
  415. if f^.ref_index=fileindex then
  416. begin
  417. get_source_file:=f;
  418. exit;
  419. end;
  420. f:=pinputfile(f^.ref_next);
  421. end;
  422. end;
  423. procedure InitBrowser;
  424. begin
  425. browse.init;
  426. end;
  427. procedure DoneBrowser;
  428. begin
  429. browse.done;
  430. end;
  431. end.
  432. {
  433. $Log$
  434. Revision 1.12 1998-10-09 16:36:01 pierre
  435. * some memory leaks specific to usebrowser define fixed
  436. * removed tmodule.implsymtable (was like tmodule.localsymtable)
  437. Revision 1.11 1998/10/08 17:17:09 pierre
  438. * current_module old scanner tagged as invalid if unit is recompiled
  439. + added ppheap for better info on tracegetmem of heaptrc
  440. (adds line column and file index)
  441. * several memory leaks removed ith help of heaptrc !!
  442. Revision 1.10 1998/09/28 16:57:12 pierre
  443. * changed all length(p^.value_str^) into str_length(p)
  444. to get it work with and without ansistrings
  445. * changed sourcefiles field of tmodule to a pointer
  446. Revision 1.9 1998/09/23 15:38:59 pierre
  447. * browser bugfixes
  448. was adding a reference when looking for the symbol
  449. if -bSYM_NAME was used
  450. Revision 1.8 1998/09/22 17:13:42 pierre
  451. + browsing updated and developed
  452. records and objects fields are also stored
  453. Revision 1.7 1998/09/21 08:45:05 pierre
  454. + added vmt_offset in tobjectdef.write for fututre use
  455. (first steps to have objects without vmt if no virtual !!)
  456. + added fpu_used field for tabstractprocdef :
  457. sets this level to 2 if the functions return with value in FPU
  458. (is then set to correct value at parsing of implementation)
  459. THIS MIGHT refuse some code with FPU expression too complex
  460. that were accepted before and even in some cases
  461. that don't overflow in fact
  462. ( like if f : float; is a forward that finally in implementation
  463. only uses one fpu register !!)
  464. Nevertheless I think that it will improve security on
  465. FPU operations !!
  466. * most other changes only for UseBrowser code
  467. (added symtable references for record and objects)
  468. local switch for refs to args and local of each function
  469. (static symtable still missing)
  470. UseBrowser still not stable and probably broken by
  471. the definition hash array !!
  472. Revision 1.6 1998/09/01 07:54:16 pierre
  473. * UseBrowser a little updated (might still be buggy !!)
  474. * bug in psub.pas in function specifier removed
  475. * stdcall allowed in interface and in implementation
  476. (FPC will not yet complain if it is missing in either part
  477. because stdcall is only a dummy !!)
  478. Revision 1.5 1998/06/13 00:10:04 peter
  479. * working browser and newppu
  480. * some small fixes against crashes which occured in bp7 (but not in
  481. fpc?!)
  482. Revision 1.4 1998/06/11 10:11:57 peter
  483. * -gb works again
  484. Revision 1.3 1998/05/20 09:42:32 pierre
  485. + UseTokenInfo now default
  486. * unit in interface uses and implementation uses gives error now
  487. * only one error for unknown symbol (uses lastsymknown boolean)
  488. the problem came from the label code !
  489. + first inlined procedures and function work
  490. (warning there might be allowed cases were the result is still wrong !!)
  491. * UseBrower updated gives a global list of all position of all used symbols
  492. with switch -gb
  493. Revision 1.2 1998/04/30 15:59:39 pierre
  494. * GDB works again better :
  495. correct type info in one pass
  496. + UseTokenInfo for better source position
  497. * fixed one remaining bug in scanner for line counts
  498. * several little fixes
  499. }