stream.seek(saved_pos)
+def roundup(num, bits):
+ """ Round up a number to nearest multiple of 2^bits. The result is a number
+ where the least significant bits passed in bits are 0.
+ """
+ return (num - 1 | (1 << bits) - 1) + 1
+
#------------------------- PRIVATE -------------------------
def _assert_with_exception(cond, msg, exception_type):
if not cond:
raise exception_type(msg)
-
VER_FLAGS.VER_FLG_BASE,
VER_FLAGS.VER_FLG_INFO) if x & flag)
+def describe_note(x):
+ n_desc = x['n_desc']
+ desc = ''
+ if x['n_type'] == 'NT_GNU_ABI_TAG':
+ desc = '\n OS: %s, ABI: %d.%d.%d' % (
+ _DESCR_NOTE_ABI_TAG_OS.get(n_desc['abi_os'], _unknown),
+ n_desc['abi_major'], n_desc['abi_minor'], n_desc['abi_tiny'])
+ elif x['n_type'] == 'NT_GNU_BUILD_ID':
+ desc = '\n Build ID: %s' % (n_desc)
+
+ note_type = (x['n_type'] if isinstance(x['n_type'], str)
+ else 'Unknown note type:')
+ note_type_desc = ('0x%.8x' % x['n_type'] if isinstance(x['n_type'], int) else
+ _DESCR_NOTE_N_TYPE.get(x['n_type'], _unknown))
+ return '%s (%s)%s' % (note_type, note_type_desc, desc)
+
#-------------------------------------------------------------------------------
_unknown = '<unknown>'
VER_FLAGS.VER_FLG_INFO: 'INFO',
}
+# PT_NOTE section types
+_DESCR_NOTE_N_TYPE = dict(
+ NT_GNU_ABI_TAG='ABI version tag',
+ NT_GNU_HWCAP='DSO-supplied software HWCAP info',
+ NT_GNU_BUILD_ID='unique build ID bitstring',
+ NT_GNU_GOLD_VERSION='gold version',
+)
+
+# Values in GNU .note.ABI-tag notes (n_type=='NT_GNU_ABI_TAG')
+_DESCR_NOTE_ABI_TAG_OS = dict(
+ ELF_NOTE_OS_LINUX='Linux',
+ ELF_NOTE_OS_GNU='GNU',
+ ELF_NOTE_OS_SOLARIS2='Solaris 2',
+ ELF_NOTE_OS_FREEBSD='FreeBSD',
+ ELF_NOTE_OS_NETBSD='NetBSD',
+ ELF_NOTE_OS_SYLLABLE='Syllable',
+)
+
_DESCR_RELOC_TYPE_i386 = dict(
(v, k) for k, v in iteritems(ENUM_RELOC_TYPE_i386))
from .gnuversions import (
GNUVerNeedSection, GNUVerDefSection,
GNUVerSymSection)
-from .segments import Segment, InterpSegment
+from .segments import Segment, InterpSegment, NoteSegment
from ..dwarf.dwarfinfo import DWARFInfo, DebugSectionDescriptor, DwarfConfig
return InterpSegment(segment_header, self.stream)
elif segtype == 'PT_DYNAMIC':
return DynamicSegment(segment_header, self.stream, self)
+ elif segtype == 'PT_NOTE':
+ return NoteSegment(segment_header, self.stream, self)
else:
return Segment(segment_header, self.stream)
name=section.name,
global_offset=section['sh_offset'],
size=section['sh_size'])
-
-
_default_=Pass,
)
+# PT_NOTE section types
+ENUM_NOTE_N_TYPE = dict(
+ NT_GNU_ABI_TAG=1,
+ NT_GNU_HWCAP=2,
+ NT_GNU_BUILD_ID=3,
+ NT_GNU_GOLD_VERSION=4,
+ _default_=Pass,
+)
+
+# Values in GNU .note.ABI-tag notes (n_type=='NT_GNU_ABI_TAG')
+ENUM_NOTE_ABI_TAG_OS = dict(
+ ELF_NOTE_OS_LINUX=0,
+ ELF_NOTE_OS_GNU=1,
+ ELF_NOTE_OS_SOLARIS2=2,
+ ELF_NOTE_OS_FREEBSD=3,
+ ELF_NOTE_OS_NETBSD=4,
+ ELF_NOTE_OS_SYLLABLE=5,
+ _default_=Pass,
+)
+
ENUM_RELOC_TYPE_ARM = dict(
R_ARM_NONE=0,
R_ARM_PC24=1,
# This code is in the public domain
#-------------------------------------------------------------------------------
from ..construct import CString
-from ..common.utils import struct_parse
+from ..common.utils import roundup, struct_parse
+from ..common.py3compat import bytes2str
from .constants import SH_FLAGS
stream_pos=path_offset)
+class NoteSegment(Segment):
+ """ NOTE segment. Knows how to parse notes.
+ """
+ def __init__(self, header, stream, elffile):
+ super(NoteSegment, self).__init__(header, stream)
+ self._elfstructs = elffile.structs
+
+ def iter_notes(self):
+ """ Iterates the list of notes in the segment.
+ """
+ offset = self['p_offset']
+ end = self['p_offset'] + self['p_filesz']
+ while offset < end:
+ note = struct_parse(
+ self._elfstructs.Elf_Nhdr,
+ self.stream,
+ stream_pos=offset)
+ note['n_offset'] = offset
+ offset += self._elfstructs.Elf_Nhdr.sizeof()
+ self.stream.seek(offset)
+ # n_namesz is 4-byte aligned.
+ disk_namesz = roundup(note['n_namesz'], 2)
+ note['n_name'] = bytes2str(
+ CString('').parse(self.stream.read(disk_namesz)))
+ offset += disk_namesz
+
+ desc_data = bytes2str(self.stream.read(note['n_descsz']))
+ if note['n_type'] == 'NT_GNU_ABI_TAG':
+ note['n_desc'] = struct_parse(self._elfstructs.Elf_Nhdr_abi,
+ self.stream,
+ offset)
+ elif note['n_type'] == 'NT_GNU_BUILD_ID':
+ note['n_desc'] = ''.join('%.2x' % ord(b) for b in desc_data)
+ else:
+ note['n_desc'] = desc_data
+ offset += roundup(note['n_descsz'], 2)
+ note['n_size'] = offset - note['n_offset']
+ yield note
self._create_gnu_verneed()
self._create_gnu_verdef()
self._create_gnu_versym()
+ self._create_note()
def _create_ehdr(self):
self.Elf_Ehdr = Struct('Elf_Ehdr',
self.Elf_Versym = Struct('Elf_Versym',
Enum(self.Elf_half('ndx'), **ENUM_VERSYM),
)
+
+ def _create_note(self):
+ # Structure of "PT_NOTE" section
+ self.Elf_Nhdr = Struct('Elf_Nhdr',
+ self.Elf_word('n_namesz'),
+ self.Elf_word('n_descsz'),
+ Enum(self.Elf_word('n_type'), **ENUM_NOTE_N_TYPE),
+ )
+ self.Elf_Nhdr_abi = Struct('Elf_Nhdr_abi',
+ Enum(self.Elf_word('abi_os'), **ENUM_NOTE_ABI_TAG_OS),
+ self.Elf_word('abi_major'),
+ self.Elf_word('abi_minor'),
+ self.Elf_word('abi_tiny'),
+ )
from elftools.elf.elffile import ELFFile
from elftools.elf.dynamic import DynamicSection, DynamicSegment
from elftools.elf.enums import ENUM_D_TAG
-from elftools.elf.segments import InterpSegment
+from elftools.elf.segments import InterpSegment, NoteSegment
from elftools.elf.sections import SymbolTableSection
from elftools.elf.gnuversions import (
GNUVerSymSection, GNUVerDefSection,
describe_sh_type, describe_sh_flags,
describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
- describe_ver_flags,
+ describe_ver_flags, describe_note
)
from elftools.elf.constants import E_FLAGS
from elftools.dwarf.dwarfinfo import DWARFInfo
if self.elffile.num_segments():
self._emitline("\nThere is no dynamic section in this file.")
+ def display_notes(self):
+ """ Display the notes contained in the file
+ """
+ for segment in self.elffile.iter_segments():
+ if isinstance(segment, NoteSegment):
+ for note in segment.iter_notes():
+ self._emitline(
+ "\nDisplaying notes found at file offset "
+ "%s with length %s:" % (
+ self._format_hex(note['n_offset'], fieldsize=8),
+ self._format_hex(note['n_size'], fieldsize=8)))
+ self._emitline(' Owner Data size Description')
+ self._emitline(' %s%s %s\t%s' % (
+ note['n_name'], ' ' * (20 - len(note['n_name'])),
+ self._format_hex(note['n_descsz'], fieldsize=8),
+ describe_note(note)))
+
def display_relocations(self):
""" Display the relocations contained in the file
"""
section, 'Version symbols', lead0x=False)
num_symbols = section.num_symbols()
-
- # Symbol version info are printed four by four entries
+
+ # Symbol version info are printed four by four entries
for idx_by_4 in range(0, num_symbols, 4):
self._emit(' %03x:' % idx_by_4)
optparser.add_option('-s', '--symbols', '--syms',
action='store_true', dest='show_symbols',
help='Display the symbol table')
+ optparser.add_option('-n', '--notes',
+ action='store_true', dest='show_notes',
+ help='Display the core notes (if present)')
optparser.add_option('-r', '--relocs',
action='store_true', dest='show_relocs',
help='Display the relocations (if present)')
readelf.display_dynamic_tags()
if options.show_symbols:
readelf.display_symbol_tables()
+ if options.show_notes:
+ readelf.display_notes()
if options.show_relocs:
readelf.display_relocations()
if options.show_version_info:
if __name__ == '__main__':
main()
#profile_main()
-
-
success = True
testlog.info("Test file '%s'" % filename)
for option in [
- '-e', '-d', '-s', '-r', '-x.text', '-p.shstrtab', '-V',
+ '-e', '-d', '-s', '-n', '-r', '-x.text', '-p.shstrtab', '-V',
'--debug-dump=info', '--debug-dump=decodedline',
'--debug-dump=frames', '--debug-dump=frames-interp']:
if verbose: testlog.info("..option='%s'" % option)
if __name__ == '__main__':
sys.exit(main())
-