lineinfo.pp 24 KB

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