Пример #1
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()
Пример #2
0
def _process_subprogram_tag(die, section_offset, M, global_var_data):
    if die.tag != 'DW_TAG_subprogram':
        return

    F = M.funcs.add()
    F.ea = 0
    F.name = get_name(die)
    F.is_entrypoint = 0
    has_frame = False
    frame_regname = ""

    if 'DW_AT_frame_base' in die.attributes:
        frame_attr = die.attributes['DW_AT_frame_base']
        has_frame = True
        loc_expr = "{}".format(
            describe_DWARF_expr(frame_attr.value, die.cu.structs)).split(' ')
        if loc_expr[0][1:][:-1] == "DW_OP_call_frame_cfa":
            lowpc_attr = die.attributes['DW_AT_low_pc']
            #DEBUG("loc_expr {0} {1:x}".format(loc_expr, lowpc_attr.value))
            frame = EH_FRAMES[
                lowpc_attr.value] if lowpc_attr.value in EH_FRAMES else None
            if frame:
                DEBUG("{0:x}, {1}".format(frame['initial_location'], frame))
                for instr in frame.instructions:
                    name = instruction_name(instr.opcode)
                    if name == 'DW_CFA_def_cfa_register':
                        frame_regname = describe_reg_name(
                            instr.args[0], None, False)

    for child in die.iter_children():
        if child.tag != 'DW_TAG_variable':
            continue

        stackvar = F.stack_vars.add()
        stackvar.name = get_name(child)
        stackvar.sp_offset = 0
        stackvar.has_frame = has_frame
        stackvar.reg_name = frame_regname
        (type, size, offset) = get_types(child)
        stackvar.size = size if size > 0 else 0

        if 'DW_AT_location' in child.attributes:
            attr = child.attributes['DW_AT_location']
            if attr.form not in ('DW_FORM_data4', 'DW_FORM_data8',
                                 'DW_FORM_sec_offset'):
                loc_expr = "{}".format(
                    describe_DWARF_expr(attr.value,
                                        child.cu.structs)).split(' ')
                if loc_expr[0][1:][:-1] == 'DW_OP_fbreg':
                    offset = int(loc_expr[1][:-1])
                    stackvar.sp_offset = offset
Пример #3
0
def _process_subprogram_tag(die, section_offset, M, global_var_data):
  if die.tag != 'DW_TAG_subprogram':
    return

  F = M.funcs.add()
  F.ea = 0
  F.name = get_name(die)
  F.is_entrypoint = 0
  has_frame = False
  frame_regname = ""
  
  if 'DW_AT_frame_base' in die.attributes:
    frame_attr = die.attributes['DW_AT_frame_base']
    has_frame = True
    loc_expr = "{}".format(describe_DWARF_expr(frame_attr.value, die.cu.structs)).split(' ')
    if loc_expr[0][1:][:-1] == "DW_OP_call_frame_cfa":
      lowpc_attr = die.attributes['DW_AT_low_pc']
      #DEBUG("loc_expr {0} {1:x}".format(loc_expr, lowpc_attr.value))
      frame = EH_FRAMES[lowpc_attr.value] if lowpc_attr.value in EH_FRAMES else None
      if frame:
        DEBUG("{0:x}, {1}".format(frame['initial_location'], frame))
        for instr in frame.instructions:
          name = instruction_name(instr.opcode)
          if name == 'DW_CFA_def_cfa_register':
            frame_regname =  describe_reg_name(instr.args[0], None, False)

  for child in die.iter_children():
    if child.tag != 'DW_TAG_variable':
      continue
  
    stackvar = F.stack_vars.add()
    stackvar.name = get_name(child)
    stackvar.sp_offset = 0
    stackvar.has_frame = has_frame
    stackvar.reg_name = frame_regname
    (type, size, offset) = get_types(child)
    stackvar.size = size if size > 0 else 0
    
    if 'DW_AT_location' in child.attributes:
      attr = child.attributes['DW_AT_location']
      if attr.form not in ('DW_FORM_data4', 'DW_FORM_data8', 'DW_FORM_sec_offset'):
        loc_expr = "{}".format(describe_DWARF_expr(attr.value, child.cu.structs)).split(' ')
        if loc_expr[0][1:][:-1] == 'DW_OP_fbreg':
          offset = int(loc_expr[1][:-1])
          stackvar.sp_offset = offset
