Esempio n. 1
0
    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
Esempio n. 2
0
    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
Esempio n. 3
0
    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
        ]
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
    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
Esempio n. 7
0
    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)
Esempio n. 8
0
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
Esempio n. 9
0
    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)
Esempio n. 10
0
    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
Esempio n. 11
0
    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
Esempio n. 12
0
    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
Esempio n. 13
0
    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)
Esempio n. 14
0
    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
Esempio n. 15
0
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'])
Esempio n. 16
0
    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
Esempio n. 17
0
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
Esempio n. 18
0
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
Esempio n. 19
0
    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))
Esempio n. 20
0
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'])
Esempio n. 21
0
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))