aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/libgnat/s-objrea.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/libgnat/s-objrea.adb')
-rw-r--r--gcc/ada/libgnat/s-objrea.adb2246
1 files changed, 2246 insertions, 0 deletions
diff --git a/gcc/ada/libgnat/s-objrea.adb b/gcc/ada/libgnat/s-objrea.adb
new file mode 100644
index 0000000..451abcd
--- /dev/null
+++ b/gcc/ada/libgnat/s-objrea.adb
@@ -0,0 +1,2246 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT COMPILER COMPONENTS --
+-- --
+-- S Y S T E M . O B J E C T _ R E A D E R --
+-- --
+-- B o d y --
+-- --
+-- Copyright (C) 2009-2017, Free Software Foundation, Inc. --
+-- --
+-- GNAT is free software; you can redistribute it and/or modify it under --
+-- terms of the GNU General Public License as published by the Free Soft- --
+-- ware Foundation; either version 3, or (at your option) any later ver- --
+-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE. --
+-- --
+-- As a special exception under Section 7 of GPL version 3, you are granted --
+-- additional permissions described in the GCC Runtime Library Exception, --
+-- version 3.1, as published by the Free Software Foundation. --
+-- --
+-- You should have received a copy of the GNU General Public License and --
+-- a copy of the GCC Runtime Library Exception along with this program; --
+-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
+-- <http://www.gnu.org/licenses/>. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
+-- --
+------------------------------------------------------------------------------
+
+with Ada.Unchecked_Conversion;
+
+with Interfaces.C;
+
+with System.CRTL;
+
+package body System.Object_Reader is
+ use Interfaces;
+ use Interfaces.C;
+ use System.Mmap;
+
+ SSU : constant := System.Storage_Unit;
+
+ function To_int32 is new Ada.Unchecked_Conversion (uint32, int32);
+
+ function Trim_Trailing_Nuls (Str : String) return String;
+ -- Return a copy of a string with any trailing NUL characters truncated
+
+ procedure Check_Read_Offset (S : in out Mapped_Stream; Size : uint32);
+ -- Check that the SIZE bytes at the current offset are still in the stream
+
+ -------------------------------------
+ -- ELF object file format handling --
+ -------------------------------------
+
+ generic
+ type uword is mod <>;
+
+ package ELF_Ops is
+
+ -- ELF version codes
+
+ ELFCLASS32 : constant := 1; -- 32 bit ELF
+ ELFCLASS64 : constant := 2; -- 64 bit ELF
+
+ -- ELF machine codes
+
+ EM_NONE : constant := 0; -- No machine
+ EM_SPARC : constant := 2; -- SUN SPARC
+ EM_386 : constant := 3; -- Intel 80386
+ EM_MIPS : constant := 8; -- MIPS RS3000 Big-Endian
+ EM_MIPS_RS3_LE : constant := 10; -- MIPS RS3000 Little-Endian
+ EM_SPARC32PLUS : constant := 18; -- Sun SPARC 32+
+ EM_PPC : constant := 20; -- PowerPC
+ EM_PPC64 : constant := 21; -- PowerPC 64-bit
+ EM_ARM : constant := 40; -- ARM
+ EM_SPARCV9 : constant := 43; -- SPARC v9 64-bit
+ EM_IA_64 : constant := 50; -- Intel Merced
+ EM_X86_64 : constant := 62; -- AMD x86-64 architecture
+
+ EN_NIDENT : constant := 16;
+
+ type E_Ident_Type is array (0 .. EN_NIDENT - 1) of uint8;
+
+ type Header is record
+ E_Ident : E_Ident_Type; -- Magic number and other info
+ E_Type : uint16; -- Object file type
+ E_Machine : uint16; -- Architecture
+ E_Version : uint32; -- Object file version
+ E_Entry : uword; -- Entry point virtual address
+ E_Phoff : uword; -- Program header table file offset
+ E_Shoff : uword; -- Section header table file offset
+ E_Flags : uint32; -- Processor-specific flags
+ E_Ehsize : uint16; -- ELF header size in bytes
+ E_Phentsize : uint16; -- Program header table entry size
+ E_Phnum : uint16; -- Program header table entry count
+ E_Shentsize : uint16; -- Section header table entry size
+ E_Shnum : uint16; -- Section header table entry count
+ E_Shstrndx : uint16; -- Section header string table index
+ end record;
+
+ type Section_Header is record
+ Sh_Name : uint32; -- Section name string table index
+ Sh_Type : uint32; -- Section type
+ Sh_Flags : uword; -- Section flags
+ Sh_Addr : uword; -- Section virtual addr at execution
+ Sh_Offset : uword; -- Section file offset
+ Sh_Size : uword; -- Section size in bytes
+ Sh_Link : uint32; -- Link to another section
+ Sh_Info : uint32; -- Additional section information
+ Sh_Addralign : uword; -- Section alignment
+ Sh_Entsize : uword; -- Entry size if section holds table
+ end record;
+
+ SHF_ALLOC : constant := 2;
+
+ type Symtab_Entry32 is record
+ St_Name : uint32; -- Name (string table index)
+ St_Value : uint32; -- Value
+ St_Size : uint32; -- Size in bytes
+ St_Info : uint8; -- Type and binding attributes
+ St_Other : uint8; -- Undefined
+ St_Shndx : uint16; -- Defining section
+ end record;
+
+ type Symtab_Entry64 is record
+ St_Name : uint32; -- Name (string table index)
+ St_Info : uint8; -- Type and binding attributes
+ St_Other : uint8; -- Undefined
+ St_Shndx : uint16; -- Defining section
+ St_Value : uint64; -- Value
+ St_Size : uint64; -- Size in bytes
+ end record;
+
+ function Read_Header (F : in out Mapped_Stream) return Header;
+ -- Read a header from an ELF format object
+
+ function First_Symbol
+ (Obj : in out ELF_Object_File) return Object_Symbol;
+ -- Return the first element in the symbol table, or Null_Symbol if the
+ -- symbol table is empty.
+
+ function Read_Symbol
+ (Obj : in out ELF_Object_File;
+ Off : Offset) return Object_Symbol;
+ -- Read a symbol at offset Off
+
+ function Name
+ (Obj : in out ELF_Object_File;
+ Sym : Object_Symbol) return String_Ptr_Len;
+ -- Return the name of the symbol
+
+ function Name
+ (Obj : in out ELF_Object_File;
+ Sec : Object_Section) return String;
+ -- Return the name of a section
+
+ function Get_Section
+ (Obj : in out ELF_Object_File;
+ Shnum : uint32) return Object_Section;
+ -- Fetch a section by index from zero
+
+ function Initialize
+ (F : Mapped_File;
+ Hdr : Header;
+ In_Exception : Boolean) return ELF_Object_File;
+ -- Initialize an object file
+
+ end ELF_Ops;
+
+ -----------------------------------
+ -- PECOFF object format handling --
+ -----------------------------------
+
+ package PECOFF_Ops is
+
+ -- Constants and data layout are taken from the document "Microsoft
+ -- Portable Executable and Common Object File Format Specification"
+ -- Revision 8.1.
+
+ Signature_Loc_Offset : constant := 16#3C#;
+ -- Offset of pointer to the file signature
+
+ Size_Of_Standard_Header_Fields : constant := 16#18#;
+ -- Length in bytes of the standard header record
+
+ Function_Symbol_Type : constant := 16#20#;
+ -- Type field value indicating a symbol refers to a function
+
+ Not_Function_Symbol_Type : constant := 16#00#;
+ -- Type field value indicating a symbol does not refer to a function
+
+ type Magic_Array is array (0 .. 3) of uint8;
+ -- Array of magic numbers from the header
+
+ -- Magic numbers for PECOFF variants
+
+ VARIANT_PE32 : constant := 16#010B#;
+ VARIANT_PE32_PLUS : constant := 16#020B#;
+
+ -- PECOFF machine codes
+
+ IMAGE_FILE_MACHINE_I386 : constant := 16#014C#;
+ IMAGE_FILE_MACHINE_IA64 : constant := 16#0200#;
+ IMAGE_FILE_MACHINE_AMD64 : constant := 16#8664#;
+
+ -- PECOFF Data layout
+
+ type Header is record
+ Magics : Magic_Array;
+ Machine : uint16;
+ NumberOfSections : uint16;
+ TimeDateStamp : uint32;
+ PointerToSymbolTable : uint32;
+ NumberOfSymbols : uint32;
+ SizeOfOptionalHeader : uint16;
+ Characteristics : uint16;
+ Variant : uint16;
+ end record;
+
+ pragma Pack (Header);
+
+ type Optional_Header_PE32 is record
+ Magic : uint16;
+ MajorLinkerVersion : uint8;
+ MinorLinkerVersion : uint8;
+ SizeOfCode : uint32;
+ SizeOfInitializedData : uint32;
+ SizeOfUninitializedData : uint32;
+ AddressOfEntryPoint : uint32;
+ BaseOfCode : uint32;
+ BaseOfData : uint32; -- Note: not in PE32+
+ ImageBase : uint32;
+ SectionAlignment : uint32;
+ FileAlignment : uint32;
+ MajorOperatingSystemVersion : uint16;
+ MinorOperationSystemVersion : uint16;
+ MajorImageVersion : uint16;
+ MinorImageVersion : uint16;
+ MajorSubsystemVersion : uint16;
+ MinorSubsystemVersion : uint16;
+ Win32VersionValue : uint32;
+ SizeOfImage : uint32;
+ SizeOfHeaders : uint32;
+ Checksum : uint32;
+ Subsystem : uint16;
+ DllCharacteristics : uint16;
+ SizeOfStackReserve : uint32;
+ SizeOfStackCommit : uint32;
+ SizeOfHeapReserve : uint32;
+ SizeOfHeapCommit : uint32;
+ LoaderFlags : uint32;
+ NumberOfRvaAndSizes : uint32;
+ end record;
+ pragma Pack (Optional_Header_PE32);
+ pragma Assert (Optional_Header_PE32'Size = 96 * SSU);
+
+ type Optional_Header_PE64 is record
+ Magic : uint16;
+ MajorLinkerVersion : uint8;
+ MinorLinkerVersion : uint8;
+ SizeOfCode : uint32;
+ SizeOfInitializedData : uint32;
+ SizeOfUninitializedData : uint32;
+ AddressOfEntryPoint : uint32;
+ BaseOfCode : uint32;
+ ImageBase : uint64;
+ SectionAlignment : uint32;
+ FileAlignment : uint32;
+ MajorOperatingSystemVersion : uint16;
+ MinorOperationSystemVersion : uint16;
+ MajorImageVersion : uint16;
+ MinorImageVersion : uint16;
+ MajorSubsystemVersion : uint16;
+ MinorSubsystemVersion : uint16;
+ Win32VersionValue : uint32;
+ SizeOfImage : uint32;
+ SizeOfHeaders : uint32;
+ Checksum : uint32;
+ Subsystem : uint16;
+ DllCharacteristics : uint16;
+ SizeOfStackReserve : uint64;
+ SizeOfStackCommit : uint64;
+ SizeOfHeapReserve : uint64;
+ SizeOfHeapCommit : uint64;
+ LoaderFlags : uint32;
+ NumberOfRvaAndSizes : uint32;
+ end record;
+ pragma Pack (Optional_Header_PE64);
+ pragma Assert (Optional_Header_PE64'Size = 112 * SSU);
+
+ subtype Name_Str is String (1 .. 8);
+
+ type Section_Header is record
+ Name : Name_Str;
+ VirtualSize : uint32;
+ VirtualAddress : uint32;
+ SizeOfRawData : uint32;
+ PointerToRawData : uint32;
+ PointerToRelocations : uint32;
+ PointerToLinenumbers : uint32;
+ NumberOfRelocations : uint16;
+ NumberOfLinenumbers : uint16;
+ Characteristics : uint32;
+ end record;
+
+ pragma Pack (Section_Header);
+
+ IMAGE_SCN_CNT_CODE : constant := 16#0020#;
+
+ type Symtab_Entry is record
+ Name : Name_Str;
+ Value : uint32;
+ SectionNumber : int16;
+ TypeField : uint16;
+ StorageClass : uint8;
+ NumberOfAuxSymbols : uint8;
+ end record;
+
+ pragma Pack (Symtab_Entry);
+
+ type Auxent_Section is record
+ Length : uint32;
+ NumberOfRelocations : uint16;
+ NumberOfLinenumbers : uint16;
+ CheckSum : uint32;
+ Number : uint16;
+ Selection : uint8;
+ Unused1 : uint8;
+ Unused2 : uint8;
+ Unused3 : uint8;
+ end record;
+
+ for Auxent_Section'Size use 18 * 8;
+
+ function Read_Header (F : in out Mapped_Stream) return Header;
+ -- Read the object file header
+
+ function First_Symbol
+ (Obj : in out PECOFF_Object_File) return Object_Symbol;
+ -- Return the first element in the symbol table, or Null_Symbol if the
+ -- symbol table is empty.
+
+ function Read_Symbol
+ (Obj : in out PECOFF_Object_File;
+ Off : Offset) return Object_Symbol;
+ -- Read a symbol at offset Off
+
+ function Name
+ (Obj : in out PECOFF_Object_File;
+ Sym : Object_Symbol) return String_Ptr_Len;
+ -- Return the name of the symbol
+
+ function Name
+ (Obj : in out PECOFF_Object_File;
+ Sec : Object_Section) return String;
+ -- Return the name of a section
+
+ function Get_Section
+ (Obj : in out PECOFF_Object_File;
+ Index : uint32) return Object_Section;
+ -- Fetch a section by index from zero
+
+ function Initialize
+ (F : Mapped_File;
+ Hdr : Header;
+ In_Exception : Boolean) return PECOFF_Object_File;
+ -- Initialize an object file
+
+ end PECOFF_Ops;
+
+ -------------------------------------
+ -- XCOFF-32 object format handling --
+ -------------------------------------
+
+ package XCOFF32_Ops is
+
+ -- XCOFF Data layout
+
+ type Header is record
+ f_magic : uint16;
+ f_nscns : uint16;
+ f_timdat : uint32;
+ f_symptr : uint32;
+ f_nsyms : uint32;
+ f_opthdr : uint16;
+ f_flags : uint16;
+ end record;
+
+ type Auxiliary_Header is record
+ o_mflag : uint16;
+ o_vstamp : uint16;
+ o_tsize : uint32;
+ o_dsize : uint32;
+ o_bsize : uint32;
+ o_entry : uint32;
+ o_text_start : uint32;
+ o_data_start : uint32;
+ o_toc : uint32;
+ o_snentry : uint16;
+ o_sntext : uint16;
+ o_sndata : uint16;
+ o_sntoc : uint16;
+ o_snloader : uint16;
+ o_snbss : uint16;
+ o_algntext : uint16;
+ o_algndata : uint16;
+ o_modtype : uint16;
+ o_cpuflag : uint8;
+ o_cputype : uint8;
+ o_maxstack : uint32;
+ o_maxdata : uint32;
+ o_debugger : uint32;
+ o_flags : uint8;
+ o_sntdata : uint16;
+ o_sntbss : uint16;
+ end record;
+ pragma Unreferenced (Auxiliary_Header);
+ -- Not used, but not removed (just in case)
+
+ subtype Name_Str is String (1 .. 8);
+
+ type Section_Header is record
+ s_name : Name_Str;
+ s_paddr : uint32;
+ s_vaddr : uint32;
+ s_size : uint32;
+ s_scnptr : uint32;
+ s_relptr : uint32;
+ s_lnnoptr : uint32;
+ s_nreloc : uint16;
+ s_nlnno : uint16;
+ s_flags : uint32;
+ end record;
+
+ pragma Pack (Section_Header);
+
+ STYP_TEXT : constant := 16#0020#;
+
+ type Symbol_Entry is record
+ n_name : Name_Str;
+ n_value : uint32;
+ n_scnum : uint16;
+ n_type : uint16;
+ n_sclass : uint8;
+ n_numaux : uint8;
+ end record;
+ for Symbol_Entry'Size use 18 * 8;
+
+ type Aux_Entry is record
+ x_scnlen : uint32;
+ x_parmhash : uint32;
+ x_snhash : uint16;
+ x_smtyp : uint8;
+ x_smclass : uint8;
+ x_stab : uint32;
+ x_snstab : uint16;
+ end record;
+ for Aux_Entry'Size use 18 * 8;
+
+ pragma Pack (Aux_Entry);
+
+ C_EXT : constant := 2;
+ C_HIDEXT : constant := 107;
+ C_WEAKEXT : constant := 111;
+
+ XTY_LD : constant := 2;
+ -- Magic constant should be documented, especially since it's changed???
+
+ function Read_Header (F : in out Mapped_Stream) return Header;
+ -- Read the object file header
+
+ function First_Symbol
+ (Obj : in out XCOFF32_Object_File) return Object_Symbol;
+ -- Return the first element in the symbol table, or Null_Symbol if the
+ -- symbol table is empty.
+
+ function Read_Symbol
+ (Obj : in out XCOFF32_Object_File;
+ Off : Offset) return Object_Symbol;
+ -- Read a symbol at offset Off
+
+ function Name
+ (Obj : in out XCOFF32_Object_File;
+ Sym : Object_Symbol) return String_Ptr_Len;
+ -- Return the name of the symbol
+
+ function Name
+ (Obj : in out XCOFF32_Object_File;
+ Sec : Object_Section) return String;
+ -- Return the name of a section
+
+ function Initialize
+ (F : Mapped_File;
+ Hdr : Header;
+ In_Exception : Boolean) return XCOFF32_Object_File;
+ -- Initialize an object file
+
+ function Get_Section
+ (Obj : in out XCOFF32_Object_File;
+ Index : uint32) return Object_Section;
+ -- Fetch a section by index from zero
+
+ end XCOFF32_Ops;
+
+ -------------
+ -- ELF_Ops --
+ -------------
+
+ package body ELF_Ops is
+
+ function Get_String_Table (Obj : in out ELF_Object_File)
+ return Object_Section;
+ -- Fetch the section containing the string table
+
+ function Get_Symbol_Table (Obj : in out ELF_Object_File)
+ return Object_Section;
+ -- Fetch the section containing the symbol table
+
+ function Read_Section_Header
+ (Obj : in out ELF_Object_File;
+ Shnum : uint32) return Section_Header;
+ -- Read the header for an ELF format object section indexed from zero
+
+ ------------------
+ -- First_Symbol --
+ ------------------
+
+ function First_Symbol
+ (Obj : in out ELF_Object_File) return Object_Symbol
+ is
+ begin
+ if Obj.Symtab_Last = 0 then
+ return Null_Symbol;
+ else
+ return Read_Symbol (Obj, 0);
+ end if;
+ end First_Symbol;
+
+ -----------------
+ -- Get_Section --
+ -----------------
+
+ function Get_Section
+ (Obj : in out ELF_Object_File;
+ Shnum : uint32) return Object_Section
+ is
+ SHdr : constant Section_Header := Read_Section_Header (Obj, Shnum);
+ begin
+ return (Shnum,
+ Offset (SHdr.Sh_Offset),
+ uint64 (SHdr.Sh_Addr),
+ uint64 (SHdr.Sh_Size),
+ (SHdr.Sh_Flags and SHF_ALLOC) /= 0);
+ end Get_Section;
+
+ ------------------------
+ -- Get_String_Table --
+ ------------------------
+
+ function Get_String_Table
+ (Obj : in out ELF_Object_File) return Object_Section
+ is
+ begin
+ -- All cases except MIPS IRIX, string table located in .strtab
+
+ if Obj.Arch /= MIPS then
+ return Get_Section (Obj, ".strtab");
+
+ -- On IRIX only .dynstr is available
+
+ else
+ return Get_Section (Obj, ".dynstr");
+ end if;
+ end Get_String_Table;
+
+ ------------------------
+ -- Get_Symbol_Table --
+ ------------------------
+
+ function Get_Symbol_Table
+ (Obj : in out ELF_Object_File) return Object_Section
+ is
+ begin
+ -- All cases except MIPS IRIX, symbol table located in .symtab
+
+ if Obj.Arch /= MIPS then
+ return Get_Section (Obj, ".symtab");
+
+ -- On IRIX, symbol table located somewhere other than .symtab
+
+ else
+ return Get_Section (Obj, ".dynsym");
+ end if;
+ end Get_Symbol_Table;
+
+ ----------------
+ -- Initialize --
+ ----------------
+
+ function Initialize
+ (F : Mapped_File;
+ Hdr : Header;
+ In_Exception : Boolean) return ELF_Object_File
+ is
+ Res : ELF_Object_File
+ (Format => (case uword'Size is
+ when 64 => ELF64,
+ when 32 => ELF32,
+ when others => raise Program_Error));
+ Sec : Object_Section;
+ begin
+ Res.MF := F;
+ Res.In_Exception := In_Exception;
+ Res.Num_Sections := uint32 (Hdr.E_Shnum);
+
+ case Hdr.E_Machine is
+ when EM_SPARC
+ | EM_SPARC32PLUS
+ =>
+ Res.Arch := SPARC;
+
+ when EM_386 =>
+ Res.Arch := i386;
+
+ when EM_MIPS
+ | EM_MIPS_RS3_LE
+ =>
+ Res.Arch := MIPS;
+
+ when EM_PPC =>
+ Res.Arch := PPC;
+
+ when EM_PPC64 =>
+ Res.Arch := PPC64;
+
+ when EM_SPARCV9 =>
+ Res.Arch := SPARC64;
+
+ when EM_IA_64 =>
+ Res.Arch := IA64;
+
+ when EM_X86_64 =>
+ Res.Arch := x86_64;
+
+ when others =>
+ raise Format_Error with "unrecognized architecture";
+ end case;
+
+ -- Map section table and section string table
+ Res.Sectab_Stream := Create_Stream
+ (F, File_Size (Hdr.E_Shoff),
+ File_Size (Hdr.E_Shnum) * File_Size (Hdr.E_Shentsize));
+ Sec := Get_Section (Res, uint32 (Hdr.E_Shstrndx));
+ Res.Secstr_Stream := Create_Stream (Res, Sec);
+
+ -- Map symbol and string table
+ Sec := Get_Symbol_Table (Res);
+ Res.Symtab_Stream := Create_Stream (Res, Sec);
+ Res.Symtab_Last := Offset (Sec.Size);
+
+ Sec := Get_String_Table (Res);
+ Res.Symstr_Stream := Create_Stream (Res, Sec);
+
+ return Res;
+ end Initialize;
+
+ -----------------
+ -- Read_Header --
+ -----------------
+
+ function Read_Header (F : in out Mapped_Stream) return Header is
+ Hdr : Header;
+ begin
+ Seek (F, 0);
+ Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
+ return Hdr;
+ end Read_Header;
+
+ -------------------------
+ -- Read_Section_Header --
+ -------------------------
+
+ function Read_Section_Header
+ (Obj : in out ELF_Object_File;
+ Shnum : uint32) return Section_Header
+ is
+ Shdr : Section_Header;
+ begin
+ Seek (Obj.Sectab_Stream, Offset (Shnum * Section_Header'Size / SSU));
+ Read_Raw (Obj.Sectab_Stream, Shdr'Address, Section_Header'Size / SSU);
+ return Shdr;
+ end Read_Section_Header;
+
+ -----------------
+ -- Read_Symbol --
+ -----------------
+
+ function Read_Symbol
+ (Obj : in out ELF_Object_File;
+ Off : Offset) return Object_Symbol
+ is
+ ST_Entry32 : Symtab_Entry32;
+ ST_Entry64 : Symtab_Entry64;
+ Res : Object_Symbol;
+
+ begin
+ Seek (Obj.Symtab_Stream, Off);
+
+ case uword'Size is
+ when 32 =>
+ Read_Raw (Obj.Symtab_Stream, ST_Entry32'Address,
+ uint32 (ST_Entry32'Size / SSU));
+ Res := (Off,
+ Off + ST_Entry32'Size / SSU,
+ uint64 (ST_Entry32.St_Value),
+ uint64 (ST_Entry32.St_Size));
+
+ when 64 =>
+ Read_Raw (Obj.Symtab_Stream, ST_Entry64'Address,
+ uint32 (ST_Entry64'Size / SSU));
+ Res := (Off,
+ Off + ST_Entry64'Size / SSU,
+ ST_Entry64.St_Value,
+ ST_Entry64.St_Size);
+
+ when others =>
+ raise Program_Error;
+ end case;
+
+ return Res;
+ end Read_Symbol;
+
+ ----------
+ -- Name --
+ ----------
+
+ function Name
+ (Obj : in out ELF_Object_File;
+ Sec : Object_Section) return String
+ is
+ SHdr : Section_Header;
+ begin
+ SHdr := Read_Section_Header (Obj, Sec.Num);
+ return Offset_To_String (Obj.Secstr_Stream, Offset (SHdr.Sh_Name));
+ end Name;
+
+ function Name
+ (Obj : in out ELF_Object_File;
+ Sym : Object_Symbol) return String_Ptr_Len
+ is
+ ST_Entry32 : Symtab_Entry32;
+ ST_Entry64 : Symtab_Entry64;
+ Name_Off : Offset;
+
+ begin
+ -- Test that this symbol is not null
+
+ if Sym = Null_Symbol then
+ return (null, 0);
+ end if;
+
+ -- Read the symbol table entry
+
+ Seek (Obj.Symtab_Stream, Sym.Off);
+
+ case uword'Size is
+ when 32 =>
+ Read_Raw (Obj.Symtab_Stream, ST_Entry32'Address,
+ uint32 (ST_Entry32'Size / SSU));
+ Name_Off := Offset (ST_Entry32.St_Name);
+
+ when 64 =>
+ Read_Raw (Obj.Symtab_Stream, ST_Entry64'Address,
+ uint32 (ST_Entry64'Size / SSU));
+ Name_Off := Offset (ST_Entry64.St_Name);
+
+ when others =>
+ raise Program_Error;
+ end case;
+
+ -- Fetch the name from the string table
+
+ Seek (Obj.Symstr_Stream, Name_Off);
+ return Read (Obj.Symstr_Stream);
+ end Name;
+
+ end ELF_Ops;
+
+ package ELF32_Ops is new ELF_Ops (uint32);
+ package ELF64_Ops is new ELF_Ops (uint64);
+
+ ----------------
+ -- PECOFF_Ops --
+ ----------------
+
+ package body PECOFF_Ops is
+
+ function Decode_Name
+ (Obj : in out PECOFF_Object_File;
+ Raw_Name : String) return String;
+ -- A section name is an 8 byte field padded on the right with null
+ -- characters, or a '\' followed by an ASCII decimal string indicating
+ -- an offset in to the string table. This routine decodes this
+
+ function Get_Section_Virtual_Address
+ (Obj : in out PECOFF_Object_File;
+ Index : uint32) return uint64;
+ -- Fetch the address at which a section is loaded
+
+ function Read_Section_Header
+ (Obj : in out PECOFF_Object_File;
+ Index : uint32) return Section_Header;
+ -- Read a header from section table
+
+ function String_Table
+ (Obj : in out PECOFF_Object_File;
+ Index : Offset) return String;
+ -- Return an entry from the string table
+
+ -----------------
+ -- Decode_Name --
+ -----------------
+
+ function Decode_Name
+ (Obj : in out PECOFF_Object_File;
+ Raw_Name : String) return String
+ is
+ Name_Or_Ref : constant String := Trim_Trailing_Nuls (Raw_Name);
+ Off : Offset;
+
+ begin
+ -- We should never find a symbol with a zero length name. If we do it
+ -- probably means we are not parsing the symbol table correctly. If
+ -- this happens we raise a fatal error.
+
+ if Name_Or_Ref'Length = 0 then
+ raise Format_Error with
+ "found zero length symbol in symbol table";
+ end if;
+
+ if Name_Or_Ref (1) /= '/' then
+ return Name_Or_Ref;
+ else
+ Off := Offset'Value (Name_Or_Ref (2 .. Name_Or_Ref'Last));
+ return String_Table (Obj, Off);
+ end if;
+ end Decode_Name;
+
+ ------------------
+ -- First_Symbol --
+ ------------------
+
+ function First_Symbol
+ (Obj : in out PECOFF_Object_File) return Object_Symbol is
+ begin
+ -- Return Null_Symbol in the case that the symbol table is empty
+
+ if Obj.Symtab_Last = 0 then
+ return Null_Symbol;
+ end if;
+
+ return Read_Symbol (Obj, 0);
+ end First_Symbol;
+
+ -----------------
+ -- Get_Section --
+ -----------------
+
+ function Get_Section
+ (Obj : in out PECOFF_Object_File;
+ Index : uint32) return Object_Section
+ is
+ Sec : constant Section_Header := Read_Section_Header (Obj, Index);
+ begin
+ -- Use VirtualSize instead of SizeOfRawData. The latter is rounded to
+ -- the page size, so it may add garbage to the content. On the other
+ -- side, the former may be larger than the latter in case of 0
+ -- padding.
+
+ return (Index,
+ Offset (Sec.PointerToRawData),
+ uint64 (Sec.VirtualAddress) + Obj.ImageBase,
+ uint64 (Sec.VirtualSize),
+ (Sec.Characteristics and IMAGE_SCN_CNT_CODE) /= 0);
+ end Get_Section;
+
+ ---------------------------------
+ -- Get_Section_Virtual_Address --
+ ---------------------------------
+
+ function Get_Section_Virtual_Address
+ (Obj : in out PECOFF_Object_File;
+ Index : uint32) return uint64
+ is
+ Sec : Section_Header;
+
+ begin
+ -- Try cache
+
+ if Index = Obj.GSVA_Sec then
+ return Obj.GSVA_Addr;
+ end if;
+
+ Obj.GSVA_Sec := Index;
+ Sec := Read_Section_Header (Obj, Index);
+ Obj.GSVA_Addr := Obj.ImageBase + uint64 (Sec.VirtualAddress);
+ return Obj.GSVA_Addr;
+ end Get_Section_Virtual_Address;
+
+ ----------------
+ -- Initialize --
+ ----------------
+
+ function Initialize
+ (F : Mapped_File;
+ Hdr : Header;
+ In_Exception : Boolean) return PECOFF_Object_File
+ is
+ Res : PECOFF_Object_File
+ (Format => (case Hdr.Variant is
+ when PECOFF_Ops.VARIANT_PE32 => PECOFF,
+ when PECOFF_Ops.VARIANT_PE32_PLUS => PECOFF_PLUS,
+ when others => raise Program_Error
+ with "unrecognized PECOFF variant"));
+ Symtab_Size : constant Offset :=
+ Offset (Hdr.NumberOfSymbols) * (Symtab_Entry'Size / SSU);
+ Strtab_Size : uint32;
+ Hdr_Offset : Offset;
+ Opt_Offset : File_Size;
+ Opt_Stream : Mapped_Stream;
+ begin
+ Res.MF := F;
+ Res.In_Exception := In_Exception;
+
+ case Hdr.Machine is
+ when PECOFF_Ops.IMAGE_FILE_MACHINE_I386 =>
+ Res.Arch := i386;
+ when PECOFF_Ops.IMAGE_FILE_MACHINE_IA64 =>
+ Res.Arch := IA64;
+ when PECOFF_Ops.IMAGE_FILE_MACHINE_AMD64 =>
+ Res.Arch := x86_64;
+ when others =>
+ raise Format_Error with "unrecognized architecture";
+ end case;
+
+ Res.Num_Sections := uint32 (Hdr.NumberOfSections);
+
+ -- Map symbol table and the first following word (which is the length
+ -- of the string table).
+
+ Res.Symtab_Last := Symtab_Size;
+ Res.Symtab_Stream := Create_Stream
+ (F,
+ File_Size (Hdr.PointerToSymbolTable),
+ File_Size (Symtab_Size + 4));
+
+ -- Map string table. The first 4 bytes are the length of the string
+ -- table and are part of it.
+
+ Seek (Res.Symtab_Stream, Symtab_Size);
+ Strtab_Size := Read (Res.Symtab_Stream);
+ Res.Symstr_Stream := Create_Stream
+ (F,
+ File_Size (Hdr.PointerToSymbolTable) + File_Size (Symtab_Size),
+ File_Size (Strtab_Size));
+
+ -- Map section table
+
+ Opt_Stream := Create_Stream (Res.Mf, Signature_Loc_Offset, 4);
+ Hdr_Offset := Offset (uint32'(Read (Opt_Stream)));
+ Close (Opt_Stream);
+ Res.Sectab_Stream := Create_Stream
+ (F,
+ File_Size (Hdr_Offset +
+ Size_Of_Standard_Header_Fields +
+ Offset (Hdr.SizeOfOptionalHeader)),
+ File_Size (Res.Num_Sections)
+ * File_Size (Section_Header'Size / SSU));
+
+ -- Read optional header and extract image base
+
+ Opt_Offset := File_Size (Hdr_Offset + Size_Of_Standard_Header_Fields);
+
+ if Res.Format = PECOFF then
+ declare
+ Opt_32 : Optional_Header_PE32;
+ begin
+ Opt_Stream := Create_Stream
+ (Res.Mf, Opt_Offset, Opt_32'Size / SSU);
+ Read_Raw
+ (Opt_Stream, Opt_32'Address, uint32 (Opt_32'Size / SSU));
+ Res.ImageBase := uint64 (Opt_32.ImageBase);
+ Close (Opt_Stream);
+ end;
+
+ else
+ declare
+ Opt_64 : Optional_Header_PE64;
+ begin
+ Opt_Stream := Create_Stream
+ (Res.Mf, Opt_Offset, Opt_64'Size / SSU);
+ Read_Raw
+ (Opt_Stream, Opt_64'Address, uint32 (Opt_64'Size / SSU));
+ Res.ImageBase := Opt_64.ImageBase;
+ Close (Opt_Stream);
+ end;
+ end if;
+
+ return Res;
+ end Initialize;
+
+ -----------------
+ -- Read_Symbol --
+ -----------------
+
+ function Read_Symbol
+ (Obj : in out PECOFF_Object_File;
+ Off : Offset) return Object_Symbol
+ is
+ ST_Entry : Symtab_Entry;
+ ST_Last : Symtab_Entry;
+ Aux_Entry : Auxent_Section;
+ Sz : constant Offset := ST_Entry'Size / SSU;
+ Result : Object_Symbol;
+ Noff : Offset;
+ Sym_Off : Offset;
+
+ begin
+ -- Seek to the successor of Prev
+
+ Noff := Off;
+
+ loop
+ Sym_Off := Noff;
+
+ Seek (Obj.Symtab_Stream, Sym_Off);
+ Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, uint32 (Sz));
+
+ -- Skip AUX entries
+
+ Noff := Noff + Offset (1 + ST_Entry.NumberOfAuxSymbols) * Sz;
+
+ exit when ST_Entry.TypeField = Function_Symbol_Type
+ and then ST_Entry.SectionNumber > 0;
+
+ if Noff >= Obj.Symtab_Last then
+ return Null_Symbol;
+ end if;
+ end loop;
+
+ -- Construct the symbol
+
+ Result :=
+ (Off => Sym_Off,
+ Next => Noff,
+ Value => uint64 (ST_Entry.Value),
+ Size => 0);
+
+ -- Set the size as accurately as possible
+
+ -- The size of a symbol is not directly available so we try scanning
+ -- to the next function and assuming the code ends there.
+
+ loop
+ -- Read symbol and AUX entries
+
+ Sym_Off := Noff;
+ Seek (Obj.Symtab_Stream, Sym_Off);
+ Read_Raw (Obj.Symtab_Stream, ST_Last'Address, uint32 (Sz));
+
+ for I in 1 .. ST_Last.NumberOfAuxSymbols loop
+ Read_Raw (Obj.Symtab_Stream, Aux_Entry'Address, uint32 (Sz));
+ end loop;
+
+ Noff := Noff + Offset (1 + ST_Last.NumberOfAuxSymbols) * Sz;
+
+ if ST_Last.TypeField = Function_Symbol_Type then
+ if ST_Last.SectionNumber = ST_Entry.SectionNumber
+ and then ST_Last.Value >= ST_Entry.Value
+ then
+ -- Symbol is a function past ST_Entry
+
+ Result.Size := uint64 (ST_Last.Value - ST_Entry.Value);
+
+ else
+ -- Not correlated function
+
+ Result.Next := Sym_Off;
+ end if;
+
+ exit;
+
+ elsif ST_Last.SectionNumber = ST_Entry.SectionNumber
+ and then ST_Last.TypeField = Not_Function_Symbol_Type
+ and then ST_Last.StorageClass = 3
+ and then ST_Last.NumberOfAuxSymbols = 1
+ then
+ -- Symbol is a section
+
+ Result.Size := uint64 (ST_Last.Value + Aux_Entry.Length
+ - ST_Entry.Value);
+ Result.Next := Noff;
+ exit;
+ end if;
+
+ exit when Noff >= Obj.Symtab_Last;
+ end loop;
+
+ -- Relocate the address
+
+ Result.Value :=
+ Result.Value + Get_Section_Virtual_Address
+ (Obj, uint32 (ST_Entry.SectionNumber - 1));
+
+ return Result;
+ end Read_Symbol;
+
+ ------------------
+ -- Read_Header --
+ ------------------
+
+ function Read_Header (F : in out Mapped_Stream) return Header is
+ Hdr : Header;
+ Off : int32;
+
+ begin
+ -- Skip the MSDOS stub, and seek directly to the file offset
+
+ Seek (F, Signature_Loc_Offset);
+ Off := Read (F);
+
+ -- Read the COFF file header
+
+ Seek (F, Offset (Off));
+ Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
+ return Hdr;
+ end Read_Header;
+
+ -------------------------
+ -- Read_Section_Header --
+ -------------------------
+
+ function Read_Section_Header
+ (Obj : in out PECOFF_Object_File;
+ Index : uint32) return Section_Header
+ is
+ Sec : Section_Header;
+ begin
+ Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
+ Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
+ return Sec;
+ end Read_Section_Header;
+
+ ----------
+ -- Name --
+ ----------
+
+ function Name
+ (Obj : in out PECOFF_Object_File;
+ Sec : Object_Section) return String
+ is
+ Shdr : constant Section_Header := Read_Section_Header (Obj, Sec.Num);
+ begin
+ return Decode_Name (Obj, Shdr.Name);
+ end Name;
+
+ -------------------
+ -- String_Table --
+ -------------------
+
+ function String_Table
+ (Obj : in out PECOFF_Object_File;
+ Index : Offset) return String is
+ begin
+ -- An index of zero is used to represent an empty string, as the
+ -- first word of the string table is specified to contain the length
+ -- of the table rather than its contents.
+
+ if Index = 0 then
+ return "";
+
+ else
+ return Offset_To_String (Obj.Symstr_Stream, Index);
+ end if;
+ end String_Table;
+
+ ----------
+ -- Name --
+ ----------
+
+ function Name
+ (Obj : in out PECOFF_Object_File;
+ Sym : Object_Symbol) return String_Ptr_Len
+ is
+ ST_Entry : Symtab_Entry;
+
+ begin
+ Seek (Obj.Symtab_Stream, Sym.Off);
+ Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, ST_Entry'Size / SSU);
+
+ declare
+ -- Symbol table entries are packed and Table_Entry.Name may not be
+ -- sufficiently aligned to interpret as a 32 bit word, so it is
+ -- copied to a temporary
+
+ Aligned_Name : Name_Str := ST_Entry.Name;
+ for Aligned_Name'Alignment use 4;
+
+ First_Word : uint32;
+ pragma Import (Ada, First_Word);
+ -- Suppress initialization in Normalized_Scalars mode
+ for First_Word'Address use Aligned_Name (1)'Address;
+
+ Second_Word : uint32;
+ pragma Import (Ada, Second_Word);
+ -- Suppress initialization in Normalized_Scalars mode
+ for Second_Word'Address use Aligned_Name (5)'Address;
+
+ begin
+ if First_Word = 0 then
+ -- Second word is an offset in the symbol table
+ if Second_Word = 0 then
+ return (null, 0);
+ else
+ Seek (Obj.Symstr_Stream, int64 (Second_Word));
+ return Read (Obj.Symstr_Stream);
+ end if;
+ else
+ -- Inlined symbol name
+ Seek (Obj.Symtab_Stream, Sym.Off);
+ return To_String_Ptr_Len (Read (Obj.Symtab_Stream), 8);
+ end if;
+ end;
+ end Name;
+
+ end PECOFF_Ops;
+
+ -----------------
+ -- XCOFF32_Ops --
+ -----------------
+
+ package body XCOFF32_Ops is
+
+ function Read_Section_Header
+ (Obj : in out XCOFF32_Object_File;
+ Index : uint32) return Section_Header;
+ -- Read a header from section table
+
+ -----------------
+ -- Read_Symbol --
+ -----------------
+
+ function Read_Symbol
+ (Obj : in out XCOFF32_Object_File;
+ Off : Offset) return Object_Symbol
+ is
+ Sym : Symbol_Entry;
+ Sz : constant Offset := Symbol_Entry'Size / SSU;
+ Aux : Aux_Entry;
+ Result : Object_Symbol;
+ Noff : Offset;
+ Sym_Off : Offset;
+
+ procedure Read_LD_Symbol;
+ -- Read the next LD symbol
+
+ --------------------
+ -- Read_LD_Symbol --
+ --------------------
+
+ procedure Read_LD_Symbol is
+ begin
+ loop
+ Sym_Off := Noff;
+
+ Read_Raw (Obj.Symtab_Stream, Sym'Address, uint32 (Sz));
+
+ Noff := Noff + Offset (1 + Sym.n_numaux) * Sz;
+
+ for J in 1 .. Sym.n_numaux loop
+ Read_Raw (Obj.Symtab_Stream, Aux'Address, uint32 (Sz));
+ end loop;
+
+ exit when Noff >= Obj.Symtab_Last;
+
+ exit when Sym.n_numaux = 1
+ and then Sym.n_scnum /= 0
+ and then (Sym.n_sclass = C_EXT
+ or else Sym.n_sclass = C_HIDEXT
+ or else Sym.n_sclass = C_WEAKEXT)
+ and then Aux.x_smtyp = XTY_LD;
+ end loop;
+ end Read_LD_Symbol;
+
+ -- Start of processing for Read_Symbol
+
+ begin
+ Seek (Obj.Symtab_Stream, Off);
+ Noff := Off;
+ Read_LD_Symbol;
+
+ if Noff >= Obj.Symtab_Last then
+ return Null_Symbol;
+ end if;
+
+ -- Construct the symbol
+
+ Result := (Off => Sym_Off,
+ Next => Noff,
+ Value => uint64 (Sym.n_value),
+ Size => 0);
+
+ -- Look for the next symbol to compute the size
+
+ Read_LD_Symbol;
+
+ if Noff >= Obj.Symtab_Last then
+ return Null_Symbol;
+ end if;
+
+ Result.Size := uint64 (Sym.n_value) - Result.Value;
+ Result.Next := Sym_Off;
+ return Result;
+ end Read_Symbol;
+
+ ------------------
+ -- First_Symbol --
+ ------------------
+
+ function First_Symbol
+ (Obj : in out XCOFF32_Object_File) return Object_Symbol
+ is
+ begin
+ -- Return Null_Symbol in the case that the symbol table is empty
+
+ if Obj.Symtab_Last = 0 then
+ return Null_Symbol;
+ end if;
+
+ return Read_Symbol (Obj, 0);
+ end First_Symbol;
+
+ ----------------
+ -- Initialize --
+ ----------------
+
+ function Initialize
+ (F : Mapped_File;
+ Hdr : Header;
+ In_Exception : Boolean) return XCOFF32_Object_File
+ is
+ Res : XCOFF32_Object_File (Format => XCOFF32);
+ Strtab_Sz : uint32;
+ begin
+ Res.Mf := F;
+ Res.In_Exception := In_Exception;
+
+ Res.Arch := PPC;
+
+ -- Map sections table
+ Res.Num_Sections := uint32 (Hdr.f_nscns);
+ Res.Sectab_Stream := Create_Stream
+ (F,
+ File_Size (Header'Size / SSU) + File_Size (Hdr.f_opthdr),
+ File_Size (Hdr.f_nscns) * (Section_Header'Size / SSU));
+
+ -- Map symbols table
+ Res.Symtab_Last := Offset (Hdr.f_nscns) * (Symbol_Entry'Size / SSU);
+ Res.Symtab_Stream := Create_Stream
+ (F,
+ File_Size (Hdr.f_symptr),
+ File_Size (Res.Symtab_Last) + 4);
+
+ -- Map string table
+ Seek (Res.Symtab_Stream, Res.Symtab_Last);
+ Strtab_Sz := Read (Res.Symtab_Stream);
+ Res.Symstr_Stream := Create_Stream
+ (F,
+ File_Size (Res.Symtab_Last) + 4,
+ File_Size (Strtab_Sz) - 4);
+
+ return Res;
+ end Initialize;
+
+ -----------------
+ -- Get_Section --
+ -----------------
+
+ function Get_Section
+ (Obj : in out XCOFF32_Object_File;
+ Index : uint32) return Object_Section
+ is
+ Sec : constant Section_Header := Read_Section_Header (Obj, Index);
+ begin
+ return (Index, Offset (Sec.s_scnptr),
+ uint64 (Sec.s_vaddr),
+ uint64 (Sec.s_size),
+ (Sec.s_flags and STYP_TEXT) /= 0);
+ end Get_Section;
+
+ -----------------
+ -- Read_Header --
+ -----------------
+
+ function Read_Header (F : in out Mapped_Stream) return Header is
+ Hdr : Header;
+ begin
+ Seek (F, 0);
+ Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
+ return Hdr;
+ end Read_Header;
+
+ -------------------------
+ -- Read_Section_Header --
+ -------------------------
+
+ function Read_Section_Header
+ (Obj : in out XCOFF32_Object_File;
+ Index : uint32) return Section_Header
+ is
+ Sec : Section_Header;
+
+ begin
+ -- Seek to the end of the object header
+
+ Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
+
+ -- Read the section
+
+ Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
+
+ return Sec;
+ end Read_Section_Header;
+
+ ----------
+ -- Name --
+ ----------
+
+ function Name
+ (Obj : in out XCOFF32_Object_File;
+ Sec : Object_Section) return String
+ is
+ Hdr : Section_Header;
+ begin
+ Hdr := Read_Section_Header (Obj, Sec.Num);
+ return Trim_Trailing_Nuls (Hdr.s_name);
+ end Name;
+
+ ----------
+ -- Name --
+ ----------
+
+ function Name
+ (Obj : in out XCOFF32_Object_File;
+ Sym : Object_Symbol) return String_Ptr_Len
+ is
+ Symbol : Symbol_Entry;
+
+ begin
+ Seek (Obj.Symtab_Stream, Sym.Off);
+ Read_Raw (Obj.Symtab_Stream, Symbol'Address, Symbol'Size / SSU);
+
+ declare
+ First_Word : uint32;
+ pragma Import (Ada, First_Word);
+ -- Suppress initialization in Normalized_Scalars mode
+ for First_Word'Address use Symbol.n_name (1)'Address;
+
+ Second_Word : uint32;
+ pragma Import (Ada, Second_Word);
+ -- Suppress initialization in Normalized_Scalars mode
+ for Second_Word'Address use Symbol.n_name (5)'Address;
+
+ begin
+ if First_Word = 0 then
+ if Second_Word = 0 then
+ return (null, 0);
+ else
+ Seek (Obj.Symstr_Stream, int64 (Second_Word));
+ return Read (Obj.Symstr_Stream);
+ end if;
+ else
+ Seek (Obj.Symtab_Stream, Sym.Off);
+ return To_String_Ptr_Len (Read (Obj.Symstr_Stream), 8);
+ end if;
+ end;
+ end Name;
+ end XCOFF32_Ops;
+
+ ----------
+ -- Arch --
+ ----------
+
+ function Arch (Obj : Object_File) return Object_Arch is
+ begin
+ return Obj.Arch;
+ end Arch;
+
+ function Create_Stream
+ (Mf : Mapped_File;
+ File_Offset : File_Size;
+ File_Length : File_Size)
+ return Mapped_Stream
+ is
+ Region : Mapped_Region;
+ begin
+ Read (Mf, Region, File_Offset, File_Length, False);
+ return (Region, 0, Offset (File_Length));
+ end Create_Stream;
+
+ function Create_Stream
+ (Obj : Object_File;
+ Sec : Object_Section) return Mapped_Stream is
+ begin
+ return Create_Stream (Obj.Mf, File_Size (Sec.Off), File_Size (Sec.Size));
+ end Create_Stream;
+
+ procedure Tell (Obj : in out Mapped_Stream; Off : out Offset) is
+ begin
+ Off := Obj.Off;
+ end Tell;
+
+ function Tell (Obj : Mapped_Stream) return Offset is
+ begin
+ return Obj.Off;
+ end Tell;
+
+ function Length (Obj : Mapped_Stream) return Offset is
+ begin
+ return Obj.Len;
+ end Length;
+
+ -----------
+ -- Close --
+ -----------
+
+ procedure Close (S : in out Mapped_Stream) is
+ begin
+ Free (S.Region);
+ end Close;
+
+ procedure Close (Obj : in out Object_File) is
+ begin
+ Close (Obj.Symtab_Stream);
+ Close (Obj.Symstr_Stream);
+ Close (Obj.Sectab_Stream);
+
+ case Obj.Format is
+ when ELF =>
+ Close (Obj.Secstr_Stream);
+ when Any_PECOFF =>
+ null;
+ when XCOFF32 =>
+ null;
+ end case;
+
+ Close (Obj.Mf);
+ end Close;
+
+ ------------------------
+ -- Strip_Leading_Char --
+ ------------------------
+
+ function Strip_Leading_Char
+ (Obj : in out Object_File;
+ Sym : String_Ptr_Len) return Positive is
+ begin
+ if (Obj.Format = PECOFF and then Sym.Ptr (1) = '_')
+ or else
+ (Obj.Format = XCOFF32 and then Sym.Ptr (1) = '.')
+ then
+ return 2;
+ else
+ return 1;
+ end if;
+ end Strip_Leading_Char;
+
+ ----------------------
+ -- Decoded_Ada_Name --
+ ----------------------
+
+ function Decoded_Ada_Name
+ (Obj : in out Object_File;
+ Sym : String_Ptr_Len) return String
+ is
+ procedure gnat_decode
+ (Coded_Name_Addr : Address;
+ Ada_Name_Addr : Address;
+ Verbose : int);
+ pragma Import (C, gnat_decode, "__gnat_decode");
+
+ subtype size_t is Interfaces.C.size_t;
+
+ Sym_Name : constant String :=
+ String (Sym.Ptr (1 .. Sym.Len)) & ASCII.NUL;
+ Decoded : char_array (0 .. size_t (Sym.Len) * 2 + 60);
+ Off : Natural;
+ begin
+ -- In the PECOFF case most but not all symbol table entries have an
+ -- extra leading underscore. In this case we trim it.
+
+ Off := Strip_Leading_Char (Obj, Sym);
+
+ gnat_decode (Sym_Name (Off)'Address, Decoded'Address, 0);
+
+ return To_Ada (Decoded);
+ end Decoded_Ada_Name;
+
+ ------------------
+ -- First_Symbol --
+ ------------------
+
+ function First_Symbol (Obj : in out Object_File) return Object_Symbol is
+ begin
+ case Obj.Format is
+ when ELF32 => return ELF32_Ops.First_Symbol (Obj);
+ when ELF64 => return ELF64_Ops.First_Symbol (Obj);
+ when Any_PECOFF => return PECOFF_Ops.First_Symbol (Obj);
+ when XCOFF32 => return XCOFF32_Ops.First_Symbol (Obj);
+ end case;
+ end First_Symbol;
+
+ ------------
+ -- Format --
+ ------------
+
+ function Format (Obj : Object_File) return Object_Format is
+ begin
+ return Obj.Format;
+ end Format;
+
+ ----------------------
+ -- Get_Load_Address --
+ ----------------------
+
+ function Get_Load_Address (Obj : Object_File) return uint64 is
+ begin
+ raise Format_Error with "Get_Load_Address not implemented";
+ return 0;
+ end Get_Load_Address;
+
+ -----------------
+ -- Get_Section --
+ -----------------
+
+ function Get_Section
+ (Obj : in out Object_File;
+ Shnum : uint32) return Object_Section is
+ begin
+ case Obj.Format is
+ when ELF32 => return ELF32_Ops.Get_Section (Obj, Shnum);
+ when ELF64 => return ELF64_Ops.Get_Section (Obj, Shnum);
+ when Any_PECOFF => return PECOFF_Ops.Get_Section (Obj, Shnum);
+ when XCOFF32 => return XCOFF32_Ops.Get_Section (Obj, Shnum);
+ end case;
+ end Get_Section;
+
+ function Get_Section
+ (Obj : in out Object_File;
+ Sec_Name : String) return Object_Section
+ is
+ Sec : Object_Section;
+
+ begin
+ for J in 0 .. Obj.Num_Sections - 1 loop
+ Sec := Get_Section (Obj, J);
+
+ if Name (Obj, Sec) = Sec_Name then
+ return Sec;
+ end if;
+ end loop;
+
+ if Obj.In_Exception then
+ return Null_Section;
+ else
+ raise Format_Error with "could not find section in object file";
+ end if;
+ end Get_Section;
+
+ -----------------------
+ -- Get_Memory_Bounds --
+ -----------------------
+
+ procedure Get_Memory_Bounds
+ (Obj : in out Object_File;
+ Low, High : out uint64) is
+ Sec : Object_Section;
+ begin
+ -- First set as an empty range
+ Low := uint64'Last;
+ High := uint64'First;
+
+ for Idx in 1 .. Num_Sections (Obj) loop
+ Sec := Get_Section (Obj, Idx - 1);
+ if Sec.Flag_Alloc then
+ if Sec.Addr < Low then
+ Low := Sec.Addr;
+ end if;
+ if Sec.Addr + Sec.Size > High then
+ High := Sec.Addr + Sec.Size;
+ end if;
+ end if;
+ end loop;
+ end Get_Memory_Bounds;
+
+ ----------
+ -- Name --
+ ----------
+
+ function Name
+ (Obj : in out Object_File;
+ Sec : Object_Section) return String is
+ begin
+ case Obj.Format is
+ when ELF32 => return ELF32_Ops.Name (Obj, Sec);
+ when ELF64 => return ELF64_Ops.Name (Obj, Sec);
+ when Any_PECOFF => return PECOFF_Ops.Name (Obj, Sec);
+ when XCOFF32 => return XCOFF32_Ops.Name (Obj, Sec);
+ end case;
+ end Name;
+
+ function Name
+ (Obj : in out Object_File;
+ Sym : Object_Symbol) return String_Ptr_Len is
+ begin
+ case Obj.Format is
+ when ELF32 => return ELF32_Ops.Name (Obj, Sym);
+ when ELF64 => return ELF64_Ops.Name (Obj, Sym);
+ when Any_PECOFF => return PECOFF_Ops.Name (Obj, Sym);
+ when XCOFF32 => return XCOFF32_Ops.Name (Obj, Sym);
+ end case;
+ end Name;
+
+ -----------------
+ -- Next_Symbol --
+ -----------------
+
+ function Next_Symbol
+ (Obj : in out Object_File;
+ Prev : Object_Symbol) return Object_Symbol is
+ begin
+ -- Test whether we've reached the end of the symbol table
+
+ if Prev.Next >= Obj.Symtab_Last then
+ return Null_Symbol;
+ end if;
+
+ return Read_Symbol (Obj, Prev.Next);
+ end Next_Symbol;
+
+ ---------
+ -- Num --
+ ---------
+
+ function Num (Sec : Object_Section) return uint32 is
+ begin
+ return Sec.Num;
+ end Num;
+
+ ------------------
+ -- Num_Sections --
+ ------------------
+
+ function Num_Sections (Obj : Object_File) return uint32 is
+ begin
+ return Obj.Num_Sections;
+ end Num_Sections;
+
+ ---------
+ -- Off --
+ ---------
+
+ function Off (Sec : Object_Section) return Offset is
+ begin
+ return Sec.Off;
+ end Off;
+
+ function Off (Sym : Object_Symbol) return Offset is
+ begin
+ return Sym.Off;
+ end Off;
+
+ ----------------------
+ -- Offset_To_String --
+ ----------------------
+
+ function Offset_To_String
+ (S : in out Mapped_Stream;
+ Off : Offset) return String
+ is
+ Buf : Buffer;
+ begin
+ Seek (S, Off);
+ Read_C_String (S, Buf);
+ return To_String (Buf);
+ end Offset_To_String;
+
+ ----------
+ -- Open --
+ ----------
+
+ function Open
+ (File_Name : String;
+ In_Exception : Boolean := False) return Object_File_Access
+ is
+ F : Mapped_File;
+ Hdr_Stream : Mapped_Stream;
+
+ begin
+ -- Open the file
+
+ F := Open_Read_No_Exception (File_Name);
+
+ if F = Invalid_Mapped_File then
+ if In_Exception then
+ return null;
+ else
+ raise IO_Error with "could not open object file";
+ end if;
+ end if;
+
+ Hdr_Stream := Create_Stream (F, 0, 4096);
+
+ declare
+ Hdr : constant ELF32_Ops.Header := ELF32_Ops.Read_Header (Hdr_Stream);
+
+ begin
+ -- Look for the magic numbers for the ELF case
+
+ if Hdr.E_Ident (0) = 16#7F# and then
+ Hdr.E_Ident (1) = Character'Pos ('E') and then
+ Hdr.E_Ident (2) = Character'Pos ('L') and then
+ Hdr.E_Ident (3) = Character'Pos ('F') and then
+ Hdr.E_Ident (4) = ELF32_Ops.ELFCLASS32
+ then
+ Close (Hdr_Stream);
+ return new Object_File'
+ (ELF32_Ops.Initialize (F, Hdr, In_Exception));
+ end if;
+ end;
+
+ declare
+ Hdr : constant ELF64_Ops.Header :=
+ ELF64_Ops.Read_Header (Hdr_Stream);
+
+ begin
+ -- Look for the magic numbers for the ELF case
+
+ if Hdr.E_Ident (0) = 16#7F# and then
+ Hdr.E_Ident (1) = Character'Pos ('E') and then
+ Hdr.E_Ident (2) = Character'Pos ('L') and then
+ Hdr.E_Ident (3) = Character'Pos ('F') and then
+ Hdr.E_Ident (4) = ELF32_Ops.ELFCLASS64
+ then
+ Close (Hdr_Stream);
+ return new Object_File'
+ (ELF64_Ops.Initialize (F, Hdr, In_Exception));
+ end if;
+ end;
+
+ declare
+ Hdr : constant PECOFF_Ops.Header :=
+ PECOFF_Ops.Read_Header (Hdr_Stream);
+
+ begin
+ -- Test the magic numbers
+
+ if Hdr.Magics (0) = Character'Pos ('P') and then
+ Hdr.Magics (1) = Character'Pos ('E') and then
+ Hdr.Magics (2) = 0 and then
+ Hdr.Magics (3) = 0
+ then
+ Close (Hdr_Stream);
+ return new Object_File'
+ (PECOFF_Ops.Initialize (F, Hdr, In_Exception));
+ end if;
+
+ exception
+ -- If this is not a PECOFF file then we've done a seek and read to a
+ -- random address, possibly raising IO_Error
+
+ when IO_Error =>
+ null;
+ end;
+
+ declare
+ Hdr : constant XCOFF32_Ops.Header :=
+ XCOFF32_Ops.Read_Header (Hdr_Stream);
+
+ begin
+ -- Test the magic numbers
+
+ if Hdr.f_magic = 8#0737# then
+ Close (Hdr_Stream);
+ return new Object_File'
+ (XCOFF32_Ops.Initialize (F, Hdr, In_Exception));
+ end if;
+ end;
+
+ Close (Hdr_Stream);
+
+ if In_Exception then
+ return null;
+ else
+ raise Format_Error with "unrecognized object format";
+ end if;
+ end Open;
+
+ ----------
+ -- Read --
+ ----------
+
+ function Read (S : in out Mapped_Stream) return Mmap.Str_Access
+ is
+ function To_Str_Access is
+ new Ada.Unchecked_Conversion (Address, Str_Access);
+ begin
+ return To_Str_Access (Data (S.Region) (Natural (S.Off + 1))'Address);
+ end Read;
+
+ function Read (S : in out Mapped_Stream) return String_Ptr_Len is
+ begin
+ return To_String_Ptr_Len (Read (S));
+ end Read;
+
+ procedure Check_Read_Offset (S : in out Mapped_Stream; Size : uint32) is
+ begin
+ if S.Off + Offset (Size) > Offset (Last (S.Region)) then
+ raise IO_Error with "could not read from object file";
+ end if;
+ end Check_Read_Offset;
+
+ procedure Read_Raw
+ (S : in out Mapped_Stream;
+ Addr : Address;
+ Size : uint32)
+ is
+ function To_Str_Access is
+ new Ada.Unchecked_Conversion (Address, Str_Access);
+
+ Sz : constant Offset := Offset (Size);
+ begin
+ -- Check size
+
+ pragma Debug (Check_Read_Offset (S, Size));
+
+ -- Copy data
+
+ To_Str_Access (Addr) (1 .. Positive (Sz)) :=
+ Data (S.Region) (Positive (S.Off + 1) .. Positive (S.Off + Sz));
+
+ -- Update offset
+
+ S.Off := S.Off + Sz;
+ end Read_Raw;
+
+ function Read (S : in out Mapped_Stream) return uint8 is
+ Data : uint8;
+ begin
+ Read_Raw (S, Data'Address, Data'Size / SSU);
+ return Data;
+ end Read;
+
+ function Read (S : in out Mapped_Stream) return uint16 is
+ Data : uint16;
+ begin
+ Read_Raw (S, Data'Address, Data'Size / SSU);
+ return Data;
+ end Read;
+
+ function Read (S : in out Mapped_Stream) return uint32 is
+ Data : uint32;
+ begin
+ Read_Raw (S, Data'Address, Data'Size / SSU);
+ return Data;
+ end Read;
+
+ function Read (S : in out Mapped_Stream) return uint64 is
+ Data : uint64;
+ begin
+ Read_Raw (S, Data'Address, Data'Size / SSU);
+ return Data;
+ end Read;
+
+ function Read (S : in out Mapped_Stream) return int8 is
+ Data : int8;
+ begin
+ Read_Raw (S, Data'Address, Data'Size / SSU);
+ return Data;
+ end Read;
+
+ function Read (S : in out Mapped_Stream) return int16 is
+ Data : int16;
+ begin
+ Read_Raw (S, Data'Address, Data'Size / SSU);
+ return Data;
+ end Read;
+
+ function Read (S : in out Mapped_Stream) return int32 is
+ Data : int32;
+ begin
+ Read_Raw (S, Data'Address, Data'Size / SSU);
+ return Data;
+ end Read;
+
+ function Read (S : in out Mapped_Stream) return int64 is
+ Data : int64;
+ begin
+ Read_Raw (S, Data'Address, Data'Size / SSU);
+ return Data;
+ end Read;
+
+ ------------------
+ -- Read_Address --
+ ------------------
+
+ function Read_Address
+ (Obj : Object_File; S : in out Mapped_Stream) return uint64 is
+ Address_32 : uint32;
+ Address_64 : uint64;
+
+ begin
+ case Obj.Arch is
+ when i386
+ | MIPS
+ | PPC
+ | SPARC
+ =>
+ Address_32 := Read (S);
+ return uint64 (Address_32);
+
+ when IA64
+ | PPC64
+ | SPARC64
+ | x86_64
+ =>
+ Address_64 := Read (S);
+ return Address_64;
+
+ when Unknown =>
+ raise Format_Error with "unrecognized machine architecture";
+ end case;
+ end Read_Address;
+
+ -------------------
+ -- Read_C_String --
+ -------------------
+
+ procedure Read_C_String (S : in out Mapped_Stream; B : out Buffer) is
+ J : Integer := 0;
+
+ begin
+ loop
+ -- Handle overflow case
+
+ if J = B'Last then
+ B (J) := 0;
+ exit;
+ end if;
+
+ B (J) := Read (S);
+ exit when B (J) = 0;
+ J := J + 1;
+ end loop;
+ end Read_C_String;
+
+ -------------------
+ -- Read_C_String --
+ -------------------
+
+ function Read_C_String (S : in out Mapped_Stream) return Str_Access is
+ Res : constant Str_Access := Read (S);
+
+ begin
+ for J in Res'Range loop
+ if S.Off + Offset (J - 1) > Offset (Last (S.Region)) then
+ raise IO_Error with "could not read from object file";
+ end if;
+
+ if Res (J) = ASCII.NUL then
+ S.Off := S.Off + Offset (J);
+ return Res;
+ end if;
+ end loop;
+
+ -- Overflow case
+ raise Constraint_Error;
+ end Read_C_String;
+
+ -----------------
+ -- Read_LEB128 --
+ -----------------
+
+ function Read_LEB128 (S : in out Mapped_Stream) return uint32 is
+ B : uint8;
+ Shift : Integer := 0;
+ Res : uint32 := 0;
+
+ begin
+ loop
+ B := Read (S);
+ Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
+ exit when (B and 16#80#) = 0;
+ Shift := Shift + 7;
+ end loop;
+
+ return Res;
+ end Read_LEB128;
+
+ function Read_LEB128 (S : in out Mapped_Stream) return int32 is
+ B : uint8;
+ Shift : Integer := 0;
+ Res : uint32 := 0;
+
+ begin
+ loop
+ B := Read (S);
+ Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
+ Shift := Shift + 7;
+ exit when (B and 16#80#) = 0;
+ end loop;
+
+ if Shift < 32 and then (Res and Shift_Left (1, Shift - 1)) /= 0 then
+ Res := Res or Shift_Left (-1, Shift);
+ end if;
+
+ return To_int32 (Res);
+ end Read_LEB128;
+
+ -----------------
+ -- Read_Symbol --
+ -----------------
+
+ function Read_Symbol
+ (Obj : in out Object_File;
+ Off : Offset) return Object_Symbol is
+ begin
+ case Obj.Format is
+ when ELF32 => return ELF32_Ops.Read_Symbol (Obj, Off);
+ when ELF64 => return ELF64_Ops.Read_Symbol (Obj, Off);
+ when Any_PECOFF => return PECOFF_Ops.Read_Symbol (Obj, Off);
+ when XCOFF32 => return XCOFF32_Ops.Read_Symbol (Obj, Off);
+ end case;
+ end Read_Symbol;
+
+ ----------
+ -- Seek --
+ ----------
+
+ procedure Seek (S : in out Mapped_Stream; Off : Offset) is
+ begin
+ if Off < 0 or else Off > Offset (Last (S.Region)) then
+ raise IO_Error with "could not seek to offset in object file";
+ end if;
+
+ S.Off := Off;
+ end Seek;
+
+ ----------
+ -- Size --
+ ----------
+
+ function Size (Sec : Object_Section) return uint64 is
+ begin
+ return Sec.Size;
+ end Size;
+
+ function Size (Sym : Object_Symbol) return uint64 is
+ begin
+ return Sym.Size;
+ end Size;
+
+ ------------
+ -- Strlen --
+ ------------
+
+ function Strlen (Buf : Buffer) return int32 is
+ begin
+ return int32 (CRTL.strlen (Buf'Address));
+ end Strlen;
+
+ -----------
+ -- Spans --
+ -----------
+
+ function Spans (Sym : Object_Symbol; Addr : uint64) return Boolean is
+ begin
+ return Addr >= Sym.Value and then Addr < Sym.Value + Sym.Size;
+ end Spans;
+
+ ---------------
+ -- To_String --
+ ---------------
+
+ function To_String (Buf : Buffer) return String is
+ Result : String (1 .. Integer (CRTL.strlen (Buf'Address)));
+ for Result'Address use Buf'Address;
+ pragma Import (Ada, Result);
+
+ begin
+ return Result;
+ end To_String;
+
+ -----------------------
+ -- To_String_Ptr_Len --
+ -----------------------
+
+ function To_String_Ptr_Len
+ (Ptr : Mmap.Str_Access;
+ Max_Len : Natural := Natural'Last) return String_Ptr_Len is
+ begin
+ for I in 1 .. Max_Len loop
+ if Ptr (I) = ASCII.NUL then
+ return (Ptr, I - 1);
+ end if;
+ end loop;
+ return (Ptr, Max_Len);
+ end To_String_Ptr_Len;
+
+ ------------------------
+ -- Trim_Trailing_Nuls --
+ ------------------------
+
+ function Trim_Trailing_Nuls (Str : String) return String is
+ begin
+ for J in Str'Range loop
+ if Str (J) = ASCII.NUL then
+ return Str (Str'First .. J - 1);
+ end if;
+ end loop;
+
+ return Str;
+ end Trim_Trailing_Nuls;
+
+ -----------
+ -- Value --
+ -----------
+
+ function Value (Sym : Object_Symbol) return uint64 is
+ begin
+ return Sym.Value;
+ end Value;
+
+end System.Object_Reader;