Esempio n. 1
0
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)))
Esempio n. 2
0
    def _print_version_section_header(self, version_section, name, lead0x=True,
                                      indent=1):
        """ Print a section header of one version related section (versym,
            verneed or verdef) with some options to accomodate readelf
            little differences between each header (e.g. indentation
            and 0x prefixing).
        """
        if hasattr(version_section, 'num_versions'):
            num_entries = version_section.num_versions()
        else:
            num_entries = version_section.num_symbols()

        self._emitline("\n%s section '%s' contains %s entries:" %
            (name, bytes2str(version_section.name), num_entries))
        self._emitline('%sAddr: %s  Offset: %s  Link: %i (%s)' % (
            ' ' * indent,
            self._format_hex(
                version_section['sh_addr'], fieldsize=16, lead0x=lead0x),
            self._format_hex(
                version_section['sh_offset'], fieldsize=6, lead0x=True),
            version_section['sh_link'],
            bytes2str(
                self.elffile.get_section(version_section['sh_link']).name)
            )
        )
Esempio n. 3
0
    def display_symbol_tables(self):
        """ Display the symbol tables contained in the file
        """
        for section in self.elffile.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue

            if section['sh_entsize'] == 0:
                self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
                    bytes2str(section.name)))
                continue

            self._emitline("\nSymbol table '%s' contains %s entries:" % (
                bytes2str(section.name), section.num_symbols()))

            if self.elffile.elfclass == 32:
                self._emitline('   Num:    Value  Size Type    Bind   Vis      Ndx Name')
            else: # 64
                self._emitline('   Num:    Value          Size Type    Bind   Vis      Ndx Name')

            for nsym, symbol in enumerate(section.iter_symbols()):
                # symbol names are truncated to 25 chars, similarly to readelf
                self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s' % (
                    nsym,
                    self._format_hex(symbol['st_value'], fullhex=True, lead0x=False),
                    symbol['st_size'],
                    describe_symbol_type(symbol['st_info']['type']),
                    describe_symbol_bind(symbol['st_info']['bind']),
                    describe_symbol_visibility(symbol['st_other']['visibility']),
                    describe_symbol_shndx(symbol['st_shndx']),
                    bytes2str(symbol.name)))
Esempio n. 4
0
    def fortify(self):
        """ NA : FORTIFY_SOURCE was not applicable
            Enabled : unsafe and _chk functions were found
            Disabled : only unsafe functions were found
                       (_chk functions missing)"""
        ret = "NA"
        for section in self.elffile.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue
            if section['sh_entsize'] == 0:
                print("\nSymbol table '%s' has a sh_entsize " \
                    "of zero!" % (bytes2str(section.name)), file=sys.stderr)
                continue
            for _, symbol in enumerate(section.iter_symbols()):
                for pattern in UNSAFE_FUNCTIONS:
                    if re.match(pattern, bytes2str(symbol.name)):
                        if ret == "NA":
                            ret = "Disabled"
                            break

            if ret == "Disabled":
                # afename = "__" + bytes2str(symbol.name) + "_chk"
                for _, symbol in enumerate(section.iter_symbols()):
                    # first look for corresponding _chk symbol
                    symbolstr = bytes2str(symbol.name)
                    if (symbolstr.startswith("__") and
                            symbolstr.endswith("_chk")) or \
                            symbolstr.endswith(" __chk_fail"):
                        ret = "Enabled"
                        break
        return ret
Esempio n. 5
0
def die_info_rec(die, func_map, global_map, type_map, struct_map, variables, global_access_map):
    """ A recursive function for showing information about a DIE and its
        children.
    """
    name = ''
    if die.tag == "DW_TAG_subprogram":
        variables = {}
        #print (die.attributes)
        for attr in itervalues(die.attributes):
            if attr.name == 'DW_AT_name':
                name = bytes2str(attr.value)

    elif die.tag == "DW_TAG_variable" or die.tag == "DW_TAG_formal_parameter":
        global_flag = 0
        #var_name, offset, line, type_val = '',0,0,''
	offset_var = ''
        for attr in itervalues(die.attributes):
            if attr.name == 'DW_AT_name':
                var_name =  bytes2str(attr.value)
            elif attr.name == 'DW_AT_location':
                val = _location_list_extra(attr, die, ' ')
                #offset = int(val[val.index(':')+1:].strip()[:-1],16)
		offset_var = val[val.find(':')+1:val.find(')')].strip()
            elif attr.name == 'DW_AT_decl_line':
                line = attr.value
            elif attr.name == 'DW_AT_type':
                type_val = (attr.value + die.cu.cu_offset)
            elif attr.name == 'DW_AT_external':
                global_flag = 1

	if type_val in struct_map.keys():
	    struct_var_name = var_name
	    members = struct_map[type_val]
	    for member in members.keys():
		var_name = struct_var_name + "." + struct_map[type_val][member][0]
		struct_offset =	struct_map[type_val][member][1]
		addVariableInMap(global_flag, global_map, variables, offset_var, var_name, type_val, line, global_access_map, struct_offset)

	else:
	   addVariableInMap(global_flag, global_map, variables, offset_var, var_name, type_val, line, global_access_map, 0)
            
    elif die.tag == 'DW_TAG_base_type':
        #type_name, size = '',0
        for attr in itervalues(die.attributes):
            if attr.name == "DW_AT_name":
                type_name = bytes2str(attr.value)
            elif attr.name == 'DW_AT_byte_size':
                size = attr.value
                
        type_map[die.offset] = (type_name, size)

    for child in die.iter_children():
        die_info_rec(child, func_map, global_map, type_map, struct_map, variables, global_access_map)

            
    if die.tag == "DW_TAG_subprogram":
        #print (die.attributes)
        func_map[name] = variables     
Esempio n. 6
0
    def display_relocations(self):
        """ Display the relocations contained in the file
        """
        has_relocation_sections = False
        for section in self.elffile.iter_sections():
            if not isinstance(section, RelocationSection):
                continue

            has_relocation_sections = True
            self._emitline("\nRelocation section '%s' at offset %s contains %s entries:" % (
                bytes2str(section.name),
                self._format_hex(section['sh_offset']),
                section.num_relocations()))
            if section.is_RELA():
                self._emitline("  Offset          Info           Type           Sym. Value    Sym. Name + Addend")
            else:
                self._emitline(" Offset     Info    Type            Sym.Value  Sym. Name")

            # The symbol table section pointed to in sh_link
            symtable = self.elffile.get_section(section['sh_link'])

            for rel in section.iter_relocations():
                hexwidth = 8 if self.elffile.elfclass == 32 else 12
                self._emit('%s  %s %-17.17s' % (
                    self._format_hex(rel['r_offset'],
                        fieldsize=hexwidth, lead0x=False),
                    self._format_hex(rel['r_info'],
                        fieldsize=hexwidth, lead0x=False),
                    describe_reloc_type(
                        rel['r_info_type'], self.elffile)))

                if rel['r_info_sym'] == 0:
                    self._emitline()
                    continue

                symbol = symtable.get_symbol(rel['r_info_sym'])
                # Some symbols have zero 'st_name', so instead what's used is
                # the name of the section they point at
                if symbol['st_name'] == 0:
                    symsec = self.elffile.get_section(symbol['st_shndx'])
                    symbol_name = symsec.name
                else:
                    symbol_name = symbol.name
                self._emit(' %s %s%22.22s' % (
                    self._format_hex(
                        symbol['st_value'],
                        fullhex=True, lead0x=False),
                    '  ' if self.elffile.elfclass == 32 else '',
                    bytes2str(symbol_name)))
                if section.is_RELA():
                    self._emit(' %s %x' % (
                        '+' if rel['r_addend'] >= 0 else '-',
                        abs(rel['r_addend'])))
                self._emitline()

        if not has_relocation_sections:
            self._emitline('\nThere are no relocations in this file.')
