1------------------------------------------------------------------------------
2--                                                                          --
3--                         GNAT COMPILER COMPONENTS                         --
4--                                                                          --
5--                 S Y S T E M . O B J E C T _ R E A D E R                  --
6--                                                                          --
7--                                 S p e c                                  --
8--                                                                          --
9--          Copyright (C) 2009-2018, Free Software Foundation, Inc.         --
10--                                                                          --
11-- GNAT is free software;  you can  redistribute it  and/or modify it under --
12-- terms of the  GNU General Public License as published  by the Free Soft- --
13-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17--                                                                          --
18-- As a special exception under Section 7 of GPL version 3, you are granted --
19-- additional permissions described in the GCC Runtime Library Exception,   --
20-- version 3.1, as published by the Free Software Foundation.               --
21--                                                                          --
22-- You should have received a copy of the GNU General Public License and    --
23-- a copy of the GCC Runtime Library Exception along with this program;     --
24-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25-- <http://www.gnu.org/licenses/>.                                          --
26--                                                                          --
27-- GNAT was originally developed  by the GNAT team at  New York University. --
28-- Extensive contributions were provided by Ada Core Technologies Inc.      --
29--                                                                          --
30------------------------------------------------------------------------------
31
32--  This package implements a simple, minimal overhead reader for object files
33--  composed of sections of untyped heterogeneous binary data.
34
35with Interfaces;
36with System.Mmap;
37
38package System.Object_Reader is
39
40   --------------
41   --  Limits  --
42   --------------
43
44   BUFFER_SIZE : constant := 8 * 1024;
45
46   ------------------
47   -- Object files --
48   ------------------
49
50   type Object_File (<>) is private;
51
52   type Object_File_Access is access Object_File;
53
54   ---------------------
55   -- Object sections --
56   ----------------------
57
58   type Object_Section is private;
59
60   Null_Section : constant Object_Section;
61
62   --------------------
63   -- Object symbols --
64   --------------------
65
66   type Object_Symbol is private;
67
68   ------------------------
69   -- Object format type --
70   ------------------------
71
72   type Object_Format is
73     (ELF32,
74      --  Object format is 32-bit ELF
75
76      ELF64,
77      --  Object format is 64-bit ELF
78
79      PECOFF,
80      --  Object format is Microsoft PECOFF
81
82      PECOFF_PLUS,
83      --  Object format is Microsoft PECOFF+
84
85      XCOFF32);
86      --  Object format is AIX 32-bit XCOFF
87
88   --  PECOFF | PECOFF_PLUS appears so often as a case choice, would
89   --  seem a good idea to have a subtype name covering these two choices ???
90
91   ------------------------------
92   -- Object architecture type --
93   ------------------------------
94
95   type Object_Arch is
96     (Unknown,
97      --  The target architecture has not yet been determined
98
99      SPARC,
100      --  32-bit SPARC
101
102      SPARC64,
103      --  64-bit SPARC
104
105      i386,
106      --  Intel IA32
107
108      MIPS,
109      --  MIPS Technologies MIPS
110
111      x86_64,
112      --  x86-64 (64-bit AMD/Intel)
113
114      IA64,
115      --  Intel IA64
116
117      PPC,
118      --  32-bit PowerPC
119
120      PPC64);
121      --  64-bit PowerPC
122
123   ------------------
124   -- Target types --
125   ------------------
126
127   subtype Offset is Interfaces.Integer_64;
128
129   subtype uint8  is Interfaces.Unsigned_8;
130   subtype uint16 is Interfaces.Unsigned_16;
131   subtype uint32 is Interfaces.Unsigned_32;
132   subtype uint64 is Interfaces.Unsigned_64;
133
134   subtype int8  is Interfaces.Integer_8;
135   subtype int16 is Interfaces.Integer_16;
136   subtype int32 is Interfaces.Integer_32;
137   subtype int64 is Interfaces.Integer_64;
138
139   type Buffer is array (0 .. BUFFER_SIZE - 1) of uint8;
140
141   type String_Ptr_Len is record
142      Ptr : Mmap.Str_Access;
143      Len : Natural;
144   end record;
145   --  A string made from a pointer and a length. Not all strings for name
146   --  are C strings: COFF inlined symbol names have a max length of 8.
147
148   -------------------------------------------
149   -- Operations on buffers of untyped data --
150   -------------------------------------------
151
152   function To_String (Buf : Buffer) return String;
153   --  Construct string from C style null-terminated string stored in a buffer
154
155   function To_String_Ptr_Len
156     (Ptr : Mmap.Str_Access;
157      Max_Len : Natural := Natural'Last) return String_Ptr_Len;
158   --  Convert PTR to a String_Ptr_Len.
159
160   function Strlen (Buf : Buffer) return int32;
161   --  Return the length of a C style null-terminated string
162
163   -------------------------
164   -- Opening and closing --
165   -------------------------
166
167   function Open
168     (File_Name    : String;
169      In_Exception : Boolean := False) return Object_File_Access;
170   --  Open the object file and initialize the reader. In_Exception is true
171   --  when the parsing is done as part of an exception handler decorator. In
172   --  this mode we do not want to raise an exception.
173
174   procedure Close (Obj : in out Object_File);
175   --  Close the object file
176
177   -----------------------
178   -- Sequential access --
179   -----------------------
180
181   type Mapped_Stream is private;
182   --  Provide an abstraction of a stream on a memory mapped file
183
184   function Create_Stream (Mf : System.Mmap.Mapped_File;
185                           File_Offset : System.Mmap.File_Size;
186                           File_Length : System.Mmap.File_Size)
187                          return Mapped_Stream;
188   --  Create a stream from Mf
189
190   procedure Close (S : in out Mapped_Stream);
191   --  Close the stream (deallocate memory)
192
193   procedure Read_Raw
194     (S   : in out Mapped_Stream;
195      Addr  : Address;
196      Size  : uint32);
197   pragma Inline (Read_Raw);
198   --  Read a number of fixed sized records
199
200   procedure Seek (S : in out Mapped_Stream; Off : Offset);
201   --  Seek to an absolute offset in bytes
202
203   procedure Tell (Obj : in out Mapped_Stream; Off : out Offset)
204     with Inline;
205   function Tell (Obj : Mapped_Stream) return Offset
206     with Inline;
207   --  Fetch the current offset
208
209   function Length (Obj : Mapped_Stream) return Offset
210     with Inline;
211   --  Length of the stream
212
213   function Read (S : in out Mapped_Stream) return Mmap.Str_Access;
214   --  Provide a pointer in memory at the current offset
215
216   function Read (S : in out Mapped_Stream) return String_Ptr_Len;
217   --  Provide a pointer in memory at the current offset
218
219   function Read (S : in out Mapped_Stream) return uint8;
220   function Read (S : in out Mapped_Stream) return uint16;
221   function Read (S : in out Mapped_Stream) return uint32;
222   function Read (S : in out Mapped_Stream) return uint64;
223   function Read (S : in out Mapped_Stream) return int8;
224   function Read (S : in out Mapped_Stream) return int16;
225   function Read (S : in out Mapped_Stream) return int32;
226   function Read (S : in out Mapped_Stream) return int64;
227   --  Read a scalar
228
229   function Read_Address
230     (Obj : Object_File; S : in out Mapped_Stream) return uint64;
231   --  Read either a 64 or 32 bit address from the file stream depending on the
232   --  address size of the target architecture and promote it to a 64 bit type.
233
234   function Read_LEB128 (S : in out Mapped_Stream) return uint32;
235   function Read_LEB128 (S : in out Mapped_Stream) return int32;
236   --  Read a value encoding in Little-Endian Base 128 format
237
238   procedure Read_C_String (S : in out Mapped_Stream; B : out Buffer);
239   function Read_C_String (S : in out Mapped_Stream) return Mmap.Str_Access;
240   --  Read a C style NULL terminated string
241
242   function Offset_To_String
243     (S : in out Mapped_Stream;
244      Off : Offset) return String;
245   --  Construct a string from a C style NULL terminated string located at an
246   --  offset into the object file.
247
248   ------------------------
249   -- Object information --
250   ------------------------
251
252   function Arch (Obj : Object_File) return Object_Arch;
253   --  Return the object architecture
254
255   function Format (Obj : Object_File) return Object_Format;
256   --  Return the object file format
257
258   function Get_Load_Address (Obj : Object_File) return uint64;
259   --  Return the load address defined in Obj. May raise Format_Error if not
260   --  implemented
261
262   function Num_Sections (Obj : Object_File) return uint32;
263   --  Return the number of sections composing the object file
264
265   function Get_Section
266     (Obj   : in out Object_File;
267      Shnum : uint32) return Object_Section;
268   --  Return the Nth section (numbered from zero)
269
270   function Get_Section
271     (Obj      : in out Object_File;
272      Sec_Name : String) return Object_Section;
273   --  Return a section by name
274
275   function Create_Stream
276     (Obj : Object_File;
277      Sec : Object_Section) return Mapped_Stream;
278   --  Create a stream for section Sec
279
280   procedure Get_Memory_Bounds
281     (Obj   : in out Object_File;
282      Low, High : out uint64);
283   --  Return the low and high addresses of the code for the object file. Can
284   --  be used to check if an address in within this object file. This
285   --  procedure is not efficient and the result should be saved to avoid
286   --  recomputation.
287
288   -------------------------
289   -- Section information --
290   -------------------------
291
292   function Name
293     (Obj : in out Object_File;
294      Sec : Object_Section) return String;
295   --  Return the name of a section as a string
296
297   function Size (Sec : Object_Section) return uint64;
298   --  Return the size of a section in bytes
299
300   function Num (Sec : Object_Section) return uint32;
301   --  Return the index of a section from zero
302
303   function Off (Sec : Object_Section) return Offset;
304   --  Return the byte offset of the section within the object
305
306   ------------------------------
307   -- Symbol table information --
308   ------------------------------
309
310   Null_Symbol : constant Object_Symbol;
311   --  An empty symbol table entry.
312
313   function First_Symbol (Obj : in out Object_File) return Object_Symbol;
314   --  Return the first element in the symbol table or Null_Symbol if the
315   --  symbol table is empty.
316
317   function Next_Symbol
318     (Obj  : in out Object_File;
319      Prev : Object_Symbol) return Object_Symbol;
320   --  Return the element following Prev in the symbol table, or Null_Symbol if
321   --  Prev is the last symbol in the table.
322
323   function Read_Symbol
324     (Obj : in out Object_File;
325      Off : Offset) return Object_Symbol;
326   --  Read symbol at Off
327
328   function Name
329     (Obj : in out Object_File;
330      Sym : Object_Symbol) return String_Ptr_Len;
331   --  Return the name of the symbol
332
333   function Decoded_Ada_Name
334     (Obj : in out Object_File;
335      Sym : String_Ptr_Len) return String;
336   --  Return the decoded name of a symbol encoded as per exp_dbug.ads
337
338   function Strip_Leading_Char
339     (Obj : in out Object_File;
340      Sym : String_Ptr_Len) return Positive;
341   --  Return the index of the first character to decode the name. This can
342   --  strip one character for ABI with a prefix (like x86 for PECOFF).
343
344   function Value (Sym : Object_Symbol) return uint64;
345   --  Return the name of the symbol
346
347   function Size (Sym : Object_Symbol) return uint64;
348   --  Return the size of the symbol in bytes
349
350   function Spans (Sym : Object_Symbol; Addr : uint64) return Boolean;
351   --  Determine whether a particular address corresponds to the range
352   --  referenced by this symbol.
353
354   function Off (Sym : Object_Symbol) return Offset;
355   --  Return the offset of the symbol.
356
357   ----------------
358   -- Exceptions --
359   ----------------
360
361   IO_Error : exception;
362   --  Input/Output error reading file
363
364   Format_Error : exception;
365   --  Encountered a problem parsing the object
366
367private
368   type Mapped_Stream is record
369      Region : System.Mmap.Mapped_Region;
370      Off    : Offset;
371      Len    : Offset;
372   end record;
373
374   subtype ELF is Object_Format range ELF32 .. ELF64;
375   subtype Any_PECOFF is Object_Format range PECOFF .. PECOFF_PLUS;
376
377   type Object_File (Format : Object_Format) is record
378      Mf           : System.Mmap.Mapped_File :=
379                        System.Mmap.Invalid_Mapped_File;
380      Arch         : Object_Arch := Unknown;
381
382      Num_Sections : uint32 := 0;
383      --  Number of sections
384
385      Symtab_Last : Offset;       --  Last offset of symbol table
386
387      In_Exception : Boolean := False;
388      --  True if the parsing is done as part of an exception handler
389
390      Sectab_Stream : Mapped_Stream;
391      --  Section table
392
393      Symtab_Stream : Mapped_Stream;
394      --  Symbol table
395
396      Symstr_Stream : Mapped_Stream;
397      --  Symbol strings
398
399      case Format is
400         when ELF =>
401            Secstr_Stream : Mapped_Stream;
402            --  Section strings
403         when Any_PECOFF =>
404            ImageBase   : uint64;       --  ImageBase value from header
405
406            --  Cache for latest result of Get_Section_Virtual_Address
407
408            GSVA_Sec  : uint32 := uint32'Last;
409            GSVA_Addr : uint64;
410         when XCOFF32 =>
411            null;
412      end case;
413   end record;
414
415   subtype ELF_Object_File is Object_File; -- with
416   --  Predicate => ELF_Object_File.Format in ELF;
417   subtype PECOFF_Object_File is Object_File; -- with
418   --  Predicate => PECOFF_Object_File.Format in Any_PECOFF;
419   subtype XCOFF32_Object_File is Object_File; -- with
420   --  Predicate => XCOFF32_Object_File.Format in XCOFF32;
421   --  ???Above predicates cause the compiler to crash when instantiating
422   --  ELF64_Ops (see package body).
423
424   type Object_Section is record
425      Num        : uint32 := 0;
426      --  Section index in the section table
427
428      Off        : Offset := 0;
429      --  First byte of the section in the object file
430
431      Addr       : uint64 := 0;
432      --  Load address of the section. Valid only when Flag_Alloc is true.
433
434      Size       : uint64 := 0;
435      --  Length of the section in bytes
436
437      Flag_Alloc : Boolean := False;
438      --  True if the section is mapped in memory by the OS loader
439   end record;
440
441   Null_Section : constant Object_Section := (0, 0, 0, 0, False);
442
443   type Object_Symbol is record
444      Off   : Offset := 0;  --  Offset of underlying symbol on disk
445      Next  : Offset := 0;  --  Offset of the following symbol
446      Value : uint64 := 0;  --  Value associated with this symbol
447      Size  : uint64 := 0;  --  Size of the referenced entity
448   end record;
449
450   Null_Symbol : constant Object_Symbol := (0, 0, 0, 0);
451end System.Object_Reader;
452