lineinfo.pp 22 KB

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