def context(self): """ """ context = Context() context.set_code_segment(0x100000) context.set_data_segment(0x200000) context.set_symbolic(False) return context
def context(self): """ """ context = Context() context.set_code_segment(self._init_code_address) context.set_data_segment(self._init_data_address) context.set_symbolic(False) context.set_absolute(True) return context
def _compute_reset_code(target, test_def, args): instructions = interpret_asm( test_def.code, target, [var.name for var in test_def.variables], show_progress=True, ) # TODO: This can be done in parallel or look for speed up the process instructions = [ instruction_from_definition(instr) for instr in instructions ] instruction_dict = {} address = test_def.default_code_address progress = Progress( len(test_def.roi_memory_access_trace), msg="Building instruction dictionary", ) for instr in instructions: progress() if instr.address is not None: if instr.address.base_address == "code": address = test_def.default_code_address + \ instr.address.displacement instr.set_address(address) else: address = address + instr.architecture_type.format.length instr.set_address(address) instruction_dict[instr.address] = instr free_regs = [] written_after_read_regs = [] read_regs = [] level = 0 dynamic_count = 0 progress = Progress( len(test_def.roi_memory_access_trace), msg="Evaluating register usage", ) reset_regs = set() for access in test_def.roi_memory_access_trace: progress() if access.data_type == "D": continue dynamic_count += 1 try: instr = instruction_dict[access.address] uses = instruction_dict[access.address].uses() sets = instruction_dict[access.address].sets() except KeyError: print_error( "Access to from instruction at address " "0x%016X registered but such instruction is not" " present in the definition." % access.address, ) exit(1) # Calls if instr.mnemonic == "BL": level += 1 elif instr.mnemonic == "BCL": level += 1 elif instr.mnemonic == "BCCTRL": if instr.operands()[2].value in [0, 3]: level += 1 # Returns if instr.mnemonic == "BCLR": if (((instr.operands()[0].value & 0b10100) == 20) and (instr.operands()[2].value == 0)): level -= 1 # TODO: this should include Z and RISCV instructions for call # and return, but currently we do not have memory access traces # for such platforms for reg in uses: if reg not in read_regs: read_regs.append(reg) for reg in sets: if reg in free_regs: continue elif reg not in read_regs: free_regs.append(reg) elif reg not in written_after_read_regs: written_after_read_regs.append(reg) reset_regs = set(read_regs).intersection( set(written_after_read_regs), ) reset_regs = sorted(reset_regs) assert len(free_regs) == len(set(free_regs)) assert len(set(free_regs).intersection(set(reset_regs))) == 0 if len(test_def.roi_memory_access_trace) == 0: # We do not have memory access trace, assume calling conventions reset_regs = target.volatile_registers reset_regs = [ reg for reg in reset_regs if reg in target.volatile_registers] if len(reset_regs) == 0 and len(test_def.roi_memory_access_trace) == 0: print_info( "No memory access trace found. Resetting volatile registers." ) reset_regs = target.volatile_registers unused_regs = sorted( (reg for reg in target.registers.values() if reg not in read_regs), ) # # Make sure scratch registers are reset last # for reg in target.scratch_registers: if reg in reset_regs: reset_regs.remove(reg) reset_regs.append(reg) free_regs = unused_regs + free_regs # Know which ones are not used (or written) and which ones are used # Use them as base / temporal registers for addresses # Check addresses conflict_addresses = {} new_ins = [] progress = Progress( len(test_def.roi_memory_access_trace), msg="Evaluating memory usage", ) for access in test_def.roi_memory_access_trace: progress() if access.data_type == "I": continue val = conflict_addresses.get( access.address, [access.length, access.access_type], ) if access.access_type not in val[1]: val[1] += access.access_type val[0] = max(val[0], access.length) conflict_addresses[access.address] = val fix_addresses = [] for address in conflict_addresses: value = conflict_addresses[address] if value[1] == "RW": wvalue = None for var in test_def.variables: if var.var_type.upper() in ["CHAR", "UINT8_T"]: elem_size = 1 else: raise NotImplementedError end_address = var.address + var.num_elements * elem_size if var.address <= address <= end_address: offset = int((address - var.address) / elem_size) svalue = var.init_value[ offset:offset + int(value[0] / elem_size) ] svalue = "".join(["%02X" % tval for tval in svalue]) wvalue = int(svalue, 16) break if wvalue is None: print_error( "Unable to restore original value for address 0x%X" % address, ) exit(1) if value[0] <= 8: fix_addresses.append((address, value[0], wvalue)) else: for selem in range(0, value[0]//8): sfmt = "%%0%dX" % (2*value[0]) nvalue = sfmt % wvalue nvalue = int(nvalue[selem*16:(selem+1)*16], 16) fix_addresses.append( (address + selem * 8, 8, nvalue) ) reset_steps = [] context = Context() context.set_symbolic(True) if len(fix_addresses) > 0: # TODO: This can be optimized. Reduce the number of instructions to # be added by sorting the reset code (shared values or similar # addresses) # TODO: This can be optimized for use vector registers when # needed # print_info("Adding instructions to reset memory state") reset_register = [ reg for reg in free_regs if reg.type.used_for_address_arithmetic and reg.name != "GPR0" ][0] for address, length, value in fix_addresses: address_obj = Address(base_address="data", displacement=address) new_instructions = target.set_register( reset_register, value, context, opt=False, ) for ins in new_instructions: ins.add_comment( "Reset code. Setting %s to 0X%016X" % (reset_register.name, value), ) reset_steps.append([new_instructions[:], reset_register, value]) context.set_register_value(reset_register, value) try: store_ins = target.store_integer( reset_register, address_obj, length * 8, context, ) new_instructions += store_ins reset_steps.append( [store_ins, reset_register, address_obj, length], ) except MicroprobeCodeGenerationError: areg = [ reg for reg in free_regs if reg.type.used_for_address_arithmetic and reg.name != "GPR0" ][1] set_ins = target.set_register( areg, address, context, opt=False, ) new_instructions += set_ins reset_steps.append([set_ins, areg, address_obj]) context.set_register_value(areg, address_obj) store_ins = target.store_integer( reset_register, address_obj, length * 8, context, ) new_instructions += store_ins reset_steps.append( [store_ins, reset_register, address_obj, length], ) for ins in set_ins: ins.add_comment( "Reset code. Setting %s to 0X%016X" % (areg.name, address), ) for ins in store_ins: ins.add_comment( "Reset code. Setting mem content in 0X%016X" % (address), ) new_ins.extend(new_instructions) # Reset contents of used registers for reset_register in reset_regs: try: value = [ reg for reg in test_def.registers if reg.name == reset_register.name ][0].value except IndexError: continue new_instructions = target.set_register( reset_register, value, context, opt=False, ) reset_steps.append([new_instructions, reset_register, value]) context.set_register_value(reset_register, value) for ins in new_instructions: ins.add_comment( "Reset code. Setting %s to 0X%016X" % (reset_register.name, value), ) new_ins.extend(new_instructions) try: overhead = (((len(new_ins) * 1.0) / dynamic_count) * 100) except ZeroDivisionError: print_warning("Unable to compute overhead. Zero dynamic instruction " "count") overhead = 0 print_info( "%03.2f%% overhead added by resetting code" % overhead, ) if overhead > args['wrap_endless_threshold']: print_error( "Instructions added: %d" % len(new_ins), ) print_error( "Total instructions: %d" % dynamic_count, ) print_error( "Reset code above --wrap-endless-threshold. Stopping generation.", ) exit(1) return new_ins, overhead, reset_steps
def _shift_and_fix_code( target, code, offset, addresses, reset_steps, registers, ): """Shift code and fix reset code.""" scode = [] for instruction in code: instruction = instruction.copy() # Fix and shift decorators (not need to modify code) for key, values in instruction.decorators.items(): if not isinstance(values, list): values = [values] if key in ['MA', 'BT']: for idx in range(0, len(values)): if addresses[0] <= values[idx] <= addresses[1]: values[idx] = values[idx] + offset scode.append(instruction) cidx = 0 context = Context() context.set_symbolic(False) for reset_step in reset_steps: rins = reset_step[0] cins = scode[cidx:cidx+len(rins)] rreg = reset_step[1] try: rval = [reg for reg in registers if reg.name == rreg.name][0].value except IndexError: # This was a support register to compute an address, # it should be fixed rval = 0 for rin, cin in zip(rins, cins): if rin.name != cin.instruction_type.name: print_error("Unable to fix the reset code") exit(1) if len(reset_step) == 3: rins, reset_register, value = reset_step if not isinstance(value, six.integer_types): # All addresses should be offset value += offset nins = target.set_register( reset_register, value.displacement, context, opt=False, ) print_info( "Fixing reset code for reg: %s. " "New value: 0x%016X" % (rreg.name, value.displacement), ) else: if abs(value-rval) == offset: # This has been shifted, force offset value += offset print_info( "Fixing reset code for reg: %s. " "New value: 0x%016X" % (rreg.name, value), ) nins = target.set_register( reset_register, value, context, opt=False, ) context.set_register_value(reset_register, value) elif len(reset_step) == 4: rins, reset_register, address_obj, length = reset_step # All addresses should be offsetted address_obj += offset nins = target.store_integer( reset_register, address_obj, length * 8, context, ) print_info( "Fixing reset code for reg: %s. " "New value: 0x%016X" % (rreg.name, address_obj.displacement), ) else: raise NotImplementedError( "Unable to shift and fix code" ) if len(rins) != len(nins): print_error("Original resetting code:") for ins in rins: print_error(ins.assembly()) print_error("New resetting code:") for ins in nins: print_error(ins.assembly()) print_error("New resetting code differs from original in length") exit(1) for ins in nins: if len(reset_step) == 3: if not isinstance(value, six.integer_types): value = value.displacement ins.add_comment( "Reset code. Setting %s to 0X%016X" % (reset_register.name, value), ) else: ins.add_comment( "Reset code. Setting mem content in 0X%016X" % (address_obj.displacement), ) for idx, (nin, cin) in enumerate(zip(nins, cins)): if nin.name != cin.instruction_type.name: print_warning("New code differs from original in opcodes") scode[cidx+idx] = instruction_to_definition(nin) scode[cidx+idx].comments = scode[cidx+idx].comments[1:] cidx += len(rins) return scode