lineinfo.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2000 by Peter Vreman
  5. Stabs Line Info Retriever
  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 lineinfo;
  13. interface
  14. {$IFDEF OS2}
  15. {$DEFINE EMX} (* EMX is the only possibility under OS/2 at the moment *)
  16. {$ENDIF OS2}
  17. { This is very important as this code can be called
  18. from inside the RTE 202 error PM }
  19. {$ifndef linux}
  20. {$S-}
  21. {$endif}
  22. procedure GetLineInfo(addr:dword;var func,source:string;var line:longint);
  23. implementation
  24. uses
  25. strings;
  26. const
  27. N_Function = $24;
  28. N_TextLine = $44;
  29. N_DataLine = $46;
  30. N_BssLine = $48;
  31. N_SourceFile = $64;
  32. N_IncludeFile = $84;
  33. maxstabs = 40; { size of the stabs buffer }
  34. { GDB after 4.18 uses offset to function begin
  35. in text section but OS/2 version still uses 4.16 PM }
  36. StabsFunctionRelative : boolean = true;
  37. type
  38. pstab=^tstab;
  39. tstab=packed record
  40. strpos : longint;
  41. ntype : byte;
  42. nother : byte;
  43. ndesc : word;
  44. nvalue : dword;
  45. end;
  46. { We use static variable so almost no stack is required, and is thus
  47. more safe when an error has occured in the program }
  48. var
  49. opened : boolean; { set if the file is already open }
  50. f : file; { current file }
  51. stabcnt, { amount of stabs }
  52. stabofs, { absolute stab section offset in executable }
  53. stabstrofs : longint; { absolute stabstr section offset in executable }
  54. dirlength : longint; { length of the dirctory part of the source file }
  55. stabs : array[0..maxstabs-1] of tstab; { buffer }
  56. funcstab, { stab with current function info }
  57. linestab, { stab with current line info }
  58. dirstab, { stab with current directory info }
  59. filestab : tstab; { stab with current file info }
  60. { value to subtract to addr parameter to get correct address on file }
  61. { this should be equal to the process start address in memory }
  62. processaddress : cardinal;
  63. {****************************************************************************
  64. Executable Loaders
  65. ****************************************************************************}
  66. {$ifdef go32v2}
  67. function LoadGo32Coff:boolean;
  68. type
  69. tcoffheader=packed record
  70. mach : word;
  71. nsects : word;
  72. time : longint;
  73. sympos : longint;
  74. syms : longint;
  75. opthdr : word;
  76. flag : word;
  77. other : array[0..27] of byte;
  78. end;
  79. tcoffsechdr=packed record
  80. name : array[0..7] of char;
  81. vsize : longint;
  82. rvaofs : longint;
  83. datalen : longint;
  84. datapos : longint;
  85. relocpos : longint;
  86. lineno1 : longint;
  87. nrelocs : word;
  88. lineno2 : word;
  89. flags : longint;
  90. end;
  91. var
  92. coffheader : tcoffheader;
  93. coffsec : tcoffsechdr;
  94. i : longint;
  95. begin
  96. processaddress := 0;
  97. LoadGo32Coff:=false;
  98. stabofs:=-1;
  99. stabstrofs:=-1;
  100. { read and check header }
  101. if filesize(f)<2048+sizeof(tcoffheader) then
  102. exit;
  103. seek(f,2048);
  104. blockread(f,coffheader,sizeof(tcoffheader));
  105. if coffheader.mach<>$14c then
  106. exit;
  107. { read section info }
  108. for i:=1to coffheader.nSects do
  109. begin
  110. blockread(f,coffsec,sizeof(tcoffsechdr));
  111. if (coffsec.name[4]='b') and
  112. (coffsec.name[1]='s') and
  113. (coffsec.name[2]='t') then
  114. begin
  115. if (coffsec.name[5]='s') and
  116. (coffsec.name[6]='t') then
  117. stabstrofs:=coffsec.datapos+2048
  118. else
  119. begin
  120. stabofs:=coffsec.datapos+2048;
  121. stabcnt:=coffsec.datalen div sizeof(tstab);
  122. end;
  123. end;
  124. end;
  125. LoadGo32Coff:=(stabofs<>-1) and (stabstrofs<>-1);
  126. end;
  127. {$endif Go32v2}
  128. {$ifdef win32}
  129. function LoadPeCoff:boolean;
  130. type
  131. tdosheader = packed record
  132. e_magic : word;
  133. e_cblp : word;
  134. e_cp : word;
  135. e_crlc : word;
  136. e_cparhdr : word;
  137. e_minalloc : word;
  138. e_maxalloc : word;
  139. e_ss : word;
  140. e_sp : word;
  141. e_csum : word;
  142. e_ip : word;
  143. e_cs : word;
  144. e_lfarlc : word;
  145. e_ovno : word;
  146. e_res : array[0..3] of word;
  147. e_oemid : word;
  148. e_oeminfo : word;
  149. e_res2 : array[0..9] of word;
  150. e_lfanew : longint;
  151. end;
  152. tpeheader = packed record
  153. PEMagic : longint;
  154. Machine : word;
  155. NumberOfSections : word;
  156. TimeDateStamp : longint;
  157. PointerToSymbolTable : longint;
  158. NumberOfSymbols : longint;
  159. SizeOfOptionalHeader : word;
  160. Characteristics : word;
  161. Magic : word;
  162. MajorLinkerVersion : byte;
  163. MinorLinkerVersion : byte;
  164. SizeOfCode : longint;
  165. SizeOfInitializedData : longint;
  166. SizeOfUninitializedData : longint;
  167. AddressOfEntryPoint : longint;
  168. BaseOfCode : longint;
  169. BaseOfData : longint;
  170. ImageBase : longint;
  171. SectionAlignment : longint;
  172. FileAlignment : longint;
  173. MajorOperatingSystemVersion : word;
  174. MinorOperatingSystemVersion : word;
  175. MajorImageVersion : word;
  176. MinorImageVersion : word;
  177. MajorSubsystemVersion : word;
  178. MinorSubsystemVersion : word;
  179. Reserved1 : longint;
  180. SizeOfImage : longint;
  181. SizeOfHeaders : longint;
  182. CheckSum : longint;
  183. Subsystem : word;
  184. DllCharacteristics : word;
  185. SizeOfStackReserve : longint;
  186. SizeOfStackCommit : longint;
  187. SizeOfHeapReserve : longint;
  188. SizeOfHeapCommit : longint;
  189. LoaderFlags : longint;
  190. NumberOfRvaAndSizes : longint;
  191. DataDirectory : array[1..$80] of byte;
  192. end;
  193. tcoffsechdr=packed record
  194. name : array[0..7] of char;
  195. vsize : longint;
  196. rvaofs : longint;
  197. datalen : longint;
  198. datapos : longint;
  199. relocpos : longint;
  200. lineno1 : longint;
  201. nrelocs : word;
  202. lineno2 : word;
  203. flags : longint;
  204. end;
  205. var
  206. dosheader : tdosheader;
  207. peheader : tpeheader;
  208. coffsec : tcoffsechdr;
  209. i : longint;
  210. begin
  211. processaddress := 0;
  212. LoadPeCoff:=false;
  213. stabofs:=-1;
  214. stabstrofs:=-1;
  215. { read and check header }
  216. if filesize(f)<sizeof(dosheader) then
  217. exit;
  218. blockread(f,dosheader,sizeof(tdosheader));
  219. seek(f,dosheader.e_lfanew);
  220. blockread(f,peheader,sizeof(tpeheader));
  221. if peheader.pemagic<>$4550 then
  222. exit;
  223. { read section info }
  224. for i:=1to peheader.NumberOfSections do
  225. begin
  226. blockread(f,coffsec,sizeof(tcoffsechdr));
  227. if (coffsec.name[4]='b') and
  228. (coffsec.name[1]='s') and
  229. (coffsec.name[2]='t') then
  230. begin
  231. if (coffsec.name[5]='s') and
  232. (coffsec.name[6]='t') then
  233. stabstrofs:=coffsec.datapos
  234. else
  235. begin
  236. stabofs:=coffsec.datapos;
  237. stabcnt:=coffsec.datalen div sizeof(tstab);
  238. end;
  239. end;
  240. end;
  241. LoadPeCoff:=(stabofs<>-1) and (stabstrofs<>-1);
  242. end;
  243. {$endif Win32}
  244. {$IFDEF EMX}
  245. function LoadEMXaout: boolean;
  246. type
  247. TDosHeader = packed record
  248. e_magic : word;
  249. e_cblp : word;
  250. e_cp : word;
  251. e_crlc : word;
  252. e_cparhdr : word;
  253. e_minalloc : word;
  254. e_maxalloc : word;
  255. e_ss : word;
  256. e_sp : word;
  257. e_csum : word;
  258. e_ip : word;
  259. e_cs : word;
  260. e_lfarlc : word;
  261. e_ovno : word;
  262. e_res : array[0..3] of word;
  263. e_oemid : word;
  264. e_oeminfo : word;
  265. e_res2 : array[0..9] of word;
  266. e_lfanew : longint;
  267. end;
  268. TEmxHeader = packed record
  269. Version: array [1..16] of char;
  270. Bound: word;
  271. AoutOfs: longint;
  272. Options: array [1..42] of char;
  273. end;
  274. TAoutHeader = packed record
  275. Magic: word;
  276. Machine: byte;
  277. Flags: byte;
  278. TextSize: longint;
  279. DataSize: longint;
  280. BssSize: longint;
  281. SymbSize: longint;
  282. EntryPoint: longint;
  283. TextRelocSize: longint;
  284. DataRelocSize: longint;
  285. end;
  286. const
  287. StartPageSize = $1000;
  288. var
  289. DosHeader: TDosHeader;
  290. EmxHeader: TEmxHeader;
  291. AoutHeader: TAoutHeader;
  292. S4: string [4];
  293. begin
  294. processaddress := 0;
  295. LoadEMXaout := false;
  296. StabOfs := -1;
  297. StabStrOfs := -1;
  298. { read and check header }
  299. if FileSize (F) > SizeOf (DosHeader) then
  300. begin
  301. BlockRead (F, DosHeader, SizeOf (TDosHeader));
  302. Seek (F, DosHeader.e_cparhdr shl 4);
  303. BlockRead (F, EmxHeader, SizeOf (TEmxHeader));
  304. S4 [0] := #4;
  305. Move (EmxHeader.Version, S4 [1], 4);
  306. if S4 = 'emx ' then
  307. begin
  308. Seek (F, EmxHeader.AoutOfs);
  309. BlockRead (F, AoutHeader, SizeOf (TAoutHeader));
  310. if AOutHeader.Magic=$10B then
  311. StabOfs := StartPageSize
  312. else
  313. StabOfs :=EmxHeader.AoutOfs + SizeOf (TAoutHeader);
  314. StabOfs := StabOfs
  315. + AoutHeader.TextSize
  316. + AoutHeader.DataSize
  317. + AoutHeader.TextRelocSize
  318. + AoutHeader.DataRelocSize;
  319. (* I don't really know, where this "+ 4" comes from, *)
  320. (* but it seems to be correct. :-) - TH *)
  321. (* Maybe not PM *)
  322. StabCnt := AoutHeader.SymbSize div SizeOf (TStab);
  323. StabStrOfs := StabOfs + AoutHeader.SymbSize;
  324. StabsFunctionRelative:=false;
  325. LoadEMXaout := (StabOfs <> -1) and (StabStrOfs <> -1);
  326. end;
  327. end;
  328. end;
  329. {$ENDIF EMX}
  330. {$ifdef linux}
  331. function LoadElf32:boolean;
  332. type
  333. telf32header=packed record
  334. magic0123 : longint;
  335. file_class : byte;
  336. data_encoding : byte;
  337. file_version : byte;
  338. padding : array[$07..$0f] of byte;
  339. e_type : word;
  340. e_machine : word;
  341. e_version : longword;
  342. e_entry : longword; // entrypoint
  343. e_phoff : longword; // program header offset
  344. e_shoff : longword; // sections header offset
  345. e_flags : longword;
  346. e_ehsize : word; // elf header size in bytes
  347. e_phentsize : word; // size of an entry in the program header array
  348. e_phnum : word; // 0..e_phnum-1 of entrys
  349. e_shentsize : word; // size of an entry in sections header array
  350. e_shnum : word; // 0..e_shnum-1 of entrys
  351. e_shstrndx : word; // index of string section header
  352. end;
  353. telf32sechdr=packed record
  354. sh_name : longword;
  355. sh_type : longword;
  356. sh_flags : longword;
  357. sh_addr : longword;
  358. sh_offset : longword;
  359. sh_size : longword;
  360. sh_link : longword;
  361. sh_info : longword;
  362. sh_addralign : longword;
  363. sh_entsize : longword;
  364. end;
  365. var
  366. elfheader : telf32header;
  367. elfsec : telf32sechdr;
  368. secnames : array[0..255] of char;
  369. pname : pchar;
  370. i : longint;
  371. begin
  372. processaddress := 0;
  373. LoadElf32:=false;
  374. stabofs:=-1;
  375. stabstrofs:=-1;
  376. { read and check header }
  377. if filesize(f)<sizeof(telf32header) then
  378. exit;
  379. blockread(f,elfheader,sizeof(telf32header));
  380. {$ifdef ENDIAN_LITTLE}
  381. if elfheader.magic0123<>$464c457f then
  382. exit;
  383. {$endif ENDIAN_LITTLE}
  384. {$ifdef ENDIAN_BIG}
  385. if elfheader.magic0123<>$7f454c46 then
  386. exit;
  387. { this seems to be at least the case for m68k cpu PM }
  388. {$ifdef m68k}
  389. {StabsFunctionRelative:=false;}
  390. {$endif m68k}
  391. {$endif ENDIAN_BIG}
  392. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  393. exit;
  394. { read section names }
  395. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  396. blockread(f,elfsec,sizeof(telf32sechdr));
  397. seek(f,elfsec.sh_offset);
  398. blockread(f,secnames,sizeof(secnames));
  399. { read section info }
  400. seek(f,elfheader.e_shoff);
  401. for i:=1to elfheader.e_shnum do
  402. begin
  403. blockread(f,elfsec,sizeof(telf32sechdr));
  404. pname:=@secnames[elfsec.sh_name];
  405. if (pname[4]='b') and
  406. (pname[1]='s') and
  407. (pname[2]='t') then
  408. begin
  409. if (pname[5]='s') and
  410. (pname[6]='t') then
  411. stabstrofs:=elfsec.sh_offset
  412. else
  413. begin
  414. stabofs:=elfsec.sh_offset;
  415. stabcnt:=elfsec.sh_size div sizeof(tstab);
  416. end;
  417. end;
  418. end;
  419. LoadElf32:=(stabofs<>-1) and (stabstrofs<>-1);
  420. end;
  421. {$endif linux}
  422. {$ifdef beos}
  423. {$linklib root}
  424. {$i osposixh.inc}
  425. {$i syscall.inc}
  426. {$i beos.inc}
  427. function get_next_image_info(team: team_id; var cookie:longint; var info:image_info; size: size_t) : status_t;cdecl; external 'root'; external name '_get_next_image_info';
  428. function LoadElf32:boolean;
  429. type
  430. telf32header=packed record
  431. magic0123 : longint;
  432. file_class : byte;
  433. data_encoding : byte;
  434. file_version : byte;
  435. padding : array[$07..$0f] of byte;
  436. e_type : word;
  437. e_machine : word;
  438. e_version : longword;
  439. e_entry : longword; // entrypoint
  440. e_phoff : longword; // program header offset
  441. e_shoff : longword; // sections header offset
  442. e_flags : longword;
  443. e_ehsize : word; // elf header size in bytes
  444. e_phentsize : word; // size of an entry in the program header array
  445. e_phnum : word; // 0..e_phnum-1 of entrys
  446. e_shentsize : word; // size of an entry in sections header array
  447. e_shnum : word; // 0..e_shnum-1 of entrys
  448. e_shstrndx : word; // index of string section header
  449. end;
  450. telf32sechdr=packed record
  451. sh_name : longword;
  452. sh_type : longword;
  453. sh_flags : longword;
  454. sh_addr : longword;
  455. sh_offset : longword;
  456. sh_size : longword;
  457. sh_link : longword;
  458. sh_info : longword;
  459. sh_addralign : longword;
  460. sh_entsize : longword;
  461. end;
  462. var
  463. elfheader : telf32header;
  464. elfsec : telf32sechdr;
  465. secnames : array[0..255] of char;
  466. pname : pchar;
  467. i : longint;
  468. cookie : longint;
  469. info : image_info;
  470. result : status_t;
  471. begin
  472. cookie := 0;
  473. fillchar(info, sizeof(image_info), 0);
  474. get_next_image_info(0,cookie,info,sizeof(info));
  475. if (info._type = B_APP_IMAGE) then
  476. processaddress := cardinal(info.text)
  477. else
  478. processaddress := 0;
  479. LoadElf32:=false;
  480. stabofs:=-1;
  481. stabstrofs:=-1;
  482. { read and check header }
  483. if filesize(f)<sizeof(telf32header) then
  484. exit;
  485. blockread(f,elfheader,sizeof(telf32header));
  486. {$ifdef ENDIAN_LITTLE}
  487. if elfheader.magic0123<>$464c457f then
  488. exit;
  489. {$endif ENDIAN_LITTLE}
  490. {$ifdef ENDIAN_BIG}
  491. if elfheader.magic0123<>$7f454c46 then
  492. exit;
  493. {$endif ENDIAN_BIG}
  494. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  495. exit;
  496. { read section names }
  497. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  498. blockread(f,elfsec,sizeof(telf32sechdr));
  499. seek(f,elfsec.sh_offset);
  500. blockread(f,secnames,sizeof(secnames));
  501. { read section info }
  502. seek(f,elfheader.e_shoff);
  503. for i:=1to elfheader.e_shnum do
  504. begin
  505. blockread(f,elfsec,sizeof(telf32sechdr));
  506. pname:=@secnames[elfsec.sh_name];
  507. if (pname[4]='b') and
  508. (pname[1]='s') and
  509. (pname[2]='t') then
  510. begin
  511. if (pname[5]='s') and
  512. (pname[6]='t') then
  513. stabstrofs:=elfsec.sh_offset
  514. else
  515. begin
  516. stabofs:=elfsec.sh_offset;
  517. stabcnt:=elfsec.sh_size div sizeof(tstab);
  518. end;
  519. end;
  520. end;
  521. LoadElf32:=(stabofs<>-1) and (stabstrofs<>-1);
  522. end;
  523. {$endif beos}
  524. {****************************************************************************
  525. Executable Open/Close
  526. ****************************************************************************}
  527. procedure CloseStabs;
  528. begin
  529. close(f);
  530. opened:=false;
  531. end;
  532. function OpenStabs:boolean;
  533. var
  534. ofm : word;
  535. begin
  536. OpenStabs:=false;
  537. assign(f,paramstr(0));
  538. {$I-}
  539. ofm:=filemode;
  540. filemode:=$40;
  541. reset(f,1);
  542. filemode:=ofm;
  543. {$I+}
  544. if ioresult<>0 then
  545. exit;
  546. opened:=true;
  547. {$ifdef go32v2}
  548. if LoadGo32Coff then
  549. begin
  550. OpenStabs:=true;
  551. exit;
  552. end;
  553. {$endif}
  554. {$IFDEF EMX}
  555. if LoadEMXaout then
  556. begin
  557. OpenStabs:=true;
  558. exit;
  559. end;
  560. {$ENDIF EMX}
  561. {$ifdef win32}
  562. if LoadPECoff then
  563. begin
  564. OpenStabs:=true;
  565. exit;
  566. end;
  567. {$endif}
  568. {$ifdef linux}
  569. if LoadElf32 then
  570. begin
  571. OpenStabs:=true;
  572. exit;
  573. end;
  574. {$endif}
  575. {$ifdef beos}
  576. if LoadElf32 then
  577. begin
  578. OpenStabs:=true;
  579. exit;
  580. end;
  581. {$endif}
  582. CloseStabs;
  583. end;
  584. {$Q-}
  585. { this avoids problems with some targets PM }
  586. procedure GetLineInfo(addr:dword;var func,source:string;var line:longint);
  587. var
  588. res : {$ifdef tp}integer{$else}longint{$endif};
  589. stabsleft,
  590. stabscnt,i : longint;
  591. found : boolean;
  592. lastfunc : tstab;
  593. begin
  594. fillchar(func,high(func)+1,0);
  595. fillchar(source,high(source)+1,0);
  596. line:=0;
  597. if not opened then
  598. begin
  599. if not OpenStabs then
  600. exit;
  601. end;
  602. { correct the value to the correct address in the file }
  603. { processaddress is set in OpenStabs }
  604. addr := addr - processaddress;
  605. fillchar(funcstab,sizeof(tstab),0);
  606. fillchar(filestab,sizeof(tstab),0);
  607. fillchar(dirstab,sizeof(tstab),0);
  608. fillchar(linestab,sizeof(tstab),0);
  609. fillchar(lastfunc,sizeof(tstab),0);
  610. found:=false;
  611. seek(f,stabofs);
  612. stabsleft:=stabcnt;
  613. repeat
  614. if stabsleft>maxstabs then
  615. stabscnt:=maxstabs
  616. else
  617. stabscnt:=stabsleft;
  618. blockread(f,stabs,stabscnt*sizeof(tstab),res);
  619. stabscnt:=res div sizeof(tstab);
  620. for i:=0 to stabscnt-1 do
  621. begin
  622. case stabs[i].ntype of
  623. N_BssLine,
  624. N_DataLine,
  625. N_TextLine :
  626. begin
  627. if (stabs[i].ntype=N_TextLine) and StabsFunctionRelative then
  628. inc(stabs[i].nvalue,lastfunc.nvalue);
  629. if (stabs[i].nvalue<=addr) and
  630. (stabs[i].nvalue>linestab.nvalue) then
  631. begin
  632. { if it's equal we can stop and take the last info }
  633. if stabs[i].nvalue=addr then
  634. found:=true
  635. else
  636. linestab:=stabs[i];
  637. end;
  638. end;
  639. N_Function :
  640. begin
  641. lastfunc:=stabs[i];
  642. if (stabs[i].nvalue<=addr) and
  643. (stabs[i].nvalue>funcstab.nvalue) then
  644. begin
  645. funcstab:=stabs[i];
  646. fillchar(linestab,sizeof(tstab),0);
  647. end;
  648. end;
  649. N_SourceFile,
  650. N_IncludeFile :
  651. begin
  652. if (stabs[i].nvalue<=addr) and
  653. (stabs[i].nvalue>=filestab.nvalue) then
  654. begin
  655. { if same value and type then the first one
  656. contained the directory PM }
  657. if (stabs[i].nvalue=filestab.nvalue) and
  658. (stabs[i].ntype=filestab.ntype) then
  659. dirstab:=filestab
  660. else
  661. fillchar(dirstab,sizeof(tstab),0);
  662. filestab:=stabs[i];
  663. fillchar(linestab,sizeof(tstab),0);
  664. { if new file then func is not valid anymore PM }
  665. if stabs[i].ntype=N_SourceFile then
  666. begin
  667. fillchar(funcstab,sizeof(tstab),0);
  668. fillchar(lastfunc,sizeof(tstab),0);
  669. end;
  670. end;
  671. end;
  672. end;
  673. end;
  674. dec(stabsleft,stabscnt);
  675. until found or (stabsleft=0);
  676. { get the line,source,function info }
  677. line:=linestab.ndesc;
  678. if dirstab.ntype<>0 then
  679. begin
  680. seek(f,stabstrofs+dirstab.strpos);
  681. blockread(f,source[1],high(source)-1,res);
  682. dirlength:=strlen(@source[1]);
  683. source[0]:=chr(dirlength);
  684. end
  685. else
  686. dirlength:=0;
  687. if filestab.ntype<>0 then
  688. begin
  689. seek(f,stabstrofs+filestab.strpos);
  690. blockread(f,source[dirlength+1],high(source)-(dirlength+1),res);
  691. source[0]:=chr(strlen(@source[1]));
  692. end;
  693. if funcstab.ntype<>0 then
  694. begin
  695. seek(f,stabstrofs+funcstab.strpos);
  696. blockread(f,func[1],high(func)-1,res);
  697. func[0]:=chr(strlen(@func[1]));
  698. i:=pos(':',func);
  699. if i>0 then
  700. Delete(func,i,255);
  701. end;
  702. end;
  703. function StabBackTraceStr(addr:longint):shortstring;
  704. var
  705. func,
  706. source : string;
  707. hs : string[32];
  708. line : longint;
  709. Store : TBackTraceStrFunc;
  710. begin
  711. { reset to prevent infinite recursion if problems inside the code PM }
  712. Store:=BackTraceStrFunc;
  713. BackTraceStrFunc:=@SysBackTraceStr;
  714. GetLineInfo(dword(addr),func,source,line);
  715. { create string }
  716. StabBackTraceStr:=' 0x'+HexStr(addr,8);
  717. if func<>'' then
  718. StabBackTraceStr:=StabBackTraceStr+' '+func;
  719. if source<>'' then
  720. begin
  721. if func<>'' then
  722. StabBackTraceStr:=StabBackTraceStr+', ';
  723. if line<>0 then
  724. begin
  725. str(line,hs);
  726. StabBackTraceStr:=StabBackTraceStr+' line '+hs;
  727. end;
  728. StabBackTraceStr:=StabBackTraceStr+' of '+source;
  729. end;
  730. if Opened then
  731. BackTraceStrFunc:=Store;
  732. end;
  733. initialization
  734. BackTraceStrFunc:=@StabBackTraceStr;
  735. finalization
  736. if opened then
  737. CloseStabs;
  738. end.
  739. {
  740. $Log$
  741. Revision 1.7 2001-11-19 02:45:10 carl
  742. + same version as fixed branches :
  743. + BeOS line information
  744. * correct prototype with shortstring result type
  745. + relocation of frame according to processaddress
  746. }