exeinfo.pp 27 KB

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