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