1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708 |
- {
- 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}
- unit exeinfo;
- 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 : string;
- // Allocate static buffer for reading data
- buf : array[0..4095] of byte;
- bufsize,
- bufcnt : longint;
- end;
- function OpenExeFile(var e:TExeFile;const fn:string):boolean;
- function FindExeSection(var e:TExeFile;const secname:string;var secofs,seclen:longint):boolean;
- function CloseExeFile(var e:TExeFile):boolean;
- function ReadDebugLink(var e:TExeFile;var dbgfn:string):boolean;
- {$ifdef CPUI8086}
- procedure GetModuleByAddr(addr: farpointer; var baseaddr: farpointer; var filename: string);
- {$else CPUI8086}
- procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
- {$endif CPUI8086}
- implementation
- uses
- {$ifdef darwin}
- ctypes, baseunix, dl,
- {$endif}
- strings{$ifdef windows},windows{$endif windows};
- {$if defined(unix) and not defined(beos) and not defined(haiku)}
- procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
- 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 Char;
- {$endif FPC_OS_UNICODE}
- procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
- 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(PChar(@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: string);
- 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: string);
- 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: string);
- 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:=PChar(@info.name);
- end;
- end;
- end;
- {$else}
- {$ifdef CPUI8086}
- procedure GetModuleByAddr(addr: farpointer; var baseaddr: farpointer; var filename: string);
- {$else CPUI8086}
- procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
- {$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) : string;
- var c : char;
- begin
- get0String := '';
- c := char (getbyte(f));
- while (c <> #0) do
- begin
- get0String := get0String + c;
- c := char (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 : string;
- hdrLength,
- dataOffset,
- dataLength : longint;
- function getLString : String;
- var Res:string;
- 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) : string;
- var i : byte;
- begin
- getFixString := '';
- for I := 1 to Len do
- getFixString := getFixString + char (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:string;var secofs,seclen:longint):boolean;
- var name : string;
- 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 char;
- 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 char; { 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:string;var secofs,seclen:longint):boolean;
- var
- i : longint;
- sechdr : tcoffsechdr;
- secname : string;
- secnamebuf : array[0..255] of char;
- 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 char;
- Bound: word;
- AoutOfs: longint;
- Options: array [1..42] of char;
- 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: string;
- 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 : openstring);
- 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 : ppchar;
- 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(pchar(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:string;var secofs,seclen:longint):boolean;
- var
- elfsec : telfsechdr;
- secname : string;
- secnamebuf : array[0..255] of char;
- 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 Char;
- 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 Char;
- segname : array [0..15] of Char;
- 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:string;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: string;
- 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 : pchar;
- 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:string;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:string):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:string;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:string;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:string):boolean;
- var
- dbglink : array[0..255] of char;
- 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:string):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.
|