Esempio n. 7
0
def process_file(do_write, syms, filename):
    addrs = dict()
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)
        print('%s: elfclass is %s' % (filename, elffile.elfclass))

        text_name = b'.text'
        sect_text = elffile.get_section_by_name(text_name)

        if not sect_text:
            print('  The file has no %s section' % bytes2str(text_name))
            return

        print('  %s section, sh_offset=%s sh_addr=%s' % (
            bytes2str(text_name), sect_text['sh_offset'], sect_text['sh_addr']))

        sect_st = elffile.get_section_by_name(b'.symtab')

        if not sect_st:
            print('  No symbol table found. Perhaps this ELF has been stripped?')
            return

        if not isinstance(sect_st, SymbolTableSection):
            print('  Not a valid symbol table')
            return

        for _sym in sect_st.iter_symbols():
            if _sym.name in syms.keys():
                sym_offset_in_file = sect_text['sh_offset'] - sect_text['sh_addr'] + _sym['st_value']
                print('found %s at virtual address %s, offset in file = %s' % 
                    (_sym.name,
                     hex(_sym['st_value']),
                     hex(sym_offset_in_file)) )
                addrs[_sym.name] = sym_offset_in_file

        if len(syms) > len(addrs):
            for sym_name in syms.keys():
                if not sym_name in addrs.keys():
                    print('   Failed to find symbol %s' % (sym_name))
            print('  Not all symbols found, aborting')
            return 
        else:
            print('  All required symbols found');
        f.close()

    if not do_write:
        print('   Scan-only mode, not writing any changes')
        return

    with open(filename, 'r+b') as f:
        print('   Writing patches to file...')
        for _sym in addrs.keys():
            f.seek(addrs[_sym])
            f.write(syms[_sym])
        f.close()
Esempio n. 8
0
    def display_symbol_tables(self):
        """ Display the symbol tables contained in the file
        """
        self._init_versioninfo()

        for section in self.elffile.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue

            if section['sh_entsize'] == 0:
                self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
                    bytes2str(section.name)))
                continue

            self._emitline("\nSymbol table '%s' contains %s entries:" % (
                bytes2str(section.name), section.num_symbols()))

            if self.elffile.elfclass == 32:
                self._emitline('   Num:    Value  Size Type    Bind   Vis      Ndx Name')
            else: # 64
                self._emitline('   Num:    Value          Size Type    Bind   Vis      Ndx Name')

            for nsym, symbol in enumerate(section.iter_symbols()):

                version_info = ''
                # readelf doesn't display version info for Solaris versioning
                if (section['sh_type'] == 'SHT_DYNSYM' and
                        self._versioninfo['type'] == 'GNU'):
                    version = self._symbol_version(nsym)
                    if (version['name'] != bytes2str(symbol.name) and
                        version['index'] not in ('VER_NDX_LOCAL',
                                                 'VER_NDX_GLOBAL')):
                        if version['filename']:
                            # external symbol
                            version_info = '@%(name)s (%(index)i)' % version
                        else:
                            # internal symbol
                            if version['hidden']:
                                version_info = '@%(name)s' % version
                            else:
                                version_info = '@@%(name)s' % version

                # symbol names are truncated to 25 chars, similarly to readelf
                self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s%s' % (
                    nsym,
                    self._format_hex(
                        symbol['st_value'], fullhex=True, lead0x=False),
                    symbol['st_size'],
                    describe_symbol_type(symbol['st_info']['type']),
                    describe_symbol_bind(symbol['st_info']['bind']),
                    describe_symbol_visibility(symbol['st_other']['visibility']),
                    describe_symbol_shndx(symbol['st_shndx']),
                    bytes2str(symbol.name),
                    version_info))
Esempio n. 9
0
 def canary(self):
     for section in self.elffile.iter_sections():
         if not isinstance(section, SymbolTableSection):
             continue
         if section['sh_entsize'] == 0:
             print ("\nSymbol table '%s' has a sh_entsize " \
                 "of zero!" % (bytes2str(section.name)), file=sys.stderr)
             continue
         for _, symbol in enumerate(section.iter_symbols()):
             if re.match(STACK_CHK, bytes2str(symbol.name)):
                 return "Enabled"
     return "Disabled"
Esempio n. 10
0
def build_symtab(elffile):
    syms = []
    for section in elffile.iter_sections():
        if isinstance(section, SymbolTableSection):
            for nsym, sym in enumerate(section.iter_symbols()):
                name = bytes2str(sym.name)
                if not name:
                    continue
                end = sym['st_value'] + sym['st_size']
                syms.append((sym['st_value'], end, 
                             bytes2str(sym.name)))
    syms.sort()
    return syms
Esempio n. 11
0
def process_file(filename):
    print('Processing file:', filename)
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)

        if not elffile.has_dwarf_info():
            print('  file has no DWARF info')
            return

        # get_dwarf_info returns a DWARFInfo context object, which is the
        # starting point for all DWARF-based processing in pyelftools.
        dwarfinfo = elffile.get_dwarf_info()

        for CU in dwarfinfo.iter_CUs():
            # DWARFInfo allows to iterate over the compile units contained in
            # the .debug_info section. CU is a CompileUnit object, with some
            # computed attributes (such as its offset in the section) and
            # a header which conforms to the DWARF standard. The access to
            # header elements is, as usual, via item-lookup.
            print('  Found a compile unit at offset %s, length %s' % (
                CU.cu_offset, CU['unit_length']))

            # Start with the top DIE, the root for this CU's DIE tree
            top_DIE = CU.get_top_DIE()
            print('    Top DIE with tag=%s' % top_DIE.tag)

            # Each DIE holds an OrderedDict of attributes, mapping names to
            # values. Values are represented by AttributeValue objects in
            # elftools/dwarf/die.py
            # We're interested in the filename, which is the join of
            # 'DW_AT_comp_dir' and 'DW_AT_name', either of which may be
            # missing in practice. Note that its value
            # is usually a string taken from the .debug_string section. This
            # is done transparently by the library, and such a value will be
            # simply given as a string.
            try:
                comp_dir_attr = top_DIE.attributes['DW_AT_comp_dir']
                comp_dir = bytes2str(comp_dir_attr.value)
                try:
                    name_attr = top_DIE.attributes['DW_AT_name']
                    name = bytes2str(name_attr.value)
                    name = os.path.join(comp_dir, name)
                except KeyError as e:
                    name = comp_dir
            except KeyError as e:
                name_attr = top_DIE.attributes['DW_AT_name']
                name = bytes2str(name_attr.value)
            print('    name=%s' % name)

            # Display DIEs recursively starting with top_DIE
            die_info_rec(top_DIE)
Esempio n. 12
0
def get_cu_filename(cu, idx=0):
    """A DW_AT_decl_file I think can be looked up, by index, from the CU
    file entry and directory index.
    """
    lineprogram = cu.dwarfinfo.line_program_for_CU(cu)
    cu_filename = bytes2str(lineprogram["file_entry"][idx - 1].name)
    if len(lineprogram["include_directory"]) > 0:
        dir_index = lineprogram["file_entry"][idx - 1].dir_index
        if dir_index > 0:
            dir_name = bytes2str(lineprogram["include_directory"][dir_index - 1])
        else:
            dir_name = "."
        cu_filename = "%s/%s" % (dir_name, cu_filename)
    return cu_filename
Esempio n. 13
0
def build_symtab(elffile):
    syms = []
    for section in elffile.iter_sections():
        if isinstance(section, SymbolTableSection):
            for nsym, sym in enumerate(section.iter_symbols()):
                name = bytes2str(sym.name)
                if not name:
                    continue
                if sym.entry.st_info.type != 'STT_FUNC':
                    continue
                end = sym['st_value'] + sym['st_size']
                syms.append((sym['st_value'], end, 
                             bytes2str(sym.name)))
    syms.sort()
    return syms
