| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737 | {    This file is part of the Free Pascal run time library.    Copyright (c) 2008 by Peter Vreman    Executable file reading functions    See the file COPYING.FPC, included in this distribution,    for details about the copyright.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************}{  This unit should not be compiled in objfpc mode, since this would make it  dependent on objpas unit.}{ Disable checks of pointers explictly,  as we are dealing here with special pointer that  might be seen as invalid by heaptrc unit CheckPointer function }{$checkpointer off}{$modeswitch out}{$IFNDEF FPC_DOTTEDUNITS}unit exeinfo;{$ENDIF FPC_DOTTEDUNITS}interface{$S-}type  TExeProcessAddress = {$ifdef cpui8086}word{$else}ptruint{$endif};  TExeOffset = {$ifdef cpui8086}longword{$else}ptruint{$endif};  TExeFile=record    f : file;    // cached filesize    size      : int64;    isopen    : boolean;    nsects    : longint;    sechdrofs,    secstrofs : TExeOffset;    processaddress : TExeProcessAddress;{$ifdef cpui8086}    processsegment : word;{$endif cpui8086}{$ifdef darwin}    { total size of all headers }    loadcommandssize: ptruint;{$endif}    FunctionRelative: boolean;    // Offset of the binary image forming permanent offset to all retrieved values    ImgOffset: TExeOffset;    filename  : shortstring;    // Allocate static buffer for reading data    buf       : array[0..4095] of byte;    bufsize,    bufcnt    : longint;  end;function OpenExeFile(var e:TExeFile;const fn:shortstring):boolean;function FindExeSection(var e:TExeFile;const secname:shortstring;var secofs,seclen:longint):boolean;function CloseExeFile(var e:TExeFile):boolean;function ReadDebugLink(var e:TExeFile;var dbgfn:ansistring):boolean; overload;function ReadDebugLink(var e:TExeFile;var dbgfn:shortstring):boolean; overload;{$ifdef CPUI8086}procedure GetModuleByAddr(addr: farpointer; var baseaddr: farpointer; var filename: ansistring);{$else CPUI8086}procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: ansistring);{$endif CPUI8086}implementation{$IFDEF FPC_DOTTEDUNITS}uses{$ifdef darwin}  System.CTypes, UnixApi.Base, UnixApi.Dl,{$endif}{$ifdef Windows}  WinApi.Windows,{$endif Windows}  System.Strings;{$ELSE FPC_DOTTEDUNITS}uses{$ifdef darwin}  ctypes, baseunix, dl,{$endif}  strings{$ifdef windows},windows{$endif windows};{$ENDIF FPC_DOTTEDUNITS}function ReadDebugLink(var e:TExeFile;var dbgfn:shortstring):boolean; var  fn : ansistring;begin  ReadDebugLink:=ReadDebugLink(e,fn);  if ReadDebugLink then    if (length(fn)<256) then      dbgfn:=fn    else      ReadDebugLink:=False;end;{$if defined(unix) and not defined(beos) and not defined(haiku)}  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: ansistring);    begin      if assigned(UnixGetModuleByAddrHook) then        UnixGetModuleByAddrHook(addr,baseaddr,filename)      else        begin          baseaddr:=nil;          filename:=ParamStr(0);        end;    end;{$elseif defined(windows)}  var    Tmm: TMemoryBasicInformation;{$ifdef FPC_OS_UNICODE}    TST: array[0..Max_Path] of WideChar;{$else}    TST: array[0..Max_Path] of AnsiChar;{$endif FPC_OS_UNICODE}  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: ansistring);    begin      baseaddr:=nil;      if VirtualQuery(addr, @Tmm, SizeOf(Tmm))<>sizeof(Tmm) then        filename:=ParamStr(0)      else        begin          baseaddr:=Tmm.AllocationBase;          TST[0]:= #0;          if baseaddr <> nil then            begin              GetModuleFileName(THandle(Tmm.AllocationBase), TST, Length(TST));{$ifdef FPC_OS_UNICODE}              filename:= String(PWideChar(@TST));{$else}              filename:= String(PAnsiChar(@TST));{$endif FPC_OS_UNICODE}            end;        end;    end;{$elseif defined(morphos) or defined(aros) or defined(amigaos4)}  procedure startsymbol; external name '_start';  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: ansistring);    begin      baseaddr:= @startsymbol;{$ifdef FPC_HAS_FEATURE_COMMANDARGS}      filename:=ParamStr(0);{$else FPC_HAS_FEATURE_COMMANDARGS}      filename:='';{$endif FPC_HAS_FEATURE_COMMANDARGS}    end;{$elseif defined(msdos)}  procedure GetModuleByAddr(addr: farpointer; var baseaddr: farpointer; var filename: ansistring);    begin      baseaddr:=Ptr(PrefixSeg+16,0);      filename:=ParamStr(0);    end;{$elseif defined(beos) or defined(haiku)}{$i ptypes.inc}{$i ostypes.inc}  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';  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: ansistring);    const      B_OK = 0;    var      cookie    : longint;      info      : image_info;    begin      filename:='';      baseaddr:=nil;      cookie:=0;      fillchar(info, sizeof(image_info), 0);      while get_next_image_info(0,cookie,info,sizeof(info))=B_OK do        begin          if (info._type = B_APP_IMAGE) and             (addr >= info.text) and (addr <= (info.text + info.text_size)) then            begin              baseaddr:=info.text;              filename:=PAnsiChar(@info.name);            end;        end;    end;{$else}{$ifdef CPUI8086}  procedure GetModuleByAddr(addr: farpointer; var baseaddr: farpointer; var filename: ansistring);{$else CPUI8086}  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: ansistring);{$endif CPUI8086}    begin      baseaddr:= nil;{$ifdef FPC_HAS_FEATURE_COMMANDARGS}      filename:=ParamStr(0);{$else FPC_HAS_FEATURE_COMMANDARGS}      filename:='';{$endif FPC_HAS_FEATURE_COMMANDARGS}    end;{$endif}{****************************************************************************                             Executable Loaders****************************************************************************}{$if defined(freebsd) or defined(netbsd) or defined (openbsd) or defined(linux) or defined(sunos) or defined(android) or defined(dragonfly)}  {$ifdef cpu64}    {$define ELF64}    {$define FIND_BASEADDR_ELF}  {$else}    {$define ELF32}    {$define FIND_BASEADDR_ELF}  {$endif}{$endif}{$if defined(beos) or defined(haiku)}  {$ifdef cpu64}    {$define ELF64}  {$else}    {$define ELF32}  {$endif}{$endif}{$if defined(morphos) or defined(aros) or defined(amigaos4)}  {$ifdef cpu64}    {$define ELF64}  {$else}    {$define ELF32}  {$endif}{$endif}{$if defined(msdos)}  {$define ELF32}{$endif}{$if defined(win32) or defined(wince)}  {$define PE32}{$endif}{$if defined(win64)}  {$define PE32PLUS}{$endif}{$ifdef netwlibc}  {$define netware}{$endif}{$IFDEF OS2}  {$DEFINE EMX}{$ENDIF OS2}{****************************************************************************                              DOS Stub****************************************************************************}{$if defined(EMX) or defined(PE32) or defined(PE32PLUS) or defined(GO32V2) or defined(MSDOS)}type  tdosheader = packed record     e_magic : word;     e_cblp : word;     e_cp : word;     e_crlc : word;     e_cparhdr : word;     e_minalloc : word;     e_maxalloc : word;     e_ss : word;     e_sp : word;     e_csum : word;     e_ip : word;     e_cs : word;     e_lfarlc : word;     e_ovno : word;     e_res : array[0..3] of word;     e_oemid : word;     e_oeminfo : word;     e_res2 : array[0..9] of word;     e_lfanew : longint;  end;{$endif EMX or PE32 or PE32PLUS or GO32v2}{****************************************************************************                                  NLM****************************************************************************}{$ifdef netware}function getByte(var f:file):byte;  begin    BlockRead (f,getByte,1);  end;  procedure Skip (var f:file; bytes : longint);  var i : longint;  begin    for i := 1 to bytes do getbyte(f);  end;  function get0String (var f:file) : shortstring;  var c : AnsiChar;  begin    get0String := '';    c := AnsiChar (getbyte(f));    while (c <> #0) do    begin      get0String := get0String + c;      c := AnsiChar (getbyte(f));    end;  end;  function getint32 (var f:file): longint;  begin    blockread (F, getint32, 4);  end;const SIZE_OF_NLM_INTERNAL_FIXED_HEADER = 130;      SIZE_OF_NLM_INTERNAL_VERSION_HEADER = 32;      SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER = 124;function openNetwareNLM(var e:TExeFile):boolean;var valid : boolean;    name  : shortstring;    hdrLength,    dataOffset,    dataLength : longint;  function getLString : ShortString;  var Res:Shortstring;  begin    blockread (e.F, res, 1);    if length (res) > 0 THEN      blockread (e.F, res[1], length (res));    getbyte(e.f);    getLString := res;  end;  function getFixString (Len : byte) : shortstring;  var i : byte;  begin    getFixString := '';    for I := 1 to Len do      getFixString := getFixString + AnsiChar (getbyte(e.f));  end;  function getword : word;  begin    blockread (e.F, getword, 2);  end;begin  e.sechdrofs := 0;  openNetwareNLM:=false;  // read and check header  Skip (e.f,SIZE_OF_NLM_INTERNAL_FIXED_HEADER);  getLString;  // NLM Description  getInt32(e.f);    // Stacksize  getInt32(e.f);    // Reserved  skip(e.f,5);     // old Thread Name  getLString;  // Screen Name  getLString;  // Thread Name  hdrLength := -1;  dataOffset := -1;  dataLength := -1;  valid := true;  repeat    name := getFixString (8);    if (name = 'VeRsIoN#') then    begin      Skip (e.f,SIZE_OF_NLM_INTERNAL_VERSION_HEADER-8);    end else    if (name = 'CoPyRiGh') then    begin      getword;     // T=      getLString;  // Copyright String    end else    if (name = 'MeSsAgEs') then    begin      skip (e.f,SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER - 8);    end else    if (name = 'CuStHeAd') then    begin      hdrLength := getInt32(e.f);      dataOffset := getInt32(e.f);      dataLength := getInt32(e.f);      Skip (e.f,8); // dateStamp      Valid := false;    end else      Valid := false;  until not valid;  if (hdrLength = -1) or (dataOffset = -1) or (dataLength = -1) then    exit;  Seek (e.F, dataOffset);  e.sechdrofs := dataOffset;  openNetwareNLM := (e.sechdrofs > 0);end;function FindSectionNetwareNLM(var e:TExeFile;const asecname:shortstring;var secofs,seclen:longint):boolean;var name : shortstring;    alignAmount : longint;begin  seek(e.f,e.sechdrofs);    (* The format of the section information is:       null terminated section name       zeroes to adjust to 4 byte boundary       4 byte section data file pointer       4 byte section size *)  Repeat    Name := Get0String(e.f);    alignAmount := 4 - ((length (Name) + 1) MOD 4);    Skip (e.f,AlignAmount);    if (Name = asecname) then    begin      secOfs := getInt32(e.f);      secLen := getInt32(e.f);    end else      Skip(e.f,8);  until (Name = '') or (Name = asecname);  FindSectionNetwareNLM := (Name=asecname);end;{$endif}{****************************************************************************                               COFF****************************************************************************}{$if defined(PE32) or defined(PE32PLUS) or defined(GO32V2)}type  tcoffsechdr=packed record    name     : array[0..7] of ansichar;    vsize    : longint;    rvaofs   : longint;    datalen  : longint;    datapos  : longint;    relocpos : longint;    lineno1  : longint;    nrelocs  : word;    lineno2  : word;    flags    : longint;  end;  coffsymbol=packed record    name    : array[0..3] of ansichar; { real is [0..7], which overlaps the strofs ! }    strofs  : longint;    value   : longint;    section : smallint;    empty   : word;    typ     : byte;    aux     : byte;  end;function FindSectionCoff(var e:TExeFile;const asecname:shortstring;var secofs,seclen:longint):boolean;var  i : longint;  sechdr     : tcoffsechdr;  secname    : shortstring;  secnamebuf : array[0..255] of ansichar;  code,  oldofs,  bufsize    : longint;  strofs     : cardinal;begin  FindSectionCoff:=false;  { read section info }  seek(e.f,e.sechdrofs);  for i:=1 to e.nsects do   begin     blockread(e.f,sechdr,sizeof(sechdr),bufsize);     move(sechdr.name,secnamebuf,8);     secnamebuf[8]:=#0;     secname:=strpas(secnamebuf);     if secname[1]='/' then       begin         Val(Copy(secname,2,8),strofs,code);         if code=0 then           begin             fillchar(secnamebuf,sizeof(secnamebuf),0);             oldofs:=filepos(e.f);             seek(e.f,e.secstrofs+strofs);             blockread(e.f,secnamebuf,sizeof(secnamebuf),bufsize);             seek(e.f,oldofs);             secname:=strpas(secnamebuf);           end         else           secname:='';       end;     if asecname=secname then       begin         secofs:=cardinal(sechdr.datapos) + E.ImgOffset;{$ifdef GO32V2}         seclen:=sechdr.datalen;{$else GO32V2}         { In PECOFF, datalen includes file padding up to the next section.           vsize is the actual payload size if it does not exceed datalen,           otherwise it is .bss (or alike) section that we should ignore.  }         if sechdr.vsize<=sechdr.datalen then           seclen:=sechdr.vsize         else           exit;{$endif GO32V2}         FindSectionCoff:=true;         exit;       end;   end;end;{$endif PE32 or PE32PLUS or GO32V2}{$ifdef go32v2}function OpenGo32Coff(var e:TExeFile):boolean;type  tgo32coffheader=packed record    mach   : word;    nsects : word;    time   : longint;    sympos : longint;    syms   : longint;    opthdr : word;    flag   : word;    other  : array[0..27] of byte;  end;const  ParagraphSize = 512;var  coffheader : tgo32coffheader;  DosHeader: TDosHeader;  BRead: cardinal;begin  OpenGo32Coff:=false;  { read and check header }  if E.Size < SizeOf (DosHeader) then   Exit;  BlockRead (E.F, DosHeader, SizeOf (DosHeader), BRead);  if BRead <> SizeOf (DosHeader) then   Exit;  if DosHeader.E_Magic = $5A4D then  begin   E.ImgOffset := DosHeader.e_cp * ParagraphSize;   if DosHeader.e_cblp > 0 then    E.ImgOffset := E.ImgOffset + DosHeader.e_cblp - ParagraphSize;  end;  if e.size < E.ImgOffset + sizeof(coffheader) then   exit;  seek(e.f,E.ImgOffset);  blockread(e.f,coffheader,sizeof(coffheader));  if coffheader.mach<>$14c then    exit;  e.sechdrofs:=filepos(e.f);  e.nsects:=coffheader.nsects;  e.secstrofs:=coffheader.sympos+coffheader.syms*sizeof(coffsymbol)+4;  if e.secstrofs>e.size then    exit;  OpenGo32Coff:=true;end;{$endif Go32v2}{$ifdef PE32}function OpenPeCoff(var e:TExeFile):boolean;type  tpeheader = packed record     PEMagic : longint;     Machine : word;     NumberOfSections : word;     TimeDateStamp : longint;     PointerToSymbolTable : longint;     NumberOfSymbols : longint;     SizeOfOptionalHeader : word;     Characteristics : word;     Magic : word;     MajorLinkerVersion : byte;     MinorLinkerVersion : byte;     SizeOfCode : longint;     SizeOfInitializedData : longint;     SizeOfUninitializedData : longint;     AddressOfEntryPoint : longint;     BaseOfCode : longint;     BaseOfData : longint;     ImageBase : longint;     SectionAlignment : longint;     FileAlignment : longint;     MajorOperatingSystemVersion : word;     MinorOperatingSystemVersion : word;     MajorImageVersion : word;     MinorImageVersion : word;     MajorSubsystemVersion : word;     MinorSubsystemVersion : word;     Reserved1 : longint;     SizeOfImage : longint;     SizeOfHeaders : longint;     CheckSum : longint;     Subsystem : word;     DllCharacteristics : word;     SizeOfStackReserve : longint;     SizeOfStackCommit : longint;     SizeOfHeapReserve : longint;     SizeOfHeapCommit : longint;     LoaderFlags : longint;     NumberOfRvaAndSizes : longint;     DataDirectory : array[1..$80] of byte;  end;var  dosheader  : tdosheader;  peheader   : tpeheader;begin  OpenPeCoff:=false;  { read and check header }  if e.size<sizeof(dosheader) then    exit;  blockread(e.f,dosheader,sizeof(tdosheader));  seek(e.f,dosheader.e_lfanew);  blockread(e.f,peheader,sizeof(tpeheader));  if peheader.pemagic<>$4550 then    exit;  e.sechdrofs:=filepos(e.f);  e.nsects:=peheader.NumberOfSections;  e.secstrofs:=peheader.PointerToSymbolTable+peheader.NumberOfSymbols*sizeof(coffsymbol);  if e.secstrofs>e.size then    exit;  e.processaddress:=peheader.ImageBase;  OpenPeCoff:=true;end;{$endif PE32}{$ifdef PE32PLUS}function OpenPePlusCoff(var e:TExeFile):boolean;type  tpeheader = packed record     PEMagic : longint;     Machine : word;     NumberOfSections : word;     TimeDateStamp : longint;     PointerToSymbolTable : longint;     NumberOfSymbols : longint;     SizeOfOptionalHeader : word;     Characteristics : word;     Magic : word;     MajorLinkerVersion : byte;     MinorLinkerVersion : byte;     SizeOfCode : longint;     SizeOfInitializedData : longint;     SizeOfUninitializedData : longint;     AddressOfEntryPoint : longint;     BaseOfCode : longint;     ImageBase : qword;     SectionAlignment : longint;     FileAlignment : longint;     MajorOperatingSystemVersion : word;     MinorOperatingSystemVersion : word;     MajorImageVersion : word;     MinorImageVersion : word;     MajorSubsystemVersion : word;     MinorSubsystemVersion : word;     Reserved1 : longint;     SizeOfImage : longint;     SizeOfHeaders : longint;     CheckSum : longint;     Subsystem : word;     DllCharacteristics : word;     SizeOfStackReserve : qword;     SizeOfStackCommit : qword;     SizeOfHeapReserve : qword;     SizeOfHeapCommit : qword;     LoaderFlags : longint;     NumberOfRvaAndSizes : longint;     DataDirectory : array[1..$80] of byte;  end;var  dosheader  : tdosheader;  peheader   : tpeheader;begin  OpenPePlusCoff:=false;  { read and check header }  if E.Size<sizeof(dosheader) then   exit;  blockread(E.F,dosheader,sizeof(tdosheader));  seek(E.F,dosheader.e_lfanew);  blockread(E.F,peheader,sizeof(tpeheader));  if peheader.pemagic<>$4550 then   exit;  e.sechdrofs:=filepos(e.f);  e.nsects:=peheader.NumberOfSections;  e.secstrofs:=peheader.PointerToSymbolTable+peheader.NumberOfSymbols*sizeof(coffsymbol);  if e.secstrofs>e.size then    exit;  e.processaddress:=peheader.ImageBase;  OpenPePlusCoff:=true;end;{$endif PE32PLUS}{****************************************************************************                                 AOUT****************************************************************************}{$IFDEF EMX}type  TEmxHeader = packed record     Version: array [1..16] of AnsiChar;     Bound: word;     AoutOfs: longint;     Options: array [1..42] of AnsiChar;  end;  TAoutHeader = packed record     Magic: word;     Machine: byte;     Flags: byte;     TextSize: longint;     DataSize: longint;     BssSize: longint;     SymbSize: longint;     EntryPoint: longint;     TextRelocSize: longint;     DataRelocSize: longint;  end;const PageSizeFill = $FFF;var DosHeader: TDosHeader; EmxHeader: TEmxHeader; AoutHeader: TAoutHeader; StabOfs: PtrUInt; S4: string [4];function OpenEMXaout (var E: TExeFile): boolean;begin OpenEMXaout := false;{ GDB after 4.18 uses offset to function begin  in text section but OS/2 version still uses 4.16 PM } E.FunctionRelative := false;{ read and check header } if E.Size > SizeOf (DosHeader) then begin  BlockRead (E.F, DosHeader, SizeOf (TDosHeader));{$IFDEF DEBUG_LINEINFO}  WriteLn (StdErr, 'DosHeader.E_CParHdr = ', DosHeader.E_cParHdr);{$ENDIF DEBUG_LINEINFO}  if E.Size > DosHeader.e_cparhdr shl 4 + SizeOf (TEmxHeader) then  begin   Seek (E.F, DosHeader.e_cparhdr shl 4);   BlockRead (E.F, EmxHeader, SizeOf (TEmxHeader));  S4 [0] := #4;  Move (EmxHeader.Version, S4 [1], 4);   if (S4 = 'emx ') and                       (E.Size > EmxHeader.AoutOfs + SizeOf (TAoutHeader)) then   begin{$IFDEF DEBUG_LINEINFO}    WriteLn (StdErr, 'EmxHeader.AoutOfs = ', EmxHeader.AoutOfs, '/', HexStr (pointer (EmxHeader.AoutOfs)));{$ENDIF DEBUG_LINEINFO}    Seek (E.F, EmxHeader.AoutOfs);    BlockRead (E.F, AoutHeader, SizeOf (TAoutHeader));{$IFDEF DEBUG_LINEINFO}    WriteLn (StdErr, 'AoutHeader.Magic = ', AoutHeader.Magic);{$ENDIF DEBUG_LINEINFO}{    if AOutHeader.Magic = $10B then}    StabOfs := (EmxHeader.AoutOfs or PageSizeFill) + 1                 + AoutHeader.TextSize                 + AoutHeader.DataSize                 + AoutHeader.TextRelocSize                 + AoutHeader.DataRelocSize;{$IFDEF DEBUG_LINEINFO}    WriteLn (StdErr, 'AoutHeader.TextSize = ', AoutHeader.TextSize, '/', HexStr (pointer (AoutHeader.TextSize)));    WriteLn (StdErr, 'AoutHeader.DataSize = ', AoutHeader.DataSize, '/', HexStr (pointer (AoutHeader.DataSize)));    WriteLn (StdErr, 'AoutHeader.TextRelocSize = ', AoutHeader.TextRelocSize, '/', HexStr (pointer (AoutHeader.TextRelocSize)));    WriteLn (StdErr, 'AoutHeader.DataRelocSize = ', AoutHeader.DataRelocSize, '/', HexStr (pointer (AoutHeader.DataRelocSize)));    WriteLn (StdErr, 'AoutHeader.SymbSize = ', AoutHeader.SymbSize, '/', HexStr (pointer (AoutHeader.SymbSize)));    WriteLn (StdErr, 'StabOfs = ', StabOfs, '/', HexStr (pointer (StabOfs)));{$ENDIF DEBUG_LINEINFO}    if E.Size > StabOfs + AoutHeader.SymbSize then     OpenEMXaout := true;   end;  end; end;end;function FindSectionEMXaout (var E: TExeFile; const ASecName: shortstring;                                         var SecOfs, SecLen: longint): boolean;begin FindSectionEMXaout := false; if ASecName = '.stab' then begin  SecOfs := StabOfs;  SecLen := AoutHeader.SymbSize;  FindSectionEMXaout := true; end else if ASecName = '.stabstr' then begin  SecOfs := StabOfs + AoutHeader.SymbSize;  SecLen := E.Size - Pred (SecOfs);  FindSectionEMXaout := true; end;end;{$ENDIF EMX}{****************************************************************************                                 ELF****************************************************************************}{$if defined(ELF32)}type  telfheader=packed record      magic0123         : longint;      file_class        : byte;      data_encoding     : byte;      file_version      : byte;      padding           : array[$07..$0f] of byte;      e_type            : word;      e_machine         : word;      e_version         : longword;      e_entry           : longword;                  // entrypoint      e_phoff           : longword;                  // program header offset      e_shoff           : longword;                  // sections header offset      e_flags           : longword;      e_ehsize          : word;             // elf header size in bytes      e_phentsize       : word;             // size of an entry in the program header array      e_phnum           : word;             // 0..e_phnum-1 of entrys      e_shentsize       : word;             // size of an entry in sections header array      e_shnum           : word;             // 0..e_shnum-1 of entrys      e_shstrndx        : word;             // index of string section header  end;  telfsechdr=packed record      sh_name           : longword;      sh_type           : longword;      sh_flags          : longword;      sh_addr           : longword;      sh_offset         : longword;      sh_size           : longword;      sh_link           : longword;      sh_info           : longword;      sh_addralign      : longword;      sh_entsize        : longword;    end;  telfproghdr=packed record    p_type            : longword;    p_offset          : longword;    p_vaddr           : longword;    p_paddr           : longword;    p_filesz          : longword;    p_memsz           : longword;    p_flags           : longword;    p_align           : longword;  end;{$endif ELF32}{$ifdef ELF64}type  telfheader=packed record      magic0123         : longint;      file_class        : byte;      data_encoding     : byte;      file_version      : byte;      padding           : array[$07..$0f] of byte;      e_type            : word;      e_machine         : word;      e_version         : longword;      e_entry           : int64;                  // entrypoint      e_phoff           : int64;                  // program header offset      e_shoff           : int64;                  // sections header offset      e_flags           : longword;      e_ehsize          : word;             // elf header size in bytes      e_phentsize       : word;             // size of an entry in the program header array      e_phnum           : word;             // 0..e_phnum-1 of entrys      e_shentsize       : word;             // size of an entry in sections header array      e_shnum           : word;             // 0..e_shnum-1 of entrys      e_shstrndx        : word;             // index of string section header  end;type  telfsechdr=packed record      sh_name           : longword;      sh_type           : longword;      sh_flags          : int64;      sh_addr           : int64;      sh_offset         : int64;      sh_size           : int64;      sh_link           : longword;      sh_info           : longword;      sh_addralign      : int64;      sh_entsize        : int64;    end;  telfproghdr=packed record    p_type            : longword;    p_flags           : longword;    p_offset          : qword;    p_vaddr           : qword;    p_paddr           : qword;    p_filesz          : qword;    p_memsz           : qword;    p_align           : qword;  end;{$endif ELF64}{$if defined(ELF32) or defined(ELF64)}{$ifdef FIND_BASEADDR_ELF}var  LocalJmpBuf : Jmp_Buf;procedure LocalError;begin  Longjmp(LocalJmpBuf,1);end;procedure GetExeInMemoryBaseAddr(addr : pointer; var BaseAddr : pointer;                                 var filename : ansistring);type  AT_HDR = record    typ : ptruint;    value : ptruint;  end;  P_AT_HDR = ^AT_HDR;{ Values taken from /usr/include/linux/auxvec.h }const  AT_HDR_COUNT = 5;{ AT_PHNUM }  AT_HDR_SIZE = 4; { AT_PHENT }  AT_HDR_Addr = 3; { AT_PHDR }  AT_EXE_FN = 31;  {AT_EXECFN }var  pc : PPAnsiChar;  pat_hdr : P_AT_HDR;  i, phdr_count : ptrint;  phdr_size : ptruint;  phdr :  ^telfproghdr;  found_addr : ptruint;  SavedExitProc : pointer;begin  filename:=ParamStr(0);  SavedExitProc:=ExitProc;  ExitProc:=@LocalError;  if SetJmp(LocalJmpBuf)=0 then  begin  { Try, avoided in order to remove exception installation }    pc:=envp;    phdr_count:=-1;    phdr_size:=0;    phdr:=nil;    found_addr:=ptruint(-1);    while (assigned(pc^)) do      inc (pointer(pc), sizeof(ptruint));    inc(pointer(pc), sizeof(ptruint));    pat_hdr:=P_AT_HDR(pc);    while assigned(pat_hdr) do      begin        if (pat_hdr^.typ=0) and (pat_hdr^.value=0) then          break;        if pat_hdr^.typ = AT_HDR_COUNT then          phdr_count:=pat_hdr^.value;        if pat_hdr^.typ = AT_HDR_SIZE then          phdr_size:=pat_hdr^.value;        if pat_hdr^.typ = AT_HDR_Addr then          phdr := pointer(pat_hdr^.value);        if pat_hdr^.typ = AT_EXE_FN then          filename:=strpas(pansichar(pat_hdr^.value));        inc (pointer(pat_hdr),sizeof(AT_HDR));      end;    if (phdr_count>0) and (phdr_size = sizeof (telfproghdr))       and  assigned(phdr) then      begin        for i:=0 to phdr_count -1 do          begin            if (phdr^.p_type = 1 {PT_LOAD}) and (ptruint(phdr^.p_vaddr) < found_addr) then              found_addr:=phdr^.p_vaddr;            inc(pointer(phdr), phdr_size);          end;      {$ifdef DEBUG_LINEINFO}      end    else      begin        if (phdr_count=-1) then           writeln(stderr,'AUX entry AT_PHNUM not found');        if (phdr_size=0) then           writeln(stderr,'AUX entry AT_PHENT not found');        if (phdr=nil) then           writeln(stderr,'AUX entry AT_PHDR not found');      {$endif DEBUG_LINEINFO}      end;     if found_addr<>ptruint(-1) then       begin          {$ifdef DEBUG_LINEINFO}          Writeln(stderr,'Found addr = $',hexstr(found_addr,2 * sizeof(ptruint)));          {$endif}          BaseAddr:=pointer(found_addr);       end  {$ifdef DEBUG_LINEINFO}     else    writeln(stderr,'Error parsing stack');  {$endif DEBUG_LINEINFO}  end  else  begin  {$ifdef DEBUG_LINEINFO}    writeln(stderr,'Exception parsing stack');  {$endif DEBUG_LINEINFO}  end;  ExitProc:=SavedExitProc;end;{$endif FIND_BASEADDR_ELF}function OpenElf(var e:TExeFile):boolean;{$ifdef MSDOS}const  ParagraphSize = 512;{$endif MSDOS}var  elfheader : telfheader;  elfsec    : telfsechdr;  phdr      : telfproghdr;  i         : longint;{$ifdef MSDOS}  DosHeader : tdosheader;  BRead     : cardinal;{$endif MSDOS}begin  OpenElf:=false;{$ifdef MSDOS}  { read and check header }  if E.Size < SizeOf (DosHeader) then   Exit;  BlockRead (E.F, DosHeader, SizeOf (DosHeader), BRead);  if BRead <> SizeOf (DosHeader) then   Exit;  if DosHeader.E_Magic = $5A4D then  begin   E.ImgOffset := LongWord(DosHeader.e_cp) * ParagraphSize;   if DosHeader.e_cblp > 0 then    E.ImgOffset := E.ImgOffset + DosHeader.e_cblp - ParagraphSize;  end;{$endif MSDOS}  { read and check header }  if e.size<(sizeof(telfheader)+e.ImgOffset) then   exit;  seek(e.f,e.ImgOffset);  blockread(e.f,elfheader,sizeof(telfheader)); if elfheader.magic0123<>{$ifdef ENDIAN_LITTLE}$464c457f{$else}$7f454c46{$endif} then   exit;  if elfheader.e_shentsize<>sizeof(telfsechdr) then   exit;  { read section names }  seek(e.f,e.ImgOffset+elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telfsechdr)));  blockread(e.f,elfsec,sizeof(telfsechdr));  e.secstrofs:=elfsec.sh_offset;  e.sechdrofs:=elfheader.e_shoff;  e.nsects:=elfheader.e_shnum;{$ifdef MSDOS}  { e.processaddress is already initialized to 0 }  e.processsegment:=PrefixSeg+16;{$else MSDOS}  { scan program headers to find the image base address }  e.processaddress:=High(e.processaddress);  seek(e.f,e.ImgOffset+elfheader.e_phoff);  for i:=1 to elfheader.e_phnum do    begin      blockread(e.f,phdr,sizeof(phdr));      if (phdr.p_type = 1 {PT_LOAD}) and (ptruint(phdr.p_vaddr) < e.processaddress) then        e.processaddress:=phdr.p_vaddr;    end;  if e.processaddress = High(e.processaddress) then    e.processaddress:=0;{$endif MSDOS}  OpenElf:=true;end;function FindSectionElf(var e:TExeFile;const asecname:shortstring;var secofs,seclen:longint):boolean;var  elfsec     : telfsechdr;  secname    : string;  secnamebuf : array[0..255] of ansichar;  oldofs,  bufsize,i  : longint;begin  FindSectionElf:=false;  seek(e.f,e.ImgOffset+e.sechdrofs);  for i:=1 to e.nsects do   begin     blockread(e.f,elfsec,sizeof(telfsechdr));     fillchar(secnamebuf,sizeof(secnamebuf),0);     oldofs:=filepos(e.f);     seek(e.f,e.ImgOffset+e.secstrofs+elfsec.sh_name);     blockread(e.f,secnamebuf,sizeof(secnamebuf)-1,bufsize);     seek(e.f,oldofs);     secname:=strpas(secnamebuf);     if asecname=secname then       begin         secofs:=e.ImgOffset+elfsec.sh_offset;         seclen:=elfsec.sh_size;         FindSectionElf:=true;         exit;       end;   end;end;{$endif ELF32 or ELF64}{****************************************************************************                                 MACHO****************************************************************************}{$ifdef darwin}{$push}{$packrecords c}type  tmach_integer = cint;  tmach_cpu_type = tmach_integer;  tmach_cpu_subtype = tmach_integer;  tmach_cpu_threadtype = tmach_integer;  tmach_fat_header=record    magic: cuint32;    nfatarch: cuint32;  end;  tmach_fat_arch=record    cputype: tmach_cpu_type;    cpusubtype: tmach_cpu_subtype;    offset: cuint32;    size: cuint32;    align: cuint32;  end;  pmach_fat_arch = ^tmach_fat_arch;(* not yet supported (only needed for slices or combined slice size > 4GB; unrelated to 64 bit processes)  tmach_fat_arch_64=record    cputype: tmach_cpu_type;    cpusubtype: tmach_cpu_subtype;    offset: cuint64;    size: cuint64;    align: cuint32;    reserved: cuint32;  end;*)  { note: always big endian }  tmach_header=record    magic: cuint32;    cputype: tmach_cpu_type;    cpusubtype: tmach_cpu_subtype;    filetype: cuint32;    ncmds: cuint32;    sizeofcmds: cuint32;    flags: cuint32;    {$IFDEF CPU64}    reserved: cuint32;    {$ENDIF}  end;  pmach_header = ^tmach_header;  tmach_load_command=record    cmd: cuint32;    cmdsize: cuint32;  end;  pmach_load_command=^tmach_load_command;  tmach_symtab_command=record    cmd    :      cuint32;    cmdsize:      cuint32;    symoff :      cuint32;    nsyms  :      cuint32;    stroff :      cuint32;    strsize:      cuint32;  end;  pmach_symtab_command = ^tmach_symtab_command;  tstab=record    strpos  : longword;    ntype   : byte;    nother  : byte;    ndesc   : word;    nvalue  : longword;  end;  pstab = ^tstab;  tmach_vm_prot = cint;  tmach_segment_command = record    cmd     : cuint32;    cmdsize : cuint32;    segname : array [0..15] of AnsiChar;    vmaddr  : {$IFDEF CPU64}cuint64{$ELSE}cuint32{$ENDIF};    vmsize  : {$IFDEF CPU64}cuint64{$ELSE}cuint32{$ENDIF};    fileoff : {$IFDEF CPU64}cuint64{$ELSE}cuint32{$ENDIF};    filesize: {$IFDEF CPU64}cuint64{$ELSE}cuint32{$ENDIF};    maxprot : tmach_vm_prot;    initptot: tmach_vm_prot;    nsects  : cuint32;    flags   : cuint32;  end;  pmach_segment_command = ^tmach_segment_command;  tmach_uuid_command = record    cmd     : cuint32;    cmdsize : cuint32;    uuid    : array[0..15] of cuint8;  end;  pmach_uuid_command = ^tmach_uuid_command;  tmach_section = record    sectname : array [0..15] of AnsiChar;    segname  : array [0..15] of AnsiChar;    addr     : {$IFDEF CPU64}cuint64{$ELSE}cuint32{$ENDIF};    size     : {$IFDEF CPU64}cuint64{$ELSE}cuint32{$ENDIF};    offset   : cuint32;    align    : cuint32;    reloff   : cuint32;    nreloc   : cuint32;    flags    : cuint32;    reserved1: cuint32;    reserved2: cuint32;    {$IFDEF CPU64}    reserved3: cuint32;    {$ENDIF}  end;  pmach_section = ^tmach_section;  tmach_fat_archs = array[1..high(longint) div sizeof(tmach_header)] of tmach_fat_arch;  tmach_fat_header_archs = record    header: tmach_fat_header;    archs: tmach_fat_archs;  end;  pmach_fat_header_archs = ^tmach_fat_header_archs;{$pop}const  MACH_MH_EXECUTE = $02;  MACH_FAT_MAGIC = $cafebabe;// not yet supported: only for binaries with slices > 4GB, or total size > 4GB//  MACH_FAT_MAGIC_64 = $cafebabf;{$ifdef cpu32}  MACH_MAGIC = $feedface;{$else}  MACH_MAGIC = $feedfacf;{$endif}  MACH_CPU_ARCH_MASK = cuint32($ff000000);{$ifdef cpu32}  MACH_LC_SEGMENT = $01;{$else}  MACH_LC_SEGMENT = $19;{$endif}  MACH_LC_SYMTAB  = $02;  MACH_LC_UUID    = $1b;{ the in-memory mapping of the mach header of the main binary }function _NSGetMachExecuteHeader: pmach_header; cdecl; external 'c';function getpagesize: cint; cdecl; external 'c';function MapMachO(const h: THandle; offset, len: SizeUInt; out addr: pointer; out memoffset, mappedsize: SizeUInt): boolean;var  pagesize: cint;begin  pagesize:=getpagesize;  addr:=fpmmap(nil, len+(offset and (pagesize-1)), PROT_READ, MAP_PRIVATE, h, offset and not(pagesize-1));  if addr=MAP_FAILED then    begin      addr:=nil;      memoffset:=0;      mappedsize:=0;    end  else    begin       memoffset:=offset and (pagesize - 1);       mappedsize:=len+(offset and (pagesize-1));    end;end;procedure UnmapMachO(p: pointer; size: SizeUInt);begin  fpmunmap(p,size);end;function OpenMachO(var e:TExeFile):boolean;var  mh         : tmach_header;  processmh  : pmach_header;  cmd: pmach_load_command;  segmentcmd: pmach_segment_command;  mappedexe: pointer;  mappedoffset, mappedsize: SizeUInt;  i: cuint32;  foundpagezero: boolean;begin  OpenMachO:=false;  E.FunctionRelative:=false;  if e.size<sizeof(mh) then    exit;  blockread (e.f, mh, sizeof(mh));  case mh.magic of    MACH_FAT_MAGIC:      begin        { todo }        exit      end;    MACH_MAGIC:      begin        // check that at least the architecture matches (we should also check the subarch,        // but that's harder because of architecture-specific backward compatibility rules)        processmh:=_NSGetMachExecuteHeader;        if (mh.cputype and not(MACH_CPU_ARCH_MASK)) <> (processmh^.cputype and not(MACH_CPU_ARCH_MASK)) then          exit;      end;    else      exit;  end;  e.sechdrofs:=filepos(e.f);  e.nsects:=mh.ncmds;  e.loadcommandssize:=mh.sizeofcmds;  if mh.filetype = MACH_MH_EXECUTE then    begin      foundpagezero:= false;      { make sure to unmap again on all exit paths }      if not MapMachO(filerec(e.f).handle, e.sechdrofs, e.loadcommandssize, mappedexe, mappedoffset, mappedsize) then        exit;      cmd:=pmach_load_command(mappedexe+mappedoffset);      for i:= 1 to e.nsects do        begin          case cmd^.cmd of            MACH_LC_SEGMENT:              begin                segmentcmd:=pmach_segment_command(cmd);                if segmentcmd^.segname='__PAGEZERO' then                  begin                    e.processaddress:=segmentcmd^.vmaddr+segmentcmd^.vmsize;                    OpenMachO:=true;                    break;                  end;              end;          end;          cmd:=pmach_load_command(pointer(cmd)+cmd^.cmdsize);        end;      UnmapMachO(mappedexe, mappedsize);    end  else    OpenMachO:=true;end;function FindSectionMachO(var e:TExeFile;const asecname:shortstring;var secofs,seclen:longint):boolean;var   i, j: cuint32;   cmd: pmach_load_command;   symtabcmd: pmach_symtab_command;   segmentcmd: pmach_segment_command;   section: pmach_section;   mappedexe: pointer;   mappedoffset, mappedsize: SizeUInt;   dwarfsecname: shortstring;begin  FindSectionMachO:=false;  { make sure to unmap again on all exit paths }  if not MapMachO(filerec(e.f).handle, e.sechdrofs, e.loadcommandssize, mappedexe, mappedoffset, mappedsize) then    exit;  cmd:=pmach_load_command(mappedexe+mappedoffset);  for i:= 1 to e.nsects do    begin      case cmd^.cmd of        MACH_LC_SEGMENT:          begin            segmentcmd:=pmach_segment_command(cmd);            if segmentcmd^.segname='__DWARF' then              begin                if asecname[1]='.' then                  dwarfsecname:='__'+copy(asecname,2,length(asecname))                else                  dwarfsecname:=asecname;                section:=pmach_section(pointer(segmentcmd)+sizeof(segmentcmd^));                for j:=1 to segmentcmd^.nsects do                  begin                    if section^.sectname = dwarfsecname then                      begin                        secofs:=section^.offset;                        seclen:=section^.size;                        FindSectionMachO:=true;                        UnmapMachO(mappedexe, mappedsize);                        exit;                      end;                    inc(section);                  end;              end;          end;        MACH_LC_SYMTAB:          begin            symtabcmd:=pmach_symtab_command(cmd);            if asecname='.stab' then              begin                secofs:=symtabcmd^.symoff;                { the caller will divide again by sizeof(tstab) }                seclen:=symtabcmd^.nsyms*sizeof(tstab);                FindSectionMachO:=true;              end            else if asecname='.stabstr' then              begin                secofs:=symtabcmd^.stroff;                seclen:=symtabcmd^.strsize;                FindSectionMachO:=true;              end;            if FindSectionMachO then              begin                UnmapMachO(mappedexe, mappedsize);                exit;              end;          end;      end;      cmd:=pmach_load_command(pointer(cmd)+cmd^.cmdsize);    end;  UnmapMachO(mappedexe, mappedsize);end;{$endif darwin}{****************************************************************************                                   CRC****************************************************************************}var  Crc32Tbl : array[0..255] of cardinal;procedure MakeCRC32Tbl;var  crc : cardinal;  i,n : integer;begin  for i:=0 to 255 do   begin     crc:=i;     for n:=1 to 8 do      if (crc and 1)<>0 then       crc:=(crc shr 1) xor cardinal($edb88320)      else       crc:=crc shr 1;     Crc32Tbl[i]:=crc;   end;end;Function UpdateCrc32(InitCrc:cardinal;const InBuf;InLen:LongInt):cardinal;var  i : LongInt;  p : pansichar;begin  if Crc32Tbl[1]=0 then   MakeCrc32Tbl;  p:=@InBuf;  UpdateCrc32:=not InitCrc;  for i:=1 to InLen do   begin     UpdateCrc32:=Crc32Tbl[byte(UpdateCrc32) xor byte(p^)] xor (UpdateCrc32 shr 8);     inc(p);   end;  UpdateCrc32:=not UpdateCrc32;end;{****************************************************************************                         Generic Executable Open/Close****************************************************************************}type  TOpenProc=function(var e:TExeFile):boolean;  TFindSectionProc=function(var e:TExeFile;const asecname:shortstring;var secofs,seclen:longint):boolean;  TExeProcRec=record    openproc : TOpenProc;    findproc : TFindSectionProc;  end;const  ExeProcs : TExeProcRec = ({$ifdef go32v2}     openproc : @OpenGo32Coff;     findproc : @FindSectionCoff;{$endif}{$ifdef PE32}     openproc : @OpenPeCoff;     findproc : @FindSectionCoff;{$endif}{$ifdef PE32PLUS}     openproc : @OpenPePlusCoff;     findproc : @FindSectionCoff;{$endif PE32PLUS}{$if defined(ELF32) or defined(ELF64)}     openproc : @OpenElf;     findproc : @FindSectionElf;{$endif ELF32 or ELF64}{$ifdef darwin}     openproc : @OpenMachO;     findproc : @FindSectionMachO;{$endif darwin}{$IFDEF EMX}     openproc : @OpenEMXaout;     findproc : @FindSectionEMXaout;{$ENDIF EMX}{$ifdef netware}     openproc : @OpenNetwareNLM;     findproc : @FindSectionNetwareNLM;{$endif}   );function OpenExeFile(var e:TExeFile;const fn:shortstring):boolean;var  ofm : word;begin  OpenExeFile:=false;  fillchar(e,sizeof(e),0);  e.bufsize:=sizeof(e.buf);  e.filename:=fn;  if fn='' then   // we don't want to read stdin    exit;  assign(e.f,fn);  {$I-}   ofm:=filemode;   filemode:=$40;   reset(e.f,1);   filemode:=ofm;  {$I+}  if ioresult<>0 then   exit;  e.isopen:=true;  // cache filesize  e.size:=filesize(e.f);  E.FunctionRelative := true;  E.ImgOffset := 0;  if ExeProcs.OpenProc<>nil then    OpenExeFile:=ExeProcs.OpenProc(e);end;function CloseExeFile(var e:TExeFile):boolean;begin  CloseExeFile:=false;  if not e.isopen then    exit;  e.isopen:=false;  close(e.f);  CloseExeFile:=true;end;function FindExeSection(var e:TExeFile;const secname:shortstring;var secofs,seclen:longint):boolean;begin  FindExeSection:=false;  if not e.isopen then    exit;  if ExeProcs.FindProc<>nil then    FindExeSection:=ExeProcs.FindProc(e,secname,secofs,seclen);end;function CheckDbgFile(var e:TExeFile;const fn:shortstring;dbgcrc:cardinal):boolean;var  c      : cardinal;  ofm    : word;  g      : file;begin  CheckDbgFile:=false;  assign(g,fn);  {$I-}   ofm:=filemode;   filemode:=$40;   reset(g,1);   filemode:=ofm;  {$I+}  if ioresult<>0 then   exit;  { We reuse the buffer from e here to prevent too much stack allocation }  c:=0;  repeat    blockread(g,e.buf,e.bufsize,e.bufcnt);    c:=UpdateCrc32(c,e.buf,e.bufcnt);  until e.bufcnt<e.bufsize;  close(g);  CheckDbgFile:=(dbgcrc=c);end;{$ifndef darwin}function ReadDebugLink(var e:TExeFile;var dbgfn:ansistring):boolean;var  dbglink : array[0..255] of AnsiChar;  i,  dbglinklen,  dbglinkofs : longint;  dbgcrc     : cardinal;begin  ReadDebugLink:=false;  if not FindExeSection(e,'.gnu_debuglink',dbglinkofs,dbglinklen) then    exit;  if dbglinklen>sizeof(dbglink)-1 then    exit;  fillchar(dbglink,sizeof(dbglink),0);  seek(e.f,dbglinkofs);  blockread(e.f,dbglink,dbglinklen);  dbgfn:=strpas(dbglink);  if length(dbgfn)=0 then    exit;  i:=align(length(dbgfn)+1,4);  if (i+4)>dbglinklen then    exit;  move(dbglink[i],dbgcrc,4);  { current dir }  if CheckDbgFile(e,dbgfn,dbgcrc) then    begin      ReadDebugLink:=true;      exit;    end;  { executable dir }  i:=length(e.filename);  while (i>0) and not(e.filename[i] in AllowDirectorySeparators) do    dec(i);  if i>0 then    begin      dbgfn:=copy(e.filename,1,i)+dbgfn;      if CheckDbgFile(e,dbgfn,dbgcrc) then        begin          ReadDebugLink:=true;          exit;        end;    end;end;{$else}function ReadDebugLink(var e:TExeFile;var dbgfn:ansistring):boolean;var   dsymexefile: TExeFile;   execmd, dsymcmd: pmach_load_command;   exeuuidcmd, dsymuuidcmd: pmach_uuid_command;   mappedexe, mappeddsym: pointer;   mappedexeoffset, mappedexesize, mappeddsymoffset, mappeddsymsize: SizeUInt;   i, j: cuint32;   filenamestartpos, b: byte;begin  ReadDebugLink:=false;  if not MapMachO(filerec(e.f).handle, e.sechdrofs, e.loadcommandssize, mappedexe, mappedexeoffset, mappedexesize) then    exit;  execmd:=pmach_load_command(mappedexe+mappedexeoffset);  for i:=1 to e.nsects do    begin      case execmd^.cmd of        MACH_LC_UUID:          begin            exeuuidcmd:=pmach_uuid_command(execmd);            filenamestartpos:=1;            for b:=1 to length(e.filename) do              begin                if e.filename[b] = '/' then                  filenamestartpos:=b+1;              end;            if not OpenExeFile(dsymexefile,e.filename+'.dSYM/Contents/Resources/DWARF/'+copy(e.filename,filenamestartpos,length(e.filename))) then              begin{$IFDEF DEBUG_LINEINFO}                writeln(stderr,'OpenExeFile for ',e.filename+'.dSYM/Contents/Resources/DWARF/'+copy(e.filename,filenamestartpos,length(e.filename)),' did not succeed.');{$endif DEBUG_LINEINFO}                                UnmapMachO(mappedexe, mappedexesize);                exit;              end;            if not MapMachO(filerec(dsymexefile.f).handle, dsymexefile.sechdrofs, dsymexefile.loadcommandssize, mappeddsym, mappeddsymoffset, mappeddsymsize) then              begin                CloseExeFile(dsymexefile);                UnmapMachO(mappedexe, mappedexesize);                exit;              end;            dsymcmd:=pmach_load_command(mappeddsym+mappeddsymoffset);            for j:=1 to dsymexefile.nsects do              begin                case dsymcmd^.cmd of                  MACH_LC_UUID:                    begin                      dsymuuidcmd:=pmach_uuid_command(dsymcmd);                      if comparebyte(exeuuidcmd^.uuid, dsymuuidcmd^.uuid, sizeof(exeuuidcmd^.uuid)) = 0 then                        begin                          dbgfn:=dsymexefile.filename;                          ReadDebugLink:=true;                        end;                      break;                    end;                end;              end;            UnmapMachO(mappeddsym, mappeddsymsize);            CloseExeFile(dsymexefile);            UnmapMachO(mappedexe, mappedexesize);            exit;          end;      end;      execmd:=pmach_load_command(pointer(execmd)+execmd^.cmdsize);    end;  UnmapMachO(mappedexe, mappedexesize);end;{$endif}begin{$ifdef FIND_BASEADDR_ELF}  UnixGetModuleByAddrHook:=@GetExeInMemoryBaseAddr;{$endif FIND_BASEADDR_ELF}end.
 |