def __init__(self, default_context=None, code_segment=None, data_segment=None, symbolic=True, absolute=False): """ :param default_context: (Default value = None) :param code_segment: (Default value = None) :param data_segment: (Default value = None) :param symbolic: (Default value = True) """ self._reserved_registers = RejectingDict() self._register_values = [{}, {}] self._memory_values = [{}, {}] self._data_segment = data_segment self._code_segment = code_segment self._symbolic = symbolic self._fabsolute = absolute self._dat = None if default_context is not None: self = default_context.copy()
def __init__(self, strict=False, instructions=None): """ """ super(ResolveSymbolicReferencesPass, self).__init__() self._description = "Translate labels of address into values" self._labels = RejectingDict() self._strict = strict self._instructions = [] if instructions is not None: self._instructions = instructions
def _interpret_decorators(str_decorators): decorators = RejectingDict() if str_decorators is None: return decorators for decorator_def in str_decorators.split(" "): if decorator_def == '': continue key = decorator_def.split("=")[0].upper() lvalue = (decorator_def + "=").split("=")[1].split(",") for idx, value in enumerate(lvalue): if os.path.isfile(value): print(value) exit(-1) else: origvalue = value value = value.upper() if value == '': value = None elif value == 'ON': value = True elif value == 'OFF': value = False elif value == 'TRUE': value = True elif value == 'FALSE': value = False elif value.isdigit(): value = int(value) elif value.startswith("0X"): try: value = int(value, 16) except ValueError: value = origvalue else: value = origvalue lvalue[idx] = value try: if len(lvalue) == 1: decorators[key] = lvalue[0] else: decorators[key] = lvalue except MicroprobeDuplicatedValueError: raise MicroprobeAsmError( "Decorator with key '%s' specified twice for the same " "instruction." % key) return decorators
def __init__(self, target, **kwargs): """ """ super(GenericDynamicAddressTranslation, self).__init__(target, **kwargs) self._map = RejectingDict() self._target = target self._control = self._control_keys.copy() self._control.update(kwargs) tmaps = kwargs.pop('dat_map', False) if tmaps: for tmap in tmaps: self.add_mapping(tmap[0], tmap[1], tmap[2])
def _init_properties(self): """ """ if self.__dict__.get("_properties", None) is None: # pylint: disable=attribute-defined-outside-init self._properties = RejectingDict()
class PropertyHolder(object): """Class to represent an object containing properties""" def _init_properties(self): """ """ if self.__dict__.get("_properties", None) is None: # pylint: disable=attribute-defined-outside-init self._properties = RejectingDict() # pylint: enable=attribute-defined-outside-init def register_property(self, prop, force=False): """ :param prop: """ self._init_properties() LOG.debug("Registering '%s' in '%s' (Force: '%s')", prop, self, force) if prop.name not in self._properties: self._properties[prop.name] = prop elif not prop.default: if force or self._properties[prop.name].default: del self._properties[prop.name] self._properties[prop.name] = prop else: self._properties[prop.name] = prop # Remove memoization at property registration if hasattr(self, prop.name): delattr(self, prop.name) # Memoize by accessing getattr(self, prop.name) def unregister_property(self, prop): """ :param prop: """ self._init_properties() del self._properties[prop.name] def list_properties(self, tabs=0): """ """ self._init_properties() rstr = "" if len(self._properties) == 0: rstr += " No properties \n" return rstr maxname = max( [ len(str(value.name)) for value in six.itervalues(self._properties) ] ) + 2 maxvalue = max( [ len(str(value.value)) for value in six.itervalues(self._properties) ] ) maxdesc = max( [ len(str(value.description)) for value in six.itervalues(self._properties) ] ) strfmt = "\t" * tabs strfmt += "%%-%ds:\t%%-%ds\t(%%-%ds)\n" % (maxname, maxvalue, maxdesc) for key in sorted(six.iterkeys(self._properties)): value = self._properties[key] rstr += strfmt % (value.name, value.value, value.description) return rstr @property def properties(self): """ """ return self._properties.copy() def __getattr__(self, name): """ :param name: """ self._init_properties() if name in self._properties: # Memoize properties # They can not change over the execution value = self._properties[name].value setattr(self, name, value) return value raise AttributeError( "'%s' object has no attribute '%s'" % (self.__class__.__name__, name) )
def _interpret_decorators(str_decorators): decorators = RejectingDict() if str_decorators is None: return decorators for decorator_def in str_decorators.split(" "): if decorator_def == '': continue key = decorator_def.split("=")[0].upper() lvalue = (decorator_def + "=").split("=")[1].split(",") nvalue = [] for idx, value in enumerate(lvalue): if value == '': continue if os.path.isfile(value): print(value) raise NotImplementedError else: origvalue = value value = value.upper() if value == '': value = None elif value == 'ON': value = True elif value == 'OFF': value = False elif value == 'TRUE': value = True elif value == 'FALSE': value = False elif value.isdigit(): value = int(value) elif value.startswith("0X"): if value.count("-") > 1: value = range_to_sequence(*value.split("-")) else: try: value = int(value, 16) except ValueError: value = origvalue else: value = origvalue if isinstance(value, list): nvalue.extend(value) else: nvalue.append(value) try: if len(lvalue) == 1: decorators[key] = nvalue[0] else: decorators[key] = nvalue except MicroprobeDuplicatedValueError: raise MicroprobeAsmError( "Decorator with key '%s' specified twice for the same " "instruction." % key) return decorators
import microprobe.code.ins from microprobe import MICROPROBE_RC from microprobe.code.address import Address, InstructionAddress from microprobe.exceptions import MicroprobeAsmError, \ MicroprobeCodeGenerationError, MicroprobeDuplicatedValueError, \ MicroprobeValueError from microprobe.target.isa.operand import InstructionAddressRelativeOperand, \ OperandConst, OperandImmRange, OperandValueSet from microprobe.utils.bin import interpret_bin from microprobe.utils.logger import get_logger from microprobe.utils.misc import Progress, RejectingDict, twocs_to_int, \ range_to_sequence # Constants LOG = get_logger(__name__) _ASM_CACHE = RejectingDict() _DECORATOR_CACHE = RejectingDict() __all__ = [ "interpret_asm", "MicroprobeAsmInstructionDefinition", "instruction_to_asm_definition" ] # Functions def interpret_asm(code, target, labels, log=True, show_progress=False, parallel=True, queue=None):
from six.moves import range, zip # Own modules import microprobe.code.ins from microprobe import MICROPROBE_RC from microprobe.exceptions import MicroprobeBinaryError, \ MicroprobeCodeGenerationError, MicroprobeValueError from microprobe.target.isa.instruction import instruction_type_from_bin from microprobe.utils.logger import get_logger from microprobe.utils.misc import Progress, \ RejectingDict, int_to_twocs, twocs_to_int # Constants LOG = get_logger(__name__) _BIN_CACHE = RejectingDict() _CODE_CACHE = RejectingDict() _DATA_CACHE = RejectingDict() _DATA_CACHE_LENGTHS = [] _DATA_CACHE_ENABLED = True _CODE_CACHE_ENABLED = True _BIN_CACHE_ENABLED = True __all__ = ["interpret_bin", "MicroprobeBinInstructionStream", ] # Functions def interpret_bin(code, target, fmt="hex", safe=None): """ Return the list of :class:`~.MicroprobeInstructionDefinition` objects
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
import six # Own modules import microprobe.code.wrapper from microprobe.code.address import Address from microprobe.code.context import Context from microprobe.utils.cmdline import print_info from microprobe.utils.logger import get_logger from microprobe.utils.misc import RejectingDict # Constants LOG = get_logger(__name__) __all__ = [ "QTrace", ] _INSTR_CACHE = RejectingDict() # Functions # Classes class QTrace(microprobe.code.wrapper.Wrapper): """:class:`Wrapper` to generate QT files (.qt). """ def __init__( self, init_code_address=0x01500000, init_data_address=0x01600000, reset=False, ):
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))
def import_properties(filename, objects): """ :param filename: :param objects: """ LOG.info("Start importing object properties") dirname = filename[::-1].replace('lmay.', 'sporp_', 1)[::-1] if not os.path.isdir(dirname): return for filename in os.listdir(dirname): if filename.startswith(".") or filename.endswith(".cache"): continue if not filename.endswith(".yaml"): continue property_definitions = read_yaml( os.path.join( dirname, filename ), SCHEMA ) for property_def in property_definitions: property_objs = RejectingDict() property_name = property_def["Name"] property_description = property_def.get( "Description", "No description" ) property_override = property_def.get("Override", False) property_default_value = property_def.get("Default", "__unset__") property_values = property_def.get("Values", {}) property_class = Property LOG.debug( "Importing property '%s - %s'", property_name, property_description ) if "Value" in property_def: # Single value property_value = property_def["Value"] default_property = property_class( property_name, property_description, property_value ) for obj in objects.values(): obj.register_property( default_property, force=property_override ) LOG.debug("Single value property") continue if ( property_default_value != "__unset__" and property_default_value != "NO_DEFAULT" ): default_property = property_class( property_name, property_description, property_default_value, default=True ) LOG.debug("Default value: %s", property_default_value) else: default_property = None LOG.debug("Default value: No default value set") for key, obj in objects.items(): if key not in property_values: if property_default_value == "NO_DEFAULT": continue if default_property is None: raise MicroprobeArchitectureDefinitionError( "Wrong property '%s' definition in file '%s'. " "Value for '%s' is not provided and a default " "value is not defined" % ( property_name, filename, key ) ) obj.register_property( default_property, force=property_override ) else: property_value = property_values[key] del property_values[key] property_value_key = property_value if isinstance(property_value, list): property_value_key = str(property_value) if property_value_key in property_objs: obj.register_property( property_objs[property_value_key], force=property_override ) else: new_property = property_class( property_name, property_description, property_value, default=False ) obj.register_property( new_property, force=property_override ) property_objs[property_value_key] = new_property for key, value in property_values.items(): LOG.warning( "'%s' not found. Property '%s' not set to '%s'", key, property_name, value ) LOG.info("Property '%s' imported", property_name) LOG.info("End importing object properties")
class ResolveSymbolicReferencesPass(microprobe.passes.Pass): """ResolveSymbolicReferencesPass pass. """ def __init__(self, strict=False, instructions=None): """ """ super(ResolveSymbolicReferencesPass, self).__init__() self._description = "Translate labels of address into values" self._labels = RejectingDict() self._strict = strict self._instructions = [] if instructions is not None: self._instructions = instructions 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 [] def _register_label(self, instruction): """ :param instruction: """ if instruction.label is None: return else: self._labels[instruction.label.upper()] = instruction def _translate_label(self, instruction, context): """ :param instruction: :param context: """ if self._instructions != []: if instruction.name not in self._instructions: return for operand in instruction.operands(): if operand.value is None: continue if not isinstance(operand.value, Address): continue address = operand.value LOG.debug("Translating label: '%s' of instruction '%s'", address, instruction.name) if isinstance(address, InstructionAddress): if address.target_instruction is not None: target_address = address.target_instruction.address comment = "Reference to instruction at" elif (isinstance(address.base_address, str) and address.base_address.upper() in list( self._labels.keys())): target_address = self._labels[ address.base_address.upper()].address + \ address.displacement comment = "Reference to %s at" % address elif (isinstance(address.base_address, str) and address.base_address.upper() == "CODE"): target_address = address comment = "Reference to %s at" % address else: LOG.critical(address.base_address) LOG.critical(address) LOG.critical(list(self._labels.keys())) raise NotImplementedError if operand.type.address_relative: if context.code_segment is not None: instruction.add_comment( "%s %s" % (comment, hex(context.code_segment + target_address.displacement))) relative_offset = target_address - instruction.address operand.set_value(relative_offset, check=self._strict) else: raise NotImplementedError elif isinstance(address.base_address, Variable): target_address = Address( base_address=address.base_address.address, displacement=address.displacement) if operand.type.address_relative: # Code referencing data, fix address taking into account # code and data offsets if instruction.address.base_address == "code" and \ target_address.base_address == "data" and \ context.data_segment is not None and \ context.code_segment is not None: instruction_address = Address( base_address="temp", displacement=context.code_segment + instruction.address.displacement) data_address = Address( base_address="temp", displacement=context.data_segment + target_address.displacement) # instruction_address = Address(base_address="data", # displacement=instruction.address.displacement) relative_offset = data_address - instruction_address try: operand.set_value(relative_offset) except MicroprobeValueError: raise MicroprobeCodeGenerationError( "Unable to codify the relative offset from " "instruction at 0x%x to data at 0x%x. " "Review the correctness of the addresses and " "change them." % (instruction_address.displacement, data_address.displacement)) comment = "Reference to var '%s' at" \ % address.base_address.name instruction.add_comment( "%s %s" % (comment, hex(data_address.displacement))) else: LOG.critical(instruction.address.base_address) LOG.critical(target_address.base_address) LOG.critical(context.data_segment) LOG.critical(context.code_segment) LOG.critical(context.symbolic) LOG.critical(target_address) LOG.critical(instruction) LOG.critical(operand) raise NotImplementedError else: raise NotImplementedError else: LOG.critical(instruction, instruction.address, address) LOG.critical(address.base_address, type(address.base_address)) raise NotImplementedError
def __init__(self): """ """ super(NormalizeBranchTargetsPass, self).__init__() self._description = "Normalize branch targets to remove the usage" \ "of labels" self._labels = RejectingDict()
class NormalizeBranchTargetsPass(Pass): """NormalizeBranchTargetsPass pass. """ def __init__(self): """ """ super(NormalizeBranchTargetsPass, self).__init__() self._description = "Normalize branch targets to remove the usage" \ "of labels" self._labels = RejectingDict() 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: for instr in (elem for elem in bbl.instrs if elem.label is not None): self._register_label(instr) 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._normalize_label(instr) for bbl in building_block.cfg.bbls: for instr in bbl.instrs: self._normalize_label(instr) for instr in building_block.fini: self._normalize_label(instr) return [] def _register_label(self, instruction): """ :param instruction: """ if instruction.label is None: return else: self._labels[instruction.label.upper()] = instruction def _normalize_label(self, instruction): """ :param instruction: :param context: """ for operand in instruction.operands(): if operand.value is None: continue if not isinstance(operand.value, InstructionAddress): continue address = operand.value LOG.debug("Normalizing label: '%s' of instruction '%s'", address, instruction.name) if address.target_instruction is not None: target_address = address.target_instruction.address 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 else: LOG.critical(address.base_address) LOG.critical(address) LOG.critical(list(self._labels.keys())) raise NotImplementedError operand.set_value(target_address) for moperand in instruction.memory_operands(): if moperand.address is None: continue if not isinstance(moperand.address, InstructionAddress): continue address = moperand.address LOG.debug("Normalizing label: '%s' of instruction '%s'", address, instruction.name) if address.target_instruction is not None: target_address = address.target_instruction.address 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 else: LOG.critical(address.base_address) LOG.critical(address) LOG.critical(list(self._labels.keys())) raise NotImplementedError moperand.update_address(target_address)
class Context(object): # pylint: disable=too-many-public-methods """Class to represent the execution context (e.g. register values, etc ... on each benchmark building block) """ def __init__(self, default_context=None, code_segment=None, data_segment=None, symbolic=True, absolute=False): """ :param default_context: (Default value = None) :param code_segment: (Default value = None) :param data_segment: (Default value = None) :param symbolic: (Default value = True) """ self._reserved_registers = RejectingDict() self._register_values = [{}, {}] self._memory_values = [{}, {}] self._data_segment = data_segment self._code_segment = code_segment self._symbolic = symbolic self._fabsolute = absolute self._dat = None if default_context is not None: self = default_context.copy() def copy(self): """Returns a copy of the current context.""" newcontext = Context() # pylint: disable=protected-access newcontext._reserved_registers = smart_copy_dict( self._reserved_registers) newcontext._register_values[0] = smart_copy_dict( self._register_values[0]) newcontext._register_values[1] = smart_copy_dict( self._register_values[1]) newcontext._memory_values[0] = smart_copy_dict(self._memory_values[0]) newcontext._memory_values[1] = smart_copy_dict( self._register_values[1]) if self._dat is not None: newcontext.set_dat(self._dat.copy()) newcontext.set_code_segment(self.code_segment) newcontext.set_data_segment(self.data_segment) newcontext.set_symbolic(self.symbolic) newcontext.set_absolute(self.force_absolute) return newcontext def add_reserved_registers(self, rregs): """Add the provided registers into the reserved register list. :param rregs: Registers to reserve :type rregs: :class:`~.list` of :class:`~.Register` """ for reg in rregs: self._reserved_registers[reg.name] = reg def remove_reserved_registers(self, rregs): """Remove the provided registers from the reserved register list. :param rregs: Registers to un-reserve :type rregs: :class:`~.list` of :class:`~.Register` """ for reg in rregs: del self._reserved_registers[reg.name] def set_register_value(self, register, value): """Set the provided register to the specified value. :param register: Register to set :type register: :class:`~.Register` :param value: Value to assign :type value: :class:`~.int`, :class:`~.float`, :class:`~.long`, :class:`~.Address` or :class:`~.str` """ LOG.debug("Setting %s to %s", register.name, value) assert isinstance( value, tuple( list(six.integer_types) + [float, Address, InstructionAddress, str])), type(value) if isinstance(value, str): assert len(value.split("_")) == 2 if self.get_register_value(register) is not None: self.unset_register(register) self._register_values[0][register] = value if value in self._register_values[1]: if register not in self._register_values[1][value]: self._register_values[1][value].append(register) else: self._register_values[1][value] = [register] # assert self.get_register_value(register) == value # assert value in self._register_values[1].keys() # assert self._register_values[0][register] == value def get_closest_address_value(self, address): """Returns the closest address to the given address. Returns the closest address to the given address. If there are not addresses registered, `None` is returned. :param address: Address to look for :type address: :class:`~.Address` """ possible_regs = [] for reg, value in self._register_values[0].items(): if not isinstance(value, Address): continue if Address(base_address=value.base_address) == \ Address(base_address=address.base_address): possible_regs.append((reg, value)) possible_regs = sorted( possible_regs, key=lambda x: abs(x[1].displacement - address.displacement)) if possible_regs: return possible_regs[0] return None def get_register_closest_value(self, value): """Returns the register with the closest value to the given value. Returns the register with the closest value to the given value. If there are not values registered, `None` is returned. Address values are ignored. :param value: Value to look for :type value: :class:`~.int`, :class:`~.float`, :class:`~.long`, :class:`~.Address` or :class:`~.str` """ possible_regs = [] for reg, reg_value in self._register_values[0].items(): if isinstance(value, Address): continue if not isinstance(reg_value, type(value)): continue if isinstance(reg_value, str): if reg_value.split("_")[1] != value.split(" ")[1]: continue possible_regs.append((reg, reg_value)) if not isinstance(value, str): possible_regs = sorted(possible_regs, key=lambda x: abs(x - value)) else: possible_regs = sorted( possible_regs, key=lambda x: abs( int(x.split("_")[0]) - int(value.split("_")[0]))) if possible_regs: return possible_regs[0] return None def get_register_value(self, register): """Returns the register value. `None` if not found. :param register: Register to get its value :type register: :class:`~.Register` """ value = self._register_values[0].get(register, None) if value is not None: assert value in self._register_values[1].keys() return value def get_registername_value(self, register_name): """Returns the register value. `None` if not found. :param register: Register name to get its value :type register: :class:`~.str` :param register_name: """ assert isinstance(register_name, str) register_names = [reg.name for reg in self._register_values[0]] if register_name not in register_names: return None register = [ reg for reg in self._register_values[0] if reg.name == register_name ][0] return self._register_values[0].get(register, None) def unset_registers(self, registers): """Removes the values from registers. :param registers: List of registers :type registers: :class:`~.list` of :class:`~.Register` """ for reg in registers: self.unset_register(reg) def unset_register(self, register): """Remove the value from a register. :param register: Registers :type register: :class:`~.Register` """ assert self._register_values[0][register] is not None value = self._register_values[0][register] self._register_values[1][value].remove(register) if not self._register_values[1][value]: del self._register_values[1][value] self._register_values[0][register] = None def set_memory_value(self, mem_value): """Sets a memory value. :param mem_value: Memory value to set. :type mem_value: :class:`~.MemoryValue` """ LOG.debug("Start set memory value: %s", mem_value) self.unset_memory(mem_value.address, mem_value.length) self._memory_values[0][mem_value.address] = mem_value if mem_value.value in self._memory_values[0]: if mem_value not in self._memory_values[1][mem_value.value]: self._memory_values[1][mem_value.value].append(mem_value) LOG.debug("Values inv %s: %s", mem_value.value, self._memory_values[1][mem_value.value]) else: LOG.debug("Already in inv dictionary") else: self._memory_values[1][mem_value.value] = [mem_value] LOG.debug("Values inv %s: %s", mem_value.value, [mem_value]) assert self._memory_values[0][mem_value.address] == mem_value assert mem_value in self._memory_values[1][mem_value.value] LOG.debug("End set memory value: %s", mem_value) def get_memory_value(self, address): """Gets a memory value. :param address: Address to look for :type address: :class:`~.Address` """ if address in self._memory_values[0]: return self._memory_values[0][address] return None def unset_memory(self, address, length): """Unsets a memory region. :param address: Start address of the region :type address: :class:`~.Address` :param length: Length in bytes of the region :type length: :class:`~.int` """ LOG.debug("Start unset address: %s (length: %s)", address, length) possible_addresses = [ addr for addr in self._memory_values[0] if addr.base_address == address.base_address ] # LOG.debug("Possible addresses: %s", possible_addresses) for paddr in possible_addresses: diff = paddr - address diff2 = address - paddr length2 = self._memory_values[0][paddr].length if ((diff >= 0 and diff < length) or (diff2 >= 0 and diff2 < length2)): LOG.debug("Address overlap: %s", paddr) mem_value = self._memory_values[0].pop(paddr) LOG.debug("Memory value: %s", mem_value) if mem_value in self._memory_values[1][mem_value.value]: self._memory_values[1][mem_value.value].remove(mem_value) LOG.debug("Finish unset address: %s (length: %s)", address, length) def register_has_value(self, value): """Returns if a value is in a register. :param value: Value to look for :type value: :class:`~.bool` """ return value in list([ elem for elem in self._register_values[1].keys() if type(elem) == type(value) ]) def registers_get_value(self, value): """Gets a list of registers containing the specified value. :param value: Value to look for :type value: :class:`~.int` or :class:`~.float` or :class:`~.Address` """ keyl = [key for key in self._register_values[1] if key == value] if len(keyl) != 1: assert keyl == 1 return self._register_values[1][keyl[0]] @property def register_values(self): """Dictionary of register, value pairs (:class:`~.dict`)""" return self._register_values[0] @property def reserved_registers(self): """List of reserved registers (:class:`~.list`)""" return list(self._reserved_registers.values()) @property def data_segment(self): """Address starting the data segment (::class:`~.int`)""" return self._data_segment def set_data_segment(self, value): """Sets the data segment start address. :param value: Start address. :type value: ::class:`~.int` """ self._data_segment = value @property def dat(self): """DAT object (:class:`~.DynamicAddressTranslation`""" return self._dat def set_dat(self, dat): """Sets the dynamic address translation object. :param dat: DAT object. :type dat: :class:`~.DynamicAddressTranslation` """ self._dat = dat @property def code_segment(self): """Address starting the code segment (::class:`~.int`)""" return self._code_segment def set_code_segment(self, value): """Sets the code segment start address. :param value: Start address. :type value: :class:`~.int` """ self._code_segment = value @property def symbolic(self): """Boolean indicating if the context allows symbol labels Boolean indicating if the context allows symbol labels (:class:`~.bool`) """ return self._symbolic def set_symbolic(self, value): """Sets the symbolic property. :param value: Boolean indicating if the context allows symbol labels :type value: :class:`~.bool` """ self._symbolic = value @property def force_absolute(self): """Boolean indicating if absolute addresses are needed. Boolean indicating if absolute addresses are needed (:class:`~.bool`) """ return self._fabsolute def set_absolute(self, value): """Sets the force_absolute property. :param value: Boolean indicating if absolute addresses are needed :type value: :class:`~.bool` """ self._fabsolute = value # def _validate(self): # for register in self._register_values[0]: # value = self._register_values[0][register] # if value is not None: # assert register in self._register_values[1][value] def dump(self): """Return a dump of the current context status. Return a dump of the current context status. Very useful for pass debugging purposes. """ mstr = [] mstr.append("-" * 80) mstr.append("Context status:") mstr.append("Reserved Registers:") for key, value in sorted(self._reserved_registers.items()): mstr.append("Idx:\t%s\tValue:\t%s" % (key, value)) mstr.append("Registers values:") for key, value in sorted(self._register_values[0].items()): mstr.append("Idx:\t%s\tRaw Value:\t%s" % (key, value)) mstr.append("Registers values inverted:") for key, value in sorted(self._register_values[1].items()): mstr.append("Idx:\t%s\tValue:\t%s" % (key, value)) mstr.append("Memory values:") for key, value in sorted(self._memory_values[0].items()): mstr.append("Idx:\t%s\tRaw Value:\t%s" % (key, value)) mstr.append("Memory values inverted:") for key, value in sorted(self._memory_values[1].items()): mstr.append("Idx:\t%s\tValue:\t%s" % (key, value)) mstr.append("Code segment: %s" % self._code_segment) mstr.append("Data segment: %s" % self._data_segment) mstr.append("Symbolic context: %s" % self._symbolic) mstr.append("-" * 80) return "\n".join(mstr)
# Constants LOG = get_logger(__name__) _BIN_CACHE_ENABLED = True _BIN_CACHE_FILE = __file__ + ".bin" _BIN_CACHE = None _BIN_CACHE_USED = False _BIN_CACHE_SIZE = 16*1024 _CODE_CACHE_ENABLED = True _CODE_CACHE_FILE = __file__ + ".code" _CODE_CACHE = None _CODE_CACHE_USED = False _CODE_CACHE_SIZE = 16*1024 _DATA_CACHE = RejectingDict() _DATA_CACHE_LENGTHS = [] _DATA_CACHE_ENABLED = True __all__ = ["interpret_bin", "MicroprobeBinInstructionStream", ] # Functions def interpret_bin( code, target, fmt="hex", safe=None, single=False, little_endian=None, word_length=None ): """ Return the list of :class:`~.MicroprobeInstructionDefinition` objects that results from interpreting the *code* (a binary stream).
def import_definition(cls, filenames, element_types): """ """ LOG.debug("Start importing microarchitecture elements") elements = RejectingDict() elements_subelements = RejectingDict() for filename in filenames: element_data = read_yaml(filename, SCHEMA) if element_data is None: continue for elem in element_data: name = elem["Name"] parent = elem.get("Parent", None) subelements = elem.get("Subelements", []) repeat = elem.get("Repeat", None) rfrom = 0 rto = 0 replace = "0" try: elem_type = element_types[elem["Type"]] except KeyError: raise MicroprobeArchitectureDefinitionError( "Unknown " "microarchitecture element type in " "microarchitecture element definition " " '%s' found in '%s'" % (name, filename)) descr = elem.get("Description", elem_type.description) if repeat: rfrom = repeat["From"] replace = "%s" % rfrom rto = repeat["To"] for index in range(rfrom, rto + 1): cname = name.replace(replace, "%d" % index) cdescr = descr.replace(replace, "%d" % index) element = cls(cname, cdescr, elem_type) try: elements[cname] = element elements_subelements[cname] = subelements except ValueError: raise MicroprobeArchitectureDefinitionError( "Duplicated microarchitecture element " "definition '%s' found in '%s'" % (name, filename)) LOG.debug(element) for filename in filenames: import_properties(filename, elements) for elem, subelements in elements_subelements.items(): try: subelements_instances = [elements[item] for item in subelements] except KeyError as exc: raise MicroprobeArchitectureDefinitionError( "Undefined sub-element '%s' in element " "definition '%s'. Check following " "files: %s" % (exc, elem, filenames)) elements[elem].set_subelements(subelements_instances) element_list = list(elements.values()) fixing_hierarchy = True LOG.info("Start building element hierarchy...") fix_pass = 0 while fixing_hierarchy: fix_pass += 1 LOG.debug("Start building element hierarchy... pass %d", fix_pass) fixing_hierarchy = False for element in element_list: parents = [ item for item in element_list if element in item.subelements ] if len(parents) > 1: # needs duplication LOG.debug("Element %s has %d parents", element, len(parents)) for parent in sorted(parents): LOG.debug("Duplicating for parent: %s", parent) # Create a new copy new_element = cls(element.name, element.description, element.type) new_element.set_subelements(element.subelements) element_list.append(new_element) # Update parent to point to the new copy new_subelements = parent.subelements new_subelements.remove(element) new_subelements.append(new_element) parent.set_subelements(new_subelements) fixing_hierarchy = True element_list.remove(element) LOG.info("Finish building element hierarchy") # Check correctness of the structure and set parents LOG.info("Checking element hierarchy...") top_element = None for element in element_list: parents = [ item for item in element_list if element in item.subelements ] if len(parents) > 1: raise MicroprobeArchitectureDefinitionError( "Wrong hierarchy of microarchitecture " "elements. The definition of element" " '%s' has multiple parents: '%s'." % (element, [str(elem) for elem in parents])) elif len(parents) == 0: if top_element is not None: raise MicroprobeArchitectureDefinitionError( "Wrong hierarchy of microarchitecture " "elements. There are at least two top " "elements: '%s' and '%s'. Define a single " "parent element for all the hierarchy." % (element, top_element)) top_element = element else: element.set_parent_element(parents[0]) if top_element is None: raise MicroprobeArchitectureDefinitionError( "Wrong hierarchy of microarchitecture " "elements. There is not a top element." " Define a single parent element for all " "the hierarchy.") LOG.info("Element hierarchy correct") elem_dict = dict([(element.full_name, element) for element in element_list]) for filename in filenames: import_properties(filename, elem_dict) LOG.info("End importing elements") return elem_dict