exeinfo.pp 37 KB

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