Exemple #1
0
    def __init__(
            self, code, target, fmt="hex",
            _data_cache=False, little_endian=None, word_length=None
            ):
        """

        :param code:
        :type code:
        :param target:
        :type target:
        """

        self._little_endian = target.little_endian

        if little_endian is not None:
            self._stream_little_endian = little_endian
        else:
            self._stream_little_endian = target.little_endian

        endianess_missmatch = self._little_endian != self._stream_little_endian

        self._code = _normalize_code(
            code,
            fmt=fmt,
            endianess_missmatch=endianess_missmatch,
            word_length=word_length
        )
        self._fmt = fmt
        self._target = target

        self._index = 0
        self._data_cache = _data_cache
        self._lenghts = list(sorted(_compute_target_lengths(target),
                                    reverse=True))
        self._progress = Progress(len(self._code), msg="Bytes parsed:")
Exemple #2
0
    def __call__(self, building_block, dummy_target):
        """

        :param building_block:
        :param dummy_target:

        """

        for instr in (elem for elem in building_block.init
                      if elem.label is not None):
            self._register_label(instr)

        for bbl in building_block.cfg.bbls:
            if MICROPROBE_RC['verbose']:
                progress = Progress(len(bbl.instrs), "Registering labels:")
            for instr in (elem for elem in bbl.instrs
                          if elem.label is not None):
                self._register_label(instr)

                if MICROPROBE_RC['verbose']:
                    progress()

        for instr in (elem for elem in building_block.fini
                      if elem.label is not None):
            self._register_label(instr)

        for instr in building_block.init:
            self._translate_label(instr, building_block.context)

        for bbl in building_block.cfg.bbls:
            if MICROPROBE_RC['verbose']:
                progress = Progress(len(bbl.instrs), "Translating labels:")
            for instr in bbl.instrs:
                self._translate_label(instr, building_block.context)
                if MICROPROBE_RC['verbose']:
                    progress()

        for instr in building_block.fini:
            self._translate_label(instr, building_block.context)

        return []
Exemple #3
0
    def __init__(self, code, target, fmt="hex", _data_cache=False):
        """

        :param code:
        :type code:
        :param target:
        :type target:
        """
        self._code = _normalize_code(code, fmt=fmt)
        self._fmt = fmt
        self._target = target
        self._index = 0
        self._data_cache = _data_cache
        self._lenghts = list(reversed(sorted(_compute_target_lengths(target))))
        self._progress = Progress(len(self._code), msg="Bytes parsed:")
Exemple #4
0
    def __init__(self, size, instructions=None):
        """

        :param size:

        """
        if size < 1:
            raise MicroprobeValueError("I can not create a Bbl with %d size" %
                                       size)

        if instructions is None:
            instructions = []

        self._copy_id = 0

        self._incstep = 10000
        self._instrs = [None] * max(self._incstep, (size + 1) * 10)
        self._pointer = 10

        self._instdic = {}

        self._address = None
        self._displacement = 0

        if MICROPROBE_RC["verbose"]:
            progress = Progress(size, "Initializing BBL:")

        if not instructions:
            for idx in range(0, size):
                # self._check_size()
                instr = microprobe.code.ins.Instruction()
                self._instrs[self._pointer] = instr
                self._instdic[instr] = self._pointer
                self._pointer += 10
                if MICROPROBE_RC["verbose"]:
                    progress()
        else:
            for idx in range(0, size):
                self._check_size()
                if idx < len(instructions):
                    self._instrs[self._pointer] = instructions[idx]
                else:
                    self._instrs[self._pointer] = \
                        microprobe.code.ins.Instruction()
                self._instdic[self._instrs[self._pointer]] = self._pointer
                self._pointer += 10
                if MICROPROBE_RC["verbose"]:
                    progress()
