[testsuite]
[official-gcc.git] / gcc / ada / libgnat / s-objrea.adb
blob4c949654dbcc45bcdf7fae133848529c17848104
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 -- B o d y --
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 ------------------------------------------------------------------------------
32 with Ada.Unchecked_Conversion;
34 with Interfaces.C;
36 with System.CRTL;
38 package body System.Object_Reader is
39 use Interfaces;
40 use Interfaces.C;
41 use System.Mmap;
43 SSU : constant := System.Storage_Unit;
45 function To_int32 is new Ada.Unchecked_Conversion (uint32, int32);
47 function Trim_Trailing_Nuls (Str : String) return String;
48 -- Return a copy of a string with any trailing NUL characters truncated
50 procedure Check_Read_Offset (S : in out Mapped_Stream; Size : uint32);
51 -- Check that the SIZE bytes at the current offset are still in the stream
53 -------------------------------------
54 -- ELF object file format handling --
55 -------------------------------------
57 generic
58 type uword is mod <>;
60 package ELF_Ops is
62 -- ELF version codes
64 ELFCLASS32 : constant := 1; -- 32 bit ELF
65 ELFCLASS64 : constant := 2; -- 64 bit ELF
67 -- ELF machine codes
69 EM_NONE : constant := 0; -- No machine
70 EM_SPARC : constant := 2; -- SUN SPARC
71 EM_386 : constant := 3; -- Intel 80386
72 EM_MIPS : constant := 8; -- MIPS RS3000 Big-Endian
73 EM_MIPS_RS3_LE : constant := 10; -- MIPS RS3000 Little-Endian
74 EM_SPARC32PLUS : constant := 18; -- Sun SPARC 32+
75 EM_PPC : constant := 20; -- PowerPC
76 EM_PPC64 : constant := 21; -- PowerPC 64-bit
77 EM_ARM : constant := 40; -- ARM
78 EM_SPARCV9 : constant := 43; -- SPARC v9 64-bit
79 EM_IA_64 : constant := 50; -- Intel Merced
80 EM_X86_64 : constant := 62; -- AMD x86-64 architecture
82 EN_NIDENT : constant := 16;
84 type E_Ident_Type is array (0 .. EN_NIDENT - 1) of uint8;
86 type Header is record
87 E_Ident : E_Ident_Type; -- Magic number and other info
88 E_Type : uint16; -- Object file type
89 E_Machine : uint16; -- Architecture
90 E_Version : uint32; -- Object file version
91 E_Entry : uword; -- Entry point virtual address
92 E_Phoff : uword; -- Program header table file offset
93 E_Shoff : uword; -- Section header table file offset
94 E_Flags : uint32; -- Processor-specific flags
95 E_Ehsize : uint16; -- ELF header size in bytes
96 E_Phentsize : uint16; -- Program header table entry size
97 E_Phnum : uint16; -- Program header table entry count
98 E_Shentsize : uint16; -- Section header table entry size
99 E_Shnum : uint16; -- Section header table entry count
100 E_Shstrndx : uint16; -- Section header string table index
101 end record;
103 type Section_Header is record
104 Sh_Name : uint32; -- Section name string table index
105 Sh_Type : uint32; -- Section type
106 Sh_Flags : uword; -- Section flags
107 Sh_Addr : uword; -- Section virtual addr at execution
108 Sh_Offset : uword; -- Section file offset
109 Sh_Size : uword; -- Section size in bytes
110 Sh_Link : uint32; -- Link to another section
111 Sh_Info : uint32; -- Additional section information
112 Sh_Addralign : uword; -- Section alignment
113 Sh_Entsize : uword; -- Entry size if section holds table
114 end record;
116 SHF_ALLOC : constant := 2;
118 type Symtab_Entry32 is record
119 St_Name : uint32; -- Name (string table index)
120 St_Value : uint32; -- Value
121 St_Size : uint32; -- Size in bytes
122 St_Info : uint8; -- Type and binding attributes
123 St_Other : uint8; -- Undefined
124 St_Shndx : uint16; -- Defining section
125 end record;
127 type Symtab_Entry64 is record
128 St_Name : uint32; -- Name (string table index)
129 St_Info : uint8; -- Type and binding attributes
130 St_Other : uint8; -- Undefined
131 St_Shndx : uint16; -- Defining section
132 St_Value : uint64; -- Value
133 St_Size : uint64; -- Size in bytes
134 end record;
136 function Read_Header (F : in out Mapped_Stream) return Header;
137 -- Read a header from an ELF format object
139 function First_Symbol
140 (Obj : in out ELF_Object_File) return Object_Symbol;
141 -- Return the first element in the symbol table, or Null_Symbol if the
142 -- symbol table is empty.
144 function Read_Symbol
145 (Obj : in out ELF_Object_File;
146 Off : Offset) return Object_Symbol;
147 -- Read a symbol at offset Off
149 function Name
150 (Obj : in out ELF_Object_File;
151 Sym : Object_Symbol) return String_Ptr_Len;
152 -- Return the name of the symbol
154 function Name
155 (Obj : in out ELF_Object_File;
156 Sec : Object_Section) return String;
157 -- Return the name of a section
159 function Get_Section
160 (Obj : in out ELF_Object_File;
161 Shnum : uint32) return Object_Section;
162 -- Fetch a section by index from zero
164 function Initialize
165 (F : Mapped_File;
166 Hdr : Header;
167 In_Exception : Boolean) return ELF_Object_File;
168 -- Initialize an object file
170 end ELF_Ops;
172 -----------------------------------
173 -- PECOFF object format handling --
174 -----------------------------------
176 package PECOFF_Ops is
178 -- Constants and data layout are taken from the document "Microsoft
179 -- Portable Executable and Common Object File Format Specification"
180 -- Revision 8.1.
182 Signature_Loc_Offset : constant := 16#3C#;
183 -- Offset of pointer to the file signature
185 Size_Of_Standard_Header_Fields : constant := 16#18#;
186 -- Length in bytes of the standard header record
188 Function_Symbol_Type : constant := 16#20#;
189 -- Type field value indicating a symbol refers to a function
191 Not_Function_Symbol_Type : constant := 16#00#;
192 -- Type field value indicating a symbol does not refer to a function
194 type Magic_Array is array (0 .. 3) of uint8;
195 -- Array of magic numbers from the header
197 -- Magic numbers for PECOFF variants
199 VARIANT_PE32 : constant := 16#010B#;
200 VARIANT_PE32_PLUS : constant := 16#020B#;
202 -- PECOFF machine codes
204 IMAGE_FILE_MACHINE_I386 : constant := 16#014C#;
205 IMAGE_FILE_MACHINE_IA64 : constant := 16#0200#;
206 IMAGE_FILE_MACHINE_AMD64 : constant := 16#8664#;
208 -- PECOFF Data layout
210 type Header is record
211 Magics : Magic_Array;
212 Machine : uint16;
213 NumberOfSections : uint16;
214 TimeDateStamp : uint32;
215 PointerToSymbolTable : uint32;
216 NumberOfSymbols : uint32;
217 SizeOfOptionalHeader : uint16;
218 Characteristics : uint16;
219 Variant : uint16;
220 end record;
222 pragma Pack (Header);
224 type Optional_Header_PE32 is record
225 Magic : uint16;
226 MajorLinkerVersion : uint8;
227 MinorLinkerVersion : uint8;
228 SizeOfCode : uint32;
229 SizeOfInitializedData : uint32;
230 SizeOfUninitializedData : uint32;
231 AddressOfEntryPoint : uint32;
232 BaseOfCode : uint32;
233 BaseOfData : uint32; -- Note: not in PE32+
234 ImageBase : uint32;
235 SectionAlignment : uint32;
236 FileAlignment : uint32;
237 MajorOperatingSystemVersion : uint16;
238 MinorOperationSystemVersion : uint16;
239 MajorImageVersion : uint16;
240 MinorImageVersion : uint16;
241 MajorSubsystemVersion : uint16;
242 MinorSubsystemVersion : uint16;
243 Win32VersionValue : uint32;
244 SizeOfImage : uint32;
245 SizeOfHeaders : uint32;
246 Checksum : uint32;
247 Subsystem : uint16;
248 DllCharacteristics : uint16;
249 SizeOfStackReserve : uint32;
250 SizeOfStackCommit : uint32;
251 SizeOfHeapReserve : uint32;
252 SizeOfHeapCommit : uint32;
253 LoaderFlags : uint32;
254 NumberOfRvaAndSizes : uint32;
255 end record;
256 pragma Pack (Optional_Header_PE32);
257 pragma Assert (Optional_Header_PE32'Size = 96 * SSU);
259 type Optional_Header_PE64 is record
260 Magic : uint16;
261 MajorLinkerVersion : uint8;
262 MinorLinkerVersion : uint8;
263 SizeOfCode : uint32;
264 SizeOfInitializedData : uint32;
265 SizeOfUninitializedData : uint32;
266 AddressOfEntryPoint : uint32;
267 BaseOfCode : uint32;
268 ImageBase : uint64;
269 SectionAlignment : uint32;
270 FileAlignment : uint32;
271 MajorOperatingSystemVersion : uint16;
272 MinorOperationSystemVersion : uint16;
273 MajorImageVersion : uint16;
274 MinorImageVersion : uint16;
275 MajorSubsystemVersion : uint16;
276 MinorSubsystemVersion : uint16;
277 Win32VersionValue : uint32;
278 SizeOfImage : uint32;
279 SizeOfHeaders : uint32;
280 Checksum : uint32;
281 Subsystem : uint16;
282 DllCharacteristics : uint16;
283 SizeOfStackReserve : uint64;
284 SizeOfStackCommit : uint64;
285 SizeOfHeapReserve : uint64;
286 SizeOfHeapCommit : uint64;
287 LoaderFlags : uint32;
288 NumberOfRvaAndSizes : uint32;
289 end record;
290 pragma Pack (Optional_Header_PE64);
291 pragma Assert (Optional_Header_PE64'Size = 112 * SSU);
293 subtype Name_Str is String (1 .. 8);
295 type Section_Header is record
296 Name : Name_Str;
297 VirtualSize : uint32;
298 VirtualAddress : uint32;
299 SizeOfRawData : uint32;
300 PointerToRawData : uint32;
301 PointerToRelocations : uint32;
302 PointerToLinenumbers : uint32;
303 NumberOfRelocations : uint16;
304 NumberOfLinenumbers : uint16;
305 Characteristics : uint32;
306 end record;
308 pragma Pack (Section_Header);
310 IMAGE_SCN_CNT_CODE : constant := 16#0020#;
312 type Symtab_Entry is record
313 Name : Name_Str;
314 Value : uint32;
315 SectionNumber : int16;
316 TypeField : uint16;
317 StorageClass : uint8;
318 NumberOfAuxSymbols : uint8;
319 end record;
321 pragma Pack (Symtab_Entry);
323 type Auxent_Section is record
324 Length : uint32;
325 NumberOfRelocations : uint16;
326 NumberOfLinenumbers : uint16;
327 CheckSum : uint32;
328 Number : uint16;
329 Selection : uint8;
330 Unused1 : uint8;
331 Unused2 : uint8;
332 Unused3 : uint8;
333 end record;
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.
345 function Read_Symbol
346 (Obj : in out PECOFF_Object_File;
347 Off : Offset) return Object_Symbol;
348 -- Read a symbol at offset Off
350 function Name
351 (Obj : in out PECOFF_Object_File;
352 Sym : Object_Symbol) return String_Ptr_Len;
353 -- Return the name of the symbol
355 function Name
356 (Obj : in out PECOFF_Object_File;
357 Sec : Object_Section) return String;
358 -- Return the name of a section
360 function Get_Section
361 (Obj : in out PECOFF_Object_File;
362 Index : uint32) return Object_Section;
363 -- Fetch a section by index from zero
365 function Initialize
366 (F : Mapped_File;
367 Hdr : Header;
368 In_Exception : Boolean) return PECOFF_Object_File;
369 -- Initialize an object file
371 end PECOFF_Ops;
373 -------------------------------------
374 -- XCOFF-32 object format handling --
375 -------------------------------------
377 package XCOFF32_Ops is
379 -- XCOFF Data layout
381 type Header is record
382 f_magic : uint16;
383 f_nscns : uint16;
384 f_timdat : uint32;
385 f_symptr : uint32;
386 f_nsyms : uint32;
387 f_opthdr : uint16;
388 f_flags : uint16;
389 end record;
391 type Auxiliary_Header is record
392 o_mflag : uint16;
393 o_vstamp : uint16;
394 o_tsize : uint32;
395 o_dsize : uint32;
396 o_bsize : uint32;
397 o_entry : uint32;
398 o_text_start : uint32;
399 o_data_start : uint32;
400 o_toc : uint32;
401 o_snentry : uint16;
402 o_sntext : uint16;
403 o_sndata : uint16;
404 o_sntoc : uint16;
405 o_snloader : uint16;
406 o_snbss : uint16;
407 o_algntext : uint16;
408 o_algndata : uint16;
409 o_modtype : uint16;
410 o_cpuflag : uint8;
411 o_cputype : uint8;
412 o_maxstack : uint32;
413 o_maxdata : uint32;
414 o_debugger : uint32;
415 o_flags : uint8;
416 o_sntdata : uint16;
417 o_sntbss : uint16;
418 end record;
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
425 s_name : Name_Str;
426 s_paddr : uint32;
427 s_vaddr : uint32;
428 s_size : uint32;
429 s_scnptr : uint32;
430 s_relptr : uint32;
431 s_lnnoptr : uint32;
432 s_nreloc : uint16;
433 s_nlnno : uint16;
434 s_flags : uint32;
435 end record;
437 pragma Pack (Section_Header);
439 STYP_TEXT : constant := 16#0020#;
441 type Symbol_Entry is record
442 n_name : Name_Str;
443 n_value : uint32;
444 n_scnum : uint16;
445 n_type : uint16;
446 n_sclass : uint8;
447 n_numaux : uint8;
448 end record;
449 for Symbol_Entry'Size use 18 * 8;
451 type Aux_Entry is record
452 x_scnlen : uint32;
453 x_parmhash : uint32;
454 x_snhash : uint16;
455 x_smtyp : uint8;
456 x_smclass : uint8;
457 x_stab : uint32;
458 x_snstab : uint16;
459 end record;
460 for Aux_Entry'Size use 18 * 8;
462 pragma Pack (Aux_Entry);
464 C_EXT : constant := 2;
465 C_HIDEXT : constant := 107;
466 C_WEAKEXT : constant := 111;
468 XTY_LD : constant := 2;
469 -- Magic constant should be documented, especially since it's changed???
471 function Read_Header (F : in out Mapped_Stream) return Header;
472 -- Read the object file header
474 function First_Symbol
475 (Obj : in out XCOFF32_Object_File) return Object_Symbol;
476 -- Return the first element in the symbol table, or Null_Symbol if the
477 -- symbol table is empty.
479 function Read_Symbol
480 (Obj : in out XCOFF32_Object_File;
481 Off : Offset) return Object_Symbol;
482 -- Read a symbol at offset Off
484 function Name
485 (Obj : in out XCOFF32_Object_File;
486 Sym : Object_Symbol) return String_Ptr_Len;
487 -- Return the name of the symbol
489 function Name
490 (Obj : in out XCOFF32_Object_File;
491 Sec : Object_Section) return String;
492 -- Return the name of a section
494 function Initialize
495 (F : Mapped_File;
496 Hdr : Header;
497 In_Exception : Boolean) return XCOFF32_Object_File;
498 -- Initialize an object file
500 function Get_Section
501 (Obj : in out XCOFF32_Object_File;
502 Index : uint32) return Object_Section;
503 -- Fetch a section by index from zero
505 end XCOFF32_Ops;
507 -------------
508 -- ELF_Ops --
509 -------------
511 package body ELF_Ops is
513 function Get_String_Table (Obj : in out ELF_Object_File)
514 return Object_Section;
515 -- Fetch the section containing the string table
517 function Get_Symbol_Table (Obj : in out ELF_Object_File)
518 return Object_Section;
519 -- Fetch the section containing the symbol table
521 function Read_Section_Header
522 (Obj : in out ELF_Object_File;
523 Shnum : uint32) return Section_Header;
524 -- Read the header for an ELF format object section indexed from zero
526 ------------------
527 -- First_Symbol --
528 ------------------
530 function First_Symbol
531 (Obj : in out ELF_Object_File) return Object_Symbol
533 begin
534 if Obj.Symtab_Last = 0 then
535 return Null_Symbol;
536 else
537 return Read_Symbol (Obj, 0);
538 end if;
539 end First_Symbol;
541 -----------------
542 -- Get_Section --
543 -----------------
545 function Get_Section
546 (Obj : in out ELF_Object_File;
547 Shnum : uint32) return Object_Section
549 SHdr : constant Section_Header := Read_Section_Header (Obj, Shnum);
550 begin
551 return (Shnum,
552 Offset (SHdr.Sh_Offset),
553 uint64 (SHdr.Sh_Addr),
554 uint64 (SHdr.Sh_Size),
555 (SHdr.Sh_Flags and SHF_ALLOC) /= 0);
556 end Get_Section;
558 ------------------------
559 -- Get_String_Table --
560 ------------------------
562 function Get_String_Table
563 (Obj : in out ELF_Object_File) return Object_Section
565 begin
566 -- All cases except MIPS IRIX, string table located in .strtab
568 if Obj.Arch /= MIPS then
569 return Get_Section (Obj, ".strtab");
571 -- On IRIX only .dynstr is available
573 else
574 return Get_Section (Obj, ".dynstr");
575 end if;
576 end Get_String_Table;
578 ------------------------
579 -- Get_Symbol_Table --
580 ------------------------
582 function Get_Symbol_Table
583 (Obj : in out ELF_Object_File) return Object_Section
585 begin
586 -- All cases except MIPS IRIX, symbol table located in .symtab
588 if Obj.Arch /= MIPS then
589 return Get_Section (Obj, ".symtab");
591 -- On IRIX, symbol table located somewhere other than .symtab
593 else
594 return Get_Section (Obj, ".dynsym");
595 end if;
596 end Get_Symbol_Table;
598 ----------------
599 -- Initialize --
600 ----------------
602 function Initialize
603 (F : Mapped_File;
604 Hdr : Header;
605 In_Exception : Boolean) return ELF_Object_File
607 Res : ELF_Object_File
608 (Format => (case uword'Size is
609 when 64 => ELF64,
610 when 32 => ELF32,
611 when others => raise Program_Error));
612 Sec : Object_Section;
613 begin
614 Res.MF := F;
615 Res.In_Exception := In_Exception;
616 Res.Num_Sections := uint32 (Hdr.E_Shnum);
618 case Hdr.E_Machine is
619 when EM_SPARC
620 | EM_SPARC32PLUS
622 Res.Arch := SPARC;
624 when EM_386 =>
625 Res.Arch := i386;
627 when EM_MIPS
628 | EM_MIPS_RS3_LE
630 Res.Arch := MIPS;
632 when EM_PPC =>
633 Res.Arch := PPC;
635 when EM_PPC64 =>
636 Res.Arch := PPC64;
638 when EM_SPARCV9 =>
639 Res.Arch := SPARC64;
641 when EM_IA_64 =>
642 Res.Arch := IA64;
644 when EM_X86_64 =>
645 Res.Arch := x86_64;
647 when others =>
648 raise Format_Error with "unrecognized architecture";
649 end case;
651 -- Map section table and section string table
652 Res.Sectab_Stream := Create_Stream
653 (F, File_Size (Hdr.E_Shoff),
654 File_Size (Hdr.E_Shnum) * File_Size (Hdr.E_Shentsize));
655 Sec := Get_Section (Res, uint32 (Hdr.E_Shstrndx));
656 Res.Secstr_Stream := Create_Stream (Res, Sec);
658 -- Map symbol and string table
659 Sec := Get_Symbol_Table (Res);
660 Res.Symtab_Stream := Create_Stream (Res, Sec);
661 Res.Symtab_Last := Offset (Sec.Size);
663 Sec := Get_String_Table (Res);
664 Res.Symstr_Stream := Create_Stream (Res, Sec);
666 return Res;
667 end Initialize;
669 -----------------
670 -- Read_Header --
671 -----------------
673 function Read_Header (F : in out Mapped_Stream) return Header is
674 Hdr : Header;
675 begin
676 Seek (F, 0);
677 Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
678 return Hdr;
679 end Read_Header;
681 -------------------------
682 -- Read_Section_Header --
683 -------------------------
685 function Read_Section_Header
686 (Obj : in out ELF_Object_File;
687 Shnum : uint32) return Section_Header
689 Shdr : Section_Header;
690 begin
691 Seek (Obj.Sectab_Stream, Offset (Shnum * Section_Header'Size / SSU));
692 Read_Raw (Obj.Sectab_Stream, Shdr'Address, Section_Header'Size / SSU);
693 return Shdr;
694 end Read_Section_Header;
696 -----------------
697 -- Read_Symbol --
698 -----------------
700 function Read_Symbol
701 (Obj : in out ELF_Object_File;
702 Off : Offset) return Object_Symbol
704 ST_Entry32 : Symtab_Entry32;
705 ST_Entry64 : Symtab_Entry64;
706 Res : Object_Symbol;
708 begin
709 Seek (Obj.Symtab_Stream, Off);
711 case uword'Size is
712 when 32 =>
713 Read_Raw (Obj.Symtab_Stream, ST_Entry32'Address,
714 uint32 (ST_Entry32'Size / SSU));
715 Res := (Off,
716 Off + ST_Entry32'Size / SSU,
717 uint64 (ST_Entry32.St_Value),
718 uint64 (ST_Entry32.St_Size));
720 when 64 =>
721 Read_Raw (Obj.Symtab_Stream, ST_Entry64'Address,
722 uint32 (ST_Entry64'Size / SSU));
723 Res := (Off,
724 Off + ST_Entry64'Size / SSU,
725 ST_Entry64.St_Value,
726 ST_Entry64.St_Size);
728 when others =>
729 raise Program_Error;
730 end case;
732 return Res;
733 end Read_Symbol;
735 ----------
736 -- Name --
737 ----------
739 function Name
740 (Obj : in out ELF_Object_File;
741 Sec : Object_Section) return String
743 SHdr : Section_Header;
744 begin
745 SHdr := Read_Section_Header (Obj, Sec.Num);
746 return Offset_To_String (Obj.Secstr_Stream, Offset (SHdr.Sh_Name));
747 end Name;
749 function Name
750 (Obj : in out ELF_Object_File;
751 Sym : Object_Symbol) return String_Ptr_Len
753 ST_Entry32 : Symtab_Entry32;
754 ST_Entry64 : Symtab_Entry64;
755 Name_Off : Offset;
757 begin
758 -- Test that this symbol is not null
760 if Sym = Null_Symbol then
761 return (null, 0);
762 end if;
764 -- Read the symbol table entry
766 Seek (Obj.Symtab_Stream, Sym.Off);
768 case uword'Size is
769 when 32 =>
770 Read_Raw (Obj.Symtab_Stream, ST_Entry32'Address,
771 uint32 (ST_Entry32'Size / SSU));
772 Name_Off := Offset (ST_Entry32.St_Name);
774 when 64 =>
775 Read_Raw (Obj.Symtab_Stream, ST_Entry64'Address,
776 uint32 (ST_Entry64'Size / SSU));
777 Name_Off := Offset (ST_Entry64.St_Name);
779 when others =>
780 raise Program_Error;
781 end case;
783 -- Fetch the name from the string table
785 Seek (Obj.Symstr_Stream, Name_Off);
786 return Read (Obj.Symstr_Stream);
787 end Name;
789 end ELF_Ops;
791 package ELF32_Ops is new ELF_Ops (uint32);
792 package ELF64_Ops is new ELF_Ops (uint64);
794 ----------------
795 -- PECOFF_Ops --
796 ----------------
798 package body PECOFF_Ops is
800 function Decode_Name
801 (Obj : in out PECOFF_Object_File;
802 Raw_Name : String) return String;
803 -- A section name is an 8 byte field padded on the right with null
804 -- characters, or a '\' followed by an ASCII decimal string indicating
805 -- an offset in to the string table. This routine decodes this
807 function Get_Section_Virtual_Address
808 (Obj : in out PECOFF_Object_File;
809 Index : uint32) return uint64;
810 -- Fetch the address at which a section is loaded
812 function Read_Section_Header
813 (Obj : in out PECOFF_Object_File;
814 Index : uint32) return Section_Header;
815 -- Read a header from section table
817 function String_Table
818 (Obj : in out PECOFF_Object_File;
819 Index : Offset) return String;
820 -- Return an entry from the string table
822 -----------------
823 -- Decode_Name --
824 -----------------
826 function Decode_Name
827 (Obj : in out PECOFF_Object_File;
828 Raw_Name : String) return String
830 Name_Or_Ref : constant String := Trim_Trailing_Nuls (Raw_Name);
831 Off : Offset;
833 begin
834 -- We should never find a symbol with a zero length name. If we do it
835 -- probably means we are not parsing the symbol table correctly. If
836 -- this happens we raise a fatal error.
838 if Name_Or_Ref'Length = 0 then
839 raise Format_Error with
840 "found zero length symbol in symbol table";
841 end if;
843 if Name_Or_Ref (1) /= '/' then
844 return Name_Or_Ref;
845 else
846 Off := Offset'Value (Name_Or_Ref (2 .. Name_Or_Ref'Last));
847 return String_Table (Obj, Off);
848 end if;
849 end Decode_Name;
851 ------------------
852 -- First_Symbol --
853 ------------------
855 function First_Symbol
856 (Obj : in out PECOFF_Object_File) return Object_Symbol is
857 begin
858 -- Return Null_Symbol in the case that the symbol table is empty
860 if Obj.Symtab_Last = 0 then
861 return Null_Symbol;
862 end if;
864 return Read_Symbol (Obj, 0);
865 end First_Symbol;
867 -----------------
868 -- Get_Section --
869 -----------------
871 function Get_Section
872 (Obj : in out PECOFF_Object_File;
873 Index : uint32) return Object_Section
875 Sec : constant Section_Header := Read_Section_Header (Obj, Index);
876 begin
877 -- Use VirtualSize instead of SizeOfRawData. The latter is rounded to
878 -- the page size, so it may add garbage to the content. On the other
879 -- side, the former may be larger than the latter in case of 0
880 -- padding.
882 return (Index,
883 Offset (Sec.PointerToRawData),
884 uint64 (Sec.VirtualAddress) + Obj.ImageBase,
885 uint64 (Sec.VirtualSize),
886 (Sec.Characteristics and IMAGE_SCN_CNT_CODE) /= 0);
887 end Get_Section;
889 ---------------------------------
890 -- Get_Section_Virtual_Address --
891 ---------------------------------
893 function Get_Section_Virtual_Address
894 (Obj : in out PECOFF_Object_File;
895 Index : uint32) return uint64
897 Sec : Section_Header;
899 begin
900 -- Try cache
902 if Index = Obj.GSVA_Sec then
903 return Obj.GSVA_Addr;
904 end if;
906 Obj.GSVA_Sec := Index;
907 Sec := Read_Section_Header (Obj, Index);
908 Obj.GSVA_Addr := Obj.ImageBase + uint64 (Sec.VirtualAddress);
909 return Obj.GSVA_Addr;
910 end Get_Section_Virtual_Address;
912 ----------------
913 -- Initialize --
914 ----------------
916 function Initialize
917 (F : Mapped_File;
918 Hdr : Header;
919 In_Exception : Boolean) return PECOFF_Object_File
921 Res : PECOFF_Object_File
922 (Format => (case Hdr.Variant is
923 when PECOFF_Ops.VARIANT_PE32 => PECOFF,
924 when PECOFF_Ops.VARIANT_PE32_PLUS => PECOFF_PLUS,
925 when others => raise Program_Error
926 with "unrecognized PECOFF variant"));
927 Symtab_Size : constant Offset :=
928 Offset (Hdr.NumberOfSymbols) * (Symtab_Entry'Size / SSU);
929 Strtab_Size : uint32;
930 Hdr_Offset : Offset;
931 Opt_Offset : File_Size;
932 Opt_Stream : Mapped_Stream;
933 begin
934 Res.MF := F;
935 Res.In_Exception := In_Exception;
937 case Hdr.Machine is
938 when PECOFF_Ops.IMAGE_FILE_MACHINE_I386 =>
939 Res.Arch := i386;
940 when PECOFF_Ops.IMAGE_FILE_MACHINE_IA64 =>
941 Res.Arch := IA64;
942 when PECOFF_Ops.IMAGE_FILE_MACHINE_AMD64 =>
943 Res.Arch := x86_64;
944 when others =>
945 raise Format_Error with "unrecognized architecture";
946 end case;
948 Res.Num_Sections := uint32 (Hdr.NumberOfSections);
950 -- Map symbol table and the first following word (which is the length
951 -- of the string table).
953 Res.Symtab_Last := Symtab_Size;
954 Res.Symtab_Stream := Create_Stream
956 File_Size (Hdr.PointerToSymbolTable),
957 File_Size (Symtab_Size + 4));
959 -- Map string table. The first 4 bytes are the length of the string
960 -- table and are part of it.
962 Seek (Res.Symtab_Stream, Symtab_Size);
963 Strtab_Size := Read (Res.Symtab_Stream);
964 Res.Symstr_Stream := Create_Stream
966 File_Size (Hdr.PointerToSymbolTable) + File_Size (Symtab_Size),
967 File_Size (Strtab_Size));
969 -- Map section table
971 Opt_Stream := Create_Stream (Res.Mf, Signature_Loc_Offset, 4);
972 Hdr_Offset := Offset (uint32'(Read (Opt_Stream)));
973 Close (Opt_Stream);
974 Res.Sectab_Stream := Create_Stream
976 File_Size (Hdr_Offset +
977 Size_Of_Standard_Header_Fields +
978 Offset (Hdr.SizeOfOptionalHeader)),
979 File_Size (Res.Num_Sections)
980 * File_Size (Section_Header'Size / SSU));
982 -- Read optional header and extract image base
984 Opt_Offset := File_Size (Hdr_Offset + Size_Of_Standard_Header_Fields);
986 if Res.Format = PECOFF then
987 declare
988 Opt_32 : Optional_Header_PE32;
989 begin
990 Opt_Stream := Create_Stream
991 (Res.Mf, Opt_Offset, Opt_32'Size / SSU);
992 Read_Raw
993 (Opt_Stream, Opt_32'Address, uint32 (Opt_32'Size / SSU));
994 Res.ImageBase := uint64 (Opt_32.ImageBase);
995 Close (Opt_Stream);
996 end;
998 else
999 declare
1000 Opt_64 : Optional_Header_PE64;
1001 begin
1002 Opt_Stream := Create_Stream
1003 (Res.Mf, Opt_Offset, Opt_64'Size / SSU);
1004 Read_Raw
1005 (Opt_Stream, Opt_64'Address, uint32 (Opt_64'Size / SSU));
1006 Res.ImageBase := Opt_64.ImageBase;
1007 Close (Opt_Stream);
1008 end;
1009 end if;
1011 return Res;
1012 end Initialize;
1014 -----------------
1015 -- Read_Symbol --
1016 -----------------
1018 function Read_Symbol
1019 (Obj : in out PECOFF_Object_File;
1020 Off : Offset) return Object_Symbol
1022 ST_Entry : Symtab_Entry;
1023 ST_Last : Symtab_Entry;
1024 Aux_Entry : Auxent_Section;
1025 Sz : constant Offset := ST_Entry'Size / SSU;
1026 Result : Object_Symbol;
1027 Noff : Offset;
1028 Sym_Off : Offset;
1030 begin
1031 -- Seek to the successor of Prev
1033 Noff := Off;
1035 loop
1036 Sym_Off := Noff;
1038 Seek (Obj.Symtab_Stream, Sym_Off);
1039 Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, uint32 (Sz));
1041 -- Skip AUX entries
1043 Noff := Noff + Offset (1 + ST_Entry.NumberOfAuxSymbols) * Sz;
1045 exit when ST_Entry.TypeField = Function_Symbol_Type
1046 and then ST_Entry.SectionNumber > 0;
1048 if Noff >= Obj.Symtab_Last then
1049 return Null_Symbol;
1050 end if;
1051 end loop;
1053 -- Construct the symbol
1055 Result :=
1056 (Off => Sym_Off,
1057 Next => Noff,
1058 Value => uint64 (ST_Entry.Value),
1059 Size => 0);
1061 -- Set the size as accurately as possible
1063 -- The size of a symbol is not directly available so we try scanning
1064 -- to the next function and assuming the code ends there.
1066 loop
1067 -- Read symbol and AUX entries
1069 Sym_Off := Noff;
1070 Seek (Obj.Symtab_Stream, Sym_Off);
1071 Read_Raw (Obj.Symtab_Stream, ST_Last'Address, uint32 (Sz));
1073 for I in 1 .. ST_Last.NumberOfAuxSymbols loop
1074 Read_Raw (Obj.Symtab_Stream, Aux_Entry'Address, uint32 (Sz));
1075 end loop;
1077 Noff := Noff + Offset (1 + ST_Last.NumberOfAuxSymbols) * Sz;
1079 if ST_Last.TypeField = Function_Symbol_Type then
1080 if ST_Last.SectionNumber = ST_Entry.SectionNumber
1081 and then ST_Last.Value >= ST_Entry.Value
1082 then
1083 -- Symbol is a function past ST_Entry
1085 Result.Size := uint64 (ST_Last.Value - ST_Entry.Value);
1087 else
1088 -- Not correlated function
1090 Result.Next := Sym_Off;
1091 end if;
1093 exit;
1095 elsif ST_Last.SectionNumber = ST_Entry.SectionNumber
1096 and then ST_Last.TypeField = Not_Function_Symbol_Type
1097 and then ST_Last.StorageClass = 3
1098 and then ST_Last.NumberOfAuxSymbols = 1
1099 then
1100 -- Symbol is a section
1102 Result.Size := uint64 (ST_Last.Value + Aux_Entry.Length
1103 - ST_Entry.Value);
1104 Result.Next := Noff;
1105 exit;
1106 end if;
1108 exit when Noff >= Obj.Symtab_Last;
1109 end loop;
1111 -- Relocate the address
1113 Result.Value :=
1114 Result.Value + Get_Section_Virtual_Address
1115 (Obj, uint32 (ST_Entry.SectionNumber - 1));
1117 return Result;
1118 end Read_Symbol;
1120 ------------------
1121 -- Read_Header --
1122 ------------------
1124 function Read_Header (F : in out Mapped_Stream) return Header is
1125 Hdr : Header;
1126 Off : int32;
1128 begin
1129 -- Skip the MSDOS stub, and seek directly to the file offset
1131 Seek (F, Signature_Loc_Offset);
1132 Off := Read (F);
1134 -- Read the COFF file header
1136 Seek (F, Offset (Off));
1137 Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
1138 return Hdr;
1139 end Read_Header;
1141 -------------------------
1142 -- Read_Section_Header --
1143 -------------------------
1145 function Read_Section_Header
1146 (Obj : in out PECOFF_Object_File;
1147 Index : uint32) return Section_Header
1149 Sec : Section_Header;
1150 begin
1151 Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
1152 Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
1153 return Sec;
1154 end Read_Section_Header;
1156 ----------
1157 -- Name --
1158 ----------
1160 function Name
1161 (Obj : in out PECOFF_Object_File;
1162 Sec : Object_Section) return String
1164 Shdr : constant Section_Header := Read_Section_Header (Obj, Sec.Num);
1165 begin
1166 return Decode_Name (Obj, Shdr.Name);
1167 end Name;
1169 -------------------
1170 -- String_Table --
1171 -------------------
1173 function String_Table
1174 (Obj : in out PECOFF_Object_File;
1175 Index : Offset) return String is
1176 begin
1177 -- An index of zero is used to represent an empty string, as the
1178 -- first word of the string table is specified to contain the length
1179 -- of the table rather than its contents.
1181 if Index = 0 then
1182 return "";
1184 else
1185 return Offset_To_String (Obj.Symstr_Stream, Index);
1186 end if;
1187 end String_Table;
1189 ----------
1190 -- Name --
1191 ----------
1193 function Name
1194 (Obj : in out PECOFF_Object_File;
1195 Sym : Object_Symbol) return String_Ptr_Len
1197 ST_Entry : Symtab_Entry;
1199 begin
1200 Seek (Obj.Symtab_Stream, Sym.Off);
1201 Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, ST_Entry'Size / SSU);
1203 declare
1204 -- Symbol table entries are packed and Table_Entry.Name may not be
1205 -- sufficiently aligned to interpret as a 32 bit word, so it is
1206 -- copied to a temporary
1208 Aligned_Name : Name_Str := ST_Entry.Name;
1209 for Aligned_Name'Alignment use 4;
1211 First_Word : uint32;
1212 pragma Import (Ada, First_Word);
1213 -- Suppress initialization in Normalized_Scalars mode
1214 for First_Word'Address use Aligned_Name (1)'Address;
1216 Second_Word : uint32;
1217 pragma Import (Ada, Second_Word);
1218 -- Suppress initialization in Normalized_Scalars mode
1219 for Second_Word'Address use Aligned_Name (5)'Address;
1221 begin
1222 if First_Word = 0 then
1223 -- Second word is an offset in the symbol table
1224 if Second_Word = 0 then
1225 return (null, 0);
1226 else
1227 Seek (Obj.Symstr_Stream, int64 (Second_Word));
1228 return Read (Obj.Symstr_Stream);
1229 end if;
1230 else
1231 -- Inlined symbol name
1232 Seek (Obj.Symtab_Stream, Sym.Off);
1233 return To_String_Ptr_Len (Read (Obj.Symtab_Stream), 8);
1234 end if;
1235 end;
1236 end Name;
1238 end PECOFF_Ops;
1240 -----------------
1241 -- XCOFF32_Ops --
1242 -----------------
1244 package body XCOFF32_Ops is
1246 function Read_Section_Header
1247 (Obj : in out XCOFF32_Object_File;
1248 Index : uint32) return Section_Header;
1249 -- Read a header from section table
1251 -----------------
1252 -- Read_Symbol --
1253 -----------------
1255 function Read_Symbol
1256 (Obj : in out XCOFF32_Object_File;
1257 Off : Offset) return Object_Symbol
1259 Sym : Symbol_Entry;
1260 Sz : constant Offset := Symbol_Entry'Size / SSU;
1261 Aux : Aux_Entry;
1262 Result : Object_Symbol;
1263 Noff : Offset;
1264 Sym_Off : Offset;
1266 procedure Read_LD_Symbol;
1267 -- Read the next LD symbol
1269 --------------------
1270 -- Read_LD_Symbol --
1271 --------------------
1273 procedure Read_LD_Symbol is
1274 begin
1275 loop
1276 Sym_Off := Noff;
1278 Read_Raw (Obj.Symtab_Stream, Sym'Address, uint32 (Sz));
1280 Noff := Noff + Offset (1 + Sym.n_numaux) * Sz;
1282 for J in 1 .. Sym.n_numaux loop
1283 Read_Raw (Obj.Symtab_Stream, Aux'Address, uint32 (Sz));
1284 end loop;
1286 exit when Noff >= Obj.Symtab_Last;
1288 exit when Sym.n_numaux = 1
1289 and then Sym.n_scnum /= 0
1290 and then (Sym.n_sclass = C_EXT
1291 or else Sym.n_sclass = C_HIDEXT
1292 or else Sym.n_sclass = C_WEAKEXT)
1293 and then Aux.x_smtyp = XTY_LD;
1294 end loop;
1295 end Read_LD_Symbol;
1297 -- Start of processing for Read_Symbol
1299 begin
1300 Seek (Obj.Symtab_Stream, Off);
1301 Noff := Off;
1302 Read_LD_Symbol;
1304 if Noff >= Obj.Symtab_Last then
1305 return Null_Symbol;
1306 end if;
1308 -- Construct the symbol
1310 Result := (Off => Sym_Off,
1311 Next => Noff,
1312 Value => uint64 (Sym.n_value),
1313 Size => 0);
1315 -- Look for the next symbol to compute the size
1317 Read_LD_Symbol;
1319 if Noff >= Obj.Symtab_Last then
1320 return Null_Symbol;
1321 end if;
1323 Result.Size := uint64 (Sym.n_value) - Result.Value;
1324 Result.Next := Sym_Off;
1325 return Result;
1326 end Read_Symbol;
1328 ------------------
1329 -- First_Symbol --
1330 ------------------
1332 function First_Symbol
1333 (Obj : in out XCOFF32_Object_File) return Object_Symbol
1335 begin
1336 -- Return Null_Symbol in the case that the symbol table is empty
1338 if Obj.Symtab_Last = 0 then
1339 return Null_Symbol;
1340 end if;
1342 return Read_Symbol (Obj, 0);
1343 end First_Symbol;
1345 ----------------
1346 -- Initialize --
1347 ----------------
1349 function Initialize
1350 (F : Mapped_File;
1351 Hdr : Header;
1352 In_Exception : Boolean) return XCOFF32_Object_File
1354 Res : XCOFF32_Object_File (Format => XCOFF32);
1355 Strtab_Sz : uint32;
1356 begin
1357 Res.Mf := F;
1358 Res.In_Exception := In_Exception;
1360 Res.Arch := PPC;
1362 -- Map sections table
1363 Res.Num_Sections := uint32 (Hdr.f_nscns);
1364 Res.Sectab_Stream := Create_Stream
1366 File_Size (Header'Size / SSU) + File_Size (Hdr.f_opthdr),
1367 File_Size (Hdr.f_nscns) * (Section_Header'Size / SSU));
1369 -- Map symbols table
1370 Res.Symtab_Last := Offset (Hdr.f_nscns) * (Symbol_Entry'Size / SSU);
1371 Res.Symtab_Stream := Create_Stream
1373 File_Size (Hdr.f_symptr),
1374 File_Size (Res.Symtab_Last) + 4);
1376 -- Map string table
1377 Seek (Res.Symtab_Stream, Res.Symtab_Last);
1378 Strtab_Sz := Read (Res.Symtab_Stream);
1379 Res.Symstr_Stream := Create_Stream
1381 File_Size (Res.Symtab_Last) + 4,
1382 File_Size (Strtab_Sz) - 4);
1384 return Res;
1385 end Initialize;
1387 -----------------
1388 -- Get_Section --
1389 -----------------
1391 function Get_Section
1392 (Obj : in out XCOFF32_Object_File;
1393 Index : uint32) return Object_Section
1395 Sec : constant Section_Header := Read_Section_Header (Obj, Index);
1396 begin
1397 return (Index, Offset (Sec.s_scnptr),
1398 uint64 (Sec.s_vaddr),
1399 uint64 (Sec.s_size),
1400 (Sec.s_flags and STYP_TEXT) /= 0);
1401 end Get_Section;
1403 -----------------
1404 -- Read_Header --
1405 -----------------
1407 function Read_Header (F : in out Mapped_Stream) return Header is
1408 Hdr : Header;
1409 begin
1410 Seek (F, 0);
1411 Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
1412 return Hdr;
1413 end Read_Header;
1415 -------------------------
1416 -- Read_Section_Header --
1417 -------------------------
1419 function Read_Section_Header
1420 (Obj : in out XCOFF32_Object_File;
1421 Index : uint32) return Section_Header
1423 Sec : Section_Header;
1425 begin
1426 -- Seek to the end of the object header
1428 Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
1430 -- Read the section
1432 Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
1434 return Sec;
1435 end Read_Section_Header;
1437 ----------
1438 -- Name --
1439 ----------
1441 function Name
1442 (Obj : in out XCOFF32_Object_File;
1443 Sec : Object_Section) return String
1445 Hdr : Section_Header;
1446 begin
1447 Hdr := Read_Section_Header (Obj, Sec.Num);
1448 return Trim_Trailing_Nuls (Hdr.s_name);
1449 end Name;
1451 ----------
1452 -- Name --
1453 ----------
1455 function Name
1456 (Obj : in out XCOFF32_Object_File;
1457 Sym : Object_Symbol) return String_Ptr_Len
1459 Symbol : Symbol_Entry;
1461 begin
1462 Seek (Obj.Symtab_Stream, Sym.Off);
1463 Read_Raw (Obj.Symtab_Stream, Symbol'Address, Symbol'Size / SSU);
1465 declare
1466 First_Word : uint32;
1467 pragma Import (Ada, First_Word);
1468 -- Suppress initialization in Normalized_Scalars mode
1469 for First_Word'Address use Symbol.n_name (1)'Address;
1471 Second_Word : uint32;
1472 pragma Import (Ada, Second_Word);
1473 -- Suppress initialization in Normalized_Scalars mode
1474 for Second_Word'Address use Symbol.n_name (5)'Address;
1476 begin
1477 if First_Word = 0 then
1478 if Second_Word = 0 then
1479 return (null, 0);
1480 else
1481 Seek (Obj.Symstr_Stream, int64 (Second_Word));
1482 return Read (Obj.Symstr_Stream);
1483 end if;
1484 else
1485 Seek (Obj.Symtab_Stream, Sym.Off);
1486 return To_String_Ptr_Len (Read (Obj.Symstr_Stream), 8);
1487 end if;
1488 end;
1489 end Name;
1490 end XCOFF32_Ops;
1492 ----------
1493 -- Arch --
1494 ----------
1496 function Arch (Obj : Object_File) return Object_Arch is
1497 begin
1498 return Obj.Arch;
1499 end Arch;
1501 function Create_Stream
1502 (Mf : Mapped_File;
1503 File_Offset : File_Size;
1504 File_Length : File_Size)
1505 return Mapped_Stream
1507 Region : Mapped_Region;
1508 begin
1509 Read (Mf, Region, File_Offset, File_Length, False);
1510 return (Region, 0, Offset (File_Length));
1511 end Create_Stream;
1513 function Create_Stream
1514 (Obj : Object_File;
1515 Sec : Object_Section) return Mapped_Stream is
1516 begin
1517 return Create_Stream (Obj.Mf, File_Size (Sec.Off), File_Size (Sec.Size));
1518 end Create_Stream;
1520 procedure Tell (Obj : in out Mapped_Stream; Off : out Offset) is
1521 begin
1522 Off := Obj.Off;
1523 end Tell;
1525 function Tell (Obj : Mapped_Stream) return Offset is
1526 begin
1527 return Obj.Off;
1528 end Tell;
1530 function Length (Obj : Mapped_Stream) return Offset is
1531 begin
1532 return Obj.Len;
1533 end Length;
1535 -----------
1536 -- Close --
1537 -----------
1539 procedure Close (S : in out Mapped_Stream) is
1540 begin
1541 Free (S.Region);
1542 end Close;
1544 procedure Close (Obj : in out Object_File) is
1545 begin
1546 Close (Obj.Symtab_Stream);
1547 Close (Obj.Symstr_Stream);
1548 Close (Obj.Sectab_Stream);
1550 case Obj.Format is
1551 when ELF =>
1552 Close (Obj.Secstr_Stream);
1553 when Any_PECOFF =>
1554 null;
1555 when XCOFF32 =>
1556 null;
1557 end case;
1559 Close (Obj.Mf);
1560 end Close;
1562 ------------------------
1563 -- Strip_Leading_Char --
1564 ------------------------
1566 function Strip_Leading_Char
1567 (Obj : in out Object_File;
1568 Sym : String_Ptr_Len) return Positive is
1569 begin
1570 if (Obj.Format = PECOFF and then Sym.Ptr (1) = '_')
1571 or else
1572 (Obj.Format = XCOFF32 and then Sym.Ptr (1) = '.')
1573 then
1574 return 2;
1575 else
1576 return 1;
1577 end if;
1578 end Strip_Leading_Char;
1580 ----------------------
1581 -- Decoded_Ada_Name --
1582 ----------------------
1584 function Decoded_Ada_Name
1585 (Obj : in out Object_File;
1586 Sym : String_Ptr_Len) return String
1588 procedure gnat_decode
1589 (Coded_Name_Addr : Address;
1590 Ada_Name_Addr : Address;
1591 Verbose : int);
1592 pragma Import (C, gnat_decode, "__gnat_decode");
1594 subtype size_t is Interfaces.C.size_t;
1596 Sym_Name : constant String :=
1597 String (Sym.Ptr (1 .. Sym.Len)) & ASCII.NUL;
1598 Decoded : char_array (0 .. size_t (Sym.Len) * 2 + 60);
1599 Off : Natural;
1600 begin
1601 -- In the PECOFF case most but not all symbol table entries have an
1602 -- extra leading underscore. In this case we trim it.
1604 Off := Strip_Leading_Char (Obj, Sym);
1606 gnat_decode (Sym_Name (Off)'Address, Decoded'Address, 0);
1608 return To_Ada (Decoded);
1609 end Decoded_Ada_Name;
1611 ------------------
1612 -- First_Symbol --
1613 ------------------
1615 function First_Symbol (Obj : in out Object_File) return Object_Symbol is
1616 begin
1617 case Obj.Format is
1618 when ELF32 => return ELF32_Ops.First_Symbol (Obj);
1619 when ELF64 => return ELF64_Ops.First_Symbol (Obj);
1620 when Any_PECOFF => return PECOFF_Ops.First_Symbol (Obj);
1621 when XCOFF32 => return XCOFF32_Ops.First_Symbol (Obj);
1622 end case;
1623 end First_Symbol;
1625 ------------
1626 -- Format --
1627 ------------
1629 function Format (Obj : Object_File) return Object_Format is
1630 begin
1631 return Obj.Format;
1632 end Format;
1634 ----------------------
1635 -- Get_Load_Address --
1636 ----------------------
1638 function Get_Load_Address (Obj : Object_File) return uint64 is
1639 begin
1640 raise Format_Error with "Get_Load_Address not implemented";
1641 return 0;
1642 end Get_Load_Address;
1644 -----------------
1645 -- Get_Section --
1646 -----------------
1648 function Get_Section
1649 (Obj : in out Object_File;
1650 Shnum : uint32) return Object_Section is
1651 begin
1652 case Obj.Format is
1653 when ELF32 => return ELF32_Ops.Get_Section (Obj, Shnum);
1654 when ELF64 => return ELF64_Ops.Get_Section (Obj, Shnum);
1655 when Any_PECOFF => return PECOFF_Ops.Get_Section (Obj, Shnum);
1656 when XCOFF32 => return XCOFF32_Ops.Get_Section (Obj, Shnum);
1657 end case;
1658 end Get_Section;
1660 function Get_Section
1661 (Obj : in out Object_File;
1662 Sec_Name : String) return Object_Section
1664 Sec : Object_Section;
1666 begin
1667 for J in 0 .. Obj.Num_Sections - 1 loop
1668 Sec := Get_Section (Obj, J);
1670 if Name (Obj, Sec) = Sec_Name then
1671 return Sec;
1672 end if;
1673 end loop;
1675 if Obj.In_Exception then
1676 return Null_Section;
1677 else
1678 raise Format_Error with "could not find section in object file";
1679 end if;
1680 end Get_Section;
1682 -----------------------
1683 -- Get_Memory_Bounds --
1684 -----------------------
1686 procedure Get_Memory_Bounds
1687 (Obj : in out Object_File;
1688 Low, High : out uint64) is
1689 Sec : Object_Section;
1690 begin
1691 -- First set as an empty range
1692 Low := uint64'Last;
1693 High := uint64'First;
1695 for Idx in 1 .. Num_Sections (Obj) loop
1696 Sec := Get_Section (Obj, Idx - 1);
1697 if Sec.Flag_Alloc then
1698 if Sec.Addr < Low then
1699 Low := Sec.Addr;
1700 end if;
1701 if Sec.Addr + Sec.Size > High then
1702 High := Sec.Addr + Sec.Size;
1703 end if;
1704 end if;
1705 end loop;
1706 end Get_Memory_Bounds;
1708 ----------
1709 -- Name --
1710 ----------
1712 function Name
1713 (Obj : in out Object_File;
1714 Sec : Object_Section) return String is
1715 begin
1716 case Obj.Format is
1717 when ELF32 => return ELF32_Ops.Name (Obj, Sec);
1718 when ELF64 => return ELF64_Ops.Name (Obj, Sec);
1719 when Any_PECOFF => return PECOFF_Ops.Name (Obj, Sec);
1720 when XCOFF32 => return XCOFF32_Ops.Name (Obj, Sec);
1721 end case;
1722 end Name;
1724 function Name
1725 (Obj : in out Object_File;
1726 Sym : Object_Symbol) return String_Ptr_Len is
1727 begin
1728 case Obj.Format is
1729 when ELF32 => return ELF32_Ops.Name (Obj, Sym);
1730 when ELF64 => return ELF64_Ops.Name (Obj, Sym);
1731 when Any_PECOFF => return PECOFF_Ops.Name (Obj, Sym);
1732 when XCOFF32 => return XCOFF32_Ops.Name (Obj, Sym);
1733 end case;
1734 end Name;
1736 -----------------
1737 -- Next_Symbol --
1738 -----------------
1740 function Next_Symbol
1741 (Obj : in out Object_File;
1742 Prev : Object_Symbol) return Object_Symbol is
1743 begin
1744 -- Test whether we've reached the end of the symbol table
1746 if Prev.Next >= Obj.Symtab_Last then
1747 return Null_Symbol;
1748 end if;
1750 return Read_Symbol (Obj, Prev.Next);
1751 end Next_Symbol;
1753 ---------
1754 -- Num --
1755 ---------
1757 function Num (Sec : Object_Section) return uint32 is
1758 begin
1759 return Sec.Num;
1760 end Num;
1762 ------------------
1763 -- Num_Sections --
1764 ------------------
1766 function Num_Sections (Obj : Object_File) return uint32 is
1767 begin
1768 return Obj.Num_Sections;
1769 end Num_Sections;
1771 ---------
1772 -- Off --
1773 ---------
1775 function Off (Sec : Object_Section) return Offset is
1776 begin
1777 return Sec.Off;
1778 end Off;
1780 function Off (Sym : Object_Symbol) return Offset is
1781 begin
1782 return Sym.Off;
1783 end Off;
1785 ----------------------
1786 -- Offset_To_String --
1787 ----------------------
1789 function Offset_To_String
1790 (S : in out Mapped_Stream;
1791 Off : Offset) return String
1793 Buf : Buffer;
1794 begin
1795 Seek (S, Off);
1796 Read_C_String (S, Buf);
1797 return To_String (Buf);
1798 end Offset_To_String;
1800 ----------
1801 -- Open --
1802 ----------
1804 function Open
1805 (File_Name : String;
1806 In_Exception : Boolean := False) return Object_File_Access
1808 F : Mapped_File;
1809 Hdr_Stream : Mapped_Stream;
1811 begin
1812 -- Open the file
1814 F := Open_Read_No_Exception (File_Name);
1816 if F = Invalid_Mapped_File then
1817 if In_Exception then
1818 return null;
1819 else
1820 raise IO_Error with "could not open object file";
1821 end if;
1822 end if;
1824 Hdr_Stream := Create_Stream (F, 0, 4096);
1826 declare
1827 Hdr : constant ELF32_Ops.Header := ELF32_Ops.Read_Header (Hdr_Stream);
1829 begin
1830 -- Look for the magic numbers for the ELF case
1832 if Hdr.E_Ident (0) = 16#7F# and then
1833 Hdr.E_Ident (1) = Character'Pos ('E') and then
1834 Hdr.E_Ident (2) = Character'Pos ('L') and then
1835 Hdr.E_Ident (3) = Character'Pos ('F') and then
1836 Hdr.E_Ident (4) = ELF32_Ops.ELFCLASS32
1837 then
1838 Close (Hdr_Stream);
1839 return new Object_File'
1840 (ELF32_Ops.Initialize (F, Hdr, In_Exception));
1841 end if;
1842 end;
1844 declare
1845 Hdr : constant ELF64_Ops.Header :=
1846 ELF64_Ops.Read_Header (Hdr_Stream);
1848 begin
1849 -- Look for the magic numbers for the ELF case
1851 if Hdr.E_Ident (0) = 16#7F# and then
1852 Hdr.E_Ident (1) = Character'Pos ('E') and then
1853 Hdr.E_Ident (2) = Character'Pos ('L') and then
1854 Hdr.E_Ident (3) = Character'Pos ('F') and then
1855 Hdr.E_Ident (4) = ELF32_Ops.ELFCLASS64
1856 then
1857 Close (Hdr_Stream);
1858 return new Object_File'
1859 (ELF64_Ops.Initialize (F, Hdr, In_Exception));
1860 end if;
1861 end;
1863 declare
1864 Hdr : constant PECOFF_Ops.Header :=
1865 PECOFF_Ops.Read_Header (Hdr_Stream);
1867 begin
1868 -- Test the magic numbers
1870 if Hdr.Magics (0) = Character'Pos ('P') and then
1871 Hdr.Magics (1) = Character'Pos ('E') and then
1872 Hdr.Magics (2) = 0 and then
1873 Hdr.Magics (3) = 0
1874 then
1875 Close (Hdr_Stream);
1876 return new Object_File'
1877 (PECOFF_Ops.Initialize (F, Hdr, In_Exception));
1878 end if;
1880 exception
1881 -- If this is not a PECOFF file then we've done a seek and read to a
1882 -- random address, possibly raising IO_Error
1884 when IO_Error =>
1885 null;
1886 end;
1888 declare
1889 Hdr : constant XCOFF32_Ops.Header :=
1890 XCOFF32_Ops.Read_Header (Hdr_Stream);
1892 begin
1893 -- Test the magic numbers
1895 if Hdr.f_magic = 8#0737# then
1896 Close (Hdr_Stream);
1897 return new Object_File'
1898 (XCOFF32_Ops.Initialize (F, Hdr, In_Exception));
1899 end if;
1900 end;
1902 Close (Hdr_Stream);
1904 if In_Exception then
1905 return null;
1906 else
1907 raise Format_Error with "unrecognized object format";
1908 end if;
1909 end Open;
1911 ----------
1912 -- Read --
1913 ----------
1915 function Read (S : in out Mapped_Stream) return Mmap.Str_Access
1917 function To_Str_Access is
1918 new Ada.Unchecked_Conversion (Address, Str_Access);
1919 begin
1920 return To_Str_Access (Data (S.Region) (Natural (S.Off + 1))'Address);
1921 end Read;
1923 function Read (S : in out Mapped_Stream) return String_Ptr_Len is
1924 begin
1925 return To_String_Ptr_Len (Read (S));
1926 end Read;
1928 procedure Check_Read_Offset (S : in out Mapped_Stream; Size : uint32) is
1929 begin
1930 if S.Off + Offset (Size) > Offset (Last (S.Region)) then
1931 raise IO_Error with "could not read from object file";
1932 end if;
1933 end Check_Read_Offset;
1935 procedure Read_Raw
1936 (S : in out Mapped_Stream;
1937 Addr : Address;
1938 Size : uint32)
1940 function To_Str_Access is
1941 new Ada.Unchecked_Conversion (Address, Str_Access);
1943 Sz : constant Offset := Offset (Size);
1944 begin
1945 -- Check size
1947 pragma Debug (Check_Read_Offset (S, Size));
1949 -- Copy data
1951 To_Str_Access (Addr) (1 .. Positive (Sz)) :=
1952 Data (S.Region) (Positive (S.Off + 1) .. Positive (S.Off + Sz));
1954 -- Update offset
1956 S.Off := S.Off + Sz;
1957 end Read_Raw;
1959 function Read (S : in out Mapped_Stream) return uint8 is
1960 Data : uint8;
1961 begin
1962 Read_Raw (S, Data'Address, Data'Size / SSU);
1963 return Data;
1964 end Read;
1966 function Read (S : in out Mapped_Stream) return uint16 is
1967 Data : uint16;
1968 begin
1969 Read_Raw (S, Data'Address, Data'Size / SSU);
1970 return Data;
1971 end Read;
1973 function Read (S : in out Mapped_Stream) return uint32 is
1974 Data : uint32;
1975 begin
1976 Read_Raw (S, Data'Address, Data'Size / SSU);
1977 return Data;
1978 end Read;
1980 function Read (S : in out Mapped_Stream) return uint64 is
1981 Data : uint64;
1982 begin
1983 Read_Raw (S, Data'Address, Data'Size / SSU);
1984 return Data;
1985 end Read;
1987 function Read (S : in out Mapped_Stream) return int8 is
1988 Data : int8;
1989 begin
1990 Read_Raw (S, Data'Address, Data'Size / SSU);
1991 return Data;
1992 end Read;
1994 function Read (S : in out Mapped_Stream) return int16 is
1995 Data : int16;
1996 begin
1997 Read_Raw (S, Data'Address, Data'Size / SSU);
1998 return Data;
1999 end Read;
2001 function Read (S : in out Mapped_Stream) return int32 is
2002 Data : int32;
2003 begin
2004 Read_Raw (S, Data'Address, Data'Size / SSU);
2005 return Data;
2006 end Read;
2008 function Read (S : in out Mapped_Stream) return int64 is
2009 Data : int64;
2010 begin
2011 Read_Raw (S, Data'Address, Data'Size / SSU);
2012 return Data;
2013 end Read;
2015 ------------------
2016 -- Read_Address --
2017 ------------------
2019 function Read_Address
2020 (Obj : Object_File; S : in out Mapped_Stream) return uint64 is
2021 Address_32 : uint32;
2022 Address_64 : uint64;
2024 begin
2025 case Obj.Arch is
2026 when i386
2027 | MIPS
2028 | PPC
2029 | SPARC
2031 Address_32 := Read (S);
2032 return uint64 (Address_32);
2034 when IA64
2035 | PPC64
2036 | SPARC64
2037 | x86_64
2039 Address_64 := Read (S);
2040 return Address_64;
2042 when Unknown =>
2043 raise Format_Error with "unrecognized machine architecture";
2044 end case;
2045 end Read_Address;
2047 -------------------
2048 -- Read_C_String --
2049 -------------------
2051 procedure Read_C_String (S : in out Mapped_Stream; B : out Buffer) is
2052 J : Integer := 0;
2054 begin
2055 loop
2056 -- Handle overflow case
2058 if J = B'Last then
2059 B (J) := 0;
2060 exit;
2061 end if;
2063 B (J) := Read (S);
2064 exit when B (J) = 0;
2065 J := J + 1;
2066 end loop;
2067 end Read_C_String;
2069 -------------------
2070 -- Read_C_String --
2071 -------------------
2073 function Read_C_String (S : in out Mapped_Stream) return Str_Access is
2074 Res : constant Str_Access := Read (S);
2076 begin
2077 for J in Res'Range loop
2078 if S.Off + Offset (J - 1) > Offset (Last (S.Region)) then
2079 raise IO_Error with "could not read from object file";
2080 end if;
2082 if Res (J) = ASCII.NUL then
2083 S.Off := S.Off + Offset (J);
2084 return Res;
2085 end if;
2086 end loop;
2088 -- Overflow case
2089 raise Constraint_Error;
2090 end Read_C_String;
2092 -----------------
2093 -- Read_LEB128 --
2094 -----------------
2096 function Read_LEB128 (S : in out Mapped_Stream) return uint32 is
2097 B : uint8;
2098 Shift : Integer := 0;
2099 Res : uint32 := 0;
2101 begin
2102 loop
2103 B := Read (S);
2104 Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
2105 exit when (B and 16#80#) = 0;
2106 Shift := Shift + 7;
2107 end loop;
2109 return Res;
2110 end Read_LEB128;
2112 function Read_LEB128 (S : in out Mapped_Stream) return int32 is
2113 B : uint8;
2114 Shift : Integer := 0;
2115 Res : uint32 := 0;
2117 begin
2118 loop
2119 B := Read (S);
2120 Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
2121 Shift := Shift + 7;
2122 exit when (B and 16#80#) = 0;
2123 end loop;
2125 if Shift < 32 and then (Res and Shift_Left (1, Shift - 1)) /= 0 then
2126 Res := Res or Shift_Left (-1, Shift);
2127 end if;
2129 return To_int32 (Res);
2130 end Read_LEB128;
2132 -----------------
2133 -- Read_Symbol --
2134 -----------------
2136 function Read_Symbol
2137 (Obj : in out Object_File;
2138 Off : Offset) return Object_Symbol is
2139 begin
2140 case Obj.Format is
2141 when ELF32 => return ELF32_Ops.Read_Symbol (Obj, Off);
2142 when ELF64 => return ELF64_Ops.Read_Symbol (Obj, Off);
2143 when Any_PECOFF => return PECOFF_Ops.Read_Symbol (Obj, Off);
2144 when XCOFF32 => return XCOFF32_Ops.Read_Symbol (Obj, Off);
2145 end case;
2146 end Read_Symbol;
2148 ----------
2149 -- Seek --
2150 ----------
2152 procedure Seek (S : in out Mapped_Stream; Off : Offset) is
2153 begin
2154 if Off < 0 or else Off > Offset (Last (S.Region)) then
2155 raise IO_Error with "could not seek to offset in object file";
2156 end if;
2158 S.Off := Off;
2159 end Seek;
2161 ----------
2162 -- Size --
2163 ----------
2165 function Size (Sec : Object_Section) return uint64 is
2166 begin
2167 return Sec.Size;
2168 end Size;
2170 function Size (Sym : Object_Symbol) return uint64 is
2171 begin
2172 return Sym.Size;
2173 end Size;
2175 ------------
2176 -- Strlen --
2177 ------------
2179 function Strlen (Buf : Buffer) return int32 is
2180 begin
2181 return int32 (CRTL.strlen (Buf'Address));
2182 end Strlen;
2184 -----------
2185 -- Spans --
2186 -----------
2188 function Spans (Sym : Object_Symbol; Addr : uint64) return Boolean is
2189 begin
2190 return Addr >= Sym.Value and then Addr < Sym.Value + Sym.Size;
2191 end Spans;
2193 ---------------
2194 -- To_String --
2195 ---------------
2197 function To_String (Buf : Buffer) return String is
2198 Result : String (1 .. Integer (CRTL.strlen (Buf'Address)));
2199 for Result'Address use Buf'Address;
2200 pragma Import (Ada, Result);
2202 begin
2203 return Result;
2204 end To_String;
2206 -----------------------
2207 -- To_String_Ptr_Len --
2208 -----------------------
2210 function To_String_Ptr_Len
2211 (Ptr : Mmap.Str_Access;
2212 Max_Len : Natural := Natural'Last) return String_Ptr_Len is
2213 begin
2214 for I in 1 .. Max_Len loop
2215 if Ptr (I) = ASCII.NUL then
2216 return (Ptr, I - 1);
2217 end if;
2218 end loop;
2219 return (Ptr, Max_Len);
2220 end To_String_Ptr_Len;
2222 ------------------------
2223 -- Trim_Trailing_Nuls --
2224 ------------------------
2226 function Trim_Trailing_Nuls (Str : String) return String is
2227 begin
2228 for J in Str'Range loop
2229 if Str (J) = ASCII.NUL then
2230 return Str (Str'First .. J - 1);
2231 end if;
2232 end loop;
2234 return Str;
2235 end Trim_Trailing_Nuls;
2237 -----------
2238 -- Value --
2239 -----------
2241 function Value (Sym : Object_Symbol) return uint64 is
2242 begin
2243 return Sym.Value;
2244 end Value;
2246 end System.Object_Reader;