exeinfo.pp 37 KB

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