exeinfo.pp 27 KB

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