exeinfo.pp 36 KB

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