exeinfo.pp 35 KB

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