Esempio n. 14
0
    def display_dynamic_tags(self):
        """ Display the dynamic tags contained in the file
        """
        has_dynamic_sections = False
        for section in self.elffile.iter_sections():
            if not isinstance(section, DynamicSection):
                continue

            has_dynamic_sections = True
            self._emitline("\nDynamic section at offset %s contains %s entries:" % (
                self._format_hex(section['sh_offset']),
                section.num_tags()))
            self._emitline("  Tag        Type                         Name/Value")

            padding = 20 + (8 if self.elffile.elfclass == 32 else 0)
            for tag in section.iter_tags():
                if tag.entry.d_tag == 'DT_NEEDED':
                    parsed = 'Shared library: [%s]' % bytes2str(tag.needed)
                elif tag.entry.d_tag == 'DT_RPATH':
                    parsed = 'Library rpath: [%s]' % bytes2str(tag.rpath)
                elif tag.entry.d_tag == 'DT_RUNPATH':
                    parsed = 'Library runpath: [%s]' % bytes2str(tag.runpath)
                elif tag.entry.d_tag == 'DT_SONAME':
                    parsed = 'Library soname: [%s]' % bytes2str(tag.soname)
                elif (tag.entry.d_tag.endswith('SZ') or
                      tag.entry.d_tag.endswith('ENT')):
                    parsed = '%i (bytes)' % tag['d_val']
                elif (tag.entry.d_tag.endswith('NUM') or
                      tag.entry.d_tag.endswith('COUNT')):
                    parsed = '%i' % tag['d_val']
                elif tag.entry.d_tag == 'DT_PLTREL':
                    s = describe_dyn_tag(tag.entry.d_val)
                    if s.startswith('DT_'):
                        s = s[3:]
                    parsed = '%s' % s
                else:
                    parsed = '%#x' % tag['d_val']

                self._emitline(" %s %-*s %s" % (
                    self._format_hex(ENUM_D_TAG.get(tag.entry.d_tag, tag.entry.d_tag),
                        fullhex=True, lead0x=True),
                    padding,
                    '(%s)' % (tag.entry.d_tag[3:],),
                    parsed))
        if not has_dynamic_sections:
            # readelf only prints this if there is at least one segment
            if self.elffile.num_segments():
                self._emitline("\nThere is no dynamic section in this file.")
Esempio n. 15
0
    def _dump_debug_frames(self):
        """ Dump the raw frame information from .debug_frame
        """
        if not self._dwarfinfo.has_CFI():
            return
        self._emitline('Contents of the .debug_frame section:')

        for entry in self._dwarfinfo.CFI_entries():
            if isinstance(entry, CIE):
                self._emitline('\n%08x %08x %08x CIE' % (
                    entry.offset, entry['length'], entry['CIE_id']))
                self._emitline('  Version:               %d' % entry['version'])
                self._emitline('  Augmentation:          "%s"' % bytes2str(entry['augmentation']))
                self._emitline('  Code alignment factor: %u' % entry['code_alignment_factor'])
                self._emitline('  Data alignment factor: %d' % entry['data_alignment_factor'])
                self._emitline('  Return address column: %d' % entry['return_address_register'])
                self._emitline()
            else: # FDE
                self._emitline('\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' % (
                    entry.offset,
                    entry['length'],
                    entry['CIE_pointer'],
                    entry.cie.offset,
                    entry['initial_location'],
                    entry['initial_location'] + entry['address_range']))

            self._emit(describe_CFI_instructions(entry))
        self._emitline()
Esempio n. 16
0
def parse_member(die):
    """DW_TAG_member seems to be nested as follows:

    <data-member access='private' layout-offset-in-bits='0'>
    <var-decl name='_M_ptr' type-id='type-id-202' visibility='default'
        filepath='/usr/include/c++/9/bits/shared_ptr_base.h' line='1404' column='1'/>
    </data-member>

    TODO: where is visibility?
    """
    child = {"_type": "var-decl"}

    filepath = get_die_filepath(die)
    if filepath:
        child["filepath"] = filepath

    # These values are not present in all namespace DIEs
    if "DW_AT_decl_line" in die.attributes:
        child["line"] = die.attributes["DW_AT_decl_line"].value
    if "DW_AT_decl_column" in die.attributes:
        child["column"] = die.attributes["DW_AT_decl_column"].value

    if "DW_AT_name" in die.attributes:
        child["name"] = bytes2str(die.attributes["DW_AT_name"].value)
    return {"_type": "member", "children": [child]}
Esempio n. 17
0
    def _lookup_function_name(self, address):
        so = self.get_so_by_address(address)

        # Addresses in DWARF are relative to base address for PIC, so
        # make the address argument relative too if needed
        if so.is_pic:
            address -= so.low_addr

        for compile_unit in so.dwarf_info.iter_CUs():
            for die in compile_unit.iter_DIEs():
                try:
                    if die.tag == 'DW_TAG_subprogram':
                        func_name = bytes2str(
                            die.attributes['DW_AT_name'].value)
                        low_pc = die.attributes['DW_AT_low_pc'].value
                        high_pc_attr = die.attributes['DW_AT_high_pc']
                        if high_pc_attr.form == 'DW_FORM_addr':
                            high_pc = high_pc_attr.value
                        else:
                            # high_pc relative to low_pc
                            high_pc = low_pc + high_pc_attr.value

                        if low_pc <= address <= high_pc:
                            self._function_names[address] = func_name
                            return self._function_names[address]
                except KeyError:
                    continue

        return None
Esempio n. 18
0
def parse_structure_type(die):
    """DW_TAG_structure, example xml:

    <class-decl name='filter_base' size-in-bits='192' is-struct='yes'
                visibility='default'
                filepath='/libabigail-1.8/build/../include/abg-comp-filter.h'
                line='120' column='1' id='type-id-1'>

    I've changed the "yes" and "no" to be True and False booleans.
    TODO: also not sure how to derive visibility here.
    """
    filepath = get_die_filepath(die)
    dmeta = {
        "_type": "class-decl",
        "is-struct": True,
    }

    # These values are not present in all structure types
    if "DW_AT_name" in die.attributes:
        dmeta["name"] = bytes2str(die.attributes["DW_AT_name"].value)
    if "DW_AT_decl_line" in die.attributes:
        dmeta["line"] = die.attributes["DW_AT_decl_line"].value
    if "DW_AT_decl_column" in die.attributes:
        dmeta["column"] = die.attributes["DW_AT_decl_column"].value
    if "DW_AT_byte_size" in die.attributes:
        dmeta["size-in-bits"] = (die.attributes["DW_AT_byte_size"].value * 8,)

    if filepath:
        dmeta["filepath"] = filepath
    if die.has_children:
        dmeta["children"] = []
    return dmeta
Esempio n. 19
0
def get_relocations(fd):
    """ 
	Return a dict with the relocations contained in a file
	"""
    elffile = ELFFile(fd)
    relocations = {}
    has_relocation_sections = False
    for section in elffile.iter_sections():
        if not isinstance(section, RelocationSection):
            continue

        has_relocation_sections = True
        # The symbol table section pointed to in sh_link
        symtable = elffile.get_section(section['sh_link'])

        for rel in section.iter_relocations():
            offset = rel['r_offset']

            symbol = symtable.get_symbol(rel['r_info_sym'])
            # Some symbols have zero 'st_name', so instead what's used is
            # the name of the section they point at
            if symbol['st_name'] == 0:
                symsec = elffile.get_section(symbol['st_shndx'])
                symbol_name = symsec.name
            else:
                symbol_name = symbol.name
                relocations[offset] = bytes2str(symbol_name)

    return relocations
Esempio n. 20
0
    def _find_deps(self, filename, recursive):
        libs = []
        filename = self._get_abs_path(filename)
        with open(filename, 'rb') as f:
            try:
                elf = ELFFile(f)
                for section in elf.iter_sections():
                    if not isinstance(section, DynamicSection):
                        continue
                    for tag in section.iter_tags():
                        if tag.entry.d_tag == 'DT_NEEDED':
                            lib = bytes2str(tag.needed)
                            libs.append(lib)
            except ELFError:
                raise

        if self._with_full_path:
            libs = [self._get_abs_path(l) for l in libs]
            deps = [(filename, libs)]
        else:
            deps = [(os.path.basename(filename), libs)]

        if recursive:
            for lib in libs:
                deps += self._find_deps(lib, recursive)
        return deps
