1 #-------------------------------------------------------------------------------
2 # elftools: elf/structs.py
4 # Encapsulation of Construct structs for parsing an ELF file, adjusted for
5 # correct endianness and word-size.
7 # Eli Bendersky (eliben@gmail.com)
8 # This code is in the public domain
9 #-------------------------------------------------------------------------------
10 from ..construct import (
11 UBInt8, UBInt16, UBInt32, UBInt64,
12 ULInt8, ULInt16, ULInt32, ULInt64,
13 SBInt32, SLInt32, SBInt64, SLInt64,
14 Struct, Array, Enum, Padding, BitStruct, BitField, Value,
20 class ELFStructs(object):
21 """ Accessible attributes:
23 Elf_{byte|half|word|word64|addr|offset|sword|xword|xsword}:
24 Data chunks, as specified by the ELF standard, adjusted for
25 correct endianness and word-size.
40 Entries in relocation sections
42 def __init__(self, little_endian=True, elfclass=32):
43 assert elfclass == 32 or elfclass == 64
44 self.little_endian = little_endian
45 self.elfclass = elfclass
46 self._create_structs()
48 def _create_structs(self):
49 if self.little_endian:
50 self.Elf_byte = ULInt8
51 self.Elf_half = ULInt16
52 self.Elf_word = ULInt32
53 self.Elf_word64 = ULInt64
54 self.Elf_addr = ULInt32 if self.elfclass == 32 else ULInt64
55 self.Elf_offset = self.Elf_addr
56 self.Elf_sword = SLInt32
57 self.Elf_xword = ULInt32 if self.elfclass == 32 else ULInt64
58 self.Elf_sxword = SLInt32 if self.elfclass == 32 else SLInt64
60 self.Elf_byte = UBInt8
61 self.Elf_half = UBInt16
62 self.Elf_word = UBInt32
63 self.Elf_word64 = UBInt64
64 self.Elf_addr = UBInt32 if self.elfclass == 32 else UBInt64
65 self.Elf_offset = self.Elf_addr
66 self.Elf_sword = SBInt32
67 self.Elf_xword = UBInt32 if self.elfclass == 32 else UBInt64
68 self.Elf_sxword = SBInt32 if self.elfclass == 32 else SBInt64
77 def _create_ehdr(self):
78 self.Elf_Ehdr = Struct('Elf_Ehdr',
80 Array(4, self.Elf_byte('EI_MAG')),
81 Enum(self.Elf_byte('EI_CLASS'), **ENUM_EI_CLASS),
82 Enum(self.Elf_byte('EI_DATA'), **ENUM_EI_DATA),
83 Enum(self.Elf_byte('EI_VERSION'), **ENUM_E_VERSION),
84 Enum(self.Elf_byte('EI_OSABI'), **ENUM_EI_OSABI),
85 self.Elf_byte('EI_ABIVERSION'),
88 Enum(self.Elf_half('e_type'), **ENUM_E_TYPE),
89 Enum(self.Elf_half('e_machine'), **ENUM_E_MACHINE),
90 Enum(self.Elf_word('e_version'), **ENUM_E_VERSION),
91 self.Elf_addr('e_entry'),
92 self.Elf_offset('e_phoff'),
93 self.Elf_offset('e_shoff'),
94 self.Elf_word('e_flags'),
95 self.Elf_half('e_ehsize'),
96 self.Elf_half('e_phentsize'),
97 self.Elf_half('e_phnum'),
98 self.Elf_half('e_shentsize'),
99 self.Elf_half('e_shnum'),
100 self.Elf_half('e_shstrndx'),
103 def _create_phdr(self):
104 if self.elfclass == 32:
105 self.Elf_Phdr = Struct('Elf_Phdr',
106 Enum(self.Elf_word('p_type'), **ENUM_P_TYPE),
107 self.Elf_offset('p_offset'),
108 self.Elf_addr('p_vaddr'),
109 self.Elf_addr('p_paddr'),
110 self.Elf_word('p_filesz'),
111 self.Elf_word('p_memsz'),
112 self.Elf_word('p_flags'),
113 self.Elf_word('p_align'),
116 self.Elf_Phdr = Struct('Elf_Phdr',
117 Enum(self.Elf_word('p_type'), **ENUM_P_TYPE),
118 self.Elf_word('p_flags'),
119 self.Elf_offset('p_offset'),
120 self.Elf_addr('p_vaddr'),
121 self.Elf_addr('p_paddr'),
122 self.Elf_xword('p_filesz'),
123 self.Elf_xword('p_memsz'),
124 self.Elf_xword('p_align'),
127 def _create_shdr(self):
128 self.Elf_Shdr = Struct('Elf_Shdr',
129 self.Elf_word('sh_name'),
130 Enum(self.Elf_word('sh_type'), **ENUM_SH_TYPE),
131 self.Elf_xword('sh_flags'),
132 self.Elf_addr('sh_addr'),
133 self.Elf_offset('sh_offset'),
134 self.Elf_xword('sh_size'),
135 self.Elf_word('sh_link'),
136 self.Elf_word('sh_info'),
137 self.Elf_xword('sh_addralign'),
138 self.Elf_xword('sh_entsize'),
141 def _create_rel(self):
142 # r_info is also taken apart into r_info_sym and r_info_type.
143 # This is done in Value to avoid endianity issues while parsing.
144 if self.elfclass == 32:
145 r_info_sym = Value('r_info_sym',
146 lambda ctx: (ctx['r_info'] >> 8) & 0xFFFFFF)
147 r_info_type = Value('r_info_type',
148 lambda ctx: ctx['r_info'] & 0xFF)
150 r_info_sym = Value('r_info_sym',
151 lambda ctx: (ctx['r_info'] >> 32) & 0xFFFFFFFF)
152 r_info_type = Value('r_info_type',
153 lambda ctx: ctx['r_info'] & 0xFFFFFFFF)
155 self.Elf_Rel = Struct('Elf_Rel',
156 self.Elf_addr('r_offset'),
157 self.Elf_xword('r_info'),
161 self.Elf_Rela = Struct('Elf_Rela',
162 self.Elf_addr('r_offset'),
163 self.Elf_xword('r_info'),
166 self.Elf_sxword('r_addend'),
169 def _create_dyn(self):
170 self.Elf_Dyn = Struct('Elf_Dyn',
171 Enum(self.Elf_sxword('d_tag'), **ENUM_D_TAG),
172 self.Elf_xword('d_val'),
173 Value('d_ptr', lambda ctx: ctx['d_val']),
176 def _create_sym(self):
177 # st_info is hierarchical. To access the type, use
178 # container['st_info']['type']
179 st_info_struct = BitStruct('st_info',
180 Enum(BitField('bind', 4), **ENUM_ST_INFO_BIND),
181 Enum(BitField('type', 4), **ENUM_ST_INFO_TYPE))
182 # st_other is hierarchical. To access the visibility,
183 # use container['st_other']['visibility']
184 st_other_struct = BitStruct('st_other',
186 Enum(BitField('visibility', 3), **ENUM_ST_VISIBILITY))
187 if self.elfclass == 32:
188 self.Elf_Sym = Struct('Elf_Sym',
189 self.Elf_word('st_name'),
190 self.Elf_addr('st_value'),
191 self.Elf_word('st_size'),
194 Enum(self.Elf_half('st_shndx'), **ENUM_ST_SHNDX),
197 self.Elf_Sym = Struct('Elf_Sym',
198 self.Elf_word('st_name'),
201 Enum(self.Elf_half('st_shndx'), **ENUM_ST_SHNDX),
202 self.Elf_addr('st_value'),
203 self.Elf_xword('st_size'),