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
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
def assertInstruction(self, instr, name, args): self.assertIsInstance(instr, CallFrameInstruction) self.assertEqual(instruction_name(instr.opcode), name) self.assertEqual(instr.args, args)
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)