Esempio n. 21
0
def parse_enumeration_type(die):
    """parse an enumeration type. The xml looks like this:

    <enum-decl name='_Rb_tree_color' filepath='/usr/include/c++/9/bits/stl_tree.h'
      line='99' column='1' id='type-id-21300'>
      <underlying-type type-id='type-id-297'/>
      <enumerator name='_S_red' value='0'/>
      <enumerator name='_S_black' value='1'/>
    </enum-decl>
    """
    index = die.attributes["DW_AT_decl_file"].value
    filepath = get_cu_filename(die.cu, index)

    dmeta = {
        "_type": "enum-decl",
        "filepath": filepath,
        "line": die.attributes["DW_AT_decl_line"].value,
    }

    if "DW_AT_name" in die.attributes:
        dmeta["name"] = bytes2str(die.attributes["DW_AT_name"].value)
    if "DW_AT_decl_column" in die.attributes:
        dmeta["column"] = die.attributes["DW_AT_decl_column"].value

    if die.has_children:
        dmeta["children"] = []
    return dmeta
Esempio n. 22
0
def parse_namespace(die):
    """parse a DW_TAG_namespace, optionally with children.
    DW_AT_export_symbols indicates that the symbols defined within the
    current scope are to be exported into the enclosing scope.

    TODO: Is DW_AT_export_symbols used anywhere? Where do we get visibility?
    """
    filepath = get_die_filepath(die)

    dmeta = {
        "_type": "namespace",
        "filepath": filepath,
    }

    # These values are not present in all namespace DIEs
    if "DW_AT_name" in die.attributes:
        dmeta["name"] = bytes2str(die.attributes["DW_AT_name"].value)
    if "DW_AT_decl_line" in die.attributes:
        dmeta["line"] = die.attributes["DW_AT_decl_line"].value
    if "DW_AT_decl_column" in die.attributes:
        dmeta["column"] = die.attributes["DW_AT_decl_column"].value

    if die.has_children:
        dmeta["children"] = []
    return dmeta
Esempio n. 23
0
    def patchFile(self, dumpfile, targetfile):
        func_name = ''
        func_addr = {}
        func_size = {}
        file_offset = {}
        text_section_file_offset = 0
        text_section_code_offset = 0
        err = ''

        # Browse Elf header
        try:
            # print "Target file: " + targetfile
            elffile = ELFFile(targetfile)
            for section in elffile.iter_sections():
                if section.name == '.text':
                    text_section_file_offset = section['sh_offset']
                    text_section_code_offset = section['sh_addr']
                    text_section_code_size = section['sh_size']
                    continue
                if not isinstance(section, SymbolTableSection):
                    # Continue if not section does not contain symbols
                    continue
                if section['sh_entsize'] == 0:
                    err = 'Symbol table "%s" has a sh_entsize of zero!' % (
                        bytes2str(section.name))
                    continue
            # Patch file
            dumpfile.seek(0)
            patch_code = dumpfile.read(text_section_code_size)
            targetfile.seek(text_section_file_offset)
            targetfile.write(patch_code)
        except Exception as e:
            return 'Error: ' + str(e)

        return err
Esempio n. 24
0
    def _dump_debug_frames_interp(self):
        """ Dump the interpreted (decoded) frame information from .debug_frame
        """
        if not self._dwarfinfo.has_CFI():
            return

        self._emitline('Contents of the .debug_frame section:')

        for entry in self._dwarfinfo.CFI_entries():
            if isinstance(entry, CIE):
                self._emitline('\n%08x %08x %08x CIE "%s" cf=%d df=%d ra=%d' %
                               (entry.offset, entry['length'], entry['CIE_id'],
                                bytes2str(entry['augmentation']),
                                entry['code_alignment_factor'],
                                entry['data_alignment_factor'],
                                entry['return_address_register']))
                ra_regnum = entry['return_address_register']
            else:  # FDE
                self._emitline(
                    '\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' %
                    (entry.offset, entry['length'], entry['CIE_pointer'],
                     entry.cie.offset, entry['initial_location'],
                     entry['initial_location'] + entry['address_range']))
                ra_regnum = entry.cie['return_address_register']

            # Print the heading row for the decoded table
            self._emit('   LOC')
            self._emit('  ' if entry.structs.address_size ==
                       4 else '          ')
            self._emit(' CFA      ')

            # Decode the table nad look at the registers it describes.
            # We build reg_order here to match readelf's order. In particular,
            # registers are sorted by their number, and the register matching
            # ra_regnum is always listed last with a special heading.
            decoded_table = entry.get_decoded()
            reg_order = sorted(
                ifilter(lambda r: r != ra_regnum, decoded_table.reg_order))

            # Headings for the registers
            for regnum in reg_order:
                self._emit('%-6s' % describe_reg_name(regnum))
            self._emitline('ra      ')

            # Now include ra_regnum in reg_order to print its values similarly
            # to the other registers.
            reg_order.append(ra_regnum)
            for line in decoded_table.table:
                self._emit(
                    self._format_hex(line['pc'], fullhex=True, lead0x=False))
                self._emit(' %-9s' % describe_CFI_CFA_rule(line['cfa']))

                for regnum in reg_order:
                    if regnum in line:
                        s = describe_CFI_register_rule(line[regnum])
                    else:
                        s = 'u'
                    self._emit('%-6s' % s)
                self._emitline()
        self._emitline()
Esempio n. 25
0
def parse_union_type(die):
    """parse a union type
    <union-decl name='__anonymous_union__' size-in-bits='64'
      is-anonymous='yes' visibility='default'
      filepath='/libabigail-1.8/build/../include/abg-ir.h'
      line='2316' column='1' id='type-id-2748'>
    """
    index = die.attributes["DW_AT_decl_file"].value
    filepath = get_cu_filename(die.cu, index)

    dmeta = {
        "_type": "union-decl",
        "line": die.attributes["DW_AT_decl_line"].value,
        "filepath": filepath,
        "size-in-bits": die.attributes["DW_AT_byte_size"].value * 8,
        "is-anonymous": "",  # TODO: how do I know if it's anonymous?
        "visibility": "",  # TODO: visibility?,
        "children": [],
    }
    if "DW_AT_name" in die.attributes:
        dmeta["name"] = bytes2str(die.attributes["DW_AT_name"].value)
    if "DW_AT_decl_column" in die.attributes:
        dmeta["column"] = die.attributes["DW_AT_decl_column"].value

    if die.has_children:
        dmeta["children"] = []
    return dmeta
Esempio n. 26
0
def decode_funcname(dwarfinfo, address):
    """Go over all DIEs in the DWARF information, looking for a subprogram
    entry with an address range that includes the given address. Note that
    this simplifies things by disregarding subprograms that may have
    split address ranges."""
    for compile_unit in dwarfinfo.iter_CUs():
        for DIE in compile_unit.iter_DIEs():
            try:
                if DIE.tag == 'DW_TAG_subprogram':
                    lowpc = DIE.attributes['DW_AT_low_pc'].value

                    # DWARF v4 in section 2.17 describes how to interpret the
                    # DW_AT_high_pc attribute based on the class of its form.
                    # For class 'address' it's taken as an absolute address
                    # (similarly to DW_AT_low_pc); for class 'constant', it's
                    # an offset from DW_AT_low_pc.
                    highpc_attr = DIE.attributes['DW_AT_high_pc']
                    highpc_attr_class = describe_form_class(highpc_attr.form)
                    if highpc_attr_class == 'address':
                        highpc = highpc_attr.value
                    elif highpc_attr_class == 'constant':
                        highpc = lowpc + highpc_attr.value
                    else:
                        print('Error: invalid DW_AT_high_pc class:',
                              highpc_attr_class)
                        continue

                    if lowpc <= address <= highpc:
                        return bytes2str(DIE.attributes['DW_AT_name'].value)
            except KeyError:
                continue
    return None
