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