def get_closest_address_value(self, address): """Returns the closest address to the given address. Returns the closest address to the given address. If there are not addresses registered, `None` is returned. :param address: Address to look for :type address: :class:`~.Address` """ possible_regs = [] for reg, value in self._register_values[0].items(): if not isinstance(value, Address): continue if Address(base_address=value.base_address) == \ Address(base_address=address.base_address): possible_regs.append((reg, value)) possible_regs = sorted( possible_regs, key=lambda x: abs(x[1].displacement - address.displacement)) if possible_regs: return possible_regs[0] return None
def elf_abi(self, stack_size, start_symbol, **kwargs): """ """ stack = VariableArray(kwargs.get("stack_name", "microprobe_stack"), "uint8_t", stack_size, align=kwargs.get("stack_alignment", 16), address=kwargs.get("stack_address", None)) instructions = [] instructions += self.target.set_register_to_address( self.stack_pointer, Address(base_address=kwargs.get("stack_name", "microprobe_stack")), Context()) if self.stack_direction == "decrease": instructions += self.target.add_to_register( self.stack_pointer, stack_size) if start_symbol is not None: instructions += self.target.function_call(start_symbol) instructions += self.target.function_call("ELF_ABI_EXIT") instructions[0].set_label("ELF_ABI_START") return [stack], instructions
def __init__(self, variables, code_init=False): """ :param variables: """ super(DeclareVariablesPass, self).__init__() self._variables = [] self._code_init = code_init for name, vartype, elems, address, align, init_value in variables: kwargs = {} if align is not None: kwargs["align"] = align if address is not None: address = Address(base_address="data", displacement=address) kwargs["address"] = address if init_value is not None: kwargs["value"] = init_value if elems > 1: var = microprobe.code.var.VariableArray( name, vartype, elems, **kwargs) else: var = microprobe.code.var.VariableSingle( name, vartype, **kwargs) self._variables.append(var) self._description = "Declaring variables: %s" % [ str(var) for var in self._variables ]
def _fix_instr_definition(instr_def, asm, target): if instr_def.instruction_type.name == 'raw': return instr_def labelmatch = re.search("^.*<(.*.)>.*$", asm) label = None if labelmatch is not None: label = labelmatch.group(1) instruction = target.new_instruction(instr_def.instruction_type.name) operands = list(instr_def.operands) for idx, operand in enumerate(instruction.operands()): if operand.type.address_relative and label is not None: operands[idx] = Address(base_address=label.upper()) operand.set_value(operands[idx]) instr_def = MicroprobeInstructionDefinition( instr_def.instruction_type, operands, instr_def.label, instr_def.address, instruction.assembly(), instr_def.decorators, instr_def.comments ) return instr_def
def _check_assembly_string(base_asm, instr_type, target, operands): """ :param base_asm: :type base_asm: :param instr_type: :type instr_type: :param target: :type target: :param operands: :type operands: """ LOG.debug("Start checking assembly string: %s", base_asm) operands = list(operands) relocation_mode = False for idx, operand in enumerate(operands): if isinstance(operand, six.string_types) and "@" not in operand: operands[idx] = Address(base_address=operand) if isinstance(operand, six.string_types) and "@" in operand: relocation_mode = True instruction = target.new_instruction(instr_type.name) try: if not relocation_mode: instruction.set_operands(operands) else: # Go one by one, and make relocation safe for operand, value in zip(instruction.operands(), operands): if (isinstance(operand.type, OperandImmRange) and "@" in value): operand.set_value(value, check=False) else: operand.set_value(value) except MicroprobeValueError: LOG.debug("End checking assembly string: Operands not valid") return False except MicroprobeCodeGenerationError: LOG.debug("End checking assembly string: Operands not valid for " "callback") return False nasm = _normalize_asm(instruction.assembly()) base_asm = _normalize_asm(base_asm) base_asm = base_asm.replace(instr_type.name, instr_type.mnemonic) LOG.debug("'%s' == '%s' ?", nasm, base_asm) if nasm == base_asm: LOG.debug("End checking assembly string: Valid") return True LOG.debug("End checking assembly string: Not valid") return False
def init_loop_pad(self): """ """ if self._init_loop_pad is None: nop = self.target.nop() nop.set_address(Address(base_address="code")) self.start_loop(nop, nop) if self._init_loop_pad is None: self._init_loop_pad = 0 return self._init_loop_pad
def __init__(self, value=0): """ :param value: (Default value = 0) """ super(InitializeMemoryFloatPass, self).__init__() self._var = microprobe.code.var.VariableSingle("FP_INITVAL", "double", value="%.20f" % value) self._varaddress = Address(base_address=self._var) self._value = value self._memvalue = MemoryValue(self._varaddress, value, 8) self._description = "Initialize all the memory location accessed by" \ " binary floating point operations to value: '%s'"\ "." % (self._value)
def _check_assembly_string(base_asm, instr_type, target, operands): """ :param base_asm: :type base_asm: :param instr_type: :type instr_type: :param target: :type target: :param operands: :type operands: """ LOG.debug("Start checking assembly string: %s", base_asm) operands = list(operands) for idx, operand in enumerate(operands): if isinstance(operand, six.string_types): operands[idx] = Address(base_address=operand) instruction = target.new_instruction(instr_type.name) try: instruction.set_operands(operands) except MicroprobeValueError: LOG.debug("End checking assembly string: Operands not valid") return False except MicroprobeCodeGenerationError: LOG.debug("End checking assembly string: Operands not valid for " "callback") return False nasm = _normalize_asm(instruction.assembly()) base_asm = _normalize_asm(base_asm) base_asm = base_asm.replace(instr_type.name, instr_type.mnemonic) LOG.debug("'%s' == '%s' ?", nasm, base_asm) if nasm == base_asm: LOG.debug("End checking assembly string: Valid") return True LOG.debug("End checking assembly string: Not valid") return False
def __call__(self, lengths): """ :param lengths: """ mcomp = self._func() var, count, max_value, module, cca = self._state[mcomp] value = self._sets[mcomp][count % module] count = count + 1 max_value = max(value, max_value) cgc = mcomp.congruence_class(value) self._check_integrity() if cgc not in cca: cca.append(cgc) self._state[mcomp] = (var, count, max_value, module, cca) return Address(base_address=var, displacement=value), max(lengths)
def set_register_to_address(self, register, address, context, force_absolute=False, force_relative=False ): instrs = [] LOG.debug("Begin setting '%s' to address '%s'", register, address) option_displacement = None option_label = None if isinstance(address.base_address, Variable): LOG.debug("Base address is a Variable: %s", address.base_address) closest = context.get_closest_address_value(address) if context.register_has_value(address): present_reg = context.registers_get_value(address)[0] displacement = 0 LOG.debug("Address already in register '%s'", present_reg) elif closest is not None: present_reg, taddress = closest displacement = address.displacement - taddress.displacement LOG.debug("Closest value '%s' found in '%s'", taddress, present_reg) LOG.debug("Displacement needed: %s", displacement) elif context.register_has_value( Address(base_address=address.base_address)): present_reg = context.registers_get_value( Address(base_address=address.base_address))[0] displacement = address.displacement LOG.debug("Base address '%s' found in '%s'", taddress, present_reg) LOG.debug("Displacement needed: %s", displacement) else: present_reg = None displacement = None LOG.debug("Present_reg: %s", present_reg) LOG.debug("Displacement: %s", displacement) if present_reg is not None: if displacement != 0 and abs(displacement) < (2 ** 11): addi_ins = self.new_instruction("ADDI_V0") addi_ins.set_operands([displacement, present_reg, register]) instrs.append(addi_ins) LOG.debug("Computing directly from context (short)") option_displacement = instrs instrs = [] if present_reg != register and option_displacement is None: or_ins = self.new_instruction("OR_V0") or_ins.set_operands([present_reg, present_reg, register]) instrs.append(or_ins) if displacement != 0 and option_displacement is None: instrs += self.add_to_register(register, displacement) LOG.debug("Computing directly from context (long)") if option_displacement is None: option_displacement = instrs instrs = [] if context.symbolic and not force_absolute and not force_relative: instrs = [] # TODO: This should be a call to the environment object because # the implementation depends on the environment # Base address can be an instruction label (str) or # a Variable instance basename = address.base_address basedisp = "" if not isinstance(address.base_address, str): basename = address.base_address.name if address.displacement >= 0: basedisp = "+0x%016X" % address.displacement else: basedisp = "-0x%016X" % abs(address.displacement) global _RISCV_PCREL_LABEL _RISCV_PCREL_LABEL += 1 lnum = _RISCV_PCREL_LABEL auipc_ins = self.new_instruction("AUIPC_V0") auipc_ins.operands()[1].set_value(register) auipc_ins.operands()[0].set_value( "%%pcrel_hi(%s)" % basename + basedisp, check=False ) auipc_ins.set_label( "%s_pcrel_%d" % (basename, lnum) ) instrs.append(auipc_ins) addi_ins = self.new_instruction("ADDI_V0") addi_ins.operands()[1].set_value(register) addi_ins.operands()[2].set_value(register) addi_ins.operands()[0].set_value( "%%pcrel_lo(%s_pcrel_%d)" % (basename, lnum), check=False ) instrs.append(addi_ins) # if address.displacement != 0: # instrs += self.add_to_register(register, # address.displacement) LOG.debug("End Loading symbolic reference") option_label = instrs if option_label is None and option_displacement is None: raise NotImplementedError elif option_label is None: return option_displacement elif option_displacement is None: return option_label if len(option_label) <= len(option_displacement): return option_label else: return option_displacement
def set_register_to_address(self, register, address, context, force_absolute=False, force_relative=False ): instrs = [] LOG.debug("Begin setting '%s' to address '%s'", register, address) if isinstance(address.base_address, Variable): LOG.debug("Base address is a Variable: %s", address.base_address) closest = context.get_closest_address_value(address) if context.register_has_value(address): present_reg = context.registers_get_value(address)[0] displacement = 0 LOG.debug("Address already in register '%s'", present_reg) elif closest is not None: present_reg, taddress = closest displacement = address.displacement - taddress.displacement LOG.debug("Closest value '%s' found in '%s'", taddress, present_reg) LOG.debug("Displacement needed: %s", displacement) elif context.register_has_value( Address(base_address=address.base_address)): present_reg = context.registers_get_value( Address(base_address=address.base_address))[0] displacement = address.displacement LOG.debug("Base address '%s' found in '%s'", taddress, present_reg) LOG.debug("Displacement needed: %s", displacement) else: present_reg = None displacement = None LOG.debug("Present_reg: %s", present_reg) LOG.debug("Displacement: %s", displacement) if present_reg is not None: if displacement != 0 and abs(displacement) < (2 ** 11): addi_ins = self.new_instruction("ADDI_V0") addi_ins.set_operands([displacement, present_reg, register]) instrs.append(addi_ins) LOG.debug("Computing directly from context (short)") return instrs if present_reg != register: or_ins = self.new_instruction("OR_V0") or_ins.set_operands([register, present_reg, present_reg]) instrs.append(or_ins) if displacement != 0: instrs += self.add_to_register(register, displacement) LOG.debug("Computing directly from context (long)") return instrs if context.symbolic and not force_absolute and not force_relative: # TODO: This should be a call to the environment object because # the implementation depends on the environment # Base address can be an instruction label (str) or # a Variable instance basename = address.base_address if not isinstance(address.base_address, str): basename = address.base_address.name lui_ins = self.new_instruction("LUI_V0") lui_ins.operands()[1].set_value(register) lui_ins.operands()[0].set_value( "%%hi(%s)" % basename, check=False ) instrs.append(lui_ins) addi_ins = self.new_instruction("ADDI_V0") addi_ins.operands()[1].set_value(register) addi_ins.operands()[2].set_value(register) addi_ins.operands()[0].set_value( "%%lo(%s)" % basename, check=False ) instrs.append(addi_ins) if address.displacement != 0: instrs += self.add_to_register(register, address.displacement) LOG.debug("End Loading symbolic reference") return instrs raise NotImplementedError
def _translate_label(self, instruction, context): """ :param instruction: :param context: """ if self._instructions != []: if instruction.name not in self._instructions: return for operand in instruction.operands(): if operand.value is None: continue if not isinstance(operand.value, Address): continue address = operand.value LOG.debug("Translating label: '%s' of instruction '%s'", address, instruction.name) if isinstance(address, InstructionAddress): if address.target_instruction is not None: target_address = address.target_instruction.address comment = "Reference to instruction at" elif (isinstance(address.base_address, str) and address.base_address.upper() in list( self._labels.keys())): target_address = self._labels[ address.base_address.upper()].address + \ address.displacement comment = "Reference to %s at" % address elif (isinstance(address.base_address, str) and address.base_address.upper() == "CODE"): target_address = address comment = "Reference to %s at" % address else: LOG.critical(address.base_address) LOG.critical(address) LOG.critical(list(self._labels.keys())) raise NotImplementedError if operand.type.address_relative: if context.code_segment is not None: instruction.add_comment( "%s %s" % (comment, hex(context.code_segment + target_address.displacement))) relative_offset = target_address - instruction.address operand.set_value(relative_offset, check=self._strict) else: raise NotImplementedError elif isinstance(address.base_address, Variable): target_address = Address( base_address=address.base_address.address, displacement=address.displacement) if operand.type.address_relative: # Code referencing data, fix address taking into account # code and data offsets if instruction.address.base_address == "code" and \ target_address.base_address == "data" and \ context.data_segment is not None and \ context.code_segment is not None: instruction_address = Address( base_address="temp", displacement=context.code_segment + instruction.address.displacement) data_address = Address( base_address="temp", displacement=context.data_segment + target_address.displacement) # instruction_address = Address(base_address="data", # displacement=instruction.address.displacement) relative_offset = data_address - instruction_address try: operand.set_value(relative_offset) except MicroprobeValueError: raise MicroprobeCodeGenerationError( "Unable to codify the relative offset from " "instruction at 0x%x to data at 0x%x. " "Review the correctness of the addresses and " "change them." % (instruction_address.displacement, data_address.displacement)) comment = "Reference to var '%s' at" \ % address.base_address.name instruction.add_comment( "%s %s" % (comment, hex(data_address.displacement))) else: LOG.critical(instruction.address.base_address) LOG.critical(target_address.base_address) LOG.critical(context.data_segment) LOG.critical(context.code_segment) LOG.critical(context.symbolic) LOG.critical(target_address) LOG.critical(instruction) LOG.critical(operand) raise NotImplementedError else: raise NotImplementedError else: LOG.critical(instruction, instruction.address, address) LOG.critical(address.base_address, type(address.base_address)) raise NotImplementedError
def set_register(self, register, value, context, opt=True): LOG.debug("Begin setting '%s' to value '%s'", register, value) instrs = [] current_value = context.get_register_value(register) force_reset = False if isinstance(current_value, Address): force_reset = True closest_register = context.get_register_closest_value(register) if closest_register is not None: closest_value = context.get_register_value(closest_register) else: closest_value = None if context.register_has_value(value): present_reg = context.registers_get_value(value)[0] if present_reg.type.name != register.type.name: present_reg = None else: present_reg = None if register.type.name == "FPR": if present_reg is not None: fmr_ins = self.new_instruction("FMR_V0") fmr_ins.set_operands([register, present_reg]) instrs.append(fmr_ins) else: instrs += self.set_register(self.scratch_registers[0], value, context) if not context.register_has_value(self.scratch_var.address): instrs += self.set_register_to_address( self.scratch_registers[1], self.scratch_var.address, context) ldstore_reg = self._scratch_registers[1] else: ldstore_reg = context.registers_get_value( self.scratch_var.address)[0] std_ins = self.new_instruction("STD_V0") std_ins.set_operands( [self.scratch_registers[0], ldstore_reg, 0]) instrs.append(std_ins) ld_ins = self.new_instruction("LFD_V0") ld_ins.set_operands([register, ldstore_reg, 0]) instrs.append(ld_ins) elif register.type.name == "GPR": value_highest = int((value & 0xFFFF000000000000) >> 48) value_higher = int((value & 0x0000FFFF00000000) >> 32) value_high = int((value & 0x00000000FFFF0000) >> 16) value_low = int((value & 0x000000000000FFFF)) if present_reg is not None and present_reg == register: # The value is already in the register return [] elif value >= -32768 and value <= 32767 and opt: li_ins = self.new_instruction("ADDI_V1") li_ins.set_operands([register, 0, value]) instrs.append(li_ins) elif present_reg is not None and opt: or_ins = self.new_instruction("OR_V0") or_ins.set_operands([present_reg, register, present_reg]) instrs.append(or_ins) elif (not force_reset and current_value is not None and abs(value - current_value) <= 32767 and opt): addi_ins = self.new_instruction("ADDI_V0") addi_ins.set_operands( [register, register, value - current_value]) instrs.append(addi_ins) elif (closest_value is not None and abs(value - closest_value) <= 32767 and opt): addi_ins = self.new_instruction("ADDI_V0") addi_ins.set_operands( [register, closest_register, value - closest_value]) instrs.append(addi_ins) elif value >= -2147483648 and value <= 2147483647 and opt: if value_high > 32767: # Negative value_high = (2**16 - value_high) * -1 lis_ins = self.new_instruction("ADDIS_V1") lis_ins.set_operands([register, 0, value_high]) instrs.append(lis_ins) ori_ins = self.new_instruction("ORI_V0") ori_ins.set_operands([register, register, value_low]) instrs.append(ori_ins) else: if value_highest > 32767: # Negative value_highest = (2**16 - value_highest) * -1 lis_ins = self.new_instruction("ADDIS_V1") lis_ins.set_operands([register, 0, value_highest]) instrs.append(lis_ins) ori_ins = self.new_instruction("ORI_V0") ori_ins.set_operands([register, register, value_higher]) instrs.append(ori_ins) rldicr_ins = self.new_instruction("RLDICR_V0") rldicr_ins.set_operands([register, register, 32, 31]) instrs.append(rldicr_ins) oris_ins = self.new_instruction("ORIS_V0") oris_ins.set_operands([register, register, value_high]) instrs.append(oris_ins) ori_ins = self.new_instruction("ORI_V0") ori_ins.set_operands([register, register, value_low]) instrs.append(ori_ins) elif register.type.name == "CR": if value > 15 and value < 0: LOG.warning( "User trying to set a CR register with an invalid " "value (%d) ", str(value)) value_4bits = int((value & 0x000000000000000F)) instrs += self.set_register(self.scratch_registers[0], value_4bits, context) fxm_mask = int( "".join( list( reversed("{0:08b}".format(2**int( register.representation))))), 2) mtocrf_ins = self.new_instruction("MTOCRF_V0") mtocrf_ins.set_operands([self.scratch_registers[0], fxm_mask]) instrs.append(mtocrf_ins) elif register.type.name == "VR" or register.type.name == "VSR": if present_reg is not None: if register.type.name == "VR": vor_ins = self.new_instruction("VOR_V0") vor_ins.set_operands([register, present_reg, present_reg]) instrs.append(vor_ins) else: xxlor_ins = self.new_instruction("XXLOR_V0") xxlor_ins.set_operands( [register, present_reg, present_reg]) instrs.append(xxlor_ins) else: if not context.register_has_value(self.scratch_var.address): if self.scratch_var.address is None and context.symbolic: # Assume symbolic instrs += self.set_register_to_address( self.scratch_registers[1], Address(base_address=self.scratch_var.name), context) else: instrs += self.set_register_to_address( self.scratch_registers[1], self.scratch_var.address, context) if len(str(value).split("_")) == 2: # Value format: <value>_<bit_size> item_value = int(str(value).split("_")[0], base=0) item_size = int(str(value).split("_")[1], base=10) item_format_str = "%%0%dx" % (item_size // 4) value = int( (item_format_str % item_value) * (128 // item_size), 16) elif len(str(value).split("_")) == 1: pass else: raise NotImplementedError("Unknown value format") value_high = int((value & 0x0000000000000000FFFFFFFFFFFFFFFF)) value_low = int((value & 0xFFFFFFFFFFFFFFFF0000000000000000) >> 64) instrs += self.set_register(self.scratch_registers[0], value_high, context) std_ins = self.new_instruction("STD_V0") std_ins.set_operands( [self.scratch_registers[0], self.scratch_registers[1], 8]) instrs.append(std_ins) instrs += self.set_register(self.scratch_registers[0], value_low, context) std_ins = self.new_instruction("STD_V0") std_ins.set_operands( [self.scratch_registers[0], self.scratch_registers[1], 0]) instrs.append(std_ins) if register.type.name == "VR": lvx_ins = self.new_instruction("LVX_V1") lvx_ins.set_operands([ register, self.registers["GPR0"], self.scratch_registers[1] ]) instrs.append(lvx_ins) else: # TODO: make sure we use the version where GPR0 is zero lxvd2x_ins = self.new_instruction("LXVD2X_V1") lxvd2x_ins.set_operands([ register, self.registers["GPR0"], self.scratch_registers[1] ]) instrs.append(lxvd2x_ins) elif register.type.name in ["SPR", "SPR32"]: instrs += self.set_register(self.scratch_registers[0], value, context) # Skip code generation for register that are # not architected if register.representation == 'N/A': return [] if register.type.name in ["SPR"]: mtspr = self.new_instruction("MTSPR_V0") else: mtspr = self.new_instruction("MTSPR_V2") mtspr.set_operands([self.scratch_registers[0], register]) instrs.append(mtspr) if len(instrs) > 0: return instrs return super(PowerISA, self).set_register(register, value, context)
def set_register_to_address(self, register, address, context, force_absolute=False, force_relative=False): instrs = [] assert address is not None LOG.debug("Begin setting '%s' to address '%s'", register, address) if isinstance(address.base_address, Variable): LOG.debug("Base address is a Variable: %s", address.base_address) closest = context.get_closest_address_value(address) if context.register_has_value(address): present_reg = context.registers_get_value(address)[0] displacement = 0 LOG.debug("Address already in register '%s'", present_reg) elif closest is not None: present_reg, taddress = closest displacement = address.displacement - taddress.displacement LOG.debug("Closest value '%s' found in '%s'", taddress, present_reg) LOG.debug("Displacement needed: %s", displacement) elif context.register_has_value( Address(base_address=address.base_address)): present_reg = context.registers_get_value( Address(base_address=address.base_address))[0] displacement = address.displacement LOG.debug("Base address '%s' found in '%s'", taddress, present_reg) LOG.debug("Displacement needed: %s", displacement) else: present_reg = None displacement = None LOG.debug("Present_reg: %s", present_reg) LOG.debug("Displacement: %s", displacement) if present_reg is not None: if displacement != 0 and abs(displacement) < (2**15): addi_ins = self.new_instruction("ADDI_V0") addi_ins.set_operands( [register, present_reg, displacement]) instrs.append(addi_ins) LOG.debug("Computing directly from context (short)") return instrs if present_reg != register: or_ins = self.new_instruction("OR_V0") or_ins.set_operands([present_reg, register, present_reg]) instrs.append(or_ins) if displacement != 0: instrs += self.add_to_register(register, displacement) LOG.debug("Computing directly from context (long)") return instrs if context.symbolic and not force_absolute and not force_relative: # TODO: This should be a call to the environment object because # the implementation depends on the environment # Base address can be an instruction label (str) or # a Variable instance basename = address.base_address if not isinstance(address.base_address, str): basename = address.base_address.name lis_ins = self.new_instruction("ADDIS_V1") lis_ins.operands()[0].set_value(register) lis_ins.operands()[1].set_value(0) lis_ins.operands()[2].set_value("%s@highest" % basename, check=False) instrs.append(lis_ins) ori_ins = self.new_instruction("ORI_V0") ori_ins.operands()[0].set_value(register) ori_ins.operands()[1].set_value(register) ori_ins.operands()[2].set_value("%s@higher" % basename, check=False) instrs.append(ori_ins) rldicr_ins = self.new_instruction("RLDICR_V0") rldicr_ins.set_operands([register, register, 32, 31]) instrs.append(rldicr_ins) oris_ins = self.new_instruction("ORIS_V0") oris_ins.operands()[0].set_value(register) oris_ins.operands()[1].set_value(register) oris_ins.operands()[2].set_value("%s@h" % basename, check=False) instrs.append(oris_ins) ori_ins = self.new_instruction("ORI_V0") ori_ins.operands()[0].set_value(register) ori_ins.operands()[1].set_value(register) ori_ins.operands()[2].set_value("%s@l" % basename, check=False) instrs.append(ori_ins) if address.displacement != 0: instrs += self.add_to_register(register, address.displacement) LOG.debug("End Loading symbolic reference") return instrs LOG.debug("Context not symbolic") base_address = address.base_address displacement = address.displacement LOG.debug("Base_address: %s", base_address) LOG.debug("Displacement: %s", displacement) if isinstance(base_address, Variable): LOG.debug("Get absolute address") displacement += base_address.address.displacement base_address = base_address.address.base_address LOG.debug("Base_address 2: %s", base_address) LOG.debug("Displacement 2: %s", displacement) if isinstance(base_address, str): if base_address == "data": base_address = Address(base_address=base_address) elif base_address == "code": base_address = InstructionAddress(base_address=base_address) source_register = None if context.register_has_value(base_address): source_register = context.registers_get_value(base_address)[0] else: for reg, value in context.register_values.items(): if not isinstance(value, Address): continue if (Address(base_address=value.base_address) == base_address.base_address): source_register = reg displacement += base_address.displacement base_address = Address( base_address=base_address.base_address) break if value.base_address == base_address.base_address: source_register = reg displacement += base_address.displacement base_address = Address( base_address=base_address.base_address) break if source_register is None or displacement >= (2**31): # Not source register found if base_address.base_address == "data": value = context.data_segment elif base_address.base_address == "code": value = context.code_segment else: LOG.debug(context.dump()) raise MicroprobeCodeGenerationError( "Unable to generate " "the base address: '%s'" " for target address: '%s'." % (base_address, address)) if abs(displacement) >= (2**31): value = value + displacement displacement = 0 assert (value is not None) instrs += self.set_register(register, value, context) if source_register is not None and source_register != register: or_ins = self.new_instruction("OR_V0") or_ins.set_operands([source_register, register, source_register]) instrs.append(or_ins) if displacement != 0: instrs += self.add_to_register(register, displacement) LOG.debug("End address generation") return instrs
def dump_mpt(input_file, target, init_data, arguments): """ :param input_file: :type input_file: :param target: :type target: :param init_data: :type init_data: :param arguments: :type arguments: """ input_file_fd = io.open(input_file, 'r') contents = input_file_fd.read() if six.PY2: contents = contents.encode("ascii") elif six.PY3: pass print_info("Parsing input file...") var_defs, req_defs, instr_defs = \ interpret_objdump(contents, target, strict=arguments.get('strict', False), sections=["microprobe.text"]) print_info("Input file parsed") print_info("%d instructions processed from the input file" % len(instr_defs)) if var_defs != []: print_info("Variables referenced and detected in the dump: %s" % ','.join([var.name for var in var_defs])) if req_defs != []: print_warning( "Variables referenced and *NOT* detected in the dump: %s" % ','.join([var.name for var in req_defs])) print_warning("You might need to edit the generated MPT to fix the" " declaration of such variables") print_info("Generating the MPT contents...") mpt_config = mpt_configuration_factory() mpt_config.set_default_code_address(arguments['default_code_address']) mpt_config.set_default_data_address(arguments['default_data_address']) kwargs = {} if "stack_name" in arguments: kwargs["stack_name"] = arguments["stack_name"] if "stack_address" in arguments: kwargs["stack_address"] = Address( base_address="code", displacement=arguments["stack_address"]) variables, instructions = target.elf_abi(arguments["stack_size"], "c2mpt_function", **kwargs) for variable in variables: req_defs.append(variable_to_test_definition(variable)) address = instr_defs[0].address for instr in reversed(instructions): instr_defs = [instruction_to_definition(instr)] + instr_defs address -= instr.architecture_type.format.length if address.displacement < 0: print_error("Default code address is below zero after" " adding the initialization code.") print_error("Check/modify the objdump provided or do not use" " the elf_abi flag.") _exit(-1) if "end_branch_to_itself" in arguments: instr = target.branch_to_itself() else: instr = target.nop() instr.set_label("ELF_ABI_EXIT") instr_defs.append(instruction_to_definition(instr)) mpt_config.set_default_code_address(address.displacement) initialized_variables = {} mindisplacement = None for data in init_data.split('\n'): if data.strip() == "": continue if data.startswith("WARNING"): print_warning(data.split(":")[1].strip()) continue name = data.split("=")[0].strip() values = ast.literal_eval(data.split("=")[1].strip()) initialized_variables[name] = values if mindisplacement is None: mindisplacement = values[2] # TODO: this is unsafe. We should compute the real size maxdisplacement = values[2] + (values[1] * 8) else: mindisplacement = min(values[2], mindisplacement) maxdisplacement = max(values[2] + (values[1] * 8), maxdisplacement) if "host_displacement" in arguments: mindisplacement = arguments.get("host_displacement", mindisplacement) for name, values in initialized_variables.items(): values[2] = values[2] - mindisplacement + \ arguments['default_data_address'] if 'fix_displacement' in arguments: for name, values in initialized_variables.items(): if "*" in values[0] and isinstance(values[4], list): new_values = [] for value in values[4]: if value <= maxdisplacement and value >= mindisplacement: value = value - mindisplacement + \ arguments['default_data_address'] new_values.append(value) values[4] = new_values elif "*" in values[0] and isinstance(values[4], int): if (values[4] <= maxdisplacement and values[4] >= mindisplacement): values[4] = values[4] - mindisplacement + \ arguments['default_data_address'] elif values[0] == "uint8_t" and isinstance(values[4], list): if len(values[4]) > 8: new_values = "".join(["%02x" % elem for elem in values[4]]) # Enable this for testing switched endianness # new_values = [new_values[idx:idx + 2] # for idx in range(0, len(new_values), 2)] # new_values = new_values[::-1] # new_values = "".join(new_values) new_values = _fix_displacement(new_values, mindisplacement, maxdisplacement, arguments) values[4] = [ int(new_values[idx:idx + 2], 16) for idx in range(0, len(new_values), 2) ] for name, values in initialized_variables.items(): mpt_config.register_variable_definition( MicroprobeTestVariableDefinition(name, *values)) print_info("Init values for variable '%s' parsed" % name) for var in var_defs + req_defs: if var.name in list(initialized_variables.keys()): continue if var.name != arguments["stack_name"]: print_warning("Variable '%s' not registered in the C file " "using the macros provided!" % var.name) mpt_config.register_variable_definition(var) mpt_config.register_instruction_definitions(instr_defs) print_info("Dumping MPT to '%s'" % arguments['output_mpt_file']) mpt_parser = mpt_parser_factory() mpt_parser.dump_mpt_config(mpt_config, arguments['output_mpt_file'])
def __call__(self, building_block, target): """ """ ivars = [ var for var in building_block.registered_global_vars() if var.address is None or var.address.base_address != "data" ] context = building_block.context maxdispl = None for bbl in building_block.cfg.bbls: for instr in bbl.instrs: if instr.address is None: continue caddress = instr.address if caddress.base_address != "code": continue if maxdispl is None: maxdispl = caddress.displacement elif maxdispl < caddress.displacement: maxdispl = caddress.displacement code_region = (context.code_segment, ((maxdispl // 0x100) + 1) * 0x100) max_code = code_region[0] + code_region[1] for var in ivars: ranges = sorted( [code_region] + [(context.data_segment + var.address.displacement, var.size) for var in building_block.registered_global_vars() if var. address is not None and var.address.base_address == "data" and (context.data_segment + var.address.displacement) > max_code], key=lambda x: x[0]) # Check overlaps in ranges for idx in range(0, len(ranges) - 1): mrange1 = ranges[idx] mrange2 = ranges[idx + 1] assert mrange1[0] + mrange1[1] <= mrange2[0] align = var.align if align is None: align = 1 if len(ranges) == 1: var.set_address( Address(base_address="data", displacement=((( (ranges[0][0] + ranges[0][1]) // align) + 1) * align) - context.data_segment)) continue for idx in range(0, len(ranges) - 1): mrange = ranges[idx] ndisp = (((mrange[0] + mrange[1]) // align) + 1) * align if ndisp + var.size >= ranges[idx + 1][0]: continue var.set_address( Address(base_address="data", displacement=(ndisp - context.data_segment))) break
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 generate(test_definition, output_file, target, **kwargs): """ Microbenchmark generation policy. :param test_definition: Test definition object :type test_definition: :class:`MicroprobeTestDefinition` :param output_file: Output file name :type output_file: :class:`str` :param target: Target definition object :type target: :class:`Target` """ end_address_orig = None overhead = 0 if len(test_definition.dat_mappings) > 0: # # Assuming MPT generated from MAMBO full system # dat = target.get_dat(dat_map=test_definition.dat_mappings) dat.control['DAT'] = True for instr in test_definition.code: instr.address = dat.translate(instr.address, rev=True) # Address order might have changed after mapping test_definition.set_instruction_definitions( sorted(test_definition.code, key=lambda x: x.address) ) # remove not translated addresses (needed?) # variables = [var for var in test_definition.variables # if var.address != dat.translate(var.address, rev=True)] # test_definition.set_variables_definition(variables) for var in test_definition.variables: var.address = dat.translate(var.address, rev=True) # Address order might have changed after mapping test_definition.set_variables_definition( sorted(test_definition.variables, key=lambda x: x.address) ) if test_definition.default_code_address != 0: test_definition.default_code_address = dat.translate( test_definition.default_code_address, rev=True ) if test_definition.default_data_address != 0: test_definition.default_data_address = dat.translate( test_definition.default_data_address, rev=True ) for access in test_definition.roi_memory_access_trace: access.address = dat.translate( access.address, rev=True ) if 'raw_bin' in kwargs: print_info("Interpreting RAW dump...") sequence = [] raw_dict = {} current_address = 0 # Assume state file provides the initial code address displ = test_definition.default_code_address test_definition.set_default_code_address(0) for entry in test_definition.code: if (not entry.assembly.upper().startswith("0X") and not entry.assembly.upper().startswith("0B")): raise MicroprobeMPTFormatError( "This is not a RAW dump as it contains " "assembly (%s)" % entry.assembly ) if entry.label is not None: raise MicroprobeMPTFormatError( "This is not a RAW dump as it contains " "labels (%s)" % entry.label ) if entry.decorators not in ['', ' ', None, []]: raise MicroprobeMPTFormatError( "This is not a RAW dump as it contains " "decorators (%s)" % entry.decorators ) if entry.comments not in ['', ' ', None, []]: raise MicroprobeMPTFormatError( "This is not a RAW dump as it contains " "comments (%s)" % entry.comments ) if entry.address is not None: current_address = entry.address + displ if current_address not in raw_dict: raw_dict[current_address] = "" # Assume that raw dump use a 4 bytes hex dump if len(entry.assembly) != 10: raise MicroprobeMPTFormatError( "This is not a RAW 4-byte dump as it contains " "lines with other formats (%s)" % entry.assembly ) raw_dict[current_address] += entry.assembly[2:] if len(raw_dict) > 1: address_ant = sorted(raw_dict.keys())[0] len_ant = len(raw_dict[address_ant])//2 # Assume that raw dump use a 4 bytes hex dump assert len_ant % 4 == 0 for address in sorted(raw_dict.keys())[1:]: if address_ant + len_ant == address: raw_dict[address_ant] += raw_dict[address] len_ant = len(raw_dict[address_ant])//2 raw_dict.pop(address) else: len_ant = len(raw_dict[address])//2 address_ant = address # Assume that raw dump use a 4 bytes hex dump assert len_ant % 4 == 0 sequence = [] for address in sorted(raw_dict.keys()): # Endianess will be big endian, because we are concatenating # full words resulting in the higher bits being encoded first code = interpret_bin( raw_dict[address], target, safe=True, little_endian=False, word_length=4 ) for instr in code: instr.address = address instr = instruction_from_definition(instr) address = address + instr.architecture_type.format.length instr = instruction_to_asm_definition(instr) sequence.append(instr) test_definition.set_instruction_definitions(sequence) reset_steps = [] if 'no_wrap_test' not in kwargs: if test_definition.default_code_address != 0: print_error("Default code address should be zero") exit(-1) print_info("Wrapping function...") start_symbol = "START_TEST" init_address = test_definition.default_code_address for register in test_definition.registers: if register.name == "PC": init_address = register.value if register.name == "PSW_ADDR": init_address = register.value displacements = [] for elem in test_definition.code: if elem.address is not None: if len(displacements) == 0: displacements.append( (elem.address, 4*1024, elem.address - init_address) ) else: displacements.append( (elem.address, elem.address - displacements[-1][0], elem.address - init_address) ) # Get ranges with enough space to put init code # Assuming 4K space is enough displacements = [ displ for displ in displacements if displ[1] >= 4*1024 and displ[2] <= 0 ] if len(displacements) == 0: print_error( "Unable to find space for the initialization code. " "Check the mpt initial code address or state of PC " "for correctness." ) exit(-1) displ_fixed = False if kwargs['fix_start_address']: displacement = kwargs['fix_start_address'] print_info("Start point set to 0x%X" % displacement) displ_fixed = True elif 'fix_long_jump' in kwargs: displacement = sorted(displacements, key=lambda x: x[0])[0][0] if displacement > 2**32: displacement = 0x1000000 print_info("Start point set to 0x%X" % displacement) displ_fixed = True else: displacement = sorted(displacements, key=lambda x: x[2])[-1][0] start_symbol = None init_found = False for instr in test_definition.code: if instr.address == init_address: if instr.label is None: instr.label = "START_TEST" start_symbol = instr.label init_found = True break if not init_found: print_error( "Initial instruction address (%s) not found" % hex(init_address) ) exit(-1) if start_symbol is None: if test_definition.code[0].label is None: test_definition.code[0].label = "START_TEST" start_symbol = test_definition.code[0].label if displacement is None: displacement = 0 instructions = [] reset_steps = [] if 'wrap_endless' in kwargs and 'reset' in kwargs: target.scratch_var.set_address( Address( base_address=target.scratch_var.name ) ) new_ins, overhead, reset_steps = _compute_reset_code( target, test_definition, kwargs, ) instructions += new_ins if 'fix_long_jump' in kwargs: instructions += target.function_call( init_address, long_jump=True ) else: instructions += target.function_call( ("%s" % start_symbol).replace("+0x-", "-0x"), ) if 'wrap_endless' not in kwargs: instructions += [target.nop()] else: instructions += _compute_reset_jump(target, instructions) instructions_definitions = [] for instruction in instructions: instruction.set_label(None) if not displ_fixed: displacement = (displacement - instruction.architecture_type.format.length) current_instruction = MicroprobeAsmInstructionDefinition( instruction.assembly(), None, None, None, instruction.comments, ) instructions_definitions.append(current_instruction) instruction = target.nop() instruction.set_label(None) if not displ_fixed: displacement = (displacement - instruction.architecture_type.format.length) # To avoid overlaps if not displ_fixed: align = 0x100 displacement = ((displacement // align) + 0) * align instructions_definitions[0].address = displacement assert instructions_definitions[0].address is not None # instr = MicroprobeAsmInstructionDefinition( # instruction.assembly(), "ELF_ABI_EXIT", None, None, None) # end_address_orig = \ # (test_definition.default_code_address + displacement_end - # instruction.architecture_type.format.length) instructions_definitions[0].label = "mpt2elf_endless" test_definition.register_instruction_definitions( instructions_definitions, prepend=True, ) assert test_definition.code[0].address is not None if not displ_fixed: test_definition.set_default_code_address( test_definition.default_code_address + displacement, ) for elem in test_definition.code: if elem.address is not None: elem.address = elem.address - displacement else: test_definition.set_default_code_address( displacement ) for elem in test_definition.code: if elem.address is not None: elem.address = elem.address - displacement variables = test_definition.variables variables = [var for var in test_definition.variables if var.address is None or var.address >= 0x00100000] test_definition.set_variables_definition(variables) print_info("Interpreting asm ...") sequence_orig = interpret_asm( test_definition.code, target, [var.name for var in variables] + [target.scratch_var.name], show_progress=True, ) if len(sequence_orig) < 1: raise MicroprobeMPTFormatError( "No instructions found in the 'instructions' entry of the MPT" " file. Check the input file.", ) raw = test_definition.raw raw['FILE_FOOTER'] = "# mp_mpt2elf: Wrapping overhead: %03.2f %%" \ % overhead # end_address = end_address_orig ckwargs = { # 'end_address': end_address, # 'reset': False, # 'endless': 'endless' in kwargs } wrapper_name = "AsmLd" if test_definition.default_data_address is not None: ckwargs['init_data_address'] = \ test_definition.default_data_address if test_definition.default_code_address is not None: ckwargs['init_code_address'] = \ test_definition.default_code_address try: code_wrapper = microprobe.code.get_wrapper(wrapper_name) except MicroprobeValueError as exc: raise MicroprobeException( "Wrapper '%s' not available. Check if you have the wrappers" " of the target installed or set up an appropriate " "MICROPROBEWRAPPERS environment variable. Original error " "was: %s" % (wrapper_name, str(exc)), ) wrapper = code_wrapper(**ckwargs) print_info("Setup synthesizer ...") synthesizer = microprobe.code.Synthesizer( target, wrapper, no_scratch=False, extra_raw=raw, ) variables = test_definition.variables registers = test_definition.registers sequence = sequence_orig if len(registers) >= 0: cr_reg = [ register for register in registers if register.name == "CR" ] registers = [ register for register in registers if register.name != "CR" ] if cr_reg: value = cr_reg[0].value for idx in range(0, 8): cr = MicroprobeTestRegisterDefinition( "CR%d" % idx, (value >> (28 - (idx * 4))) & 0xF, ) registers.append(cr) synthesizer.add_pass( microprobe.passes.initialization.InitializeRegistersPass( registers, skip_unknown=True, warn_unknown=True, skip_control=True, force_reserved=True ), ) synthesizer.add_pass( microprobe.passes.structure.SimpleBuildingBlockPass( len(sequence), ), ) synthesizer.add_pass( microprobe.passes.variable.DeclareVariablesPass( variables, ), ) synthesizer.add_pass( microprobe.passes.instruction.ReproduceSequencePass(sequence), ) if target.name.startswith("power"): fix_branches = [instr.name for instr in target.instructions.values() if instr.branch_conditional] if 'raw_bin' in kwargs: # We do not know what is code and what is data, so we safely # disable the asm generation and keep the values for orig in [21, 17, 19]: synthesizer.add_pass( microprobe.passes.instruction.DisableAsmByOpcodePass( fix_branches, 0, ifval=orig ) ) else: # We know what is code and what is data, so we can safely # fix the branch instructions for new, orig in [(20, 21), (16, 17), (18, 19)]: synthesizer.add_pass( SetInstructionOperandsByOpcodePass( fix_branches, 0, new, force=True, ifval=orig ) ) if kwargs.get("fix_memory_registers", False): kwargs["fix_memory_references"] = True if kwargs.get("fix_memory_references", False): print_info("Fix memory references: On") synthesizer.add_pass( microprobe.passes.memory.FixMemoryReferencesPass( reset_registers=kwargs.get("fix_memory_registers", False), ), ) synthesizer.add_pass( microprobe.passes.register.FixRegistersPass( forbid_writes=['GPR3'], ), ) if kwargs.get("fix_memory_registers", False): print_info("Fix memory registers: On") synthesizer.add_pass( microprobe.passes.register.NoHazardsAllocationPass(), ) if kwargs.get("fix_branch_next", False): print_info("Force branch to next: On") synthesizer.add_pass( microprobe.passes.address.UpdateInstructionAddressesPass( force="fix_flatten_code" in kwargs, noinit=True ) ) synthesizer.add_pass( microprobe.passes.branch.BranchNextPass(force=True), ) if kwargs.get("fix_indirect_branches", False): print_info("Fix indirect branches: On") synthesizer.add_pass( microprobe.passes.address.UpdateInstructionAddressesPass( noinit=True ), ) synthesizer.add_pass( microprobe.passes.branch.FixIndirectBranchPass(), ) if displ_fixed: synthesizer.add_pass( microprobe.passes.address.SetInitAddressPass(displacement) ) synthesizer.add_pass( microprobe.passes.address.UpdateInstructionAddressesPass( noinit=True, init_from_first=not displ_fixed, ), ) synthesizer.add_pass( microprobe.passes.variable.UpdateVariableAddressesPass( ), ) synthesizer.add_pass( microprobe.passes.symbol.ResolveSymbolicReferencesPass( onlyraw=True ), ) print_info("Start synthesizer ...") bench = synthesizer.synthesize() # Save the microbenchmark synthesizer.save(output_file, bench=bench) print_info("'%s' generated!" % output_file) _compile(output_file, target, **kwargs) return
def register_var(self, var, context): """Registers the given variable as a global variable. :param var: Variable to register :type var: :class:`~.Variable` """ LOG.debug("Registering global var: '%s'", var.name) if var.name in self._global_vars: var2 = self._global_vars[var.name] if (var.value == var2.value and var.address == var2.address and var.address is not None and MICROPROBE_RC['safe_bin']): LOG.warning("Variable: '%s' registered multiple times!", var.name) return LOG.critical("Registered variables: %s", list(self._global_vars.keys())) raise MicroprobeCodeGenerationError( "Variable already registered: %s" % (var.name)) self._global_vars[var.name] = var if context.symbolic: LOG.debug("Context symbolic. No need to track base addresses") var_address = Address(base_address=var.name, displacement=0) var.set_address(var_address) elif var.address is None: LOG.debug("Context not symbolic and variable address not set") # if (self._vardisplacement == 0 and # context.data_segment is not None): # self._vardisplacement = context.data_segment address_ok = False while not address_ok: var_address = Address(base_address="data", displacement=self._vardisplacement) LOG.debug("Address before alignment: %s", var_address) align = var.align if align is None: align = 1 LOG.debug("Variable alignment: %s", align) LOG.debug("Current address: %s", var_address) if var_address.displacement % align != 0: # alignment needed var_address += align - (var_address.displacement % align) LOG.debug("Address after alignment: %s", var_address) LOG.debug("Current var displacement: %x", self._vardisplacement) var.set_address(var_address) over = self._check_variable_overlap(var) if over is not None: self._vardisplacement = max( self._vardisplacement, over.address.displacement + over.size) continue address_ok = True LOG.debug("Variable registered at address: '%s'", var_address) self._vardisplacement = var_address.displacement + var.size else: LOG.debug("Using pre-defined address: '%s'", var.address) over = self._check_variable_overlap(var) if over is not None: raise MicroprobeCodeGenerationError( "Variable '%s' overlaps with variable '%s'" % (var.name, over.name))
def dump_mpt(input_file_fd, target, arguments): """ :param input_file_fd: :type input_file_fd: :param target: :type target: :param arguments: :type arguments: """ try: contents = input_file_fd.read() if six.PY3 and not isinstance(contents, str): contents = contents.decode() except KeyboardInterrupt: print_info("No input data provided. Exiting...") exit(1) print_info("Parsing input file...") print_info("Sections to parse: %s" % arguments['sections']) var_defs, req_defs, instr_defs = \ interpret_objdump(contents, target, strict=arguments.get('strict', False), sections=arguments['sections'], start_address=arguments['from_address'], end_address=arguments['to_address']) print_info("Input file parsed") print_info( "%d instructions processed from the input file" % len(instr_defs) ) if var_defs != []: print_info( "Variables referenced and detected in the dump: %s" % ','.join([var.name for var in var_defs]) ) if req_defs != []: print_warning( "Variables referenced and *NOT* detected in the dump: %s" % ','.join([var.name for var in req_defs]) ) print_warning( "You might need to edit the generated MPT to fix the" " declaration of such variables" ) print_info("Generating the MPT contents...") mpt_config = mpt_configuration_factory() if 'default_code_address' in arguments: mpt_config.set_default_code_address(arguments['default_code_address']) else: mpt_config.set_default_code_address(instr_defs[0].address.displacement) if 'default_data_address' in arguments: mpt_config.set_default_data_address(arguments['default_data_address']) else: mpt_config.set_default_data_address(0) if arguments.get('elf_abi', False): kwargs = {} if "stack_name" in arguments: kwargs["stack_name"] = arguments["stack_name"] if "stack_address" in arguments: kwargs["stack_address"] = Address( base_address="code", displacement=arguments["stack_address"] ) variables, instructions = target.elf_abi( arguments["stack_size"], arguments.get( "start_symbol", None ), **kwargs ) for variable in variables: req_defs.append(variable_to_test_definition(variable)) address = instr_defs[0].address for instr in reversed(instructions): instr_defs = [instruction_to_definition(instr)] + instr_defs address -= instr.architecture_type.format.length if address.displacement < 0: print_error( "Default code address is below zero after" " adding the initialization code." ) print_error( "Check/modify the objdump provided or do not use" " the elf_abi flag." ) exit(-1) mpt_config.set_default_code_address(address.displacement) instr = None if "end_branch_to_itself" in arguments: instr = target.branch_to_itself() elif arguments.get('elf_abi', False): instr = target.nop() if instr is not None: instr.set_label("ELF_ABI_EXIT") instr_defs.append(instruction_to_definition(instr)) for var in var_defs + req_defs: mpt_config.register_variable_definition(var) mpt_config.register_instruction_definitions(instr_defs) print_info("Dumping MPT to '%s'" % arguments['output_mpt_file']) mpt_parser = mpt_parser_factory() mpt_parser.dump_mpt_config(mpt_config, arguments['output_mpt_file'])
def dump_objdump(target, arguments): """ :param target: :type target: :param arguments: :type arguments: """ ifile = open(arguments['input_dma_file'], 'r') dataw = arguments['width_bytes'] inputlines = ifile.readlines() ifile.close() progress = Progress(len(inputlines), msg="Lines parsed:") lines_dict = {} for idx, line in enumerate(inputlines): splitline = line.upper().split(" ") if len(splitline) != 3: raise MicroprobeDMAFormatError("Unable to parse line %d: %s" % (idx, line)) if (splitline[0] != "D" or len(splitline[1]) != 16 or len(splitline[1]) != 16): raise MicroprobeDMAFormatError("Unable to parse line %d: %s" % (idx, line)) key = int(splitline[1], base=16) if key in lines_dict: print_warning("Address (%s) in line %d overwrites previous entry" % (splitline[1], idx)) lines_dict[key] = splitline[2][:-1] progress() current_key = None progress = Progress(len(list(lines_dict.keys())), msg="Detecting segments:") for key in sorted(lines_dict): progress() if current_key is None: current_key = key continue current_address = current_key + (len(lines_dict[current_key]) // 2) if current_address == key: lines_dict[current_key] += lines_dict[key] lines_dict.pop(key) else: current_key = key instrs = [] progress = Progress(len(list(lines_dict.keys())), msg="Interpreting segments:") for key in sorted(lines_dict): progress() current_instrs = interpret_bin(lines_dict[key], target, safe=not arguments['strict']) current_instrs[0].address = Address(base_address='code', displacement=key) instrs += current_instrs maxlen = max([ins.format.length for ins in target.instructions.values()] + [dataw]) * 2 maxlen += maxlen // 2 counter = 0 label_dict = RejectingDict() instr_dict = RejectingDict() range_num = 1 progress = Progress(len(instrs), msg="Computing labels:") for instr_def in instrs: progress() if instr_def.address is not None: counter = instr_def.address.displacement if instr_def.instruction_type is None: for idx in range(0, len(instr_def.asm), dataw * 2): label = None if instr_def.address is not None and idx == 0: label = ".range_%x" % range_num label_dict[counter] = label range_num += 1 elif counter in label_dict: label = label_dict[counter] idx2 = min(idx + (dataw * 2), len(instr_def.asm)) masm = instr_def.asm[idx:idx2].lower() binary = " ".join([ str(masm)[i:i + 2] for i in range(0, len(masm), 2) ]).lower() instr_dict[counter] = [binary, "0x" + masm, label, None, None] counter += (idx2 - idx) // 2 continue instr = instruction_from_definition(instr_def, fix_relative=False) asm = instr.assembly().lower() relative = None absolute = None if instr.branch: for memoperand in instr.memory_operands(): if not memoperand.descriptor.is_branch_target: continue for operand in memoperand.operands: if operand.type.address_relative: relative = operand.value if operand.type.address_absolute: absolute = operand.value masm = instr_def.asm[2:] if len(masm) % 2 != 0: masm = "0" + masm binary = " ".join([str(masm)[i:i + 2] for i in range(0, len(masm), 2)]) label = None if instr_def.address is not None: if counter not in label_dict: label = ".range_%x" % range_num label_dict[counter] = label range_num += 1 else: label = label_dict[counter] elif counter in label_dict: label = label_dict[counter] rtarget = None atarget = None if relative is not None or absolute is not None: if relative is not None: assert absolute is None if isinstance(relative, int): target_addr = counter + relative rtarget = relative elif isinstance(relative, Address): target_addr = counter + relative.displacement rtarget = relative.displacement else: raise NotImplementedError if absolute is not None: assert relative is None if isinstance(absolute, int): target_addr = absolute atarget = absolute elif isinstance(absolute, Address): target_addr = absolute.displacement atarget = absolute.displacement else: raise NotImplementedError if target_addr not in label_dict: label_dict[target_addr] = "branch_%x" % target_addr if target_addr in instr_dict: instr_dict[target_addr][2] = label_dict[target_addr] instr_dict[counter] = [binary, asm, label, rtarget, atarget] counter = counter + (len(masm) // 2) print("") print("%s:\tfile format raw %s" % (os.path.basename(arguments['input_dma_file']), target.isa.name)) print("") print("") print("Disassembly of section .code:") print("") str_format = "%8s:\t%-" + str(maxlen) + "s\t%s" for counter in sorted(instr_dict.keys()): binary, asm, label, rtarget, atarget = instr_dict[counter] if label is not None: print("%016x <%s>:" % (counter, label)) cformat = str_format if rtarget is not None: cformat = str_format + "\t <%s>" % (label_dict[counter + rtarget]) elif atarget is not None: cformat = str_format + "\t <%s>" % (label_dict[atarget]) print(cformat % (hex(counter)[2:], binary, asm))