lineinfo.pp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  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 Unix}
  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 Unix}
  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}
  422. {$ifdef sunos}
  423. function LoadElf32:boolean;
  424. type
  425. telf32header=packed record
  426. magic0123 : longint;
  427. file_class : byte;
  428. data_encoding : byte;
  429. file_version : byte;
  430. padding : array[$07..$0f] of byte;
  431. e_type : word;
  432. e_machine : word;
  433. e_version : longword;
  434. e_entry : longword; // entrypoint
  435. e_phoff : longword; // program header offset
  436. e_shoff : longword; // sections header offset
  437. e_flags : longword;
  438. e_ehsize : word; // elf header size in bytes
  439. e_phentsize : word; // size of an entry in the program header array
  440. e_phnum : word; // 0..e_phnum-1 of entrys
  441. e_shentsize : word; // size of an entry in sections header array
  442. e_shnum : word; // 0..e_shnum-1 of entrys
  443. e_shstrndx : word; // index of string section header
  444. end;
  445. telf32sechdr=packed record
  446. sh_name : longword;
  447. sh_type : longword;
  448. sh_flags : longword;
  449. sh_addr : longword;
  450. sh_offset : longword;
  451. sh_size : longword;
  452. sh_link : longword;
  453. sh_info : longword;
  454. sh_addralign : longword;
  455. sh_entsize : longword;
  456. end;
  457. var
  458. elfheader : telf32header;
  459. elfsec : telf32sechdr;
  460. secnames : array[0..255] of char;
  461. pname : pchar;
  462. i : longint;
  463. begin
  464. processaddress := 0;
  465. LoadElf32:=false;
  466. stabofs:=-1;
  467. stabstrofs:=-1;
  468. { read and check header }
  469. if filesize(f)<sizeof(telf32header) then
  470. exit;
  471. blockread(f,elfheader,sizeof(telf32header));
  472. {$ifdef ENDIAN_LITTLE}
  473. if elfheader.magic0123<>$464c457f then
  474. exit;
  475. {$endif ENDIAN_LITTLE}
  476. {$ifdef ENDIAN_BIG}
  477. if elfheader.magic0123<>$7f454c46 then
  478. exit;
  479. { this seems to be at least the case for m68k cpu PM }
  480. {$endif ENDIAN_BIG}
  481. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  482. exit;
  483. { read section names }
  484. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  485. blockread(f,elfsec,sizeof(telf32sechdr));
  486. seek(f,elfsec.sh_offset);
  487. blockread(f,secnames,sizeof(secnames));
  488. { read section info }
  489. seek(f,elfheader.e_shoff);
  490. for i:=1to elfheader.e_shnum do
  491. begin
  492. blockread(f,elfsec,sizeof(telf32sechdr));
  493. pname:=@secnames[elfsec.sh_name];
  494. if (pname[4]='b') and
  495. (pname[1]='s') and
  496. (pname[2]='t') then
  497. begin
  498. if (pname[5]='s') and
  499. (pname[6]='t') then
  500. stabstrofs:=elfsec.sh_offset
  501. else
  502. begin
  503. stabofs:=elfsec.sh_offset;
  504. stabcnt:=elfsec.sh_size div sizeof(tstab);
  505. end;
  506. end;
  507. end;
  508. LoadElf32:=(stabofs<>-1) and (stabstrofs<>-1);
  509. end;
  510. {$endif sunos}
  511. {$ifdef beos}
  512. {$i osposixh.inc}
  513. {$i syscall.inc}
  514. {$i beos.inc}
  515. 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';
  516. function LoadElf32:boolean;
  517. type
  518. telf32header=packed record
  519. magic0123 : longint;
  520. file_class : byte;
  521. data_encoding : byte;
  522. file_version : byte;
  523. padding : array[$07..$0f] of byte;
  524. e_type : word;
  525. e_machine : word;
  526. e_version : longword;
  527. e_entry : longword; // entrypoint
  528. e_phoff : longword; // program header offset
  529. e_shoff : longword; // sections header offset
  530. e_flags : longword;
  531. e_ehsize : word; // elf header size in bytes
  532. e_phentsize : word; // size of an entry in the program header array
  533. e_phnum : word; // 0..e_phnum-1 of entrys
  534. e_shentsize : word; // size of an entry in sections header array
  535. e_shnum : word; // 0..e_shnum-1 of entrys
  536. e_shstrndx : word; // index of string section header
  537. end;
  538. telf32sechdr=packed record
  539. sh_name : longword;
  540. sh_type : longword;
  541. sh_flags : longword;
  542. sh_addr : longword;
  543. sh_offset : longword;
  544. sh_size : longword;
  545. sh_link : longword;
  546. sh_info : longword;
  547. sh_addralign : longword;
  548. sh_entsize : longword;
  549. end;
  550. var
  551. elfheader : telf32header;
  552. elfsec : telf32sechdr;
  553. secnames : array[0..255] of char;
  554. pname : pchar;
  555. i : longint;
  556. cookie : longint;
  557. info : image_info;
  558. result : status_t;
  559. begin
  560. cookie := 0;
  561. fillchar(info, sizeof(image_info), 0);
  562. get_next_image_info(0,cookie,info,sizeof(info));
  563. if (info._type = B_APP_IMAGE) then
  564. processaddress := cardinal(info.text)
  565. else
  566. processaddress := 0;
  567. LoadElf32:=false;
  568. stabofs:=-1;
  569. stabstrofs:=-1;
  570. { read and check header }
  571. if filesize(f)<sizeof(telf32header) then
  572. exit;
  573. blockread(f,elfheader,sizeof(telf32header));
  574. {$ifdef ENDIAN_LITTLE}
  575. if elfheader.magic0123<>$464c457f then
  576. exit;
  577. {$endif ENDIAN_LITTLE}
  578. {$ifdef ENDIAN_BIG}
  579. if elfheader.magic0123<>$7f454c46 then
  580. exit;
  581. {$endif ENDIAN_BIG}
  582. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  583. exit;
  584. { read section names }
  585. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  586. blockread(f,elfsec,sizeof(telf32sechdr));
  587. seek(f,elfsec.sh_offset);
  588. blockread(f,secnames,sizeof(secnames));
  589. { read section info }
  590. seek(f,elfheader.e_shoff);
  591. for i:=1to elfheader.e_shnum do
  592. begin
  593. blockread(f,elfsec,sizeof(telf32sechdr));
  594. pname:=@secnames[elfsec.sh_name];
  595. if (pname[4]='b') and
  596. (pname[1]='s') and
  597. (pname[2]='t') then
  598. begin
  599. if (pname[5]='s') and
  600. (pname[6]='t') then
  601. stabstrofs:=elfsec.sh_offset
  602. else
  603. begin
  604. stabofs:=elfsec.sh_offset;
  605. stabcnt:=elfsec.sh_size div sizeof(tstab);
  606. end;
  607. end;
  608. end;
  609. LoadElf32:=(stabofs<>-1) and (stabstrofs<>-1);
  610. end;
  611. {$endif beos}
  612. {****************************************************************************
  613. Executable Open/Close
  614. ****************************************************************************}
  615. procedure CloseStabs;
  616. begin
  617. close(f);
  618. opened:=false;
  619. end;
  620. function OpenStabs:boolean;
  621. var
  622. ofm : word;
  623. begin
  624. OpenStabs:=false;
  625. assign(f,paramstr(0));
  626. {$I-}
  627. ofm:=filemode;
  628. filemode:=$40;
  629. reset(f,1);
  630. filemode:=ofm;
  631. {$I+}
  632. if ioresult<>0 then
  633. exit;
  634. opened:=true;
  635. {$ifdef go32v2}
  636. if LoadGo32Coff then
  637. begin
  638. OpenStabs:=true;
  639. exit;
  640. end;
  641. {$endif}
  642. {$IFDEF EMX}
  643. if LoadEMXaout then
  644. begin
  645. OpenStabs:=true;
  646. exit;
  647. end;
  648. {$ENDIF EMX}
  649. {$ifdef win32}
  650. if LoadPECoff then
  651. begin
  652. OpenStabs:=true;
  653. exit;
  654. end;
  655. {$endif}
  656. {$ifdef Unix}
  657. if LoadElf32 then
  658. begin
  659. OpenStabs:=true;
  660. exit;
  661. end;
  662. {$endif}
  663. {$ifdef sunos}
  664. if LoadElf32 then
  665. begin
  666. OpenStabs:=true;
  667. exit;
  668. end;
  669. {$endif}
  670. {$ifdef beos}
  671. if LoadElf32 then
  672. begin
  673. OpenStabs:=true;
  674. exit;
  675. end;
  676. {$endif}
  677. CloseStabs;
  678. end;
  679. {$Q-}
  680. { this avoids problems with some targets PM }
  681. procedure GetLineInfo(addr:dword;var func,source:string;var line:longint);
  682. var
  683. res : {$ifdef tp}integer{$else}longint{$endif};
  684. stabsleft,
  685. stabscnt,i : longint;
  686. found : boolean;
  687. lastfunc : tstab;
  688. begin
  689. fillchar(func,high(func)+1,0);
  690. fillchar(source,high(source)+1,0);
  691. line:=0;
  692. if not opened then
  693. begin
  694. if not OpenStabs then
  695. exit;
  696. end;
  697. { correct the value to the correct address in the file }
  698. { processaddress is set in OpenStabs }
  699. addr := addr - processaddress;
  700. fillchar(funcstab,sizeof(tstab),0);
  701. fillchar(filestab,sizeof(tstab),0);
  702. fillchar(dirstab,sizeof(tstab),0);
  703. fillchar(linestab,sizeof(tstab),0);
  704. fillchar(lastfunc,sizeof(tstab),0);
  705. found:=false;
  706. seek(f,stabofs);
  707. stabsleft:=stabcnt;
  708. repeat
  709. if stabsleft>maxstabs then
  710. stabscnt:=maxstabs
  711. else
  712. stabscnt:=stabsleft;
  713. blockread(f,stabs,stabscnt*sizeof(tstab),res);
  714. stabscnt:=res div sizeof(tstab);
  715. for i:=0 to stabscnt-1 do
  716. begin
  717. case stabs[i].ntype of
  718. N_BssLine,
  719. N_DataLine,
  720. N_TextLine :
  721. begin
  722. if (stabs[i].ntype=N_TextLine) and StabsFunctionRelative then
  723. inc(stabs[i].nvalue,lastfunc.nvalue);
  724. if (stabs[i].nvalue<=addr) and
  725. (stabs[i].nvalue>linestab.nvalue) then
  726. begin
  727. { if it's equal we can stop and take the last info }
  728. if stabs[i].nvalue=addr then
  729. found:=true
  730. else
  731. linestab:=stabs[i];
  732. end;
  733. end;
  734. N_Function :
  735. begin
  736. lastfunc:=stabs[i];
  737. if (stabs[i].nvalue<=addr) and
  738. (stabs[i].nvalue>funcstab.nvalue) then
  739. begin
  740. funcstab:=stabs[i];
  741. fillchar(linestab,sizeof(tstab),0);
  742. end;
  743. end;
  744. N_SourceFile,
  745. N_IncludeFile :
  746. begin
  747. if (stabs[i].nvalue<=addr) and
  748. (stabs[i].nvalue>=filestab.nvalue) then
  749. begin
  750. { if same value and type then the first one
  751. contained the directory PM }
  752. if (stabs[i].nvalue=filestab.nvalue) and
  753. (stabs[i].ntype=filestab.ntype) then
  754. dirstab:=filestab
  755. else
  756. fillchar(dirstab,sizeof(tstab),0);
  757. filestab:=stabs[i];
  758. fillchar(linestab,sizeof(tstab),0);
  759. { if new file then func is not valid anymore PM }
  760. if stabs[i].ntype=N_SourceFile then
  761. begin
  762. fillchar(funcstab,sizeof(tstab),0);
  763. fillchar(lastfunc,sizeof(tstab),0);
  764. end;
  765. end;
  766. end;
  767. end;
  768. end;
  769. dec(stabsleft,stabscnt);
  770. until found or (stabsleft=0);
  771. { get the line,source,function info }
  772. line:=linestab.ndesc;
  773. if dirstab.ntype<>0 then
  774. begin
  775. seek(f,stabstrofs+dirstab.strpos);
  776. blockread(f,source[1],high(source)-1,res);
  777. dirlength:=strlen(@source[1]);
  778. source[0]:=chr(dirlength);
  779. end
  780. else
  781. dirlength:=0;
  782. if filestab.ntype<>0 then
  783. begin
  784. seek(f,stabstrofs+filestab.strpos);
  785. blockread(f,source[dirlength+1],high(source)-(dirlength+1),res);
  786. source[0]:=chr(strlen(@source[1]));
  787. end;
  788. if funcstab.ntype<>0 then
  789. begin
  790. seek(f,stabstrofs+funcstab.strpos);
  791. blockread(f,func[1],high(func)-1,res);
  792. func[0]:=chr(strlen(@func[1]));
  793. i:=pos(':',func);
  794. if i>0 then
  795. Delete(func,i,255);
  796. end;
  797. end;
  798. function StabBackTraceStr(addr:longint):shortstring;
  799. var
  800. func,
  801. source : string;
  802. hs : string[32];
  803. line : longint;
  804. Store : TBackTraceStrFunc;
  805. begin
  806. { reset to prevent infinite recursion if problems inside the code PM }
  807. Store:=BackTraceStrFunc;
  808. BackTraceStrFunc:=@SysBackTraceStr;
  809. GetLineInfo(dword(addr),func,source,line);
  810. { create string }
  811. StabBackTraceStr:=' 0x'+HexStr(addr,8);
  812. if func<>'' then
  813. StabBackTraceStr:=StabBackTraceStr+' '+func;
  814. if source<>'' then
  815. begin
  816. if func<>'' then
  817. StabBackTraceStr:=StabBackTraceStr+', ';
  818. if line<>0 then
  819. begin
  820. str(line,hs);
  821. StabBackTraceStr:=StabBackTraceStr+' line '+hs;
  822. end;
  823. StabBackTraceStr:=StabBackTraceStr+' of '+source;
  824. end;
  825. if Opened then
  826. BackTraceStrFunc:=Store;
  827. end;
  828. initialization
  829. BackTraceStrFunc:=@StabBackTraceStr;
  830. finalization
  831. if opened then
  832. CloseStabs;
  833. end.
  834. {
  835. $Log$
  836. Revision 1.9 2002-05-31 13:37:24 marco
  837. * more Renamefest
  838. Revision 1.8 2001/12/13 03:50:00 carl
  839. + SunOS target
  840. Revision 1.1 2000/07/13 06:30:47 michael
  841. + Initial import
  842. }