Esempio n. 27
0
    def _lookup_function_name(self, address):
        so = self.get_so_by_address(address)

        # Addresses in DWARF are relative to base address for PIC, so
        # make the address argument relative too if needed
        if so.is_pic:
            address -= so.low_addr

        for compile_unit in so.dwarf_info.iter_CUs():
            for die in compile_unit.iter_DIEs():
                try:
                    if die.tag == 'DW_TAG_subprogram':
                        func_name = bytes2str(
                            die.attributes['DW_AT_name'].value)
                        low_pc = die.attributes['DW_AT_low_pc'].value
                        high_pc_attr = die.attributes['DW_AT_high_pc']
                        if high_pc_attr.form == 'DW_FORM_addr':
                            high_pc = high_pc_attr.value
                        else:
                            # high_pc relative to low_pc
                            high_pc = low_pc + high_pc_attr.value

                        if low_pc <= address <= high_pc:
                            self._function_names[address] = func_name
                            return self._function_names[address]
                except KeyError:
                    continue

        return None
Esempio n. 28
0
    def search_for_autoload_path(self):
        scanelf = self
        scanfile = None
        library = None

        section = self._section_from_spec(".dynamic")
        try:
            eallib = self.find_librte_eal(section)
            if eallib is not None:
                ldlibpath = os.environ.get('LD_LIBRARY_PATH')
                if ldlibpath is None:
                    ldlibpath = ""
                dtr = self.get_dt_runpath(section)
                library = search_file(
                    eallib,
                    dtr + ":" + ldlibpath + ":/usr/lib64:/lib64:/usr/lib:/lib")
                if library is None:
                    return (None, None)
                if raw_output is False:
                    print("Scanning for autoload path in %s" % library)
                scanfile = open(library, 'rb')
                scanelf = ReadElf(scanfile, sys.stdout)
        except AttributeError:
            # Not a dynamic binary
            pass
        except ELFError:
            scanfile.close()
            return (None, None)

        section = scanelf._section_from_spec(".rodata")
        if section is None:
            if scanfile is not None:
                scanfile.close()
            return (None, None)

        data = section.data()
        dataptr = 0

        while dataptr < len(data):
            while (dataptr < len(data)
                   and not (32 <= byte2int(data[dataptr]) <= 127)):
                dataptr += 1

            if dataptr >= len(data):
                break

            endptr = dataptr
            while endptr < len(data) and byte2int(data[endptr]) != 0:
                endptr += 1

            mystring = bytes2str(data[dataptr:endptr])
            rc = mystring.find("DPDK_PLUGIN_PATH")
            if (rc != -1):
                rc = mystring.find("=")
                return (mystring[rc + 1:], library)

            dataptr = endptr
        if scanfile is not None:
            scanfile.close()
        return (None, None)
Esempio n. 29
0
    def search_for_autoload_path(self):
        scanelf = self
        scanfile = None
        library = None

        section = self._section_from_spec(".dynamic")
        try:
            eallib = self.find_librte_eal(section)
            if eallib is not None:
                ldlibpath = os.environ.get('LD_LIBRARY_PATH')
                if ldlibpath is None:
                    ldlibpath = ""
                dtr = self.get_dt_runpath(section)
                library = search_file(eallib,
                                      dtr + ":" + ldlibpath +
                                      ":/usr/lib64:/lib64:/usr/lib:/lib")
                if library is None:
                    return (None, None)
                if raw_output is False:
                    print("Scanning for autoload path in %s" % library)
                scanfile = open(library, 'rb')
                scanelf = ReadElf(scanfile, sys.stdout)
        except AttributeError:
            # Not a dynamic binary
            pass
        except ELFError:
            scanfile.close()
            return (None, None)

        section = scanelf._section_from_spec(".rodata")
        if section is None:
            if scanfile is not None:
                scanfile.close()
            return (None, None)

        data = section.data()
        dataptr = 0

        while dataptr < len(data):
            while (dataptr < len(data) and
                    not (32 <= byte2int(data[dataptr]) <= 127)):
                dataptr += 1

            if dataptr >= len(data):
                break

            endptr = dataptr
            while endptr < len(data) and byte2int(data[endptr]) != 0:
                endptr += 1

            mystring = bytes2str(data[dataptr:endptr])
            rc = mystring.find("DPDK_PLUGIN_PATH")
            if (rc != -1):
                rc = mystring.find("=")
                return (mystring[rc + 1:], library)

            dataptr = endptr
        if scanfile is not None:
            scanfile.close()
        return (None, None)
Esempio n. 30
0
def parse_dwarf(dwarfinfo):
    if should_log:
        print("")
        print("Building DWARF lookup table...")
    templist = []
    for CU in dwarfinfo.iter_CUs():
        for DIE in CU.iter_DIEs():
            try:
                # Using each DIE (Debugging Information Entry), the lower and
                # upper bounds of a function (subprogram) are recorded. This
                # takes into account entries that may only have a length instead
                # of an upper-bound attribute
                if DIE.tag == 'DW_TAG_subprogram':
                    lowpc = DIE.attributes['DW_AT_low_pc'].value
                    highpc_attr = DIE.attributes['DW_AT_high_pc']
                    highpc_attr_class = describe_form_class(highpc_attr.form)
                    if highpc_attr_class == 'address':
                        highpc = highpc_attr.value
                    elif highpc_attr_class == 'constant':
                        highpc = lowpc + highpc_attr.value
                    else:
                        highpc = 0
                    namestring = bytes2str(DIE.attributes['DW_AT_name'].value)
                    if lowpc > 0:
                        templist.append(
                            FuncNode(lowpc=lowpc,
                                     highpc=highpc,
                                     namestring=namestring))
            except KeyError:
                continue
    if should_log:
        for temp in templist:
            print(temp.namestring + ": " + str(temp.lowpc) + "/" +
                  str(temp.highpc))
    return sorted(templist, key=lambda x: x.lowpc)
Esempio n. 31
0
def process_file(filename):
    print('Processing file:', filename)
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)

        if not elffile.has_dwarf_info():
            print('  file has no DWARF info')
            return

        # get_dwarf_info returns a DWARFInfo context object, which is the
        # starting point for all DWARF-based processing in pyelftools.
        dwarfinfo = elffile.get_dwarf_info()

        for CU in dwarfinfo.iter_CUs():
            # DWARFInfo allows to iterate over the compile units contained in
            # the .debug_info section. CU is a CompileUnit object, with some
            # computed attributes (such as its offset in the section) and
            # a header which conforms to the DWARF standard. The access to
            # header elements is, as usual, via item-lookup.
            print('  Found a compile unit at offset %s, length %s' % (
                CU.cu_offset, CU['unit_length']))

            # The first DIE in each compile unit describes it.
            top_DIE = CU.get_top_DIE()
            print('    Top DIE with tag=%s' % top_DIE.tag)

            # Each DIE holds an OrderedDict of attributes, mapping names to
            # values. Values are represented by AttributeValue objects in
            # elftools/dwarf/die.py
            # We're interested in the DW_AT_name attribute. Note that its value
            # is usually a string taken from the .debug_str section. This
            # is done transparently by the library, and such a value will be
            # simply given as a string.
            name_attr = top_DIE.attributes['DW_AT_name']
            print('    name=%s' % bytes2str(name_attr.value))
Esempio n. 32
0
def get_relocations(fd):
	""" 
	Return a dict with the relocations contained in a file
	"""
	elffile = ELFFile(fd)
	relocations = {}
	has_relocation_sections = False
	for section in elffile.iter_sections():
	    if not isinstance(section, RelocationSection):
		continue

	    has_relocation_sections = True
	    # The symbol table section pointed to in sh_link
	    symtable = elffile.get_section(section['sh_link'])

	    for rel in section.iter_relocations():
		offset = rel['r_offset'] 

		symbol = symtable.get_symbol(rel['r_info_sym'])
		# Some symbols have zero 'st_name', so instead what's used is
		# the name of the section they point at
		if symbol['st_name'] == 0:
		    symsec = elffile.get_section(symbol['st_shndx'])
		    symbol_name = symsec.name
		else:
		    symbol_name = symbol.name
		    relocations[offset] = bytes2str(symbol_name)

	return relocations
