exeinfo.pp 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  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. seek(e.f,e.sechdrofs);
  777. for i:= 1 to e.nsects do
  778. begin
  779. blockread (e.f, block, sizeof(block));
  780. if block.cmd = $2 then
  781. begin
  782. blockread (e.f, symbolsSeg, sizeof(symbolsSeg));
  783. if asecname='.stab' then
  784. begin
  785. secofs:=symbolsSeg.symoff;
  786. { the caller will divide again by sizeof(tstab) }
  787. seclen:=symbolsSeg.nsyms*sizeof(tstab);
  788. end
  789. else if asecname='.stabstr' then
  790. begin
  791. secofs:=symbolsSeg.stroff;
  792. seclen:=symbolsSeg.strsize;
  793. end;
  794. FindSectionMachO32PPC:=true;
  795. exit;
  796. end;
  797. Seek(e.f, FilePos (e.f) + block.cmdsize - sizeof(block));
  798. end;
  799. end;
  800. {$endif darwin}
  801. {****************************************************************************
  802. CRC
  803. ****************************************************************************}
  804. var
  805. Crc32Tbl : array[0..255] of cardinal;
  806. procedure MakeCRC32Tbl;
  807. var
  808. crc : cardinal;
  809. i,n : integer;
  810. begin
  811. for i:=0 to 255 do
  812. begin
  813. crc:=i;
  814. for n:=1 to 8 do
  815. if (crc and 1)<>0 then
  816. crc:=(crc shr 1) xor cardinal($edb88320)
  817. else
  818. crc:=crc shr 1;
  819. Crc32Tbl[i]:=crc;
  820. end;
  821. end;
  822. Function UpdateCrc32(InitCrc:cardinal;const InBuf;InLen:LongInt):cardinal;
  823. var
  824. i : LongInt;
  825. p : pchar;
  826. begin
  827. if Crc32Tbl[1]=0 then
  828. MakeCrc32Tbl;
  829. p:=@InBuf;
  830. UpdateCrc32:=not InitCrc;
  831. for i:=1 to InLen do
  832. begin
  833. UpdateCrc32:=Crc32Tbl[byte(UpdateCrc32) xor byte(p^)] xor (UpdateCrc32 shr 8);
  834. inc(p);
  835. end;
  836. UpdateCrc32:=not UpdateCrc32;
  837. end;
  838. {****************************************************************************
  839. Generic Executable Open/Close
  840. ****************************************************************************}
  841. type
  842. TOpenProc=function(var e:TExeFile):boolean;
  843. TFindSectionProc=function(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
  844. TExeProcRec=record
  845. openproc : TOpenProc;
  846. findproc : TFindSectionProc;
  847. end;
  848. const
  849. ExeProcs : TExeProcRec = (
  850. {$ifdef go32v2}
  851. openproc : @OpenGo32Coff;
  852. findproc : @FindSectionCoff;
  853. {$endif}
  854. {$ifdef PE32}
  855. openproc : @OpenPeCoff;
  856. findproc : @FindSectionCoff;
  857. {$endif}
  858. {$ifdef PE32PLUS}
  859. openproc : @OpenPePlusCoff;
  860. findproc : @FindSectionCoff;
  861. {$endif PE32PLUS}
  862. {$if defined(ELF32) or defined(ELF64)}
  863. openproc : @OpenElf;
  864. findproc : @FindSectionElf;
  865. {$endif ELF32 or ELF64}
  866. {$ifdef BEOS}
  867. openproc : @OpenElf32Beos;
  868. findproc : @FindSectionElf;
  869. {$endif BEOS}
  870. {$ifdef darwin}
  871. openproc : @OpenMachO32PPC;
  872. findproc : @FindSectionMachO32PPC;
  873. {$endif darwin}
  874. {$IFDEF EMX}
  875. openproc : @OpenEMXaout;
  876. findproc : @FindSectionEMXaout;
  877. {$ENDIF EMX}
  878. {$ifdef netware}
  879. openproc : @OpenNetwareNLM;
  880. findproc : @FindSectionNetwareNLM;
  881. {$endif}
  882. );
  883. function OpenExeFile(var e:TExeFile;const fn:string):boolean;
  884. var
  885. ofm : word;
  886. begin
  887. OpenExeFile:=false;
  888. fillchar(e,sizeof(e),0);
  889. e.bufsize:=sizeof(e.buf);
  890. e.filename:=fn;
  891. assign(e.f,fn);
  892. {$I-}
  893. ofm:=filemode;
  894. filemode:=$40;
  895. reset(e.f,1);
  896. filemode:=ofm;
  897. {$I+}
  898. if ioresult<>0 then
  899. exit;
  900. e.isopen:=true;
  901. // cache filesize
  902. e.size:=filesize(e.f);
  903. E.FunctionRelative := true;
  904. if ExeProcs.OpenProc<>nil then
  905. OpenExeFile:=ExeProcs.OpenProc(e);
  906. end;
  907. function CloseExeFile(var e:TExeFile):boolean;
  908. begin
  909. CloseExeFile:=false;
  910. if not e.isopen then
  911. exit;
  912. e.isopen:=false;
  913. close(e.f);
  914. CloseExeFile:=true;
  915. end;
  916. function FindExeSection(var e:TExeFile;const secname:string;var secofs,seclen:longint):boolean;
  917. begin
  918. FindExeSection:=false;
  919. if not e.isopen then
  920. exit;
  921. if ExeProcs.FindProc<>nil then
  922. FindExeSection:=ExeProcs.FindProc(e,secname,secofs,seclen);
  923. end;
  924. function CheckDbgFile(var e:TExeFile;const fn:string;dbgcrc:cardinal):boolean;
  925. var
  926. c : cardinal;
  927. ofm : word;
  928. g : file;
  929. begin
  930. CheckDbgFile:=false;
  931. assign(g,fn);
  932. {$I-}
  933. ofm:=filemode;
  934. filemode:=$40;
  935. reset(g,1);
  936. filemode:=ofm;
  937. {$I+}
  938. if ioresult<>0 then
  939. exit;
  940. { We reuse the buffer from e here to prevent too much stack allocation }
  941. c:=0;
  942. repeat
  943. blockread(g,e.buf,e.bufsize,e.bufcnt);
  944. c:=UpdateCrc32(c,e.buf,e.bufcnt);
  945. until e.bufcnt<e.bufsize;
  946. close(g);
  947. CheckDbgFile:=(dbgcrc=c);
  948. end;
  949. function ReadDebugLink(var e:TExeFile;var dbgfn:string):boolean;
  950. var
  951. dbglink : array[0..255] of char;
  952. i,
  953. dbglinklen,
  954. dbglinkofs : longint;
  955. dbgcrc : cardinal;
  956. begin
  957. ReadDebugLink:=false;
  958. if not FindExeSection(e,'.gnu_debuglink',dbglinkofs,dbglinklen) then
  959. exit;
  960. if dbglinklen>sizeof(dbglink)-1 then
  961. exit;
  962. fillchar(dbglink,sizeof(dbglink),0);
  963. seek(e.f,dbglinkofs);
  964. blockread(e.f,dbglink,dbglinklen);
  965. dbgfn:=strpas(dbglink);
  966. if length(dbgfn)=0 then
  967. exit;
  968. i:=align(length(dbgfn)+1,4);
  969. if i>dbglinklen then
  970. exit;
  971. move(dbglink[i],dbgcrc,4);
  972. { current dir }
  973. if CheckDbgFile(e,dbgfn,dbgcrc) then
  974. begin
  975. ReadDebugLink:=true;
  976. exit;
  977. end;
  978. { executable dir }
  979. i:=length(e.filename);
  980. while (i>0) and not(e.filename[i] in AllowDirectorySeparators) do
  981. dec(i);
  982. if i>0 then
  983. begin
  984. dbgfn:=copy(e.filename,1,i)+dbgfn;
  985. if CheckDbgFile(e,dbgfn,dbgcrc) then
  986. begin
  987. ReadDebugLink:=true;
  988. exit;
  989. end;
  990. end;
  991. end;
  992. end.