exeinfo.pp 27 KB

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