------------------------------------------------------------------------------ -- -- -- GNAT COMPILER COMPONENTS -- -- -- -- S Y S T E M . O B J E C T _ R E A D E R -- -- -- -- S p e c -- -- -- -- Copyright (C) 2009-2019, 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 -- -- . -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- This package implements a simple, minimal overhead reader for object files -- composed of sections of untyped heterogeneous binary data. with Interfaces; with System.Mmap; package System.Object_Reader is -------------- -- Limits -- -------------- BUFFER_SIZE : constant := 8 * 1024; --------------------- -- Object sections -- ---------------------- type Object_Section is private; Null_Section : constant Object_Section; -------------------- -- Object symbols -- -------------------- type Object_Symbol is private; ------------------------ -- Object format type -- ------------------------ type Object_Format is (ELF32, -- Object format is 32-bit ELF ELF64, -- Object format is 64-bit ELF PECOFF, -- Object format is Microsoft PECOFF PECOFF_PLUS, -- Object format is Microsoft PECOFF+ XCOFF32); -- Object format is AIX 32-bit XCOFF -- PECOFF | PECOFF_PLUS appears so often as a case choice, would -- seem a good idea to have a subtype name covering these two choices ??? ------------------ -- Object files -- ------------------ type Object_File (Format : Object_Format) is private; type Object_File_Access is access Object_File; ------------------------------ -- Object architecture type -- ------------------------------ type Object_Arch is (Unknown, -- The target architecture has not yet been determined SPARC, -- 32-bit SPARC SPARC64, -- 64-bit SPARC i386, -- Intel IA32 MIPS, -- MIPS Technologies MIPS x86_64, -- x86-64 (64-bit AMD/Intel) IA64, -- Intel IA64 PPC, -- 32-bit PowerPC PPC64); -- 64-bit PowerPC ------------------ -- Target types -- ------------------ subtype Offset is Interfaces.Integer_64; subtype uint8 is Interfaces.Unsigned_8; subtype uint16 is Interfaces.Unsigned_16; subtype uint32 is Interfaces.Unsigned_32; subtype uint64 is Interfaces.Unsigned_64; subtype int8 is Interfaces.Integer_8; subtype int16 is Interfaces.Integer_16; subtype int32 is Interfaces.Integer_32; subtype int64 is Interfaces.Integer_64; type Buffer is array (0 .. BUFFER_SIZE - 1) of uint8; type String_Ptr_Len is record Ptr : Mmap.Str_Access; Len : Natural; end record; -- A string made from a pointer and a length. Not all strings for name -- are C strings: COFF inlined symbol names have a max length of 8. ------------------------------------------- -- Operations on buffers of untyped data -- ------------------------------------------- function To_String (Buf : Buffer) return String; -- Construct string from C style null-terminated string stored in a buffer function To_String_Ptr_Len (Ptr : Mmap.Str_Access; Max_Len : Natural := Natural'Last) return String_Ptr_Len; -- Convert PTR to a String_Ptr_Len. function Strlen (Buf : Buffer) return int32; -- Return the length of a C style null-terminated string ------------------------- -- Opening and closing -- ------------------------- function Open (File_Name : String; In_Exception : Boolean := False) return Object_File_Access; -- Open the object file and initialize the reader. In_Exception is true -- when the parsing is done as part of an exception handler decorator. In -- this mode we do not want to raise an exception. procedure Close (Obj : in out Object_File); -- Close the object file ----------------------- -- Sequential access -- ----------------------- type Mapped_Stream is private; -- Provide an abstraction of a stream on a memory mapped file function Create_Stream (Mf : System.Mmap.Mapped_File; File_Offset : System.Mmap.File_Size; File_Length : System.Mmap.File_Size) return Mapped_Stream; -- Create a stream from Mf procedure Close (S : in out Mapped_Stream); -- Close the stream (deallocate memory) procedure Read_Raw (S : in out Mapped_Stream; Addr : Address; Size : uint32); pragma Inline (Read_Raw); -- Read a number of fixed sized records procedure Seek (S : in out Mapped_Stream; Off : Offset); -- Seek to an absolute offset in bytes procedure Tell (Obj : in out Mapped_Stream; Off : out Offset) with Inline; function Tell (Obj : Mapped_Stream) return Offset with Inline; -- Fetch the current offset function Length (Obj : Mapped_Stream) return Offset with Inline; -- Length of the stream function Read (S : in out Mapped_Stream) return Mmap.Str_Access; -- Provide a pointer in memory at the current offset function Read (S : in out Mapped_Stream) return String_Ptr_Len; -- Provide a pointer in memory at the current offset function Read (S : in out Mapped_Stream) return uint8; function Read (S : in out Mapped_Stream) return uint16; function Read (S : in out Mapped_Stream) return uint32; function Read (S : in out Mapped_Stream) return uint64; function Read (S : in out Mapped_Stream) return int8; function Read (S : in out Mapped_Stream) return int16; function Read (S : in out Mapped_Stream) return int32; function Read (S : in out Mapped_Stream) return int64; -- Read a scalar function Read_Address (Obj : Object_File; S : in out Mapped_Stream) return uint64; -- Read either a 64 or 32 bit address from the file stream depending on the -- address size of the target architecture and promote it to a 64 bit type. function Read_LEB128 (S : in out Mapped_Stream) return uint32; function Read_LEB128 (S : in out Mapped_Stream) return int32; -- Read a value encoding in Little-Endian Base 128 format procedure Read_C_String (S : in out Mapped_Stream; B : out Buffer); function Read_C_String (S : in out Mapped_Stream) return Mmap.Str_Access; -- Read a C style NULL terminated string function Offset_To_String (S : in out Mapped_Stream; Off : Offset) return String; -- Construct a string from a C style NULL terminated string located at an -- offset into the object file. ------------------------ -- Object information -- ------------------------ function Arch (Obj : Object_File) return Object_Arch; -- Return the object architecture function Format (Obj : Object_File) return Object_Format; -- Return the object file format function Get_Load_Address (Obj : Object_File) return uint64; -- Return the load address defined in Obj. May raise Format_Error if not -- implemented function Num_Sections (Obj : Object_File) return uint32; -- Return the number of sections composing the object file function Get_Section (Obj : in out Object_File; Shnum : uint32) return Object_Section; -- Return the Nth section (numbered from zero) function Get_Section (Obj : in out Object_File; Sec_Name : String) return Object_Section; -- Return a section by name function Create_Stream (Obj : Object_File; Sec : Object_Section) return Mapped_Stream; -- Create a stream for section Sec procedure Get_Xcode_Bounds (Obj : in out Object_File; Low, High : out uint64); -- Return the low and high addresses of the code for the object file. Can -- be used to check if an address in within this object file. This -- procedure is not efficient and the result should be saved to avoid -- recomputation. ------------------------- -- Section information -- ------------------------- function Name (Obj : in out Object_File; Sec : Object_Section) return String; -- Return the name of a section as a string function Size (Sec : Object_Section) return uint64; -- Return the size of a section in bytes function Num (Sec : Object_Section) return uint32; -- Return the index of a section from zero function Off (Sec : Object_Section) return Offset; -- Return the byte offset of the section within the object ------------------------------ -- Symbol table information -- ------------------------------ Null_Symbol : constant Object_Symbol; -- An empty symbol table entry. function First_Symbol (Obj : in out Object_File) return Object_Symbol; -- Return the first element in the symbol table or Null_Symbol if the -- symbol table is empty. function Next_Symbol (Obj : in out Object_File; Prev : Object_Symbol) return Object_Symbol; -- Return the element following Prev in the symbol table, or Null_Symbol if -- Prev is the last symbol in the table. function Read_Symbol (Obj : in out Object_File; Off : Offset) return Object_Symbol; -- Read symbol at Off function Name (Obj : in out Object_File; Sym : Object_Symbol) return String_Ptr_Len; -- Return the name of the symbol function Decoded_Ada_Name (Obj : in out Object_File; Sym : String_Ptr_Len) return String; -- Return the decoded name of a symbol encoded as per exp_dbug.ads function Strip_Leading_Char (Obj : in out Object_File; Sym : String_Ptr_Len) return Positive; -- Return the index of the first character to decode the name. This can -- strip one character for ABI with a prefix (like x86 for PECOFF). function Value (Sym : Object_Symbol) return uint64; -- Return the name of the symbol function Size (Sym : Object_Symbol) return uint64; -- Return the size of the symbol in bytes function Spans (Sym : Object_Symbol; Addr : uint64) return Boolean; -- Determine whether a particular address corresponds to the range -- referenced by this symbol. function Off (Sym : Object_Symbol) return Offset; -- Return the offset of the symbol. ---------------- -- Exceptions -- ---------------- IO_Error : exception; -- Input/Output error reading file Format_Error : exception; -- Encountered a problem parsing the object private type Mapped_Stream is record Region : System.Mmap.Mapped_Region; Off : Offset; Len : Offset; end record; subtype ELF is Object_Format range ELF32 .. ELF64; subtype Any_PECOFF is Object_Format range PECOFF .. PECOFF_PLUS; type Object_File (Format : Object_Format) is record Mf : System.Mmap.Mapped_File := System.Mmap.Invalid_Mapped_File; Arch : Object_Arch := Unknown; Num_Sections : uint32 := 0; -- Number of sections Symtab_Last : Offset; -- Last offset of symbol table In_Exception : Boolean := False; -- True if the parsing is done as part of an exception handler Sectab_Stream : Mapped_Stream; -- Section table Symtab_Stream : Mapped_Stream; -- Symbol table Symstr_Stream : Mapped_Stream; -- Symbol strings case Format is when ELF => Secstr_Stream : Mapped_Stream; -- Section strings when Any_PECOFF => ImageBase : uint64; -- ImageBase value from header -- Cache for latest result of Get_Section_Virtual_Address GSVA_Sec : uint32 := uint32'Last; GSVA_Addr : uint64; when XCOFF32 => null; end case; end record; subtype ELF_Object_File is Object_File; -- with -- Predicate => ELF_Object_File.Format in ELF; subtype PECOFF_Object_File is Object_File; -- with -- Predicate => PECOFF_Object_File.Format in Any_PECOFF; subtype XCOFF32_Object_File is Object_File; -- with -- Predicate => XCOFF32_Object_File.Format in XCOFF32; -- ???Above predicates cause the compiler to crash when instantiating -- ELF64_Ops (see package body). type Object_Section is record Num : uint32 := 0; -- Section index in the section table Off : Offset := 0; -- First byte of the section in the object file Addr : uint64 := 0; -- Load address of the section. Valid only when Flag_Alloc is true. Size : uint64 := 0; -- Length of the section in bytes Flag_Xcode : Boolean := False; -- True if the section is advertised to contain executable code end record; Null_Section : constant Object_Section := (0, 0, 0, 0, False); type Object_Symbol is record Off : Offset := 0; -- Offset of underlying symbol on disk Next : Offset := 0; -- Offset of the following symbol Value : uint64 := 0; -- Value associated with this symbol Size : uint64 := 0; -- Size of the referenced entity end record; Null_Symbol : constant Object_Symbol := (0, 0, 0, 0); end System.Object_Reader;