exeinfo.pp 28 KB

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