exeinfo.pp 36 KB

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