exeinfo.pp 36 KB

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