exeinfo.pp 36 KB

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