예제 #1
0
    def cmp_func():
        func_new_size = func_new_dio.get_size()
        func_obj_size = func_obj_dio.get_size()

        if func_new_size != func_obj_size:
            raise Exception("Function {} size mismatch".format(func_new_dio))
        func_size = func_new_size

        reloc_map = {}
        for rel_type, rel_offset, key in relocs:
            reloc_map[rel_offset] = RELOC_SIZES[rel_type]
        assert len(reloc_map) == len(relocs)

        func_new_code = read(new_text_sec, func_new_addr, func_size)
        func_obj_code = read(obj_text_sec, func_obj_addr, func_size)

        next_offset = 0
        for offset, (x_new,
                     x_obj) in enumerate(zip(func_new_code, func_obj_code)):
            skip = reloc_map.get(offset)
            if skip:
                next_offset = offset + skip
            if offset < next_offset:
                continue

            if x_new != x_obj:
                raise Exception(
                    "Code mismatch for function {} at offset {}".format(
                        debuginfo.format_di_key(func_di_key), offset))
예제 #2
0
    def get_relocs(self, check_symbol=None):
        elf = self.elf
        di_reloc = self.di_reloc
        symtab = di_reloc.symtab
        get_di_key = self.get_di_key
        result = {}

        def append_rel():
            reloc_list.append((rel_type, rel.entry.r_offset, key))

        for sec in elf.iter_sections():
            if not sec.name.startswith('.rela.text'):
                continue
            if sec.header.sh_link != di_reloc.sym_sec_idx:
                raise Exception("Symbol table mismatch")

            print "== Processing", sec.name,
            text_sec_idx = sec.header.sh_info
            text_sec = elf.get_section(text_sec_idx)
            print "=>", text_sec.name

            func_di_key = get_di_key(text_sec_idx)
            reloc_list = []
            result[func_di_key] = (text_sec, reloc_list)

            for rel in sec.iter_relocations():
                rel_type = rel.entry.r_info_type
                rel_size = RELOC_SIZES[rel_type]

                sym = symtab.get_symbol(rel.entry.r_info_sym)
                check_symbol and check_symbol(rel, sym)
                sym_bind = sym.entry.st_info.bind
                target_sec_idx = sym.entry.st_shndx
                target_sec = elf.get_section(target_sec_idx) \
                  if isinstance(target_sec_idx, INT_TYPES) else None
                target_sec_name = target_sec.name if target_sec else target_sec_idx

                if sym_bind == STR.STB_GLOBAL:
                    key = key_repr = sym.name
                elif sym_bind == STR.STB_LOCAL:
                    if not should_resolve(target_sec):
                        key = None
                        append_rel()
                        continue

                    key = get_di_key(target_sec_idx)
                    key_repr = debuginfo.format_di_key(key)
                else:
                    assert 0

                append_rel()
                print "  +{:<5d} {:40s} {}".format(rel.entry.r_offset,
                                                   target_sec_name, key_repr)

        return result