Пример #4
0
def _full_reg_name(regnum):
    regname = describe_reg_name(regnum, None, False)
    if regname:
        return 'r%s (%s)' % (regnum, regname)
    else:
        return 'r%s' % regnum
Пример #5
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()
Пример #6
0
def _full_reg_name(regnum):
  regname = describe_reg_name(regnum, None, False)
  if regname:
    return 'r%s (%s)' % (regnum, regname)
  else:
    return 'r%s' % regnum
Пример #7
0
def dump_eh_frame_table(entry):
    """ dumps an interpreted EH_CFI entry
    """
    if isinstance(entry, CIE):
        emitline(
            '\n%08x %s %s CIE "%s" cf=%d df=%d ra=%d' %
            (entry.offset,
             format_hex(entry['length'], fullhex=True, lead0x=False),
             format_hex(entry['CIE_id'], fullhex=True, lead0x=False),
             bytes2str(entry['augmentation']), entry['code_alignment_factor'],
             entry['data_alignment_factor'], entry['return_address_register']))
        ra_regnum = entry['return_address_register']
    else:  # FDE
        emitline(
            '\n%08x %s %s FDE cie=%08x pc=%s..%s' %
            (entry.offset,
             format_hex(entry['length'], fullhex=True, lead0x=False),
             format_hex(entry['CIE_pointer'], fullhex=True,
                        lead0x=False), entry.cie.offset,
             format_hex(entry['initial_location'], fullhex=True, lead0x=False),
             format_hex(entry['initial_location'] + entry['address_range'],
                        fullhex=True,
                        lead0x=False)))
        ra_regnum = entry.cie['return_address_register']

    # Print the heading row for the decoded table
    emit('   LOC')
    emit('  ' if entry.structs.address_size == 4 else '          ')
    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()

    # print ("\n\nDecoded table:\n"+(str(decoded_table))+"\n\n")

    reg_order = sorted(
        ifilter(lambda r: r != ra_regnum, decoded_table.reg_order))
    if len(decoded_table.reg_order):

        # Headings for the registers
        for regnum in reg_order:
            emit('%-6s' % describe_reg_name(regnum))
        emitline('ra      ')

        # Now include ra_regnum in reg_order to print its values similarly
        # to the other registers.
        reg_order.append(ra_regnum)
    else:
        emitline()

    for line in decoded_table.table:
        emit(format_hex(line['pc'], fullhex=True, lead0x=False))
        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'
            emit('%-6s' % s)
        emitline()
    emitline()
