#------------------------------------------------------------------------------- # elftools example: elf_low_high_api.py # # A simple example that shows some usage of the low-level API pyelftools # provides versus the high-level API while inspecting an ELF file's symbol # table. # # Eli Bendersky (eliben@gmail.com) # This code is in the public domain #------------------------------------------------------------------------------- from __future__ import print_function import sys # If elftools is not installed, maybe we're running from the root or examples # dir of the source distribution try: import elftools except ImportError: sys.path.extend(['.', '..']) from elftools.common.py3compat import bytes2str from elftools.elf.elffile import ELFFile from elftools.elf.sections import SymbolTableSection def process_file(filename): print('Processing file:', filename) with open(filename, 'rb') as f: section_info_lowlevel(f) f.seek(0) section_info_highlevel(f) def section_info_lowlevel(stream): print('Low level API...') # We'll still be using the ELFFile context object. It's just too # convenient to give up, even in the low-level API demonstation :-) elffile = ELFFile(stream) # The e_shnum ELF header field says how many sections there are in a file print(' %s sections' % elffile['e_shnum']) # Try to find the symbol table for i in range(elffile['e_shnum']): section_offset = elffile['e_shoff'] + i * elffile['e_shentsize'] # Parse the section header using structs.Elf_Shdr stream.seek(section_offset) section_header = elffile.structs.Elf_Shdr.parse_stream(stream) if section_header['sh_type'] == 'SHT_SYMTAB': # Some details about the section. Note that the section name is a # pointer to the object's string table, so it's only a number # here. To get to the actual name one would need to parse the string # table section and extract the name from there (or use the # high-level API!) print(' Section name: %s, type: %s' % ( section_header['sh_name'], section_header['sh_type'])) break else: print(' No symbol table found. Perhaps this ELF has been stripped?') def section_info_highlevel(stream): print('High level API...') elffile = ELFFile(stream) # Just use the public methods of ELFFile to get what we need # Note that section names, like everything read from the file, are bytes # objects. print(' %s sections' % elffile.num_sections()) section = elffile.get_section_by_name(b'.symtab') if not section: print(' No symbol table found. Perhaps this ELF has been stripped?') return # A section type is in its header, but the name was decoded and placed in # a public attribute. # bytes2str is used to print the name of the section for consistency of # output between Python 2 and 3. The section name is a bytes object. print(' Section name: %s, type: %s' %( bytes2str(section.name), section['sh_type'])) # But there's more... If this section is a symbol table section (which is # the case in the sample ELF file that comes with the examples), we can # get some more information about it. if isinstance(section, SymbolTableSection): num_symbols = section.num_symbols() print(" It's a symbol section with %s symbols" % num_symbols) print(" The name of the last symbol in the section is: %s" % ( bytes2str(section.get_symbol(num_symbols - 1).name))) if __name__ == '__main__': for filename in sys.argv[1:]: process_file(filename)