111
|
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 -- --
|
145
|
9 -- Copyright (C) 2009-2019, Free Software Foundation, Inc. --
|
111
|
10 -- --
|
|
11 -- GNAT is free software; you can redistribute it and/or modify it under --
|
|
12 -- terms of the GNU General Public License as published by the Free Soft- --
|
|
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
|
|
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
|
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
|
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
|
|
17 -- --
|
|
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
|
|
19 -- additional permissions described in the GCC Runtime Library Exception, --
|
|
20 -- version 3.1, as published by the Free Software Foundation. --
|
|
21 -- --
|
|
22 -- You should have received a copy of the GNU General Public License and --
|
|
23 -- a copy of the GCC Runtime Library Exception along with this program; --
|
|
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
|
|
25 -- <http://www.gnu.org/licenses/>. --
|
|
26 -- --
|
|
27 -- GNAT was originally developed by the GNAT team at New York University. --
|
|
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
|
|
29 -- --
|
|
30 ------------------------------------------------------------------------------
|
|
31
|
|
32 with Ada.Unchecked_Conversion;
|
|
33
|
|
34 with Interfaces.C;
|
|
35
|
|
36 with System.CRTL;
|
|
37
|
|
38 package body System.Object_Reader is
|
|
39 use Interfaces;
|
|
40 use Interfaces.C;
|
|
41 use System.Mmap;
|
|
42
|
|
43 SSU : constant := System.Storage_Unit;
|
|
44
|
|
45 function To_int32 is new Ada.Unchecked_Conversion (uint32, int32);
|
|
46
|
|
47 function Trim_Trailing_Nuls (Str : String) return String;
|
|
48 -- Return a copy of a string with any trailing NUL characters truncated
|
|
49
|
|
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
|
|
52
|
|
53 -------------------------------------
|
|
54 -- ELF object file format handling --
|
|
55 -------------------------------------
|
|
56
|
|
57 generic
|
|
58 type uword is mod <>;
|
|
59
|
|
60 package ELF_Ops is
|
|
61
|
|
62 -- ELF version codes
|
|
63
|
|
64 ELFCLASS32 : constant := 1; -- 32 bit ELF
|
|
65 ELFCLASS64 : constant := 2; -- 64 bit ELF
|
|
66
|
|
67 -- ELF machine codes
|
|
68
|
|
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
|
|
81
|
|
82 EN_NIDENT : constant := 16;
|
|
83
|
|
84 type E_Ident_Type is array (0 .. EN_NIDENT - 1) of uint8;
|
|
85
|
|
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;
|
|
102
|
|
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;
|
|
115
|
|
116 SHF_ALLOC : constant := 2;
|
131
|
117 SHF_EXECINSTR : constant := 4;
|
111
|
118
|
|
119 type Symtab_Entry32 is record
|
|
120 St_Name : uint32; -- Name (string table index)
|
|
121 St_Value : uint32; -- Value
|
|
122 St_Size : uint32; -- Size in bytes
|
|
123 St_Info : uint8; -- Type and binding attributes
|
|
124 St_Other : uint8; -- Undefined
|
|
125 St_Shndx : uint16; -- Defining section
|
|
126 end record;
|
|
127
|
|
128 type Symtab_Entry64 is record
|
|
129 St_Name : uint32; -- Name (string table index)
|
|
130 St_Info : uint8; -- Type and binding attributes
|
|
131 St_Other : uint8; -- Undefined
|
|
132 St_Shndx : uint16; -- Defining section
|
|
133 St_Value : uint64; -- Value
|
|
134 St_Size : uint64; -- Size in bytes
|
|
135 end record;
|
|
136
|
|
137 function Read_Header (F : in out Mapped_Stream) return Header;
|
|
138 -- Read a header from an ELF format object
|
|
139
|
|
140 function First_Symbol
|
|
141 (Obj : in out ELF_Object_File) return Object_Symbol;
|
|
142 -- Return the first element in the symbol table, or Null_Symbol if the
|
|
143 -- symbol table is empty.
|
|
144
|
|
145 function Read_Symbol
|
|
146 (Obj : in out ELF_Object_File;
|
|
147 Off : Offset) return Object_Symbol;
|
|
148 -- Read a symbol at offset Off
|
|
149
|
|
150 function Name
|
|
151 (Obj : in out ELF_Object_File;
|
|
152 Sym : Object_Symbol) return String_Ptr_Len;
|
|
153 -- Return the name of the symbol
|
|
154
|
|
155 function Name
|
|
156 (Obj : in out ELF_Object_File;
|
|
157 Sec : Object_Section) return String;
|
|
158 -- Return the name of a section
|
|
159
|
|
160 function Get_Section
|
|
161 (Obj : in out ELF_Object_File;
|
|
162 Shnum : uint32) return Object_Section;
|
|
163 -- Fetch a section by index from zero
|
|
164
|
|
165 function Initialize
|
|
166 (F : Mapped_File;
|
|
167 Hdr : Header;
|
|
168 In_Exception : Boolean) return ELF_Object_File;
|
|
169 -- Initialize an object file
|
|
170
|
|
171 end ELF_Ops;
|
|
172
|
|
173 -----------------------------------
|
|
174 -- PECOFF object format handling --
|
|
175 -----------------------------------
|
|
176
|
|
177 package PECOFF_Ops is
|
|
178
|
|
179 -- Constants and data layout are taken from the document "Microsoft
|
|
180 -- Portable Executable and Common Object File Format Specification"
|
|
181 -- Revision 8.1.
|
|
182
|
|
183 Signature_Loc_Offset : constant := 16#3C#;
|
|
184 -- Offset of pointer to the file signature
|
|
185
|
|
186 Size_Of_Standard_Header_Fields : constant := 16#18#;
|
|
187 -- Length in bytes of the standard header record
|
|
188
|
|
189 Function_Symbol_Type : constant := 16#20#;
|
|
190 -- Type field value indicating a symbol refers to a function
|
|
191
|
|
192 Not_Function_Symbol_Type : constant := 16#00#;
|
|
193 -- Type field value indicating a symbol does not refer to a function
|
|
194
|
|
195 type Magic_Array is array (0 .. 3) of uint8;
|
|
196 -- Array of magic numbers from the header
|
|
197
|
|
198 -- Magic numbers for PECOFF variants
|
|
199
|
|
200 VARIANT_PE32 : constant := 16#010B#;
|
|
201 VARIANT_PE32_PLUS : constant := 16#020B#;
|
|
202
|
|
203 -- PECOFF machine codes
|
|
204
|
|
205 IMAGE_FILE_MACHINE_I386 : constant := 16#014C#;
|
|
206 IMAGE_FILE_MACHINE_IA64 : constant := 16#0200#;
|
|
207 IMAGE_FILE_MACHINE_AMD64 : constant := 16#8664#;
|
|
208
|
|
209 -- PECOFF Data layout
|
|
210
|
|
211 type Header is record
|
|
212 Magics : Magic_Array;
|
|
213 Machine : uint16;
|
|
214 NumberOfSections : uint16;
|
|
215 TimeDateStamp : uint32;
|
|
216 PointerToSymbolTable : uint32;
|
|
217 NumberOfSymbols : uint32;
|
|
218 SizeOfOptionalHeader : uint16;
|
|
219 Characteristics : uint16;
|
|
220 Variant : uint16;
|
|
221 end record;
|
|
222
|
|
223 pragma Pack (Header);
|
|
224
|
|
225 type Optional_Header_PE32 is record
|
|
226 Magic : uint16;
|
|
227 MajorLinkerVersion : uint8;
|
|
228 MinorLinkerVersion : uint8;
|
|
229 SizeOfCode : uint32;
|
|
230 SizeOfInitializedData : uint32;
|
|
231 SizeOfUninitializedData : uint32;
|
|
232 AddressOfEntryPoint : uint32;
|
|
233 BaseOfCode : uint32;
|
|
234 BaseOfData : uint32; -- Note: not in PE32+
|
|
235 ImageBase : uint32;
|
|
236 SectionAlignment : uint32;
|
|
237 FileAlignment : uint32;
|
|
238 MajorOperatingSystemVersion : uint16;
|
|
239 MinorOperationSystemVersion : uint16;
|
|
240 MajorImageVersion : uint16;
|
|
241 MinorImageVersion : uint16;
|
|
242 MajorSubsystemVersion : uint16;
|
|
243 MinorSubsystemVersion : uint16;
|
|
244 Win32VersionValue : uint32;
|
|
245 SizeOfImage : uint32;
|
|
246 SizeOfHeaders : uint32;
|
|
247 Checksum : uint32;
|
|
248 Subsystem : uint16;
|
|
249 DllCharacteristics : uint16;
|
|
250 SizeOfStackReserve : uint32;
|
|
251 SizeOfStackCommit : uint32;
|
|
252 SizeOfHeapReserve : uint32;
|
|
253 SizeOfHeapCommit : uint32;
|
|
254 LoaderFlags : uint32;
|
|
255 NumberOfRvaAndSizes : uint32;
|
|
256 end record;
|
|
257 pragma Pack (Optional_Header_PE32);
|
|
258 pragma Assert (Optional_Header_PE32'Size = 96 * SSU);
|
|
259
|
|
260 type Optional_Header_PE64 is record
|
|
261 Magic : uint16;
|
|
262 MajorLinkerVersion : uint8;
|
|
263 MinorLinkerVersion : uint8;
|
|
264 SizeOfCode : uint32;
|
|
265 SizeOfInitializedData : uint32;
|
|
266 SizeOfUninitializedData : uint32;
|
|
267 AddressOfEntryPoint : uint32;
|
|
268 BaseOfCode : uint32;
|
|
269 ImageBase : uint64;
|
|
270 SectionAlignment : uint32;
|
|
271 FileAlignment : uint32;
|
|
272 MajorOperatingSystemVersion : uint16;
|
|
273 MinorOperationSystemVersion : uint16;
|
|
274 MajorImageVersion : uint16;
|
|
275 MinorImageVersion : uint16;
|
|
276 MajorSubsystemVersion : uint16;
|
|
277 MinorSubsystemVersion : uint16;
|
|
278 Win32VersionValue : uint32;
|
|
279 SizeOfImage : uint32;
|
|
280 SizeOfHeaders : uint32;
|
|
281 Checksum : uint32;
|
|
282 Subsystem : uint16;
|
|
283 DllCharacteristics : uint16;
|
|
284 SizeOfStackReserve : uint64;
|
|
285 SizeOfStackCommit : uint64;
|
|
286 SizeOfHeapReserve : uint64;
|
|
287 SizeOfHeapCommit : uint64;
|
|
288 LoaderFlags : uint32;
|
|
289 NumberOfRvaAndSizes : uint32;
|
|
290 end record;
|
|
291 pragma Pack (Optional_Header_PE64);
|
|
292 pragma Assert (Optional_Header_PE64'Size = 112 * SSU);
|
|
293
|
|
294 subtype Name_Str is String (1 .. 8);
|
|
295
|
|
296 type Section_Header is record
|
|
297 Name : Name_Str;
|
|
298 VirtualSize : uint32;
|
|
299 VirtualAddress : uint32;
|
|
300 SizeOfRawData : uint32;
|
|
301 PointerToRawData : uint32;
|
|
302 PointerToRelocations : uint32;
|
|
303 PointerToLinenumbers : uint32;
|
|
304 NumberOfRelocations : uint16;
|
|
305 NumberOfLinenumbers : uint16;
|
|
306 Characteristics : uint32;
|
|
307 end record;
|
|
308
|
|
309 pragma Pack (Section_Header);
|
|
310
|
|
311 IMAGE_SCN_CNT_CODE : constant := 16#0020#;
|
|
312
|
|
313 type Symtab_Entry is record
|
|
314 Name : Name_Str;
|
|
315 Value : uint32;
|
|
316 SectionNumber : int16;
|
|
317 TypeField : uint16;
|
|
318 StorageClass : uint8;
|
|
319 NumberOfAuxSymbols : uint8;
|
|
320 end record;
|
|
321
|
|
322 pragma Pack (Symtab_Entry);
|
|
323
|
|
324 type Auxent_Section is record
|
|
325 Length : uint32;
|
|
326 NumberOfRelocations : uint16;
|
|
327 NumberOfLinenumbers : uint16;
|
|
328 CheckSum : uint32;
|
|
329 Number : uint16;
|
|
330 Selection : uint8;
|
|
331 Unused1 : uint8;
|
|
332 Unused2 : uint8;
|
|
333 Unused3 : uint8;
|
|
334 end record;
|
|
335
|
|
336 for Auxent_Section'Size use 18 * 8;
|
|
337
|
|
338 function Read_Header (F : in out Mapped_Stream) return Header;
|
|
339 -- Read the object file header
|
|
340
|
|
341 function First_Symbol
|
|
342 (Obj : in out PECOFF_Object_File) return Object_Symbol;
|
|
343 -- Return the first element in the symbol table, or Null_Symbol if the
|
|
344 -- symbol table is empty.
|
|
345
|
|
346 function Read_Symbol
|
|
347 (Obj : in out PECOFF_Object_File;
|
|
348 Off : Offset) return Object_Symbol;
|
|
349 -- Read a symbol at offset Off
|
|
350
|
|
351 function Name
|
|
352 (Obj : in out PECOFF_Object_File;
|
|
353 Sym : Object_Symbol) return String_Ptr_Len;
|
|
354 -- Return the name of the symbol
|
|
355
|
|
356 function Name
|
|
357 (Obj : in out PECOFF_Object_File;
|
|
358 Sec : Object_Section) return String;
|
|
359 -- Return the name of a section
|
|
360
|
|
361 function Get_Section
|
|
362 (Obj : in out PECOFF_Object_File;
|
|
363 Index : uint32) return Object_Section;
|
|
364 -- Fetch a section by index from zero
|
|
365
|
|
366 function Initialize
|
|
367 (F : Mapped_File;
|
|
368 Hdr : Header;
|
|
369 In_Exception : Boolean) return PECOFF_Object_File;
|
|
370 -- Initialize an object file
|
|
371
|
|
372 end PECOFF_Ops;
|
|
373
|
|
374 -------------------------------------
|
|
375 -- XCOFF-32 object format handling --
|
|
376 -------------------------------------
|
|
377
|
|
378 package XCOFF32_Ops is
|
|
379
|
|
380 -- XCOFF Data layout
|
|
381
|
|
382 type Header is record
|
|
383 f_magic : uint16;
|
|
384 f_nscns : uint16;
|
|
385 f_timdat : uint32;
|
|
386 f_symptr : uint32;
|
|
387 f_nsyms : uint32;
|
|
388 f_opthdr : uint16;
|
|
389 f_flags : uint16;
|
|
390 end record;
|
|
391
|
|
392 type Auxiliary_Header is record
|
|
393 o_mflag : uint16;
|
|
394 o_vstamp : uint16;
|
|
395 o_tsize : uint32;
|
|
396 o_dsize : uint32;
|
|
397 o_bsize : uint32;
|
|
398 o_entry : uint32;
|
|
399 o_text_start : uint32;
|
|
400 o_data_start : uint32;
|
|
401 o_toc : uint32;
|
|
402 o_snentry : uint16;
|
|
403 o_sntext : uint16;
|
|
404 o_sndata : uint16;
|
|
405 o_sntoc : uint16;
|
|
406 o_snloader : uint16;
|
|
407 o_snbss : uint16;
|
|
408 o_algntext : uint16;
|
|
409 o_algndata : uint16;
|
|
410 o_modtype : uint16;
|
|
411 o_cpuflag : uint8;
|
|
412 o_cputype : uint8;
|
|
413 o_maxstack : uint32;
|
|
414 o_maxdata : uint32;
|
|
415 o_debugger : uint32;
|
|
416 o_flags : uint8;
|
|
417 o_sntdata : uint16;
|
|
418 o_sntbss : uint16;
|
|
419 end record;
|
|
420 pragma Unreferenced (Auxiliary_Header);
|
|
421 -- Not used, but not removed (just in case)
|
|
422
|
|
423 subtype Name_Str is String (1 .. 8);
|
|
424
|
|
425 type Section_Header is record
|
|
426 s_name : Name_Str;
|
|
427 s_paddr : uint32;
|
|
428 s_vaddr : uint32;
|
|
429 s_size : uint32;
|
|
430 s_scnptr : uint32;
|
|
431 s_relptr : uint32;
|
|
432 s_lnnoptr : uint32;
|
|
433 s_nreloc : uint16;
|
|
434 s_nlnno : uint16;
|
|
435 s_flags : uint32;
|
|
436 end record;
|
|
437
|
|
438 pragma Pack (Section_Header);
|
|
439
|
|
440 STYP_TEXT : constant := 16#0020#;
|
|
441
|
|
442 type Symbol_Entry is record
|
|
443 n_name : Name_Str;
|
|
444 n_value : uint32;
|
|
445 n_scnum : uint16;
|
|
446 n_type : uint16;
|
|
447 n_sclass : uint8;
|
|
448 n_numaux : uint8;
|
|
449 end record;
|
|
450 for Symbol_Entry'Size use 18 * 8;
|
|
451
|
|
452 type Aux_Entry is record
|
|
453 x_scnlen : uint32;
|
|
454 x_parmhash : uint32;
|
|
455 x_snhash : uint16;
|
|
456 x_smtyp : uint8;
|
|
457 x_smclass : uint8;
|
|
458 x_stab : uint32;
|
|
459 x_snstab : uint16;
|
|
460 end record;
|
|
461 for Aux_Entry'Size use 18 * 8;
|
|
462
|
|
463 pragma Pack (Aux_Entry);
|
|
464
|
|
465 C_EXT : constant := 2;
|
|
466 C_HIDEXT : constant := 107;
|
|
467 C_WEAKEXT : constant := 111;
|
|
468
|
|
469 XTY_LD : constant := 2;
|
|
470 -- Magic constant should be documented, especially since it's changed???
|
|
471
|
|
472 function Read_Header (F : in out Mapped_Stream) return Header;
|
|
473 -- Read the object file header
|
|
474
|
|
475 function First_Symbol
|
|
476 (Obj : in out XCOFF32_Object_File) return Object_Symbol;
|
|
477 -- Return the first element in the symbol table, or Null_Symbol if the
|
|
478 -- symbol table is empty.
|
|
479
|
|
480 function Read_Symbol
|
|
481 (Obj : in out XCOFF32_Object_File;
|
|
482 Off : Offset) return Object_Symbol;
|
|
483 -- Read a symbol at offset Off
|
|
484
|
|
485 function Name
|
|
486 (Obj : in out XCOFF32_Object_File;
|
|
487 Sym : Object_Symbol) return String_Ptr_Len;
|
|
488 -- Return the name of the symbol
|
|
489
|
|
490 function Name
|
|
491 (Obj : in out XCOFF32_Object_File;
|
|
492 Sec : Object_Section) return String;
|
|
493 -- Return the name of a section
|
|
494
|
|
495 function Initialize
|
|
496 (F : Mapped_File;
|
|
497 Hdr : Header;
|
|
498 In_Exception : Boolean) return XCOFF32_Object_File;
|
|
499 -- Initialize an object file
|
|
500
|
|
501 function Get_Section
|
|
502 (Obj : in out XCOFF32_Object_File;
|
|
503 Index : uint32) return Object_Section;
|
|
504 -- Fetch a section by index from zero
|
|
505
|
|
506 end XCOFF32_Ops;
|
|
507
|
|
508 -------------
|
|
509 -- ELF_Ops --
|
|
510 -------------
|
|
511
|
|
512 package body ELF_Ops is
|
|
513
|
|
514 function Get_String_Table (Obj : in out ELF_Object_File)
|
|
515 return Object_Section;
|
|
516 -- Fetch the section containing the string table
|
|
517
|
|
518 function Get_Symbol_Table (Obj : in out ELF_Object_File)
|
|
519 return Object_Section;
|
|
520 -- Fetch the section containing the symbol table
|
|
521
|
|
522 function Read_Section_Header
|
|
523 (Obj : in out ELF_Object_File;
|
|
524 Shnum : uint32) return Section_Header;
|
|
525 -- Read the header for an ELF format object section indexed from zero
|
|
526
|
|
527 ------------------
|
|
528 -- First_Symbol --
|
|
529 ------------------
|
|
530
|
|
531 function First_Symbol
|
|
532 (Obj : in out ELF_Object_File) return Object_Symbol
|
|
533 is
|
|
534 begin
|
|
535 if Obj.Symtab_Last = 0 then
|
|
536 return Null_Symbol;
|
|
537 else
|
|
538 return Read_Symbol (Obj, 0);
|
|
539 end if;
|
|
540 end First_Symbol;
|
|
541
|
|
542 -----------------
|
|
543 -- Get_Section --
|
|
544 -----------------
|
|
545
|
|
546 function Get_Section
|
|
547 (Obj : in out ELF_Object_File;
|
|
548 Shnum : uint32) return Object_Section
|
|
549 is
|
|
550 SHdr : constant Section_Header := Read_Section_Header (Obj, Shnum);
|
|
551 begin
|
|
552 return (Shnum,
|
|
553 Offset (SHdr.Sh_Offset),
|
|
554 uint64 (SHdr.Sh_Addr),
|
|
555 uint64 (SHdr.Sh_Size),
|
131
|
556 (SHdr.Sh_Flags and SHF_EXECINSTR) /= 0);
|
111
|
557 end Get_Section;
|
|
558
|
|
559 ------------------------
|
|
560 -- Get_String_Table --
|
|
561 ------------------------
|
|
562
|
|
563 function Get_String_Table
|
|
564 (Obj : in out ELF_Object_File) return Object_Section
|
|
565 is
|
|
566 begin
|
|
567 -- All cases except MIPS IRIX, string table located in .strtab
|
|
568
|
|
569 if Obj.Arch /= MIPS then
|
|
570 return Get_Section (Obj, ".strtab");
|
|
571
|
|
572 -- On IRIX only .dynstr is available
|
|
573
|
|
574 else
|
|
575 return Get_Section (Obj, ".dynstr");
|
|
576 end if;
|
|
577 end Get_String_Table;
|
|
578
|
|
579 ------------------------
|
|
580 -- Get_Symbol_Table --
|
|
581 ------------------------
|
|
582
|
|
583 function Get_Symbol_Table
|
|
584 (Obj : in out ELF_Object_File) return Object_Section
|
|
585 is
|
|
586 begin
|
|
587 -- All cases except MIPS IRIX, symbol table located in .symtab
|
|
588
|
|
589 if Obj.Arch /= MIPS then
|
|
590 return Get_Section (Obj, ".symtab");
|
|
591
|
|
592 -- On IRIX, symbol table located somewhere other than .symtab
|
|
593
|
|
594 else
|
|
595 return Get_Section (Obj, ".dynsym");
|
|
596 end if;
|
|
597 end Get_Symbol_Table;
|
|
598
|
|
599 ----------------
|
|
600 -- Initialize --
|
|
601 ----------------
|
|
602
|
|
603 function Initialize
|
|
604 (F : Mapped_File;
|
|
605 Hdr : Header;
|
|
606 In_Exception : Boolean) return ELF_Object_File
|
|
607 is
|
|
608 Res : ELF_Object_File
|
|
609 (Format => (case uword'Size is
|
|
610 when 64 => ELF64,
|
|
611 when 32 => ELF32,
|
|
612 when others => raise Program_Error));
|
|
613 Sec : Object_Section;
|
|
614 begin
|
|
615 Res.MF := F;
|
|
616 Res.In_Exception := In_Exception;
|
|
617 Res.Num_Sections := uint32 (Hdr.E_Shnum);
|
|
618
|
|
619 case Hdr.E_Machine is
|
|
620 when EM_SPARC
|
|
621 | EM_SPARC32PLUS
|
|
622 =>
|
|
623 Res.Arch := SPARC;
|
|
624
|
|
625 when EM_386 =>
|
|
626 Res.Arch := i386;
|
|
627
|
|
628 when EM_MIPS
|
|
629 | EM_MIPS_RS3_LE
|
|
630 =>
|
|
631 Res.Arch := MIPS;
|
|
632
|
|
633 when EM_PPC =>
|
|
634 Res.Arch := PPC;
|
|
635
|
|
636 when EM_PPC64 =>
|
|
637 Res.Arch := PPC64;
|
|
638
|
|
639 when EM_SPARCV9 =>
|
|
640 Res.Arch := SPARC64;
|
|
641
|
|
642 when EM_IA_64 =>
|
|
643 Res.Arch := IA64;
|
|
644
|
|
645 when EM_X86_64 =>
|
|
646 Res.Arch := x86_64;
|
|
647
|
|
648 when others =>
|
|
649 raise Format_Error with "unrecognized architecture";
|
|
650 end case;
|
|
651
|
|
652 -- Map section table and section string table
|
|
653 Res.Sectab_Stream := Create_Stream
|
|
654 (F, File_Size (Hdr.E_Shoff),
|
|
655 File_Size (Hdr.E_Shnum) * File_Size (Hdr.E_Shentsize));
|
|
656 Sec := Get_Section (Res, uint32 (Hdr.E_Shstrndx));
|
|
657 Res.Secstr_Stream := Create_Stream (Res, Sec);
|
|
658
|
|
659 -- Map symbol and string table
|
|
660 Sec := Get_Symbol_Table (Res);
|
|
661 Res.Symtab_Stream := Create_Stream (Res, Sec);
|
|
662 Res.Symtab_Last := Offset (Sec.Size);
|
|
663
|
|
664 Sec := Get_String_Table (Res);
|
|
665 Res.Symstr_Stream := Create_Stream (Res, Sec);
|
|
666
|
|
667 return Res;
|
|
668 end Initialize;
|
|
669
|
|
670 -----------------
|
|
671 -- Read_Header --
|
|
672 -----------------
|
|
673
|
|
674 function Read_Header (F : in out Mapped_Stream) return Header is
|
|
675 Hdr : Header;
|
|
676 begin
|
|
677 Seek (F, 0);
|
|
678 Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
|
|
679 return Hdr;
|
|
680 end Read_Header;
|
|
681
|
|
682 -------------------------
|
|
683 -- Read_Section_Header --
|
|
684 -------------------------
|
|
685
|
|
686 function Read_Section_Header
|
|
687 (Obj : in out ELF_Object_File;
|
|
688 Shnum : uint32) return Section_Header
|
|
689 is
|
|
690 Shdr : Section_Header;
|
|
691 begin
|
|
692 Seek (Obj.Sectab_Stream, Offset (Shnum * Section_Header'Size / SSU));
|
|
693 Read_Raw (Obj.Sectab_Stream, Shdr'Address, Section_Header'Size / SSU);
|
|
694 return Shdr;
|
|
695 end Read_Section_Header;
|
|
696
|
|
697 -----------------
|
|
698 -- Read_Symbol --
|
|
699 -----------------
|
|
700
|
|
701 function Read_Symbol
|
|
702 (Obj : in out ELF_Object_File;
|
|
703 Off : Offset) return Object_Symbol
|
|
704 is
|
|
705 ST_Entry32 : Symtab_Entry32;
|
|
706 ST_Entry64 : Symtab_Entry64;
|
|
707 Res : Object_Symbol;
|
|
708
|
|
709 begin
|
|
710 Seek (Obj.Symtab_Stream, Off);
|
|
711
|
|
712 case uword'Size is
|
|
713 when 32 =>
|
|
714 Read_Raw (Obj.Symtab_Stream, ST_Entry32'Address,
|
|
715 uint32 (ST_Entry32'Size / SSU));
|
|
716 Res := (Off,
|
|
717 Off + ST_Entry32'Size / SSU,
|
|
718 uint64 (ST_Entry32.St_Value),
|
|
719 uint64 (ST_Entry32.St_Size));
|
|
720
|
|
721 when 64 =>
|
|
722 Read_Raw (Obj.Symtab_Stream, ST_Entry64'Address,
|
|
723 uint32 (ST_Entry64'Size / SSU));
|
|
724 Res := (Off,
|
|
725 Off + ST_Entry64'Size / SSU,
|
|
726 ST_Entry64.St_Value,
|
|
727 ST_Entry64.St_Size);
|
|
728
|
|
729 when others =>
|
|
730 raise Program_Error;
|
|
731 end case;
|
|
732
|
|
733 return Res;
|
|
734 end Read_Symbol;
|
|
735
|
|
736 ----------
|
|
737 -- Name --
|
|
738 ----------
|
|
739
|
|
740 function Name
|
|
741 (Obj : in out ELF_Object_File;
|
|
742 Sec : Object_Section) return String
|
|
743 is
|
|
744 SHdr : Section_Header;
|
|
745 begin
|
|
746 SHdr := Read_Section_Header (Obj, Sec.Num);
|
|
747 return Offset_To_String (Obj.Secstr_Stream, Offset (SHdr.Sh_Name));
|
|
748 end Name;
|
|
749
|
|
750 function Name
|
|
751 (Obj : in out ELF_Object_File;
|
|
752 Sym : Object_Symbol) return String_Ptr_Len
|
|
753 is
|
|
754 ST_Entry32 : Symtab_Entry32;
|
|
755 ST_Entry64 : Symtab_Entry64;
|
|
756 Name_Off : Offset;
|
|
757
|
|
758 begin
|
|
759 -- Test that this symbol is not null
|
|
760
|
|
761 if Sym = Null_Symbol then
|
|
762 return (null, 0);
|
|
763 end if;
|
|
764
|
|
765 -- Read the symbol table entry
|
|
766
|
|
767 Seek (Obj.Symtab_Stream, Sym.Off);
|
|
768
|
|
769 case uword'Size is
|
|
770 when 32 =>
|
|
771 Read_Raw (Obj.Symtab_Stream, ST_Entry32'Address,
|
|
772 uint32 (ST_Entry32'Size / SSU));
|
|
773 Name_Off := Offset (ST_Entry32.St_Name);
|
|
774
|
|
775 when 64 =>
|
|
776 Read_Raw (Obj.Symtab_Stream, ST_Entry64'Address,
|
|
777 uint32 (ST_Entry64'Size / SSU));
|
|
778 Name_Off := Offset (ST_Entry64.St_Name);
|
|
779
|
|
780 when others =>
|
|
781 raise Program_Error;
|
|
782 end case;
|
|
783
|
|
784 -- Fetch the name from the string table
|
|
785
|
|
786 Seek (Obj.Symstr_Stream, Name_Off);
|
|
787 return Read (Obj.Symstr_Stream);
|
|
788 end Name;
|
|
789
|
|
790 end ELF_Ops;
|
|
791
|
|
792 package ELF32_Ops is new ELF_Ops (uint32);
|
|
793 package ELF64_Ops is new ELF_Ops (uint64);
|
|
794
|
|
795 ----------------
|
|
796 -- PECOFF_Ops --
|
|
797 ----------------
|
|
798
|
|
799 package body PECOFF_Ops is
|
|
800
|
|
801 function Decode_Name
|
|
802 (Obj : in out PECOFF_Object_File;
|
|
803 Raw_Name : String) return String;
|
|
804 -- A section name is an 8 byte field padded on the right with null
|
|
805 -- characters, or a '\' followed by an ASCII decimal string indicating
|
|
806 -- an offset in to the string table. This routine decodes this
|
|
807
|
|
808 function Get_Section_Virtual_Address
|
|
809 (Obj : in out PECOFF_Object_File;
|
|
810 Index : uint32) return uint64;
|
|
811 -- Fetch the address at which a section is loaded
|
|
812
|
|
813 function Read_Section_Header
|
|
814 (Obj : in out PECOFF_Object_File;
|
|
815 Index : uint32) return Section_Header;
|
|
816 -- Read a header from section table
|
|
817
|
|
818 function String_Table
|
|
819 (Obj : in out PECOFF_Object_File;
|
|
820 Index : Offset) return String;
|
|
821 -- Return an entry from the string table
|
|
822
|
|
823 -----------------
|
|
824 -- Decode_Name --
|
|
825 -----------------
|
|
826
|
|
827 function Decode_Name
|
|
828 (Obj : in out PECOFF_Object_File;
|
|
829 Raw_Name : String) return String
|
|
830 is
|
|
831 Name_Or_Ref : constant String := Trim_Trailing_Nuls (Raw_Name);
|
|
832 Off : Offset;
|
|
833
|
|
834 begin
|
|
835 -- We should never find a symbol with a zero length name. If we do it
|
|
836 -- probably means we are not parsing the symbol table correctly. If
|
|
837 -- this happens we raise a fatal error.
|
|
838
|
|
839 if Name_Or_Ref'Length = 0 then
|
|
840 raise Format_Error with
|
|
841 "found zero length symbol in symbol table";
|
|
842 end if;
|
|
843
|
|
844 if Name_Or_Ref (1) /= '/' then
|
|
845 return Name_Or_Ref;
|
|
846 else
|
|
847 Off := Offset'Value (Name_Or_Ref (2 .. Name_Or_Ref'Last));
|
|
848 return String_Table (Obj, Off);
|
|
849 end if;
|
|
850 end Decode_Name;
|
|
851
|
|
852 ------------------
|
|
853 -- First_Symbol --
|
|
854 ------------------
|
|
855
|
|
856 function First_Symbol
|
|
857 (Obj : in out PECOFF_Object_File) return Object_Symbol is
|
|
858 begin
|
|
859 -- Return Null_Symbol in the case that the symbol table is empty
|
|
860
|
|
861 if Obj.Symtab_Last = 0 then
|
|
862 return Null_Symbol;
|
|
863 end if;
|
|
864
|
|
865 return Read_Symbol (Obj, 0);
|
|
866 end First_Symbol;
|
|
867
|
|
868 -----------------
|
|
869 -- Get_Section --
|
|
870 -----------------
|
|
871
|
|
872 function Get_Section
|
|
873 (Obj : in out PECOFF_Object_File;
|
|
874 Index : uint32) return Object_Section
|
|
875 is
|
|
876 Sec : constant Section_Header := Read_Section_Header (Obj, Index);
|
|
877 begin
|
|
878 -- Use VirtualSize instead of SizeOfRawData. The latter is rounded to
|
|
879 -- the page size, so it may add garbage to the content. On the other
|
|
880 -- side, the former may be larger than the latter in case of 0
|
|
881 -- padding.
|
|
882
|
|
883 return (Index,
|
|
884 Offset (Sec.PointerToRawData),
|
|
885 uint64 (Sec.VirtualAddress) + Obj.ImageBase,
|
|
886 uint64 (Sec.VirtualSize),
|
|
887 (Sec.Characteristics and IMAGE_SCN_CNT_CODE) /= 0);
|
|
888 end Get_Section;
|
|
889
|
|
890 ---------------------------------
|
|
891 -- Get_Section_Virtual_Address --
|
|
892 ---------------------------------
|
|
893
|
|
894 function Get_Section_Virtual_Address
|
|
895 (Obj : in out PECOFF_Object_File;
|
|
896 Index : uint32) return uint64
|
|
897 is
|
|
898 Sec : Section_Header;
|
|
899
|
|
900 begin
|
|
901 -- Try cache
|
|
902
|
|
903 if Index = Obj.GSVA_Sec then
|
|
904 return Obj.GSVA_Addr;
|
|
905 end if;
|
|
906
|
|
907 Obj.GSVA_Sec := Index;
|
|
908 Sec := Read_Section_Header (Obj, Index);
|
|
909 Obj.GSVA_Addr := Obj.ImageBase + uint64 (Sec.VirtualAddress);
|
|
910 return Obj.GSVA_Addr;
|
|
911 end Get_Section_Virtual_Address;
|
|
912
|
|
913 ----------------
|
|
914 -- Initialize --
|
|
915 ----------------
|
|
916
|
|
917 function Initialize
|
|
918 (F : Mapped_File;
|
|
919 Hdr : Header;
|
|
920 In_Exception : Boolean) return PECOFF_Object_File
|
|
921 is
|
|
922 Res : PECOFF_Object_File
|
|
923 (Format => (case Hdr.Variant is
|
|
924 when PECOFF_Ops.VARIANT_PE32 => PECOFF,
|
|
925 when PECOFF_Ops.VARIANT_PE32_PLUS => PECOFF_PLUS,
|
|
926 when others => raise Program_Error
|
|
927 with "unrecognized PECOFF variant"));
|
|
928 Symtab_Size : constant Offset :=
|
|
929 Offset (Hdr.NumberOfSymbols) * (Symtab_Entry'Size / SSU);
|
|
930 Strtab_Size : uint32;
|
|
931 Hdr_Offset : Offset;
|
|
932 Opt_Offset : File_Size;
|
|
933 Opt_Stream : Mapped_Stream;
|
|
934 begin
|
|
935 Res.MF := F;
|
|
936 Res.In_Exception := In_Exception;
|
|
937
|
|
938 case Hdr.Machine is
|
|
939 when PECOFF_Ops.IMAGE_FILE_MACHINE_I386 =>
|
|
940 Res.Arch := i386;
|
|
941 when PECOFF_Ops.IMAGE_FILE_MACHINE_IA64 =>
|
|
942 Res.Arch := IA64;
|
|
943 when PECOFF_Ops.IMAGE_FILE_MACHINE_AMD64 =>
|
|
944 Res.Arch := x86_64;
|
|
945 when others =>
|
|
946 raise Format_Error with "unrecognized architecture";
|
|
947 end case;
|
|
948
|
|
949 Res.Num_Sections := uint32 (Hdr.NumberOfSections);
|
|
950
|
|
951 -- Map symbol table and the first following word (which is the length
|
|
952 -- of the string table).
|
|
953
|
|
954 Res.Symtab_Last := Symtab_Size;
|
|
955 Res.Symtab_Stream := Create_Stream
|
|
956 (F,
|
|
957 File_Size (Hdr.PointerToSymbolTable),
|
|
958 File_Size (Symtab_Size + 4));
|
|
959
|
|
960 -- Map string table. The first 4 bytes are the length of the string
|
|
961 -- table and are part of it.
|
|
962
|
|
963 Seek (Res.Symtab_Stream, Symtab_Size);
|
|
964 Strtab_Size := Read (Res.Symtab_Stream);
|
|
965 Res.Symstr_Stream := Create_Stream
|
|
966 (F,
|
|
967 File_Size (Hdr.PointerToSymbolTable) + File_Size (Symtab_Size),
|
|
968 File_Size (Strtab_Size));
|
|
969
|
|
970 -- Map section table
|
|
971
|
|
972 Opt_Stream := Create_Stream (Res.Mf, Signature_Loc_Offset, 4);
|
|
973 Hdr_Offset := Offset (uint32'(Read (Opt_Stream)));
|
|
974 Close (Opt_Stream);
|
|
975 Res.Sectab_Stream := Create_Stream
|
|
976 (F,
|
|
977 File_Size (Hdr_Offset +
|
|
978 Size_Of_Standard_Header_Fields +
|
|
979 Offset (Hdr.SizeOfOptionalHeader)),
|
|
980 File_Size (Res.Num_Sections)
|
|
981 * File_Size (Section_Header'Size / SSU));
|
|
982
|
|
983 -- Read optional header and extract image base
|
|
984
|
|
985 Opt_Offset := File_Size (Hdr_Offset + Size_Of_Standard_Header_Fields);
|
|
986
|
|
987 if Res.Format = PECOFF then
|
|
988 declare
|
|
989 Opt_32 : Optional_Header_PE32;
|
|
990 begin
|
|
991 Opt_Stream := Create_Stream
|
|
992 (Res.Mf, Opt_Offset, Opt_32'Size / SSU);
|
|
993 Read_Raw
|
|
994 (Opt_Stream, Opt_32'Address, uint32 (Opt_32'Size / SSU));
|
|
995 Res.ImageBase := uint64 (Opt_32.ImageBase);
|
|
996 Close (Opt_Stream);
|
|
997 end;
|
|
998
|
|
999 else
|
|
1000 declare
|
|
1001 Opt_64 : Optional_Header_PE64;
|
|
1002 begin
|
|
1003 Opt_Stream := Create_Stream
|
|
1004 (Res.Mf, Opt_Offset, Opt_64'Size / SSU);
|
|
1005 Read_Raw
|
|
1006 (Opt_Stream, Opt_64'Address, uint32 (Opt_64'Size / SSU));
|
|
1007 Res.ImageBase := Opt_64.ImageBase;
|
|
1008 Close (Opt_Stream);
|
|
1009 end;
|
|
1010 end if;
|
|
1011
|
|
1012 return Res;
|
|
1013 end Initialize;
|
|
1014
|
|
1015 -----------------
|
|
1016 -- Read_Symbol --
|
|
1017 -----------------
|
|
1018
|
|
1019 function Read_Symbol
|
|
1020 (Obj : in out PECOFF_Object_File;
|
|
1021 Off : Offset) return Object_Symbol
|
|
1022 is
|
|
1023 ST_Entry : Symtab_Entry;
|
|
1024 ST_Last : Symtab_Entry;
|
|
1025 Aux_Entry : Auxent_Section;
|
|
1026 Sz : constant Offset := ST_Entry'Size / SSU;
|
|
1027 Result : Object_Symbol;
|
|
1028 Noff : Offset;
|
|
1029 Sym_Off : Offset;
|
|
1030
|
|
1031 begin
|
|
1032 -- Seek to the successor of Prev
|
|
1033
|
|
1034 Noff := Off;
|
|
1035
|
|
1036 loop
|
|
1037 Sym_Off := Noff;
|
|
1038
|
|
1039 Seek (Obj.Symtab_Stream, Sym_Off);
|
|
1040 Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, uint32 (Sz));
|
|
1041
|
|
1042 -- Skip AUX entries
|
|
1043
|
|
1044 Noff := Noff + Offset (1 + ST_Entry.NumberOfAuxSymbols) * Sz;
|
|
1045
|
|
1046 exit when ST_Entry.TypeField = Function_Symbol_Type
|
|
1047 and then ST_Entry.SectionNumber > 0;
|
|
1048
|
|
1049 if Noff >= Obj.Symtab_Last then
|
|
1050 return Null_Symbol;
|
|
1051 end if;
|
|
1052 end loop;
|
|
1053
|
|
1054 -- Construct the symbol
|
|
1055
|
|
1056 Result :=
|
|
1057 (Off => Sym_Off,
|
|
1058 Next => Noff,
|
|
1059 Value => uint64 (ST_Entry.Value),
|
|
1060 Size => 0);
|
|
1061
|
|
1062 -- Set the size as accurately as possible
|
|
1063
|
|
1064 -- The size of a symbol is not directly available so we try scanning
|
|
1065 -- to the next function and assuming the code ends there.
|
|
1066
|
|
1067 loop
|
|
1068 -- Read symbol and AUX entries
|
|
1069
|
|
1070 Sym_Off := Noff;
|
|
1071 Seek (Obj.Symtab_Stream, Sym_Off);
|
|
1072 Read_Raw (Obj.Symtab_Stream, ST_Last'Address, uint32 (Sz));
|
|
1073
|
|
1074 for I in 1 .. ST_Last.NumberOfAuxSymbols loop
|
|
1075 Read_Raw (Obj.Symtab_Stream, Aux_Entry'Address, uint32 (Sz));
|
|
1076 end loop;
|
|
1077
|
|
1078 Noff := Noff + Offset (1 + ST_Last.NumberOfAuxSymbols) * Sz;
|
|
1079
|
|
1080 if ST_Last.TypeField = Function_Symbol_Type then
|
|
1081 if ST_Last.SectionNumber = ST_Entry.SectionNumber
|
|
1082 and then ST_Last.Value >= ST_Entry.Value
|
|
1083 then
|
|
1084 -- Symbol is a function past ST_Entry
|
|
1085
|
|
1086 Result.Size := uint64 (ST_Last.Value - ST_Entry.Value);
|
|
1087
|
|
1088 else
|
|
1089 -- Not correlated function
|
|
1090
|
|
1091 Result.Next := Sym_Off;
|
|
1092 end if;
|
|
1093
|
|
1094 exit;
|
|
1095
|
|
1096 elsif ST_Last.SectionNumber = ST_Entry.SectionNumber
|
|
1097 and then ST_Last.TypeField = Not_Function_Symbol_Type
|
|
1098 and then ST_Last.StorageClass = 3
|
|
1099 and then ST_Last.NumberOfAuxSymbols = 1
|
|
1100 then
|
|
1101 -- Symbol is a section
|
|
1102
|
|
1103 Result.Size := uint64 (ST_Last.Value + Aux_Entry.Length
|
|
1104 - ST_Entry.Value);
|
|
1105 Result.Next := Noff;
|
|
1106 exit;
|
|
1107 end if;
|
|
1108
|
|
1109 exit when Noff >= Obj.Symtab_Last;
|
|
1110 end loop;
|
|
1111
|
|
1112 -- Relocate the address
|
|
1113
|
|
1114 Result.Value :=
|
|
1115 Result.Value + Get_Section_Virtual_Address
|
|
1116 (Obj, uint32 (ST_Entry.SectionNumber - 1));
|
|
1117
|
|
1118 return Result;
|
|
1119 end Read_Symbol;
|
|
1120
|
|
1121 ------------------
|
|
1122 -- Read_Header --
|
|
1123 ------------------
|
|
1124
|
|
1125 function Read_Header (F : in out Mapped_Stream) return Header is
|
|
1126 Hdr : Header;
|
|
1127 Off : int32;
|
|
1128
|
|
1129 begin
|
|
1130 -- Skip the MSDOS stub, and seek directly to the file offset
|
|
1131
|
|
1132 Seek (F, Signature_Loc_Offset);
|
|
1133 Off := Read (F);
|
|
1134
|
|
1135 -- Read the COFF file header
|
|
1136
|
|
1137 Seek (F, Offset (Off));
|
|
1138 Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
|
|
1139 return Hdr;
|
|
1140 end Read_Header;
|
|
1141
|
|
1142 -------------------------
|
|
1143 -- Read_Section_Header --
|
|
1144 -------------------------
|
|
1145
|
|
1146 function Read_Section_Header
|
|
1147 (Obj : in out PECOFF_Object_File;
|
|
1148 Index : uint32) return Section_Header
|
|
1149 is
|
|
1150 Sec : Section_Header;
|
|
1151 begin
|
|
1152 Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
|
|
1153 Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
|
|
1154 return Sec;
|
|
1155 end Read_Section_Header;
|
|
1156
|
|
1157 ----------
|
|
1158 -- Name --
|
|
1159 ----------
|
|
1160
|
|
1161 function Name
|
|
1162 (Obj : in out PECOFF_Object_File;
|
|
1163 Sec : Object_Section) return String
|
|
1164 is
|
|
1165 Shdr : constant Section_Header := Read_Section_Header (Obj, Sec.Num);
|
|
1166 begin
|
|
1167 return Decode_Name (Obj, Shdr.Name);
|
|
1168 end Name;
|
|
1169
|
|
1170 -------------------
|
|
1171 -- String_Table --
|
|
1172 -------------------
|
|
1173
|
|
1174 function String_Table
|
|
1175 (Obj : in out PECOFF_Object_File;
|
|
1176 Index : Offset) return String is
|
|
1177 begin
|
|
1178 -- An index of zero is used to represent an empty string, as the
|
|
1179 -- first word of the string table is specified to contain the length
|
|
1180 -- of the table rather than its contents.
|
|
1181
|
|
1182 if Index = 0 then
|
|
1183 return "";
|
|
1184
|
|
1185 else
|
|
1186 return Offset_To_String (Obj.Symstr_Stream, Index);
|
|
1187 end if;
|
|
1188 end String_Table;
|
|
1189
|
|
1190 ----------
|
|
1191 -- Name --
|
|
1192 ----------
|
|
1193
|
|
1194 function Name
|
|
1195 (Obj : in out PECOFF_Object_File;
|
|
1196 Sym : Object_Symbol) return String_Ptr_Len
|
|
1197 is
|
|
1198 ST_Entry : Symtab_Entry;
|
|
1199
|
|
1200 begin
|
|
1201 Seek (Obj.Symtab_Stream, Sym.Off);
|
|
1202 Read_Raw (Obj.Symtab_Stream, ST_Entry'Address, ST_Entry'Size / SSU);
|
|
1203
|
|
1204 declare
|
|
1205 -- Symbol table entries are packed and Table_Entry.Name may not be
|
|
1206 -- sufficiently aligned to interpret as a 32 bit word, so it is
|
|
1207 -- copied to a temporary
|
|
1208
|
|
1209 Aligned_Name : Name_Str := ST_Entry.Name;
|
|
1210 for Aligned_Name'Alignment use 4;
|
|
1211
|
|
1212 First_Word : uint32;
|
|
1213 pragma Import (Ada, First_Word);
|
|
1214 -- Suppress initialization in Normalized_Scalars mode
|
|
1215 for First_Word'Address use Aligned_Name (1)'Address;
|
|
1216
|
|
1217 Second_Word : uint32;
|
|
1218 pragma Import (Ada, Second_Word);
|
|
1219 -- Suppress initialization in Normalized_Scalars mode
|
|
1220 for Second_Word'Address use Aligned_Name (5)'Address;
|
|
1221
|
|
1222 begin
|
|
1223 if First_Word = 0 then
|
|
1224 -- Second word is an offset in the symbol table
|
|
1225 if Second_Word = 0 then
|
|
1226 return (null, 0);
|
|
1227 else
|
|
1228 Seek (Obj.Symstr_Stream, int64 (Second_Word));
|
|
1229 return Read (Obj.Symstr_Stream);
|
|
1230 end if;
|
|
1231 else
|
|
1232 -- Inlined symbol name
|
|
1233 Seek (Obj.Symtab_Stream, Sym.Off);
|
|
1234 return To_String_Ptr_Len (Read (Obj.Symtab_Stream), 8);
|
|
1235 end if;
|
|
1236 end;
|
|
1237 end Name;
|
|
1238
|
|
1239 end PECOFF_Ops;
|
|
1240
|
|
1241 -----------------
|
|
1242 -- XCOFF32_Ops --
|
|
1243 -----------------
|
|
1244
|
|
1245 package body XCOFF32_Ops is
|
|
1246
|
|
1247 function Read_Section_Header
|
|
1248 (Obj : in out XCOFF32_Object_File;
|
|
1249 Index : uint32) return Section_Header;
|
|
1250 -- Read a header from section table
|
|
1251
|
|
1252 -----------------
|
|
1253 -- Read_Symbol --
|
|
1254 -----------------
|
|
1255
|
|
1256 function Read_Symbol
|
|
1257 (Obj : in out XCOFF32_Object_File;
|
|
1258 Off : Offset) return Object_Symbol
|
|
1259 is
|
|
1260 Sym : Symbol_Entry;
|
|
1261 Sz : constant Offset := Symbol_Entry'Size / SSU;
|
|
1262 Aux : Aux_Entry;
|
|
1263 Result : Object_Symbol;
|
|
1264 Noff : Offset;
|
|
1265 Sym_Off : Offset;
|
|
1266
|
|
1267 procedure Read_LD_Symbol;
|
|
1268 -- Read the next LD symbol
|
|
1269
|
|
1270 --------------------
|
|
1271 -- Read_LD_Symbol --
|
|
1272 --------------------
|
|
1273
|
|
1274 procedure Read_LD_Symbol is
|
|
1275 begin
|
|
1276 loop
|
|
1277 Sym_Off := Noff;
|
|
1278
|
|
1279 Read_Raw (Obj.Symtab_Stream, Sym'Address, uint32 (Sz));
|
|
1280
|
|
1281 Noff := Noff + Offset (1 + Sym.n_numaux) * Sz;
|
|
1282
|
|
1283 for J in 1 .. Sym.n_numaux loop
|
|
1284 Read_Raw (Obj.Symtab_Stream, Aux'Address, uint32 (Sz));
|
|
1285 end loop;
|
|
1286
|
|
1287 exit when Noff >= Obj.Symtab_Last;
|
|
1288
|
|
1289 exit when Sym.n_numaux = 1
|
|
1290 and then Sym.n_scnum /= 0
|
|
1291 and then (Sym.n_sclass = C_EXT
|
|
1292 or else Sym.n_sclass = C_HIDEXT
|
|
1293 or else Sym.n_sclass = C_WEAKEXT)
|
|
1294 and then Aux.x_smtyp = XTY_LD;
|
|
1295 end loop;
|
|
1296 end Read_LD_Symbol;
|
|
1297
|
|
1298 -- Start of processing for Read_Symbol
|
|
1299
|
|
1300 begin
|
|
1301 Seek (Obj.Symtab_Stream, Off);
|
|
1302 Noff := Off;
|
|
1303 Read_LD_Symbol;
|
|
1304
|
|
1305 if Noff >= Obj.Symtab_Last then
|
|
1306 return Null_Symbol;
|
|
1307 end if;
|
|
1308
|
|
1309 -- Construct the symbol
|
|
1310
|
|
1311 Result := (Off => Sym_Off,
|
|
1312 Next => Noff,
|
|
1313 Value => uint64 (Sym.n_value),
|
|
1314 Size => 0);
|
|
1315
|
|
1316 -- Look for the next symbol to compute the size
|
|
1317
|
|
1318 Read_LD_Symbol;
|
|
1319
|
|
1320 if Noff >= Obj.Symtab_Last then
|
|
1321 return Null_Symbol;
|
|
1322 end if;
|
|
1323
|
|
1324 Result.Size := uint64 (Sym.n_value) - Result.Value;
|
|
1325 Result.Next := Sym_Off;
|
|
1326 return Result;
|
|
1327 end Read_Symbol;
|
|
1328
|
|
1329 ------------------
|
|
1330 -- First_Symbol --
|
|
1331 ------------------
|
|
1332
|
|
1333 function First_Symbol
|
|
1334 (Obj : in out XCOFF32_Object_File) return Object_Symbol
|
|
1335 is
|
|
1336 begin
|
|
1337 -- Return Null_Symbol in the case that the symbol table is empty
|
|
1338
|
|
1339 if Obj.Symtab_Last = 0 then
|
|
1340 return Null_Symbol;
|
|
1341 end if;
|
|
1342
|
|
1343 return Read_Symbol (Obj, 0);
|
|
1344 end First_Symbol;
|
|
1345
|
|
1346 ----------------
|
|
1347 -- Initialize --
|
|
1348 ----------------
|
|
1349
|
|
1350 function Initialize
|
|
1351 (F : Mapped_File;
|
|
1352 Hdr : Header;
|
|
1353 In_Exception : Boolean) return XCOFF32_Object_File
|
|
1354 is
|
|
1355 Res : XCOFF32_Object_File (Format => XCOFF32);
|
|
1356 Strtab_Sz : uint32;
|
|
1357 begin
|
|
1358 Res.Mf := F;
|
|
1359 Res.In_Exception := In_Exception;
|
|
1360
|
|
1361 Res.Arch := PPC;
|
|
1362
|
|
1363 -- Map sections table
|
|
1364 Res.Num_Sections := uint32 (Hdr.f_nscns);
|
|
1365 Res.Sectab_Stream := Create_Stream
|
|
1366 (F,
|
|
1367 File_Size (Header'Size / SSU) + File_Size (Hdr.f_opthdr),
|
|
1368 File_Size (Hdr.f_nscns) * (Section_Header'Size / SSU));
|
|
1369
|
|
1370 -- Map symbols table
|
|
1371 Res.Symtab_Last := Offset (Hdr.f_nscns) * (Symbol_Entry'Size / SSU);
|
|
1372 Res.Symtab_Stream := Create_Stream
|
|
1373 (F,
|
|
1374 File_Size (Hdr.f_symptr),
|
|
1375 File_Size (Res.Symtab_Last) + 4);
|
|
1376
|
|
1377 -- Map string table
|
|
1378 Seek (Res.Symtab_Stream, Res.Symtab_Last);
|
|
1379 Strtab_Sz := Read (Res.Symtab_Stream);
|
|
1380 Res.Symstr_Stream := Create_Stream
|
|
1381 (F,
|
|
1382 File_Size (Res.Symtab_Last) + 4,
|
|
1383 File_Size (Strtab_Sz) - 4);
|
|
1384
|
|
1385 return Res;
|
|
1386 end Initialize;
|
|
1387
|
|
1388 -----------------
|
|
1389 -- Get_Section --
|
|
1390 -----------------
|
|
1391
|
|
1392 function Get_Section
|
|
1393 (Obj : in out XCOFF32_Object_File;
|
|
1394 Index : uint32) return Object_Section
|
|
1395 is
|
|
1396 Sec : constant Section_Header := Read_Section_Header (Obj, Index);
|
|
1397 begin
|
|
1398 return (Index, Offset (Sec.s_scnptr),
|
|
1399 uint64 (Sec.s_vaddr),
|
|
1400 uint64 (Sec.s_size),
|
|
1401 (Sec.s_flags and STYP_TEXT) /= 0);
|
|
1402 end Get_Section;
|
|
1403
|
|
1404 -----------------
|
|
1405 -- Read_Header --
|
|
1406 -----------------
|
|
1407
|
|
1408 function Read_Header (F : in out Mapped_Stream) return Header is
|
|
1409 Hdr : Header;
|
|
1410 begin
|
|
1411 Seek (F, 0);
|
|
1412 Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU));
|
|
1413 return Hdr;
|
|
1414 end Read_Header;
|
|
1415
|
|
1416 -------------------------
|
|
1417 -- Read_Section_Header --
|
|
1418 -------------------------
|
|
1419
|
|
1420 function Read_Section_Header
|
|
1421 (Obj : in out XCOFF32_Object_File;
|
|
1422 Index : uint32) return Section_Header
|
|
1423 is
|
|
1424 Sec : Section_Header;
|
|
1425
|
|
1426 begin
|
|
1427 -- Seek to the end of the object header
|
|
1428
|
|
1429 Seek (Obj.Sectab_Stream, Offset (Index * Section_Header'Size / SSU));
|
|
1430
|
|
1431 -- Read the section
|
|
1432
|
|
1433 Read_Raw (Obj.Sectab_Stream, Sec'Address, Section_Header'Size / SSU);
|
|
1434
|
|
1435 return Sec;
|
|
1436 end Read_Section_Header;
|
|
1437
|
|
1438 ----------
|
|
1439 -- Name --
|
|
1440 ----------
|
|
1441
|
|
1442 function Name
|
|
1443 (Obj : in out XCOFF32_Object_File;
|
|
1444 Sec : Object_Section) return String
|
|
1445 is
|
|
1446 Hdr : Section_Header;
|
|
1447 begin
|
|
1448 Hdr := Read_Section_Header (Obj, Sec.Num);
|
|
1449 return Trim_Trailing_Nuls (Hdr.s_name);
|
|
1450 end Name;
|
|
1451
|
|
1452 ----------
|
|
1453 -- Name --
|
|
1454 ----------
|
|
1455
|
|
1456 function Name
|
|
1457 (Obj : in out XCOFF32_Object_File;
|
|
1458 Sym : Object_Symbol) return String_Ptr_Len
|
|
1459 is
|
|
1460 Symbol : Symbol_Entry;
|
|
1461
|
|
1462 begin
|
|
1463 Seek (Obj.Symtab_Stream, Sym.Off);
|
|
1464 Read_Raw (Obj.Symtab_Stream, Symbol'Address, Symbol'Size / SSU);
|
|
1465
|
|
1466 declare
|
|
1467 First_Word : uint32;
|
|
1468 pragma Import (Ada, First_Word);
|
|
1469 -- Suppress initialization in Normalized_Scalars mode
|
|
1470 for First_Word'Address use Symbol.n_name (1)'Address;
|
|
1471
|
|
1472 Second_Word : uint32;
|
|
1473 pragma Import (Ada, Second_Word);
|
|
1474 -- Suppress initialization in Normalized_Scalars mode
|
|
1475 for Second_Word'Address use Symbol.n_name (5)'Address;
|
|
1476
|
|
1477 begin
|
|
1478 if First_Word = 0 then
|
|
1479 if Second_Word = 0 then
|
|
1480 return (null, 0);
|
|
1481 else
|
|
1482 Seek (Obj.Symstr_Stream, int64 (Second_Word));
|
|
1483 return Read (Obj.Symstr_Stream);
|
|
1484 end if;
|
|
1485 else
|
|
1486 Seek (Obj.Symtab_Stream, Sym.Off);
|
|
1487 return To_String_Ptr_Len (Read (Obj.Symstr_Stream), 8);
|
|
1488 end if;
|
|
1489 end;
|
|
1490 end Name;
|
|
1491 end XCOFF32_Ops;
|
|
1492
|
|
1493 ----------
|
|
1494 -- Arch --
|
|
1495 ----------
|
|
1496
|
|
1497 function Arch (Obj : Object_File) return Object_Arch is
|
|
1498 begin
|
|
1499 return Obj.Arch;
|
|
1500 end Arch;
|
|
1501
|
|
1502 function Create_Stream
|
|
1503 (Mf : Mapped_File;
|
|
1504 File_Offset : File_Size;
|
|
1505 File_Length : File_Size)
|
|
1506 return Mapped_Stream
|
|
1507 is
|
|
1508 Region : Mapped_Region;
|
|
1509 begin
|
|
1510 Read (Mf, Region, File_Offset, File_Length, False);
|
|
1511 return (Region, 0, Offset (File_Length));
|
|
1512 end Create_Stream;
|
|
1513
|
|
1514 function Create_Stream
|
|
1515 (Obj : Object_File;
|
|
1516 Sec : Object_Section) return Mapped_Stream is
|
|
1517 begin
|
|
1518 return Create_Stream (Obj.Mf, File_Size (Sec.Off), File_Size (Sec.Size));
|
|
1519 end Create_Stream;
|
|
1520
|
|
1521 procedure Tell (Obj : in out Mapped_Stream; Off : out Offset) is
|
|
1522 begin
|
|
1523 Off := Obj.Off;
|
|
1524 end Tell;
|
|
1525
|
|
1526 function Tell (Obj : Mapped_Stream) return Offset is
|
|
1527 begin
|
|
1528 return Obj.Off;
|
|
1529 end Tell;
|
|
1530
|
|
1531 function Length (Obj : Mapped_Stream) return Offset is
|
|
1532 begin
|
|
1533 return Obj.Len;
|
|
1534 end Length;
|
|
1535
|
|
1536 -----------
|
|
1537 -- Close --
|
|
1538 -----------
|
|
1539
|
|
1540 procedure Close (S : in out Mapped_Stream) is
|
|
1541 begin
|
|
1542 Free (S.Region);
|
|
1543 end Close;
|
|
1544
|
|
1545 procedure Close (Obj : in out Object_File) is
|
|
1546 begin
|
|
1547 Close (Obj.Symtab_Stream);
|
|
1548 Close (Obj.Symstr_Stream);
|
|
1549 Close (Obj.Sectab_Stream);
|
|
1550
|
|
1551 case Obj.Format is
|
|
1552 when ELF =>
|
|
1553 Close (Obj.Secstr_Stream);
|
|
1554 when Any_PECOFF =>
|
|
1555 null;
|
|
1556 when XCOFF32 =>
|
|
1557 null;
|
|
1558 end case;
|
|
1559
|
|
1560 Close (Obj.Mf);
|
|
1561 end Close;
|
|
1562
|
|
1563 ------------------------
|
|
1564 -- Strip_Leading_Char --
|
|
1565 ------------------------
|
|
1566
|
|
1567 function Strip_Leading_Char
|
|
1568 (Obj : in out Object_File;
|
|
1569 Sym : String_Ptr_Len) return Positive is
|
|
1570 begin
|
|
1571 if (Obj.Format = PECOFF and then Sym.Ptr (1) = '_')
|
|
1572 or else
|
|
1573 (Obj.Format = XCOFF32 and then Sym.Ptr (1) = '.')
|
|
1574 then
|
|
1575 return 2;
|
|
1576 else
|
|
1577 return 1;
|
|
1578 end if;
|
|
1579 end Strip_Leading_Char;
|
|
1580
|
|
1581 ----------------------
|
|
1582 -- Decoded_Ada_Name --
|
|
1583 ----------------------
|
|
1584
|
|
1585 function Decoded_Ada_Name
|
|
1586 (Obj : in out Object_File;
|
|
1587 Sym : String_Ptr_Len) return String
|
|
1588 is
|
|
1589 procedure gnat_decode
|
|
1590 (Coded_Name_Addr : Address;
|
|
1591 Ada_Name_Addr : Address;
|
|
1592 Verbose : int);
|
|
1593 pragma Import (C, gnat_decode, "__gnat_decode");
|
|
1594
|
|
1595 subtype size_t is Interfaces.C.size_t;
|
|
1596
|
|
1597 Sym_Name : constant String :=
|
|
1598 String (Sym.Ptr (1 .. Sym.Len)) & ASCII.NUL;
|
|
1599 Decoded : char_array (0 .. size_t (Sym.Len) * 2 + 60);
|
|
1600 Off : Natural;
|
|
1601 begin
|
|
1602 -- In the PECOFF case most but not all symbol table entries have an
|
|
1603 -- extra leading underscore. In this case we trim it.
|
|
1604
|
|
1605 Off := Strip_Leading_Char (Obj, Sym);
|
|
1606
|
|
1607 gnat_decode (Sym_Name (Off)'Address, Decoded'Address, 0);
|
|
1608
|
|
1609 return To_Ada (Decoded);
|
|
1610 end Decoded_Ada_Name;
|
|
1611
|
|
1612 ------------------
|
|
1613 -- First_Symbol --
|
|
1614 ------------------
|
|
1615
|
|
1616 function First_Symbol (Obj : in out Object_File) return Object_Symbol is
|
|
1617 begin
|
|
1618 case Obj.Format is
|
|
1619 when ELF32 => return ELF32_Ops.First_Symbol (Obj);
|
|
1620 when ELF64 => return ELF64_Ops.First_Symbol (Obj);
|
|
1621 when Any_PECOFF => return PECOFF_Ops.First_Symbol (Obj);
|
|
1622 when XCOFF32 => return XCOFF32_Ops.First_Symbol (Obj);
|
|
1623 end case;
|
|
1624 end First_Symbol;
|
|
1625
|
|
1626 ------------
|
|
1627 -- Format --
|
|
1628 ------------
|
|
1629
|
|
1630 function Format (Obj : Object_File) return Object_Format is
|
|
1631 begin
|
|
1632 return Obj.Format;
|
|
1633 end Format;
|
|
1634
|
|
1635 ----------------------
|
|
1636 -- Get_Load_Address --
|
|
1637 ----------------------
|
|
1638
|
|
1639 function Get_Load_Address (Obj : Object_File) return uint64 is
|
|
1640 begin
|
|
1641 raise Format_Error with "Get_Load_Address not implemented";
|
|
1642 return 0;
|
|
1643 end Get_Load_Address;
|
|
1644
|
|
1645 -----------------
|
|
1646 -- Get_Section --
|
|
1647 -----------------
|
|
1648
|
|
1649 function Get_Section
|
|
1650 (Obj : in out Object_File;
|
|
1651 Shnum : uint32) return Object_Section is
|
|
1652 begin
|
|
1653 case Obj.Format is
|
|
1654 when ELF32 => return ELF32_Ops.Get_Section (Obj, Shnum);
|
|
1655 when ELF64 => return ELF64_Ops.Get_Section (Obj, Shnum);
|
|
1656 when Any_PECOFF => return PECOFF_Ops.Get_Section (Obj, Shnum);
|
|
1657 when XCOFF32 => return XCOFF32_Ops.Get_Section (Obj, Shnum);
|
|
1658 end case;
|
|
1659 end Get_Section;
|
|
1660
|
|
1661 function Get_Section
|
|
1662 (Obj : in out Object_File;
|
|
1663 Sec_Name : String) return Object_Section
|
|
1664 is
|
|
1665 Sec : Object_Section;
|
|
1666
|
|
1667 begin
|
|
1668 for J in 0 .. Obj.Num_Sections - 1 loop
|
|
1669 Sec := Get_Section (Obj, J);
|
|
1670
|
|
1671 if Name (Obj, Sec) = Sec_Name then
|
|
1672 return Sec;
|
|
1673 end if;
|
|
1674 end loop;
|
|
1675
|
|
1676 if Obj.In_Exception then
|
|
1677 return Null_Section;
|
|
1678 else
|
|
1679 raise Format_Error with "could not find section in object file";
|
|
1680 end if;
|
|
1681 end Get_Section;
|
|
1682
|
131
|
1683 ----------------------
|
|
1684 -- Get_Xcode_Bounds --
|
|
1685 ----------------------
|
111
|
1686
|
131
|
1687 procedure Get_Xcode_Bounds
|
111
|
1688 (Obj : in out Object_File;
|
|
1689 Low, High : out uint64) is
|
|
1690 Sec : Object_Section;
|
|
1691 begin
|
|
1692 -- First set as an empty range
|
|
1693 Low := uint64'Last;
|
|
1694 High := uint64'First;
|
|
1695
|
131
|
1696 -- Now find the lowest and highest offsets
|
|
1697 -- attached to executable code sections
|
111
|
1698 for Idx in 1 .. Num_Sections (Obj) loop
|
|
1699 Sec := Get_Section (Obj, Idx - 1);
|
131
|
1700 if Sec.Flag_Xcode then
|
111
|
1701 if Sec.Addr < Low then
|
|
1702 Low := Sec.Addr;
|
|
1703 end if;
|
|
1704 if Sec.Addr + Sec.Size > High then
|
|
1705 High := Sec.Addr + Sec.Size;
|
|
1706 end if;
|
|
1707 end if;
|
|
1708 end loop;
|
131
|
1709 end Get_Xcode_Bounds;
|
111
|
1710
|
|
1711 ----------
|
|
1712 -- Name --
|
|
1713 ----------
|
|
1714
|
|
1715 function Name
|
|
1716 (Obj : in out Object_File;
|
|
1717 Sec : Object_Section) return String is
|
|
1718 begin
|
|
1719 case Obj.Format is
|
|
1720 when ELF32 => return ELF32_Ops.Name (Obj, Sec);
|
|
1721 when ELF64 => return ELF64_Ops.Name (Obj, Sec);
|
|
1722 when Any_PECOFF => return PECOFF_Ops.Name (Obj, Sec);
|
|
1723 when XCOFF32 => return XCOFF32_Ops.Name (Obj, Sec);
|
|
1724 end case;
|
|
1725 end Name;
|
|
1726
|
|
1727 function Name
|
|
1728 (Obj : in out Object_File;
|
|
1729 Sym : Object_Symbol) return String_Ptr_Len is
|
|
1730 begin
|
|
1731 case Obj.Format is
|
|
1732 when ELF32 => return ELF32_Ops.Name (Obj, Sym);
|
|
1733 when ELF64 => return ELF64_Ops.Name (Obj, Sym);
|
|
1734 when Any_PECOFF => return PECOFF_Ops.Name (Obj, Sym);
|
|
1735 when XCOFF32 => return XCOFF32_Ops.Name (Obj, Sym);
|
|
1736 end case;
|
|
1737 end Name;
|
|
1738
|
|
1739 -----------------
|
|
1740 -- Next_Symbol --
|
|
1741 -----------------
|
|
1742
|
|
1743 function Next_Symbol
|
|
1744 (Obj : in out Object_File;
|
|
1745 Prev : Object_Symbol) return Object_Symbol is
|
|
1746 begin
|
|
1747 -- Test whether we've reached the end of the symbol table
|
|
1748
|
|
1749 if Prev.Next >= Obj.Symtab_Last then
|
|
1750 return Null_Symbol;
|
|
1751 end if;
|
|
1752
|
|
1753 return Read_Symbol (Obj, Prev.Next);
|
|
1754 end Next_Symbol;
|
|
1755
|
|
1756 ---------
|
|
1757 -- Num --
|
|
1758 ---------
|
|
1759
|
|
1760 function Num (Sec : Object_Section) return uint32 is
|
|
1761 begin
|
|
1762 return Sec.Num;
|
|
1763 end Num;
|
|
1764
|
|
1765 ------------------
|
|
1766 -- Num_Sections --
|
|
1767 ------------------
|
|
1768
|
|
1769 function Num_Sections (Obj : Object_File) return uint32 is
|
|
1770 begin
|
|
1771 return Obj.Num_Sections;
|
|
1772 end Num_Sections;
|
|
1773
|
|
1774 ---------
|
|
1775 -- Off --
|
|
1776 ---------
|
|
1777
|
|
1778 function Off (Sec : Object_Section) return Offset is
|
|
1779 begin
|
|
1780 return Sec.Off;
|
|
1781 end Off;
|
|
1782
|
|
1783 function Off (Sym : Object_Symbol) return Offset is
|
|
1784 begin
|
|
1785 return Sym.Off;
|
|
1786 end Off;
|
|
1787
|
|
1788 ----------------------
|
|
1789 -- Offset_To_String --
|
|
1790 ----------------------
|
|
1791
|
|
1792 function Offset_To_String
|
|
1793 (S : in out Mapped_Stream;
|
|
1794 Off : Offset) return String
|
|
1795 is
|
|
1796 Buf : Buffer;
|
|
1797 begin
|
|
1798 Seek (S, Off);
|
|
1799 Read_C_String (S, Buf);
|
|
1800 return To_String (Buf);
|
|
1801 end Offset_To_String;
|
|
1802
|
|
1803 ----------
|
|
1804 -- Open --
|
|
1805 ----------
|
|
1806
|
|
1807 function Open
|
|
1808 (File_Name : String;
|
|
1809 In_Exception : Boolean := False) return Object_File_Access
|
|
1810 is
|
|
1811 F : Mapped_File;
|
|
1812 Hdr_Stream : Mapped_Stream;
|
|
1813
|
|
1814 begin
|
|
1815 -- Open the file
|
|
1816
|
|
1817 F := Open_Read_No_Exception (File_Name);
|
|
1818
|
|
1819 if F = Invalid_Mapped_File then
|
|
1820 if In_Exception then
|
|
1821 return null;
|
|
1822 else
|
|
1823 raise IO_Error with "could not open object file";
|
|
1824 end if;
|
|
1825 end if;
|
|
1826
|
|
1827 Hdr_Stream := Create_Stream (F, 0, 4096);
|
|
1828
|
|
1829 declare
|
|
1830 Hdr : constant ELF32_Ops.Header := ELF32_Ops.Read_Header (Hdr_Stream);
|
|
1831
|
|
1832 begin
|
|
1833 -- Look for the magic numbers for the ELF case
|
|
1834
|
|
1835 if Hdr.E_Ident (0) = 16#7F# and then
|
|
1836 Hdr.E_Ident (1) = Character'Pos ('E') and then
|
|
1837 Hdr.E_Ident (2) = Character'Pos ('L') and then
|
|
1838 Hdr.E_Ident (3) = Character'Pos ('F') and then
|
|
1839 Hdr.E_Ident (4) = ELF32_Ops.ELFCLASS32
|
|
1840 then
|
|
1841 Close (Hdr_Stream);
|
|
1842 return new Object_File'
|
|
1843 (ELF32_Ops.Initialize (F, Hdr, In_Exception));
|
|
1844 end if;
|
|
1845 end;
|
|
1846
|
|
1847 declare
|
|
1848 Hdr : constant ELF64_Ops.Header :=
|
|
1849 ELF64_Ops.Read_Header (Hdr_Stream);
|
|
1850
|
|
1851 begin
|
|
1852 -- Look for the magic numbers for the ELF case
|
|
1853
|
|
1854 if Hdr.E_Ident (0) = 16#7F# and then
|
|
1855 Hdr.E_Ident (1) = Character'Pos ('E') and then
|
|
1856 Hdr.E_Ident (2) = Character'Pos ('L') and then
|
|
1857 Hdr.E_Ident (3) = Character'Pos ('F') and then
|
|
1858 Hdr.E_Ident (4) = ELF32_Ops.ELFCLASS64
|
|
1859 then
|
|
1860 Close (Hdr_Stream);
|
|
1861 return new Object_File'
|
|
1862 (ELF64_Ops.Initialize (F, Hdr, In_Exception));
|
|
1863 end if;
|
|
1864 end;
|
|
1865
|
|
1866 declare
|
|
1867 Hdr : constant PECOFF_Ops.Header :=
|
|
1868 PECOFF_Ops.Read_Header (Hdr_Stream);
|
|
1869
|
|
1870 begin
|
|
1871 -- Test the magic numbers
|
|
1872
|
|
1873 if Hdr.Magics (0) = Character'Pos ('P') and then
|
|
1874 Hdr.Magics (1) = Character'Pos ('E') and then
|
|
1875 Hdr.Magics (2) = 0 and then
|
|
1876 Hdr.Magics (3) = 0
|
|
1877 then
|
|
1878 Close (Hdr_Stream);
|
|
1879 return new Object_File'
|
|
1880 (PECOFF_Ops.Initialize (F, Hdr, In_Exception));
|
|
1881 end if;
|
|
1882
|
|
1883 exception
|
|
1884 -- If this is not a PECOFF file then we've done a seek and read to a
|
|
1885 -- random address, possibly raising IO_Error
|
|
1886
|
|
1887 when IO_Error =>
|
|
1888 null;
|
|
1889 end;
|
|
1890
|
|
1891 declare
|
|
1892 Hdr : constant XCOFF32_Ops.Header :=
|
|
1893 XCOFF32_Ops.Read_Header (Hdr_Stream);
|
|
1894
|
|
1895 begin
|
|
1896 -- Test the magic numbers
|
|
1897
|
|
1898 if Hdr.f_magic = 8#0737# then
|
|
1899 Close (Hdr_Stream);
|
|
1900 return new Object_File'
|
|
1901 (XCOFF32_Ops.Initialize (F, Hdr, In_Exception));
|
|
1902 end if;
|
|
1903 end;
|
|
1904
|
|
1905 Close (Hdr_Stream);
|
|
1906
|
|
1907 if In_Exception then
|
|
1908 return null;
|
|
1909 else
|
|
1910 raise Format_Error with "unrecognized object format";
|
|
1911 end if;
|
|
1912 end Open;
|
|
1913
|
|
1914 ----------
|
|
1915 -- Read --
|
|
1916 ----------
|
|
1917
|
|
1918 function Read (S : in out Mapped_Stream) return Mmap.Str_Access
|
|
1919 is
|
|
1920 function To_Str_Access is
|
|
1921 new Ada.Unchecked_Conversion (Address, Str_Access);
|
|
1922 begin
|
|
1923 return To_Str_Access (Data (S.Region) (Natural (S.Off + 1))'Address);
|
|
1924 end Read;
|
|
1925
|
|
1926 function Read (S : in out Mapped_Stream) return String_Ptr_Len is
|
|
1927 begin
|
|
1928 return To_String_Ptr_Len (Read (S));
|
|
1929 end Read;
|
|
1930
|
|
1931 procedure Check_Read_Offset (S : in out Mapped_Stream; Size : uint32) is
|
|
1932 begin
|
|
1933 if S.Off + Offset (Size) > Offset (Last (S.Region)) then
|
|
1934 raise IO_Error with "could not read from object file";
|
|
1935 end if;
|
|
1936 end Check_Read_Offset;
|
|
1937
|
|
1938 procedure Read_Raw
|
|
1939 (S : in out Mapped_Stream;
|
|
1940 Addr : Address;
|
|
1941 Size : uint32)
|
|
1942 is
|
|
1943 function To_Str_Access is
|
|
1944 new Ada.Unchecked_Conversion (Address, Str_Access);
|
|
1945
|
|
1946 Sz : constant Offset := Offset (Size);
|
|
1947 begin
|
|
1948 -- Check size
|
|
1949
|
|
1950 pragma Debug (Check_Read_Offset (S, Size));
|
|
1951
|
|
1952 -- Copy data
|
|
1953
|
|
1954 To_Str_Access (Addr) (1 .. Positive (Sz)) :=
|
|
1955 Data (S.Region) (Positive (S.Off + 1) .. Positive (S.Off + Sz));
|
|
1956
|
|
1957 -- Update offset
|
|
1958
|
|
1959 S.Off := S.Off + Sz;
|
|
1960 end Read_Raw;
|
|
1961
|
|
1962 function Read (S : in out Mapped_Stream) return uint8 is
|
|
1963 Data : uint8;
|
|
1964 begin
|
|
1965 Read_Raw (S, Data'Address, Data'Size / SSU);
|
|
1966 return Data;
|
|
1967 end Read;
|
|
1968
|
|
1969 function Read (S : in out Mapped_Stream) return uint16 is
|
|
1970 Data : uint16;
|
|
1971 begin
|
|
1972 Read_Raw (S, Data'Address, Data'Size / SSU);
|
|
1973 return Data;
|
|
1974 end Read;
|
|
1975
|
|
1976 function Read (S : in out Mapped_Stream) return uint32 is
|
|
1977 Data : uint32;
|
|
1978 begin
|
|
1979 Read_Raw (S, Data'Address, Data'Size / SSU);
|
|
1980 return Data;
|
|
1981 end Read;
|
|
1982
|
|
1983 function Read (S : in out Mapped_Stream) return uint64 is
|
|
1984 Data : uint64;
|
|
1985 begin
|
|
1986 Read_Raw (S, Data'Address, Data'Size / SSU);
|
|
1987 return Data;
|
|
1988 end Read;
|
|
1989
|
|
1990 function Read (S : in out Mapped_Stream) return int8 is
|
|
1991 Data : int8;
|
|
1992 begin
|
|
1993 Read_Raw (S, Data'Address, Data'Size / SSU);
|
|
1994 return Data;
|
|
1995 end Read;
|
|
1996
|
|
1997 function Read (S : in out Mapped_Stream) return int16 is
|
|
1998 Data : int16;
|
|
1999 begin
|
|
2000 Read_Raw (S, Data'Address, Data'Size / SSU);
|
|
2001 return Data;
|
|
2002 end Read;
|
|
2003
|
|
2004 function Read (S : in out Mapped_Stream) return int32 is
|
|
2005 Data : int32;
|
|
2006 begin
|
|
2007 Read_Raw (S, Data'Address, Data'Size / SSU);
|
|
2008 return Data;
|
|
2009 end Read;
|
|
2010
|
|
2011 function Read (S : in out Mapped_Stream) return int64 is
|
|
2012 Data : int64;
|
|
2013 begin
|
|
2014 Read_Raw (S, Data'Address, Data'Size / SSU);
|
|
2015 return Data;
|
|
2016 end Read;
|
|
2017
|
|
2018 ------------------
|
|
2019 -- Read_Address --
|
|
2020 ------------------
|
|
2021
|
|
2022 function Read_Address
|
|
2023 (Obj : Object_File; S : in out Mapped_Stream) return uint64 is
|
|
2024 Address_32 : uint32;
|
|
2025 Address_64 : uint64;
|
|
2026
|
|
2027 begin
|
|
2028 case Obj.Arch is
|
|
2029 when i386
|
|
2030 | MIPS
|
|
2031 | PPC
|
|
2032 | SPARC
|
|
2033 =>
|
|
2034 Address_32 := Read (S);
|
|
2035 return uint64 (Address_32);
|
|
2036
|
|
2037 when IA64
|
|
2038 | PPC64
|
|
2039 | SPARC64
|
|
2040 | x86_64
|
|
2041 =>
|
|
2042 Address_64 := Read (S);
|
|
2043 return Address_64;
|
|
2044
|
|
2045 when Unknown =>
|
|
2046 raise Format_Error with "unrecognized machine architecture";
|
|
2047 end case;
|
|
2048 end Read_Address;
|
|
2049
|
|
2050 -------------------
|
|
2051 -- Read_C_String --
|
|
2052 -------------------
|
|
2053
|
|
2054 procedure Read_C_String (S : in out Mapped_Stream; B : out Buffer) is
|
|
2055 J : Integer := 0;
|
|
2056
|
|
2057 begin
|
|
2058 loop
|
|
2059 -- Handle overflow case
|
|
2060
|
|
2061 if J = B'Last then
|
|
2062 B (J) := 0;
|
|
2063 exit;
|
|
2064 end if;
|
|
2065
|
|
2066 B (J) := Read (S);
|
|
2067 exit when B (J) = 0;
|
|
2068 J := J + 1;
|
|
2069 end loop;
|
|
2070 end Read_C_String;
|
|
2071
|
|
2072 -------------------
|
|
2073 -- Read_C_String --
|
|
2074 -------------------
|
|
2075
|
|
2076 function Read_C_String (S : in out Mapped_Stream) return Str_Access is
|
|
2077 Res : constant Str_Access := Read (S);
|
|
2078
|
|
2079 begin
|
|
2080 for J in Res'Range loop
|
|
2081 if S.Off + Offset (J - 1) > Offset (Last (S.Region)) then
|
|
2082 raise IO_Error with "could not read from object file";
|
|
2083 end if;
|
|
2084
|
|
2085 if Res (J) = ASCII.NUL then
|
|
2086 S.Off := S.Off + Offset (J);
|
|
2087 return Res;
|
|
2088 end if;
|
|
2089 end loop;
|
|
2090
|
|
2091 -- Overflow case
|
|
2092 raise Constraint_Error;
|
|
2093 end Read_C_String;
|
|
2094
|
|
2095 -----------------
|
|
2096 -- Read_LEB128 --
|
|
2097 -----------------
|
|
2098
|
|
2099 function Read_LEB128 (S : in out Mapped_Stream) return uint32 is
|
|
2100 B : uint8;
|
|
2101 Shift : Integer := 0;
|
|
2102 Res : uint32 := 0;
|
|
2103
|
|
2104 begin
|
|
2105 loop
|
|
2106 B := Read (S);
|
|
2107 Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
|
|
2108 exit when (B and 16#80#) = 0;
|
|
2109 Shift := Shift + 7;
|
|
2110 end loop;
|
|
2111
|
|
2112 return Res;
|
|
2113 end Read_LEB128;
|
|
2114
|
|
2115 function Read_LEB128 (S : in out Mapped_Stream) return int32 is
|
|
2116 B : uint8;
|
|
2117 Shift : Integer := 0;
|
|
2118 Res : uint32 := 0;
|
|
2119
|
|
2120 begin
|
|
2121 loop
|
|
2122 B := Read (S);
|
|
2123 Res := Res or Shift_Left (uint32 (B and 16#7f#), Shift);
|
|
2124 Shift := Shift + 7;
|
|
2125 exit when (B and 16#80#) = 0;
|
|
2126 end loop;
|
|
2127
|
|
2128 if Shift < 32 and then (Res and Shift_Left (1, Shift - 1)) /= 0 then
|
|
2129 Res := Res or Shift_Left (-1, Shift);
|
|
2130 end if;
|
|
2131
|
|
2132 return To_int32 (Res);
|
|
2133 end Read_LEB128;
|
|
2134
|
|
2135 -----------------
|
|
2136 -- Read_Symbol --
|
|
2137 -----------------
|
|
2138
|
|
2139 function Read_Symbol
|
|
2140 (Obj : in out Object_File;
|
|
2141 Off : Offset) return Object_Symbol is
|
|
2142 begin
|
|
2143 case Obj.Format is
|
|
2144 when ELF32 => return ELF32_Ops.Read_Symbol (Obj, Off);
|
|
2145 when ELF64 => return ELF64_Ops.Read_Symbol (Obj, Off);
|
|
2146 when Any_PECOFF => return PECOFF_Ops.Read_Symbol (Obj, Off);
|
|
2147 when XCOFF32 => return XCOFF32_Ops.Read_Symbol (Obj, Off);
|
|
2148 end case;
|
|
2149 end Read_Symbol;
|
|
2150
|
|
2151 ----------
|
|
2152 -- Seek --
|
|
2153 ----------
|
|
2154
|
|
2155 procedure Seek (S : in out Mapped_Stream; Off : Offset) is
|
|
2156 begin
|
|
2157 if Off < 0 or else Off > Offset (Last (S.Region)) then
|
|
2158 raise IO_Error with "could not seek to offset in object file";
|
|
2159 end if;
|
|
2160
|
|
2161 S.Off := Off;
|
|
2162 end Seek;
|
|
2163
|
|
2164 ----------
|
|
2165 -- Size --
|
|
2166 ----------
|
|
2167
|
|
2168 function Size (Sec : Object_Section) return uint64 is
|
|
2169 begin
|
|
2170 return Sec.Size;
|
|
2171 end Size;
|
|
2172
|
|
2173 function Size (Sym : Object_Symbol) return uint64 is
|
|
2174 begin
|
|
2175 return Sym.Size;
|
|
2176 end Size;
|
|
2177
|
|
2178 ------------
|
|
2179 -- Strlen --
|
|
2180 ------------
|
|
2181
|
|
2182 function Strlen (Buf : Buffer) return int32 is
|
|
2183 begin
|
|
2184 return int32 (CRTL.strlen (Buf'Address));
|
|
2185 end Strlen;
|
|
2186
|
|
2187 -----------
|
|
2188 -- Spans --
|
|
2189 -----------
|
|
2190
|
|
2191 function Spans (Sym : Object_Symbol; Addr : uint64) return Boolean is
|
|
2192 begin
|
|
2193 return Addr >= Sym.Value and then Addr < Sym.Value + Sym.Size;
|
|
2194 end Spans;
|
|
2195
|
|
2196 ---------------
|
|
2197 -- To_String --
|
|
2198 ---------------
|
|
2199
|
|
2200 function To_String (Buf : Buffer) return String is
|
|
2201 Result : String (1 .. Integer (CRTL.strlen (Buf'Address)));
|
|
2202 for Result'Address use Buf'Address;
|
|
2203 pragma Import (Ada, Result);
|
|
2204
|
|
2205 begin
|
|
2206 return Result;
|
|
2207 end To_String;
|
|
2208
|
|
2209 -----------------------
|
|
2210 -- To_String_Ptr_Len --
|
|
2211 -----------------------
|
|
2212
|
|
2213 function To_String_Ptr_Len
|
|
2214 (Ptr : Mmap.Str_Access;
|
|
2215 Max_Len : Natural := Natural'Last) return String_Ptr_Len is
|
|
2216 begin
|
|
2217 for I in 1 .. Max_Len loop
|
|
2218 if Ptr (I) = ASCII.NUL then
|
|
2219 return (Ptr, I - 1);
|
|
2220 end if;
|
|
2221 end loop;
|
|
2222 return (Ptr, Max_Len);
|
|
2223 end To_String_Ptr_Len;
|
|
2224
|
|
2225 ------------------------
|
|
2226 -- Trim_Trailing_Nuls --
|
|
2227 ------------------------
|
|
2228
|
|
2229 function Trim_Trailing_Nuls (Str : String) return String is
|
|
2230 begin
|
|
2231 for J in Str'Range loop
|
|
2232 if Str (J) = ASCII.NUL then
|
|
2233 return Str (Str'First .. J - 1);
|
|
2234 end if;
|
|
2235 end loop;
|
|
2236
|
|
2237 return Str;
|
|
2238 end Trim_Trailing_Nuls;
|
|
2239
|
|
2240 -----------
|
|
2241 -- Value --
|
|
2242 -----------
|
|
2243
|
|
2244 function Value (Sym : Object_Symbol) return uint64 is
|
|
2245 begin
|
|
2246 return Sym.Value;
|
|
2247 end Value;
|
|
2248
|
|
2249 end System.Object_Reader;
|