exeinfo.pp 29 KB

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