exeinfo.pp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401
  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. { Disable checks of pointers explictly,
  16. as we are dealing here with special pointer that
  17. might be seen as invalid by heaptrc unit CheckPointer function }
  18. {$checkpointer off}
  19. unit exeinfo;
  20. interface
  21. {$S-}
  22. type
  23. TExeFile=record
  24. f : file;
  25. // cached filesize
  26. size : int64;
  27. isopen : boolean;
  28. nsects : longint;
  29. sechdrofs,
  30. secstrofs : {$ifdef cpui8086}longword{$else}ptruint{$endif};
  31. processaddress : {$ifdef cpui8086}word{$else}ptruint{$endif};
  32. {$ifdef cpui8086}
  33. processsegment : word;
  34. {$endif cpui8086}
  35. FunctionRelative: boolean;
  36. // Offset of the binary image forming permanent offset to all retrieved values
  37. ImgOffset: {$ifdef cpui8086}longword{$else}ptruint{$endif};
  38. filename : string;
  39. // Allocate static buffer for reading data
  40. buf : array[0..4095] of byte;
  41. bufsize,
  42. bufcnt : longint;
  43. end;
  44. function OpenExeFile(var e:TExeFile;const fn:string):boolean;
  45. function FindExeSection(var e:TExeFile;const secname:string;var secofs,seclen:longint):boolean;
  46. function CloseExeFile(var e:TExeFile):boolean;
  47. function ReadDebugLink(var e:TExeFile;var dbgfn:string):boolean;
  48. {$ifdef CPUI8086}
  49. procedure GetModuleByAddr(addr: farpointer; var baseaddr: farpointer; var filename: string);
  50. {$else CPUI8086}
  51. procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
  52. {$endif CPUI8086}
  53. implementation
  54. uses
  55. strings{$ifdef windows},windows{$endif windows};
  56. {$if defined(unix) and not defined(beos) and not defined(haiku)}
  57. procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
  58. begin
  59. if assigned(UnixGetModuleByAddrHook) then
  60. UnixGetModuleByAddrHook(addr,baseaddr,filename)
  61. else
  62. begin
  63. baseaddr:=nil;
  64. filename:=ParamStr(0);
  65. end;
  66. end;
  67. {$elseif defined(windows)}
  68. var
  69. Tmm: TMemoryBasicInformation;
  70. {$ifdef FPC_OS_UNICODE}
  71. TST: array[0..Max_Path] of WideChar;
  72. {$else}
  73. TST: array[0..Max_Path] of Char;
  74. {$endif FPC_OS_UNICODE}
  75. procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
  76. begin
  77. baseaddr:=nil;
  78. if VirtualQuery(addr, @Tmm, SizeOf(Tmm))<>sizeof(Tmm) then
  79. filename:=ParamStr(0)
  80. else
  81. begin
  82. baseaddr:=Tmm.AllocationBase;
  83. TST[0]:= #0;
  84. GetModuleFileName(THandle(Tmm.AllocationBase), TST, Length(TST));
  85. {$ifdef FPC_OS_UNICODE}
  86. filename:= String(PWideChar(@TST));
  87. {$else}
  88. filename:= String(PChar(@TST));
  89. {$endif FPC_OS_UNICODE}
  90. end;
  91. end;
  92. {$elseif defined(morphos) or defined(aros) or defined(amigaos4)}
  93. procedure startsymbol; external name '_start';
  94. procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
  95. begin
  96. baseaddr:= @startsymbol;
  97. {$ifdef FPC_HAS_FEATURE_COMMANDARGS}
  98. filename:=ParamStr(0);
  99. {$else FPC_HAS_FEATURE_COMMANDARGS}
  100. filename:='';
  101. {$endif FPC_HAS_FEATURE_COMMANDARGS}
  102. end;
  103. {$elseif defined(msdos)}
  104. procedure GetModuleByAddr(addr: farpointer; var baseaddr: farpointer; var filename: string);
  105. begin
  106. baseaddr:=Ptr(PrefixSeg+16,0);
  107. filename:=ParamStr(0);
  108. end;
  109. {$elseif defined(beos) or defined(haiku)}
  110. {$i ptypes.inc}
  111. {$i ostypes.inc}
  112. 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';
  113. procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
  114. const
  115. B_OK = 0;
  116. var
  117. cookie : longint;
  118. info : image_info;
  119. begin
  120. filename:='';
  121. baseaddr:=nil;
  122. cookie:=0;
  123. fillchar(info, sizeof(image_info), 0);
  124. while get_next_image_info(0,cookie,info,sizeof(info))=B_OK do
  125. begin
  126. if (info._type = B_APP_IMAGE) and
  127. (addr >= info.text) and (addr <= (info.text + info.text_size)) then
  128. begin
  129. baseaddr:=info.text;
  130. filename:=PChar(@info.name);
  131. end;
  132. end;
  133. end;
  134. {$else}
  135. {$ifdef CPUI8086}
  136. procedure GetModuleByAddr(addr: farpointer; var baseaddr: farpointer; var filename: string);
  137. {$else CPUI8086}
  138. procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
  139. {$endif CPUI8086}
  140. begin
  141. baseaddr:= nil;
  142. {$ifdef FPC_HAS_FEATURE_COMMANDARGS}
  143. filename:=ParamStr(0);
  144. {$else FPC_HAS_FEATURE_COMMANDARGS}
  145. filename:='';
  146. {$endif FPC_HAS_FEATURE_COMMANDARGS}
  147. end;
  148. {$endif}
  149. {****************************************************************************
  150. Executable Loaders
  151. ****************************************************************************}
  152. {$if defined(freebsd) or defined(netbsd) or defined (openbsd) or defined(linux) or defined(sunos) or defined(android) or defined(dragonfly)}
  153. {$ifdef cpu64}
  154. {$define ELF64}
  155. {$define FIND_BASEADDR_ELF}
  156. {$else}
  157. {$define ELF32}
  158. {$define FIND_BASEADDR_ELF}
  159. {$endif}
  160. {$endif}
  161. {$if defined(beos) or defined(haiku)}
  162. {$ifdef cpu64}
  163. {$define ELF64}
  164. {$else}
  165. {$define ELF32}
  166. {$endif}
  167. {$endif}
  168. {$if defined(morphos) or defined(aros) or defined(amigaos4)}
  169. {$ifdef cpu64}
  170. {$define ELF64}
  171. {$else}
  172. {$define ELF32}
  173. {$endif}
  174. {$endif}
  175. {$if defined(msdos)}
  176. {$define ELF32}
  177. {$endif}
  178. {$if defined(win32) or defined(wince)}
  179. {$define PE32}
  180. {$endif}
  181. {$if defined(win64)}
  182. {$define PE32PLUS}
  183. {$endif}
  184. {$ifdef netwlibc}
  185. {$define netware}
  186. {$endif}
  187. {$IFDEF OS2}
  188. {$DEFINE EMX}
  189. {$ENDIF OS2}
  190. {****************************************************************************
  191. DOS Stub
  192. ****************************************************************************}
  193. {$if defined(EMX) or defined(PE32) or defined(PE32PLUS) or defined(GO32V2) or defined(MSDOS)}
  194. type
  195. tdosheader = packed record
  196. e_magic : word;
  197. e_cblp : word;
  198. e_cp : word;
  199. e_crlc : word;
  200. e_cparhdr : word;
  201. e_minalloc : word;
  202. e_maxalloc : word;
  203. e_ss : word;
  204. e_sp : word;
  205. e_csum : word;
  206. e_ip : word;
  207. e_cs : word;
  208. e_lfarlc : word;
  209. e_ovno : word;
  210. e_res : array[0..3] of word;
  211. e_oemid : word;
  212. e_oeminfo : word;
  213. e_res2 : array[0..9] of word;
  214. e_lfanew : longint;
  215. end;
  216. {$endif EMX or PE32 or PE32PLUS or GO32v2}
  217. {****************************************************************************
  218. NLM
  219. ****************************************************************************}
  220. {$ifdef netware}
  221. function getByte(var f:file):byte;
  222. begin
  223. BlockRead (f,getByte,1);
  224. end;
  225. procedure Skip (var f:file; bytes : longint);
  226. var i : longint;
  227. begin
  228. for i := 1 to bytes do getbyte(f);
  229. end;
  230. function get0String (var f:file) : string;
  231. var c : char;
  232. begin
  233. get0String := '';
  234. c := char (getbyte(f));
  235. while (c <> #0) do
  236. begin
  237. get0String := get0String + c;
  238. c := char (getbyte(f));
  239. end;
  240. end;
  241. function getint32 (var f:file): longint;
  242. begin
  243. blockread (F, getint32, 4);
  244. end;
  245. const SIZE_OF_NLM_INTERNAL_FIXED_HEADER = 130;
  246. SIZE_OF_NLM_INTERNAL_VERSION_HEADER = 32;
  247. SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER = 124;
  248. function openNetwareNLM(var e:TExeFile):boolean;
  249. var valid : boolean;
  250. name : string;
  251. hdrLength,
  252. dataOffset,
  253. dataLength : longint;
  254. function getLString : String;
  255. var Res:string;
  256. begin
  257. blockread (e.F, res, 1);
  258. if length (res) > 0 THEN
  259. blockread (e.F, res[1], length (res));
  260. getbyte(e.f);
  261. getLString := res;
  262. end;
  263. function getFixString (Len : byte) : string;
  264. var i : byte;
  265. begin
  266. getFixString := '';
  267. for I := 1 to Len do
  268. getFixString := getFixString + char (getbyte(e.f));
  269. end;
  270. function getword : word;
  271. begin
  272. blockread (e.F, getword, 2);
  273. end;
  274. begin
  275. e.sechdrofs := 0;
  276. openNetwareNLM:=false;
  277. // read and check header
  278. Skip (e.f,SIZE_OF_NLM_INTERNAL_FIXED_HEADER);
  279. getLString; // NLM Description
  280. getInt32(e.f); // Stacksize
  281. getInt32(e.f); // Reserved
  282. skip(e.f,5); // old Thread Name
  283. getLString; // Screen Name
  284. getLString; // Thread Name
  285. hdrLength := -1;
  286. dataOffset := -1;
  287. dataLength := -1;
  288. valid := true;
  289. repeat
  290. name := getFixString (8);
  291. if (name = 'VeRsIoN#') then
  292. begin
  293. Skip (e.f,SIZE_OF_NLM_INTERNAL_VERSION_HEADER-8);
  294. end else
  295. if (name = 'CoPyRiGh') then
  296. begin
  297. getword; // T=
  298. getLString; // Copyright String
  299. end else
  300. if (name = 'MeSsAgEs') then
  301. begin
  302. skip (e.f,SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER - 8);
  303. end else
  304. if (name = 'CuStHeAd') then
  305. begin
  306. hdrLength := getInt32(e.f);
  307. dataOffset := getInt32(e.f);
  308. dataLength := getInt32(e.f);
  309. Skip (e.f,8); // dateStamp
  310. Valid := false;
  311. end else
  312. Valid := false;
  313. until not valid;
  314. if (hdrLength = -1) or (dataOffset = -1) or (dataLength = -1) then
  315. exit;
  316. Seek (e.F, dataOffset);
  317. e.sechdrofs := dataOffset;
  318. openNetwareNLM := (e.sechdrofs > 0);
  319. end;
  320. function FindSectionNetwareNLM(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
  321. var name : string;
  322. alignAmount : longint;
  323. begin
  324. seek(e.f,e.sechdrofs);
  325. (* The format of the section information is:
  326. null terminated section name
  327. zeroes to adjust to 4 byte boundary
  328. 4 byte section data file pointer
  329. 4 byte section size *)
  330. Repeat
  331. Name := Get0String(e.f);
  332. alignAmount := 4 - ((length (Name) + 1) MOD 4);
  333. Skip (e.f,AlignAmount);
  334. if (Name = asecname) then
  335. begin
  336. secOfs := getInt32(e.f);
  337. secLen := getInt32(e.f);
  338. end else
  339. Skip(e.f,8);
  340. until (Name = '') or (Name = asecname);
  341. FindSectionNetwareNLM := (Name=asecname);
  342. end;
  343. {$endif}
  344. {****************************************************************************
  345. COFF
  346. ****************************************************************************}
  347. {$if defined(PE32) or defined(PE32PLUS) or defined(GO32V2)}
  348. type
  349. tcoffsechdr=packed record
  350. name : array[0..7] of char;
  351. vsize : longint;
  352. rvaofs : longint;
  353. datalen : longint;
  354. datapos : longint;
  355. relocpos : longint;
  356. lineno1 : longint;
  357. nrelocs : word;
  358. lineno2 : word;
  359. flags : longint;
  360. end;
  361. coffsymbol=packed record
  362. name : array[0..3] of char; { real is [0..7], which overlaps the strofs ! }
  363. strofs : longint;
  364. value : longint;
  365. section : smallint;
  366. empty : word;
  367. typ : byte;
  368. aux : byte;
  369. end;
  370. function FindSectionCoff(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
  371. var
  372. i : longint;
  373. sechdr : tcoffsechdr;
  374. secname : string;
  375. secnamebuf : array[0..255] of char;
  376. code,
  377. oldofs,
  378. bufsize : longint;
  379. strofs : cardinal;
  380. begin
  381. FindSectionCoff:=false;
  382. { read section info }
  383. seek(e.f,e.sechdrofs);
  384. for i:=1 to e.nsects do
  385. begin
  386. blockread(e.f,sechdr,sizeof(sechdr),bufsize);
  387. move(sechdr.name,secnamebuf,8);
  388. secnamebuf[8]:=#0;
  389. secname:=strpas(secnamebuf);
  390. if secname[1]='/' then
  391. begin
  392. Val(Copy(secname,2,8),strofs,code);
  393. if code=0 then
  394. begin
  395. fillchar(secnamebuf,sizeof(secnamebuf),0);
  396. oldofs:=filepos(e.f);
  397. seek(e.f,e.secstrofs+strofs);
  398. blockread(e.f,secnamebuf,sizeof(secnamebuf),bufsize);
  399. seek(e.f,oldofs);
  400. secname:=strpas(secnamebuf);
  401. end
  402. else
  403. secname:='';
  404. end;
  405. if asecname=secname then
  406. begin
  407. secofs:=cardinal(sechdr.datapos) + E.ImgOffset;
  408. {$ifdef GO32V2}
  409. seclen:=sechdr.datalen;
  410. {$else GO32V2}
  411. { In PECOFF, datalen includes file padding up to the next section.
  412. vsize is the actual payload size if it does not exceed datalen,
  413. otherwise it is .bss (or alike) section that we should ignore. }
  414. if sechdr.vsize<=sechdr.datalen then
  415. seclen:=sechdr.vsize
  416. else
  417. exit;
  418. {$endif GO32V2}
  419. FindSectionCoff:=true;
  420. exit;
  421. end;
  422. end;
  423. end;
  424. {$endif PE32 or PE32PLUS or GO32V2}
  425. {$ifdef go32v2}
  426. function OpenGo32Coff(var e:TExeFile):boolean;
  427. type
  428. tgo32coffheader=packed record
  429. mach : word;
  430. nsects : word;
  431. time : longint;
  432. sympos : longint;
  433. syms : longint;
  434. opthdr : word;
  435. flag : word;
  436. other : array[0..27] of byte;
  437. end;
  438. const
  439. ParagraphSize = 512;
  440. var
  441. coffheader : tgo32coffheader;
  442. DosHeader: TDosHeader;
  443. BRead: cardinal;
  444. begin
  445. OpenGo32Coff:=false;
  446. { read and check header }
  447. if E.Size < SizeOf (DosHeader) then
  448. Exit;
  449. BlockRead (E.F, DosHeader, SizeOf (DosHeader), BRead);
  450. if BRead <> SizeOf (DosHeader) then
  451. Exit;
  452. if DosHeader.E_Magic = $5A4D then
  453. begin
  454. E.ImgOffset := DosHeader.e_cp * ParagraphSize;
  455. if DosHeader.e_cblp > 0 then
  456. E.ImgOffset := E.ImgOffset + DosHeader.e_cblp - ParagraphSize;
  457. end;
  458. if e.size < E.ImgOffset + sizeof(coffheader) then
  459. exit;
  460. seek(e.f,E.ImgOffset);
  461. blockread(e.f,coffheader,sizeof(coffheader));
  462. if coffheader.mach<>$14c then
  463. exit;
  464. e.sechdrofs:=filepos(e.f);
  465. e.nsects:=coffheader.nsects;
  466. e.secstrofs:=coffheader.sympos+coffheader.syms*sizeof(coffsymbol)+4;
  467. if e.secstrofs>e.size then
  468. exit;
  469. OpenGo32Coff:=true;
  470. end;
  471. {$endif Go32v2}
  472. {$ifdef PE32}
  473. function OpenPeCoff(var e:TExeFile):boolean;
  474. type
  475. tpeheader = packed record
  476. PEMagic : longint;
  477. Machine : word;
  478. NumberOfSections : word;
  479. TimeDateStamp : longint;
  480. PointerToSymbolTable : longint;
  481. NumberOfSymbols : longint;
  482. SizeOfOptionalHeader : word;
  483. Characteristics : word;
  484. Magic : word;
  485. MajorLinkerVersion : byte;
  486. MinorLinkerVersion : byte;
  487. SizeOfCode : longint;
  488. SizeOfInitializedData : longint;
  489. SizeOfUninitializedData : longint;
  490. AddressOfEntryPoint : longint;
  491. BaseOfCode : longint;
  492. BaseOfData : longint;
  493. ImageBase : longint;
  494. SectionAlignment : longint;
  495. FileAlignment : longint;
  496. MajorOperatingSystemVersion : word;
  497. MinorOperatingSystemVersion : word;
  498. MajorImageVersion : word;
  499. MinorImageVersion : word;
  500. MajorSubsystemVersion : word;
  501. MinorSubsystemVersion : word;
  502. Reserved1 : longint;
  503. SizeOfImage : longint;
  504. SizeOfHeaders : longint;
  505. CheckSum : longint;
  506. Subsystem : word;
  507. DllCharacteristics : word;
  508. SizeOfStackReserve : longint;
  509. SizeOfStackCommit : longint;
  510. SizeOfHeapReserve : longint;
  511. SizeOfHeapCommit : longint;
  512. LoaderFlags : longint;
  513. NumberOfRvaAndSizes : longint;
  514. DataDirectory : array[1..$80] of byte;
  515. end;
  516. var
  517. dosheader : tdosheader;
  518. peheader : tpeheader;
  519. begin
  520. OpenPeCoff:=false;
  521. { read and check header }
  522. if e.size<sizeof(dosheader) then
  523. exit;
  524. blockread(e.f,dosheader,sizeof(tdosheader));
  525. seek(e.f,dosheader.e_lfanew);
  526. blockread(e.f,peheader,sizeof(tpeheader));
  527. if peheader.pemagic<>$4550 then
  528. exit;
  529. e.sechdrofs:=filepos(e.f);
  530. e.nsects:=peheader.NumberOfSections;
  531. e.secstrofs:=peheader.PointerToSymbolTable+peheader.NumberOfSymbols*sizeof(coffsymbol);
  532. if e.secstrofs>e.size then
  533. exit;
  534. e.processaddress:=peheader.ImageBase;
  535. OpenPeCoff:=true;
  536. end;
  537. {$endif PE32}
  538. {$ifdef PE32PLUS}
  539. function OpenPePlusCoff(var e:TExeFile):boolean;
  540. type
  541. tpeheader = packed record
  542. PEMagic : longint;
  543. Machine : word;
  544. NumberOfSections : word;
  545. TimeDateStamp : longint;
  546. PointerToSymbolTable : longint;
  547. NumberOfSymbols : longint;
  548. SizeOfOptionalHeader : word;
  549. Characteristics : word;
  550. Magic : word;
  551. MajorLinkerVersion : byte;
  552. MinorLinkerVersion : byte;
  553. SizeOfCode : longint;
  554. SizeOfInitializedData : longint;
  555. SizeOfUninitializedData : longint;
  556. AddressOfEntryPoint : longint;
  557. BaseOfCode : longint;
  558. ImageBase : qword;
  559. SectionAlignment : longint;
  560. FileAlignment : longint;
  561. MajorOperatingSystemVersion : word;
  562. MinorOperatingSystemVersion : word;
  563. MajorImageVersion : word;
  564. MinorImageVersion : word;
  565. MajorSubsystemVersion : word;
  566. MinorSubsystemVersion : word;
  567. Reserved1 : longint;
  568. SizeOfImage : longint;
  569. SizeOfHeaders : longint;
  570. CheckSum : longint;
  571. Subsystem : word;
  572. DllCharacteristics : word;
  573. SizeOfStackReserve : qword;
  574. SizeOfStackCommit : qword;
  575. SizeOfHeapReserve : qword;
  576. SizeOfHeapCommit : qword;
  577. LoaderFlags : longint;
  578. NumberOfRvaAndSizes : longint;
  579. DataDirectory : array[1..$80] of byte;
  580. end;
  581. var
  582. dosheader : tdosheader;
  583. peheader : tpeheader;
  584. begin
  585. OpenPePlusCoff:=false;
  586. { read and check header }
  587. if E.Size<sizeof(dosheader) then
  588. exit;
  589. blockread(E.F,dosheader,sizeof(tdosheader));
  590. seek(E.F,dosheader.e_lfanew);
  591. blockread(E.F,peheader,sizeof(tpeheader));
  592. if peheader.pemagic<>$4550 then
  593. exit;
  594. e.sechdrofs:=filepos(e.f);
  595. e.nsects:=peheader.NumberOfSections;
  596. e.secstrofs:=peheader.PointerToSymbolTable+peheader.NumberOfSymbols*sizeof(coffsymbol);
  597. if e.secstrofs>e.size then
  598. exit;
  599. e.processaddress:=peheader.ImageBase;
  600. OpenPePlusCoff:=true;
  601. end;
  602. {$endif PE32PLUS}
  603. {****************************************************************************
  604. AOUT
  605. ****************************************************************************}
  606. {$IFDEF EMX}
  607. type
  608. TEmxHeader = packed record
  609. Version: array [1..16] of char;
  610. Bound: word;
  611. AoutOfs: longint;
  612. Options: array [1..42] of char;
  613. end;
  614. TAoutHeader = packed record
  615. Magic: word;
  616. Machine: byte;
  617. Flags: byte;
  618. TextSize: longint;
  619. DataSize: longint;
  620. BssSize: longint;
  621. SymbSize: longint;
  622. EntryPoint: longint;
  623. TextRelocSize: longint;
  624. DataRelocSize: longint;
  625. end;
  626. const
  627. PageSizeFill = $FFF;
  628. var
  629. DosHeader: TDosHeader;
  630. EmxHeader: TEmxHeader;
  631. AoutHeader: TAoutHeader;
  632. StabOfs: PtrUInt;
  633. S4: string [4];
  634. function OpenEMXaout (var E: TExeFile): boolean;
  635. begin
  636. OpenEMXaout := false;
  637. { GDB after 4.18 uses offset to function begin
  638. in text section but OS/2 version still uses 4.16 PM }
  639. E.FunctionRelative := false;
  640. { read and check header }
  641. if E.Size > SizeOf (DosHeader) then
  642. begin
  643. BlockRead (E.F, DosHeader, SizeOf (TDosHeader));
  644. {$IFDEF DEBUG_LINEINFO}
  645. WriteLn (StdErr, 'DosHeader.E_CParHdr = ', DosHeader.E_cParHdr);
  646. {$ENDIF DEBUG_LINEINFO}
  647. if E.Size > DosHeader.e_cparhdr shl 4 + SizeOf (TEmxHeader) then
  648. begin
  649. Seek (E.F, DosHeader.e_cparhdr shl 4);
  650. BlockRead (E.F, EmxHeader, SizeOf (TEmxHeader));
  651. S4 [0] := #4;
  652. Move (EmxHeader.Version, S4 [1], 4);
  653. if (S4 = 'emx ') and
  654. (E.Size > EmxHeader.AoutOfs + SizeOf (TAoutHeader)) then
  655. begin
  656. {$IFDEF DEBUG_LINEINFO}
  657. WriteLn (StdErr, 'EmxHeader.AoutOfs = ', EmxHeader.AoutOfs, '/', HexStr (pointer (EmxHeader.AoutOfs)));
  658. {$ENDIF DEBUG_LINEINFO}
  659. Seek (E.F, EmxHeader.AoutOfs);
  660. BlockRead (E.F, AoutHeader, SizeOf (TAoutHeader));
  661. {$IFDEF DEBUG_LINEINFO}
  662. WriteLn (StdErr, 'AoutHeader.Magic = ', AoutHeader.Magic);
  663. {$ENDIF DEBUG_LINEINFO}
  664. { if AOutHeader.Magic = $10B then}
  665. StabOfs := (EmxHeader.AoutOfs or PageSizeFill) + 1
  666. + AoutHeader.TextSize
  667. + AoutHeader.DataSize
  668. + AoutHeader.TextRelocSize
  669. + AoutHeader.DataRelocSize;
  670. {$IFDEF DEBUG_LINEINFO}
  671. WriteLn (StdErr, 'AoutHeader.TextSize = ', AoutHeader.TextSize, '/', HexStr (pointer (AoutHeader.TextSize)));
  672. WriteLn (StdErr, 'AoutHeader.DataSize = ', AoutHeader.DataSize, '/', HexStr (pointer (AoutHeader.DataSize)));
  673. WriteLn (StdErr, 'AoutHeader.TextRelocSize = ', AoutHeader.TextRelocSize, '/', HexStr (pointer (AoutHeader.TextRelocSize)));
  674. WriteLn (StdErr, 'AoutHeader.DataRelocSize = ', AoutHeader.DataRelocSize, '/', HexStr (pointer (AoutHeader.DataRelocSize)));
  675. WriteLn (StdErr, 'AoutHeader.SymbSize = ', AoutHeader.SymbSize, '/', HexStr (pointer (AoutHeader.SymbSize)));
  676. WriteLn (StdErr, 'StabOfs = ', StabOfs, '/', HexStr (pointer (StabOfs)));
  677. {$ENDIF DEBUG_LINEINFO}
  678. if E.Size > StabOfs + AoutHeader.SymbSize then
  679. OpenEMXaout := true;
  680. end;
  681. end;
  682. end;
  683. end;
  684. function FindSectionEMXaout (var E: TExeFile; const ASecName: string;
  685. var SecOfs, SecLen: longint): boolean;
  686. begin
  687. FindSectionEMXaout := false;
  688. if ASecName = '.stab' then
  689. begin
  690. SecOfs := StabOfs;
  691. SecLen := AoutHeader.SymbSize;
  692. FindSectionEMXaout := true;
  693. end else
  694. if ASecName = '.stabstr' then
  695. begin
  696. SecOfs := StabOfs + AoutHeader.SymbSize;
  697. SecLen := E.Size - Pred (SecOfs);
  698. FindSectionEMXaout := true;
  699. end;
  700. end;
  701. {$ENDIF EMX}
  702. {****************************************************************************
  703. ELF
  704. ****************************************************************************}
  705. {$if defined(ELF32)}
  706. type
  707. telfheader=packed record
  708. magic0123 : longint;
  709. file_class : byte;
  710. data_encoding : byte;
  711. file_version : byte;
  712. padding : array[$07..$0f] of byte;
  713. e_type : word;
  714. e_machine : word;
  715. e_version : longword;
  716. e_entry : longword; // entrypoint
  717. e_phoff : longword; // program header offset
  718. e_shoff : longword; // sections header offset
  719. e_flags : longword;
  720. e_ehsize : word; // elf header size in bytes
  721. e_phentsize : word; // size of an entry in the program header array
  722. e_phnum : word; // 0..e_phnum-1 of entrys
  723. e_shentsize : word; // size of an entry in sections header array
  724. e_shnum : word; // 0..e_shnum-1 of entrys
  725. e_shstrndx : word; // index of string section header
  726. end;
  727. telfsechdr=packed record
  728. sh_name : longword;
  729. sh_type : longword;
  730. sh_flags : longword;
  731. sh_addr : longword;
  732. sh_offset : longword;
  733. sh_size : longword;
  734. sh_link : longword;
  735. sh_info : longword;
  736. sh_addralign : longword;
  737. sh_entsize : longword;
  738. end;
  739. telfproghdr=packed record
  740. p_type : longword;
  741. p_offset : longword;
  742. p_vaddr : longword;
  743. p_paddr : longword;
  744. p_filesz : longword;
  745. p_memsz : longword;
  746. p_flags : longword;
  747. p_align : longword;
  748. end;
  749. {$endif ELF32}
  750. {$ifdef ELF64}
  751. type
  752. telfheader=packed record
  753. magic0123 : longint;
  754. file_class : byte;
  755. data_encoding : byte;
  756. file_version : byte;
  757. padding : array[$07..$0f] of byte;
  758. e_type : word;
  759. e_machine : word;
  760. e_version : longword;
  761. e_entry : int64; // entrypoint
  762. e_phoff : int64; // program header offset
  763. e_shoff : int64; // sections header offset
  764. e_flags : longword;
  765. e_ehsize : word; // elf header size in bytes
  766. e_phentsize : word; // size of an entry in the program header array
  767. e_phnum : word; // 0..e_phnum-1 of entrys
  768. e_shentsize : word; // size of an entry in sections header array
  769. e_shnum : word; // 0..e_shnum-1 of entrys
  770. e_shstrndx : word; // index of string section header
  771. end;
  772. type
  773. telfsechdr=packed record
  774. sh_name : longword;
  775. sh_type : longword;
  776. sh_flags : int64;
  777. sh_addr : int64;
  778. sh_offset : int64;
  779. sh_size : int64;
  780. sh_link : longword;
  781. sh_info : longword;
  782. sh_addralign : int64;
  783. sh_entsize : int64;
  784. end;
  785. telfproghdr=packed record
  786. p_type : longword;
  787. p_flags : longword;
  788. p_offset : qword;
  789. p_vaddr : qword;
  790. p_paddr : qword;
  791. p_filesz : qword;
  792. p_memsz : qword;
  793. p_align : qword;
  794. end;
  795. {$endif ELF64}
  796. {$if defined(ELF32) or defined(ELF64)}
  797. {$ifdef FIND_BASEADDR_ELF}
  798. var
  799. LocalJmpBuf : Jmp_Buf;
  800. procedure LocalError;
  801. begin
  802. Longjmp(LocalJmpBuf,1);
  803. end;
  804. procedure GetExeInMemoryBaseAddr(addr : pointer; var BaseAddr : pointer;
  805. var filename : openstring);
  806. type
  807. AT_HDR = record
  808. typ : ptruint;
  809. value : ptruint;
  810. end;
  811. P_AT_HDR = ^AT_HDR;
  812. { Values taken from /usr/include/linux/auxvec.h }
  813. const
  814. AT_HDR_COUNT = 5;{ AT_PHNUM }
  815. AT_HDR_SIZE = 4; { AT_PHENT }
  816. AT_HDR_Addr = 3; { AT_PHDR }
  817. AT_EXE_FN = 31; {AT_EXECFN }
  818. var
  819. pc : ppchar;
  820. pat_hdr : P_AT_HDR;
  821. i, phdr_count : ptrint;
  822. phdr_size : ptruint;
  823. phdr : ^telfproghdr;
  824. found_addr : ptruint;
  825. SavedExitProc : pointer;
  826. begin
  827. filename:=ParamStr(0);
  828. SavedExitProc:=ExitProc;
  829. ExitProc:=@LocalError;
  830. if SetJmp(LocalJmpBuf)=0 then
  831. begin
  832. { Try, avoided in order to remove exception installation }
  833. pc:=envp;
  834. phdr_count:=-1;
  835. phdr_size:=0;
  836. phdr:=nil;
  837. found_addr:=ptruint(-1);
  838. while (assigned(pc^)) do
  839. inc (pointer(pc), sizeof(ptruint));
  840. inc(pointer(pc), sizeof(ptruint));
  841. pat_hdr:=P_AT_HDR(pc);
  842. while assigned(pat_hdr) do
  843. begin
  844. if (pat_hdr^.typ=0) and (pat_hdr^.value=0) then
  845. break;
  846. if pat_hdr^.typ = AT_HDR_COUNT then
  847. phdr_count:=pat_hdr^.value;
  848. if pat_hdr^.typ = AT_HDR_SIZE then
  849. phdr_size:=pat_hdr^.value;
  850. if pat_hdr^.typ = AT_HDR_Addr then
  851. phdr := pointer(pat_hdr^.value);
  852. if pat_hdr^.typ = AT_EXE_FN then
  853. filename:=strpas(pchar(pat_hdr^.value));
  854. inc (pointer(pat_hdr),sizeof(AT_HDR));
  855. end;
  856. if (phdr_count>0) and (phdr_size = sizeof (telfproghdr))
  857. and assigned(phdr) then
  858. begin
  859. for i:=0 to phdr_count -1 do
  860. begin
  861. if (phdr^.p_type = 1 {PT_LOAD}) and (ptruint(phdr^.p_vaddr) < found_addr) then
  862. found_addr:=phdr^.p_vaddr;
  863. inc(pointer(phdr), phdr_size);
  864. end;
  865. {$ifdef DEBUG_LINEINFO}
  866. end
  867. else
  868. begin
  869. if (phdr_count=-1) then
  870. writeln(stderr,'AUX entry AT_PHNUM not found');
  871. if (phdr_size=0) then
  872. writeln(stderr,'AUX entry AT_PHENT not found');
  873. if (phdr=nil) then
  874. writeln(stderr,'AUX entry AT_PHDR not found');
  875. {$endif DEBUG_LINEINFO}
  876. end;
  877. if found_addr<>ptruint(-1) then
  878. begin
  879. {$ifdef DEBUG_LINEINFO}
  880. Writeln(stderr,'Found addr = $',hexstr(found_addr,2 * sizeof(ptruint)));
  881. {$endif}
  882. BaseAddr:=pointer(found_addr);
  883. end
  884. {$ifdef DEBUG_LINEINFO}
  885. else
  886. writeln(stderr,'Error parsing stack');
  887. {$endif DEBUG_LINEINFO}
  888. end
  889. else
  890. begin
  891. {$ifdef DEBUG_LINEINFO}
  892. writeln(stderr,'Exception parsing stack');
  893. {$endif DEBUG_LINEINFO}
  894. end;
  895. ExitProc:=SavedExitProc;
  896. end;
  897. {$endif FIND_BASEADDR_ELF}
  898. function OpenElf(var e:TExeFile):boolean;
  899. {$ifdef MSDOS}
  900. const
  901. ParagraphSize = 512;
  902. {$endif MSDOS}
  903. var
  904. elfheader : telfheader;
  905. elfsec : telfsechdr;
  906. phdr : telfproghdr;
  907. i : longint;
  908. {$ifdef MSDOS}
  909. DosHeader : tdosheader;
  910. BRead : cardinal;
  911. {$endif MSDOS}
  912. begin
  913. OpenElf:=false;
  914. {$ifdef MSDOS}
  915. { read and check header }
  916. if E.Size < SizeOf (DosHeader) then
  917. Exit;
  918. BlockRead (E.F, DosHeader, SizeOf (DosHeader), BRead);
  919. if BRead <> SizeOf (DosHeader) then
  920. Exit;
  921. if DosHeader.E_Magic = $5A4D then
  922. begin
  923. E.ImgOffset := LongWord(DosHeader.e_cp) * ParagraphSize;
  924. if DosHeader.e_cblp > 0 then
  925. E.ImgOffset := E.ImgOffset + DosHeader.e_cblp - ParagraphSize;
  926. end;
  927. {$endif MSDOS}
  928. { read and check header }
  929. if e.size<(sizeof(telfheader)+e.ImgOffset) then
  930. exit;
  931. seek(e.f,e.ImgOffset);
  932. blockread(e.f,elfheader,sizeof(telfheader));
  933. if elfheader.magic0123<>{$ifdef ENDIAN_LITTLE}$464c457f{$else}$7f454c46{$endif} then
  934. exit;
  935. if elfheader.e_shentsize<>sizeof(telfsechdr) then
  936. exit;
  937. { read section names }
  938. seek(e.f,e.ImgOffset+elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telfsechdr)));
  939. blockread(e.f,elfsec,sizeof(telfsechdr));
  940. e.secstrofs:=elfsec.sh_offset;
  941. e.sechdrofs:=elfheader.e_shoff;
  942. e.nsects:=elfheader.e_shnum;
  943. {$ifdef MSDOS}
  944. { e.processaddress is already initialized to 0 }
  945. e.processsegment:=PrefixSeg+16;
  946. {$else MSDOS}
  947. { scan program headers to find the image base address }
  948. e.processaddress:=High(e.processaddress);
  949. seek(e.f,e.ImgOffset+elfheader.e_phoff);
  950. for i:=1 to elfheader.e_phnum do
  951. begin
  952. blockread(e.f,phdr,sizeof(phdr));
  953. if (phdr.p_type = 1 {PT_LOAD}) and (ptruint(phdr.p_vaddr) < e.processaddress) then
  954. e.processaddress:=phdr.p_vaddr;
  955. end;
  956. if e.processaddress = High(e.processaddress) then
  957. e.processaddress:=0;
  958. {$endif MSDOS}
  959. OpenElf:=true;
  960. end;
  961. function FindSectionElf(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
  962. var
  963. elfsec : telfsechdr;
  964. secname : string;
  965. secnamebuf : array[0..255] of char;
  966. oldofs,
  967. bufsize,i : longint;
  968. begin
  969. FindSectionElf:=false;
  970. seek(e.f,e.ImgOffset+e.sechdrofs);
  971. for i:=1 to e.nsects do
  972. begin
  973. blockread(e.f,elfsec,sizeof(telfsechdr));
  974. fillchar(secnamebuf,sizeof(secnamebuf),0);
  975. oldofs:=filepos(e.f);
  976. seek(e.f,e.ImgOffset+e.secstrofs+elfsec.sh_name);
  977. blockread(e.f,secnamebuf,sizeof(secnamebuf)-1,bufsize);
  978. seek(e.f,oldofs);
  979. secname:=strpas(secnamebuf);
  980. if asecname=secname then
  981. begin
  982. secofs:=e.ImgOffset+elfsec.sh_offset;
  983. seclen:=elfsec.sh_size;
  984. FindSectionElf:=true;
  985. exit;
  986. end;
  987. end;
  988. end;
  989. {$endif ELF32 or ELF64}
  990. {****************************************************************************
  991. MACHO
  992. ****************************************************************************}
  993. {$ifdef darwin}
  994. type
  995. MachoFatHeader= packed record
  996. magic: longint;
  997. nfatarch: longint;
  998. end;
  999. MachoHeader=packed record
  1000. magic: longword;
  1001. cpu_type_t: longint;
  1002. cpu_subtype_t: longint;
  1003. filetype: longint;
  1004. ncmds: longint;
  1005. sizeofcmds: longint;
  1006. flags: longint;
  1007. end;
  1008. cmdblock=packed record
  1009. cmd: longint;
  1010. cmdsize: longint;
  1011. end;
  1012. symbSeg=packed record
  1013. symoff : longint;
  1014. nsyms : longint;
  1015. stroff : longint;
  1016. strsize: longint;
  1017. end;
  1018. tstab=packed record
  1019. strpos : longint;
  1020. ntype : byte;
  1021. nother : byte;
  1022. ndesc : word;
  1023. nvalue : dword;
  1024. end;
  1025. function OpenMachO32PPC(var e:TExeFile):boolean;
  1026. var
  1027. mh:MachoHeader;
  1028. begin
  1029. OpenMachO32PPC:= false;
  1030. E.FunctionRelative:=false;
  1031. if e.size<sizeof(mh) then
  1032. exit;
  1033. blockread (e.f, mh, sizeof(mh));
  1034. e.sechdrofs:=filepos(e.f);
  1035. e.nsects:=mh.ncmds;
  1036. OpenMachO32PPC:=true;
  1037. end;
  1038. function FindSectionMachO32PPC(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
  1039. var
  1040. i: longint;
  1041. block:cmdblock;
  1042. symbolsSeg: symbSeg;
  1043. begin
  1044. FindSectionMachO32PPC:=false;
  1045. seek(e.f,e.sechdrofs);
  1046. for i:= 1 to e.nsects do
  1047. begin
  1048. {$I-}
  1049. blockread (e.f, block, sizeof(block));
  1050. {$I+}
  1051. if IOResult <> 0 then
  1052. Exit;
  1053. if block.cmd = $2 then
  1054. begin
  1055. blockread (e.f, symbolsSeg, sizeof(symbolsSeg));
  1056. if asecname='.stab' then
  1057. begin
  1058. secofs:=symbolsSeg.symoff;
  1059. { the caller will divide again by sizeof(tstab) }
  1060. seclen:=symbolsSeg.nsyms*sizeof(tstab);
  1061. FindSectionMachO32PPC:=true;
  1062. end
  1063. else if asecname='.stabstr' then
  1064. begin
  1065. secofs:=symbolsSeg.stroff;
  1066. seclen:=symbolsSeg.strsize;
  1067. FindSectionMachO32PPC:=true;
  1068. end;
  1069. exit;
  1070. end;
  1071. Seek(e.f, FilePos (e.f) + block.cmdsize - sizeof(block));
  1072. end;
  1073. end;
  1074. {$endif darwin}
  1075. {****************************************************************************
  1076. CRC
  1077. ****************************************************************************}
  1078. var
  1079. Crc32Tbl : array[0..255] of cardinal;
  1080. procedure MakeCRC32Tbl;
  1081. var
  1082. crc : cardinal;
  1083. i,n : integer;
  1084. begin
  1085. for i:=0 to 255 do
  1086. begin
  1087. crc:=i;
  1088. for n:=1 to 8 do
  1089. if (crc and 1)<>0 then
  1090. crc:=(crc shr 1) xor cardinal($edb88320)
  1091. else
  1092. crc:=crc shr 1;
  1093. Crc32Tbl[i]:=crc;
  1094. end;
  1095. end;
  1096. Function UpdateCrc32(InitCrc:cardinal;const InBuf;InLen:LongInt):cardinal;
  1097. var
  1098. i : LongInt;
  1099. p : pchar;
  1100. begin
  1101. if Crc32Tbl[1]=0 then
  1102. MakeCrc32Tbl;
  1103. p:=@InBuf;
  1104. UpdateCrc32:=not InitCrc;
  1105. for i:=1 to InLen do
  1106. begin
  1107. UpdateCrc32:=Crc32Tbl[byte(UpdateCrc32) xor byte(p^)] xor (UpdateCrc32 shr 8);
  1108. inc(p);
  1109. end;
  1110. UpdateCrc32:=not UpdateCrc32;
  1111. end;
  1112. {****************************************************************************
  1113. Generic Executable Open/Close
  1114. ****************************************************************************}
  1115. type
  1116. TOpenProc=function(var e:TExeFile):boolean;
  1117. TFindSectionProc=function(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
  1118. TExeProcRec=record
  1119. openproc : TOpenProc;
  1120. findproc : TFindSectionProc;
  1121. end;
  1122. const
  1123. ExeProcs : TExeProcRec = (
  1124. {$ifdef go32v2}
  1125. openproc : @OpenGo32Coff;
  1126. findproc : @FindSectionCoff;
  1127. {$endif}
  1128. {$ifdef PE32}
  1129. openproc : @OpenPeCoff;
  1130. findproc : @FindSectionCoff;
  1131. {$endif}
  1132. {$ifdef PE32PLUS}
  1133. openproc : @OpenPePlusCoff;
  1134. findproc : @FindSectionCoff;
  1135. {$endif PE32PLUS}
  1136. {$if defined(ELF32) or defined(ELF64)}
  1137. openproc : @OpenElf;
  1138. findproc : @FindSectionElf;
  1139. {$endif ELF32 or ELF64}
  1140. {$ifdef darwin}
  1141. openproc : @OpenMachO32PPC;
  1142. findproc : @FindSectionMachO32PPC;
  1143. {$endif darwin}
  1144. {$IFDEF EMX}
  1145. openproc : @OpenEMXaout;
  1146. findproc : @FindSectionEMXaout;
  1147. {$ENDIF EMX}
  1148. {$ifdef netware}
  1149. openproc : @OpenNetwareNLM;
  1150. findproc : @FindSectionNetwareNLM;
  1151. {$endif}
  1152. );
  1153. function OpenExeFile(var e:TExeFile;const fn:string):boolean;
  1154. var
  1155. ofm : word;
  1156. begin
  1157. OpenExeFile:=false;
  1158. fillchar(e,sizeof(e),0);
  1159. e.bufsize:=sizeof(e.buf);
  1160. e.filename:=fn;
  1161. if fn='' then // we don't want to read stdin
  1162. exit;
  1163. assign(e.f,fn);
  1164. {$I-}
  1165. ofm:=filemode;
  1166. filemode:=$40;
  1167. reset(e.f,1);
  1168. filemode:=ofm;
  1169. {$I+}
  1170. if ioresult<>0 then
  1171. exit;
  1172. e.isopen:=true;
  1173. // cache filesize
  1174. e.size:=filesize(e.f);
  1175. E.FunctionRelative := true;
  1176. E.ImgOffset := 0;
  1177. if ExeProcs.OpenProc<>nil then
  1178. OpenExeFile:=ExeProcs.OpenProc(e);
  1179. end;
  1180. function CloseExeFile(var e:TExeFile):boolean;
  1181. begin
  1182. CloseExeFile:=false;
  1183. if not e.isopen then
  1184. exit;
  1185. e.isopen:=false;
  1186. close(e.f);
  1187. CloseExeFile:=true;
  1188. end;
  1189. function FindExeSection(var e:TExeFile;const secname:string;var secofs,seclen:longint):boolean;
  1190. begin
  1191. FindExeSection:=false;
  1192. if not e.isopen then
  1193. exit;
  1194. if ExeProcs.FindProc<>nil then
  1195. FindExeSection:=ExeProcs.FindProc(e,secname,secofs,seclen);
  1196. end;
  1197. function CheckDbgFile(var e:TExeFile;const fn:string;dbgcrc:cardinal):boolean;
  1198. var
  1199. c : cardinal;
  1200. ofm : word;
  1201. g : file;
  1202. begin
  1203. CheckDbgFile:=false;
  1204. assign(g,fn);
  1205. {$I-}
  1206. ofm:=filemode;
  1207. filemode:=$40;
  1208. reset(g,1);
  1209. filemode:=ofm;
  1210. {$I+}
  1211. if ioresult<>0 then
  1212. exit;
  1213. { We reuse the buffer from e here to prevent too much stack allocation }
  1214. c:=0;
  1215. repeat
  1216. blockread(g,e.buf,e.bufsize,e.bufcnt);
  1217. c:=UpdateCrc32(c,e.buf,e.bufcnt);
  1218. until e.bufcnt<e.bufsize;
  1219. close(g);
  1220. CheckDbgFile:=(dbgcrc=c);
  1221. end;
  1222. function ReadDebugLink(var e:TExeFile;var dbgfn:string):boolean;
  1223. var
  1224. dbglink : array[0..255] of char;
  1225. i,
  1226. dbglinklen,
  1227. dbglinkofs : longint;
  1228. dbgcrc : cardinal;
  1229. begin
  1230. ReadDebugLink:=false;
  1231. if not FindExeSection(e,'.gnu_debuglink',dbglinkofs,dbglinklen) then
  1232. exit;
  1233. if dbglinklen>sizeof(dbglink)-1 then
  1234. exit;
  1235. fillchar(dbglink,sizeof(dbglink),0);
  1236. seek(e.f,dbglinkofs);
  1237. blockread(e.f,dbglink,dbglinklen);
  1238. dbgfn:=strpas(dbglink);
  1239. if length(dbgfn)=0 then
  1240. exit;
  1241. i:=align(length(dbgfn)+1,4);
  1242. if (i+4)>dbglinklen then
  1243. exit;
  1244. move(dbglink[i],dbgcrc,4);
  1245. { current dir }
  1246. if CheckDbgFile(e,dbgfn,dbgcrc) then
  1247. begin
  1248. ReadDebugLink:=true;
  1249. exit;
  1250. end;
  1251. { executable dir }
  1252. i:=length(e.filename);
  1253. while (i>0) and not(e.filename[i] in AllowDirectorySeparators) do
  1254. dec(i);
  1255. if i>0 then
  1256. begin
  1257. dbgfn:=copy(e.filename,1,i)+dbgfn;
  1258. if CheckDbgFile(e,dbgfn,dbgcrc) then
  1259. begin
  1260. ReadDebugLink:=true;
  1261. exit;
  1262. end;
  1263. end;
  1264. end;
  1265. begin
  1266. {$ifdef FIND_BASEADDR_ELF}
  1267. UnixGetModuleByAddrHook:=@GetExeInMemoryBaseAddr;
  1268. {$endif FIND_BASEADDR_ELF}
  1269. end.