exeinfo.pp 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Peter Vreman
  4. Executable file reading functions
  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 exeinfo;
  12. interface
  13. {$mode objfpc}
  14. {$S-}
  15. type
  16. TExeFile=record
  17. f : file;
  18. // cached filesize
  19. size : int64;
  20. isopen : boolean;
  21. nsects : longint;
  22. sechdrofs,
  23. secstrofs : ptruint;
  24. processaddress : ptruint;
  25. FunctionRelative: boolean;
  26. end;
  27. function OpenExeFile(out e:TExeFile;const fn:string):boolean;
  28. function FindExeSection(var e:TExeFile;const secname:string;out secofs,seclen:longint):boolean;
  29. function CloseExeFile(var e:TExeFile):boolean;
  30. implementation
  31. uses
  32. strings;
  33. {****************************************************************************
  34. Executable Loaders
  35. ****************************************************************************}
  36. {$if defined(netbsd) or defined(freebsd) or defined(linux) or defined(sunos)}
  37. {$ifdef cpu64}
  38. {$define ELF64}
  39. {$else}
  40. {$define ELF32}
  41. {$endif}
  42. {$endif}
  43. {$if defined(win32) or defined(wince)}
  44. {$define PE32}
  45. {$endif}
  46. {$if defined(win64)}
  47. {$define PE32PLUS}
  48. {$endif}
  49. {$ifdef netwlibc}
  50. {$define netware}
  51. {$endif}
  52. {$IFDEF OS2}
  53. {$DEFINE EMX}
  54. {$ENDIF OS2}
  55. {$ifdef netware}
  56. const SIZE_OF_NLM_INTERNAL_FIXED_HEADER = 130;
  57. SIZE_OF_NLM_INTERNAL_VERSION_HEADER = 32;
  58. SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER = 124;
  59. function loadNetwareNLM:boolean;
  60. var valid : boolean;
  61. name : string;
  62. StabLength,
  63. StabStrLength,
  64. alignAmount,
  65. hdrLength,
  66. dataOffset,
  67. dataLength : longint;
  68. function getByte:byte;
  69. begin
  70. BlockRead (f,getByte,1);
  71. end;
  72. procedure Skip (bytes : longint);
  73. var i : longint;
  74. begin
  75. for i := 1 to bytes do getbyte;
  76. end;
  77. function getLString : String;
  78. var Res:string;
  79. begin
  80. blockread (F, res, 1);
  81. if length (res) > 0 THEN
  82. blockread (F, res[1], length (res));
  83. getbyte;
  84. getLString := res;
  85. end;
  86. function getFixString (Len : byte) : string;
  87. var i : byte;
  88. begin
  89. getFixString := '';
  90. for I := 1 to Len do
  91. getFixString := getFixString + char (getbyte);
  92. end;
  93. function get0String : string;
  94. var c : char;
  95. begin
  96. get0String := '';
  97. c := char (getbyte);
  98. while (c <> #0) do
  99. begin
  100. get0String := get0String + c;
  101. c := char (getbyte);
  102. end;
  103. end;
  104. function getword : word;
  105. begin
  106. blockread (F, getword, 2);
  107. end;
  108. function getint32 : longint;
  109. begin
  110. blockread (F, getint32, 4);
  111. end;
  112. begin
  113. processaddress := 0;
  114. LoadNetwareNLM:=false;
  115. stabofs:=-1;
  116. stabstrofs:=-1;
  117. { read and check header }
  118. Skip (SIZE_OF_NLM_INTERNAL_FIXED_HEADER);
  119. getLString; // NLM Description
  120. getInt32; // Stacksize
  121. getInt32; // Reserved
  122. skip(5); // old Thread Name
  123. getLString; // Screen Name
  124. getLString; // Thread Name
  125. hdrLength := -1;
  126. dataOffset := -1;
  127. dataLength := -1;
  128. valid := true;
  129. repeat
  130. name := getFixString (8);
  131. if (name = 'VeRsIoN#') then
  132. begin
  133. Skip (SIZE_OF_NLM_INTERNAL_VERSION_HEADER-8);
  134. end else
  135. if (name = 'CoPyRiGh') then
  136. begin
  137. getword; // T=
  138. getLString; // Copyright String
  139. end else
  140. if (name = 'MeSsAgEs') then
  141. begin
  142. skip (SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER - 8);
  143. end else
  144. if (name = 'CuStHeAd') then
  145. begin
  146. hdrLength := getInt32;
  147. dataOffset := getInt32;
  148. dataLength := getInt32;
  149. Skip (8); // dataStamp
  150. Valid := false;
  151. end else
  152. Valid := false;
  153. until not valid;
  154. if (hdrLength = -1) or (dataOffset = -1) or (dataLength = -1) then
  155. exit;
  156. (* The format of the section information is:
  157. null terminated section name
  158. zeroes to adjust to 4 byte boundary
  159. 4 byte section data file pointer
  160. 4 byte section size *)
  161. Seek (F, dataOffset);
  162. stabOfs := 0;
  163. stabStrOfs := 0;
  164. Repeat
  165. Name := Get0String;
  166. alignAmount := 4 - ((length (Name) + 1) MOD 4);
  167. Skip (alignAmount);
  168. if (Name = '.stab') then
  169. begin
  170. stabOfs := getInt32;
  171. stabLength := getInt32;
  172. stabcnt:=stabLength div sizeof(tstab);
  173. end else
  174. if (Name = '.stabstr') then
  175. begin
  176. stabStrOfs := getInt32;
  177. stabStrLength := getInt32;
  178. end else
  179. Skip (8);
  180. until (Name = '') or ((StabOfs <> 0) and (stabStrOfs <> 0));
  181. Seek (F,stabOfs);
  182. //if (StabOfs = 0) then __ConsolePrintf ('StabOfs = 0');
  183. //if (StabStrOfs = 0) then __ConsolePrintf ('StabStrOfs = 0');
  184. LoadNetwareNLM := ((stabOfs > 0) and (stabStrOfs > 0));
  185. end;
  186. {$endif}
  187. {$ifdef go32v2}
  188. function LoadGo32Coff:boolean;
  189. type
  190. tcoffheader=packed record
  191. mach : word;
  192. nsects : word;
  193. time : longint;
  194. sympos : longint;
  195. syms : longint;
  196. opthdr : word;
  197. flag : word;
  198. other : array[0..27] of byte;
  199. end;
  200. tcoffsechdr=packed record
  201. name : array[0..7] of char;
  202. vsize : longint;
  203. rvaofs : longint;
  204. datalen : longint;
  205. datapos : longint;
  206. relocpos : longint;
  207. lineno1 : longint;
  208. nrelocs : word;
  209. lineno2 : word;
  210. flags : longint;
  211. end;
  212. var
  213. coffheader : tcoffheader;
  214. coffsec : tcoffsechdr;
  215. i : longint;
  216. begin
  217. processaddress := 0;
  218. LoadGo32Coff:=false;
  219. stabofs:=-1;
  220. stabstrofs:=-1;
  221. { read and check header }
  222. if e.size<2048+sizeof(tcoffheader) then
  223. exit;
  224. seek(f,2048);
  225. blockread(f,coffheader,sizeof(tcoffheader));
  226. if coffheader.mach<>$14c then
  227. exit;
  228. { read section info }
  229. for i:=1to coffheader.nSects do
  230. begin
  231. blockread(f,coffsec,sizeof(tcoffsechdr));
  232. if (coffsec.name[4]='b') and
  233. (coffsec.name[1]='s') and
  234. (coffsec.name[2]='t') then
  235. begin
  236. if (coffsec.name[5]='s') and
  237. (coffsec.name[6]='t') then
  238. stabstrofs:=coffsec.datapos+2048
  239. else
  240. begin
  241. stabofs:=coffsec.datapos+2048;
  242. stabcnt:=coffsec.datalen div sizeof(tstab);
  243. end;
  244. end;
  245. end;
  246. LoadGo32Coff:=(stabofs<>-1) and (stabstrofs<>-1);
  247. end;
  248. {$endif Go32v2}
  249. {$ifdef PE32}
  250. function OpenPeCoff(var e:TExeFile):boolean;
  251. type
  252. tdosheader = packed record
  253. e_magic : word;
  254. e_cblp : word;
  255. e_cp : word;
  256. e_crlc : word;
  257. e_cparhdr : word;
  258. e_minalloc : word;
  259. e_maxalloc : word;
  260. e_ss : word;
  261. e_sp : word;
  262. e_csum : word;
  263. e_ip : word;
  264. e_cs : word;
  265. e_lfarlc : word;
  266. e_ovno : word;
  267. e_res : array[0..3] of word;
  268. e_oemid : word;
  269. e_oeminfo : word;
  270. e_res2 : array[0..9] of word;
  271. e_lfanew : longint;
  272. end;
  273. tpeheader = packed record
  274. PEMagic : longint;
  275. Machine : word;
  276. NumberOfSections : word;
  277. TimeDateStamp : longint;
  278. PointerToSymbolTable : longint;
  279. NumberOfSymbols : longint;
  280. SizeOfOptionalHeader : word;
  281. Characteristics : word;
  282. Magic : word;
  283. MajorLinkerVersion : byte;
  284. MinorLinkerVersion : byte;
  285. SizeOfCode : longint;
  286. SizeOfInitializedData : longint;
  287. SizeOfUninitializedData : longint;
  288. AddressOfEntryPoint : longint;
  289. BaseOfCode : longint;
  290. BaseOfData : longint;
  291. ImageBase : longint;
  292. SectionAlignment : longint;
  293. FileAlignment : longint;
  294. MajorOperatingSystemVersion : word;
  295. MinorOperatingSystemVersion : word;
  296. MajorImageVersion : word;
  297. MinorImageVersion : word;
  298. MajorSubsystemVersion : word;
  299. MinorSubsystemVersion : word;
  300. Reserved1 : longint;
  301. SizeOfImage : longint;
  302. SizeOfHeaders : longint;
  303. CheckSum : longint;
  304. Subsystem : word;
  305. DllCharacteristics : word;
  306. SizeOfStackReserve : longint;
  307. SizeOfStackCommit : longint;
  308. SizeOfHeapReserve : longint;
  309. SizeOfHeapCommit : longint;
  310. LoaderFlags : longint;
  311. NumberOfRvaAndSizes : longint;
  312. DataDirectory : array[1..$80] of byte;
  313. end;
  314. coffsymbol=packed record
  315. name : array[0..3] of char; { real is [0..7], which overlaps the strofs ! }
  316. strofs : longint;
  317. value : longint;
  318. section : smallint;
  319. empty : word;
  320. typ : byte;
  321. aux : byte;
  322. end;
  323. var
  324. dosheader : tdosheader;
  325. peheader : tpeheader;
  326. begin
  327. result:=false;
  328. { read and check header }
  329. if e.size<sizeof(dosheader) then
  330. exit;
  331. blockread(e.f,dosheader,sizeof(tdosheader));
  332. seek(e.f,dosheader.e_lfanew);
  333. blockread(e.f,peheader,sizeof(tpeheader));
  334. if peheader.pemagic<>$4550 then
  335. exit;
  336. e.sechdrofs:=filepos(e.f);
  337. e.nsects:=peheader.NumberOfSections;
  338. e.secstrofs:=peheader.PointerToSymbolTable+peheader.NumberOfSymbols*sizeof(coffsymbol)+4;
  339. if e.secstrofs>e.size then
  340. exit;
  341. result:=true;
  342. end;
  343. {$endif PE32}
  344. {$if defined(PE32) or defined(PE32PLUS)}
  345. function FindSectionPECoff(var e:TExeFile;const asecname:string;out secofs,seclen:longint):boolean;
  346. type
  347. tcoffsechdr=packed record
  348. name : array[0..7] of char;
  349. vsize : longint;
  350. rvaofs : longint;
  351. datalen : longint;
  352. datapos : longint;
  353. relocpos : longint;
  354. lineno1 : longint;
  355. nrelocs : word;
  356. lineno2 : word;
  357. flags : longint;
  358. end;
  359. var
  360. i : longint;
  361. sechdr : tcoffsechdr;
  362. secname : string;
  363. secnamebuf : array[0..255] of char;
  364. code,
  365. oldofs,
  366. bufsize : longint;
  367. strofs : cardinal;
  368. begin
  369. result:=false;
  370. { read section info }
  371. seek(e.f,e.sechdrofs);
  372. for i:=1 to e.nsects do
  373. begin
  374. blockread(e.f,sechdr,sizeof(sechdr),bufsize);
  375. move(sechdr.name,secnamebuf,8);
  376. secnamebuf[8]:=#0;
  377. secname:=strpas(secnamebuf);
  378. if secname[1]='/' then
  379. begin
  380. Val(Copy(secname,2,8),strofs,code);
  381. if code=0 then
  382. begin
  383. fillchar(secnamebuf,sizeof(secnamebuf),0);
  384. oldofs:=filepos(e.f);
  385. seek(e.f,e.secstrofs+strofs);
  386. blockread(e.f,secnamebuf,sizeof(secnamebuf),bufsize);
  387. seek(e.f,oldofs);
  388. secname:=strpas(secnamebuf);
  389. end
  390. else
  391. secname:='';
  392. end;
  393. if asecname=secname then
  394. begin
  395. secofs:=sechdr.datapos;
  396. seclen:=sechdr.datalen;
  397. result:=true;
  398. exit;
  399. end;
  400. end;
  401. end;
  402. {$endif PE32 or PE32PLUS}
  403. {$ifdef PE32PLUS}
  404. function OpenPePlusCoff(var e:TExeFile):boolean;
  405. type
  406. tdosheader = packed record
  407. e_magic : word;
  408. e_cblp : word;
  409. e_cp : word;
  410. e_crlc : word;
  411. e_cparhdr : word;
  412. e_minalloc : word;
  413. e_maxalloc : word;
  414. e_ss : word;
  415. e_sp : word;
  416. e_csum : word;
  417. e_ip : word;
  418. e_cs : word;
  419. e_lfarlc : word;
  420. e_ovno : word;
  421. e_res : array[0..3] of word;
  422. e_oemid : word;
  423. e_oeminfo : word;
  424. e_res2 : array[0..9] of word;
  425. e_lfanew : longint;
  426. end;
  427. tpeheader = packed record
  428. PEMagic : longint;
  429. Machine : word;
  430. NumberOfSections : word;
  431. TimeDateStamp : longint;
  432. PointerToSymbolTable : longint;
  433. NumberOfSymbols : longint;
  434. SizeOfOptionalHeader : word;
  435. Characteristics : word;
  436. Magic : word;
  437. MajorLinkerVersion : byte;
  438. MinorLinkerVersion : byte;
  439. SizeOfCode : longint;
  440. SizeOfInitializedData : longint;
  441. SizeOfUninitializedData : longint;
  442. AddressOfEntryPoint : longint;
  443. BaseOfCode : longint;
  444. BaseOfData : longint;
  445. ImageBase : longint;
  446. SectionAlignment : longint;
  447. FileAlignment : longint;
  448. MajorOperatingSystemVersion : word;
  449. MinorOperatingSystemVersion : word;
  450. MajorImageVersion : word;
  451. MinorImageVersion : word;
  452. MajorSubsystemVersion : word;
  453. MinorSubsystemVersion : word;
  454. Reserved1 : longint;
  455. SizeOfImage : longint;
  456. SizeOfHeaders : longint;
  457. CheckSum : longint;
  458. Subsystem : word;
  459. DllCharacteristics : word;
  460. SizeOfStackReserve : int64;
  461. SizeOfStackCommit : int64;
  462. SizeOfHeapReserve : int64;
  463. SizeOfHeapCommit : int64;
  464. LoaderFlags : longint;
  465. NumberOfRvaAndSizes : longint;
  466. DataDirectory : array[1..$80] of byte;
  467. end;
  468. tcoffsechdr=packed record
  469. name : array[0..7] of char;
  470. vsize : longint;
  471. rvaofs : longint;
  472. datalen : longint;
  473. datapos : longint;
  474. relocpos : longint;
  475. lineno1 : longint;
  476. nrelocs : word;
  477. lineno2 : word;
  478. flags : longint;
  479. end;
  480. var
  481. dosheader : tdosheader;
  482. peheader : tpeheader;
  483. begin
  484. result:=false;
  485. { read and check header }
  486. if E.Size<sizeof(dosheader) then
  487. exit;
  488. blockread(E.F,dosheader,sizeof(tdosheader));
  489. seek(E.F,dosheader.e_lfanew);
  490. blockread(E.F,peheader,sizeof(tpeheader));
  491. if peheader.pemagic<>$4550 then
  492. exit;
  493. e.sechdrofs:=filepos(e.f);
  494. e.nsects:=peheader.NumberOfSections;
  495. e.secstrofs:=peheader.PointerToSymbolTable+peheader.NumberOfSymbols*sizeof(coffsymbol)+4;
  496. if e.secstrofs>e.size then
  497. exit;
  498. result:=true;
  499. end;
  500. {$endif PE32PLUS}
  501. {$IFDEF EMX}
  502. type
  503. TDosHeader = packed record
  504. e_magic : word;
  505. e_cblp : word;
  506. e_cp : word;
  507. e_crlc : word;
  508. e_cparhdr : word;
  509. e_minalloc : word;
  510. e_maxalloc : word;
  511. e_ss : word;
  512. e_sp : word;
  513. e_csum : word;
  514. e_ip : word;
  515. e_cs : word;
  516. e_lfarlc : word;
  517. e_ovno : word;
  518. e_res : array[0..3] of word;
  519. e_oemid : word;
  520. e_oeminfo : word;
  521. e_res2 : array[0..9] of word;
  522. e_lfanew : longint;
  523. end;
  524. TEmxHeader = packed record
  525. Version: array [1..16] of char;
  526. Bound: word;
  527. AoutOfs: longint;
  528. Options: array [1..42] of char;
  529. end;
  530. TAoutHeader = packed record
  531. Magic: word;
  532. Machine: byte;
  533. Flags: byte;
  534. TextSize: longint;
  535. DataSize: longint;
  536. BssSize: longint;
  537. SymbSize: longint;
  538. EntryPoint: longint;
  539. TextRelocSize: longint;
  540. DataRelocSize: longint;
  541. end;
  542. const
  543. StartPageSize = $1000;
  544. var
  545. DosHeader: TDosHeader;
  546. EmxHeader: TEmxHeader;
  547. AoutHeader: TAoutHeader;
  548. StabOfs: PtrUInt;
  549. S4: string [4];
  550. function OpenEMXaout (var E: TExeFile): boolean;
  551. begin
  552. OpenEMXaout := false;
  553. { GDB after 4.18 uses offset to function begin
  554. in text section but OS/2 version still uses 4.16 PM }
  555. E.FunctionRelative := false;
  556. { read and check header }
  557. if E.Size > SizeOf (DosHeader) then
  558. begin
  559. BlockRead (E.F, DosHeader, SizeOf (TDosHeader));
  560. if E.Size > DosHeader.e_cparhdr shl 4 + SizeOf (TEmxHeader) then
  561. begin
  562. Seek (E.F, DosHeader.e_cparhdr shl 4);
  563. BlockRead (E.F, EmxHeader, SizeOf (TEmxHeader));
  564. S4 [0] := #4;
  565. Move (EmxHeader.Version, S4 [1], 4);
  566. if (S4 = 'emx ') and
  567. (E.Size > EmxHeader.AoutOfs + SizeOf (TAoutHeader)) then
  568. begin
  569. Seek (E.F, EmxHeader.AoutOfs);
  570. BlockRead (E.F, AoutHeader, SizeOf (TAoutHeader));
  571. if AOutHeader.Magic = $10B then
  572. StabOfs := StartPageSize
  573. else
  574. StabOfs := EmxHeader.AoutOfs + SizeOf (TAoutHeader);
  575. StabOfs := StabOfs
  576. + AoutHeader.TextSize
  577. + AoutHeader.DataSize
  578. + AoutHeader.TextRelocSize
  579. + AoutHeader.DataRelocSize;
  580. if E.Size > StabOfs + AoutHeader.SymbSize then
  581. OpenEMXaout := true;
  582. end;
  583. end;
  584. end;
  585. end;
  586. function FindSectionEMXaout (var E: TExeFile; const ASecName: string;
  587. out SecOfs, SecLen: longint): boolean;
  588. begin
  589. FindSectionEMXaout := false;
  590. if ASecName = '.stab' then
  591. begin
  592. SecOfs := StabOfs;
  593. SecLen := AoutHeader.SymbSize;
  594. FindSectionEMXaout := true;
  595. end else
  596. if ASecName = '.stabstr' then
  597. begin
  598. SecOfs := StabOfs + AoutHeader.SymbSize;
  599. SecLen := E.Size - Pred (SecOfs);
  600. FindSectionEMXaout := true;
  601. end;
  602. end;
  603. {$ENDIF EMX}
  604. {$if defined(ELF32) or defined(ELF64)}
  605. type
  606. {$ifdef ELF32}
  607. telfheader=packed record
  608. magic0123 : longint;
  609. file_class : byte;
  610. data_encoding : byte;
  611. file_version : byte;
  612. padding : array[$07..$0f] of byte;
  613. e_type : word;
  614. e_machine : word;
  615. e_version : longword;
  616. e_entry : longword; // entrypoint
  617. e_phoff : longword; // program header offset
  618. e_shoff : longword; // sections header offset
  619. e_flags : longword;
  620. e_ehsize : word; // elf header size in bytes
  621. e_phentsize : word; // size of an entry in the program header array
  622. e_phnum : word; // 0..e_phnum-1 of entrys
  623. e_shentsize : word; // size of an entry in sections header array
  624. e_shnum : word; // 0..e_shnum-1 of entrys
  625. e_shstrndx : word; // index of string section header
  626. end;
  627. telfsechdr=packed record
  628. sh_name : longword;
  629. sh_type : longword;
  630. sh_flags : longword;
  631. sh_addr : longword;
  632. sh_offset : longword;
  633. sh_size : longword;
  634. sh_link : longword;
  635. sh_info : longword;
  636. sh_addralign : longword;
  637. sh_entsize : longword;
  638. end;
  639. {$endif ELF32}
  640. {$ifdef ELF64}
  641. telfheader=packed record
  642. magic0123 : longint;
  643. file_class : byte;
  644. data_encoding : byte;
  645. file_version : byte;
  646. padding : array[$07..$0f] of byte;
  647. e_type : word;
  648. e_machine : word;
  649. e_version : longword;
  650. e_entry : int64; // entrypoint
  651. e_phoff : int64; // program header offset
  652. e_shoff : int64; // sections header offset
  653. e_flags : longword;
  654. e_ehsize : word; // elf header size in bytes
  655. e_phentsize : word; // size of an entry in the program header array
  656. e_phnum : word; // 0..e_phnum-1 of entrys
  657. e_shentsize : word; // size of an entry in sections header array
  658. e_shnum : word; // 0..e_shnum-1 of entrys
  659. e_shstrndx : word; // index of string section header
  660. end;
  661. telfsechdr=packed record
  662. sh_name : longword;
  663. sh_type : longword;
  664. sh_flags : int64;
  665. sh_addr : int64;
  666. sh_offset : int64;
  667. sh_size : int64;
  668. sh_link : longword;
  669. sh_info : longword;
  670. sh_addralign : int64;
  671. sh_entsize : int64;
  672. end;
  673. {$endif ELF64}
  674. function OpenElf(var e:TExeFile):boolean;
  675. var
  676. elfheader : telfheader;
  677. elfsec : telfsechdr;
  678. begin
  679. result:=false;
  680. { read and check header }
  681. if e.size<sizeof(telfheader) then
  682. exit;
  683. blockread(e.f,elfheader,sizeof(telfheader));
  684. if elfheader.magic0123<>{$ifdef ENDIAN_LITTLE}$464c457f{$else}$7f454c46{$endif} then
  685. exit;
  686. if elfheader.e_shentsize<>sizeof(telfsechdr) then
  687. exit;
  688. { read section names }
  689. seek(e.f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telfsechdr)));
  690. blockread(e.f,elfsec,sizeof(telfsechdr));
  691. e.secstrofs:=elfsec.sh_offset;
  692. e.sechdrofs:=elfheader.e_shoff;
  693. e.nsects:=elfheader.e_shnum;
  694. result:=true;
  695. end;
  696. function FindSectionElf(var e:TExeFile;const asecname:string;out secofs,seclen:longint):boolean;
  697. var
  698. elfsec : telfsechdr;
  699. secname : string;
  700. secnamebuf : array[0..255] of char;
  701. oldofs,
  702. bufsize,i : longint;
  703. begin
  704. result:=false;
  705. seek(e.f,e.sechdrofs);
  706. for i:=1 to e.nsects do
  707. begin
  708. blockread(e.f,elfsec,sizeof(telfsechdr));
  709. fillchar(secnamebuf,sizeof(secnamebuf),0);
  710. oldofs:=filepos(e.f);
  711. seek(e.f,e.secstrofs+elfsec.sh_name);
  712. blockread(e.f,secnamebuf,sizeof(secnamebuf),bufsize);
  713. seek(e.f,oldofs);
  714. secname:=strpas(secnamebuf);
  715. if asecname=secname then
  716. begin
  717. secofs:=elfsec.sh_offset;
  718. seclen:=elfsec.sh_size;
  719. result:=true;
  720. exit;
  721. end;
  722. end;
  723. end;
  724. {$endif ELF32}
  725. {$ifdef beos}
  726. {$i ptypes.inc}
  727. { ------------------------- Images --------------------------- }
  728. type
  729. // Descriptive formats
  730. status_t = Longint;
  731. team_id = Longint;
  732. image_id = Longint;
  733. { image types }
  734. const
  735. B_APP_IMAGE = 1;
  736. B_LIBRARY_IMAGE = 2;
  737. B_ADD_ON_IMAGE = 3;
  738. B_SYSTEM_IMAGE = 4;
  739. type
  740. image_info = packed record
  741. id : image_id;
  742. _type : longint;
  743. sequence: longint;
  744. init_order: longint;
  745. init_routine: pointer;
  746. term_routine: pointer;
  747. device: dev_t;
  748. node: ino_t;
  749. name: array[0..MAXPATHLEN-1] of char;
  750. { name: string[255];
  751. name2: string[255];
  752. name3: string[255];
  753. name4: string[255];
  754. name5: string[5];
  755. }
  756. text: pointer;
  757. data: pointer;
  758. text_size: longint;
  759. data_size: longint;
  760. end;
  761. 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';
  762. function LoadElf32Beos:boolean;
  763. type
  764. telf32header=packed record
  765. magic0123 : longint;
  766. file_class : byte;
  767. data_encoding : byte;
  768. file_version : byte;
  769. padding : array[$07..$0f] of byte;
  770. e_type : word;
  771. e_machine : word;
  772. e_version : longword;
  773. e_entry : longword; // entrypoint
  774. e_phoff : longword; // program header offset
  775. e_shoff : longword; // sections header offset
  776. e_flags : longword;
  777. e_ehsize : word; // elf header size in bytes
  778. e_phentsize : word; // size of an entry in the program header array
  779. e_phnum : word; // 0..e_phnum-1 of entrys
  780. e_shentsize : word; // size of an entry in sections header array
  781. e_shnum : word; // 0..e_shnum-1 of entrys
  782. e_shstrndx : word; // index of string section header
  783. end;
  784. telf32sechdr=packed record
  785. sh_name : longword;
  786. sh_type : longword;
  787. sh_flags : longword;
  788. sh_addr : longword;
  789. sh_offset : longword;
  790. sh_size : longword;
  791. sh_link : longword;
  792. sh_info : longword;
  793. sh_addralign : longword;
  794. sh_entsize : longword;
  795. end;
  796. var
  797. elfheader : telf32header;
  798. elfsec : telf32sechdr;
  799. secnames : array[0..255] of char;
  800. pname : pchar;
  801. i : longint;
  802. cookie : longint;
  803. info : image_info;
  804. result : status_t;
  805. begin
  806. cookie := 0;
  807. fillchar(info, sizeof(image_info), 0);
  808. get_next_image_info(0,cookie,info,sizeof(info));
  809. if (info._type = B_APP_IMAGE) then
  810. processaddress := cardinal(info.text)
  811. else
  812. processaddress := 0;
  813. LoadElf32Beos:=false;
  814. stabofs:=-1;
  815. stabstrofs:=-1;
  816. { read and check header }
  817. if E.Size<sizeof(telf32header) then
  818. exit;
  819. blockread(f,elfheader,sizeof(telf32header));
  820. {$ifdef ENDIAN_LITTLE}
  821. if elfheader.magic0123<>$464c457f then
  822. exit;
  823. {$endif ENDIAN_LITTLE}
  824. {$ifdef ENDIAN_BIG}
  825. if elfheader.magic0123<>$7f454c46 then
  826. exit;
  827. {$endif ENDIAN_BIG}
  828. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  829. exit;
  830. { read section names }
  831. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  832. blockread(f,elfsec,sizeof(telf32sechdr));
  833. seek(f,elfsec.sh_offset);
  834. blockread(f,secnames,sizeof(secnames));
  835. { read section info }
  836. seek(f,elfheader.e_shoff);
  837. for i:=1to elfheader.e_shnum do
  838. begin
  839. blockread(f,elfsec,sizeof(telf32sechdr));
  840. pname:=@secnames[elfsec.sh_name];
  841. if (pname[4]='b') and
  842. (pname[1]='s') and
  843. (pname[2]='t') then
  844. begin
  845. if (pname[5]='s') and
  846. (pname[6]='t') then
  847. stabstrofs:=elfsec.sh_offset
  848. else
  849. begin
  850. stabofs:=elfsec.sh_offset;
  851. stabcnt:=elfsec.sh_size div sizeof(tstab);
  852. end;
  853. end;
  854. end;
  855. LoadElf32Beos:=(stabofs<>-1) and (stabstrofs<>-1);
  856. end;
  857. {$endif beos}
  858. {$ifdef darwin}
  859. type
  860. MachoFatHeader=
  861. packed record
  862. magic: longint;
  863. nfatarch: longint;
  864. end;
  865. MachoHeader=
  866. packed record
  867. magic: longword;
  868. cpu_type_t: longint;
  869. cpu_subtype_t: longint;
  870. filetype: longint;
  871. ncmds: longint;
  872. sizeofcmds: longint;
  873. flags: longint;
  874. end;
  875. cmdblock=
  876. packed record
  877. cmd: longint;
  878. cmdsize: longint;
  879. end;
  880. symbSeg=
  881. packed record
  882. symoff : longint;
  883. nsyms : longint;
  884. stroff : longint;
  885. strsize: longint;
  886. end;
  887. tstab=packed record
  888. strpos : longint;
  889. ntype : byte;
  890. nother : byte;
  891. ndesc : word;
  892. nvalue : dword;
  893. end;
  894. function OpenMachO32PPC(var e:TExeFile):boolean;
  895. var
  896. mh:MachoHeader;
  897. begin
  898. result:= false;
  899. if e.size<sizeof(mh) then
  900. exit;
  901. blockread (e.f, mh, sizeof(mh));
  902. e.sechdrofs:=filepos(e.f);
  903. e.nsects:=mh.ncmds;
  904. result:=true;
  905. end;
  906. function FindSectionMachO32PPC(var e:TExeFile;const asecname:string;out secofs,seclen:longint):boolean;
  907. var
  908. i: longint;
  909. block:cmdblock;
  910. symbolsSeg: symbSeg;
  911. begin
  912. seek(e.f,e.sechdrofs);
  913. for i:= 1 to e.nsects do
  914. begin
  915. blockread (e.f, block, sizeof(block));
  916. if block.cmd = $2 then
  917. begin
  918. blockread (e.f, symbolsSeg, sizeof(symbolsSeg));
  919. if asecname='.stab' then
  920. begin
  921. secofs:=symbolsSeg.symoff;
  922. { the caller will divide again by sizeof(tstab) }
  923. seclen:=symbolsSeg.nsyms*sizeof(tstab);
  924. end
  925. else if asecname='.stabstr' then
  926. begin
  927. secofs:=symbolsSeg.stroff;
  928. seclen:=symbolsSeg.strsize;
  929. end;
  930. result:=true;
  931. exit;
  932. end;
  933. Seek(e.f, FilePos (e.f) + block.cmdsize - sizeof(block));
  934. end;
  935. end;
  936. {$endif darwin}
  937. {****************************************************************************
  938. Generic Executable Open/Close
  939. ****************************************************************************}
  940. type
  941. TOpenProc=function(var e:TExeFile):boolean;
  942. TFindSectionProc=function(var e:TExeFile;const asecname:string;out secofs,seclen:longint):boolean;
  943. TExeProcRec=record
  944. openproc : TOpenProc;
  945. findproc : TFindSectionProc;
  946. end;
  947. const
  948. ExeProcs : TExeProcRec = (
  949. {$ifdef go32v2}
  950. openproc : @OpenGo32Coff;
  951. findproc : @FindSectionGo32Coff;
  952. {$endif}
  953. {$IFDEF EMX}
  954. openproc : @OpenEMXaout;
  955. findproc : @FindSectionEMXaout;
  956. {$ENDIF EMX}
  957. {$ifdef PE32}
  958. openproc : @OpenPeCoff;
  959. findproc : @FindSectionPeCoff;
  960. {$endif}
  961. {$ifdef PE32PLUS}
  962. openproc : @OpenPePlusCoff;
  963. findproc : @FindSectionPeCoff;
  964. {$endif PE32PLUS}
  965. {$if defined(ELF32) or defined(ELF64)}
  966. openproc : @OpenElf;
  967. findproc : @FindSectionElf;
  968. {$endif}
  969. {$ifdef Beos}
  970. openproc : @OpenElf32Beos;
  971. findproc : @FindSectionElf32Beos;
  972. {$endif}
  973. {$ifdef darwin}
  974. openproc : @OpenMachO32PPC;
  975. findproc : @FindSectionMachO32PPC;
  976. {$endif darwin}
  977. {$ifdef netware}
  978. openproc : @OpenNetwareNLM;
  979. findproc : @FindSectionNetwareNLM;
  980. {$endif}
  981. );
  982. function OpenExeFile(out e:TExeFile;const fn:string):boolean;
  983. var
  984. ofm : word;
  985. begin
  986. result:=false;
  987. fillchar(e,sizeof(e),0);
  988. assign(e.f,fn);
  989. {$I-}
  990. ofm:=filemode;
  991. filemode:=$40;
  992. reset(e.f,1);
  993. filemode:=ofm;
  994. {$I+}
  995. if ioresult<>0 then
  996. exit;
  997. e.isopen:=true;
  998. // cache filesize
  999. e.size:=filesize(e.f);
  1000. E.FunctionRelative := true;
  1001. if ExeProcs.OpenProc<>nil then
  1002. result:=ExeProcs.OpenProc(e);
  1003. end;
  1004. function CloseExeFile(var e:TExeFile):boolean;
  1005. begin
  1006. result:=false;
  1007. if not e.isopen then
  1008. exit;
  1009. e.isopen:=false;
  1010. close(e.f);
  1011. result:=true;
  1012. end;
  1013. function FindExeSection(var e:TExeFile;const secname:string;out secofs,seclen:longint):boolean;
  1014. begin
  1015. result:=false;
  1016. if not e.isopen then
  1017. exit;
  1018. if ExeProcs.FindProc<>nil then
  1019. result:=ExeProcs.FindProc(e,secname,secofs,seclen);
  1020. end;
  1021. end.