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-2020, 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 sections --
48   ----------------------
49
50   type Object_Section is private;
51
52   Null_Section : constant Object_Section;
53
54   --------------------
55   -- Object symbols --
56   --------------------
57
58   type Object_Symbol is private;
59
60   ------------------------
61   -- Object format type --
62   ------------------------
63
64   type Object_Format is
65     (ELF32,
66      --  Object format is 32-bit ELF
67
68      ELF64,
69      --  Object format is 64-bit ELF
70
71      PECOFF,
72      --  Object format is Microsoft PECOFF
73
74      PECOFF_PLUS,
75      --  Object format is Microsoft PECOFF+
76
77      XCOFF32);
78      --  Object format is AIX 32-bit XCOFF
79
80   --  PECOFF | PECOFF_PLUS appears so often as a case choice, would
81   --  seem a good idea to have a subtype name covering these two choices ???
82
83   ------------------
84   -- Object files --
85   ------------------
86
87   type Object_File (Format : Object_Format) is private;
88
89   type Object_File_Access is access Object_File;
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      ARM);
124      --  32-bit ARM
125
126   ------------------
127   -- Target types --
128   ------------------
129
130   subtype Offset is Interfaces.Integer_64;
131
132   subtype uint8  is Interfaces.Unsigned_8;
133   subtype uint16 is Interfaces.Unsigned_16;
134   subtype uint32 is Interfaces.Unsigned_32;
135   subtype uint64 is Interfaces.Unsigned_64;
136
137   subtype int8  is Interfaces.Integer_8;
138   subtype int16 is Interfaces.Integer_16;
139   subtype int32 is Interfaces.Integer_32;
140   subtype int64 is Interfaces.Integer_64;
141
142   type Buffer is array (0 .. BUFFER_SIZE - 1) of uint8;
143
144   type String_Ptr_Len is record
145      Ptr : Mmap.Str_Access;
146      Len : Natural;
147   end record;
148   --  A string made from a pointer and a length. Not all strings for name
149   --  are C strings: COFF inlined symbol names have a max length of 8.
150
151   -------------------------------------------
152   -- Operations on buffers of untyped data --
153   -------------------------------------------
154
155   function To_String (Buf : Buffer) return String;
156   --  Construct string from C style null-terminated string stored in a buffer
157
158   function To_String_Ptr_Len
159     (Ptr : Mmap.Str_Access;
160      Max_Len : Natural := Natural'Last) return String_Ptr_Len;
161   --  Convert PTR to a String_Ptr_Len.
162
163   function Strlen (Buf : Buffer) return int32;
164   --  Return the length of a C style null-terminated string
165
166   -------------------------
167   -- Opening and closing --
168   -------------------------
169
170   function Open
171     (File_Name    : String;
172      In_Exception : Boolean := False) return Object_File_Access;
173   --  Open the object file and initialize the reader. In_Exception is true
174   --  when the parsing is done as part of an exception handler decorator. In
175   --  this mode we do not want to raise an exception.
176
177   procedure Close (Obj : in out Object_File);
178   --  Close the object file
179
180   -----------------------
181   -- Sequential access --
182   -----------------------
183
184   type Mapped_Stream is private;
185   --  Provide an abstraction of a stream on a memory mapped file
186
187   function Create_Stream (Mf : System.Mmap.Mapped_File;
188                           File_Offset : System.Mmap.File_Size;
189                           File_Length : System.Mmap.File_Size)
190                          return Mapped_Stream;
191   --  Create a stream from Mf
192
193   procedure Close (S : in out Mapped_Stream);
194   --  Close the stream (deallocate memory)
195
196   procedure Read_Raw
197     (S   : in out Mapped_Stream;
198      Addr  : Address;
199      Size  : uint32);
200   pragma Inline (Read_Raw);
201   --  Read a number of fixed sized records
202
203   procedure Seek (S : in out Mapped_Stream; Off : Offset);
204   --  Seek to an absolute offset in bytes
205
206   procedure Tell (Obj : in out Mapped_Stream; Off : out Offset)
207     with Inline;
208   function Tell (Obj : Mapped_Stream) return Offset
209     with Inline;
210   --  Fetch the current offset
211
212   function Length (Obj : Mapped_Stream) return Offset
213     with Inline;
214   --  Length of the stream
215
216   function Read (S : in out Mapped_Stream) return Mmap.Str_Access;
217   --  Provide a pointer in memory at the current offset
218
219   function Read (S : in out Mapped_Stream) return String_Ptr_Len;
220   --  Provide a pointer in memory at the current offset
221
222   function Read (S : in out Mapped_Stream) return uint8;
223   function Read (S : in out Mapped_Stream) return uint16;
224   function Read (S : in out Mapped_Stream) return uint32;
225   function Read (S : in out Mapped_Stream) return uint64;
226   function Read (S : in out Mapped_Stream) return int8;
227   function Read (S : in out Mapped_Stream) return int16;
228   function Read (S : in out Mapped_Stream) return int32;
229   function Read (S : in out Mapped_Stream) return int64;
230   --  Read a scalar
231
232   function Read_Address
233     (Obj : Object_File; S : in out Mapped_Stream) return uint64;
234   --  Read either a 64 or 32 bit address from the file stream depending on the
235   --  address size of the target architecture and promote it to a 64 bit type.
236
237   function Read_LEB128 (S : in out Mapped_Stream) return uint32;
238   function Read_LEB128 (S : in out Mapped_Stream) return int32;
239   --  Read a value encoding in Little-Endian Base 128 format
240
241   procedure Read_C_String (S : in out Mapped_Stream; B : out Buffer);
242   function Read_C_String (S : in out Mapped_Stream) return Mmap.Str_Access;
243   --  Read a C style NULL terminated string
244
245   function Offset_To_String
246     (S : in out Mapped_Stream;
247      Off : Offset) return String;
248   --  Construct a string from a C style NULL terminated string located at an
249   --  offset into the object file.
250
251   ------------------------
252   -- Object information --
253   ------------------------
254
255   function Arch (Obj : Object_File) return Object_Arch;
256   --  Return the object architecture
257
258   function Format (Obj : Object_File) return Object_Format;
259   --  Return the object file format
260
261   function Get_Load_Address (Obj : Object_File) return uint64;
262   --  Return the load address defined in Obj. May raise Format_Error if not
263   --  implemented
264
265   function Num_Sections (Obj : Object_File) return uint32;
266   --  Return the number of sections composing the object file
267
268   function Get_Section
269     (Obj   : in out Object_File;
270      Shnum : uint32) return Object_Section;
271   --  Return the Nth section (numbered from zero)
272
273   function Get_Section
274     (Obj      : in out Object_File;
275      Sec_Name : String) return Object_Section;
276   --  Return a section by name
277
278   function Create_Stream
279     (Obj : Object_File;
280      Sec : Object_Section) return Mapped_Stream;
281   --  Create a stream for section Sec
282
283   procedure Get_Xcode_Bounds
284     (Obj   : in out Object_File;
285      Low, High : out uint64);
286   --  Return the low and high addresses of the code for the object file. Can
287   --  be used to check if an address lies within this object file. This
288   --  procedure is not efficient and the result should be saved to avoid
289   --  recomputation.
290
291   -------------------------
292   -- Section information --
293   -------------------------
294
295   function Name
296     (Obj : in out Object_File;
297      Sec : Object_Section) return String;
298   --  Return the name of a section as a string
299
300   function Size (Sec : Object_Section) return uint64;
301   --  Return the size of a section in bytes
302
303   function Num (Sec : Object_Section) return uint32;
304   --  Return the index of a section from zero
305
306   function Off (Sec : Object_Section) return Offset;
307   --  Return the byte offset of the section within the object
308
309   ------------------------------
310   -- Symbol table information --
311   ------------------------------
312
313   Null_Symbol : constant Object_Symbol;
314   --  An empty symbol table entry.
315
316   function First_Symbol (Obj : in out Object_File) return Object_Symbol;
317   --  Return the first element in the symbol table or Null_Symbol if the
318   --  symbol table is empty.
319
320   function Next_Symbol
321     (Obj  : in out Object_File;
322      Prev : Object_Symbol) return Object_Symbol;
323   --  Return the element following Prev in the symbol table, or Null_Symbol if
324   --  Prev is the last symbol in the table.
325
326   function Read_Symbol
327     (Obj : in out Object_File;
328      Off : Offset) return Object_Symbol;
329   --  Read symbol at Off
330
331   function Name
332     (Obj : in out Object_File;
333      Sym : Object_Symbol) return String_Ptr_Len;
334   --  Return the name of the symbol
335
336   function Decoded_Ada_Name
337     (Obj : in out Object_File;
338      Sym : String_Ptr_Len) return String;
339   --  Return the decoded name of a symbol encoded as per exp_dbug.ads
340
341   function Strip_Leading_Char
342     (Obj : in out Object_File;
343      Sym : String_Ptr_Len) return Positive;
344   --  Return the index of the first character to decode the name. This can
345   --  strip one character for ABI with a prefix (like x86 for PECOFF).
346
347   function Value (Sym : Object_Symbol) return uint64;
348   --  Return the name of the symbol
349
350   function Size (Sym : Object_Symbol) return uint64;
351   --  Return the size of the symbol in bytes
352
353   function Spans (Sym : Object_Symbol; Addr : uint64) return Boolean;
354   --  Determine whether a particular address corresponds to the range
355   --  referenced by this symbol.
356
357   function Off (Sym : Object_Symbol) return Offset;
358   --  Return the offset of the symbol.
359
360   ----------------
361   -- Exceptions --
362   ----------------
363
364   IO_Error : exception;
365   --  Input/Output error reading file
366
367   Format_Error : exception;
368   --  Encountered a problem parsing the object
369
370private
371   type Mapped_Stream is record
372      Region : System.Mmap.Mapped_Region;
373      Off    : Offset;
374      Len    : Offset;
375   end record;
376
377   subtype ELF is Object_Format range ELF32 .. ELF64;
378   subtype Any_PECOFF is Object_Format range PECOFF .. PECOFF_PLUS;
379
380   type Object_File (Format : Object_Format) is record
381      Mf   : System.Mmap.Mapped_File := System.Mmap.Invalid_Mapped_File;
382      Arch : Object_Arch := Unknown;
383
384      Num_Sections : uint32 := 0;
385      --  Number of sections
386
387      Symtab_Last : Offset;       --  Last offset of symbol table
388
389      In_Exception : Boolean := False;
390      --  True if the parsing is done as part of an exception handler
391
392      Sectab_Stream : Mapped_Stream;
393      --  Section table
394
395      Symtab_Stream : Mapped_Stream;
396      --  Symbol table
397
398      Symstr_Stream : Mapped_Stream;
399      --  Symbol strings
400
401      case Format is
402         when ELF =>
403            Secstr_Stream : Mapped_Stream;
404            --  Section strings
405
406         when Any_PECOFF =>
407            ImageBase   : uint64;       --  ImageBase value from header
408
409            --  Cache for latest result of Get_Section_Virtual_Address
410
411            GSVA_Sec  : uint32 := uint32'Last;
412            GSVA_Addr : uint64;
413
414         when XCOFF32 =>
415            null;
416      end case;
417   end record;
418
419   subtype ELF_Object_File is Object_File
420     with Predicate => ELF_Object_File.Format in ELF;
421
422   subtype PECOFF_Object_File is Object_File
423     with Predicate => PECOFF_Object_File.Format in Any_PECOFF;
424
425   subtype XCOFF32_Object_File is Object_File
426     with Predicate => XCOFF32_Object_File.Format in XCOFF32;
427
428   type Object_Section is record
429      Num        : uint32 := 0;
430      --  Section index in the section table
431
432      Off        : Offset := 0;
433      --  First byte of the section in the object file
434
435      Addr       : uint64 := 0;
436      --  Load address of the section. Valid only when Flag_Alloc is true.
437
438      Size       : uint64 := 0;
439      --  Length of the section in bytes
440
441      Flag_Xcode : Boolean := False;
442      --  True if the section is advertised to contain executable code
443   end record;
444
445   Null_Section : constant Object_Section := (0, 0, 0, 0, False);
446
447   type Object_Symbol is record
448      Off   : Offset := 0;  --  Offset of underlying symbol on disk
449      Next  : Offset := 0;  --  Offset of the following symbol
450      Value : uint64 := 0;  --  Value associated with this symbol
451      Size  : uint64 := 0;  --  Size of the referenced entity
452   end record;
453
454   Null_Symbol : constant Object_Symbol := (0, 0, 0, 0);
455end System.Object_Reader;
456