#------------------------------------------------------------------------------- # elftools: elf/notes.py # # ELF notes # # Eli Bendersky (eliben@gmail.com) # This code is in the public domain #------------------------------------------------------------------------------- from __future__ import annotations from typing import TYPE_CHECKING from ..common.utils import struct_parse, roundup, bytes2str from ..construct import CString if TYPE_CHECKING: from collections.abc import Iterator from ..construct.lib.container import Container from .elffile import ELFFile def iter_notes(elffile: ELFFile, offset: int, size: int) -> Iterator[Container]: """ Yield all the notes in a section or segment. """ end = offset + size nhdr_size = elffile.structs.Elf_Nhdr.sizeof() # Note: a note's name and data are 4-byte aligned, but it's possible there's # additional padding at the end to satisfy the alignment requirement of the segment. while offset + nhdr_size < end: note: Container = struct_parse( elffile.structs.Elf_Nhdr, elffile.stream, stream_pos=offset) note['n_offset'] = offset offset += nhdr_size elffile.stream.seek(offset) if note['n_namesz']: # n_namesz is 4-byte aligned. disk_namesz: int = roundup(note['n_namesz'], 2) note['n_name'] = bytes2str( CString('').parse(elffile.stream.read(disk_namesz))) offset += disk_namesz else: note['n_name'] = None desc_data: bytes = elffile.stream.read(note['n_descsz']) note['n_descdata'] = desc_data if note['n_type'] == 'NT_GNU_ABI_TAG' and note['n_name'] == 'GNU': note['n_desc'] = struct_parse(elffile.structs.Elf_abi, elffile.stream, offset) elif note['n_type'] == 'NT_GNU_BUILD_ID' and note['n_name'] == 'GNU': note['n_desc'] = bytes(desc_data).hex() elif note['n_type'] == 'NT_GNU_GOLD_VERSION' and note['n_name'] == 'GNU': note['n_desc'] = bytes2str(desc_data) elif note['n_type'] == 'NT_PRPSINFO': note['n_desc'] = struct_parse(elffile.structs.Elf_Prpsinfo, elffile.stream, offset) elif note['n_type'] == 'NT_FILE': note['n_desc'] = struct_parse(elffile.structs.Elf_Nt_File, elffile.stream, offset) elif note['n_type'] == 'NT_GNU_PROPERTY_TYPE_0' and note['n_name'] == 'GNU': off = offset props: list[Container] = [] # n_descsz contains the size of the note "descriptor" (the data payload), # excluding padding. See "Note Section" in https://refspecs.linuxfoundation.org/elf/elf.pdf current_note_end: int = offset + note['n_descsz'] while off < current_note_end: p: Container = struct_parse(elffile.structs.Elf_Prop, elffile.stream, off) off += roundup(p.pr_datasz + 8, 2 if elffile.elfclass == 32 else 3) props.append(p) note['n_desc'] = props else: note['n_desc'] = desc_data offset += roundup(note['n_descsz'], 2) note['n_size'] = offset - note['n_offset'] yield note