lineinfo.pp 29 KB

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