browser.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  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. function get_source_file(moduleindex,fileindex : word) : pinputfile;
  69. implementation
  70. uses
  71. comphook,globals,symtable,systems,verbose;
  72. {****************************************************************************
  73. TRef
  74. ****************************************************************************}
  75. constructor tref.init(ref :pref;pos : pfileposinfo);
  76. begin
  77. nextref:=nil;
  78. if assigned(pos) then
  79. posinfo:=pos^;
  80. if assigned(current_module) then
  81. moduleindex:=current_module^.unit_index;
  82. if assigned(ref) then
  83. ref^.nextref:=@self;
  84. is_written:=false;
  85. end;
  86. destructor tref.done;
  87. var
  88. inputfile : pinputfile;
  89. ref : pref;
  90. begin
  91. inputfile:=get_source_file(moduleindex,posinfo.fileindex);
  92. if inputfile<>nil then
  93. dec(inputfile^.ref_count);
  94. ref:=@self;
  95. if assigned(ref^.nextref) then
  96. dispose(ref^.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^.symtable;
  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. begin
  424. browse.init
  425. end.
  426. {
  427. $Log$
  428. Revision 1.10 1998-09-28 16:57:12 pierre
  429. * changed all length(p^.value_str^) into str_length(p)
  430. to get it work with and without ansistrings
  431. * changed sourcefiles field of tmodule to a pointer
  432. Revision 1.9 1998/09/23 15:38:59 pierre
  433. * browser bugfixes
  434. was adding a reference when looking for the symbol
  435. if -bSYM_NAME was used
  436. Revision 1.8 1998/09/22 17:13:42 pierre
  437. + browsing updated and developed
  438. records and objects fields are also stored
  439. Revision 1.7 1998/09/21 08:45:05 pierre
  440. + added vmt_offset in tobjectdef.write for fututre use
  441. (first steps to have objects without vmt if no virtual !!)
  442. + added fpu_used field for tabstractprocdef :
  443. sets this level to 2 if the functions return with value in FPU
  444. (is then set to correct value at parsing of implementation)
  445. THIS MIGHT refuse some code with FPU expression too complex
  446. that were accepted before and even in some cases
  447. that don't overflow in fact
  448. ( like if f : float; is a forward that finally in implementation
  449. only uses one fpu register !!)
  450. Nevertheless I think that it will improve security on
  451. FPU operations !!
  452. * most other changes only for UseBrowser code
  453. (added symtable references for record and objects)
  454. local switch for refs to args and local of each function
  455. (static symtable still missing)
  456. UseBrowser still not stable and probably broken by
  457. the definition hash array !!
  458. Revision 1.6 1998/09/01 07:54:16 pierre
  459. * UseBrowser a little updated (might still be buggy !!)
  460. * bug in psub.pas in function specifier removed
  461. * stdcall allowed in interface and in implementation
  462. (FPC will not yet complain if it is missing in either part
  463. because stdcall is only a dummy !!)
  464. Revision 1.5 1998/06/13 00:10:04 peter
  465. * working browser and newppu
  466. * some small fixes against crashes which occured in bp7 (but not in
  467. fpc?!)
  468. Revision 1.4 1998/06/11 10:11:57 peter
  469. * -gb works again
  470. Revision 1.3 1998/05/20 09:42:32 pierre
  471. + UseTokenInfo now default
  472. * unit in interface uses and implementation uses gives error now
  473. * only one error for unknown symbol (uses lastsymknown boolean)
  474. the problem came from the label code !
  475. + first inlined procedures and function work
  476. (warning there might be allowed cases were the result is still wrong !!)
  477. * UseBrower updated gives a global list of all position of all used symbols
  478. with switch -gb
  479. Revision 1.2 1998/04/30 15:59:39 pierre
  480. * GDB works again better :
  481. correct type info in one pass
  482. + UseTokenInfo for better source position
  483. * fixed one remaining bug in scanner for line counts
  484. * several little fixes
  485. }