244841a2e4cbf1abc24bbc4b219fdd93c5d9c7b3
1 #-------------------------------------------------------------------------------
2 # elftools: elf/elffile.py
4 # ELFFile - main class for accessing ELF files
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
15 PAGESIZE
= resource
.getpagesize()
20 PAGESIZE
= mmap
.PAGESIZE
25 from ..common
.py3compat
import BytesIO
26 from ..common
.exceptions
import ELFError
27 from ..common
.utils
import struct_parse
, elf_assert
28 from .structs
import ELFStructs
29 from .sections
import (
30 Section
, StringTableSection
, SymbolTableSection
,
31 SymbolTableIndexSection
, SUNWSyminfoTableSection
, NullSection
,
32 NoteSection
, StabSection
, ARMAttributesSection
)
33 from .dynamic
import DynamicSection
, DynamicSegment
34 from .relocation
import (RelocationSection
, RelocationHandler
,
35 RelrRelocationSection
)
36 from .gnuversions
import (
37 GNUVerNeedSection
, GNUVerDefSection
,
39 from .segments
import Segment
, InterpSegment
, NoteSegment
40 from ..dwarf
.dwarfinfo
import DWARFInfo
, DebugSectionDescriptor
, DwarfConfig
41 from ..ehabi
.ehabiinfo
import EHABIInfo
42 from .hash import ELFHashSection
, GNUHashSection
43 from .constants
import SHN_INDICES
45 class ELFFile(object):
46 """ Creation: the constructor accepts a stream (file-like object) with the
47 contents of an ELF file.
49 Accessible attributes:
52 The stream holding the data of the file - must be a binary
53 stream (bytes, not string).
56 32 or 64 - specifies the word size of the target machine
59 boolean - specifies the target machine's endianness
62 string or int, either known value of E_TYPE enum defining ELF
63 type (e.g. executable, dynamic library or core dump) or integral
67 the complete ELF file header
70 the raw e_ident field of the header
72 def __init__(self
, stream
):
75 self
.structs
= ELFStructs(
76 little_endian
=self
.little_endian
,
77 elfclass
=self
.elfclass
)
79 self
.structs
.create_basic_structs()
80 self
.header
= self
._parse
_elf
_header
()
81 self
.structs
.create_advanced_structs(
84 self
['e_ident']['EI_OSABI'])
86 self
.e_ident_raw
= self
.stream
.read(16)
88 self
._section
_header
_stringtable
= \
89 self
._get
_section
_header
_stringtable
()
90 self
._section
_name
_map
= None
92 def num_sections(self
):
93 """ Number of sections in the file
95 if self
['e_shoff'] == 0:
97 # From the ELF ABI documentation at
98 # https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.sheader.html:
99 # "e_shnum normally tells how many entries the section header table
100 # contains. [...] If the number of sections is greater than or equal to
101 # SHN_LORESERVE (0xff00), e_shnum has the value SHN_UNDEF (0) and the
102 # actual number of section header table entries is contained in the
103 # sh_size field of the section header at index 0 (otherwise, the sh_size
104 # member of the initial entry contains 0)."
105 if self
['e_shnum'] == 0:
106 return self
._get
_section
_header
(0)['sh_size']
107 return self
['e_shnum']
109 def get_section(self
, n
):
110 """ Get the section at index #n from the file (Section object or a
113 section_header
= self
._get
_section
_header
(n
)
114 return self
._make
_section
(section_header
)
116 def get_section_by_name(self
, name
):
117 """ Get a section from the file, by name. Return None if no such
120 # The first time this method is called, construct a name to number
123 if self
._section
_name
_map
is None:
124 self
._make
_section
_name
_map
()
125 secnum
= self
._section
_name
_map
.get(name
, None)
126 return None if secnum
is None else self
.get_section(secnum
)
128 def get_section_index(self
, section_name
):
129 """ Gets the index of the section by name. Return None if no such
132 # The first time this method is called, construct a name to number
135 if self
._section
_name
_map
is None:
136 self
._make
_section
_name
_map
()
137 return self
._section
_name
_map
.get(section_name
, None)
139 def iter_sections(self
, type=None):
140 """ Yield all the sections in the file. If the optional |type|
141 parameter is passed, this method will only yield sections of the
142 given type. The parameter value must be a string containing the
143 name of the type as defined in the ELF specification, e.g.
146 for i
in range(self
.num_sections()):
147 section
= self
.get_section(i
)
148 if type is None or section
['sh_type'] == type:
151 def num_segments(self
):
152 """ Number of segments in the file
154 # From: https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
155 # Section: 4.1.2 Number of Program Headers
156 # If the number of program headers is greater than or equal to
157 # PN_XNUM (0xffff), this member has the value PN_XNUM
158 # (0xffff). The actual number of program header table entries
159 # is contained in the sh_info field of the section header at
161 if self
['e_phnum'] < 0xffff:
162 return self
['e_phnum']
164 return self
.get_section(0)['sh_info']
166 def get_segment(self
, n
):
167 """ Get the segment at index #n from the file (Segment object)
169 segment_header
= self
._get
_segment
_header
(n
)
170 return self
._make
_segment
(segment_header
)
172 def iter_segments(self
, type=None):
173 """ Yield all the segments in the file. If the optional |type|
174 parameter is passed, this method will only yield segments of the
175 given type. The parameter value must be a string containing the
176 name of the type as defined in the ELF specification, e.g.
179 for i
in range(self
.num_segments()):
180 segment
= self
.get_segment(i
)
181 if type is None or segment
['p_type'] == type:
184 def address_offsets(self
, start
, size
=1):
185 """ Yield a file offset for each ELF segment containing a memory region.
187 A memory region is defined by the range [start...start+size). The
188 offset of the region is yielded.
191 # consider LOAD only to prevent same address being yielded twice
192 for seg
in self
.iter_segments(type='PT_LOAD'):
193 if (start
>= seg
['p_vaddr'] and
194 end
<= seg
['p_vaddr'] + seg
['p_filesz']):
195 yield start
- seg
['p_vaddr'] + seg
['p_offset']
197 def has_dwarf_info(self
):
198 """ Check whether this file appears to have debugging information.
199 We assume that if it has the .debug_info or .zdebug_info section, it
200 has all the other required sections as well.
202 return bool(self
.get_section_by_name('.debug_info') or
203 self
.get_section_by_name('.zdebug_info') or
204 self
.get_section_by_name('.eh_frame'))
206 def get_dwarf_info(self
, relocate_dwarf_sections
=True):
207 """ Return a DWARFInfo object representing the debugging information in
210 If relocate_dwarf_sections is True, relocations for DWARF sections
211 are looked up and applied.
213 # Expect that has_dwarf_info was called, so at least .debug_info is
215 # Sections that aren't found will be passed as None to DWARFInfo.
217 section_names
= ('.debug_info', '.debug_aranges', '.debug_abbrev',
218 '.debug_str', '.debug_line', '.debug_frame',
219 '.debug_loc', '.debug_ranges', '.debug_pubtypes',
220 '.debug_pubnames', '.debug_addr', '.debug_str_offsets')
222 compressed
= bool(self
.get_section_by_name('.zdebug_info'))
224 section_names
= tuple(map(lambda x
: '.z' + x
[1:], section_names
))
226 # As it is loaded in the process image, .eh_frame cannot be compressed
227 section_names
+= ('.eh_frame', )
229 (debug_info_sec_name
, debug_aranges_sec_name
, debug_abbrev_sec_name
,
230 debug_str_sec_name
, debug_line_sec_name
, debug_frame_sec_name
,
231 debug_loc_sec_name
, debug_ranges_sec_name
, debug_pubtypes_name
,
232 debug_pubnames_name
, debug_addr_name
, debug_str_offsets_name
,
233 eh_frame_sec_name
) = section_names
236 for secname
in section_names
:
237 section
= self
.get_section_by_name(secname
)
239 debug_sections
[secname
] = None
241 dwarf_section
= self
._read
_dwarf
_section
(
243 relocate_dwarf_sections
)
244 if compressed
and secname
.startswith('.z'):
245 dwarf_section
= self
._decompress
_dwarf
_section
(dwarf_section
)
246 debug_sections
[secname
] = dwarf_section
250 little_endian
=self
.little_endian
,
251 default_address_size
=self
.elfclass
// 8,
252 machine_arch
=self
.get_machine_arch()),
253 debug_info_sec
=debug_sections
[debug_info_sec_name
],
254 debug_aranges_sec
=debug_sections
[debug_aranges_sec_name
],
255 debug_abbrev_sec
=debug_sections
[debug_abbrev_sec_name
],
256 debug_frame_sec
=debug_sections
[debug_frame_sec_name
],
257 eh_frame_sec
=debug_sections
[eh_frame_sec_name
],
258 debug_str_sec
=debug_sections
[debug_str_sec_name
],
259 debug_loc_sec
=debug_sections
[debug_loc_sec_name
],
260 debug_ranges_sec
=debug_sections
[debug_ranges_sec_name
],
261 debug_line_sec
=debug_sections
[debug_line_sec_name
],
262 debug_pubtypes_sec
=debug_sections
[debug_pubtypes_name
],
263 debug_pubnames_sec
=debug_sections
[debug_pubnames_name
],
264 debug_addr_sec
=debug_sections
[debug_addr_name
],
265 debug_str_offsets_sec
=debug_sections
[debug_str_offsets_name
],
268 def has_ehabi_info(self
):
269 """ Check whether this file appears to have arm exception handler index table.
271 return any(self
.iter_sections(type='SHT_ARM_EXIDX'))
273 def get_ehabi_infos(self
):
274 """ Generally, shared library and executable contain 1 .ARM.exidx section.
275 Object file contains many .ARM.exidx sections.
276 So we must traverse every section and filter sections whose type is SHT_ARM_EXIDX.
279 if self
['e_type'] == 'ET_REL':
280 # TODO: support relocatable file
281 assert False, "Current version of pyelftools doesn't support relocatable file."
282 for section
in self
.iter_sections(type='SHT_ARM_EXIDX'):
283 _ret
.append(EHABIInfo(section
, self
.little_endian
))
284 return _ret
if len(_ret
) > 0 else None
286 def get_machine_arch(self
):
287 """ Return the machine architecture, as detected from the ELF header.
290 'EM_M32' : 'AT&T WE 32100',
291 'EM_SPARC' : 'SPARC',
293 'EM_68K' : 'Motorola 68000',
294 'EM_88K' : 'Motorola 88000',
295 'EM_IAMCU' : 'Intel MCU',
296 'EM_860' : 'Intel 80860',
298 'EM_S370' : 'IBM System/370',
299 'EM_MIPS_RS3_LE' : 'MIPS RS3000 Little-endian',
300 'EM_PARISC' : 'Hewlett-Packard PA-RISC',
301 'EM_VPP500' : 'Fujitsu VPP500',
302 'EM_SPARC32PLUS' : 'Enhanced SPARC',
303 'EM_960' : 'Intel 80960',
304 'EM_PPC' : 'PowerPC',
305 'EM_PPC64' : '64-bit PowerPC',
306 'EM_S390' : 'IBM System/390',
307 'EM_SPU' : 'IBM SPU/SPC',
308 'EM_V800' : 'NEC V800',
309 'EM_FR20' : 'Fujitsu FR20',
310 'EM_RH32' : 'TRW RH-32',
311 'EM_RCE' : 'Motorola RCE',
313 'EM_ALPHA' : 'Digital Alpha',
314 'EM_SH' : 'Hitachi SH',
315 'EM_SPARCV9' : 'SPARC Version 9',
316 'EM_TRICORE' : 'Siemens TriCore embedded processor',
317 'EM_ARC' : 'Argonaut RISC Core, Argonaut Technologies Inc.',
318 'EM_H8_300' : 'Hitachi H8/300',
319 'EM_H8_300H' : 'Hitachi H8/300H',
320 'EM_H8S' : 'Hitachi H8S',
321 'EM_H8_500' : 'Hitachi H8/500',
322 'EM_IA_64' : 'Intel IA-64',
323 'EM_MIPS_X' : 'MIPS-X',
324 'EM_COLDFIRE' : 'Motorola ColdFire',
325 'EM_68HC12' : 'Motorola M68HC12',
326 'EM_MMA' : 'Fujitsu MMA',
327 'EM_PCP' : 'Siemens PCP',
328 'EM_NCPU' : 'Sony nCPU',
329 'EM_NDR1' : 'Denso NDR1',
330 'EM_STARCORE' : 'Motorola Star*Core',
331 'EM_ME16' : 'Toyota ME16',
332 'EM_ST100' : 'STMicroelectronics ST100',
333 'EM_TINYJ' : 'Advanced Logic TinyJ',
335 'EM_PDSP' : 'Sony DSP',
336 'EM_PDP10' : 'Digital Equipment PDP-10',
337 'EM_PDP11' : 'Digital Equipment PDP-11',
338 'EM_FX66' : 'Siemens FX66',
339 'EM_ST9PLUS' : 'STMicroelectronics ST9+ 8/16 bit',
340 'EM_ST7' : 'STMicroelectronics ST7 8-bit',
341 'EM_68HC16' : 'Motorola MC68HC16',
342 'EM_68HC11' : 'Motorola MC68HC11',
343 'EM_68HC08' : 'Motorola MC68HC08',
344 'EM_68HC05' : 'Motorola MC68HC05',
345 'EM_SVX' : 'Silicon Graphics SVx',
346 'EM_ST19' : 'STMicroelectronics ST19 8-bit',
347 'EM_VAX' : 'Digital VAX',
348 'EM_CRIS' : 'Axis Communications 32-bit',
349 'EM_JAVELIN' : 'Infineon Technologies 32-bit',
350 'EM_FIREPATH' : 'Element 14 64-bit DSP',
351 'EM_ZSP' : 'LSI Logic 16-bit DSP',
352 'EM_MMIX' : 'Donald Knuth\'s educational 64-bit',
353 'EM_HUANY' : 'Harvard University machine-independent object files',
354 'EM_PRISM' : 'SiTera Prism',
355 'EM_AVR' : 'Atmel AVR 8-bit',
356 'EM_FR30' : 'Fujitsu FR30',
357 'EM_D10V' : 'Mitsubishi D10V',
358 'EM_D30V' : 'Mitsubishi D30V',
359 'EM_V850' : 'NEC v850',
360 'EM_M32R' : 'Mitsubishi M32R',
361 'EM_MN10300' : 'Matsushita MN10300',
362 'EM_MN10200' : 'Matsushita MN10200',
363 'EM_PJ' : 'picoJava',
364 'EM_OPENRISC' : 'OpenRISC 32-bit',
365 'EM_ARC_COMPACT' : 'ARC International ARCompact',
366 'EM_XTENSA' : 'Tensilica Xtensa',
367 'EM_VIDEOCORE' : 'Alphamosaic VideoCore',
368 'EM_TMM_GPP' : 'Thompson Multimedia',
369 'EM_NS32K' : 'National Semiconductor 32000 series',
370 'EM_TPC' : 'Tenor Network TPC',
371 'EM_SNP1K' : 'Trebia SNP 1000',
372 'EM_ST200' : 'STMicroelectronics ST200',
373 'EM_IP2K' : 'Ubicom IP2xxx',
375 'EM_CR' : 'National Semiconductor CompactRISC',
376 'EM_F2MC16' : 'Fujitsu F2MC16',
377 'EM_MSP430' : 'Texas Instruments msp430',
378 'EM_BLACKFIN' : 'Analog Devices Blackfin',
379 'EM_SE_C33' : 'Seiko Epson S1C33',
381 'EM_ARCA' : 'Arca RISC',
382 'EM_UNICORE' : 'PKU-Unity MPRC',
383 'EM_EXCESS' : 'eXcess',
384 'EM_DXP' : 'Icera Semiconductor Deep Execution Processor',
385 'EM_ALTERA_NIOS2' : 'Altera Nios II',
386 'EM_CRX' : 'National Semiconductor CompactRISC CRX',
387 'EM_XGATE' : 'Motorola XGATE',
388 'EM_C166' : 'Infineon C16x/XC16x',
389 'EM_M16C' : 'Renesas M16C',
390 'EM_DSPIC30F' : 'Microchip Technology dsPIC30F',
391 'EM_CE' : 'Freescale Communication Engine RISC core',
392 'EM_M32C' : 'Renesas M32C',
393 'EM_TSK3000' : 'Altium TSK3000',
394 'EM_RS08' : 'Freescale RS08',
395 'EM_SHARC' : 'Analog Devices SHARC',
396 'EM_ECOG2' : 'Cyan Technology eCOG2',
397 'EM_SCORE7' : 'Sunplus S+core7 RISC',
398 'EM_DSP24' : 'New Japan Radio (NJR) 24-bit DSP',
399 'EM_VIDEOCORE3' : 'Broadcom VideoCore III',
400 'EM_LATTICEMICO32' : 'Lattice FPGA RISC',
401 'EM_SE_C17' : 'Seiko Epson C17',
402 'EM_TI_C6000' : 'TI TMS320C6000',
403 'EM_TI_C2000' : 'TI TMS320C2000',
404 'EM_TI_C5500' : 'TI TMS320C55x',
405 'EM_TI_ARP32' : 'TI Application Specific RISC, 32bit',
406 'EM_TI_PRU' : 'TI Programmable Realtime Unit',
407 'EM_MMDSP_PLUS' : 'STMicroelectronics 64bit VLIW',
408 'EM_CYPRESS_M8C' : 'Cypress M8C',
409 'EM_R32C' : 'Renesas R32C',
410 'EM_TRIMEDIA' : 'NXP Semiconductors TriMedia',
411 'EM_QDSP6' : 'QUALCOMM DSP6',
412 'EM_8051' : 'Intel 8051',
413 'EM_STXP7X' : 'STMicroelectronics STxP7x',
414 'EM_NDS32' : 'Andes Technology RISC',
415 'EM_ECOG1' : 'Cyan Technology eCOG1X',
416 'EM_ECOG1X' : 'Cyan Technology eCOG1X',
417 'EM_MAXQ30' : 'Dallas Semiconductor MAXQ30',
418 'EM_XIMO16' : 'New Japan Radio (NJR) 16-bit',
419 'EM_MANIK' : 'M2000 Reconfigurable RISC',
420 'EM_CRAYNV2' : 'Cray Inc. NV2',
421 'EM_RX' : 'Renesas RX',
422 'EM_METAG' : 'Imagination Technologies META',
423 'EM_MCST_ELBRUS' : 'MCST Elbrus',
424 'EM_ECOG16' : 'Cyan Technology eCOG16',
425 'EM_CR16' : 'National Semiconductor CompactRISC CR16 16-bit',
426 'EM_ETPU' : 'Freescale',
427 'EM_SLE9X' : 'Infineon Technologies SLE9X',
428 'EM_L10M' : 'Intel L10M',
429 'EM_K10M' : 'Intel K10M',
430 'EM_AARCH64' : 'AArch64',
431 'EM_AVR32' : 'Atmel 32-bit',
432 'EM_STM8' : 'STMicroeletronics STM8 8-bit',
433 'EM_TILE64' : 'Tilera TILE64',
434 'EM_TILEPRO' : 'Tilera TILEPro',
435 'EM_MICROBLAZE' : 'Xilinx MicroBlaze 32-bit RISC',
436 'EM_CUDA' : 'NVIDIA CUDA',
437 'EM_TILEGX' : 'Tilera TILE-Gx',
438 'EM_CLOUDSHIELD' : 'CloudShield',
439 'EM_COREA_1ST' : 'KIPO-KAIST Core-A 1st generation',
440 'EM_COREA_2ND' : 'KIPO-KAIST Core-A 2nd generation',
441 'EM_ARC_COMPACT2' : 'Synopsys ARCompact V2',
442 'EM_OPEN8' : 'Open8 8-bit RISC',
443 'EM_RL78' : 'Renesas RL78',
444 'EM_VIDEOCORE5' : 'Broadcom VideoCore V',
445 'EM_78KOR' : 'Renesas 78KOR',
446 'EM_56800EX' : 'Freescale 56800EX',
447 'EM_BA1' : 'Beyond BA1',
448 'EM_BA2' : 'Beyond BA2',
449 'EM_XCORE' : 'XMOS xCORE',
450 'EM_MCHP_PIC' : 'Microchip 8-bit PIC',
451 'EM_INTEL205' : 'Reserved by Intel',
452 'EM_INTEL206' : 'Reserved by Intel',
453 'EM_INTEL207' : 'Reserved by Intel',
454 'EM_INTEL208' : 'Reserved by Intel',
455 'EM_INTEL209' : 'Reserved by Intel',
456 'EM_KM32' : 'KM211 KM32 32-bit',
457 'EM_KMX32' : 'KM211 KMX32 32-bit',
458 'EM_KMX16' : 'KM211 KMX16 16-bit',
459 'EM_KMX8' : 'KM211 KMX8 8-bit',
460 'EM_KVARC' : 'KM211 KVARC',
461 'EM_CDP' : 'Paneve CDP',
462 'EM_COGE' : 'Cognitive',
463 'EM_COOL' : 'Bluechip Systems CoolEngine',
464 'EM_NORC' : 'Nanoradio Optimized RISC',
465 'EM_CSR_KALIMBA' : 'CSR Kalimba',
466 'EM_Z80' : 'Zilog Z80',
467 'EM_VISIUM' : 'VISIUMcore',
468 'EM_FT32' : 'FTDI Chip FT32 32-bit RISC',
469 'EM_MOXIE' : 'Moxie',
470 'EM_AMDGPU' : 'AMD GPU',
471 'EM_RISCV' : 'RISC-V',
472 'EM_BPF' : 'Linux BPF - in-kernel virtual machine',
474 'EM_FRV' : 'Fujitsu FR-V'
477 return architectures
.get(self
['e_machine'], '<unknown>')
479 def get_shstrndx(self
):
480 """ Find the string table section index for the section header table
482 # From https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html:
483 # If the section name string table section index is greater than or
484 # equal to SHN_LORESERVE (0xff00), this member has the value SHN_XINDEX
485 # (0xffff) and the actual index of the section name string table section
486 # is contained in the sh_link field of the section header at index 0.
487 if self
['e_shstrndx'] != SHN_INDICES
.SHN_XINDEX
:
488 return self
['e_shstrndx']
490 return self
._get
_section
_header
(0)['sh_link']
492 #-------------------------------- PRIVATE --------------------------------#
494 def __getitem__(self
, name
):
495 """ Implement dict-like access to header entries
497 return self
.header
[name
]
499 def _identify_file(self
):
500 """ Verify the ELF file and identify its class and endianness.
502 # Note: this code reads the stream directly, without using ELFStructs,
503 # since we don't yet know its exact format. ELF was designed to be
504 # read like this - its e_ident field is word-size and endian agnostic.
506 magic
= self
.stream
.read(4)
507 elf_assert(magic
== b
'\x7fELF', 'Magic number does not match')
509 ei_class
= self
.stream
.read(1)
510 if ei_class
== b
'\x01':
512 elif ei_class
== b
'\x02':
515 raise ELFError('Invalid EI_CLASS %s' % repr(ei_class
))
517 ei_data
= self
.stream
.read(1)
518 if ei_data
== b
'\x01':
519 self
.little_endian
= True
520 elif ei_data
== b
'\x02':
521 self
.little_endian
= False
523 raise ELFError('Invalid EI_DATA %s' % repr(ei_data
))
525 def _section_offset(self
, n
):
526 """ Compute the offset of section #n in the file
528 return self
['e_shoff'] + n
* self
['e_shentsize']
530 def _segment_offset(self
, n
):
531 """ Compute the offset of segment #n in the file
533 return self
['e_phoff'] + n
* self
['e_phentsize']
535 def _make_segment(self
, segment_header
):
536 """ Create a Segment object of the appropriate type
538 segtype
= segment_header
['p_type']
539 if segtype
== 'PT_INTERP':
540 return InterpSegment(segment_header
, self
.stream
)
541 elif segtype
== 'PT_DYNAMIC':
542 return DynamicSegment(segment_header
, self
.stream
, self
)
543 elif segtype
== 'PT_NOTE':
544 return NoteSegment(segment_header
, self
.stream
, self
)
546 return Segment(segment_header
, self
.stream
)
548 def _get_section_header(self
, n
):
549 """ Find the header of section #n, parse it and return the struct
552 self
.structs
.Elf_Shdr
,
554 stream_pos
=self
._section
_offset
(n
))
556 def _get_section_name(self
, section_header
):
557 """ Given a section header, find this section's name in the file's
560 name_offset
= section_header
['sh_name']
561 return self
._section
_header
_stringtable
.get_string(name_offset
)
563 def _make_section(self
, section_header
):
564 """ Create a section object of the appropriate type
566 name
= self
._get
_section
_name
(section_header
)
567 sectype
= section_header
['sh_type']
569 if sectype
== 'SHT_STRTAB':
570 return StringTableSection(section_header
, name
, self
)
571 elif sectype
== 'SHT_NULL':
572 return NullSection(section_header
, name
, self
)
573 elif sectype
in ('SHT_SYMTAB', 'SHT_DYNSYM', 'SHT_SUNW_LDYNSYM'):
574 return self
._make
_symbol
_table
_section
(section_header
, name
)
575 elif sectype
== 'SHT_SYMTAB_SHNDX':
576 return self
._make
_symbol
_table
_index
_section
(section_header
, name
)
577 elif sectype
== 'SHT_SUNW_syminfo':
578 return self
._make
_sunwsyminfo
_table
_section
(section_header
, name
)
579 elif sectype
== 'SHT_GNU_verneed':
580 return self
._make
_gnu
_verneed
_section
(section_header
, name
)
581 elif sectype
== 'SHT_GNU_verdef':
582 return self
._make
_gnu
_verdef
_section
(section_header
, name
)
583 elif sectype
== 'SHT_GNU_versym':
584 return self
._make
_gnu
_versym
_section
(section_header
, name
)
585 elif sectype
in ('SHT_REL', 'SHT_RELA'):
586 return RelocationSection(section_header
, name
, self
)
587 elif sectype
== 'SHT_DYNAMIC':
588 return DynamicSection(section_header
, name
, self
)
589 elif sectype
== 'SHT_NOTE':
590 return NoteSection(section_header
, name
, self
)
591 elif sectype
== 'SHT_PROGBITS' and name
== '.stab':
592 return StabSection(section_header
, name
, self
)
593 elif sectype
== 'SHT_ARM_ATTRIBUTES':
594 return ARMAttributesSection(section_header
, name
, self
)
595 elif sectype
== 'SHT_HASH':
596 return self
._make
_elf
_hash
_section
(section_header
, name
)
597 elif sectype
== 'SHT_GNU_HASH':
598 return self
._make
_gnu
_hash
_section
(section_header
, name
)
599 elif sectype
== 'SHT_RELR':
600 return RelrRelocationSection(section_header
, name
, self
)
602 return Section(section_header
, name
, self
)
604 def _make_section_name_map(self
):
605 self
._section
_name
_map
= {}
606 for i
, sec
in enumerate(self
.iter_sections()):
607 self
._section
_name
_map
[sec
.name
] = i
609 def _make_symbol_table_section(self
, section_header
, name
):
610 """ Create a SymbolTableSection
612 linked_strtab_index
= section_header
['sh_link']
613 strtab_section
= self
.get_section(linked_strtab_index
)
614 return SymbolTableSection(
615 section_header
, name
,
617 stringtable
=strtab_section
)
619 def _make_symbol_table_index_section(self
, section_header
, name
):
620 """ Create a SymbolTableIndexSection object
622 linked_symtab_index
= section_header
['sh_link']
623 return SymbolTableIndexSection(
624 section_header
, name
, elffile
=self
,
625 symboltable
=linked_symtab_index
)
627 def _make_sunwsyminfo_table_section(self
, section_header
, name
):
628 """ Create a SUNWSyminfoTableSection
630 linked_strtab_index
= section_header
['sh_link']
631 strtab_section
= self
.get_section(linked_strtab_index
)
632 return SUNWSyminfoTableSection(
633 section_header
, name
,
635 symboltable
=strtab_section
)
637 def _make_gnu_verneed_section(self
, section_header
, name
):
638 """ Create a GNUVerNeedSection
640 linked_strtab_index
= section_header
['sh_link']
641 strtab_section
= self
.get_section(linked_strtab_index
)
642 return GNUVerNeedSection(
643 section_header
, name
,
645 stringtable
=strtab_section
)
647 def _make_gnu_verdef_section(self
, section_header
, name
):
648 """ Create a GNUVerDefSection
650 linked_strtab_index
= section_header
['sh_link']
651 strtab_section
= self
.get_section(linked_strtab_index
)
652 return GNUVerDefSection(
653 section_header
, name
,
655 stringtable
=strtab_section
)
657 def _make_gnu_versym_section(self
, section_header
, name
):
658 """ Create a GNUVerSymSection
660 linked_strtab_index
= section_header
['sh_link']
661 strtab_section
= self
.get_section(linked_strtab_index
)
662 return GNUVerSymSection(
663 section_header
, name
,
665 symboltable
=strtab_section
)
667 def _make_elf_hash_section(self
, section_header
, name
):
668 linked_symtab_index
= section_header
['sh_link']
669 symtab_section
= self
.get_section(linked_symtab_index
)
670 return ELFHashSection(
671 section_header
, name
, self
, symtab_section
674 def _make_gnu_hash_section(self
, section_header
, name
):
675 linked_symtab_index
= section_header
['sh_link']
676 symtab_section
= self
.get_section(linked_symtab_index
)
677 return GNUHashSection(
678 section_header
, name
, self
, symtab_section
681 def _get_segment_header(self
, n
):
682 """ Find the header of segment #n, parse it and return the struct
685 self
.structs
.Elf_Phdr
,
687 stream_pos
=self
._segment
_offset
(n
))
689 def _get_section_header_stringtable(self
):
690 """ Get the string table section corresponding to the section header
693 stringtable_section_num
= self
.get_shstrndx()
694 return StringTableSection(
695 header
=self
._get
_section
_header
(stringtable_section_num
),
699 def _parse_elf_header(self
):
700 """ Parses the ELF file header and assigns the result to attributes
703 return struct_parse(self
.structs
.Elf_Ehdr
, self
.stream
, stream_pos
=0)
705 def _read_dwarf_section(self
, section
, relocate_dwarf_sections
):
706 """ Read the contents of a DWARF section from the stream and return a
707 DebugSectionDescriptor. Apply relocations if asked to.
709 # The section data is read into a new stream, for processing
710 section_stream
= BytesIO()
711 section_stream
.write(section
.data())
713 if relocate_dwarf_sections
:
714 reloc_handler
= RelocationHandler(self
)
715 reloc_section
= reloc_handler
.find_relocations_for_section(section
)
716 if reloc_section
is not None:
717 reloc_handler
.apply_section_relocations(
718 section_stream
, reloc_section
)
720 return DebugSectionDescriptor(
721 stream
=section_stream
,
723 global_offset
=section
['sh_offset'],
724 size
=section
.data_size
,
725 address
=section
['sh_addr'])
728 def _decompress_dwarf_section(section
):
729 """ Returns the uncompressed contents of the provided DWARF section.
731 # TODO: support other compression formats from readelf.c
732 assert section
.size
> 12, 'Unsupported compression format.'
734 section
.stream
.seek(0)
735 # According to readelf.c the content should contain "ZLIB"
736 # followed by the uncompressed section size - 8 bytes in
738 compression_type
= section
.stream
.read(4)
739 assert compression_type
== b
'ZLIB', \
740 'Invalid compression type: %r' % (compression_type
)
742 uncompressed_size
= struct
.unpack('>Q', section
.stream
.read(8))[0]
744 decompressor
= zlib
.decompressobj()
745 uncompressed_stream
= BytesIO()
747 chunk
= section
.stream
.read(PAGESIZE
)
750 uncompressed_stream
.write(decompressor
.decompress(chunk
))
751 uncompressed_stream
.write(decompressor
.flush())
753 uncompressed_stream
.seek(0, io
.SEEK_END
)
754 size
= uncompressed_stream
.tell()
755 assert uncompressed_size
== size
, \
756 'Wrong uncompressed size: expected %r, but got %r' % (
757 uncompressed_size
, size
,
760 return section
._replace
(stream
=uncompressed_stream
, size
=size
)