Exemplo n.º 1
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
Exemplo n.º 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
Exemplo n.º 3
0
 def assertInstruction(self, instr, name, args):
     self.assertIsInstance(instr, CallFrameInstruction)
     self.assertEqual(instruction_name(instr.opcode), name)
     self.assertEqual(instr.args, args)
Exemplo n.º 4
0
 def assertInstruction(self, instr, name, args):
     self.assertIsInstance(instr, CallFrameInstruction)
     self.assertEqual(instruction_name(instr.opcode), name)
     self.assertEqual(instr.args, args)
Exemplo n.º 5
0
def run(inelf, outbin):
    elf = ELFFile(open(inelf, "rb"))

    # go trhough all symbols

    symtable = {}
    addr_set = []
    symtable_section = elf.get_section_by_name(".symtab")

    for symbol in symtable_section.iter_symbols():
        try:
            if not elf.get_section(symbol.entry.st_shndx).name.startswith(".text"):
                continue
        except TypeError:
            continue
        if symbol.entry.st_value in addr_set:
            continue
        if not is_good_symbol(symbol.name):
            continue
        symtable[symbol.name] = symbol.entry.st_value
        addr_set.append(symbol.entry.st_value)

    # generate debug table

    dbgtable = {}
    dbgdata = elf.get_dwarf_info()

    # go over dbg CFI (common informations)
    fdes = [x for x in dbgdata.CFI_entries() if isinstance(x, FDE)]
    fde: FDE

    for fde in fdes:
        cie: CIE = fde.cie

        base_address = fde.header.initial_location
        if base_address < 0x08000000:  # not in flash
            continue
            
        instructions = cie.instructions + fde.instructions

        block_start = base_address
        block_end   = block_start
        cfe_offset = 0
        pc_addr_offset = 0
        is_lx      = True

        LX_REGNO = 14

        code_mult = cie.header.code_alignment_factor
        data_mult = cie.header.data_alignment_factor

        stack = []

        def do_add():
            nonlocal block_start, block_end

            if is_lx and cfe_offset == 0:
                unwind_offset = -32768
            elif is_lx:
                unwind_offset = -cfe_offset
            else:
                unwind_offset = cfe_offset + pc_addr_offset

            dbgtable[(block_start, block_end)] = unwind_offset
            block_start = block_end

        for instruction in instructions:
            opcode = instruction_name(instruction.opcode)
            if opcode.startswith("DW_CFA_advance_loc") and opcode[-1] in "c1248":
                if instruction.args[0] < 0:
                    print("ia0", instruction.args[0])
                block_end += instruction.args[0] * code_mult
                if block_start != block_end:
                    do_add()
            elif opcode == "DW_CFA_set_loc":
                block_end = instruction.args[0]
                if block_end < block_start:
                    print("dw_cfa_set_loc backwards to", block_end)
                if block_start != block_end:
                    do_add()
            elif opcode.startswith("DW_CFA_def_cfa_offset"):
                cfe_offset = instruction.args[0]
            elif opcode.startswith("DW_CFA_offset"):
                if instruction.args[0] == LX_REGNO:
                    # are we changing the location of r14?
                    is_lx = False
                    pc_addr_offset = instruction.args[1] * data_mult
            elif opcode == "DW_CFA_remember_state":
                stack.append((cfe_offset, pc_addr_offset, is_lx))
            elif opcode == "DW_CFA_restore_state":
                (cfe_offset, pc_addr_offset, is_lx) = stack.pop(-1)
            elif opcode == "DW_CFA_restore" or opcode == "DW_CFA_restore_extended":
                if instruction.args[0] == LX_REGNO:
                    is_lx = True
                    pc_addr_offset = 0

        block_end = base_address + fde.header.address_range 
        if block_end < block_start:
            block_start, block_end = block_end, block_start
        do_add()

    #print(dbgtable)

    # optimize table
    dbgtable_optimized = []
    for (start, end), offs in sorted(dbgtable.items(), key=lambda x: x[0][0]):
        if dbgtable_optimized:
            if dbgtable_optimized[-1][1] == start and dbgtable_optimized[-1][2] == offs:
                dbgtable_optimized[-1][1] = end
                continue
        dbgtable_optimized.append([start, end, offs])

    # output in sorted form

    f1 = io.BytesIO()  # symbol table
    f2 = io.BytesIO()  # unwind table

    for name, addr in sorted(symtable.items(), key=lambda x: x[1]):
        f1.write(struct.pack(">I", addr))
        f1.write(process_name(cxxfilt.demangle(name)).encode('ascii'))
        f1.write(b'\x00')

    for start, end, offs in dbgtable_optimized:
        if end < start:
            print("{:08x} - {:08x} = {}".format(start, end, offs))
        f2.write(struct.pack(">IHh", start, (end - start), offs))

    blob1 = lowmemcompress(f1.getvalue())
    blob2 = lowmemcompress(f2.getvalue())

    with open(outbin, "wb") as f:
        f.write(struct.pack("<I", len(blob1)))
        f.write(blob1)
        f.write(blob2)