exeinfo.pp 37 KB

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