lineinfo.pp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2000 by Peter Vreman
  4. Stabs Line Info Retriever
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit lineinfo;
  12. interface
  13. {$IFDEF OS2}
  14. {$DEFINE EMX} (* EMX is the only possibility under OS/2 at the moment *)
  15. {$ENDIF OS2}
  16. {$S-}
  17. procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
  18. implementation
  19. uses
  20. strings;
  21. const
  22. N_Function = $24;
  23. N_TextLine = $44;
  24. N_DataLine = $46;
  25. N_BssLine = $48;
  26. N_SourceFile = $64;
  27. N_IncludeFile = $84;
  28. maxstabs = 40; { size of the stabs buffer }
  29. { GDB after 4.18 uses offset to function begin
  30. in text section but OS/2 version still uses 4.16 PM }
  31. StabsFunctionRelative : boolean = true;
  32. type
  33. pstab=^tstab;
  34. tstab=packed record
  35. strpos : longint;
  36. ntype : byte;
  37. nother : byte;
  38. ndesc : word;
  39. nvalue : dword;
  40. end;
  41. { We use static variable so almost no stack is required, and is thus
  42. more safe when an error has occured in the program }
  43. var
  44. opened : boolean; { set if the file is already open }
  45. f : file; { current file }
  46. stabcnt, { amount of stabs }
  47. stabofs, { absolute stab section offset in executable }
  48. stabstrofs : longint; { absolute stabstr section offset in executable }
  49. dirlength : longint; { length of the dirctory part of the source file }
  50. stabs : array[0..maxstabs-1] of tstab; { buffer }
  51. funcstab, { stab with current function info }
  52. linestab, { stab with current line info }
  53. dirstab, { stab with current directory info }
  54. filestab : tstab; { stab with current file info }
  55. { value to subtract to addr parameter to get correct address on file }
  56. { this should be equal to the process start address in memory }
  57. processaddress : cardinal;
  58. {****************************************************************************
  59. Executable Loaders
  60. ****************************************************************************}
  61. {$if defined(netbsd) or defined(freebsd) or defined(linux) or defined(sunos)}
  62. {$ifdef cpu64}
  63. {$define ELF64}
  64. {$else}
  65. {$define ELF32}
  66. {$endif}
  67. {$endif}
  68. {$ifdef netwlibc}
  69. {$define netware}
  70. {$endif}
  71. {$ifdef netware}
  72. const SIZE_OF_NLM_INTERNAL_FIXED_HEADER = 130;
  73. SIZE_OF_NLM_INTERNAL_VERSION_HEADER = 32;
  74. SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER = 124;
  75. function loadNetwareNLM:boolean;
  76. var valid : boolean;
  77. name : string;
  78. StabLength,
  79. StabStrLength,
  80. alignAmount,
  81. hdrLength,
  82. dataOffset,
  83. dataLength : longint;
  84. function getByte:byte;
  85. begin
  86. BlockRead (f,getByte,1);
  87. end;
  88. procedure Skip (bytes : longint);
  89. var i : longint;
  90. begin
  91. for i := 1 to bytes do getbyte;
  92. end;
  93. function getLString : String;
  94. var Res:string;
  95. begin
  96. blockread (F, res, 1);
  97. if length (res) > 0 THEN
  98. blockread (F, res[1], length (res));
  99. getbyte;
  100. getLString := res;
  101. end;
  102. function getFixString (Len : byte) : string;
  103. var i : byte;
  104. begin
  105. getFixString := '';
  106. for I := 1 to Len do
  107. getFixString := getFixString + char (getbyte);
  108. end;
  109. function get0String : string;
  110. var c : char;
  111. begin
  112. get0String := '';
  113. c := char (getbyte);
  114. while (c <> #0) do
  115. begin
  116. get0String := get0String + c;
  117. c := char (getbyte);
  118. end;
  119. end;
  120. function getword : word;
  121. begin
  122. blockread (F, getword, 2);
  123. end;
  124. function getint32 : longint;
  125. begin
  126. blockread (F, getint32, 4);
  127. end;
  128. begin
  129. processaddress := 0;
  130. LoadNetwareNLM:=false;
  131. stabofs:=-1;
  132. stabstrofs:=-1;
  133. { read and check header }
  134. Skip (SIZE_OF_NLM_INTERNAL_FIXED_HEADER);
  135. getLString; // NLM Description
  136. getInt32; // Stacksize
  137. getInt32; // Reserved
  138. skip(5); // old Thread Name
  139. getLString; // Screen Name
  140. getLString; // Thread Name
  141. hdrLength := -1;
  142. dataOffset := -1;
  143. dataLength := -1;
  144. valid := true;
  145. repeat
  146. name := getFixString (8);
  147. if (name = 'VeRsIoN#') then
  148. begin
  149. Skip (SIZE_OF_NLM_INTERNAL_VERSION_HEADER-8);
  150. end else
  151. if (name = 'CoPyRiGh') then
  152. begin
  153. getword; // T=
  154. getLString; // Copyright String
  155. end else
  156. if (name = 'MeSsAgEs') then
  157. begin
  158. skip (SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER - 8);
  159. end else
  160. if (name = 'CuStHeAd') then
  161. begin
  162. hdrLength := getInt32;
  163. dataOffset := getInt32;
  164. dataLength := getInt32;
  165. Skip (8); // dataStamp
  166. Valid := false;
  167. end else
  168. Valid := false;
  169. until not valid;
  170. if (hdrLength = -1) or (dataOffset = -1) or (dataLength = -1) then
  171. exit;
  172. (* The format of the section information is:
  173. null terminated section name
  174. zeroes to adjust to 4 byte boundary
  175. 4 byte section data file pointer
  176. 4 byte section size *)
  177. Seek (F, dataOffset);
  178. stabOfs := 0;
  179. stabStrOfs := 0;
  180. Repeat
  181. Name := Get0String;
  182. alignAmount := 4 - ((length (Name) + 1) MOD 4);
  183. Skip (alignAmount);
  184. if (Name = '.stab') then
  185. begin
  186. stabOfs := getInt32;
  187. stabLength := getInt32;
  188. stabcnt:=stabLength div sizeof(tstab);
  189. end else
  190. if (Name = '.stabstr') then
  191. begin
  192. stabStrOfs := getInt32;
  193. stabStrLength := getInt32;
  194. end else
  195. Skip (8);
  196. until (Name = '') or ((StabOfs <> 0) and (stabStrOfs <> 0));
  197. Seek (F,stabOfs);
  198. //if (StabOfs = 0) then __ConsolePrintf ('StabOfs = 0');
  199. //if (StabStrOfs = 0) then __ConsolePrintf ('StabStrOfs = 0');
  200. LoadNetwareNLM := ((stabOfs > 0) and (stabStrOfs > 0));
  201. end;
  202. {$endif}
  203. {$ifdef go32v2}
  204. function LoadGo32Coff:boolean;
  205. type
  206. tcoffheader=packed record
  207. mach : word;
  208. nsects : word;
  209. time : longint;
  210. sympos : longint;
  211. syms : longint;
  212. opthdr : word;
  213. flag : word;
  214. other : array[0..27] of byte;
  215. end;
  216. tcoffsechdr=packed record
  217. name : array[0..7] of char;
  218. vsize : longint;
  219. rvaofs : longint;
  220. datalen : longint;
  221. datapos : longint;
  222. relocpos : longint;
  223. lineno1 : longint;
  224. nrelocs : word;
  225. lineno2 : word;
  226. flags : longint;
  227. end;
  228. var
  229. coffheader : tcoffheader;
  230. coffsec : tcoffsechdr;
  231. i : longint;
  232. begin
  233. processaddress := 0;
  234. LoadGo32Coff:=false;
  235. stabofs:=-1;
  236. stabstrofs:=-1;
  237. { read and check header }
  238. if filesize(f)<2048+sizeof(tcoffheader) then
  239. exit;
  240. seek(f,2048);
  241. blockread(f,coffheader,sizeof(tcoffheader));
  242. if coffheader.mach<>$14c then
  243. exit;
  244. { read section info }
  245. for i:=1to coffheader.nSects do
  246. begin
  247. blockread(f,coffsec,sizeof(tcoffsechdr));
  248. if (coffsec.name[4]='b') and
  249. (coffsec.name[1]='s') and
  250. (coffsec.name[2]='t') then
  251. begin
  252. if (coffsec.name[5]='s') and
  253. (coffsec.name[6]='t') then
  254. stabstrofs:=coffsec.datapos+2048
  255. else
  256. begin
  257. stabofs:=coffsec.datapos+2048;
  258. stabcnt:=coffsec.datalen div sizeof(tstab);
  259. end;
  260. end;
  261. end;
  262. LoadGo32Coff:=(stabofs<>-1) and (stabstrofs<>-1);
  263. end;
  264. {$endif Go32v2}
  265. {$ifdef win32}
  266. function LoadPeCoff:boolean;
  267. type
  268. tdosheader = packed record
  269. e_magic : word;
  270. e_cblp : word;
  271. e_cp : word;
  272. e_crlc : word;
  273. e_cparhdr : word;
  274. e_minalloc : word;
  275. e_maxalloc : word;
  276. e_ss : word;
  277. e_sp : word;
  278. e_csum : word;
  279. e_ip : word;
  280. e_cs : word;
  281. e_lfarlc : word;
  282. e_ovno : word;
  283. e_res : array[0..3] of word;
  284. e_oemid : word;
  285. e_oeminfo : word;
  286. e_res2 : array[0..9] of word;
  287. e_lfanew : longint;
  288. end;
  289. tpeheader = packed record
  290. PEMagic : longint;
  291. Machine : word;
  292. NumberOfSections : word;
  293. TimeDateStamp : longint;
  294. PointerToSymbolTable : longint;
  295. NumberOfSymbols : longint;
  296. SizeOfOptionalHeader : word;
  297. Characteristics : word;
  298. Magic : word;
  299. MajorLinkerVersion : byte;
  300. MinorLinkerVersion : byte;
  301. SizeOfCode : longint;
  302. SizeOfInitializedData : longint;
  303. SizeOfUninitializedData : longint;
  304. AddressOfEntryPoint : longint;
  305. BaseOfCode : longint;
  306. BaseOfData : longint;
  307. ImageBase : longint;
  308. SectionAlignment : longint;
  309. FileAlignment : longint;
  310. MajorOperatingSystemVersion : word;
  311. MinorOperatingSystemVersion : word;
  312. MajorImageVersion : word;
  313. MinorImageVersion : word;
  314. MajorSubsystemVersion : word;
  315. MinorSubsystemVersion : word;
  316. Reserved1 : longint;
  317. SizeOfImage : longint;
  318. SizeOfHeaders : longint;
  319. CheckSum : longint;
  320. Subsystem : word;
  321. DllCharacteristics : word;
  322. SizeOfStackReserve : longint;
  323. SizeOfStackCommit : longint;
  324. SizeOfHeapReserve : longint;
  325. SizeOfHeapCommit : longint;
  326. LoaderFlags : longint;
  327. NumberOfRvaAndSizes : longint;
  328. DataDirectory : array[1..$80] of byte;
  329. end;
  330. tcoffsechdr=packed record
  331. name : array[0..7] of char;
  332. vsize : longint;
  333. rvaofs : longint;
  334. datalen : longint;
  335. datapos : longint;
  336. relocpos : longint;
  337. lineno1 : longint;
  338. nrelocs : word;
  339. lineno2 : word;
  340. flags : longint;
  341. end;
  342. var
  343. dosheader : tdosheader;
  344. peheader : tpeheader;
  345. coffsec : tcoffsechdr;
  346. i : longint;
  347. begin
  348. processaddress := 0;
  349. LoadPeCoff:=false;
  350. stabofs:=-1;
  351. stabstrofs:=-1;
  352. { read and check header }
  353. if filesize(f)<sizeof(dosheader) then
  354. exit;
  355. blockread(f,dosheader,sizeof(tdosheader));
  356. seek(f,dosheader.e_lfanew);
  357. blockread(f,peheader,sizeof(tpeheader));
  358. if peheader.pemagic<>$4550 then
  359. exit;
  360. { read section info }
  361. for i:=1to peheader.NumberOfSections do
  362. begin
  363. blockread(f,coffsec,sizeof(tcoffsechdr));
  364. if (coffsec.name[4]='b') and
  365. (coffsec.name[1]='s') and
  366. (coffsec.name[2]='t') then
  367. begin
  368. if (coffsec.name[5]='s') and
  369. (coffsec.name[6]='t') then
  370. stabstrofs:=coffsec.datapos
  371. else
  372. begin
  373. stabofs:=coffsec.datapos;
  374. stabcnt:=coffsec.datalen div sizeof(tstab);
  375. end;
  376. end;
  377. end;
  378. LoadPeCoff:=(stabofs<>-1) and (stabstrofs<>-1);
  379. end;
  380. {$endif Win32}
  381. {$IFDEF EMX}
  382. function LoadEMXaout: boolean;
  383. type
  384. TDosHeader = packed record
  385. e_magic : word;
  386. e_cblp : word;
  387. e_cp : word;
  388. e_crlc : word;
  389. e_cparhdr : word;
  390. e_minalloc : word;
  391. e_maxalloc : word;
  392. e_ss : word;
  393. e_sp : word;
  394. e_csum : word;
  395. e_ip : word;
  396. e_cs : word;
  397. e_lfarlc : word;
  398. e_ovno : word;
  399. e_res : array[0..3] of word;
  400. e_oemid : word;
  401. e_oeminfo : word;
  402. e_res2 : array[0..9] of word;
  403. e_lfanew : longint;
  404. end;
  405. TEmxHeader = packed record
  406. Version: array [1..16] of char;
  407. Bound: word;
  408. AoutOfs: longint;
  409. Options: array [1..42] of char;
  410. end;
  411. TAoutHeader = packed record
  412. Magic: word;
  413. Machine: byte;
  414. Flags: byte;
  415. TextSize: longint;
  416. DataSize: longint;
  417. BssSize: longint;
  418. SymbSize: longint;
  419. EntryPoint: longint;
  420. TextRelocSize: longint;
  421. DataRelocSize: longint;
  422. end;
  423. const
  424. StartPageSize = $1000;
  425. var
  426. DosHeader: TDosHeader;
  427. EmxHeader: TEmxHeader;
  428. AoutHeader: TAoutHeader;
  429. S4: string [4];
  430. begin
  431. processaddress := 0;
  432. LoadEMXaout := false;
  433. StabOfs := -1;
  434. StabStrOfs := -1;
  435. { read and check header }
  436. if FileSize (F) > SizeOf (DosHeader) then
  437. begin
  438. BlockRead (F, DosHeader, SizeOf (TDosHeader));
  439. Seek (F, DosHeader.e_cparhdr shl 4);
  440. BlockRead (F, EmxHeader, SizeOf (TEmxHeader));
  441. S4 [0] := #4;
  442. Move (EmxHeader.Version, S4 [1], 4);
  443. if S4 = 'emx ' then
  444. begin
  445. Seek (F, EmxHeader.AoutOfs);
  446. BlockRead (F, AoutHeader, SizeOf (TAoutHeader));
  447. if AOutHeader.Magic=$10B then
  448. StabOfs := StartPageSize
  449. else
  450. StabOfs :=EmxHeader.AoutOfs + SizeOf (TAoutHeader);
  451. StabOfs := StabOfs
  452. + AoutHeader.TextSize
  453. + AoutHeader.DataSize
  454. + AoutHeader.TextRelocSize
  455. + AoutHeader.DataRelocSize;
  456. StabCnt := AoutHeader.SymbSize div SizeOf (TStab);
  457. StabStrOfs := StabOfs + AoutHeader.SymbSize;
  458. StabsFunctionRelative:=false;
  459. LoadEMXaout := (StabOfs <> -1) and (StabStrOfs <> -1);
  460. end;
  461. end;
  462. end;
  463. {$ENDIF EMX}
  464. {$ifdef ELF32}
  465. function LoadElf32:boolean;
  466. type
  467. telf32header=packed record
  468. magic0123 : longint;
  469. file_class : byte;
  470. data_encoding : byte;
  471. file_version : byte;
  472. padding : array[$07..$0f] of byte;
  473. e_type : word;
  474. e_machine : word;
  475. e_version : longword;
  476. e_entry : longword; // entrypoint
  477. e_phoff : longword; // program header offset
  478. e_shoff : longword; // sections header offset
  479. e_flags : longword;
  480. e_ehsize : word; // elf header size in bytes
  481. e_phentsize : word; // size of an entry in the program header array
  482. e_phnum : word; // 0..e_phnum-1 of entrys
  483. e_shentsize : word; // size of an entry in sections header array
  484. e_shnum : word; // 0..e_shnum-1 of entrys
  485. e_shstrndx : word; // index of string section header
  486. end;
  487. telf32sechdr=packed record
  488. sh_name : longword;
  489. sh_type : longword;
  490. sh_flags : longword;
  491. sh_addr : longword;
  492. sh_offset : longword;
  493. sh_size : longword;
  494. sh_link : longword;
  495. sh_info : longword;
  496. sh_addralign : longword;
  497. sh_entsize : longword;
  498. end;
  499. var
  500. elfheader : telf32header;
  501. elfsec : telf32sechdr;
  502. secnames : array[0..255] of char;
  503. pname : pchar;
  504. i : longint;
  505. begin
  506. processaddress := 0;
  507. LoadElf32:=false;
  508. stabofs:=-1;
  509. stabstrofs:=-1;
  510. { read and check header }
  511. if filesize(f)<sizeof(telf32header) then
  512. exit;
  513. blockread(f,elfheader,sizeof(telf32header));
  514. {$ifdef ENDIAN_LITTLE}
  515. if elfheader.magic0123<>$464c457f then
  516. exit;
  517. {$endif ENDIAN_LITTLE}
  518. {$ifdef ENDIAN_BIG}
  519. if elfheader.magic0123<>$7f454c46 then
  520. exit;
  521. { this seems to be at least the case for m68k cpu PM }
  522. {$ifdef cpum68k}
  523. {StabsFunctionRelative:=false;}
  524. {$endif cpum68k}
  525. {$endif ENDIAN_BIG}
  526. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  527. exit;
  528. { read section names }
  529. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  530. blockread(f,elfsec,sizeof(telf32sechdr));
  531. seek(f,elfsec.sh_offset);
  532. blockread(f,secnames,sizeof(secnames));
  533. { read section info }
  534. seek(f,elfheader.e_shoff);
  535. for i:=1to elfheader.e_shnum do
  536. begin
  537. blockread(f,elfsec,sizeof(telf32sechdr));
  538. pname:=@secnames[elfsec.sh_name];
  539. if (pname[4]='b') and
  540. (pname[1]='s') and
  541. (pname[2]='t') then
  542. begin
  543. if (pname[5]='s') and
  544. (pname[6]='t') then
  545. stabstrofs:=elfsec.sh_offset
  546. else
  547. begin
  548. stabofs:=elfsec.sh_offset;
  549. stabcnt:=elfsec.sh_size div sizeof(tstab);
  550. end;
  551. end;
  552. end;
  553. LoadElf32:=(stabofs<>-1) and (stabstrofs<>-1);
  554. end;
  555. {$endif ELF32}
  556. {$ifdef ELF64}
  557. function LoadElf64:boolean;
  558. type
  559. telf64header=packed record
  560. magic0123 : longint;
  561. file_class : byte;
  562. data_encoding : byte;
  563. file_version : byte;
  564. padding : array[$07..$0f] of byte;
  565. e_type : word;
  566. e_machine : word;
  567. e_version : longword;
  568. e_entry : int64; // entrypoint
  569. e_phoff : int64; // program header offset
  570. e_shoff : int64; // sections header offset
  571. e_flags : longword;
  572. e_ehsize : word; // elf header size in bytes
  573. e_phentsize : word; // size of an entry in the program header array
  574. e_phnum : word; // 0..e_phnum-1 of entrys
  575. e_shentsize : word; // size of an entry in sections header array
  576. e_shnum : word; // 0..e_shnum-1 of entrys
  577. e_shstrndx : word; // index of string section header
  578. end;
  579. telf64sechdr=packed record
  580. sh_name : longword;
  581. sh_type : longword;
  582. sh_flags : int64;
  583. sh_addr : int64;
  584. sh_offset : int64;
  585. sh_size : int64;
  586. sh_link : longword;
  587. sh_info : longword;
  588. sh_addralign : int64;
  589. sh_entsize : int64;
  590. end;
  591. var
  592. elfheader : telf64header;
  593. elfsec : telf64sechdr;
  594. secnames : array[0..255] of char;
  595. pname : pchar;
  596. i : longint;
  597. begin
  598. processaddress := 0;
  599. LoadElf64:=false;
  600. stabofs:=-1;
  601. stabstrofs:=-1;
  602. { read and check header }
  603. if filesize(f)<sizeof(telf64header) then
  604. exit;
  605. blockread(f,elfheader,sizeof(telf64header));
  606. {$ifdef ENDIAN_LITTLE}
  607. if elfheader.magic0123<>$464c457f then
  608. exit;
  609. {$endif ENDIAN_LITTLE}
  610. {$ifdef ENDIAN_BIG}
  611. if elfheader.magic0123<>$7f454c46 then
  612. exit;
  613. { this seems to be at least the case for m68k cpu PM }
  614. {$ifdef cpum68k}
  615. {StabsFunctionRelative:=false;}
  616. {$endif cpum68k}
  617. {$endif ENDIAN_BIG}
  618. if elfheader.e_shentsize<>sizeof(telf64sechdr) then
  619. exit;
  620. { read section names }
  621. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf64sechdr)));
  622. blockread(f,elfsec,sizeof(telf64sechdr));
  623. seek(f,elfsec.sh_offset);
  624. blockread(f,secnames,sizeof(secnames));
  625. { read section info }
  626. seek(f,elfheader.e_shoff);
  627. for i:=1to elfheader.e_shnum do
  628. begin
  629. blockread(f,elfsec,sizeof(telf64sechdr));
  630. pname:=@secnames[elfsec.sh_name];
  631. if (pname[4]='b') and
  632. (pname[1]='s') and
  633. (pname[2]='t') then
  634. begin
  635. if (pname[5]='s') and
  636. (pname[6]='t') then
  637. stabstrofs:=elfsec.sh_offset
  638. else
  639. begin
  640. stabofs:=elfsec.sh_offset;
  641. stabcnt:=elfsec.sh_size div sizeof(tstab);
  642. end;
  643. end;
  644. end;
  645. LoadElf64:=(stabofs<>-1) and (stabstrofs<>-1);
  646. end;
  647. {$endif ELF64}
  648. {$ifdef beos}
  649. {$i osposixh.inc}
  650. {$i syscall.inc}
  651. {$i beos.inc}
  652. 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';
  653. function LoadElf32Beos:boolean;
  654. type
  655. telf32header=packed record
  656. magic0123 : longint;
  657. file_class : byte;
  658. data_encoding : byte;
  659. file_version : byte;
  660. padding : array[$07..$0f] of byte;
  661. e_type : word;
  662. e_machine : word;
  663. e_version : longword;
  664. e_entry : longword; // entrypoint
  665. e_phoff : longword; // program header offset
  666. e_shoff : longword; // sections header offset
  667. e_flags : longword;
  668. e_ehsize : word; // elf header size in bytes
  669. e_phentsize : word; // size of an entry in the program header array
  670. e_phnum : word; // 0..e_phnum-1 of entrys
  671. e_shentsize : word; // size of an entry in sections header array
  672. e_shnum : word; // 0..e_shnum-1 of entrys
  673. e_shstrndx : word; // index of string section header
  674. end;
  675. telf32sechdr=packed record
  676. sh_name : longword;
  677. sh_type : longword;
  678. sh_flags : longword;
  679. sh_addr : longword;
  680. sh_offset : longword;
  681. sh_size : longword;
  682. sh_link : longword;
  683. sh_info : longword;
  684. sh_addralign : longword;
  685. sh_entsize : longword;
  686. end;
  687. var
  688. elfheader : telf32header;
  689. elfsec : telf32sechdr;
  690. secnames : array[0..255] of char;
  691. pname : pchar;
  692. i : longint;
  693. cookie : longint;
  694. info : image_info;
  695. result : status_t;
  696. begin
  697. cookie := 0;
  698. fillchar(info, sizeof(image_info), 0);
  699. get_next_image_info(0,cookie,info,sizeof(info));
  700. if (info._type = B_APP_IMAGE) then
  701. processaddress := cardinal(info.text)
  702. else
  703. processaddress := 0;
  704. LoadElf32Beos:=false;
  705. stabofs:=-1;
  706. stabstrofs:=-1;
  707. { read and check header }
  708. if filesize(f)<sizeof(telf32header) then
  709. exit;
  710. blockread(f,elfheader,sizeof(telf32header));
  711. {$ifdef ENDIAN_LITTLE}
  712. if elfheader.magic0123<>$464c457f then
  713. exit;
  714. {$endif ENDIAN_LITTLE}
  715. {$ifdef ENDIAN_BIG}
  716. if elfheader.magic0123<>$7f454c46 then
  717. exit;
  718. {$endif ENDIAN_BIG}
  719. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  720. exit;
  721. { read section names }
  722. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  723. blockread(f,elfsec,sizeof(telf32sechdr));
  724. seek(f,elfsec.sh_offset);
  725. blockread(f,secnames,sizeof(secnames));
  726. { read section info }
  727. seek(f,elfheader.e_shoff);
  728. for i:=1to elfheader.e_shnum do
  729. begin
  730. blockread(f,elfsec,sizeof(telf32sechdr));
  731. pname:=@secnames[elfsec.sh_name];
  732. if (pname[4]='b') and
  733. (pname[1]='s') and
  734. (pname[2]='t') then
  735. begin
  736. if (pname[5]='s') and
  737. (pname[6]='t') then
  738. stabstrofs:=elfsec.sh_offset
  739. else
  740. begin
  741. stabofs:=elfsec.sh_offset;
  742. stabcnt:=elfsec.sh_size div sizeof(tstab);
  743. end;
  744. end;
  745. end;
  746. LoadElf32Beos:=(stabofs<>-1) and (stabstrofs<>-1);
  747. end;
  748. {$endif beos}
  749. {****************************************************************************
  750. Executable Open/Close
  751. ****************************************************************************}
  752. procedure CloseStabs;
  753. begin
  754. close(f);
  755. opened:=false;
  756. end;
  757. function OpenStabs:boolean;
  758. var
  759. ofm : word;
  760. begin
  761. OpenStabs:=false;
  762. assign(f,paramstr(0));
  763. {$I-}
  764. ofm:=filemode;
  765. filemode:=$40;
  766. reset(f,1);
  767. filemode:=ofm;
  768. {$I+}
  769. if ioresult<>0 then
  770. exit;
  771. opened:=true;
  772. {$ifdef go32v2}
  773. if LoadGo32Coff then
  774. begin
  775. OpenStabs:=true;
  776. exit;
  777. end;
  778. {$endif}
  779. {$IFDEF EMX}
  780. if LoadEMXaout then
  781. begin
  782. OpenStabs:=true;
  783. exit;
  784. end;
  785. {$ENDIF EMX}
  786. {$ifdef win32}
  787. if LoadPECoff then
  788. begin
  789. OpenStabs:=true;
  790. exit;
  791. end;
  792. {$endif}
  793. {$ifdef ELF32}
  794. if LoadElf32 then
  795. begin
  796. OpenStabs:=true;
  797. exit;
  798. end;
  799. {$endif}
  800. {$ifdef ELF64}
  801. if LoadElf64 then
  802. begin
  803. OpenStabs:=true;
  804. exit;
  805. end;
  806. {$endif}
  807. {$ifdef Beos}
  808. if LoadElf32Beos then
  809. begin
  810. OpenStabs:=true;
  811. exit;
  812. end;
  813. {$endif}
  814. {$ifdef netware}
  815. if LoadNetwareNLM then
  816. begin
  817. OpenStabs:=true;
  818. exit;
  819. end;
  820. {$endif}
  821. CloseStabs;
  822. end;
  823. {$Q-}
  824. { this avoids problems with some targets PM }
  825. procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
  826. var
  827. res : {$ifdef tp}integer{$else}longint{$endif};
  828. stabsleft,
  829. stabscnt,i : longint;
  830. found : boolean;
  831. lastfunc : tstab;
  832. begin
  833. fillchar(func,high(func)+1,0);
  834. fillchar(source,high(source)+1,0);
  835. line:=0;
  836. if not opened then
  837. begin
  838. if not OpenStabs then
  839. exit;
  840. end;
  841. { correct the value to the correct address in the file }
  842. { processaddress is set in OpenStabs }
  843. addr := addr - processaddress;
  844. //ScreenPrintfL1 (NWLoggerScreen,'addr: %x\n',addr);
  845. fillchar(funcstab,sizeof(tstab),0);
  846. fillchar(filestab,sizeof(tstab),0);
  847. fillchar(dirstab,sizeof(tstab),0);
  848. fillchar(linestab,sizeof(tstab),0);
  849. fillchar(lastfunc,sizeof(tstab),0);
  850. found:=false;
  851. seek(f,stabofs);
  852. stabsleft:=stabcnt;
  853. repeat
  854. if stabsleft>maxstabs then
  855. stabscnt:=maxstabs
  856. else
  857. stabscnt:=stabsleft;
  858. blockread(f,stabs,stabscnt*sizeof(tstab),res);
  859. stabscnt:=res div sizeof(tstab);
  860. for i:=0 to stabscnt-1 do
  861. begin
  862. case stabs[i].ntype of
  863. N_BssLine,
  864. N_DataLine,
  865. N_TextLine :
  866. begin
  867. if (stabs[i].ntype=N_TextLine) and StabsFunctionRelative then
  868. inc(stabs[i].nvalue,lastfunc.nvalue);
  869. if (stabs[i].nvalue<=addr) and
  870. (stabs[i].nvalue>linestab.nvalue) then
  871. begin
  872. { if it's equal we can stop and take the last info }
  873. if stabs[i].nvalue=addr then
  874. found:=true
  875. else
  876. linestab:=stabs[i];
  877. end;
  878. end;
  879. N_Function :
  880. begin
  881. lastfunc:=stabs[i];
  882. if (stabs[i].nvalue<=addr) and
  883. (stabs[i].nvalue>funcstab.nvalue) then
  884. begin
  885. funcstab:=stabs[i];
  886. fillchar(linestab,sizeof(tstab),0);
  887. end;
  888. end;
  889. N_SourceFile,
  890. N_IncludeFile :
  891. begin
  892. if (stabs[i].nvalue<=addr) and
  893. (stabs[i].nvalue>=filestab.nvalue) then
  894. begin
  895. { if same value and type then the first one
  896. contained the directory PM }
  897. if (stabs[i].nvalue=filestab.nvalue) and
  898. (stabs[i].ntype=filestab.ntype) then
  899. dirstab:=filestab
  900. else
  901. fillchar(dirstab,sizeof(tstab),0);
  902. filestab:=stabs[i];
  903. fillchar(linestab,sizeof(tstab),0);
  904. { if new file then func is not valid anymore PM }
  905. if stabs[i].ntype=N_SourceFile then
  906. begin
  907. fillchar(funcstab,sizeof(tstab),0);
  908. fillchar(lastfunc,sizeof(tstab),0);
  909. end;
  910. end;
  911. end;
  912. end;
  913. end;
  914. dec(stabsleft,stabscnt);
  915. until found or (stabsleft=0);
  916. { get the line,source,function info }
  917. line:=linestab.ndesc;
  918. if dirstab.ntype<>0 then
  919. begin
  920. seek(f,stabstrofs+dirstab.strpos);
  921. blockread(f,source[1],high(source)-1,res);
  922. dirlength:=strlen(@source[1]);
  923. source[0]:=chr(dirlength);
  924. end
  925. else
  926. dirlength:=0;
  927. if filestab.ntype<>0 then
  928. begin
  929. seek(f,stabstrofs+filestab.strpos);
  930. blockread(f,source[dirlength+1],high(source)-(dirlength+1),res);
  931. source[0]:=chr(strlen(@source[1]));
  932. end;
  933. if funcstab.ntype<>0 then
  934. begin
  935. seek(f,stabstrofs+funcstab.strpos);
  936. blockread(f,func[1],high(func)-1,res);
  937. func[0]:=chr(strlen(@func[1]));
  938. i:=pos(':',func);
  939. if i>0 then
  940. Delete(func,i,255);
  941. end;
  942. end;
  943. function StabBackTraceStr(addr:Pointer):shortstring;
  944. var
  945. func,
  946. source : string;
  947. hs : string[32];
  948. line : longint;
  949. Store : TBackTraceStrFunc;
  950. begin
  951. { reset to prevent infinite recursion if problems inside the code PM }
  952. {$ifdef netware}
  953. dec(addr,system.NWGetCodeStart); {we need addr relative to code start on netware}
  954. {$endif}
  955. Store:=BackTraceStrFunc;
  956. BackTraceStrFunc:=@SysBackTraceStr;
  957. GetLineInfo(ptruint(addr),func,source,line);
  958. { create string }
  959. {$ifdef netware}
  960. StabBackTraceStr:=' CodeStart + $'+HexStr(ptrint(addr),sizeof(ptrint)*2);
  961. {$else}
  962. StabBackTraceStr:=' $'+HexStr(ptrint(addr),sizeof(ptrint)*2);
  963. {$endif}
  964. if func<>'' then
  965. StabBackTraceStr:=StabBackTraceStr+' '+func;
  966. if source<>'' then
  967. begin
  968. if func<>'' then
  969. StabBackTraceStr:=StabBackTraceStr+', ';
  970. if line<>0 then
  971. begin
  972. str(line,hs);
  973. StabBackTraceStr:=StabBackTraceStr+' line '+hs;
  974. end;
  975. StabBackTraceStr:=StabBackTraceStr+' of '+source;
  976. end;
  977. if Opened then
  978. BackTraceStrFunc:=Store;
  979. end;
  980. initialization
  981. BackTraceStrFunc:=@StabBackTraceStr;
  982. finalization
  983. if opened then
  984. CloseStabs;
  985. end.