1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- S Y S T E M . O B J E C T _ R E A D E R --
9 -- Copyright (C) 2009-2024, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 -- This package implements a simple, minimal overhead reader for object files
33 -- composed of sections of untyped heterogeneous binary data.
38 package System
.Object_Reader
is
44 BUFFER_SIZE
: constant := 8 * 1024;
48 ----------------------
50 type Object_Section
is private;
52 Null_Section
: constant Object_Section
;
58 type Object_Symbol
is private;
60 ------------------------
61 -- Object format type --
62 ------------------------
66 -- Object format is 32-bit ELF
69 -- Object format is 64-bit ELF
72 -- Object format is Microsoft PECOFF
75 -- Object format is Microsoft PECOFF+
78 -- Object format is AIX 32-bit XCOFF
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 ???
87 type Object_File
(Format
: Object_Format
) is private;
89 type Object_File_Access
is access Object_File
;
91 ------------------------------
92 -- Object architecture type --
93 ------------------------------
97 -- The target architecture has not yet been determined
109 -- MIPS Technologies MIPS
112 -- x86-64 (64-bit AMD/Intel)
133 subtype Offset
is Interfaces
.Integer_64
;
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
;
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
;
145 type Buffer
is array (0 .. BUFFER_SIZE
- 1) of uint8
;
147 type String_Ptr_Len
is record
148 Ptr
: Mmap
.Str_Access
;
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.
154 -------------------------------------------
155 -- Operations on buffers of untyped data --
156 -------------------------------------------
158 function To_String
(Buf
: Buffer
) return String;
159 -- Construct string from C style null-terminated string stored in a buffer
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.
166 function Strlen
(Buf
: Buffer
) return int32
;
167 -- Return the length of a C style null-terminated string
169 -------------------------
170 -- Opening and closing --
171 -------------------------
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.
180 procedure Close
(Obj
: in out Object_File
);
181 -- Close the object file
183 -----------------------
184 -- Sequential access --
185 -----------------------
187 type Mapped_Stream
is private;
188 -- Provide an abstraction of a stream on a memory mapped file
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
196 procedure Close
(S
: in out Mapped_Stream
);
197 -- Close the stream (deallocate memory)
200 (S
: in out Mapped_Stream
;
203 pragma Inline
(Read_Raw
);
204 -- Read a number of fixed sized records
206 procedure Seek
(S
: in out Mapped_Stream
; Off
: Offset
);
207 -- Seek to an absolute offset in bytes
209 procedure Tell
(Obj
: in out Mapped_Stream
; Off
: out Offset
)
211 function Tell
(Obj
: Mapped_Stream
) return Offset
213 -- Fetch the current offset
215 function Length
(Obj
: Mapped_Stream
) return Offset
217 -- Length of the stream
219 function Read
(S
: in out Mapped_Stream
) return Mmap
.Str_Access
;
220 -- Provide a pointer in memory at the current offset
222 function Read
(S
: in out Mapped_Stream
) return String_Ptr_Len
;
223 -- Provide a pointer in memory at the current offset
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
;
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.
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
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
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.
254 ------------------------
255 -- Object information --
256 ------------------------
258 function Arch
(Obj
: Object_File
) return Object_Arch
;
259 -- Return the object architecture
261 function Format
(Obj
: Object_File
) return Object_Format
;
262 -- Return the object file format
264 function Get_Load_Address
(Obj
: Object_File
) return uint64
;
265 -- Return the load address defined in Obj. May raise Format_Error if not
268 function Num_Sections
(Obj
: Object_File
) return uint32
;
269 -- Return the number of sections composing the object file
272 (Obj
: in out Object_File
;
273 Shnum
: uint32
) return Object_Section
;
274 -- Return the Nth section (numbered from zero)
277 (Obj
: in out Object_File
;
278 Sec_Name
: String) return Object_Section
;
279 -- Return a section by name
281 function Create_Stream
283 Sec
: Object_Section
) return Mapped_Stream
;
284 -- Create a stream for section Sec
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
294 -------------------------
295 -- Section information --
296 -------------------------
299 (Obj
: in out Object_File
;
300 Sec
: Object_Section
) return String;
301 -- Return the name of a section as a string
303 function Size
(Sec
: Object_Section
) return uint64
;
304 -- Return the size of a section in bytes
306 function Num
(Sec
: Object_Section
) return uint32
;
307 -- Return the index of a section from zero
309 function Off
(Sec
: Object_Section
) return Offset
;
310 -- Return the byte offset of the section within the object
312 ------------------------------
313 -- Symbol table information --
314 ------------------------------
316 Null_Symbol
: constant Object_Symbol
;
317 -- An empty symbol table entry.
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.
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.
330 (Obj
: in out Object_File
;
331 Off
: Offset
) return Object_Symbol
;
332 -- Read symbol at Off
335 (Obj
: in out Object_File
;
336 Sym
: Object_Symbol
) return String_Ptr_Len
;
337 -- Return the name of the symbol
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
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).
350 function Value
(Sym
: Object_Symbol
) return uint64
;
351 -- Return the name of the symbol
353 function Size
(Sym
: Object_Symbol
) return uint64
;
354 -- Return the size of the symbol in bytes
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.
360 function Off
(Sym
: Object_Symbol
) return Offset
;
361 -- Return the offset of the symbol.
367 IO_Error
: exception;
368 -- Input/Output error reading file
370 Format_Error
: exception;
371 -- Encountered a problem parsing the object
374 type Mapped_Stream
is record
375 Region
: System
.Mmap
.Mapped_Region
;
380 subtype ELF
is Object_Format
range ELF32
.. ELF64
;
381 subtype Any_PECOFF
is Object_Format
range PECOFF
.. PECOFF_PLUS
;
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
;
387 Num_Sections
: uint32
:= 0;
388 -- Number of sections
390 Symtab_Last
: Offset
; -- Last offset of symbol table
392 In_Exception
: Boolean := False;
393 -- True if the parsing is done as part of an exception handler
395 Sectab_Stream
: Mapped_Stream
;
398 Symtab_Stream
: Mapped_Stream
;
401 Symstr_Stream
: Mapped_Stream
;
406 Secstr_Stream
: Mapped_Stream
;
410 ImageBase
: uint64
; -- ImageBase value from header
412 -- Cache for latest result of Get_Section_Virtual_Address
414 GSVA_Sec
: uint32
:= uint32
'Last;
422 subtype ELF_Object_File
is Object_File
423 with Predicate
=> ELF_Object_File
.Format
in ELF
;
425 subtype PECOFF_Object_File
is Object_File
426 with Predicate
=> PECOFF_Object_File
.Format
in Any_PECOFF
;
428 subtype XCOFF32_Object_File
is Object_File
429 with Predicate
=> XCOFF32_Object_File
.Format
in XCOFF32
;
431 type Object_Section
is record
433 -- Section index in the section table
436 -- First byte of the section in the object file
439 -- Load address of the section. Valid only when Flag_Alloc is true.
442 -- Length of the section in bytes
444 Flag_Xcode
: Boolean := False;
445 -- True if the section is advertised to contain executable code
448 Null_Section
: constant Object_Section
:= (0, 0, 0, 0, False);
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
457 Null_Symbol
: constant Object_Symbol
:= (0, 0, 0, 0);
458 end System
.Object_Reader
;