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 with Ada
.Unchecked_Conversion
;
38 package body System
.Object_Reader
is
44 SSU
: constant := System
.Storage_Unit
;
46 function To_int32
is new Ada
.Unchecked_Conversion
(uint32
, int32
);
48 function Trim_Trailing_Nuls
(Str
: String) return String;
49 -- Return a copy of a string with any trailing NUL characters truncated
51 procedure Check_Read_Offset
(S
: Mapped_Stream
; Size
: uint32
);
52 -- Check that the SIZE bytes at the current offset are still in the stream
54 -------------------------------------
55 -- ELF object file format handling --
56 -------------------------------------
65 ELFCLASS32
: constant := 1; -- 32 bit ELF
66 ELFCLASS64
: constant := 2; -- 64 bit ELF
70 EM_NONE
: constant := 0; -- No machine
71 EM_SPARC
: constant := 2; -- SUN SPARC
72 EM_386
: constant := 3; -- Intel 80386
73 EM_MIPS
: constant := 8; -- MIPS RS3000 Big-Endian
74 EM_MIPS_RS3_LE
: constant := 10; -- MIPS RS3000 Little-Endian
75 EM_SPARC32PLUS
: constant := 18; -- Sun SPARC 32+
76 EM_PPC
: constant := 20; -- PowerPC
77 EM_PPC64
: constant := 21; -- PowerPC 64-bit
78 EM_ARM
: constant := 40; -- ARM
79 EM_SPARCV9
: constant := 43; -- SPARC v9 64-bit
80 EM_IA_64
: constant := 50; -- Intel Merced
81 EM_X86_64
: constant := 62; -- AMD x86-64 architecture
82 EM_AARCH64
: constant := 183; -- Aarch64
84 EN_NIDENT
: constant := 16;
86 type E_Ident_Type
is array (0 .. EN_NIDENT
- 1) of uint8
;
89 E_Ident
: E_Ident_Type
; -- Magic number and other info
90 E_Type
: uint16
; -- Object file type
91 E_Machine
: uint16
; -- Architecture
92 E_Version
: uint32
; -- Object file version
93 E_Entry
: uword
; -- Entry point virtual address
94 E_Phoff
: uword
; -- Program header table file offset
95 E_Shoff
: uword
; -- Section header table file offset
96 E_Flags
: uint32
; -- Processor-specific flags
97 E_Ehsize
: uint16
; -- ELF header size in bytes
98 E_Phentsize
: uint16
; -- Program header table entry size
99 E_Phnum
: uint16
; -- Program header table entry count
100 E_Shentsize
: uint16
; -- Section header table entry size
101 E_Shnum
: uint16
; -- Section header table entry count
102 E_Shstrndx
: uint16
; -- Section header string table index
105 type Section_Header
is record
106 Sh_Name
: uint32
; -- Section name string table index
107 Sh_Type
: uint32
; -- Section type
108 Sh_Flags
: uword
; -- Section flags
109 Sh_Addr
: uword
; -- Section virtual addr at execution
110 Sh_Offset
: uword
; -- Section file offset
111 Sh_Size
: uword
; -- Section size in bytes
112 Sh_Link
: uint32
; -- Link to another section
113 Sh_Info
: uint32
; -- Additional section information
114 Sh_Addralign
: uword
; -- Section alignment
115 Sh_Entsize
: uword
; -- Entry size if section holds table
118 SHF_ALLOC
: constant := 2;
119 SHF_EXECINSTR
: constant := 4;
121 type Symtab_Entry32
is record
122 St_Name
: uint32
; -- Name (string table index)
123 St_Value
: uint32
; -- Value
124 St_Size
: uint32
; -- Size in bytes
125 St_Info
: uint8
; -- Type and binding attributes
126 St_Other
: uint8
; -- Undefined
127 St_Shndx
: uint16
; -- Defining section
130 type Symtab_Entry64
is record
131 St_Name
: uint32
; -- Name (string table index)
132 St_Info
: uint8
; -- Type and binding attributes
133 St_Other
: uint8
; -- Undefined
134 St_Shndx
: uint16
; -- Defining section
135 St_Value
: uint64
; -- Value
136 St_Size
: uint64
; -- Size in bytes
139 function Read_Header
(F
: in out Mapped_Stream
) return Header
;
140 -- Read a header from an ELF format object
142 function First_Symbol
143 (Obj
: in out ELF_Object_File
) return Object_Symbol
;
144 -- Return the first element in the symbol table, or Null_Symbol if the
145 -- symbol table is empty.
148 (Obj
: in out ELF_Object_File
;
149 Off
: Offset
) return Object_Symbol
;
150 -- Read a symbol at offset Off
153 (Obj
: in out ELF_Object_File
;
154 Sym
: Object_Symbol
) return String_Ptr_Len
;
155 -- Return the name of the symbol
158 (Obj
: in out ELF_Object_File
;
159 Sec
: Object_Section
) return String;
160 -- Return the name of a section
163 (Obj
: in out ELF_Object_File
;
164 Shnum
: uint32
) return Object_Section
;
165 -- Fetch a section by index from zero
170 In_Exception
: Boolean) return ELF_Object_File
;
171 -- Initialize an object file
175 -----------------------------------
176 -- PECOFF object format handling --
177 -----------------------------------
179 package PECOFF_Ops
is
181 -- Constants and data layout are taken from the document "Microsoft
182 -- Portable Executable and Common Object File Format Specification"
185 Signature_Loc_Offset
: constant := 16#
3C#
;
186 -- Offset of pointer to the file signature
188 Size_Of_Standard_Header_Fields
: constant := 16#
18#
;
189 -- Length in bytes of the standard header record
191 Function_Symbol_Type
: constant := 16#
20#
;
192 -- Type field value indicating a symbol refers to a function
194 Not_Function_Symbol_Type
: constant := 16#
00#
;
195 -- Type field value indicating a symbol does not refer to a function
197 type Magic_Array
is array (0 .. 3) of uint8
;
198 -- Array of magic numbers from the header
200 -- Magic numbers for PECOFF variants
202 VARIANT_PE32
: constant := 16#
010B#
;
203 VARIANT_PE32_PLUS
: constant := 16#
020B#
;
205 -- PECOFF machine codes
207 IMAGE_FILE_MACHINE_I386
: constant := 16#
014C#
;
208 IMAGE_FILE_MACHINE_IA64
: constant := 16#
0200#
;
209 IMAGE_FILE_MACHINE_AMD64
: constant := 16#
8664#
;
211 -- PECOFF Data layout
213 type Header
is record
214 Magics
: Magic_Array
;
216 NumberOfSections
: uint16
;
217 TimeDateStamp
: uint32
;
218 PointerToSymbolTable
: uint32
;
219 NumberOfSymbols
: uint32
;
220 SizeOfOptionalHeader
: uint16
;
221 Characteristics
: uint16
;
224 pragma Pack
(Header
);
226 type Optional_Header_PE32
is record
228 MajorLinkerVersion
: uint8
;
229 MinorLinkerVersion
: uint8
;
231 SizeOfInitializedData
: uint32
;
232 SizeOfUninitializedData
: uint32
;
233 AddressOfEntryPoint
: uint32
;
235 BaseOfData
: uint32
; -- Note: not in PE32+
237 SectionAlignment
: uint32
;
238 FileAlignment
: uint32
;
239 MajorOperatingSystemVersion
: uint16
;
240 MinorOperationSystemVersion
: uint16
;
241 MajorImageVersion
: uint16
;
242 MinorImageVersion
: uint16
;
243 MajorSubsystemVersion
: uint16
;
244 MinorSubsystemVersion
: uint16
;
245 Win32VersionValue
: uint32
;
246 SizeOfImage
: uint32
;
247 SizeOfHeaders
: uint32
;
250 DllCharacteristics
: uint16
;
251 SizeOfStackReserve
: uint32
;
252 SizeOfStackCommit
: uint32
;
253 SizeOfHeapReserve
: uint32
;
254 SizeOfHeapCommit
: uint32
;
255 LoaderFlags
: uint32
;
256 NumberOfRvaAndSizes
: uint32
;
258 pragma Pack
(Optional_Header_PE32
);
259 pragma Assert
(Optional_Header_PE32
'Size = 96 * SSU
);
261 type Optional_Header_PE64
is record
263 MajorLinkerVersion
: uint8
;
264 MinorLinkerVersion
: uint8
;
266 SizeOfInitializedData
: uint32
;
267 SizeOfUninitializedData
: uint32
;
268 AddressOfEntryPoint
: uint32
;
271 SectionAlignment
: uint32
;
272 FileAlignment
: uint32
;
273 MajorOperatingSystemVersion
: uint16
;
274 MinorOperationSystemVersion
: uint16
;
275 MajorImageVersion
: uint16
;
276 MinorImageVersion
: uint16
;
277 MajorSubsystemVersion
: uint16
;
278 MinorSubsystemVersion
: uint16
;
279 Win32VersionValue
: uint32
;
280 SizeOfImage
: uint32
;
281 SizeOfHeaders
: uint32
;
284 DllCharacteristics
: uint16
;
285 SizeOfStackReserve
: uint64
;
286 SizeOfStackCommit
: uint64
;
287 SizeOfHeapReserve
: uint64
;
288 SizeOfHeapCommit
: uint64
;
289 LoaderFlags
: uint32
;
290 NumberOfRvaAndSizes
: uint32
;
292 pragma Pack
(Optional_Header_PE64
);
293 pragma Assert
(Optional_Header_PE64
'Size = 112 * SSU
);
295 subtype Name_Str
is String (1 .. 8);
297 type Section_Header
is record
299 VirtualSize
: uint32
;
300 VirtualAddress
: uint32
;
301 SizeOfRawData
: uint32
;
302 PointerToRawData
: uint32
;
303 PointerToRelocations
: uint32
;
304 PointerToLinenumbers
: uint32
;
305 NumberOfRelocations
: uint16
;
306 NumberOfLinenumbers
: uint16
;
307 Characteristics
: uint32
;
309 pragma Pack
(Section_Header
);
311 IMAGE_SCN_CNT_CODE
: constant := 16#
0020#
;
313 type Symtab_Entry
is record
316 SectionNumber
: int16
;
318 StorageClass
: uint8
;
319 NumberOfAuxSymbols
: uint8
;
321 pragma Pack
(Symtab_Entry
);
323 type Auxent_Section
is record
325 NumberOfRelocations
: uint16
;
326 NumberOfLinenumbers
: uint16
;
335 for Auxent_Section
'Size use 18 * 8;
337 function Read_Header
(F
: in out Mapped_Stream
) return Header
;
338 -- Read the object file header
340 function First_Symbol
341 (Obj
: in out PECOFF_Object_File
) return Object_Symbol
;
342 -- Return the first element in the symbol table, or Null_Symbol if the
343 -- symbol table is empty.
346 (Obj
: in out PECOFF_Object_File
;
347 Off
: Offset
) return Object_Symbol
;
348 -- Read a symbol at offset Off
351 (Obj
: in out PECOFF_Object_File
;
352 Sym
: Object_Symbol
) return String_Ptr_Len
;
353 -- Return the name of the symbol
356 (Obj
: in out PECOFF_Object_File
;
357 Sec
: Object_Section
) return String;
358 -- Return the name of a section
361 (Obj
: in out PECOFF_Object_File
;
362 Index
: uint32
) return Object_Section
;
363 -- Fetch a section by index from zero
368 In_Exception
: Boolean) return PECOFF_Object_File
;
369 -- Initialize an object file
373 -------------------------------------
374 -- XCOFF-32 object format handling --
375 -------------------------------------
377 package XCOFF32_Ops
is
381 type Header
is record
391 type Auxiliary_Header
is record
398 o_text_start
: uint32
;
399 o_data_start
: uint32
;
419 pragma Unreferenced
(Auxiliary_Header
);
420 -- Not used, but not removed (just in case)
422 subtype Name_Str
is String (1 .. 8);
424 type Section_Header
is record
436 pragma Pack
(Section_Header
);
438 STYP_TEXT
: constant := 16#
0020#
;
440 type Symbol_Entry
is record
448 for Symbol_Entry
'Size use 18 * 8;
450 type Aux_Entry
is record
459 for Aux_Entry
'Size use 18 * 8;
460 pragma Pack
(Aux_Entry
);
462 C_EXT
: constant := 2;
463 C_HIDEXT
: constant := 107;
464 C_WEAKEXT
: constant := 111;
466 XTY_LD
: constant := 2;
467 -- Magic constant should be documented, especially since it's changed???
469 function Read_Header
(F
: in out Mapped_Stream
) return Header
;
470 -- Read the object file header
472 function First_Symbol
473 (Obj
: in out XCOFF32_Object_File
) return Object_Symbol
;
474 -- Return the first element in the symbol table, or Null_Symbol if the
475 -- symbol table is empty.
478 (Obj
: in out XCOFF32_Object_File
;
479 Off
: Offset
) return Object_Symbol
;
480 -- Read a symbol at offset Off
483 (Obj
: in out XCOFF32_Object_File
;
484 Sym
: Object_Symbol
) return String_Ptr_Len
;
485 -- Return the name of the symbol
488 (Obj
: in out XCOFF32_Object_File
;
489 Sec
: Object_Section
) return String;
490 -- Return the name of a section
495 In_Exception
: Boolean) return XCOFF32_Object_File
;
496 -- Initialize an object file
499 (Obj
: in out XCOFF32_Object_File
;
500 Index
: uint32
) return Object_Section
;
501 -- Fetch a section by index from zero
509 package body ELF_Ops
is
511 function Get_String_Table
(Obj
: in out ELF_Object_File
)
512 return Object_Section
;
513 -- Fetch the section containing the string table
515 function Get_Symbol_Table
(Obj
: in out ELF_Object_File
)
516 return Object_Section
;
517 -- Fetch the section containing the symbol table
519 function Read_Section_Header
520 (Obj
: in out ELF_Object_File
;
521 Shnum
: uint32
) return Section_Header
;
522 -- Read the header for an ELF format object section indexed from zero
528 function First_Symbol
529 (Obj
: in out ELF_Object_File
) return Object_Symbol
532 if Obj
.Symtab_Last
= 0 then
535 return Read_Symbol
(Obj
, 0);
544 (Obj
: in out ELF_Object_File
;
545 Shnum
: uint32
) return Object_Section
547 SHdr
: constant Section_Header
:= Read_Section_Header
(Obj
, Shnum
);
551 Offset
(SHdr
.Sh_Offset
),
552 uint64
(SHdr
.Sh_Addr
),
553 uint64
(SHdr
.Sh_Size
),
554 (SHdr
.Sh_Flags
and SHF_EXECINSTR
) /= 0);
557 ------------------------
558 -- Get_String_Table --
559 ------------------------
561 function Get_String_Table
562 (Obj
: in out ELF_Object_File
) return Object_Section
565 -- All cases except MIPS IRIX, string table located in .strtab
567 if Obj
.Arch
/= MIPS
then
568 return Get_Section
(Obj
, ".strtab");
570 -- On IRIX only .dynstr is available
573 return Get_Section
(Obj
, ".dynstr");
575 end Get_String_Table
;
577 ------------------------
578 -- Get_Symbol_Table --
579 ------------------------
581 function Get_Symbol_Table
582 (Obj
: in out ELF_Object_File
) return Object_Section
585 -- All cases except MIPS IRIX, symbol table located in .symtab
587 if Obj
.Arch
/= MIPS
then
588 return Get_Section
(Obj
, ".symtab");
590 -- On IRIX, symbol table located somewhere other than .symtab
593 return Get_Section
(Obj
, ".dynsym");
595 end Get_Symbol_Table
;
604 In_Exception
: Boolean) return ELF_Object_File
606 Res
: ELF_Object_File
607 (Format
=> (case uword
'Size is
610 when others => raise Program_Error
));
611 Sec
: Object_Section
;
614 Res
.In_Exception
:= In_Exception
;
615 Res
.Num_Sections
:= uint32
(Hdr
.E_Shnum
);
617 case Hdr
.E_Machine
is
653 raise Format_Error
with "unrecognized architecture";
656 -- Map section table and section string table
657 Res
.Sectab_Stream
:= Create_Stream
658 (F
, File_Size
(Hdr
.E_Shoff
),
659 File_Size
(Hdr
.E_Shnum
) * File_Size
(Hdr
.E_Shentsize
));
660 Sec
:= Get_Section
(Res
, uint32
(Hdr
.E_Shstrndx
));
661 Res
.Secstr_Stream
:= Create_Stream
(Res
, Sec
);
663 -- Map symbol and string table
664 Sec
:= Get_Symbol_Table
(Res
);
665 Res
.Symtab_Stream
:= Create_Stream
(Res
, Sec
);
666 Res
.Symtab_Last
:= Offset
(Sec
.Size
);
668 Sec
:= Get_String_Table
(Res
);
669 Res
.Symstr_Stream
:= Create_Stream
(Res
, Sec
);
678 function Read_Header
(F
: in out Mapped_Stream
) return Header
is
683 Read_Raw
(F
, Hdr
'Address, uint32
(Hdr
'Size / SSU
));
687 -------------------------
688 -- Read_Section_Header --
689 -------------------------
691 function Read_Section_Header
692 (Obj
: in out ELF_Object_File
;
693 Shnum
: uint32
) return Section_Header
695 Shdr
: Section_Header
;
698 Seek
(Obj
.Sectab_Stream
, Offset
(Shnum
* Section_Header
'Size / SSU
));
699 Read_Raw
(Obj
.Sectab_Stream
, Shdr
'Address, Section_Header
'Size / SSU
);
701 end Read_Section_Header
;
708 (Obj
: in out ELF_Object_File
;
709 Off
: Offset
) return Object_Symbol
711 ST_Entry32
: Symtab_Entry32
;
712 ST_Entry64
: Symtab_Entry64
;
716 Seek
(Obj
.Symtab_Stream
, Off
);
720 Read_Raw
(Obj
.Symtab_Stream
, ST_Entry32
'Address,
721 uint32
(ST_Entry32
'Size / SSU
));
723 Off
+ ST_Entry32
'Size / SSU
,
724 uint64
(ST_Entry32
.St_Value
),
725 uint64
(ST_Entry32
.St_Size
));
728 Read_Raw
(Obj
.Symtab_Stream
, ST_Entry64
'Address,
729 uint32
(ST_Entry64
'Size / SSU
));
731 Off
+ ST_Entry64
'Size / SSU
,
747 (Obj
: in out ELF_Object_File
;
748 Sec
: Object_Section
) return String
750 SHdr
: Section_Header
;
753 SHdr
:= Read_Section_Header
(Obj
, Sec
.Num
);
754 return Offset_To_String
(Obj
.Secstr_Stream
, Offset
(SHdr
.Sh_Name
));
758 (Obj
: in out ELF_Object_File
;
759 Sym
: Object_Symbol
) return String_Ptr_Len
761 ST_Entry32
: Symtab_Entry32
;
762 ST_Entry64
: Symtab_Entry64
;
766 -- Test that this symbol is not null
768 if Sym
= Null_Symbol
then
772 -- Read the symbol table entry
774 Seek
(Obj
.Symtab_Stream
, Sym
.Off
);
778 Read_Raw
(Obj
.Symtab_Stream
, ST_Entry32
'Address,
779 uint32
(ST_Entry32
'Size / SSU
));
780 Name_Off
:= Offset
(ST_Entry32
.St_Name
);
783 Read_Raw
(Obj
.Symtab_Stream
, ST_Entry64
'Address,
784 uint32
(ST_Entry64
'Size / SSU
));
785 Name_Off
:= Offset
(ST_Entry64
.St_Name
);
791 -- Fetch the name from the string table
793 Seek
(Obj
.Symstr_Stream
, Name_Off
);
794 return Read
(Obj
.Symstr_Stream
);
799 package ELF32_Ops
is new ELF_Ops
(uint32
);
800 package ELF64_Ops
is new ELF_Ops
(uint64
);
806 package body PECOFF_Ops
is
809 (Obj
: in out PECOFF_Object_File
;
810 Raw_Name
: String) return String;
811 -- A section name is an 8 byte field padded on the right with null
812 -- characters, or a '\' followed by an ASCII decimal string indicating
813 -- an offset in to the string table. This routine decodes this
815 function Get_Section_Virtual_Address
816 (Obj
: in out PECOFF_Object_File
;
817 Index
: uint32
) return uint64
;
818 -- Fetch the address at which a section is loaded
820 function Read_Section_Header
821 (Obj
: in out PECOFF_Object_File
;
822 Index
: uint32
) return Section_Header
;
823 -- Read a header from section table
825 function String_Table
826 (Obj
: in out PECOFF_Object_File
;
827 Index
: Offset
) return String;
828 -- Return an entry from the string table
835 (Obj
: in out PECOFF_Object_File
;
836 Raw_Name
: String) return String
838 Name_Or_Ref
: constant String := Trim_Trailing_Nuls
(Raw_Name
);
842 -- We should never find a symbol with a zero length name. If we do it
843 -- probably means we are not parsing the symbol table correctly. If
844 -- this happens we raise a fatal error.
846 if Name_Or_Ref
'Length = 0 then
847 raise Format_Error
with
848 "found zero length symbol in symbol table";
851 if Name_Or_Ref
(1) /= '/' then
854 Off
:= Offset
'Value (Name_Or_Ref
(2 .. Name_Or_Ref
'Last));
855 return String_Table
(Obj
, Off
);
863 function First_Symbol
864 (Obj
: in out PECOFF_Object_File
) return Object_Symbol
867 -- Return Null_Symbol in the case that the symbol table is empty
869 if Obj
.Symtab_Last
= 0 then
873 return Read_Symbol
(Obj
, 0);
881 (Obj
: in out PECOFF_Object_File
;
882 Index
: uint32
) return Object_Section
884 Sec
: constant Section_Header
:= Read_Section_Header
(Obj
, Index
);
887 -- Use VirtualSize instead of SizeOfRawData. The latter is rounded to
888 -- the page size, so it may add garbage to the content. On the other
889 -- side, the former may be larger than the latter in case of 0
893 Offset
(Sec
.PointerToRawData
),
894 uint64
(Sec
.VirtualAddress
) + Obj
.ImageBase
,
895 uint64
(Sec
.VirtualSize
),
896 (Sec
.Characteristics
and IMAGE_SCN_CNT_CODE
) /= 0);
899 ---------------------------------
900 -- Get_Section_Virtual_Address --
901 ---------------------------------
903 function Get_Section_Virtual_Address
904 (Obj
: in out PECOFF_Object_File
;
905 Index
: uint32
) return uint64
907 Sec
: Section_Header
;
912 if Index
= Obj
.GSVA_Sec
then
913 return Obj
.GSVA_Addr
;
916 Obj
.GSVA_Sec
:= Index
;
917 Sec
:= Read_Section_Header
(Obj
, Index
);
918 Obj
.GSVA_Addr
:= Obj
.ImageBase
+ uint64
(Sec
.VirtualAddress
);
919 return Obj
.GSVA_Addr
;
920 end Get_Section_Virtual_Address
;
929 In_Exception
: Boolean) return PECOFF_Object_File
931 Res
: PECOFF_Object_File
932 (Format
=> (case Hdr
.Variant
is
933 when PECOFF_Ops
.VARIANT_PE32
=> PECOFF
,
934 when PECOFF_Ops
.VARIANT_PE32_PLUS
=> PECOFF_PLUS
,
935 when others => raise Program_Error
936 with "unrecognized PECOFF variant"));
937 Symtab_Size
: constant Offset
:=
938 Offset
(Hdr
.NumberOfSymbols
) * (Symtab_Entry
'Size / SSU
);
939 Strtab_Size
: uint32
;
941 Opt_Offset
: File_Size
;
942 Opt_Stream
: Mapped_Stream
;
946 Res
.In_Exception
:= In_Exception
;
949 when PECOFF_Ops
.IMAGE_FILE_MACHINE_I386
=>
951 when PECOFF_Ops
.IMAGE_FILE_MACHINE_IA64
=>
953 when PECOFF_Ops
.IMAGE_FILE_MACHINE_AMD64
=>
956 raise Format_Error
with "unrecognized architecture";
959 Res
.Num_Sections
:= uint32
(Hdr
.NumberOfSections
);
961 -- Map symbol table and the first following word (which is the length
962 -- of the string table).
964 Res
.Symtab_Last
:= Symtab_Size
;
965 Res
.Symtab_Stream
:= Create_Stream
967 File_Size
(Hdr
.PointerToSymbolTable
),
968 File_Size
(Symtab_Size
+ 4));
970 -- Map string table. The first 4 bytes are the length of the string
971 -- table and are part of it.
973 Seek
(Res
.Symtab_Stream
, Symtab_Size
);
974 Strtab_Size
:= Read
(Res
.Symtab_Stream
);
975 Res
.Symstr_Stream
:= Create_Stream
977 File_Size
(Hdr
.PointerToSymbolTable
) + File_Size
(Symtab_Size
),
978 File_Size
(Strtab_Size
));
982 Opt_Stream
:= Create_Stream
(Res
.MF
, Signature_Loc_Offset
, 4);
983 Hdr_Offset
:= Offset
(uint32
'(Read (Opt_Stream)));
985 Res.Sectab_Stream := Create_Stream
987 File_Size (Hdr_Offset +
988 Size_Of_Standard_Header_Fields +
989 Offset (Hdr.SizeOfOptionalHeader)),
990 File_Size (Res.Num_Sections)
991 * File_Size (Section_Header'Size / SSU));
993 -- Read optional header and extract image base
995 Opt_Offset := File_Size (Hdr_Offset + Size_Of_Standard_Header_Fields);
997 if Res.Format = PECOFF then
999 Opt_32 : Optional_Header_PE32;
1001 Opt_Stream := Create_Stream
1002 (Res.MF, Opt_Offset, Opt_32'Size / SSU);
1004 (Opt_Stream, Opt_32'Address, uint32 (Opt_32'Size / SSU));
1005 Res.ImageBase := uint64 (Opt_32.ImageBase);
1011 Opt_64 : Optional_Header_PE64;
1013 Opt_Stream := Create_Stream
1014 (Res.MF, Opt_Offset, Opt_64'Size / SSU);
1016 (Opt_Stream, Opt_64'Address, uint32 (Opt_64'Size / SSU));
1017 Res.ImageBase := Opt_64.ImageBase;
1029 function Read_Symbol
1030 (Obj : in out PECOFF_Object_File;
1031 Off : Offset) return Object_Symbol
1033 ST_Entry : Symtab_Entry;
1034 ST_Last : Symtab_Entry;
1035 Aux_Entry : Auxent_Section;
1036 Sz : constant Offset := ST_Entry'Size / SSU;
1037 Result : Object_Symbol;
1042 -- Seek to the successor of Prev
1049 Seek (Obj.Symtab_Stream, Sym_Off);
1050 Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, uint32 (Sz));
1054 Noff := Noff + Offset (1 + ST_Entry.NumberOfAuxSymbols) * Sz;
1056 exit when ST_Entry.TypeField = Function_Symbol_Type
1057 and then ST_Entry.SectionNumber > 0;
1059 if Noff >= Obj.Symtab_Last then
1064 -- Construct the symbol
1069 Value => uint64 (ST_Entry.Value),
1072 -- Set the size as accurately as possible
1074 -- The size of a symbol is not directly available so we try scanning
1075 -- to the next function and assuming the code ends there.
1078 -- Read symbol and AUX entries
1081 Seek (Obj.Symtab_Stream, Sym_Off);
1082 Read_Raw (Obj.Symtab_Stream, ST_Last'Address, uint32 (Sz));
1084 for I in 1 .. ST_Last.NumberOfAuxSymbols loop
1085 Read_Raw (Obj.Symtab_Stream, Aux_Entry'Address, uint32 (Sz));
1088 Noff := Noff + Offset (1 + ST_Last.NumberOfAuxSymbols) * Sz;
1090 if ST_Last.TypeField = Function_Symbol_Type then
1091 if ST_Last.SectionNumber = ST_Entry.SectionNumber
1092 and then ST_Last.Value >= ST_Entry.Value
1094 -- Symbol is a function past ST_Entry
1096 Result.Size := uint64 (ST_Last.Value - ST_Entry.Value);
1099 -- Not correlated function
1101 Result.Next := Sym_Off;
1106 elsif ST_Last.SectionNumber = ST_Entry.SectionNumber
1107 and then ST_Last.TypeField = Not_Function_Symbol_Type
1108 and then ST_Last.StorageClass = 3
1109 and then ST_Last.NumberOfAuxSymbols = 1
1111 -- Symbol is a section
1113 Result.Size := uint64 (ST_Last.Value + Aux_Entry.Length
1115 Result.Next := Noff;
1119 exit when Noff >= Obj.Symtab_Last;
1122 -- Relocate the address
1125 Result.Value + Get_Section_Virtual_Address
1126 (Obj, uint32 (ST_Entry.SectionNumber - 1));
1135 function Read_Header (F : in out Mapped_Stream) return Header is
1140 -- Skip the MSDOS stub, and seek directly to the file offset
1142 Seek (F, Signature_Loc_Offset);
1145 -- Read the COFF file header
1147 Seek (F, Offset (Off));
1148 Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
1152 -------------------------
1153 -- Read_Section_Header --
1154 -------------------------
1156 function Read_Section_Header
1157 (Obj : in out PECOFF_Object_File;
1158 Index : uint32) return Section_Header
1160 Sec : Section_Header;
1162 Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
1163 Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
1165 end Read_Section_Header;
1172 (Obj : in out PECOFF_Object_File;
1173 Sec : Object_Section) return String
1175 Shdr : constant Section_Header := Read_Section_Header (Obj, Sec.Num);
1177 return Decode_Name (Obj, Shdr.Name);
1184 function String_Table
1185 (Obj : in out PECOFF_Object_File;
1186 Index : Offset) return String
1189 -- An index of zero is used to represent an empty string, as the
1190 -- first word of the string table is specified to contain the length
1191 -- of the table rather than its contents.
1197 return Offset_To_String (Obj.Symstr_Stream, Index);
1206 (Obj : in out PECOFF_Object_File;
1207 Sym : Object_Symbol) return String_Ptr_Len
1209 ST_Entry : Symtab_Entry;
1212 Seek (Obj.Symtab_Stream, Sym.Off);
1213 Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, ST_Entry'Size / SSU);
1216 -- Symbol table entries are packed and Table_Entry.Name may not be
1217 -- sufficiently aligned to interpret as a 32 bit word, so it is
1218 -- copied to a temporary
1220 Aligned_Name : Name_Str := ST_Entry.Name;
1221 for Aligned_Name'Alignment use 4;
1223 First_Word : uint32;
1224 pragma Import (Ada, First_Word);
1225 -- Suppress initialization in Normalized_Scalars mode
1226 for First_Word'Address use Aligned_Name (1)'Address;
1228 Second_Word : uint32;
1229 pragma Import (Ada, Second_Word);
1230 -- Suppress initialization in Normalized_Scalars mode
1231 for Second_Word'Address use Aligned_Name (5)'Address;
1234 if First_Word = 0 then
1235 -- Second word is an offset in the symbol table
1236 if Second_Word = 0 then
1239 Seek (Obj.Symstr_Stream, int64 (Second_Word));
1240 return Read (Obj.Symstr_Stream);
1243 -- Inlined symbol name
1244 Seek (Obj.Symtab_Stream, Sym.Off);
1245 return To_String_Ptr_Len (Read (Obj.Symtab_Stream), 8);
1256 package body XCOFF32_Ops is
1258 function Read_Section_Header
1259 (Obj : in out XCOFF32_Object_File;
1260 Index : uint32) return Section_Header;
1261 -- Read a header from section table
1267 function Read_Symbol
1268 (Obj : in out XCOFF32_Object_File;
1269 Off : Offset) return Object_Symbol
1272 Sz : constant Offset := Symbol_Entry'Size / SSU;
1274 Result : Object_Symbol;
1278 procedure Read_LD_Symbol;
1279 -- Read the next LD symbol
1281 --------------------
1282 -- Read_LD_Symbol --
1283 --------------------
1285 procedure Read_LD_Symbol is
1290 Read_Raw (Obj.Symtab_Stream, Sym'Address, uint32 (Sz));
1292 Noff := Noff + Offset (1 + Sym.n_numaux) * Sz;
1294 for J in 1 .. Sym.n_numaux loop
1295 Read_Raw (Obj.Symtab_Stream, Aux'Address, uint32 (Sz));
1298 exit when Noff >= Obj.Symtab_Last;
1300 exit when Sym.n_numaux = 1
1301 and then Sym.n_scnum /= 0
1302 and then (Sym.n_sclass = C_EXT
1303 or else Sym.n_sclass = C_HIDEXT
1304 or else Sym.n_sclass = C_WEAKEXT)
1305 and then Aux.x_smtyp = XTY_LD;
1309 -- Start of processing for Read_Symbol
1312 Seek (Obj.Symtab_Stream, Off);
1316 if Noff >= Obj.Symtab_Last then
1320 -- Construct the symbol
1322 Result := (Off => Sym_Off,
1324 Value => uint64 (Sym.n_value),
1327 -- Look for the next symbol to compute the size
1331 if Noff >= Obj.Symtab_Last then
1335 Result.Size := uint64 (Sym.n_value) - Result.Value;
1336 Result.Next := Sym_Off;
1344 function First_Symbol
1345 (Obj : in out XCOFF32_Object_File) return Object_Symbol
1348 -- Return Null_Symbol in the case that the symbol table is empty
1350 if Obj.Symtab_Last = 0 then
1354 return Read_Symbol (Obj, 0);
1364 In_Exception : Boolean) return XCOFF32_Object_File
1366 Res : XCOFF32_Object_File (Format => XCOFF32);
1371 Res.In_Exception := In_Exception;
1375 -- Map sections table
1376 Res.Num_Sections := uint32 (Hdr.f_nscns);
1377 Res.Sectab_Stream := Create_Stream
1379 File_Size (Header'Size / SSU) + File_Size (Hdr.f_opthdr),
1380 File_Size (Hdr.f_nscns) * (Section_Header'Size / SSU));
1382 -- Map symbols table
1383 Res.Symtab_Last := Offset (Hdr.f_nscns) * (Symbol_Entry'Size / SSU);
1384 Res.Symtab_Stream := Create_Stream
1386 File_Size (Hdr.f_symptr),
1387 File_Size (Res.Symtab_Last) + 4);
1390 Seek (Res.Symtab_Stream, Res.Symtab_Last);
1391 Strtab_Sz := Read (Res.Symtab_Stream);
1392 Res.Symstr_Stream := Create_Stream
1394 File_Size (Res.Symtab_Last) + 4,
1395 File_Size (Strtab_Sz) - 4);
1404 function Get_Section
1405 (Obj : in out XCOFF32_Object_File;
1406 Index : uint32) return Object_Section
1408 Sec : constant Section_Header := Read_Section_Header (Obj, Index);
1411 return (Index, Offset (Sec.s_scnptr),
1412 uint64 (Sec.s_vaddr),
1413 uint64 (Sec.s_size),
1414 (Sec.s_flags and STYP_TEXT) /= 0);
1421 function Read_Header (F : in out Mapped_Stream) return Header is
1426 Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
1430 -------------------------
1431 -- Read_Section_Header --
1432 -------------------------
1434 function Read_Section_Header
1435 (Obj : in out XCOFF32_Object_File;
1436 Index : uint32) return Section_Header
1438 Sec : Section_Header;
1441 -- Seek to the end of the object header
1443 Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
1447 Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
1450 end Read_Section_Header;
1457 (Obj : in out XCOFF32_Object_File;
1458 Sec : Object_Section) return String
1460 Hdr : Section_Header;
1463 Hdr := Read_Section_Header (Obj, Sec.Num);
1464 return Trim_Trailing_Nuls (Hdr.s_name);
1472 (Obj : in out XCOFF32_Object_File;
1473 Sym : Object_Symbol) return String_Ptr_Len
1475 Symbol : Symbol_Entry;
1478 Seek (Obj.Symtab_Stream, Sym.Off);
1479 Read_Raw (Obj.Symtab_Stream, Symbol'Address, Symbol'Size / SSU);
1482 First_Word : uint32;
1483 pragma Import (Ada, First_Word);
1484 -- Suppress initialization in Normalized_Scalars mode
1485 for First_Word'Address use Symbol.n_name (1)'Address;
1487 Second_Word : uint32;
1488 pragma Import (Ada, Second_Word);
1489 -- Suppress initialization in Normalized_Scalars mode
1490 for Second_Word'Address use Symbol.n_name (5)'Address;
1493 if First_Word = 0 then
1494 if Second_Word = 0 then
1497 Seek (Obj.Symstr_Stream, int64 (Second_Word));
1498 return Read (Obj.Symstr_Stream);
1501 Seek (Obj.Symtab_Stream, Sym.Off);
1502 return To_String_Ptr_Len (Read (Obj.Symstr_Stream), 8);
1512 function Arch (Obj : Object_File) return Object_Arch is
1517 function Create_Stream
1519 File_Offset : File_Size;
1520 File_Length : File_Size)
1521 return Mapped_Stream
1523 Region : Mapped_Region;
1525 Read (MF, Region, File_Offset, File_Length, False);
1526 return (Region, 0, Offset (File_Length));
1529 function Create_Stream
1531 Sec : Object_Section) return Mapped_Stream
1534 return Create_Stream (Obj.MF, File_Size (Sec.Off), File_Size (Sec.Size));
1537 procedure Tell (Obj : in out Mapped_Stream; Off : out Offset) is
1542 function Tell (Obj : Mapped_Stream) return Offset is
1547 function Length (Obj : Mapped_Stream) return Offset is
1556 procedure Close (S : in out Mapped_Stream) is
1561 procedure Close (Obj : in out Object_File) is
1563 Close (Obj.Symtab_Stream);
1564 Close (Obj.Symstr_Stream);
1565 Close (Obj.Sectab_Stream);
1569 Close (Obj.Secstr_Stream);
1579 ------------------------
1580 -- Strip_Leading_Char --
1581 ------------------------
1583 function Strip_Leading_Char
1584 (Obj : in out Object_File;
1585 Sym : String_Ptr_Len) return Positive
1588 if (Obj.Format = PECOFF and then Sym.Ptr (1) = '_
')
1590 (Obj.Format = XCOFF32 and then Sym.Ptr (1) = '.')
1596 end Strip_Leading_Char;
1598 ----------------------
1599 -- Decoded_Ada_Name --
1600 ----------------------
1602 function Decoded_Ada_Name
1603 (Obj : in out Object_File;
1604 Sym : String_Ptr_Len) return String
1606 procedure gnat_decode
1607 (Coded_Name_Addr : Address;
1608 Ada_Name_Addr : Address;
1610 pragma Import (C, gnat_decode, "__gnat_decode");
1612 subtype size_t is Interfaces.C.size_t;
1614 Sym_Name : constant String :=
1615 String (Sym.Ptr (1 .. Sym.Len)) & ASCII.NUL;
1616 Decoded : char_array (0 .. size_t (Sym.Len) * 2 + 60);
1620 -- In the PECOFF case most but not all symbol table entries have an
1621 -- extra leading underscore. In this case we trim it.
1623 Off := Strip_Leading_Char (Obj, Sym);
1625 gnat_decode (Sym_Name (Off)'Address, Decoded'Address, 0);
1627 return To_Ada (Decoded);
1628 end Decoded_Ada_Name;
1634 function First_Symbol (Obj : in out Object_File) return Object_Symbol is
1637 when ELF32 => return ELF32_Ops.First_Symbol (Obj);
1638 when ELF64 => return ELF64_Ops.First_Symbol (Obj);
1639 when Any_PECOFF => return PECOFF_Ops.First_Symbol (Obj);
1640 when XCOFF32 => return XCOFF32_Ops.First_Symbol (Obj);
1648 function Format (Obj : Object_File) return Object_Format is
1653 ----------------------
1654 -- Get_Load_Address --
1655 ----------------------
1657 function Get_Load_Address (Obj : Object_File) return uint64 is
1660 when ELF => return 0;
1661 when Any_PECOFF => return Obj.ImageBase;
1662 when XCOFF32 => raise Format_Error;
1664 end Get_Load_Address;
1670 function Get_Section
1671 (Obj : in out Object_File;
1672 Shnum : uint32) return Object_Section
1676 when ELF32 => return ELF32_Ops.Get_Section (Obj, Shnum);
1677 when ELF64 => return ELF64_Ops.Get_Section (Obj, Shnum);
1678 when Any_PECOFF => return PECOFF_Ops.Get_Section (Obj, Shnum);
1679 when XCOFF32 => return XCOFF32_Ops.Get_Section (Obj, Shnum);
1683 function Get_Section
1684 (Obj : in out Object_File;
1685 Sec_Name : String) return Object_Section
1687 Sec : Object_Section;
1690 for J in 0 .. Obj.Num_Sections - 1 loop
1691 Sec := Get_Section (Obj, J);
1693 if Name (Obj, Sec) = Sec_Name then
1698 if Obj.In_Exception then
1699 return Null_Section;
1701 raise Format_Error with "could not find section in object file";
1705 ----------------------
1706 -- Get_Xcode_Bounds --
1707 ----------------------
1709 procedure Get_Xcode_Bounds
1710 (Obj : in out Object_File;
1711 Low, High : out uint64)
1713 Sec : Object_Section;
1716 -- First set as an empty range
1718 High := uint64'First;
1720 -- Now find the lowest and highest offsets
1721 -- attached to executable code sections
1722 for Idx in 1 .. Num_Sections (Obj) loop
1723 Sec := Get_Section (Obj, Idx - 1);
1724 if Sec.Flag_Xcode then
1725 if Sec.Addr < Low then
1728 if Sec.Addr + Sec.Size > High then
1729 High := Sec.Addr + Sec.Size;
1733 end Get_Xcode_Bounds;
1740 (Obj : in out Object_File;
1741 Sec : Object_Section) return String
1745 when ELF32 => return ELF32_Ops.Name (Obj, Sec);
1746 when ELF64 => return ELF64_Ops.Name (Obj, Sec);
1747 when Any_PECOFF => return PECOFF_Ops.Name (Obj, Sec);
1748 when XCOFF32 => return XCOFF32_Ops.Name (Obj, Sec);
1753 (Obj : in out Object_File;
1754 Sym : Object_Symbol) return String_Ptr_Len
1758 when ELF32 => return ELF32_Ops.Name (Obj, Sym);
1759 when ELF64 => return ELF64_Ops.Name (Obj, Sym);
1760 when Any_PECOFF => return PECOFF_Ops.Name (Obj, Sym);
1761 when XCOFF32 => return XCOFF32_Ops.Name (Obj, Sym);
1769 function Next_Symbol
1770 (Obj : in out Object_File;
1771 Prev : Object_Symbol) return Object_Symbol
1774 -- Test whether we've reached the end of the symbol table
1776 if Prev.Next >= Obj.Symtab_Last then
1780 return Read_Symbol (Obj, Prev.Next);
1787 function Num (Sec : Object_Section) return uint32 is
1796 function Num_Sections (Obj : Object_File) return uint32 is
1798 return Obj.Num_Sections;
1805 function Off (Sec : Object_Section) return Offset is
1810 function Off (Sym : Object_Symbol) return Offset is
1815 ----------------------
1816 -- Offset_To_String --
1817 ----------------------
1819 function Offset_To_String
1820 (S : in out Mapped_Stream;
1821 Off : Offset) return String
1827 Read_C_String (S, Buf);
1828 return To_String (Buf);
1829 end Offset_To_String;
1836 (File_Name : String;
1837 In_Exception : Boolean := False) return Object_File_Access
1840 Hdr_Stream : Mapped_Stream;
1845 F := Open_Read_No_Exception (File_Name);
1847 if F = Invalid_Mapped_File then
1848 if In_Exception then
1851 raise IO_Error with "could not open object file";
1855 Hdr_Stream := Create_Stream (F, 0, 4096);
1858 Hdr : constant ELF32_Ops.Header := ELF32_Ops.Read_Header (Hdr_Stream);
1861 -- Look for the magic numbers for the ELF case
1863 if Hdr.E_Ident (0) = 16#7F# and then
1864 Hdr.E_Ident (1) = Character'Pos ('E
') and then
1865 Hdr.E_Ident (2) = Character'Pos ('L
') and then
1866 Hdr.E_Ident (3) = Character'Pos ('F
') and then
1867 Hdr.E_Ident (4) = ELF32_Ops.ELFCLASS32
1870 return new Object_File'
1871 (ELF32_Ops
.Initialize
(F
, Hdr
, In_Exception
));
1876 Hdr
: constant ELF64_Ops
.Header
:=
1877 ELF64_Ops
.Read_Header
(Hdr_Stream
);
1880 -- Look for the magic numbers for the ELF case
1882 if Hdr
.E_Ident
(0) = 16#
7F#
and then
1883 Hdr
.E_Ident
(1) = Character'Pos ('E') and then
1884 Hdr
.E_Ident
(2) = Character'Pos ('L') and then
1885 Hdr
.E_Ident
(3) = Character'Pos ('F') and then
1886 Hdr
.E_Ident
(4) = ELF32_Ops
.ELFCLASS64
1889 return new Object_File
'
1890 (ELF64_Ops.Initialize (F, Hdr, In_Exception));
1895 Hdr : constant PECOFF_Ops.Header :=
1896 PECOFF_Ops.Read_Header (Hdr_Stream);
1899 -- Test the magic numbers
1901 if Hdr.Magics (0) = Character'Pos ('P
') and then
1902 Hdr.Magics (1) = Character'Pos ('E
') and then
1903 Hdr.Magics (2) = 0 and then
1907 return new Object_File'
1908 (PECOFF_Ops
.Initialize
(F
, Hdr
, In_Exception
));
1912 -- If this is not a PECOFF file then we've done a seek and read to a
1913 -- random address, possibly raising IO_Error
1920 Hdr
: constant XCOFF32_Ops
.Header
:=
1921 XCOFF32_Ops
.Read_Header
(Hdr_Stream
);
1924 -- Test the magic numbers
1926 if Hdr
.f_magic
= 8#
0737#
then
1928 return new Object_File
'
1929 (XCOFF32_Ops.Initialize (F, Hdr, In_Exception));
1935 if In_Exception then
1938 raise Format_Error with "unrecognized object format";
1946 function Read (S : in out Mapped_Stream) return Mmap.Str_Access is
1947 function To_Str_Access is
1948 new Ada.Unchecked_Conversion (Address, Str_Access);
1951 return To_Str_Access (Data (S.Region) (Natural (S.Off + 1))'Address);
1954 function Read (S : in out Mapped_Stream) return String_Ptr_Len is
1956 return To_String_Ptr_Len (Read (S));
1959 procedure Check_Read_Offset (S : Mapped_Stream; Size : uint32) is
1961 if S.Off + Offset (Size) > Offset (Last (S.Region)) then
1962 raise IO_Error with "could not read from object file";
1964 end Check_Read_Offset;
1967 (S : in out Mapped_Stream;
1971 function To_Str_Access is
1972 new Ada.Unchecked_Conversion (Address, Str_Access);
1973 Sz : constant Offset := Offset (Size);
1978 pragma Debug (Check_Read_Offset (S, Size));
1982 To_Str_Access (Addr) (1 .. Positive (Sz)) :=
1983 Data (S.Region) (Positive (S.Off + 1) .. Positive (S.Off + Sz));
1987 S.Off := S.Off + Sz;
1990 function Read (S : in out Mapped_Stream) return uint8 is
1993 Read_Raw (S, Data'Address, Data'Size / SSU);
1997 function Read (S : in out Mapped_Stream) return uint16 is
2000 Read_Raw (S, Data'Address, Data'Size / SSU);
2004 function Read (S : in out Mapped_Stream) return uint32 is
2007 Read_Raw (S, Data'Address, Data'Size / SSU);
2011 function Read (S : in out Mapped_Stream) return uint64 is
2014 Read_Raw (S, Data'Address, Data'Size / SSU);
2018 function Read (S : in out Mapped_Stream) return int8 is
2021 Read_Raw (S, Data'Address, Data'Size / SSU);
2025 function Read (S : in out Mapped_Stream) return int16 is
2028 Read_Raw (S, Data'Address, Data'Size / SSU);
2032 function Read (S : in out Mapped_Stream) return int32 is
2035 Read_Raw (S, Data'Address, Data'Size / SSU);
2039 function Read (S : in out Mapped_Stream) return int64 is
2042 Read_Raw (S, Data'Address, Data'Size / SSU);
2050 function Read_Address
2051 (Obj : Object_File; S : in out Mapped_Stream) return uint64
2053 Address_32 : uint32;
2054 Address_64 : uint64;
2064 Address_32 := Read (S);
2065 return uint64 (Address_32);
2073 Address_64 := Read (S);
2077 raise Format_Error with "unrecognized machine architecture";
2085 procedure Read_C_String (S : in out Mapped_Stream; B : out Buffer) is
2090 -- Handle overflow case
2098 exit when B (J) = 0;
2107 function Read_C_String (S : in out Mapped_Stream) return Str_Access is
2108 Res : constant Str_Access := Read (S);
2111 for J in Res'Range loop
2112 if S.Off + Offset (J - 1) > Offset (Last (S.Region)) then
2113 raise IO_Error with "could not read from object file";
2116 if Res (J) = ASCII.NUL then
2117 S.Off := S.Off + Offset (J);
2123 raise Constraint_Error;
2130 function Read_LEB128 (S : in out Mapped_Stream) return uint32 is
2132 Shift : Integer := 0;
2138 Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
2139 exit when (B and 16#80#) = 0;
2146 function Read_LEB128 (S : in out Mapped_Stream) return int32 is
2148 Shift : Integer := 0;
2154 Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
2156 exit when (B and 16#80#) = 0;
2159 if Shift < 32 and then (Res and Shift_Left (1, Shift - 1)) /= 0 then
2160 Res := Res or Shift_Left (-1, Shift);
2163 return To_int32 (Res);
2170 function Read_Symbol
2171 (Obj : in out Object_File;
2172 Off : Offset) return Object_Symbol
2176 when ELF32 => return ELF32_Ops.Read_Symbol (Obj, Off);
2177 when ELF64 => return ELF64_Ops.Read_Symbol (Obj, Off);
2178 when Any_PECOFF => return PECOFF_Ops.Read_Symbol (Obj, Off);
2179 when XCOFF32 => return XCOFF32_Ops.Read_Symbol (Obj, Off);
2187 procedure Seek (S : in out Mapped_Stream; Off : Offset) is
2189 if Off < 0 or else Off > Offset (Last (S.Region)) then
2190 raise IO_Error with "could not seek to offset in object file";
2200 function Size (Sec : Object_Section) return uint64 is
2205 function Size (Sym : Object_Symbol) return uint64 is
2214 function Strlen (Buf : Buffer) return int32 is
2216 return int32 (CRTL.strlen (Buf'Address));
2223 function Spans (Sym : Object_Symbol; Addr : uint64) return Boolean is
2225 return Addr >= Sym.Value and then Addr < Sym.Value + Sym.Size;
2232 function To_String (Buf : Buffer) return String is
2233 Result : String (1 .. Integer (CRTL.strlen (Buf'Address)));
2234 for Result'Address use Buf'Address;
2235 pragma Import (Ada, Result);
2241 -----------------------
2242 -- To_String_Ptr_Len --
2243 -----------------------
2245 function To_String_Ptr_Len
2246 (Ptr : Mmap.Str_Access;
2247 Max_Len : Natural := Natural'Last) return String_Ptr_Len
2250 for I in 1 .. Max_Len loop
2251 if Ptr (I) = ASCII.NUL then
2252 return (Ptr, I - 1);
2255 return (Ptr, Max_Len);
2256 end To_String_Ptr_Len;
2258 ------------------------
2259 -- Trim_Trailing_Nuls --
2260 ------------------------
2262 function Trim_Trailing_Nuls (Str : String) return String is
2264 for J in Str'Range loop
2265 if Str (J) = ASCII.NUL then
2266 return Str (Str'First .. J - 1);
2271 end Trim_Trailing_Nuls;
2277 function Value (Sym : Object_Symbol) return uint64 is
2282 end System.Object_Reader;