exeinfo.pp 36 KB

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