예제 #3
0
def resolve(old_elf, new_elf, obj_seq):
    obj_seq = list(obj_seq)

    old_elf_di = debuginfo.get_debug_info(old_elf)
    old_elf_cus = set(old_elf_di.get_cu_names())

    new_elf_di = debuginfo.get_debug_info(new_elf)
    new_elf_cus = set(new_elf_di.get_cu_names())

    if not (new_elf_cus <= old_elf_cus):
        print "NEW CUs", " ".join(new_elf_cus)
        print "OLD CUs", " ".join(old_elf_cus)
        raise Exception("CU mismatch")

    obj_cus = set()
    for obj in obj_seq:
        obj_di = debuginfo.get_debug_info(obj)
        obj_cus.update(obj_di.get_cu_names())

    if new_elf_cus != obj_cus:
        print "NEW CUs", " ".join(new_elf_cus)
        print "OBJ CUs", " ".join(obj_cus)
        raise Exception("CU mismatch")

    new_text_sec = new_elf.get_section_by_name('.text')

    def read(sec, addr, size):
        stream = sec.stream
        pos = addr - sec.header.sh_addr + sec.header.sh_offset

        stream.seek(pos)
        data = stream.read(size)
        assert len(data) == size
        return data

    def read_num(sec, addr, size):
        data = read(sec, addr, size)

        result = 0
        shift = 0
        for b in data:
            result += ord(b) << shift
            shift += 8
        return result

    def sign_extend(n, low_bits, high_bits):
        low_sign = 1 << (low_bits - 1)
        low_lim = low_sign << 1
        high_lim = 1 << high_bits
        assert 0 <= n < low_lim
        sign = n & low_sign
        return n + high_lim - low_lim if sign else n

    def get_addr(elf, key):
        if isinstance(key, basestring):
            symtab = get_module_symtab(elf)
            sym = symtab.get_sym(key)
            return sym.entry.st_value
        else:
            di = debuginfo.get_debug_info(elf)
            return di.get_dio_by_key(key).get_addr()

    def cmp_func():
        func_new_size = func_new_dio.get_size()
        func_obj_size = func_obj_dio.get_size()

        if func_new_size != func_obj_size:
            raise Exception("Function {} size mismatch".format(func_new_dio))
        func_size = func_new_size

        reloc_map = {}
        for rel_type, rel_offset, key in relocs:
            reloc_map[rel_offset] = RELOC_SIZES[rel_type]
        assert len(reloc_map) == len(relocs)

        func_new_code = read(new_text_sec, func_new_addr, func_size)
        func_obj_code = read(obj_text_sec, func_obj_addr, func_size)

        next_offset = 0
        for offset, (x_new,
                     x_obj) in enumerate(zip(func_new_code, func_obj_code)):
            skip = reloc_map.get(offset)
            if skip:
                next_offset = offset + skip
            if offset < next_offset:
                continue

            if x_new != x_obj:
                raise Exception(
                    "Code mismatch for function {} at offset {}".format(
                        debuginfo.format_di_key(func_di_key), offset))

    result = []
    modulo = 1 << 64
    format_key = lambda: key if isinstance(key, basestring
                                           ) else debuginfo.format_di_key(key)
    check_sym = functools.partial(check_interposable,
                                  get_module_symtab(new_elf).module_sym_names)
    for obj in obj_seq:
        obj_di = debuginfo.get_debug_info(obj)
        for func_di_key, (
                obj_text_sec,
                relocs) in ObjectFile(obj).get_relocs(check_sym).iteritems():
            func_new_dio = new_elf_di.get_dio_by_key(func_di_key)
            func_obj_dio = obj_di.get_dio_by_key(func_di_key)

            func_new_addr = func_new_dio.get_addr()
            func_obj_addr = func_obj_dio.get_addr()

            cmp_func()

            for rel_type, rel_offset, key in relocs:
                if rel_type not in RELOC_PIC_TYPES:
                    continue
                if key is None:
                    continue

                patch_address = func_new_addr + rel_offset

                old_addr = get_addr(old_elf, key)
                if not old_addr:
                    print "!! {} is absent in old ELF".format(format_key())
                    continue

                rel_size = RELOC_SIZES[rel_type]
                rel_value = read_num(new_text_sec, patch_address, rel_size)
                if rel_size < 8:
                    rel_value = sign_extend(rel_value, 8 * rel_size, 64)

                new_addr = get_addr(new_elf, key)
                # Emulate arithmetic modulo 2**64
                # To get final address, one should subtract base load address of new ELF, and
                # add base load address of old ELF  (zero for executables).  This calculation
                # should also be made with modulo arithmetic. Then, for small relocation size
                # one should verify that truncated value sign-extends to the full value.
                target_value = (rel_value + old_addr - new_addr) % modulo

                result.append((rel_size, patch_address, target_value))

    return result