exeinfo.pp 28 KB

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