1# This file is part of PeachPy package and is licensed under the Simplified BSD license.
2#    See license.rst for the full text of the license.
3
4from enum import IntEnum
5
6
7class FileType(IntEnum):
8    # No file type
9    null = 0
10    # Relocatable file
11    object = 1
12    # Executable file
13    executable = 2
14    # Shared object file
15    dynamic_shared_object = 3
16    # Core dump file
17    core_dump = 4
18
19
20class MachineType(IntEnum):
21    # Not specified
22    unspecified = 0
23    # SPARC
24    sparc = 2
25    # IA32 (x86)
26    x86 = 3
27    # MIPS
28    mips = 8
29    # 32-bit subset of SPARC V9
30    sparc32plus = 18
31    # IBM POWER and PowerPC
32    ppc = 20
33    # IBM PowerPC 64
34    ppc64 = 21
35    # ARM
36    arm = 40
37    # SPARC V9 (64-bit)
38    sparc64 = 43
39    # IA64 (Itanium)
40    ia64 = 50
41    # x86-64 (AMD64, Intel64, x64)
42    x86_64 = 62
43    # Intel Knights Ferry
44    l1om = 180
45    # Intel Knights Corner
46    k1om = 181
47    # ARMv8 AArch64
48    arm64 = 183
49    # ATI/AMD GPU code (for any GPU arch)
50    cal = 125
51    # nVidia CUDA GPU code (for any GPU arch)
52    cuda = 190
53    # HSAIL code (32-bit ELF)
54    hsail32 = 0xAF5A
55    # HSAIL code (64-bit ELF)
56    hsail64 = 0xAF5B
57
58
59class FormatVersion(IntEnum):
60    # Invalid version
61    invalid = 0
62    # Current version
63    current = 1
64
65
66class ElfClass(IntEnum):
67    # Invalid class
68    invalid = 0
69    # 32-bit ELF
70    class32 = 1
71    # 64-bit ELF
72    class64 = 2
73
74
75class DataEncoding(IntEnum):
76    # Invalid data encoding
77    invalid = 0
78    # Least significant byte first (Little-Endian)
79    little_endian = 1
80    # Most significant byte first (Big-Endian)
81    big_endian = 2
82
83
84class OSABI(IntEnum):
85    # No extensions or unspecified
86    none = 0
87    # GNU Linux
88    gnu = 3
89    # ATI/AMD GPU ABI
90    cal = 100
91
92
93class FileIdentification:
94    def __init__(self, abi):
95        self.abi = abi
96        self.file_version = FormatVersion.current
97
98    @property
99    def as_bytearray(self):
100        identification = bytearray(16)
101        identification[0] = 0x7F
102        identification[1] = ord('E')
103        identification[2] = ord('L')
104        identification[3] = ord('F')
105        identification[4] = self.abi.elf_class
106        identification[5] = self.abi.elf_data_encoding
107        identification[6] = self.file_version
108        return identification
109
110
111class FileHeader:
112    def __init__(self, abi):
113        import peachpy.formats.elf.section
114        import peachpy.abi
115        if not isinstance(abi, peachpy.abi.ABI):
116            raise TypeError("ABI %s must be represented by an ABI object" % str(abi))
117        if not abi.is_elf_compatible:
118            raise ValueError("ABI %s is not compatible with ELF" % str(abi))
119        self.abi = abi
120
121        self.identification = FileIdentification(self.abi)
122        if self.abi.elf_class == ElfClass.class32:
123            # Size of ELF32 file header, in bytes
124            self.file_header_size = 52
125            # Size of program header, in bytes. All program headers have the same size.
126            self.program_header_entry_size = 32
127            # Size of a section header, in bytes. All sections have the same size.
128            self.section_header_entry_size = 40
129        else:
130            # Size of ELF64 file header, in bytes
131            self.file_header_size = 64
132            # Size of program header, in bytes. All program headers have the same size.
133            self.program_header_entry_size = 56
134            # Size of a section header, in bytes. All sections have the same size.
135            self.section_header_entry_size = 64
136
137        self.size = self.file_header_size
138        self.file_type = FileType.object
139        self.file_version = FormatVersion.current
140        self.entry_address = None
141        self.program_header_table_offset = None
142        self.section_header_table_offset = None
143        self.flags = 0
144        # Number of program headers in the program header table.
145        self.program_header_entries_count = 0
146        # Number of section headers in the section header table.
147        self.section_header_entries_count = 0
148        # Index of the section header for a section which contains section name string table.
149        # Usually this section is called ".shstrtab"
150        self.section_name_string_table_index = peachpy.formats.elf.section.SectionIndex.undefined
151
152    @property
153    def as_bytearray(self):
154        import peachpy.encoder
155        encoder = peachpy.encoder.Encoder(self.abi.endianness, self.abi.elf_bitness)
156
157        return self.identification.as_bytearray + \
158            encoder.uint16(self.file_type) + \
159            encoder.uint16(self.abi.elf_machine_type) + \
160            encoder.uint32(self.file_version) + \
161            encoder.unsigned_offset(self.entry_address or 0) + \
162            encoder.unsigned_offset(self.program_header_table_offset or 0) + \
163            encoder.unsigned_offset(self.section_header_table_offset or 0) + \
164            encoder.uint32(self.flags) + \
165            encoder.uint16(self.file_header_size) + \
166            encoder.uint16(self.program_header_entry_size) + \
167            encoder.uint16(self.program_header_entries_count) + \
168            encoder.uint16(self.section_header_entry_size) + \
169            encoder.uint16(self.section_header_entries_count) + \
170            encoder.uint16(self.section_name_string_table_index)
171