Пример #8
0
    def _handle_stack(self, top, stack):
        opcode_name = top.opcode_name
        args = top.args

        # register location
        if opcode_name[:9] == "DW_OP_reg":
            regnum = opcode_name[9:] if opcode_name[9:] != 'x' else args[0]
            regname = describe_reg_name(int(regnum), _MACHINE_ARCH)
            stack.append(OpPiece(REG, regname, regname, None))

        # register + computation
        elif opcode_name[:10] == "DW_OP_breg":
            regnum = opcode_name[10:] if opcode_name[10:] != 'x' else args[0]
            offset = args[0] if regnum != 'x' else args[1]
            regname = describe_reg_name(int(regnum), _MACHINE_ARCH)
            separator = "+" if offset >= 0 else ""
            stack.append(
                OpPiece(REG, regname, regname + separator + hex(offset), None))

        # frame base offset
        elif opcode_name == "DW_OP_fbreg":
            offset = args[0]
            separator = "+" if offset >= 0 else ""
            stack.append(
                OpPiece(ADDR, "frame base",
                        "frame base" + separator + hex(offset), None))

        # address location
        elif opcode_name[:10] == "DW_OP_addr":
            addr = args[0]
            stack.append(OpPiece(ADDR, hex(addr), hex(addr), None))

        # composite locations
        elif opcode_name == "DW_OP_piece":
            size = args[0]
            prev_piece = stack.pop()
            new_piece = OpPiece(prev_piece.format, prev_piece.key,
                                prev_piece.value, size)
            stack.append(new_piece)
        elif opcode_name == "DW_OP_bit_piece":
            return None, True

        # known value, not location
        elif opcode_name == "DW_OP_implicit_value":
            length = args[0]
            for i in range(length):
                stack.push(OpPiece(VALUE, args[i + 1], args[i + 1], None))
        elif opcode_name == "DW_OP_stack_value" or opcode_name == "OP:0x9f":
            prev_piece = stack.pop()
            # prev_piece.format = VALUE
            stack.append(prev_piece)
            return stack, True  # terminate

        ## literal encodings; DWARF4 2.5.1.1
        elif opcode_name[:9] == "DW_OP_lit":
            stack.append(opcode_name[9])
        elif opcode_name[:11] == "DW_OP_const":
            const = args[0]
            stack.append(const)

        ## stack ops; 2.5.1.3
        elif opcode_name == "DW_OP_dup":
            stack.append(stack[-1])
        elif opcode_name == "DW_OP_drop":
            stack.pop()
        elif opcode_name == "DW_OP_pick":
            index = args[0]
            stack.append(stack[index])
        elif opcode_name == "DW_OP_over":
            stack.append(stack[-2])
        elif opcode_name == "DW_OP_swap":
            old_order = stack[-2:]
            for piece in old_order[::-1]:
                stack.append(piece)
        elif opcode_name == "DW_OP_rot":
            old_order = stack[-3:]
            for piece in old_order[::-1]:
                stack.append(piece)
        elif opcode_name == "DW_OP_deref":
            return None, True
        elif opcode_name == "DW_OP_deref_size":
            return None, True
        elif opcode_name == "DW_OP_xderef":
            return None, True
        elif opcode_name == "DW_OP_xderef_size":
            return None, True
        elif opcode_name == "DW_OP_push_object_address":
            return None, True
        elif opcode_name == "DW_OP_form_tls_address":
            return None, True
        elif opcode_name == "DW_OP_call_frame_cfa":
            return None, True

        # DW_OP_GNU_entry_value
        # pyelftools doesn't know how to parse its args
        elif opcode_name == "OP:0xf3":
            return None, True

        ## arithmetic/logical ops
        elif opcode_name == "DW_OP_abs":
            old = stack.pop()
            try:
                stack.append(abs(old))
            except:
                stack.append(
                    OpPiece(old.format, old.key, "|" + old.value + "|",
                            old.size))
        elif opcode_name == "DW_OP_and":
            first = stack.pop()
            second = stack.pop()
            try:
                stack.append(first & second)
            except:
                new = self._handle_2arg_exception(opcode_name, first, second)
                stack.append(new)
        elif opcode_name == "DW_OP_div":
            first = stack.pop()
            second = stack.pop()
            try:
                stack.append(second / first)
            except:
                new = self._handle_2arg_exception(opcode_name, second, first)
                stack.append(new)
        elif opcode_name == "DW_OP_minus":
            first = stack.pop()
            second = stack.pop()
            try:
                stack.append(second - first)
            except:
                new = self._handle_2arg_exception(opcode_name, second, first)
                stack.append(new)
        elif opcode_name == "DW_OP_mod":
            first = stack.pop()
            second = stack.pop()
            try:
                stack.append(second % first)
            except:
                new = self._handle_2arg_exception(opcode_name, second, first)
                stack.append(new)
        elif opcode_name == "DW_OP_mul":
            first = stack.pop()
            second = stack.pop()
            try:
                stack.append(second * first)
            except:
                new = self._handle_2arg_exception(opcode_name, first, second)
                stack.append(new)
        elif opcode_name == "DW_OP_neg":
            first = stack.pop()
            try:
                stack.append(-first)
            except:
                stack.append(
                    OpPiece(first.format, first.key, '-' + first.value,
                            first.size))
        elif opcode_name == "DW_OP_not":
            first = stack.pop()
            try:
                stack.append(~first)
            except:
                stack.append(
                    OpPiece(first.format, first.key, '~' + first.value,
                            first.size))
        elif opcode_name == "DW_OP_or":
            first = stack.pop()
            second = stack.pop()
            try:
                stack.append(second | first)
            except:
                new = self._handle_2arg_exception(opcode_name, first, second)
                stack.append(new)
        elif opcode_name == "DW_OP_plus":
            first = stack.pop()
            second = stack.pop()
            try:
                stack.append(second + first)
            except:
                new = self._handle_2arg_exception(opcode_name, first, second)
                stack.append(new)
        elif opcode_name == "DW_OP_plus_uconst":
            first = stack.pop()
            second = args[0]
            try:
                stack.append(first + second)
            except:
                stack.append(
                    OpPiece(first.format, first.key,
                            first.value + "+" + second, first.size))
        elif opcode_name == "DW_OP_shl":
            return None, True
        elif opcode_name == "DW_OP_shr":
            return None, True
        elif opcode_name == "DW_OP_shra":
            return None, True
        elif opcode_name == "DW_OP_xor":
            first = stack.pop()
            second = stack.pop()
            try:
                stack.append(second ^ first)
            except:
                new = self._handle_2arg_exception(opcode_name, first, second)
                stack.append(new)

        ## control flow ops
        elif opcode_name == "DW_OP_le":
            first = stack.pop()
            second = stack.pop()
            if second <= first:
                stack.append(1)
            else:
                stack.append(0)
        elif opcode_name == "DW_OP_ge":
            first = stack.pop()
            second = stack.pop()
            if second >= first:
                stack.append(1)
            else:
                stack.append(0)
        elif opcode_name == "DW_OP_eq":
            first = stack.pop()
            second = stack.pop()
            if second == first:
                stack.append(1)
            else:
                stack.append(0)
        elif opcode_name == "DW_OP_lt":
            first = stack.pop()
            second = stack.pop()
            if second < first:
                stack.append(1)
            else:
                stack.append(0)
        elif opcode_name == "DW_OP_gt":
            first = stack.pop()
            second = stack.pop()
            if second > first:
                stack.append(1)
            else:
                stack.append(0)
        elif opcode_name == "DW_OP_ne":
            first = stack.pop()
            second = stack.pop()
            if second != first:
                stack.append(1)
            else:
                stack.append(0)
        elif opcode_name == "DW_OP_skip":
            return None, True
        elif opcode_name == "DW_OP_bra":
            return None, True

        # OP:0xf3
        else:
            return None, True

        return stack, False
