lineinfo.pp 29 KB

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