2 # ELF support functionality for Python.
3 # Copyright (C) 2022 Free Software Foundation, Inc.
4 # This file is part of the GNU C Library.
6 # The GNU C Library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # The GNU C Library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with the GNU C Library; if not, see
18 # <https://www.gnu.org/licenses/>.
22 Use Image.readfile(path) to read an ELF file into memory and begin
31 if not hasattr(enum
, 'IntFlag'):
34 'warning: glibcelf.py needs Python 3.6 for enum support\n')
37 class _OpenIntEnum(enum
.IntEnum
):
38 """Integer enumeration that supports arbitrary int values."""
40 def _missing_(cls
, value
):
41 # See enum.IntFlag._create_pseudo_member_. This allows
42 # creating of enum constants with arbitrary integer values.
43 pseudo_member
= int.__new
__(cls
, value
)
44 pseudo_member
._name
_ = None
45 pseudo_member
._value
_ = value
51 # The names have prefixes like SHT_, implying their type.
53 return '{}({})'.format(self
.__class
__.__name
__, self
._value
_)
59 return str(self
._value
_)
61 class ElfClass(_OpenIntEnum
):
62 """ELF word size. Type of EI_CLASS values."""
67 class ElfData(_OpenIntEnum
):
68 """ELF endianess. Type of EI_DATA values."""
73 class Machine(_OpenIntEnum
):
74 """ELF machine type. Type of values in Ehdr.e_machine field."""
171 EM_ALTERA_NIOS2
= 113
186 EM_LATTICEMICO32
= 138
259 class Et(_OpenIntEnum
):
260 """ELF file type. Type of ET_* values and the Ehdr.e_type field."""
267 class Shn(_OpenIntEnum
):
268 """ELF reserved section indices."""
276 class ShnMIPS(enum
.Enum
):
277 """Supplemental SHN_* constants for EM_MIPS."""
278 SHN_MIPS_ACOMMON
= 0xff00
279 SHN_MIPS_TEXT
= 0xff01
280 SHN_MIPS_DATA
= 0xff02
281 SHN_MIPS_SCOMMON
= 0xff03
282 SHN_MIPS_SUNDEFINED
= 0xff04
284 class ShnPARISC(enum
.Enum
):
285 """Supplemental SHN_* constants for EM_PARISC."""
286 SHN_PARISC_ANSI_COMMON
= 0xff00
287 SHN_PARISC_HUGE_COMMON
= 0xff01
289 class Sht(_OpenIntEnum
):
290 """ELF section types. Type of SHT_* values."""
305 SHT_PREINIT_ARRAY
= 16
307 SHT_SYMTAB_SHNDX
= 18
309 SHT_GNU_ATTRIBUTES
= 0x6ffffff5
310 SHT_GNU_HASH
= 0x6ffffff6
311 SHT_GNU_LIBLIST
= 0x6ffffff7
312 SHT_CHECKSUM
= 0x6ffffff8
313 SHT_SUNW_move
= 0x6ffffffa
314 SHT_SUNW_COMDAT
= 0x6ffffffb
315 SHT_SUNW_syminfo
= 0x6ffffffc
316 SHT_GNU_verdef
= 0x6ffffffd
317 SHT_GNU_verneed
= 0x6ffffffe
318 SHT_GNU_versym
= 0x6fffffff
320 class ShtALPHA(enum
.Enum
):
321 """Supplemental SHT_* constants for EM_ALPHA."""
322 SHT_ALPHA_DEBUG
= 0x70000001
323 SHT_ALPHA_REGINFO
= 0x70000002
325 class ShtARM(enum
.Enum
):
326 """Supplemental SHT_* constants for EM_ARM."""
327 SHT_ARM_EXIDX
= 0x70000001
328 SHT_ARM_PREEMPTMAP
= 0x70000002
329 SHT_ARM_ATTRIBUTES
= 0x70000003
331 class ShtCSKY(enum
.Enum
):
332 """Supplemental SHT_* constants for EM_CSKY."""
333 SHT_CSKY_ATTRIBUTES
= 0x70000001
335 class ShtIA_64(enum
.Enum
):
336 """Supplemental SHT_* constants for EM_IA_64."""
337 SHT_IA_64_EXT
= 0x70000000
338 SHT_IA_64_UNWIND
= 0x70000001
340 class ShtMIPS(enum
.Enum
):
341 """Supplemental SHT_* constants for EM_MIPS."""
342 SHT_MIPS_LIBLIST
= 0x70000000
343 SHT_MIPS_MSYM
= 0x70000001
344 SHT_MIPS_CONFLICT
= 0x70000002
345 SHT_MIPS_GPTAB
= 0x70000003
346 SHT_MIPS_UCODE
= 0x70000004
347 SHT_MIPS_DEBUG
= 0x70000005
348 SHT_MIPS_REGINFO
= 0x70000006
349 SHT_MIPS_PACKAGE
= 0x70000007
350 SHT_MIPS_PACKSYM
= 0x70000008
351 SHT_MIPS_RELD
= 0x70000009
352 SHT_MIPS_IFACE
= 0x7000000b
353 SHT_MIPS_CONTENT
= 0x7000000c
354 SHT_MIPS_OPTIONS
= 0x7000000d
355 SHT_MIPS_SHDR
= 0x70000010
356 SHT_MIPS_FDESC
= 0x70000011
357 SHT_MIPS_EXTSYM
= 0x70000012
358 SHT_MIPS_DENSE
= 0x70000013
359 SHT_MIPS_PDESC
= 0x70000014
360 SHT_MIPS_LOCSYM
= 0x70000015
361 SHT_MIPS_AUXSYM
= 0x70000016
362 SHT_MIPS_OPTSYM
= 0x70000017
363 SHT_MIPS_LOCSTR
= 0x70000018
364 SHT_MIPS_LINE
= 0x70000019
365 SHT_MIPS_RFDESC
= 0x7000001a
366 SHT_MIPS_DELTASYM
= 0x7000001b
367 SHT_MIPS_DELTAINST
= 0x7000001c
368 SHT_MIPS_DELTACLASS
= 0x7000001d
369 SHT_MIPS_DWARF
= 0x7000001e
370 SHT_MIPS_DELTADECL
= 0x7000001f
371 SHT_MIPS_SYMBOL_LIB
= 0x70000020
372 SHT_MIPS_EVENTS
= 0x70000021
373 SHT_MIPS_TRANSLATE
= 0x70000022
374 SHT_MIPS_PIXIE
= 0x70000023
375 SHT_MIPS_XLATE
= 0x70000024
376 SHT_MIPS_XLATE_DEBUG
= 0x70000025
377 SHT_MIPS_WHIRL
= 0x70000026
378 SHT_MIPS_EH_REGION
= 0x70000027
379 SHT_MIPS_XLATE_OLD
= 0x70000028
380 SHT_MIPS_PDR_EXCEPTION
= 0x70000029
381 SHT_MIPS_XHASH
= 0x7000002b
383 class ShtPARISC(enum
.Enum
):
384 """Supplemental SHT_* constants for EM_PARISC."""
385 SHT_PARISC_EXT
= 0x70000000
386 SHT_PARISC_UNWIND
= 0x70000001
387 SHT_PARISC_DOC
= 0x70000002
389 class ShtRISCV(enum
.Enum
):
390 """Supplemental SHT_* constants for EM_RISCV."""
391 SHT_RISCV_ATTRIBUTES
= 0x70000003
393 class Pf(enum
.IntFlag
):
394 """Program header flags. Type of Phdr.p_flags values."""
399 class PfARM(enum
.IntFlag
):
400 """Supplemental PF_* flags for EM_ARM."""
401 PF_ARM_SB
= 0x10000000
402 PF_ARM_PI
= 0x20000000
403 PF_ARM_ABS
= 0x40000000
405 class PfPARISC(enum
.IntFlag
):
406 """Supplemental PF_* flags for EM_PARISC."""
407 PF_HP_PAGE_SIZE
= 0x00100000
408 PF_HP_FAR_SHARED
= 0x00200000
409 PF_HP_NEAR_SHARED
= 0x00400000
410 PF_HP_CODE
= 0x01000000
411 PF_HP_MODIFY
= 0x02000000
412 PF_HP_LAZYSWAP
= 0x04000000
413 PF_HP_SBP
= 0x08000000
415 class PfIA_64(enum
.IntFlag
):
416 """Supplemental PF_* flags for EM_IA_64."""
417 PF_IA_64_NORECOV
= 0x80000000
419 class PfMIPS(enum
.IntFlag
):
420 """Supplemental PF_* flags for EM_MIPS."""
421 PF_MIPS_LOCAL
= 0x10000000
423 class Shf(enum
.IntFlag
):
424 """Section flags. Type of Shdr.sh_type values."""
427 SHF_EXECINSTR
= 1 << 2
430 SHF_INFO_LINK
= 1 << 6
431 SHF_LINK_ORDER
= 1 << 7
432 SHF_OS_NONCONFORMING
= 256
435 SHF_COMPRESSED
= 1 << 11
436 SHF_GNU_RETAIN
= 1 << 21
437 SHF_ORDERED
= 1 << 30
438 SHF_EXCLUDE
= 1 << 31
440 class ShfALPHA(enum
.IntFlag
):
441 """Supplemental SHF_* constants for EM_ALPHA."""
442 SHF_ALPHA_GPREL
= 0x10000000
444 class ShfARM(enum
.IntFlag
):
445 """Supplemental SHF_* constants for EM_ARM."""
446 SHF_ARM_ENTRYSECT
= 0x10000000
447 SHF_ARM_COMDEF
= 0x80000000
449 class ShfIA_64(enum
.IntFlag
):
450 """Supplemental SHF_* constants for EM_IA_64."""
451 SHF_IA_64_SHORT
= 0x10000000
452 SHF_IA_64_NORECOV
= 0x20000000
454 class ShfMIPS(enum
.IntFlag
):
455 """Supplemental SHF_* constants for EM_MIPS."""
456 SHF_MIPS_GPREL
= 0x10000000
457 SHF_MIPS_MERGE
= 0x20000000
458 SHF_MIPS_ADDR
= 0x40000000
459 SHF_MIPS_STRINGS
= 0x80000000
460 SHF_MIPS_NOSTRIP
= 0x08000000
461 SHF_MIPS_LOCAL
= 0x04000000
462 SHF_MIPS_NAMES
= 0x02000000
463 SHF_MIPS_NODUPE
= 0x01000000
465 class ShfPARISC(enum
.IntFlag
):
466 """Supplemental SHF_* constants for EM_PARISC."""
467 SHF_PARISC_SHORT
= 0x20000000
468 SHF_PARISC_HUGE
= 0x40000000
469 SHF_PARISC_SBP
= 0x80000000
471 class Stb(_OpenIntEnum
):
472 """ELF symbol binding type."""
477 STB_MIPS_SPLIT_COMMON
= 13
479 class Stt(_OpenIntEnum
):
480 """ELF symbol type."""
490 class SttARM(enum
.Enum
):
491 """Supplemental STT_* constants for EM_ARM."""
495 class SttPARISC(enum
.Enum
):
496 """Supplemental STT_* constants for EM_PARISC."""
499 STT_PARISC_MILLICODE
= 13
501 class SttSPARC(enum
.Enum
):
502 """Supplemental STT_* constants for EM_SPARC."""
503 STT_SPARC_REGISTER
= 13
505 class SttX86_64(enum
.Enum
):
506 """Supplemental STT_* constants for EM_X86_64."""
507 SHT_X86_64_UNWIND
= 0x70000001
509 class Pt(_OpenIntEnum
):
510 """ELF program header types. Type of Phdr.p_type."""
520 PT_GNU_EH_FRAME
= 0x6474e550
521 PT_GNU_STACK
= 0x6474e551
522 PT_GNU_RELRO
= 0x6474e552
523 PT_GNU_PROPERTY
= 0x6474e553
524 PT_SUNWBSS
= 0x6ffffffa
525 PT_SUNWSTACK
= 0x6ffffffb
527 class PtAARCH64(enum
.Enum
):
528 """Supplemental PT_* constants for EM_AARCH64."""
529 PT_AARCH64_MEMTAG_MTE
= 0x70000002
531 class PtARM(enum
.Enum
):
532 """Supplemental PT_* constants for EM_ARM."""
533 PT_ARM_EXIDX
= 0x70000001
535 class PtIA_64(enum
.Enum
):
536 """Supplemental PT_* constants for EM_IA_64."""
537 PT_IA_64_HP_OPT_ANOT
= 0x60000012
538 PT_IA_64_HP_HSL_ANOT
= 0x60000013
539 PT_IA_64_HP_STACK
= 0x60000014
540 PT_IA_64_ARCHEXT
= 0x70000000
541 PT_IA_64_UNWIND
= 0x70000001
543 class PtMIPS(enum
.Enum
):
544 """Supplemental PT_* constants for EM_MIPS."""
545 PT_MIPS_REGINFO
= 0x70000000
546 PT_MIPS_RTPROC
= 0x70000001
547 PT_MIPS_OPTIONS
= 0x70000002
548 PT_MIPS_ABIFLAGS
= 0x70000003
550 class PtPARISC(enum
.Enum
):
551 """Supplemental PT_* constants for EM_PARISC."""
552 PT_HP_TLS
= 0x60000000
553 PT_HP_CORE_NONE
= 0x60000001
554 PT_HP_CORE_VERSION
= 0x60000002
555 PT_HP_CORE_KERNEL
= 0x60000003
556 PT_HP_CORE_COMM
= 0x60000004
557 PT_HP_CORE_PROC
= 0x60000005
558 PT_HP_CORE_LOADABLE
= 0x60000006
559 PT_HP_CORE_STACK
= 0x60000007
560 PT_HP_CORE_SHM
= 0x60000008
561 PT_HP_CORE_MMF
= 0x60000009
562 PT_HP_PARALLEL
= 0x60000010
563 PT_HP_FASTBIND
= 0x60000011
564 PT_HP_OPT_ANNOT
= 0x60000012
565 PT_HP_HSL_ANNOT
= 0x60000013
566 PT_HP_STACK
= 0x60000014
567 PT_PARISC_ARCHEXT
= 0x70000000
568 PT_PARISC_UNWIND
= 0x70000001
570 class PtRISCV(enum
.Enum
):
571 """Supplemental PT_* constants for EM_RISCV."""
572 PT_RISCV_ATTRIBUTES
= 0x70000003
574 class Dt(_OpenIntEnum
):
575 """ELF dynamic segment tags. Type of Dyn.d_val."""
607 DT_PREINIT_ARRAY
= 32
608 DT_PREINIT_ARRAYSZ
= 33
613 DT_GNU_PRELINKED
= 0x6ffffdf5
614 DT_GNU_CONFLICTSZ
= 0x6ffffdf6
615 DT_GNU_LIBLISTSZ
= 0x6ffffdf7
616 DT_CHECKSUM
= 0x6ffffdf8
617 DT_PLTPADSZ
= 0x6ffffdf9
618 DT_MOVEENT
= 0x6ffffdfa
619 DT_MOVESZ
= 0x6ffffdfb
620 DT_FEATURE_1
= 0x6ffffdfc
621 DT_POSFLAG_1
= 0x6ffffdfd
622 DT_SYMINSZ
= 0x6ffffdfe
623 DT_SYMINENT
= 0x6ffffdff
624 DT_GNU_HASH
= 0x6ffffef5
625 DT_TLSDESC_PLT
= 0x6ffffef6
626 DT_TLSDESC_GOT
= 0x6ffffef7
627 DT_GNU_CONFLICT
= 0x6ffffef8
628 DT_GNU_LIBLIST
= 0x6ffffef9
629 DT_CONFIG
= 0x6ffffefa
630 DT_DEPAUDIT
= 0x6ffffefb
631 DT_AUDIT
= 0x6ffffefc
632 DT_PLTPAD
= 0x6ffffefd
633 DT_MOVETAB
= 0x6ffffefe
634 DT_SYMINFO
= 0x6ffffeff
635 DT_VERSYM
= 0x6ffffff0
636 DT_RELACOUNT
= 0x6ffffff9
637 DT_RELCOUNT
= 0x6ffffffa
638 DT_FLAGS_1
= 0x6ffffffb
639 DT_VERDEF
= 0x6ffffffc
640 DT_VERDEFNUM
= 0x6ffffffd
641 DT_VERNEED
= 0x6ffffffe
642 DT_VERNEEDNUM
= 0x6fffffff
643 DT_AUXILIARY
= 0x7ffffffd
644 DT_FILTER
= 0x7fffffff
646 class DtAARCH64(enum
.Enum
):
647 """Supplemental DT_* constants for EM_AARCH64."""
648 DT_AARCH64_BTI_PLT
= 0x70000001
649 DT_AARCH64_PAC_PLT
= 0x70000003
650 DT_AARCH64_VARIANT_PCS
= 0x70000005
652 class DtALPHA(enum
.Enum
):
653 """Supplemental DT_* constants for EM_ALPHA."""
654 DT_ALPHA_PLTRO
= 0x70000000
656 class DtALTERA_NIOS2(enum
.Enum
):
657 """Supplemental DT_* constants for EM_ALTERA_NIOS2."""
658 DT_NIOS2_GP
= 0x70000002
660 class DtIA_64(enum
.Enum
):
661 """Supplemental DT_* constants for EM_IA_64."""
662 DT_IA_64_PLT_RESERVE
= 0x70000000
664 class DtMIPS(enum
.Enum
):
665 """Supplemental DT_* constants for EM_MIPS."""
666 DT_MIPS_RLD_VERSION
= 0x70000001
667 DT_MIPS_TIME_STAMP
= 0x70000002
668 DT_MIPS_ICHECKSUM
= 0x70000003
669 DT_MIPS_IVERSION
= 0x70000004
670 DT_MIPS_FLAGS
= 0x70000005
671 DT_MIPS_BASE_ADDRESS
= 0x70000006
672 DT_MIPS_MSYM
= 0x70000007
673 DT_MIPS_CONFLICT
= 0x70000008
674 DT_MIPS_LIBLIST
= 0x70000009
675 DT_MIPS_LOCAL_GOTNO
= 0x7000000a
676 DT_MIPS_CONFLICTNO
= 0x7000000b
677 DT_MIPS_LIBLISTNO
= 0x70000010
678 DT_MIPS_SYMTABNO
= 0x70000011
679 DT_MIPS_UNREFEXTNO
= 0x70000012
680 DT_MIPS_GOTSYM
= 0x70000013
681 DT_MIPS_HIPAGENO
= 0x70000014
682 DT_MIPS_RLD_MAP
= 0x70000016
683 DT_MIPS_DELTA_CLASS
= 0x70000017
684 DT_MIPS_DELTA_CLASS_NO
= 0x70000018
685 DT_MIPS_DELTA_INSTANCE
= 0x70000019
686 DT_MIPS_DELTA_INSTANCE_NO
= 0x7000001a
687 DT_MIPS_DELTA_RELOC
= 0x7000001b
688 DT_MIPS_DELTA_RELOC_NO
= 0x7000001c
689 DT_MIPS_DELTA_SYM
= 0x7000001d
690 DT_MIPS_DELTA_SYM_NO
= 0x7000001e
691 DT_MIPS_DELTA_CLASSSYM
= 0x70000020
692 DT_MIPS_DELTA_CLASSSYM_NO
= 0x70000021
693 DT_MIPS_CXX_FLAGS
= 0x70000022
694 DT_MIPS_PIXIE_INIT
= 0x70000023
695 DT_MIPS_SYMBOL_LIB
= 0x70000024
696 DT_MIPS_LOCALPAGE_GOTIDX
= 0x70000025
697 DT_MIPS_LOCAL_GOTIDX
= 0x70000026
698 DT_MIPS_HIDDEN_GOTIDX
= 0x70000027
699 DT_MIPS_PROTECTED_GOTIDX
= 0x70000028
700 DT_MIPS_OPTIONS
= 0x70000029
701 DT_MIPS_INTERFACE
= 0x7000002a
702 DT_MIPS_DYNSTR_ALIGN
= 0x7000002b
703 DT_MIPS_INTERFACE_SIZE
= 0x7000002c
704 DT_MIPS_RLD_TEXT_RESOLVE_ADDR
= 0x7000002d
705 DT_MIPS_PERF_SUFFIX
= 0x7000002e
706 DT_MIPS_COMPACT_SIZE
= 0x7000002f
707 DT_MIPS_GP_VALUE
= 0x70000030
708 DT_MIPS_AUX_DYNAMIC
= 0x70000031
709 DT_MIPS_PLTGOT
= 0x70000032
710 DT_MIPS_RWPLT
= 0x70000034
711 DT_MIPS_RLD_MAP_REL
= 0x70000035
712 DT_MIPS_XHASH
= 0x70000036
714 class DtPPC(enum
.Enum
):
715 """Supplemental DT_* constants for EM_PPC."""
716 DT_PPC_GOT
= 0x70000000
717 DT_PPC_OPT
= 0x70000001
719 class DtPPC64(enum
.Enum
):
720 """Supplemental DT_* constants for EM_PPC64."""
721 DT_PPC64_GLINK
= 0x70000000
722 DT_PPC64_OPD
= 0x70000001
723 DT_PPC64_OPDSZ
= 0x70000002
724 DT_PPC64_OPT
= 0x70000003
726 class DtRISCV(enum
.Enum
):
727 """Supplemental DT_* constants for EM_RISCV."""
728 DT_RISCV_VARIANT_CC
= 0x70000001
730 class DtSPARC(enum
.Enum
):
731 """Supplemental DT_* constants for EM_SPARC."""
732 DT_SPARC_REGISTER
= 0x70000001
735 """ELF symbol binding and type. Type of the Sym.st_info field."""
736 def __init__(self
, arg0
, arg1
=None):
737 if isinstance(arg0
, int) and arg1
is None:
738 self
.bind
= Stb(arg0
>> 4)
739 self
.type = Stt(arg0
& 15)
741 self
.bind
= Stb(arg0
)
742 self
.type = Stt(arg1
)
745 """Returns the raw value for the bind/type combination."""
746 return (self
.bind
.value() << 4) |
(self
.type.value())
748 # Type in an ELF file. Used for deserialization.
749 _Layout
= collections
.namedtuple('_Layout', 'unpack size')
751 def _define_layouts(baseclass
: type, layout32
: str, layout64
: str,
752 types
=None, fields32
=None):
753 """Assign variants dict to baseclass.
755 The variants dict is indexed by (ElfClass, ElfData) pairs, and its
756 values are _Layout instances.
759 struct32
= struct
.Struct(layout32
)
760 struct64
= struct
.Struct(layout64
)
762 # Check that the struct formats yield the right number of components.
763 for s
in (struct32
, struct64
):
764 example
= s
.unpack(b
' ' * s
.size
)
765 if len(example
) != len(baseclass
._fields
):
766 raise ValueError('{!r} yields wrong field count: {} != {}'.format(
767 s
.format
, len(example
), len(baseclass
._fields
)))
769 # Check that field names in types are correct.
773 if n
not in baseclass
._fields
:
774 raise ValueError('{} does not have field {!r}'.format(
775 baseclass
.__name
__, n
))
777 if fields32
is not None \
778 and set(fields32
) != set(baseclass
._fields
):
779 raise ValueError('{!r} is not a permutation of the fields {!r}'.format(
780 fields32
, baseclass
._fields
))
782 def unique_name(name
, used_names
= (set((baseclass
.__name
__,))
783 |
set(baseclass
._fields
)
785 for n
in (types
or {}).values()})):
786 """Find a name that is not used for a class or field name."""
789 while candidate
in used_names
:
791 candidate
= '{}{}'.format(name
, n
)
792 used_names
.add(candidate
)
795 blob_name
= unique_name('blob')
796 struct_unpack_name
= unique_name('struct_unpack')
797 comps_name
= unique_name('comps')
800 for (bits
, elfclass
, layout
, fields
) in (
801 (32, ElfClass
.ELFCLASS32
, layout32
, fields32
),
802 (64, ElfClass
.ELFCLASS64
, layout64
, None),
804 for (elfdata
, structprefix
, funcsuffix
) in (
805 (ElfData
.ELFDATA2LSB
, '<', 'LE'),
806 (ElfData
.ELFDATA2MSB
, '>', 'BE'),
809 baseclass
.__name
__: baseclass
,
810 struct_unpack_name
: struct
.unpack
,
813 # Add the type converters.
815 for cls
in types
.values():
816 env
[cls
.__name
__] = cls
819 ('unpack_', baseclass
.__name
__, str(bits
), funcsuffix
))
822 def {funcname}({blob_name}):
823 '''.format(funcname
=funcname
, blob_name
=blob_name
)
826 unpack_call
= '{}({!r}, {})'.format(
827 struct_unpack_name
, structprefix
+ layout
, blob_name
)
828 field_names
= ', '.join(baseclass
._fields
)
829 if types
is None and fields
is None:
830 code
+= '{}return {}({})\n'.format(
831 indent
, baseclass
.__name
__, unpack_call
)
833 # Destructuring tuple assignment.
835 code
+= '{}{} = {}\n'.format(
836 indent
, field_names
, unpack_call
)
838 # Use custom field order.
839 code
+= '{}{} = {}\n'.format(
840 indent
, ', '.join(fields
), unpack_call
)
842 # Perform the type conversions.
843 for n
in baseclass
._fields
:
845 code
+= '{}{} = {}({})\n'.format(
846 indent
, n
, types
[n
].__name
__, n
)
847 # Create the named tuple.
848 code
+= '{}return {}({})\n'.format(
849 indent
, baseclass
.__name
__, field_names
)
852 layouts
[(elfclass
, elfdata
)] = _Layout(
853 env
[funcname
], struct
.calcsize(layout
))
854 baseclass
.layouts
= layouts
857 # Corresponds to EI_* indices into Elf*_Ehdr.e_indent.
858 class Ident(collections
.namedtuple('Ident',
859 'ei_mag ei_class ei_data ei_version ei_osabi ei_abiversion ei_pad')):
861 def __new__(cls
, *args
):
862 """Construct an object from a blob or its constituent fields."""
864 return cls
.unpack(args
[0])
865 return cls
.__base
__.__new
__(cls
, *args
)
868 def unpack(blob
: memoryview
) -> 'Ident':
869 """Parse raws data into a tuple."""
870 ei_mag
, ei_class
, ei_data
, ei_version
, ei_osabi
, ei_abiversion
, \
871 ei_pad
= struct
.unpack('4s5B7s', blob
)
872 return Ident(ei_mag
, ElfClass(ei_class
), ElfData(ei_data
),
873 ei_version
, ei_osabi
, ei_abiversion
, ei_pad
)
876 # Corresponds to Elf32_Ehdr and Elf64_Ehdr.
877 Ehdr
= collections
.namedtuple('Ehdr',
878 'e_ident e_type e_machine e_version e_entry e_phoff e_shoff e_flags'
879 + ' e_ehsize e_phentsize e_phnum e_shentsize e_shnum e_shstrndx')
880 _define_layouts(Ehdr
,
881 layout32
='16s2H5I6H',
882 layout64
='16s2HI3QI6H',
883 types
=dict(e_ident
=Ident
,
888 # Corresponds to Elf32_Phdr and Elf64_Pdhr. Order follows the latter.
889 Phdr
= collections
.namedtuple('Phdr',
890 'p_type p_flags p_offset p_vaddr p_paddr p_filesz p_memsz p_align')
891 _define_layouts(Phdr
,
893 fields32
=('p_type', 'p_offset', 'p_vaddr', 'p_paddr',
894 'p_filesz', 'p_memsz', 'p_flags', 'p_align'),
896 types
=dict(p_type
=Pt
, p_flags
=Pf
))
899 # Corresponds to Elf32_Shdr and Elf64_Shdr.
900 class Shdr(collections
.namedtuple('Shdr',
901 'sh_name sh_type sh_flags sh_addr sh_offset sh_size sh_link sh_info'
902 + ' sh_addralign sh_entsize')):
903 def resolve(self
, strtab
: 'StringTable') -> 'Shdr':
904 """Resolve sh_name using a string table."""
905 return self
.__class
__(strtab
.get(self
[0]), *self
[1:])
906 _define_layouts(Shdr
,
909 types
=dict(sh_type
=Sht
,
913 # Corresponds to Elf32_Dyn and Elf64_Dyn. The nesting through the
914 # d_un union is skipped, and d_ptr is missing (its representation in
915 # Python would be identical to d_val).
916 Dyn
= collections
.namedtuple('Dyn', 'd_tag d_val')
920 types
=dict(d_tag
=Dt
))
922 # Corresponds to Elf32_Sym and Elf64_Sym.
923 class Sym(collections
.namedtuple('Sym',
924 'st_name st_info st_other st_shndx st_value st_size')):
925 def resolve(self
, strtab
: 'StringTable') -> 'Sym':
926 """Resolve st_name using a string table."""
927 return self
.__class
__(strtab
.get(self
[0]), *self
[1:])
931 fields32
=('st_name', 'st_value', 'st_size', 'st_info',
932 'st_other', 'st_shndx'),
933 types
=dict(st_shndx
=Shn
,
936 # Corresponds to Elf32_Rel and Elf64_Rel.
937 Rel
= collections
.namedtuple('Rel', 'r_offset r_info')
942 # Corresponds to Elf32_Rel and Elf64_Rel.
943 Rela
= collections
.namedtuple('Rela', 'r_offset r_info r_addend')
944 _define_layouts(Rela
,
949 """ELF string table."""
950 def __init__(self
, blob
):
951 """Create a new string table backed by the data in the blob.
953 blob: a memoryview-like object
958 def get(self
, index
) -> bytes
:
959 """Returns the null-terminated byte string at the index."""
963 if blob
[endindex
] == 0:
964 return bytes(blob
[index
:endindex
])
968 """ELF image parser."""
969 def __init__(self
, image
):
970 """Create an ELF image from binary image data.
972 image: a memoryview-like object that supports efficient range
977 ident
= self
.read(Ident
, 0)
978 classdata
= (ident
.ei_class
, ident
.ei_data
)
979 # Set self.Ehdr etc. to the subtypes with the right parsers.
980 for typ
in (Ehdr
, Phdr
, Shdr
, Dyn
, Sym
, Rel
, Rela
):
981 setattr(self
, typ
.__name
__, typ
.layouts
.get(classdata
, None))
983 if self
.Ehdr
is not None:
984 self
.ehdr
= self
.read(self
.Ehdr
, 0)
985 self
._shdr
_num
= self
._compute
_shdr
_num
()
993 if self
._shdr
_num
> 0:
994 self
._shdr
_strtab
= self
._find
_shdr
_strtab
()
996 self
._shdr
_strtab
= None
999 def readfile(path
: str) -> 'Image':
1000 """Reads the ELF file at the specified path."""
1001 with
open(path
, 'rb') as inp
:
1002 return Image(memoryview(inp
.read()))
1004 def _compute_shdr_num(self
) -> int:
1005 """Computes the actual number of section headers."""
1006 shnum
= self
.ehdr
.e_shnum
1008 if self
.ehdr
.e_shoff
== 0 or self
.ehdr
.e_shentsize
== 0:
1009 # No section headers.
1011 # Otherwise the extension mechanism is used (which may be
1012 # needed because e_shnum is just 16 bits).
1013 return self
.read(self
.Shdr
, self
.ehdr
.e_shoff
).sh_size
1016 def _find_shdr_strtab(self
) -> StringTable
:
1017 """Finds the section header string table (maybe via extensions)."""
1018 shstrndx
= self
.ehdr
.e_shstrndx
1019 if shstrndx
== Shn
.SHN_XINDEX
:
1020 shstrndx
= self
.read(self
.Shdr
, self
.ehdr
.e_shoff
).sh_link
1021 return self
._find
_stringtab
(shstrndx
)
1023 def read(self
, typ
: type, offset
:int ):
1024 """Reads an object at a specific offset.
1026 The type must have been enhanced using _define_variants.
1029 return typ
.unpack(self
.image
[offset
: offset
+ typ
.size
])
1031 def phdrs(self
) -> Phdr
:
1032 """Generator iterating over the program headers."""
1033 if self
.ehdr
is None:
1035 size
= self
.ehdr
.e_phentsize
1036 if size
!= self
.Phdr
.size
:
1037 raise ValueError('Unexpected Phdr size in ELF header: {} != {}'
1038 .format(size
, self
.Phdr
.size
))
1040 offset
= self
.ehdr
.e_phoff
1041 for _
in range(self
.ehdr
.e_phnum
):
1042 yield self
.read(self
.Phdr
, offset
)
1045 def shdrs(self
, resolve
: bool=True) -> Shdr
:
1046 """Generator iterating over the section headers.
1048 If resolve, section names are automatically translated
1049 using the section header string table.
1052 if self
._shdr
_num
== 0:
1055 size
= self
.ehdr
.e_shentsize
1056 if size
!= self
.Shdr
.size
:
1057 raise ValueError('Unexpected Shdr size in ELF header: {} != {}'
1058 .format(size
, self
.Shdr
.size
))
1060 offset
= self
.ehdr
.e_shoff
1061 for _
in range(self
._shdr
_num
):
1062 shdr
= self
.read(self
.Shdr
, offset
)
1064 shdr
= shdr
.resolve(self
._shdr
_strtab
)
1068 def dynamic(self
) -> Dyn
:
1069 """Generator iterating over the dynamic segment."""
1070 for phdr
in self
.phdrs():
1071 if phdr
.p_type
== Pt
.PT_DYNAMIC
:
1072 # Pick the first dynamic segment, like the loader.
1073 if phdr
.p_filesz
== 0:
1074 # Probably separated debuginfo.
1076 offset
= phdr
.p_offset
1077 end
= offset
+ phdr
.p_memsz
1078 size
= self
.Dyn
.size
1080 next_offset
= offset
+ size
1081 if next_offset
> end
:
1083 'Dynamic segment size {} is not a multiple of Dyn size {}'.format(
1084 phdr
.p_memsz
, size
))
1085 yield self
.read(self
.Dyn
, offset
)
1086 if next_offset
== end
:
1088 offset
= next_offset
1090 def syms(self
, shdr
: Shdr
, resolve
: bool=True) -> Sym
:
1091 """A generator iterating over a symbol table.
1093 If resolve, symbol names are automatically translated using
1094 the string table for the symbol table.
1097 assert shdr
.sh_type
== Sht
.SHT_SYMTAB
1098 size
= shdr
.sh_entsize
1099 if size
!= self
.Sym
.size
:
1100 raise ValueError('Invalid symbol table entry size {}'.format(size
))
1101 offset
= shdr
.sh_offset
1102 end
= shdr
.sh_offset
+ shdr
.sh_size
1104 strtab
= self
._find
_stringtab
(shdr
.sh_link
)
1106 sym
= self
.read(self
.Sym
, offset
)
1108 sym
= sym
.resolve(strtab
)
1112 raise ValueError('Symbol table is not a multiple of entry size')
1114 def lookup_string(self
, strtab_index
: int, strtab_offset
: int) -> bytes
:
1115 """Looks up a string in a string table identified by its link index."""
1117 strtab
= self
._stringtab
[strtab_index
]
1119 strtab
= self
._find
_stringtab
(strtab_index
)
1120 return strtab
.get(strtab_offset
)
1122 def find_section(self
, shndx
: Shn
) -> Shdr
:
1123 """Returns the section header for the indexed section.
1125 The section name is not resolved.
1128 return self
._section
[shndx
]
1132 raise ValueError('Reserved section index {}'.format(shndx
))
1134 if idx
< 0 or idx
> self
._shdr
_num
:
1135 raise ValueError('Section index {} out of range [0, {})'.format(
1136 idx
, self
._shdr
_num
))
1138 self
.Shdr
, self
.ehdr
.e_shoff
+ idx
* self
.Shdr
.size
)
1139 self
._section
[shndx
] = shdr
1142 def _find_stringtab(self
, sh_link
: int) -> StringTable
:
1143 if sh_link
in self
._stringtab
:
1144 return self
._stringtab
1145 if sh_link
< 0 or sh_link
>= self
._shdr
_num
:
1146 raise ValueError('Section index {} out of range [0, {})'.format(
1147 sh_link
, self
._shdr
_num
))
1149 self
.Shdr
, self
.ehdr
.e_shoff
+ sh_link
* self
.Shdr
.size
)
1150 if shdr
.sh_type
!= Sht
.SHT_STRTAB
:
1152 'Section {} is not a string table: {}'.format(
1153 sh_link
, shdr
.sh_type
))
1154 strtab
= StringTable(
1155 self
.image
[shdr
.sh_offset
:shdr
.sh_offset
+ shdr
.sh_size
])
1156 # This could retrain essentially arbitrary amounts of data,
1157 # but caching string tables seems important for performance.
1158 self
._stringtab
[sh_link
] = strtab
1162 __all__
= [name
for name
in dir() if name
[0].isupper()]