Esempio n. 33
0
    def _dump_debug_frames(self):
        """ Dump the raw frame information from .debug_frame
        """
        if not self._dwarfinfo.has_CFI():
            return
        self._emitline('Contents of the .debug_frame section:')

        for entry in self._dwarfinfo.CFI_entries():
            if isinstance(entry, CIE):
                self._emitline(
                    '\n%08x %08x %08x CIE' %
                    (entry.offset, entry['length'], entry['CIE_id']))
                self._emitline('  Version:               %d' %
                               entry['version'])
                self._emitline('  Augmentation:          "%s"' %
                               bytes2str(entry['augmentation']))
                self._emitline('  Code alignment factor: %u' %
                               entry['code_alignment_factor'])
                self._emitline('  Data alignment factor: %d' %
                               entry['data_alignment_factor'])
                self._emitline('  Return address column: %d' %
                               entry['return_address_register'])
                self._emitline()
            else:  # FDE
                self._emitline(
                    '\n%08x %08x %08x FDE cie=%08x pc=%08x..%08x' %
                    (entry.offset, entry['length'], entry['CIE_pointer'],
                     entry.cie.offset, entry['initial_location'],
                     entry['initial_location'] + entry['address_range']))

            self._emit(describe_CFI_instructions(entry))
        self._emitline()
Esempio n. 34
0
def parse_class_type(die):
    """parse a DW_TAG_class_type. An example XML is the following:

    # <class-decl name='filter_base' size-in-bits='192' is-struct='yes'
                  visibility='default'
                  filepath='/libabigail-1.8/build/../include/abg-comp-filter.h'
                  line='120' column='1' id='type-id-1'>

    TODO: It's not clear how to get visibility "default" here as shown above
    """
    filepath = get_die_filepath(die)

    dmeta = {
        "_type": "class-decl",
        "name": bytes2str(die.attributes["DW_AT_name"].value),
        "is-struct": False,
    }

    # These values are not present in all class declaration DIEs
    if "DW_AT_decl_line" in die.attributes:
        dmeta["line"] = die.attributes["DW_AT_decl_line"].value
    if "DW_AT_decl_column" in die.attributes:
        dmeta["column"] = die.attributes["DW_AT_decl_column"].value
    if "DW_AT_byte_size" in die.attributes:
        dmeta["size-in-bits"] = (die.attributes["DW_AT_byte_size"].value * 8,)

    if filepath:
        dmeta["filepath"] = filepath

    if die.has_children:
        dmeta["children"] = []
    return dmeta
Esempio n. 35
0
    def display_pmd_info_strings(self, section_spec):
        """ Display a strings dump of a section. section_spec is either a
            section number or a name.
        """
        section = self._section_from_spec(section_spec)
        if section is None:
            return

        data = section.data()
        dataptr = 0

        while dataptr < len(data):
            while (dataptr < len(data)
                   and not (32 <= byte2int(data[dataptr]) <= 127)):
                dataptr += 1

            if dataptr >= len(data):
                break

            endptr = dataptr
            while endptr < len(data) and byte2int(data[endptr]) != 0:
                endptr += 1

            mystring = bytes2str(data[dataptr:endptr])
            rc = mystring.find("PMD_INFO_STRING")
            if (rc != -1):
                self.parse_pmd_info_string(mystring)

            dataptr = endptr
Esempio n. 36
0
    def display_pmd_info_strings(self, section_spec):
        """ Display a strings dump of a section. section_spec is either a
            section number or a name.
        """
        section = self._section_from_spec(section_spec)
        if section is None:
            return

        data = section.data()
        dataptr = 0

        while dataptr < len(data):
            while (dataptr < len(data) and
                    not (32 <= byte2int(data[dataptr]) <= 127)):
                dataptr += 1

            if dataptr >= len(data):
                break

            endptr = dataptr
            while endptr < len(data) and byte2int(data[endptr]) != 0:
                endptr += 1

            mystring = bytes2str(data[dataptr:endptr])
            rc = mystring.find("PMD_INFO_STRING")
            if (rc != -1):
                self.parse_pmd_info_string(mystring)

            dataptr = endptr
Esempio n. 37
0
def get_dwz(dwz, offset):
    elffile = ELFFile(dwz)

    for section in elffile.iter_sections():
        name = bytes2str(section.name)
        if name == ".debug_str":
            data = section.data()
            end = data[offset:].find(b"\x00")
            return data[offset:offset + end]
Esempio n. 38
0
def process_file(filename):
    print('In file:', filename)
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)

        for section in elffile.iter_sections():
            # Section names are bytes objects
            if section.name.startswith(b'.debug'):
                print('  ' + bytes2str(section.name))
def process_file(filename):
    print("In file:", filename)
    with open(filename, "rb") as f:
        elffile = ELFFile(f)

        for section in elffile.iter_sections():
            # Section names are bytes objects
            if section.name.startswith(b".debug"):
                print("  " + bytes2str(section.name))
Esempio n. 40
0
def process_file(filename, address):
    print('Processing file:', filename)
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)

        if not elffile.has_dwarf_info():
            print('  file has no DWARF info')
            return

        # get_dwarf_info returns a DWARFInfo context object, which is the
        # starting point for all DWARF-based processing in pyelftools.
        dwarfinfo = elffile.get_dwarf_info()

        funcname = decode_funcname(dwarfinfo, address)
        file, line = decode_file_line(dwarfinfo, address)

        print('Function:', bytes2str(funcname))
        print('File:', bytes2str(file))
        print('Line:', line)
Esempio n. 41
0
def fetch_PC(filename, secname='.symtab'):
    toreturn = 0
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)

        section = elffile.get_section_by_name(str2bytes(secname))
        #print section['sh_entsize']
        if section['sh_entsize'] == 0:
            print("\nSymbol table '%s' has a sh_entsize of zero!" %
                  (bytes2str(section.name)))

        print("Symbol table '%s' contains %s entries" %
              (bytes2str(section.name), section.num_symbols()))

        for nsym, symbol in enumerate(section.iter_symbols()):
            if (bytes2str(symbol.name) == '_start'):
                toreturn = symbol['st_value']

    setPC(toreturn)
Esempio n. 42
0
def process_file(filename, address):
    print('Processing file:', filename)
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)

        if not elffile.has_dwarf_info():
            print('  file has no DWARF info')
            return

        # get_dwarf_info returns a DWARFInfo context object, which is the
        # starting point for all DWARF-based processing in pyelftools.
        dwarfinfo = elffile.get_dwarf_info()

        funcname = decode_funcname(dwarfinfo, address)
        file, line = decode_file_line(dwarfinfo, address)

        print('Function:', bytes2str(funcname))
        print('File:', bytes2str(file))
        print('Line:', line)
Esempio n. 43
0
def stack_cookies_check(elffile):
    for section in elffile.iter_sections():
        if not isinstance(section, SymbolTableSection):
            continue
        if section['sh_entsize'] == 0:
            continue
        for _, symbol in enumerate(section.iter_symbols()):
            if bytes2str(symbol.name) in STACK_CHK:
                return True
    return False
Esempio n. 44
0
def load_lineinfo(dwarfinfo):
    # Load all line infos and all function names into lists
    # Lines contains tuples of startaddr, endaddress, filename, line
    lines = []
    # Functions contains tuples of lowpc, highpc, function
    functions = []
    for CU in dwarfinfo.iter_CUs():
        # First, look at line programs to find the file/line map
        lineprog = dwarfinfo.line_program_for_CU(CU)
        prevstate = None
        for entry in lineprog.get_entries():
            # We're interested in those entries where a new state is assigned
            state = entry.state
            if state is None: continue
            if prevstate and prevstate.address <= state.address and not prevstate.end_sequence:
                file_entry = lineprog['file_entry'][prevstate.file - 1]
                if file_entry.dir_index == 0:
                    # current directory
                    # TODO get directory of source file and prepend it
                    filename = './%s' % (bytes2str(file_entry.name))
                else:
                    filename = '%s/%s' % (bytes2str(
                        lineprog['include_directory'][file_entry.dir_index -
                                                      1]),
                                          bytes2str(file_entry.name))
                line = prevstate.line
                info = prevstate.address, state.address, filename, line
                lines.append(info)
            prevstate = state
        # Go over all DIEs in the DWARF information. Note that
        # this simplifies things by disregarding subprograms that may have
        # split address ranges.
        for DIE in CU.iter_DIEs():
            try:
                if DIE.tag == 'DW_TAG_subprogram':
                    lowpc = DIE.attributes['DW_AT_low_pc'].value
                    highpc = DIE.attributes['DW_AT_high_pc'].value
                    function = DIE.attributes['DW_AT_name'].value
                    info = lowpc, highpc, bytes2str(function)
                    functions.append(info)
            except KeyError:
                continue
    return lines, functions
