lineinfo.pp 25 KB

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