exeinfo.pp 36 KB

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