Esempio n. 45
0
def _get_dependencies(elf_handle):
    shared_libraries = []
    
    for section in elf_handle.iter_sections():
        if isinstance(section, DynamicSection):
            for tag in section.iter_tags():
                if tag.entry.d_tag == 'DT_NEEDED':
                    shared_libraries.append(bytes2str(tag.needed))

    return shared_libraries
Esempio n. 46
0
def get_dwz(path, offset):
    with open(path, "rb") as f:
        elffile = ELFFile(f)

        for section in elffile.iter_sections():
            name = bytes2str(section.name)
            if name == ".debug_str":
                data = section.data()
                end = data[offset:].find(b"\x00")
                return data[offset:offset + end]
Esempio n. 47
0
def fetch_PC(filename, secname='.symtab'):
    toreturn=0
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)
        
        section=elffile.get_section_by_name(str2bytes(secname))
        #print section['sh_entsize']
        if section['sh_entsize'] == 0:
                print("\nSymbol table '%s' has a sh_entsize of zero!" % (
                    bytes2str(section.name)))
                
        print("Symbol table '%s' contains %s entries" % (
                bytes2str(section.name), section.num_symbols()))
        
        for nsym, symbol in enumerate(section.iter_symbols()):
            if(bytes2str(symbol.name)=='_start'):
                toreturn = symbol['st_value']
                 
    setPC(toreturn)
Esempio n. 48
0
    def _load_db(self):
        """Load symbol and section data into the database."""
        # Load ELF section metadata.
        for nsec, section in enumerate(self.elffile.iter_sections()):
            self.db.execute('INSERT INTO sections VALUES (?,?,?,?,?,?,?,?,?,?,?)',
                            (nsec,
                             bytes2str(section.name).strip(),
                             describe_sh_type(section['sh_type']).strip(),
                             describe_sh_flags(section['sh_flags']).strip(),
                             section['sh_addr'],
                             section['sh_offset'],
                             section['sh_size'],
                             section['sh_link'],
                             section['sh_info'],
                             section['sh_addralign'],
                             section['sh_entsize']))
            self.db.commit()

        # Load ELF symbol data into DB.  Adapted from readelf.py.
        for section in self.elffile.iter_sections():
            if not isinstance(section, SymbolTableSection):
                continue
            if section['sh_entsize'] == 0:
                continue
            for nsym, symbol in enumerate(section.iter_symbols()):
                # Get the related section header index and name for this symbol.
                shndx = describe_symbol_shndx(symbol['st_shndx']).strip()
                related_section = None
                if str.isdigit(shndx):
                    sec = self._get_section(shndx)
                    if sec is not None:
                        related_section = sec[1]
                # Write the symbol value to the table.
                self.db.execute('INSERT INTO symbols VALUES (NULL,?,?,?,?,?,?,?,?)',
                                (symbol['st_value'],
                                 symbol['st_size'],
                                 describe_symbol_type(symbol['st_info']['type']).strip(),
                                 describe_symbol_bind(symbol['st_info']['bind']).strip(),
                                 describe_symbol_visibility(symbol['st_other']['visibility']).strip(),
                                 shndx,
                                 bytes2str(symbol.name).strip(),
                                 related_section))
                self.db.commit()
Esempio n. 49
0
    def display_section_headers(self, show_heading=True):
        """ Display the ELF section headers
        """
        elfheader = self.elffile.header
        if show_heading:
            self._emitline('There are %s section headers, starting at offset %s' % (
                elfheader['e_shnum'], self._format_hex(elfheader['e_shoff'])))

        self._emitline('\nSection Header%s:' % (
            's' if elfheader['e_shnum'] > 1 else ''))

        # Different formatting constraints of 32-bit and 64-bit addresses
        #
        if self.elffile.elfclass == 32:
            self._emitline('  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al')
        else:
            self._emitline('  [Nr] Name              Type             Address           Offset')
            self._emitline('       Size              EntSize          Flags  Link  Info  Align')

        # Now the entries
        #
        for nsec, section in enumerate(self.elffile.iter_sections()):
            self._emit('  [%2u] %-17.17s %-15.15s ' % (
                nsec, bytes2str(section.name), describe_sh_type(section['sh_type'])))

            if self.elffile.elfclass == 32:
                self._emitline('%s %s %s %s %3s %2s %3s %2s' % (
                    self._format_hex(section['sh_addr'], fieldsize=8, lead0x=False),
                    self._format_hex(section['sh_offset'], fieldsize=6, lead0x=False),
                    self._format_hex(section['sh_size'], fieldsize=6, lead0x=False),
                    self._format_hex(section['sh_entsize'], fieldsize=2, lead0x=False),
                    describe_sh_flags(section['sh_flags']),
                    section['sh_link'], section['sh_info'],
                    section['sh_addralign']))
            else: # 64
                self._emitline(' %s  %s' % (
                    self._format_hex(section['sh_addr'], fullhex=True, lead0x=False),
                    self._format_hex(section['sh_offset'],
                        fieldsize=16 if section['sh_offset'] > 0xffffffff else 8,
                        lead0x=False)))
                self._emitline('       %s  %s %3s      %2s   %3s     %s' % (
                    self._format_hex(section['sh_size'], fullhex=True, lead0x=False),
                    self._format_hex(section['sh_entsize'], fullhex=True, lead0x=False),
                    describe_sh_flags(section['sh_flags']),
                    section['sh_link'], section['sh_info'],
                    section['sh_addralign']))

        self._emitline('Key to Flags:')
        self._emit('  W (write), A (alloc), X (execute), M (merge), S (strings)')
        if self.elffile['e_machine'] in ('EM_X86_64', 'EM_L10M'):
            self._emitline(', l (large)')
        else:
            self._emitline()
        self._emitline('  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)')
        self._emitline('  O (extra OS processing required) o (OS specific), p (processor specific)')
Esempio n. 50
0
    def display_hex_dump(self, section_spec):
        """ Display a hex dump of a section. section_spec is either a section
            number or a name.
        """
        section = self._section_from_spec(section_spec)
        if section is None:
            self._emitline("Section '%s' does not exist in the file!" %
                           (section_spec))
            return

        self._emitline("\nHex dump of section '%s':" % bytes2str(section.name))
        self._note_relocs_for_section(section)
        addr = section['sh_addr']
        data = section.data()
        dataptr = 0

        while dataptr < len(data):
            bytesleft = len(data) - dataptr
            # chunks of 16 bytes per line
            linebytes = 16 if bytesleft > 16 else bytesleft

            self._emit('  %s ' % self._format_hex(addr, fieldsize=8))
            for i in range(16):
                if i < linebytes:
                    self._emit('%2.2x' % byte2int(data[dataptr + i]))
                else:
                    self._emit('  ')
                if i % 4 == 3:
                    self._emit(' ')

            for i in range(linebytes):
                c = data[dataptr + i:dataptr + i + 1]
                if byte2int(c[0]) >= 32 and byte2int(c[0]) < 0x7f:
                    self._emit(bytes2str(c))
                else:
                    self._emit(bytes2str(b'.'))

            self._emitline()
            addr += linebytes
            dataptr += linebytes

        self._emitline()
