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