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
258 class Et(_OpenIntEnum
):
259 """ELF file type. Type of ET_* values and the Ehdr.e_type field."""
266 class Shn(_OpenIntEnum
):
267 """ELF reserved section indices."""
275 class ShnMIPS(enum
.Enum
):
276 """Supplemental SHN_* constants for EM_MIPS."""
277 SHN_MIPS_ACOMMON
= 0xff00
278 SHN_MIPS_TEXT
= 0xff01
279 SHN_MIPS_DATA
= 0xff02
280 SHN_MIPS_SCOMMON
= 0xff03
281 SHN_MIPS_SUNDEFINED
= 0xff04
283 class ShnPARISC(enum
.Enum
):
284 """Supplemental SHN_* constants for EM_PARISC."""
285 SHN_PARISC_ANSI_COMMON
= 0xff00
286 SHN_PARISC_HUGE_COMMON
= 0xff01
288 class Sht(_OpenIntEnum
):
289 """ELF section types. Type of SHT_* values."""
304 SHT_PREINIT_ARRAY
= 16
306 SHT_SYMTAB_SHNDX
= 18
308 SHT_GNU_ATTRIBUTES
= 0x6ffffff5
309 SHT_GNU_HASH
= 0x6ffffff6
310 SHT_GNU_LIBLIST
= 0x6ffffff7
311 SHT_CHECKSUM
= 0x6ffffff8
312 SHT_SUNW_move
= 0x6ffffffa
313 SHT_SUNW_COMDAT
= 0x6ffffffb
314 SHT_SUNW_syminfo
= 0x6ffffffc
315 SHT_GNU_verdef
= 0x6ffffffd
316 SHT_GNU_verneed
= 0x6ffffffe
317 SHT_GNU_versym
= 0x6fffffff
319 class ShtALPHA(enum
.Enum
):
320 """Supplemental SHT_* constants for EM_ALPHA."""
321 SHT_ALPHA_DEBUG
= 0x70000001
322 SHT_ALPHA_REGINFO
= 0x70000002
324 class ShtARM(enum
.Enum
):
325 """Supplemental SHT_* constants for EM_ARM."""
326 SHT_ARM_EXIDX
= 0x70000001
327 SHT_ARM_PREEMPTMAP
= 0x70000002
328 SHT_ARM_ATTRIBUTES
= 0x70000003
330 class ShtCSKY(enum
.Enum
):
331 """Supplemental SHT_* constants for EM_CSKY."""
332 SHT_CSKY_ATTRIBUTES
= 0x70000001
334 class ShtIA_64(enum
.Enum
):
335 """Supplemental SHT_* constants for EM_IA_64."""
336 SHT_IA_64_EXT
= 0x70000000
337 SHT_IA_64_UNWIND
= 0x70000001
339 class ShtMIPS(enum
.Enum
):
340 """Supplemental SHT_* constants for EM_MIPS."""
341 SHT_MIPS_LIBLIST
= 0x70000000
342 SHT_MIPS_MSYM
= 0x70000001
343 SHT_MIPS_CONFLICT
= 0x70000002
344 SHT_MIPS_GPTAB
= 0x70000003
345 SHT_MIPS_UCODE
= 0x70000004
346 SHT_MIPS_DEBUG
= 0x70000005
347 SHT_MIPS_REGINFO
= 0x70000006
348 SHT_MIPS_PACKAGE
= 0x70000007
349 SHT_MIPS_PACKSYM
= 0x70000008
350 SHT_MIPS_RELD
= 0x70000009
351 SHT_MIPS_IFACE
= 0x7000000b
352 SHT_MIPS_CONTENT
= 0x7000000c
353 SHT_MIPS_OPTIONS
= 0x7000000d
354 SHT_MIPS_SHDR
= 0x70000010
355 SHT_MIPS_FDESC
= 0x70000011
356 SHT_MIPS_EXTSYM
= 0x70000012
357 SHT_MIPS_DENSE
= 0x70000013
358 SHT_MIPS_PDESC
= 0x70000014
359 SHT_MIPS_LOCSYM
= 0x70000015
360 SHT_MIPS_AUXSYM
= 0x70000016
361 SHT_MIPS_OPTSYM
= 0x70000017
362 SHT_MIPS_LOCSTR
= 0x70000018
363 SHT_MIPS_LINE
= 0x70000019
364 SHT_MIPS_RFDESC
= 0x7000001a
365 SHT_MIPS_DELTASYM
= 0x7000001b
366 SHT_MIPS_DELTAINST
= 0x7000001c
367 SHT_MIPS_DELTACLASS
= 0x7000001d
368 SHT_MIPS_DWARF
= 0x7000001e
369 SHT_MIPS_DELTADECL
= 0x7000001f
370 SHT_MIPS_SYMBOL_LIB
= 0x70000020
371 SHT_MIPS_EVENTS
= 0x70000021
372 SHT_MIPS_TRANSLATE
= 0x70000022
373 SHT_MIPS_PIXIE
= 0x70000023
374 SHT_MIPS_XLATE
= 0x70000024
375 SHT_MIPS_XLATE_DEBUG
= 0x70000025
376 SHT_MIPS_WHIRL
= 0x70000026
377 SHT_MIPS_EH_REGION
= 0x70000027
378 SHT_MIPS_XLATE_OLD
= 0x70000028
379 SHT_MIPS_PDR_EXCEPTION
= 0x70000029
380 SHT_MIPS_XHASH
= 0x7000002b
382 class ShtPARISC(enum
.Enum
):
383 """Supplemental SHT_* constants for EM_PARISC."""
384 SHT_PARISC_EXT
= 0x70000000
385 SHT_PARISC_UNWIND
= 0x70000001
386 SHT_PARISC_DOC
= 0x70000002
388 class ShtRISCV(enum
.Enum
):
389 """Supplemental SHT_* constants for EM_RISCV."""
390 SHT_RISCV_ATTRIBUTES
= 0x70000003
392 class Pf(enum
.IntFlag
):
393 """Program header flags. Type of Phdr.p_flags values."""
398 class PfARM(enum
.IntFlag
):
399 """Supplemental PF_* flags for EM_ARM."""
400 PF_ARM_SB
= 0x10000000
401 PF_ARM_PI
= 0x20000000
402 PF_ARM_ABS
= 0x40000000
404 class PfPARISC(enum
.IntFlag
):
405 """Supplemental PF_* flags for EM_PARISC."""
406 PF_HP_PAGE_SIZE
= 0x00100000
407 PF_HP_FAR_SHARED
= 0x00200000
408 PF_HP_NEAR_SHARED
= 0x00400000
409 PF_HP_CODE
= 0x01000000
410 PF_HP_MODIFY
= 0x02000000
411 PF_HP_LAZYSWAP
= 0x04000000
412 PF_HP_SBP
= 0x08000000
414 class PfIA_64(enum
.IntFlag
):
415 """Supplemental PF_* flags for EM_IA_64."""
416 PF_IA_64_NORECOV
= 0x80000000
418 class PfMIPS(enum
.IntFlag
):
419 """Supplemental PF_* flags for EM_MIPS."""
420 PF_MIPS_LOCAL
= 0x10000000
422 class Shf(enum
.IntFlag
):
423 """Section flags. Type of Shdr.sh_type values."""
426 SHF_EXECINSTR
= 1 << 2
429 SHF_INFO_LINK
= 1 << 6
430 SHF_LINK_ORDER
= 1 << 7
431 SHF_OS_NONCONFORMING
= 256
434 SHF_COMPRESSED
= 1 << 11
435 SHF_GNU_RETAIN
= 1 << 21
436 SHF_ORDERED
= 1 << 30
437 SHF_EXCLUDE
= 1 << 31
439 class ShfALPHA(enum
.IntFlag
):
440 """Supplemental SHF_* constants for EM_ALPHA."""
441 SHF_ALPHA_GPREL
= 0x10000000
443 class ShfARM(enum
.IntFlag
):
444 """Supplemental SHF_* constants for EM_ARM."""
445 SHF_ARM_ENTRYSECT
= 0x10000000
446 SHF_ARM_COMDEF
= 0x80000000
448 class ShfIA_64(enum
.IntFlag
):
449 """Supplemental SHF_* constants for EM_IA_64."""
450 SHF_IA_64_SHORT
= 0x10000000
451 SHF_IA_64_NORECOV
= 0x20000000
453 class ShfMIPS(enum
.IntFlag
):
454 """Supplemental SHF_* constants for EM_MIPS."""
455 SHF_MIPS_GPREL
= 0x10000000
456 SHF_MIPS_MERGE
= 0x20000000
457 SHF_MIPS_ADDR
= 0x40000000
458 SHF_MIPS_STRINGS
= 0x80000000
459 SHF_MIPS_NOSTRIP
= 0x08000000
460 SHF_MIPS_LOCAL
= 0x04000000
461 SHF_MIPS_NAMES
= 0x02000000
462 SHF_MIPS_NODUPE
= 0x01000000
464 class ShfPARISC(enum
.IntFlag
):
465 """Supplemental SHF_* constants for EM_PARISC."""
466 SHF_PARISC_SHORT
= 0x20000000
467 SHF_PARISC_HUGE
= 0x40000000
468 SHF_PARISC_SBP
= 0x80000000
470 class Stb(_OpenIntEnum
):
471 """ELF symbol binding type."""
476 STB_MIPS_SPLIT_COMMON
= 13
478 class Stt(_OpenIntEnum
):
479 """ELF symbol type."""
489 class SttARM(enum
.Enum
):
490 """Supplemental STT_* constants for EM_ARM."""
494 class SttPARISC(enum
.Enum
):
495 """Supplemental STT_* constants for EM_PARISC."""
498 STT_PARISC_MILLICODE
= 13
500 class SttSPARC(enum
.Enum
):
501 """Supplemental STT_* constants for EM_SPARC."""
502 STT_SPARC_REGISTER
= 13
504 class SttX86_64(enum
.Enum
):
505 """Supplemental STT_* constants for EM_X86_64."""
506 SHT_X86_64_UNWIND
= 0x70000001
508 class Pt(_OpenIntEnum
):
509 """ELF program header types. Type of Phdr.p_type."""
519 PT_GNU_EH_FRAME
= 0x6474e550
520 PT_GNU_STACK
= 0x6474e551
521 PT_GNU_RELRO
= 0x6474e552
522 PT_GNU_PROPERTY
= 0x6474e553
523 PT_SUNWBSS
= 0x6ffffffa
524 PT_SUNWSTACK
= 0x6ffffffb
526 class PtAARCH64(enum
.Enum
):
527 """Supplemental PT_* constants for EM_AARCH64."""
528 PT_AARCH64_MEMTAG_MTE
= 0x70000002
530 class PtARM(enum
.Enum
):
531 """Supplemental PT_* constants for EM_ARM."""
532 PT_ARM_EXIDX
= 0x70000001
534 class PtIA_64(enum
.Enum
):
535 """Supplemental PT_* constants for EM_IA_64."""
536 PT_IA_64_HP_OPT_ANOT
= 0x60000012
537 PT_IA_64_HP_HSL_ANOT
= 0x60000013
538 PT_IA_64_HP_STACK
= 0x60000014
539 PT_IA_64_ARCHEXT
= 0x70000000
540 PT_IA_64_UNWIND
= 0x70000001
542 class PtMIPS(enum
.Enum
):
543 """Supplemental PT_* constants for EM_MIPS."""
544 PT_MIPS_REGINFO
= 0x70000000
545 PT_MIPS_RTPROC
= 0x70000001
546 PT_MIPS_OPTIONS
= 0x70000002
547 PT_MIPS_ABIFLAGS
= 0x70000003
549 class PtPARISC(enum
.Enum
):
550 """Supplemental PT_* constants for EM_PARISC."""
551 PT_HP_TLS
= 0x60000000
552 PT_HP_CORE_NONE
= 0x60000001
553 PT_HP_CORE_VERSION
= 0x60000002
554 PT_HP_CORE_KERNEL
= 0x60000003
555 PT_HP_CORE_COMM
= 0x60000004
556 PT_HP_CORE_PROC
= 0x60000005
557 PT_HP_CORE_LOADABLE
= 0x60000006
558 PT_HP_CORE_STACK
= 0x60000007
559 PT_HP_CORE_SHM
= 0x60000008
560 PT_HP_CORE_MMF
= 0x60000009
561 PT_HP_PARALLEL
= 0x60000010
562 PT_HP_FASTBIND
= 0x60000011
563 PT_HP_OPT_ANNOT
= 0x60000012
564 PT_HP_HSL_ANNOT
= 0x60000013
565 PT_HP_STACK
= 0x60000014
566 PT_PARISC_ARCHEXT
= 0x70000000
567 PT_PARISC_UNWIND
= 0x70000001
569 class PtRISCV(enum
.Enum
):
570 """Supplemental PT_* constants for EM_RISCV."""
571 PT_RISCV_ATTRIBUTES
= 0x70000003
573 class Dt(_OpenIntEnum
):
574 """ELF dynamic segment tags. Type of Dyn.d_val."""
606 DT_PREINIT_ARRAY
= 32
607 DT_PREINIT_ARRAYSZ
= 33
612 DT_GNU_PRELINKED
= 0x6ffffdf5
613 DT_GNU_CONFLICTSZ
= 0x6ffffdf6
614 DT_GNU_LIBLISTSZ
= 0x6ffffdf7
615 DT_CHECKSUM
= 0x6ffffdf8
616 DT_PLTPADSZ
= 0x6ffffdf9
617 DT_MOVEENT
= 0x6ffffdfa
618 DT_MOVESZ
= 0x6ffffdfb
619 DT_FEATURE_1
= 0x6ffffdfc
620 DT_POSFLAG_1
= 0x6ffffdfd
621 DT_SYMINSZ
= 0x6ffffdfe
622 DT_SYMINENT
= 0x6ffffdff
623 DT_GNU_HASH
= 0x6ffffef5
624 DT_TLSDESC_PLT
= 0x6ffffef6
625 DT_TLSDESC_GOT
= 0x6ffffef7
626 DT_GNU_CONFLICT
= 0x6ffffef8
627 DT_GNU_LIBLIST
= 0x6ffffef9
628 DT_CONFIG
= 0x6ffffefa
629 DT_DEPAUDIT
= 0x6ffffefb
630 DT_AUDIT
= 0x6ffffefc
631 DT_PLTPAD
= 0x6ffffefd
632 DT_MOVETAB
= 0x6ffffefe
633 DT_SYMINFO
= 0x6ffffeff
634 DT_VERSYM
= 0x6ffffff0
635 DT_RELACOUNT
= 0x6ffffff9
636 DT_RELCOUNT
= 0x6ffffffa
637 DT_FLAGS_1
= 0x6ffffffb
638 DT_VERDEF
= 0x6ffffffc
639 DT_VERDEFNUM
= 0x6ffffffd
640 DT_VERNEED
= 0x6ffffffe
641 DT_VERNEEDNUM
= 0x6fffffff
642 DT_AUXILIARY
= 0x7ffffffd
643 DT_FILTER
= 0x7fffffff
645 class DtAARCH64(enum
.Enum
):
646 """Supplemental DT_* constants for EM_AARCH64."""
647 DT_AARCH64_BTI_PLT
= 0x70000001
648 DT_AARCH64_PAC_PLT
= 0x70000003
649 DT_AARCH64_VARIANT_PCS
= 0x70000005
651 class DtALPHA(enum
.Enum
):
652 """Supplemental DT_* constants for EM_ALPHA."""
653 DT_ALPHA_PLTRO
= 0x70000000
655 class DtALTERA_NIOS2(enum
.Enum
):
656 """Supplemental DT_* constants for EM_ALTERA_NIOS2."""
657 DT_NIOS2_GP
= 0x70000002
659 class DtIA_64(enum
.Enum
):
660 """Supplemental DT_* constants for EM_IA_64."""
661 DT_IA_64_PLT_RESERVE
= 0x70000000
663 class DtMIPS(enum
.Enum
):
664 """Supplemental DT_* constants for EM_MIPS."""
665 DT_MIPS_RLD_VERSION
= 0x70000001
666 DT_MIPS_TIME_STAMP
= 0x70000002
667 DT_MIPS_ICHECKSUM
= 0x70000003
668 DT_MIPS_IVERSION
= 0x70000004
669 DT_MIPS_FLAGS
= 0x70000005
670 DT_MIPS_BASE_ADDRESS
= 0x70000006
671 DT_MIPS_MSYM
= 0x70000007
672 DT_MIPS_CONFLICT
= 0x70000008
673 DT_MIPS_LIBLIST
= 0x70000009
674 DT_MIPS_LOCAL_GOTNO
= 0x7000000a
675 DT_MIPS_CONFLICTNO
= 0x7000000b
676 DT_MIPS_LIBLISTNO
= 0x70000010
677 DT_MIPS_SYMTABNO
= 0x70000011
678 DT_MIPS_UNREFEXTNO
= 0x70000012
679 DT_MIPS_GOTSYM
= 0x70000013
680 DT_MIPS_HIPAGENO
= 0x70000014
681 DT_MIPS_RLD_MAP
= 0x70000016
682 DT_MIPS_DELTA_CLASS
= 0x70000017
683 DT_MIPS_DELTA_CLASS_NO
= 0x70000018
684 DT_MIPS_DELTA_INSTANCE
= 0x70000019
685 DT_MIPS_DELTA_INSTANCE_NO
= 0x7000001a
686 DT_MIPS_DELTA_RELOC
= 0x7000001b
687 DT_MIPS_DELTA_RELOC_NO
= 0x7000001c
688 DT_MIPS_DELTA_SYM
= 0x7000001d
689 DT_MIPS_DELTA_SYM_NO
= 0x7000001e
690 DT_MIPS_DELTA_CLASSSYM
= 0x70000020
691 DT_MIPS_DELTA_CLASSSYM_NO
= 0x70000021
692 DT_MIPS_CXX_FLAGS
= 0x70000022
693 DT_MIPS_PIXIE_INIT
= 0x70000023
694 DT_MIPS_SYMBOL_LIB
= 0x70000024
695 DT_MIPS_LOCALPAGE_GOTIDX
= 0x70000025
696 DT_MIPS_LOCAL_GOTIDX
= 0x70000026
697 DT_MIPS_HIDDEN_GOTIDX
= 0x70000027
698 DT_MIPS_PROTECTED_GOTIDX
= 0x70000028
699 DT_MIPS_OPTIONS
= 0x70000029
700 DT_MIPS_INTERFACE
= 0x7000002a
701 DT_MIPS_DYNSTR_ALIGN
= 0x7000002b
702 DT_MIPS_INTERFACE_SIZE
= 0x7000002c
703 DT_MIPS_RLD_TEXT_RESOLVE_ADDR
= 0x7000002d
704 DT_MIPS_PERF_SUFFIX
= 0x7000002e
705 DT_MIPS_COMPACT_SIZE
= 0x7000002f
706 DT_MIPS_GP_VALUE
= 0x70000030
707 DT_MIPS_AUX_DYNAMIC
= 0x70000031
708 DT_MIPS_PLTGOT
= 0x70000032
709 DT_MIPS_RWPLT
= 0x70000034
710 DT_MIPS_RLD_MAP_REL
= 0x70000035
711 DT_MIPS_XHASH
= 0x70000036
713 class DtPPC(enum
.Enum
):
714 """Supplemental DT_* constants for EM_PPC."""
715 DT_PPC_GOT
= 0x70000000
716 DT_PPC_OPT
= 0x70000001
718 class DtPPC64(enum
.Enum
):
719 """Supplemental DT_* constants for EM_PPC64."""
720 DT_PPC64_GLINK
= 0x70000000
721 DT_PPC64_OPD
= 0x70000001
722 DT_PPC64_OPDSZ
= 0x70000002
723 DT_PPC64_OPT
= 0x70000003
725 class DtRISCV(enum
.Enum
):
726 """Supplemental DT_* constants for EM_RISCV."""
727 DT_RISCV_VARIANT_CC
= 0x70000001
729 class DtSPARC(enum
.Enum
):
730 """Supplemental DT_* constants for EM_SPARC."""
731 DT_SPARC_REGISTER
= 0x70000001
734 """ELF symbol binding and type. Type of the Sym.st_info field."""
735 def __init__(self
, arg0
, arg1
=None):
736 if isinstance(arg0
, int) and arg1
is None:
737 self
.bind
= Stb(arg0
>> 4)
738 self
.type = Stt(arg0
& 15)
740 self
.bind
= Stb(arg0
)
741 self
.type = Stt(arg1
)
744 """Returns the raw value for the bind/type combination."""
745 return (self
.bind
.value() << 4) |
(self
.type.value())
747 # Type in an ELF file. Used for deserialization.
748 _Layout
= collections
.namedtuple('_Layout', 'unpack size')
750 def _define_layouts(baseclass
: type, layout32
: str, layout64
: str,
751 types
=None, fields32
=None):
752 """Assign variants dict to baseclass.
754 The variants dict is indexed by (ElfClass, ElfData) pairs, and its
755 values are _Layout instances.
758 struct32
= struct
.Struct(layout32
)
759 struct64
= struct
.Struct(layout64
)
761 # Check that the struct formats yield the right number of components.
762 for s
in (struct32
, struct64
):
763 example
= s
.unpack(b
' ' * s
.size
)
764 if len(example
) != len(baseclass
._fields
):
765 raise ValueError('{!r} yields wrong field count: {} != {}'.format(
766 s
.format
, len(example
), len(baseclass
._fields
)))
768 # Check that field names in types are correct.
772 if n
not in baseclass
._fields
:
773 raise ValueError('{} does not have field {!r}'.format(
774 baseclass
.__name
__, n
))
776 if fields32
is not None \
777 and set(fields32
) != set(baseclass
._fields
):
778 raise ValueError('{!r} is not a permutation of the fields {!r}'.format(
779 fields32
, baseclass
._fields
))
781 def unique_name(name
, used_names
= (set((baseclass
.__name
__,))
782 |
set(baseclass
._fields
)
784 for n
in (types
or {}).values()})):
785 """Find a name that is not used for a class or field name."""
788 while candidate
in used_names
:
790 candidate
= '{}{}'.format(name
, n
)
791 used_names
.add(candidate
)
794 blob_name
= unique_name('blob')
795 struct_unpack_name
= unique_name('struct_unpack')
796 comps_name
= unique_name('comps')
799 for (bits
, elfclass
, layout
, fields
) in (
800 (32, ElfClass
.ELFCLASS32
, layout32
, fields32
),
801 (64, ElfClass
.ELFCLASS64
, layout64
, None),
803 for (elfdata
, structprefix
, funcsuffix
) in (
804 (ElfData
.ELFDATA2LSB
, '<', 'LE'),
805 (ElfData
.ELFDATA2MSB
, '>', 'BE'),
808 baseclass
.__name
__: baseclass
,
809 struct_unpack_name
: struct
.unpack
,
812 # Add the type converters.
814 for cls
in types
.values():
815 env
[cls
.__name
__] = cls
818 ('unpack_', baseclass
.__name
__, str(bits
), funcsuffix
))
821 def {funcname}({blob_name}):
822 '''.format(funcname
=funcname
, blob_name
=blob_name
)
825 unpack_call
= '{}({!r}, {})'.format(
826 struct_unpack_name
, structprefix
+ layout
, blob_name
)
827 field_names
= ', '.join(baseclass
._fields
)
828 if types
is None and fields
is None:
829 code
+= '{}return {}({})\n'.format(
830 indent
, baseclass
.__name
__, unpack_call
)
832 # Destructuring tuple assignment.
834 code
+= '{}{} = {}\n'.format(
835 indent
, field_names
, unpack_call
)
837 # Use custom field order.
838 code
+= '{}{} = {}\n'.format(
839 indent
, ', '.join(fields
), unpack_call
)
841 # Perform the type conversions.
842 for n
in baseclass
._fields
:
844 code
+= '{}{} = {}({})\n'.format(
845 indent
, n
, types
[n
].__name
__, n
)
846 # Create the named tuple.
847 code
+= '{}return {}({})\n'.format(
848 indent
, baseclass
.__name
__, field_names
)
851 layouts
[(elfclass
, elfdata
)] = _Layout(
852 env
[funcname
], struct
.calcsize(layout
))
853 baseclass
.layouts
= layouts
856 # Corresponds to EI_* indices into Elf*_Ehdr.e_indent.
857 class Ident(collections
.namedtuple('Ident',
858 'ei_mag ei_class ei_data ei_version ei_osabi ei_abiversion ei_pad')):
860 def __new__(cls
, *args
):
861 """Construct an object from a blob or its constituent fields."""
863 return cls
.unpack(args
[0])
864 return cls
.__base
__.__new
__(cls
, *args
)
867 def unpack(blob
: memoryview
) -> 'Ident':
868 """Parse raws data into a tuple."""
869 ei_mag
, ei_class
, ei_data
, ei_version
, ei_osabi
, ei_abiversion
, \
870 ei_pad
= struct
.unpack('4s5B7s', blob
)
871 return Ident(ei_mag
, ElfClass(ei_class
), ElfData(ei_data
),
872 ei_version
, ei_osabi
, ei_abiversion
, ei_pad
)
875 # Corresponds to Elf32_Ehdr and Elf64_Ehdr.
876 Ehdr
= collections
.namedtuple('Ehdr',
877 'e_ident e_type e_machine e_version e_entry e_phoff e_shoff e_flags'
878 + ' e_ehsize e_phentsize e_phnum e_shentsize e_shnum e_shstrndx')
879 _define_layouts(Ehdr
,
880 layout32
='16s2H5I6H',
881 layout64
='16s2HI3QI6H',
882 types
=dict(e_ident
=Ident
,
887 # Corresponds to Elf32_Phdr and Elf64_Pdhr. Order follows the latter.
888 Phdr
= collections
.namedtuple('Phdr',
889 'p_type p_flags p_offset p_vaddr p_paddr p_filesz p_memsz p_align')
890 _define_layouts(Phdr
,
892 fields32
=('p_type', 'p_offset', 'p_vaddr', 'p_paddr',
893 'p_filesz', 'p_memsz', 'p_flags', 'p_align'),
895 types
=dict(p_type
=Pt
, p_flags
=Pf
))
898 # Corresponds to Elf32_Shdr and Elf64_Shdr.
899 class Shdr(collections
.namedtuple('Shdr',
900 'sh_name sh_type sh_flags sh_addr sh_offset sh_size sh_link sh_info'
901 + ' sh_addralign sh_entsize')):
902 def resolve(self
, strtab
: 'StringTable') -> 'Shdr':
903 """Resolve sh_name using a string table."""
904 return self
.__class
__(strtab
.get(self
[0]), *self
[1:])
905 _define_layouts(Shdr
,
908 types
=dict(sh_type
=Sht
,
912 # Corresponds to Elf32_Dyn and Elf64_Dyn. The nesting through the
913 # d_un union is skipped, and d_ptr is missing (its representation in
914 # Python would be identical to d_val).
915 Dyn
= collections
.namedtuple('Dyn', 'd_tag d_val')
919 types
=dict(d_tag
=Dt
))
921 # Corresponds to Elf32_Sym and Elf64_Sym.
922 class Sym(collections
.namedtuple('Sym',
923 'st_name st_info st_other st_shndx st_value st_size')):
924 def resolve(self
, strtab
: 'StringTable') -> 'Sym':
925 """Resolve st_name using a string table."""
926 return self
.__class
__(strtab
.get(self
[0]), *self
[1:])
930 fields32
=('st_name', 'st_value', 'st_size', 'st_info',
931 'st_other', 'st_shndx'),
932 types
=dict(st_shndx
=Shn
,
935 # Corresponds to Elf32_Rel and Elf64_Rel.
936 Rel
= collections
.namedtuple('Rel', 'r_offset r_info')
941 # Corresponds to Elf32_Rel and Elf64_Rel.
942 Rela
= collections
.namedtuple('Rela', 'r_offset r_info r_addend')
943 _define_layouts(Rela
,
948 """ELF string table."""
949 def __init__(self
, blob
):
950 """Create a new string table backed by the data in the blob.
952 blob: a memoryview-like object
957 def get(self
, index
) -> bytes
:
958 """Returns the null-terminated byte string at the index."""
962 if blob
[endindex
] == 0:
963 return bytes(blob
[index
:endindex
])
967 """ELF image parser."""
968 def __init__(self
, image
):
969 """Create an ELF image from binary image data.
971 image: a memoryview-like object that supports efficient range
976 ident
= self
.read(Ident
, 0)
977 classdata
= (ident
.ei_class
, ident
.ei_data
)
978 # Set self.Ehdr etc. to the subtypes with the right parsers.
979 for typ
in (Ehdr
, Phdr
, Shdr
, Dyn
, Sym
, Rel
, Rela
):
980 setattr(self
, typ
.__name
__, typ
.layouts
.get(classdata
, None))
982 if self
.Ehdr
is not None:
983 self
.ehdr
= self
.read(self
.Ehdr
, 0)
984 self
._shdr
_num
= self
._compute
_shdr
_num
()
992 if self
._shdr
_num
> 0:
993 self
._shdr
_strtab
= self
._find
_shdr
_strtab
()
995 self
._shdr
_strtab
= None
998 def readfile(path
: str) -> 'Image':
999 """Reads the ELF file at the specified path."""
1000 with
open(path
, 'rb') as inp
:
1001 return Image(memoryview(inp
.read()))
1003 def _compute_shdr_num(self
) -> int:
1004 """Computes the actual number of section headers."""
1005 shnum
= self
.ehdr
.e_shnum
1007 if self
.ehdr
.e_shoff
== 0 or self
.ehdr
.e_shentsize
== 0:
1008 # No section headers.
1010 # Otherwise the extension mechanism is used (which may be
1011 # needed because e_shnum is just 16 bits).
1012 return self
.read(self
.Shdr
, self
.ehdr
.e_shoff
).sh_size
1015 def _find_shdr_strtab(self
) -> StringTable
:
1016 """Finds the section header string table (maybe via extensions)."""
1017 shstrndx
= self
.ehdr
.e_shstrndx
1018 if shstrndx
== Shn
.SHN_XINDEX
:
1019 shstrndx
= self
.read(self
.Shdr
, self
.ehdr
.e_shoff
).sh_link
1020 return self
._find
_stringtab
(shstrndx
)
1022 def read(self
, typ
: type, offset
:int ):
1023 """Reads an object at a specific offset.
1025 The type must have been enhanced using _define_variants.
1028 return typ
.unpack(self
.image
[offset
: offset
+ typ
.size
])
1030 def phdrs(self
) -> Phdr
:
1031 """Generator iterating over the program headers."""
1032 if self
.ehdr
is None:
1034 size
= self
.ehdr
.e_phentsize
1035 if size
!= self
.Phdr
.size
:
1036 raise ValueError('Unexpected Phdr size in ELF header: {} != {}'
1037 .format(size
, self
.Phdr
.size
))
1039 offset
= self
.ehdr
.e_phoff
1040 for _
in range(self
.ehdr
.e_phnum
):
1041 yield self
.read(self
.Phdr
, offset
)
1044 def shdrs(self
, resolve
: bool=True) -> Shdr
:
1045 """Generator iterating over the section headers.
1047 If resolve, section names are automatically translated
1048 using the section header string table.
1051 if self
._shdr
_num
== 0:
1054 size
= self
.ehdr
.e_shentsize
1055 if size
!= self
.Shdr
.size
:
1056 raise ValueError('Unexpected Shdr size in ELF header: {} != {}'
1057 .format(size
, self
.Shdr
.size
))
1059 offset
= self
.ehdr
.e_shoff
1060 for _
in range(self
._shdr
_num
):
1061 shdr
= self
.read(self
.Shdr
, offset
)
1063 shdr
= shdr
.resolve(self
._shdr
_strtab
)
1067 def dynamic(self
) -> Dyn
:
1068 """Generator iterating over the dynamic segment."""
1069 for phdr
in self
.phdrs():
1070 if phdr
.p_type
== Pt
.PT_DYNAMIC
:
1071 # Pick the first dynamic segment, like the loader.
1072 if phdr
.p_filesz
== 0:
1073 # Probably separated debuginfo.
1075 offset
= phdr
.p_offset
1076 end
= offset
+ phdr
.p_memsz
1077 size
= self
.Dyn
.size
1079 next_offset
= offset
+ size
1080 if next_offset
> end
:
1082 'Dynamic segment size {} is not a multiple of Dyn size {}'.format(
1083 phdr
.p_memsz
, size
))
1084 yield self
.read(self
.Dyn
, offset
)
1085 if next_offset
== end
:
1087 offset
= next_offset
1089 def syms(self
, shdr
: Shdr
, resolve
: bool=True) -> Sym
:
1090 """A generator iterating over a symbol table.
1092 If resolve, symbol names are automatically translated using
1093 the string table for the symbol table.
1096 assert shdr
.sh_type
== Sht
.SHT_SYMTAB
1097 size
= shdr
.sh_entsize
1098 if size
!= self
.Sym
.size
:
1099 raise ValueError('Invalid symbol table entry size {}'.format(size
))
1100 offset
= shdr
.sh_offset
1101 end
= shdr
.sh_offset
+ shdr
.sh_size
1103 strtab
= self
._find
_stringtab
(shdr
.sh_link
)
1105 sym
= self
.read(self
.Sym
, offset
)
1107 sym
= sym
.resolve(strtab
)
1111 raise ValueError('Symbol table is not a multiple of entry size')
1113 def lookup_string(self
, strtab_index
: int, strtab_offset
: int) -> bytes
:
1114 """Looks up a string in a string table identified by its link index."""
1116 strtab
= self
._stringtab
[strtab_index
]
1118 strtab
= self
._find
_stringtab
(strtab_index
)
1119 return strtab
.get(strtab_offset
)
1121 def find_section(self
, shndx
: Shn
) -> Shdr
:
1122 """Returns the section header for the indexed section.
1124 The section name is not resolved.
1127 return self
._section
[shndx
]
1131 raise ValueError('Reserved section index {}'.format(shndx
))
1133 if idx
< 0 or idx
> self
._shdr
_num
:
1134 raise ValueError('Section index {} out of range [0, {})'.format(
1135 idx
, self
._shdr
_num
))
1137 self
.Shdr
, self
.ehdr
.e_shoff
+ idx
* self
.Shdr
.size
)
1138 self
._section
[shndx
] = shdr
1141 def _find_stringtab(self
, sh_link
: int) -> StringTable
:
1142 if sh_link
in self
._stringtab
:
1143 return self
._stringtab
1144 if sh_link
< 0 or sh_link
>= self
._shdr
_num
:
1145 raise ValueError('Section index {} out of range [0, {})'.format(
1146 sh_link
, self
._shdr
_num
))
1148 self
.Shdr
, self
.ehdr
.e_shoff
+ sh_link
* self
.Shdr
.size
)
1149 if shdr
.sh_type
!= Sht
.SHT_STRTAB
:
1151 'Section {} is not a string table: {}'.format(
1152 sh_link
, shdr
.sh_type
))
1153 strtab
= StringTable(
1154 self
.image
[shdr
.sh_offset
:shdr
.sh_offset
+ shdr
.sh_size
])
1155 # This could retrain essentially arbitrary amounts of data,
1156 # but caching string tables seems important for performance.
1157 self
._stringtab
[sh_link
] = strtab
1161 __all__
= [name
for name
in dir() if name
[0].isupper()]