exeinfo.pp 29 KB

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