Пример #9
0
    def _after_visit(self, opcode, args) -> Optional[bool]:
        if opcode == DW_OP_stack_value:
            # The value on the stack is the actual value, not the location.
            self._is_stack_value = True
            return False
        elif opcode in self._const_ops:
            self._stack.append(args[0])
        elif DW_OP_lit0 <= opcode and opcode <= DW_OP_lit31:
            self._stack.append(opcode - DW_OP_lit0)
        elif DW_OP_reg0 <= opcode and opcode <= DW_OP_reg31:
            regnum = opcode - DW_OP_reg0
            self._stack.append(describe_reg_name(regnum, self._arch))
        elif DW_OP_breg0 <= opcode and opcode <= DW_OP_breg31:
            regnum = opcode - DW_OP_breg0
            regname = describe_reg_name(regnum, self._arch)
            self._stack.extend([regname, args[0], ExprOp.ADD])
            self._stack.append(ExprOp.DYNAMIC)
            return False
        elif opcode == DW_OP_fbreg and isinstance(self._frame_base, ExprOp):
            self._stack.extend([self._frame_base, args[0], ExprOp.ADD])
        elif opcode == DW_OP_fbreg and self._frame_base is None:
            self._stack.extend([ExprOp.CFA, args[0], ExprOp.ADD])
        elif opcode == DW_OP_regx:
            regnum = args[0]
            if regnum < len(_REG_NAMES_x64):
                regname = describe_reg_name(regnum, self._arch)
                self._stack.append(regname)
            else:
                print('Unsupported reg num:', regnum)
        elif opcode == DW_OP_piece and len(self._stack) == 0:
            # if you run into a DW_OP_piece and the expression stack is
            # empty, then the bytes for the piece are optimized out.
            pass
        elif opcode == DW_OP_piece and len(self._stack) > 0 and isinstance(
                self.stack[-1], str):
            # if you run into a DW_OP_piece and it refers to a register
            # then select the subrange.
            self._stack.extend([args[0], ExprOp.VAR_FIELD])
        elif opcode == DW_OP_bit_piece and len(self._stack) == 0:
            # if you run into a DW_OP_bit_piece and the expression stack is
            # empty, then the bits for the piece are optimized out.
            pass
        elif opcode == DW_OP_bit_piece and len(self._stack) > 0 and isinstance(
                self.stack[-1], str) and args[1] == 0:
            # the location is only the lower `args[0]` bits of the register.
            pass
        elif opcode == DW_OP_call_frame_cfa:
            # assert(self._is_setting_frame_base)
            self._stack.append(ExprOp.CFA)
        elif opcode in self._dynamic_ops:
            self._stack.append(ExprOp.DYNAMIC)
            return False
        elif opcode == DW_OP_plus:
            self._stack.append(ExprOp.ADD)
        elif opcode == DW_OP_not:
            self._stack.append(ExprOp.NOT)
        elif opcode == DW_OP_neg:
            self._stack.append(ExprOp.NEG)
        elif opcode == DW_OP_or:
            self._stack.append(ExprOp.OR)
        elif opcode == DW_OP_ne:
            self._stack.append(ExprOp.NE)
        elif opcode == DW_OP_eq:
            self._stack.append(ExprOp.EQ)
        elif opcode == DW_OP_le:
            self._stack.append(ExprOp.LE)
        elif opcode == DW_OP_ge:
            self._stack.append(ExprOp.GE)
        elif opcode == DW_OP_gt:
            self._stack.append(ExprOp.GT)
        elif opcode == DW_OP_lt:
            self._stack.append(ExprOp.LT)
        elif opcode == DW_OP_and:
            self._stack.append(ExprOp.AND)
        elif opcode == DW_OP_minus:
            self._stack.append(ExprOp.MINUS)
        elif opcode == DW_OP_shra:
            self._stack.append(ExprOp.ASHR)
        elif opcode == DW_OP_xor:
            self._stack.append(ExprOp.XOR)
        elif opcode == DW_OP_mul:
            self._stack.append(ExprOp.MUL)
        elif opcode == DW_OP_mod:
            self._stack.append(ExprOp.MOD)
        elif opcode == DW_OP_div:
            self._stack.append(ExprOp.DIV)
        elif opcode == DW_OP_shr:
            self._stack.append(ExprOp.SHR)
        elif opcode == DW_OP_plus_uconst:
            self._stack.append(ExprOp.PLUS_IMM)
        elif opcode == DW_OP_over:
            self._stack.append(ExprOp.OVER)
        elif opcode == DW_OP_implicit_value:
            v = int.from_bytes(args[0], 'little')
            self._stack.append(v)
            self._is_stack_value = True

        elif DW_OP_lo_user <= opcode and opcode <= DW_OP_hi_user:
            self._stack.append(ExprOp.UNSUPPORTED)
            return False
        elif opcode in self._unsupported_ops:
            self._stack.append(ExprOp.UNSUPPORTED)
            return False
        else:
            if not self._is_setting_frame_base:
                print('Expr:', [hex(x) for x in self.save_expr])
                print('Args:', args)
                print('Stack:', self._stack)
                print('Frame:', self._frame_base)
                raise Exception(
                    f'unimplemented opcode: {hex(opcode)} {DW_OP_opcode2name.get(opcode,"UNK")}\nFrame: {self._frame_base}'
                )