exeinfo.pp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351
  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. {$ifndef SOLARIS}
  728. { Solaris has envp variable in system unit interface,
  729. so we directly use system envp variable in that case }
  730. var
  731. envp : ppchar external name 'operatingsystem_parameter_envp';
  732. {$endif not SOLARIS}
  733. procedure GetExeInMemoryBaseAddr(addr : pointer; var BaseAddr : pointer;
  734. var filename : openstring);
  735. type
  736. AT_HDR = record
  737. typ : ptruint;
  738. value : ptruint;
  739. end;
  740. P_AT_HDR = ^AT_HDR;
  741. { Values taken from /usr/include/linux/auxvec.h }
  742. const
  743. AT_HDR_COUNT = 5;{ AT_PHNUM }
  744. AT_HDR_SIZE = 4; { AT_PHENT }
  745. AT_HDR_Addr = 3; { AT_PHDR }
  746. AT_EXE_FN = 31; {AT_EXECFN }
  747. var
  748. pc : ppchar;
  749. pat_hdr : P_AT_HDR;
  750. i, phdr_count : ptrint;
  751. phdr_size : ptruint;
  752. phdr : ^telfproghdr;
  753. found_addr : ptruint;
  754. begin
  755. filename:=ParamStr(0);
  756. Try
  757. pc:=envp;
  758. phdr_count:=-1;
  759. phdr_size:=0;
  760. phdr:=nil;
  761. found_addr:=ptruint(-1);
  762. while (assigned(pc^)) do
  763. inc (pointer(pc), sizeof(ptruint));
  764. inc(pointer(pc), sizeof(ptruint));
  765. pat_hdr:=P_AT_HDR(pc);
  766. while assigned(pat_hdr) do
  767. begin
  768. if (pat_hdr^.typ=0) and (pat_hdr^.value=0) then
  769. break;
  770. if pat_hdr^.typ = AT_HDR_COUNT then
  771. phdr_count:=pat_hdr^.value;
  772. if pat_hdr^.typ = AT_HDR_SIZE then
  773. phdr_size:=pat_hdr^.value;
  774. if pat_hdr^.typ = AT_HDR_Addr then
  775. phdr := pointer(pat_hdr^.value);
  776. if pat_hdr^.typ = AT_EXE_FN then
  777. filename:=strpas(pchar(pat_hdr^.value));
  778. inc (pointer(pat_hdr),sizeof(AT_HDR));
  779. end;
  780. if (phdr_count>0) and (phdr_size = sizeof (telfproghdr))
  781. and assigned(phdr) then
  782. begin
  783. for i:=0 to phdr_count -1 do
  784. begin
  785. if (phdr^.p_type = 1 {PT_LOAD}) and (ptruint(phdr^.p_vaddr) < found_addr) then
  786. found_addr:=phdr^.p_vaddr;
  787. inc(pointer(phdr), phdr_size);
  788. end;
  789. {$ifdef DEBUG}
  790. end
  791. else
  792. begin
  793. if (phdr_count=-1) then
  794. writeln(stderr,'AUX entry AT_PHNUM not found');
  795. if (phdr_size=0) then
  796. writeln(stderr,'AUX entry AT_PHENT not found');
  797. if (phdr=nil) then
  798. writeln(stderr,'AUX entry AT_PHDR not found');
  799. {$endif DEBUG}
  800. end;
  801. if found_addr<>ptruint(-1) then
  802. begin
  803. {$ifdef DEBUG}
  804. Writeln(stderr,'Found addr = $',hexstr(found_addr,2 * sizeof(ptruint)));
  805. {$endif}
  806. BaseAddr:=pointer(found_addr);
  807. end
  808. {$ifdef DEBUG}
  809. else
  810. writeln(stderr,'Error parsing stack');
  811. {$endif DEBUG}
  812. except
  813. {$ifdef DEBUG}
  814. writeln(stderr,'Exception parsing stack');
  815. {$endif DEBUG}
  816. end
  817. end;
  818. {$endif FIND_BASEADDR_ELF}
  819. function OpenElf(var e:TExeFile):boolean;
  820. var
  821. elfheader : telfheader;
  822. elfsec : telfsechdr;
  823. phdr : telfproghdr;
  824. i : longint;
  825. begin
  826. OpenElf:=false;
  827. { read and check header }
  828. if e.size<sizeof(telfheader) then
  829. exit;
  830. blockread(e.f,elfheader,sizeof(telfheader));
  831. if elfheader.magic0123<>{$ifdef ENDIAN_LITTLE}$464c457f{$else}$7f454c46{$endif} then
  832. exit;
  833. if elfheader.e_shentsize<>sizeof(telfsechdr) then
  834. exit;
  835. { read section names }
  836. seek(e.f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telfsechdr)));
  837. blockread(e.f,elfsec,sizeof(telfsechdr));
  838. e.secstrofs:=elfsec.sh_offset;
  839. e.sechdrofs:=elfheader.e_shoff;
  840. e.nsects:=elfheader.e_shnum;
  841. { scan program headers to find the image base address }
  842. e.processaddress:=High(e.processaddress);
  843. seek(e.f,elfheader.e_phoff);
  844. for i:=1 to elfheader.e_phnum do
  845. begin
  846. blockread(e.f,phdr,sizeof(phdr));
  847. if (phdr.p_type = 1 {PT_LOAD}) and (ptruint(phdr.p_vaddr) < e.processaddress) then
  848. e.processaddress:=phdr.p_vaddr;
  849. end;
  850. if e.processaddress = High(e.processaddress) then
  851. e.processaddress:=0;
  852. OpenElf:=true;
  853. end;
  854. function FindSectionElf(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
  855. var
  856. elfsec : telfsechdr;
  857. secname : string;
  858. secnamebuf : array[0..255] of char;
  859. oldofs,
  860. bufsize,i : longint;
  861. begin
  862. FindSectionElf:=false;
  863. seek(e.f,e.sechdrofs);
  864. for i:=1 to e.nsects do
  865. begin
  866. blockread(e.f,elfsec,sizeof(telfsechdr));
  867. fillchar(secnamebuf,sizeof(secnamebuf),0);
  868. oldofs:=filepos(e.f);
  869. seek(e.f,e.secstrofs+elfsec.sh_name);
  870. blockread(e.f,secnamebuf,sizeof(secnamebuf)-1,bufsize);
  871. seek(e.f,oldofs);
  872. secname:=strpas(secnamebuf);
  873. if asecname=secname then
  874. begin
  875. secofs:=elfsec.sh_offset;
  876. seclen:=elfsec.sh_size;
  877. FindSectionElf:=true;
  878. exit;
  879. end;
  880. end;
  881. end;
  882. {$endif ELF32 or ELF64 or BEOS}
  883. {$ifdef beos}
  884. {$i ptypes.inc}
  885. type
  886. // Descriptive formats
  887. status_t = Longint;
  888. team_id = Longint;
  889. image_id = Longint;
  890. { image types }
  891. const
  892. B_APP_IMAGE = 1;
  893. B_LIBRARY_IMAGE = 2;
  894. B_ADD_ON_IMAGE = 3;
  895. B_SYSTEM_IMAGE = 4;
  896. B_OK = 0;
  897. type
  898. image_info = packed record
  899. id : image_id;
  900. _type : longint;
  901. sequence: longint;
  902. init_order: longint;
  903. init_routine: pointer;
  904. term_routine: pointer;
  905. device: dev_t;
  906. node: ino_t;
  907. name: array[0..MAXPATHLEN-1] of char;
  908. { name: string[255];
  909. name2: string[255];
  910. name3: string[255];
  911. name4: string[255];
  912. name5: string[5];
  913. }
  914. text: pointer;
  915. data: pointer;
  916. text_size: longint;
  917. data_size: longint;
  918. end;
  919. 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';
  920. function OpenElf32Beos(var e:TExeFile):boolean;
  921. var
  922. cookie : longint;
  923. info : image_info;
  924. begin
  925. // The only BeOS specific part is setting the processaddress
  926. cookie := 0;
  927. OpenElf32Beos:=false;
  928. fillchar(info, sizeof(image_info), 0);
  929. while get_next_image_info(0,cookie,info,sizeof(info))=B_OK do
  930. begin
  931. if e.filename=String(pchar(@info.name)) then
  932. begin
  933. if (info._type = B_APP_IMAGE) then
  934. e.processaddress := cardinal(info.text)
  935. else
  936. e.processaddress := 0;
  937. OpenElf32Beos := OpenElf(e);
  938. exit;
  939. end;
  940. end;
  941. end;
  942. {$endif beos}
  943. {****************************************************************************
  944. MACHO
  945. ****************************************************************************}
  946. {$ifdef darwin}
  947. type
  948. MachoFatHeader= packed record
  949. magic: longint;
  950. nfatarch: longint;
  951. end;
  952. MachoHeader=packed record
  953. magic: longword;
  954. cpu_type_t: longint;
  955. cpu_subtype_t: longint;
  956. filetype: longint;
  957. ncmds: longint;
  958. sizeofcmds: longint;
  959. flags: longint;
  960. end;
  961. cmdblock=packed record
  962. cmd: longint;
  963. cmdsize: longint;
  964. end;
  965. symbSeg=packed record
  966. symoff : longint;
  967. nsyms : longint;
  968. stroff : longint;
  969. strsize: longint;
  970. end;
  971. tstab=packed record
  972. strpos : longint;
  973. ntype : byte;
  974. nother : byte;
  975. ndesc : word;
  976. nvalue : dword;
  977. end;
  978. function OpenMachO32PPC(var e:TExeFile):boolean;
  979. var
  980. mh:MachoHeader;
  981. begin
  982. OpenMachO32PPC:= false;
  983. E.FunctionRelative:=false;
  984. if e.size<sizeof(mh) then
  985. exit;
  986. blockread (e.f, mh, sizeof(mh));
  987. e.sechdrofs:=filepos(e.f);
  988. e.nsects:=mh.ncmds;
  989. OpenMachO32PPC:=true;
  990. end;
  991. function FindSectionMachO32PPC(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
  992. var
  993. i: longint;
  994. block:cmdblock;
  995. symbolsSeg: symbSeg;
  996. begin
  997. FindSectionMachO32PPC:=false;
  998. seek(e.f,e.sechdrofs);
  999. for i:= 1 to e.nsects do
  1000. begin
  1001. {$I-}
  1002. blockread (e.f, block, sizeof(block));
  1003. {$I+}
  1004. if IOResult <> 0 then
  1005. Exit;
  1006. if block.cmd = $2 then
  1007. begin
  1008. blockread (e.f, symbolsSeg, sizeof(symbolsSeg));
  1009. if asecname='.stab' then
  1010. begin
  1011. secofs:=symbolsSeg.symoff;
  1012. { the caller will divide again by sizeof(tstab) }
  1013. seclen:=symbolsSeg.nsyms*sizeof(tstab);
  1014. FindSectionMachO32PPC:=true;
  1015. end
  1016. else if asecname='.stabstr' then
  1017. begin
  1018. secofs:=symbolsSeg.stroff;
  1019. seclen:=symbolsSeg.strsize;
  1020. FindSectionMachO32PPC:=true;
  1021. end;
  1022. exit;
  1023. end;
  1024. Seek(e.f, FilePos (e.f) + block.cmdsize - sizeof(block));
  1025. end;
  1026. end;
  1027. {$endif darwin}
  1028. {****************************************************************************
  1029. CRC
  1030. ****************************************************************************}
  1031. var
  1032. Crc32Tbl : array[0..255] of cardinal;
  1033. procedure MakeCRC32Tbl;
  1034. var
  1035. crc : cardinal;
  1036. i,n : integer;
  1037. begin
  1038. for i:=0 to 255 do
  1039. begin
  1040. crc:=i;
  1041. for n:=1 to 8 do
  1042. if (crc and 1)<>0 then
  1043. crc:=(crc shr 1) xor cardinal($edb88320)
  1044. else
  1045. crc:=crc shr 1;
  1046. Crc32Tbl[i]:=crc;
  1047. end;
  1048. end;
  1049. Function UpdateCrc32(InitCrc:cardinal;const InBuf;InLen:LongInt):cardinal;
  1050. var
  1051. i : LongInt;
  1052. p : pchar;
  1053. begin
  1054. if Crc32Tbl[1]=0 then
  1055. MakeCrc32Tbl;
  1056. p:=@InBuf;
  1057. UpdateCrc32:=not InitCrc;
  1058. for i:=1 to InLen do
  1059. begin
  1060. UpdateCrc32:=Crc32Tbl[byte(UpdateCrc32) xor byte(p^)] xor (UpdateCrc32 shr 8);
  1061. inc(p);
  1062. end;
  1063. UpdateCrc32:=not UpdateCrc32;
  1064. end;
  1065. {****************************************************************************
  1066. Generic Executable Open/Close
  1067. ****************************************************************************}
  1068. type
  1069. TOpenProc=function(var e:TExeFile):boolean;
  1070. TFindSectionProc=function(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
  1071. TExeProcRec=record
  1072. openproc : TOpenProc;
  1073. findproc : TFindSectionProc;
  1074. end;
  1075. const
  1076. ExeProcs : TExeProcRec = (
  1077. {$ifdef go32v2}
  1078. openproc : @OpenGo32Coff;
  1079. findproc : @FindSectionCoff;
  1080. {$endif}
  1081. {$ifdef PE32}
  1082. openproc : @OpenPeCoff;
  1083. findproc : @FindSectionCoff;
  1084. {$endif}
  1085. {$ifdef PE32PLUS}
  1086. openproc : @OpenPePlusCoff;
  1087. findproc : @FindSectionCoff;
  1088. {$endif PE32PLUS}
  1089. {$if defined(ELF32) or defined(ELF64)}
  1090. openproc : @OpenElf;
  1091. findproc : @FindSectionElf;
  1092. {$endif ELF32 or ELF64}
  1093. {$ifdef BEOS}
  1094. openproc : @OpenElf32Beos;
  1095. findproc : @FindSectionElf;
  1096. {$endif BEOS}
  1097. {$ifdef darwin}
  1098. openproc : @OpenMachO32PPC;
  1099. findproc : @FindSectionMachO32PPC;
  1100. {$endif darwin}
  1101. {$IFDEF EMX}
  1102. openproc : @OpenEMXaout;
  1103. findproc : @FindSectionEMXaout;
  1104. {$ENDIF EMX}
  1105. {$ifdef netware}
  1106. openproc : @OpenNetwareNLM;
  1107. findproc : @FindSectionNetwareNLM;
  1108. {$endif}
  1109. );
  1110. function OpenExeFile(var e:TExeFile;const fn:string):boolean;
  1111. var
  1112. ofm : word;
  1113. begin
  1114. OpenExeFile:=false;
  1115. fillchar(e,sizeof(e),0);
  1116. e.bufsize:=sizeof(e.buf);
  1117. e.filename:=fn;
  1118. if fn='' then // we don't want to read stdin
  1119. exit;
  1120. assign(e.f,fn);
  1121. {$I-}
  1122. ofm:=filemode;
  1123. filemode:=$40;
  1124. reset(e.f,1);
  1125. filemode:=ofm;
  1126. {$I+}
  1127. if ioresult<>0 then
  1128. exit;
  1129. e.isopen:=true;
  1130. // cache filesize
  1131. e.size:=filesize(e.f);
  1132. E.FunctionRelative := true;
  1133. E.ImgOffset := 0;
  1134. if ExeProcs.OpenProc<>nil then
  1135. OpenExeFile:=ExeProcs.OpenProc(e);
  1136. end;
  1137. function CloseExeFile(var e:TExeFile):boolean;
  1138. begin
  1139. CloseExeFile:=false;
  1140. if not e.isopen then
  1141. exit;
  1142. e.isopen:=false;
  1143. close(e.f);
  1144. CloseExeFile:=true;
  1145. end;
  1146. function FindExeSection(var e:TExeFile;const secname:string;var secofs,seclen:longint):boolean;
  1147. begin
  1148. FindExeSection:=false;
  1149. if not e.isopen then
  1150. exit;
  1151. if ExeProcs.FindProc<>nil then
  1152. FindExeSection:=ExeProcs.FindProc(e,secname,secofs,seclen);
  1153. end;
  1154. function CheckDbgFile(var e:TExeFile;const fn:string;dbgcrc:cardinal):boolean;
  1155. var
  1156. c : cardinal;
  1157. ofm : word;
  1158. g : file;
  1159. begin
  1160. CheckDbgFile:=false;
  1161. assign(g,fn);
  1162. {$I-}
  1163. ofm:=filemode;
  1164. filemode:=$40;
  1165. reset(g,1);
  1166. filemode:=ofm;
  1167. {$I+}
  1168. if ioresult<>0 then
  1169. exit;
  1170. { We reuse the buffer from e here to prevent too much stack allocation }
  1171. c:=0;
  1172. repeat
  1173. blockread(g,e.buf,e.bufsize,e.bufcnt);
  1174. c:=UpdateCrc32(c,e.buf,e.bufcnt);
  1175. until e.bufcnt<e.bufsize;
  1176. close(g);
  1177. CheckDbgFile:=(dbgcrc=c);
  1178. end;
  1179. function ReadDebugLink(var e:TExeFile;var dbgfn:string):boolean;
  1180. var
  1181. dbglink : array[0..255] of char;
  1182. i,
  1183. dbglinklen,
  1184. dbglinkofs : longint;
  1185. dbgcrc : cardinal;
  1186. begin
  1187. ReadDebugLink:=false;
  1188. if not FindExeSection(e,'.gnu_debuglink',dbglinkofs,dbglinklen) then
  1189. exit;
  1190. if dbglinklen>sizeof(dbglink)-1 then
  1191. exit;
  1192. fillchar(dbglink,sizeof(dbglink),0);
  1193. seek(e.f,dbglinkofs);
  1194. blockread(e.f,dbglink,dbglinklen);
  1195. dbgfn:=strpas(dbglink);
  1196. if length(dbgfn)=0 then
  1197. exit;
  1198. i:=align(length(dbgfn)+1,4);
  1199. if (i+4)>dbglinklen then
  1200. exit;
  1201. move(dbglink[i],dbgcrc,4);
  1202. { current dir }
  1203. if CheckDbgFile(e,dbgfn,dbgcrc) then
  1204. begin
  1205. ReadDebugLink:=true;
  1206. exit;
  1207. end;
  1208. { executable dir }
  1209. i:=length(e.filename);
  1210. while (i>0) and not(e.filename[i] in AllowDirectorySeparators) do
  1211. dec(i);
  1212. if i>0 then
  1213. begin
  1214. dbgfn:=copy(e.filename,1,i)+dbgfn;
  1215. if CheckDbgFile(e,dbgfn,dbgcrc) then
  1216. begin
  1217. ReadDebugLink:=true;
  1218. exit;
  1219. end;
  1220. end;
  1221. end;
  1222. begin
  1223. {$ifdef FIND_BASEADDR_ELF}
  1224. UnixGetModuleByAddrHook:=@GetExeInMemoryBaseAddr;
  1225. {$endif FIND_BASEADDR_ELF}
  1226. end.