def _set_props(largs, queue=None, show_progress=False):

    rlist = []

    if show_progress:
        progress = Progress(len(largs), msg="Setting instruction properties: ")

    for args in largs:
        instr, definition, building_block, target, displ = args
        instruction_set_def_properties(instr,
                                       definition,
                                       building_block=building_block,
                                       target=target,
                                       label_displ=displ)

        if show_progress:
            progress()

        rlist.append(instr)

    if queue is not None:
        queue.put(rlist)

    return rlist
Exemple #6
0
    def _wrap(self, bench):
        """Wrap a benchmark.

        This function wraps a benchmark using the synthesizer wrapper. The
        wrapping process is the process of converting the internal
        representation of the benchmark to the actual string that is written
        to a file, adding the necessary prologue and epilogue bytes of
        data.

        :param bench: Benchmark to wrap.
        :type bench: :class:`~.Benchmark`
        :return: A string representation of the benchmark
        :rtype: :class:`~.str`
        """
        self.wrapper.set_benchmark(bench)

        bench_str = []
        bench_str.append(self.wrapper.headers())

        instructions = []
        instructions_dict = {}
        instructions_next_dict = {}

        for instr in bench.init:
            instructions.append(instr)

        for bbl in bench.cfg.bbls:
            for instr in bbl.instrs:
                instructions.append(instr)

        for instr in bench.fini:
            instructions.append(instr)

        for instr in instructions:
            instructions_dict[instr.address] = instr
            if (instr.branch or instr.syscall or instr.trap):
                instructions_next_dict[instr.address] = \
                    instr.decorators['NI']['value']
            else:
                instructions_next_dict[instr.address] = \
                    instr.address + instr.architecture_type.format.length

        instr = instructions[0]
        count = 0

        cmd.cmdline.print_info(
            "Maximum trace size: %s instructions " %
            self._maxins)

        progress = Progress(self._maxins, msg="Instructions generated:")

        while True:

            count = count + 1

            if count > self._maxins:
                cmd.cmdline.print_info(
                    "Max number of instructions (%d) reached. "
                    "Stoping trace generation." % self._maxins)
                break

            try:
                instr_address = instructions_next_dict[instr.address]
                if not isinstance(instr_address, InstructionAddress):
                    instr_address = next(instr_address)

                next_instr = instructions_dict[instr_address]

            except KeyError:
                cmd.cmdline.print_info(
                    "Jump to an unknown instruction in address "
                    "%s found. Stoping trace generation." %
                    instr_address)
                break

            progress()
            wrap_ins = self.wrapper.wrap_ins(instr,
                                             next_instr=next_instr,
                                             show=self._show_trace)

            bench_str.append(
                wrap_ins
            )

            instr = next_instr

        bench_str = [elem for elem in bench_str if elem != ""]
        return bench_str
