exeinfo.pp 37 KB

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