exeinfo.pp 37 KB

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