Exemple #7
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
Exemple #8
0
def interpret_asm(code,
                  target,
                  labels,
                  log=True,
                  show_progress=False,
                  parallel=True,
                  queue=None):
    """
    Return the list of :class:`~.MicroprobeInstructionDefinition` objects
    that results from interpreting the *code* (list of assembly statements).
    The *target* object is used to validate the existence of the instruction
    and operands in the target and the *labels* are needed to validate the
    correctness of the symbolic labels used in the assembly statements.

    :param code: Assembly to interpret
    :type code: :class:`list` of :class:`~.MicroprobeAsmInstructionDefinition`
                or string/s to interpret
    :param target: Target definition
    :type target: :class:`~.Target` object
    :param labels: Labels available
    :type labels: :class:`~.list` of :class:`~.str`
    :return: A list of instructions, operands, labels, etc. resulting from
            interpreting the assembly
    :rtype: :class:`~.list` of :class:`~.MicroprobeInstructionDefinition`
    :raise microprobe.exceptions.MicroprobeAsmError: if something is wrong
        during the interpretation
    """

    LOG.debug("Start interpret_asm")
    instructions_and_params = []

    LOG.debug("Extract defined labels")
    def_labels = labels

    if def_labels is None:
        def_labels = []

    if isinstance(code, str):
        code = [code]

    if len(code) > MICROPROBE_RC["parallel_threshold"] and parallel:
        # Do parallel parsing
        processes = []
        queues = []

        chunksize = max(len(code) // MICROPROBE_RC['cpus'], 1)

        extra_args = {}
        extra_args['log'] = log
        extra_args['show_progress'] = show_progress
        extra_args['parallel'] = False

        for chunk in [
                code[i:i + chunksize] for i in range(0, len(code), chunksize)
        ]:
            queue = mp.Queue()
            extra_args['queue'] = queue
            proc = mp.Process(target=interpret_asm,
                              args=(chunk, target, def_labels),
                              kwargs=extra_args)
            processes.append(proc)
            queues.append(queue)
            proc.start()
            extra_args['show_progress'] = False

        instructions_and_params = []
        for queue in queues:
            instructions_and_params += queue.get()
            queue.close()
            queue.join_thread()

        for process in processes:
            process.join()
            process.terminate()

        return instructions_and_params

    try:

        if show_progress:
            progress = Progress(len(code), msg="Labels parsed:")

        for instr_def in code:

            if isinstance(instr_def, six.string_types):
                instr_def = _str_to_asmdef(instr_def)

            if instr_def.label in def_labels:
                raise MicroprobeAsmError("Label '%s' defined twice!" %
                                         instr_def.label)

            if instr_def.label is not None:
                def_labels.append(instr_def.label.upper())

            if show_progress:
                progress()

        if show_progress:
            progress = Progress(len(code), msg="Instructions parsed:")

        for instr_def in code:

            if isinstance(instr_def, six.string_types):
                instr_def = _str_to_asmdef(instr_def)

            intr_asm = _interpret_instr_def(instr_def, target, def_labels)

            instructions_and_params.append(intr_asm)

            LOG.debug("Instruction: '%s' interpreted", instr_def.assembly)

            if show_progress:
                progress()

    except MicroprobeAsmError as exc:

        if log:

            LOG.critical("Assembly provided:")
            LOG.critical("%20s\t%20s\t%25s\t%s", "-" * 20, "-" * 20, "-" * 25,
                         "-" * 20)
            LOG.critical("%20s\t%20s\t%25s\t%s", "label", "address",
                         "instruction", "decorators")
            LOG.critical("%20s\t%20s\t%25s\t%s", "-" * 20, "-" * 20, "-" * 25,
                         "-" * 20)
            for instr in code:
                if isinstance(instr, six.string_types):
                    instr = _str_to_asmdef(instr)

                address = "--"
                if instr.address is not None:
                    address = "0x%016x" % instr.address

                LOG.critical("%20s\t%20s\t%25s\t%s", instr.label, address,
                             instr.assembly, instr.decorators)
            LOG.critical("%20s\t%20s\t%25s\t%s", "-" * 20, "-" * 20, "-" * 25,
                         "-" * 20)

            LOG.critical("If the previous assembly is not correct, "
                         "check the format of the assembly file provided")
        raise exc

    LOG.debug("End interpret_asm")

    if queue is not None:
        queue.put(instructions_and_params)

    return instructions_and_params
    def _parallel(self, building_block, target):
        def _iter_zip(list1, list2, extra=None):
            idx = 0
            try:
                while True:
                    item1 = next(list1)
                    item2 = next(list2)
                    if extra is None:
                        yield (item1, item2, idx)

                    else:
                        yield tuple([item1, item2] + extra + [idx])
                    idx = idx + 1
            except StopIteration:
                return

        props = iter(self._sequence)

        for bbl in building_block.cfg.bbls:
            instrs = iter(bbl.instrs)
            instrs_props = list(
                _iter_zip(instrs, props, extra=[building_block, target]))

            csize = max(len(bbl.instrs) // MICROPROBE_RC['cpus'], 1)

            instrs_propsl = (instrs_props[idx:idx + csize]
                             for idx in range(0, len(self._sequence), csize))

            if MICROPROBE_RC['verbose']:
                print_info("Start mapping to %s threads ... " %
                           MICROPROBE_RC['cpus'])

            extra_args = {}
            extra_args['show_progress'] = True
            processes = []
            queues = []
            for chunk in instrs_propsl:
                queue = mp.Queue()
                extra_args['queue'] = queue
                proc = mp.Process(target=_set_props,
                                  args=(chunk, ),
                                  kwargs=extra_args)
                processes.append(proc)
                queues.append(queue)
                proc.start()
                extra_args['show_progress'] = False

            new_instrs = []
            for queue in queues:
                new_instrs += queue.get()

            progress = Progress(len(bbl.instrs),
                                msg="Setting instruction properties: ")

            instrs = iter(bbl.instrs)
            for instr, new_instr in zip(instrs, new_instrs):
                bbl.reset_instruction(instr, new_instr)
                progress()

            for queue in queues:
                queue.close()
                queue.join_thread()

            for process in processes:
                process.join()
                process.terminate()

        return []
Exemple #10
0
def interpret_objdump(
    objdump_output,
    target,
    strict=False,
    sections=None,
    start_address=-1,
    end_address=float('+inf')
):
    """
    Returns a :class:`~.MicroprobeTestDefinition` object
    that results from interpreting the objdump output.
    The *target* object is used to validate the existence of the instruction
    and operands.

    :param objdump_output: Assembly to interpret
    :type objdump_output: Objdump textual output
    :param target: Target definition
    :type target: :class:`~.Target` object
    :param strict: If set, fail if an opcode can not be interpreted.
                  (Default: False)
    :type strict: :class:`~.bool`
    :param sections: List of section names to parse
    :type sections: :class:`~.list` of :class:`~.str`
    :param start_address: Start address to interpret
    :type start_address: ::class:`~.int`
    :param end_address: End address to interpret
    :type end_address: ::class:`~.int`
    :return: An object representing the microprobe test
    :rtype: :class:`~.list` of :class:`~.MicroprobeTestDefinition`
    :raise microprobe.exceptions.MicroprobeObjdumpError: if something is wrong
        during the interpretation of the objdump
    """

    if not strict:
        MICROPROBE_RC['safe_bin'] = True

    if isinstance(objdump_output, str):
        objdump_output = objdump_output.replace('\r', '\n')
        objdump_output = objdump_output.split('\n')

    filtered_objdump_output = _objdump_cleanup(
        objdump_output, sections, start_address, end_address
    )

    code_labels = _find_code_labels(filtered_objdump_output)
    var_labels = _find_var_labels(filtered_objdump_output, code_labels)

    labels = code_labels + var_labels
    label_pattern = _generate_label_pattern(labels)

    binary_format = _binary_reformat(filtered_objdump_output)
    asm_format = _asm_reformat(filtered_objdump_output)

    assert len(binary_format) == len(asm_format)

    instr_defs = []
    current_labels = var_labels[:]

    progress = Progress(len(binary_format), msg="Lines parsed:")

    for binary, asm in zip(binary_format, asm_format):

        instr_def = None
        if not label_pattern.search(asm):
            try:
                instr_def = interpret_asm(binary, target, current_labels)
            except MicroprobeBinaryError:
                if strict:
                    raise MicroprobeObjdumpError(
                        "Unable to interpret binary '%s' (asm:' %s')" %
                        (binary, asm)
                    )
                else:
                    LOG.warning("Skiping binary '%s' (asm:' %s')", binary, asm)
                instr_def = None
        else:
            try:
                instr_def = interpret_asm(
                    asm, target, current_labels,
                    log=False
                )
            except MicroprobeAsmError:
                instr_def = interpret_asm(binary, target, current_labels)

        if instr_def is not None:
            fixed_instr_def = _fix_instr_definition(instr_def[0], asm, target)
            instr_defs.append(fixed_instr_def)

            if fixed_instr_def.label is not None:
                current_labels.append(fixed_instr_def.label)

        progress()

    variable_defs = []
    required_defs = []
    for var_label in var_labels:
        var_def = _interpret_variable(var_label, objdump_output)
        if var_def is not None:
            variable_defs.append(var_def)
        else:
            LOG.warning(
                "Variable label: '%s' referenced but not found "
                "in the dump"
            )
            required_defs.append(_default_variable(var_label))

    return variable_defs, required_defs, instr_defs
Exemple #11
0
def dump_dma(arguments):
    """

    :param target:
    :type target:
    :param arguments:
    :type arguments:
    """

    ifile = open(arguments['input_objdump_file'], 'r')
    inputlines = ifile.readlines()
    ifile.close()

    progress = Progress(len(inputlines), msg="Lines parsed:")
    lines_dict = {}
    caddress = None
    displace = 0
    for idx, line in enumerate(inputlines):

        idx = idx + 1
        progress()

        line = line.strip()

        if line == "" or "file format" in line or line.startswith("Disass"):
            continue

        tsplit = line.split("\t")

        if len(tsplit) not in [1, 3, 4]:
            raise MicroprobeObjdumpError("Unable to parse '%s' at line '%s'" %
                                         (line, idx))
        if len(tsplit) == 1:

            space_split = tsplit[0].split(" ")

            if len(space_split) != 2:
                raise MicroprobeObjdumpError(
                    "Unable to parse '%s' at line '%s'" % (line, idx))

            address, label = space_split

            if not label.endswith('>:') or label[0] != '<':
                raise MicroprobeObjdumpError(
                    "Unable to parse '%s' at line '%s'" % (line, idx))

            try:
                new_address = int(address, 16)
            except ValueError:
                raise MicroprobeObjdumpError(
                    "Unable to parse '%s' at line '%s'" % (line, idx))

            if caddress is None:
                caddress = new_address
            elif new_address != (caddress + displace):
                caddress = new_address
                displace = 0

            continue

        if len(tsplit) in [3, 4] and caddress is None:
            raise MicroprobeObjdumpError(
                "Unable to know the address of '%s' at line '%s'" %
                (line, idx))

        if not tsplit[0].endswith(":"):
            raise MicroprobeObjdumpError("Unable to parse '%s' at line '%s'" %
                                         (line, idx))

        if (caddress + displace) < int(tsplit[0][:-1], 16):

            caddress = int(tsplit[0][:-1], 16)
            displace = 0

        elif (caddress + displace) > int(tsplit[0][:-1], 16):

            raise MicroprobeObjdumpError(
                "Conflicting addresses in '%s' at line '%s'" % (line, idx))

        value = "".join(tsplit[1].split(' ')).lower()
        if caddress in lines_dict:
            lines_dict[caddress] += value
            displace += len(value) // 2
        else:
            lines_dict[caddress] = value
            displace = len(value) // 2

    used_addresses = RejectingDict()
    progress = Progress(len(list(lines_dict.keys())), msg="Writing output")

    with open(arguments['output_dma_file'], 'w') as fdout:

        for caddress in sorted(lines_dict):

            value = lines_dict[caddress]

            progress()

            if caddress % 8 != 0:

                contents = value[0:((caddress % 8) * 2)]
                value = value[((caddress % 8) * 2):]
                contents = "0" * (16 - len(contents)) + contents
                caddress = (caddress // 8) * 8

                line = "D %016x %s\n" % (caddress, contents)
                used_addresses[caddress] = line
                fdout.write(line)
                caddress += 8

            for idx in range(0, len(value), 16):

                contents = value[idx:idx + 16]
                contents += "0" * (16 - len(contents))

                line = "D %016x %s\n" % (caddress, contents)
                used_addresses[caddress] = line
                fdout.write(line)
                caddress += 8
Exemple #12
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))