Esempio n. 51
0
    def _dump_debug_line_programs(self):
        """ Dump the (decoded) line programs from .debug_line
            The programs are dumped in the order of the CUs they belong to.
        """
        self._emitline('Decoded dump of debug contents of section .debug_line:\n')

        for cu in self._dwarfinfo.iter_CUs():
            lineprogram = self._dwarfinfo.line_program_for_CU(cu)

            cu_filename = ''
            if len(lineprogram['include_directory']) > 0:
                cu_filename = '%s/%s' % (
                    bytes2str(lineprogram['include_directory'][0]),
                    bytes2str(lineprogram['file_entry'][0].name))
            else:
                cu_filename = bytes2str(lineprogram['file_entry'][0].name)

            self._emitline('CU: %s:' % cu_filename)
            self._emitline('File name                            Line number    Starting address')

            # Print each state's file, line and address information. For some
            # instructions other output is needed to be compatible with
            # readelf.
            for entry in lineprogram.get_entries():
                state = entry.state
                if state is None:
                    # Special handling for commands that don't set a new state
                    if entry.command == DW_LNS_set_file:
                        file_entry = lineprogram['file_entry'][entry.args[0] - 1]
                        if file_entry.dir_index == 0:
                            # current directory
                            self._emitline('\n./%s:[++]' % (
                                bytes2str(file_entry.name)))
                        else:
                            self._emitline('\n%s/%s:' % (
                                bytes2str(lineprogram['include_directory'][file_entry.dir_index - 1]),
                                bytes2str(file_entry.name)))
                    elif entry.command == DW_LNE_define_file:
                        self._emitline('%s:' % (
                            bytes2str(lineprogram['include_directory'][entry.args[0].dir_index])))
                elif not state.end_sequence:
                    # readelf doesn't print the state after end_sequence
                    # instructions. I think it's a bug but to be compatible
                    # I don't print them too.
                    self._emitline('%-35s  %11d  %18s' % (
                        bytes2str(lineprogram['file_entry'][state.file - 1].name),
                        state.line,
                        '0' if state.address == 0 else
                               self._format_hex(state.address)))
                if entry.command == DW_LNS_copy:
                    # Another readelf oddity...
                    self._emitline()
Esempio n. 52
0
    def display_hex_dump(self, section_spec):
        """ Display a hex dump of a section. section_spec is either a section
            number or a name.
        """
        section = self._section_from_spec(section_spec)
        if section is None:
            self._emitline("Section '%s' does not exist in the file!" % (
                section_spec))
            return

        self._emitline("\nHex dump of section '%s':" % bytes2str(section.name))
        self._note_relocs_for_section(section)
        addr = section['sh_addr']
        data = section.data()
        dataptr = 0

        while dataptr < len(data):
            bytesleft = len(data) - dataptr
            # chunks of 16 bytes per line
            linebytes = 16 if bytesleft > 16 else bytesleft

            self._emit('  %s ' % self._format_hex(addr, fieldsize=8))
            for i in range(16):
                if i < linebytes:
                    self._emit('%2.2x' % byte2int(data[dataptr + i]))
                else:
                    self._emit('  ')
                if i % 4 == 3:
                    self._emit(' ')

            for i in range(linebytes):
                c = data[dataptr + i : dataptr + i + 1]
                if byte2int(c[0]) >= 32 and byte2int(c[0]) < 0x7f:
                    self._emit(bytes2str(c))
                else:
                    self._emit(bytes2str(b'.'))

            self._emitline()
            addr += linebytes
            dataptr += linebytes

        self._emitline()
Esempio n. 53
0
 def network(self):
     ret = "None"
     for section in self.elffile.iter_sections():
         if not isinstance(section, SymbolTableSection):
             continue
         if section['sh_entsize'] == 0:
             print("\nSymbol table '%s' has a sh_entsize " \
                 "of zero!" % (bytes2str(section.name)), file=sys.stderr)
             continue
         for _, symbol in enumerate(section.iter_symbols()):
             # first match IP_PATTERNS
             for pattern in IP_PATTERNS:
                 if re.match(pattern, bytes2str(symbol.name)):
                     return "network-ip"
             # then match LOCAL_PATTERNS
             for pattern in LOCAL_PATTERNS:
                 if re.match(pattern, bytes2str(symbol.name)):
                     ret = "network-local"
                     break
     return ret
Esempio n. 54
0
def parse_base_type(die):
    """parse a DW_TAG_base_type. Here is the xml equivalent"

    # <type-decl name='__float128' size-in-bits='128' id='type-id-32691'/>
    """
    return {
        "_type": "type-decl",
        "name": bytes2str(die.attributes["DW_AT_name"].value),
        # Size in in bytes, multiply by 8 to get bits
        "size-in-bits": die.attributes["DW_AT_byte_size"].value * 8,
    }
Esempio n. 55
0
def run_exe(exe_path, args):
    """ Runs the given executable as a subprocess, given the
        list of arguments. Captures its return code (rc) and stdout and
        returns a pair: rc, stdout_str
    """
    popen_cmd = [exe_path] + args
    if os.path.splitext(exe_path)[1] == '.py':
        popen_cmd.insert(0, 'python')
    proc = subprocess.Popen(popen_cmd, stdout=subprocess.PIPE)
    proc_stdout = proc.communicate()[0]
    return proc.returncode, bytes2str(proc_stdout)
Esempio n. 56
0
def get_producer(path):
    with open(path, "rb") as f:
        elffile = ELFFile(f)
        dwarfinfo = elffile.get_dwarf_info()

        for CU in dwarfinfo.iter_CUs():
            # DWARFInfo allows to iterate over the compile units
            # contained in the .debug_info section. CU is a CompileUnit
            # object, with some computed attributes (such as its offset
            # in the section) and a header which conforms to the DWARF
            # standard. The access to header elements is, as usual, via
            # item-lookup.
            # print('  Found a compile unit at offset %s, length %s' % (
            #    CU.cu_offset, CU['unit_length']))

            # Start with the top DIE, the root for this CU's DIE tree
            top_DIE = CU.get_top_DIE()
            try:
                attrs = top_DIE.attributes['DW_AT_producer']
                if attrs.form == 'DW_FORM_GNU_strp_alt':
                    # DWARF extensions elfutils recognizes/supports are
                    # described at,
                    #
                    # https://fedorahosted.org/elfutils/wiki/DwarfExtensions
                    #
                    # You can find the alt dwz file by reading the
                    # .gnu_debugaltlink section. Which contains a file name
                    # followed by the build-id of the dwz file. The build-id
                    # symlink will point at the /usr/lib/debug/.dwz/ file.
                    #
                    # export nm=".gnu_debugaltlink"
                    # objdump -s -j $nm /usr/lib/debug/.build-id/XY/34...debug
                    # print("DWZ has the string!")
                    #
                    # DW_FORM_GNU_ref_alt is like DW_FORM_ref, but it refers to
                    # an offset in the .dwz file, not in the main file.
                    # DW_FORM_GNU_strp_alt is like DW_FORM_strp, but it refers
                    # to a string in the .dwz file, not in the main file.
                    for section in elffile.iter_sections():
                        name = bytes2str(section.name)
                        if name == ".gnu_debugaltlink":
                            data = section.data()
                            fdata = data[0:data.find(b"\x00")]
                            i = fdata.find(".dwz/")
                            rpath = os.path.join("/usr/lib/debug/",
                                                 fdata[i:].decode("utf-8"))
                            # offset in alternate (.dwz/...)'s .debug_str"
                            return get_dwz(rpath, offset=attrs.value)
                elif attrs.form == 'DW_FORM_strp':  # lucky ;)
                    return attrs.value
                else:
                    assert 0
            except:
                pass
Esempio n. 57
0
 def network(self):
     ret = "None"
     for section in self.elffile.iter_sections():
         if not isinstance(section, SymbolTableSection):
             continue
         if section['sh_entsize'] == 0:
             print("\nSymbol table '%s' has a sh_entsize " \
                 "of zero!" % (bytes2str(section.name)), file=sys.stderr)
             continue
         for _, symbol in enumerate(section.iter_symbols()):
             # first match IP_PATTERNS
             for pattern in IP_PATTERNS:
                 if re.match(pattern, bytes2str(symbol.name)):
                     return "network-ip"
             # then match LOCAL_PATTERNS
             for pattern in LOCAL_PATTERNS:
                 if re.match(pattern, bytes2str(symbol.name)):
                     ret = "network-local"
                     break
     return ret