Пример #1
0
    def _gen_default_action(self, nts):
        ''' add to to each nonterminal the default action that should be taken
        in case the no rule was satisfied '''

        for nt in nts:
            if nt.otherwise == 'error':
                err_fb = 'ERROR=XED_ERROR_GENERAL_ERROR'
                nt.default_action = actions.action_t(err_fb)
            else:
                #creating return action which return nothing
                nt.default_action = actions.gen_return_action('')
Пример #2
0
    def __init__(self, ii, eosz_nts, easz_nts, imm_nts, disp_nts,
                 brdisp_nts, mode_space, state_space):

        self.ptrn = ii.ipattern_input
        self.ptrn_wrds = self.ptrn.split()
        self.iclass = ii.iclass
        self.legal = True

        self.category = ii.category
        #FIXME: remove all members of ii stored directly as members
        self.ii = ii

        #incomplete_opcode is used for expanding opcodes that have registers
        #embedded in them
        self.incomplete_opcode = False

        #number of missing bits in incomplete opcode. usually 0 or 3
        self.missing_bits = 0

        self.insn_map = None
        self.opcode = None

        self.space = None # LEGACY|VEX|EVEX
        self.has_modrm = False

        self.imm_nt_seq = None

        self.disp_nt_seq = None

        #modrm.reg bits value, set only when it is explicitly
        #e.g. bounded: REG[010]
        self.ext_opcode = None

        #all legal values for MODE operand in this pattern
        self.mode = None


        #an ordered string of EOSZ setting NTs in the pattern
        #we will use it to create the eosz lookup table for the pattern
        self.eosz_nt_seq = None

        #same for EASZ
        self.easz_nt_seq = None

        #operand deciders of the pattern
        self.constraints = None
        self._set_constraints(ii, state_space)
        
        self.vv = None # vexvalid, integer
        self._set_vexvalid()
        
        self.encspace = None
        self._set_encoding_space()

        mi,insn_map,opcode = self._get_map_opcode()
        self.map_info = mi
        self.insn_map = insn_map
        self.opcode = opcode

        self.has_modrm = ild_modrm.get_hasmodrm(self.ptrn)
        self.set_ext_opcode()

        self.set_mode(ii, mode_space)

        self.eosz_nt_seq = ild_eosz.get_eosz_nt_seq(self.ptrn_wrds,
                                                         eosz_nts)

        self.easz_nt_seq = ild_easz.get_easz_nt_seq(self.ptrn_wrds,
                                                         easz_nts)

        self.imm_nt_seq = ild_imm.get_imm_nt_seq(self.ptrn_wrds, imm_nts)

        self.disp_nt_seq = ild_disp.get_disp_nt_seq(self.ptrn_wrds,
                                                    disp_nts.union(brdisp_nts))
        
        self.actions = [actions.gen_return_action(ii.inum)]
Пример #3
0
    def __init__(self, ii, is_3dnow, eosz_nts, easz_nts, imm_nts, disp_nts,
                 brdisp_nts, mode_space, state_space):

        # FIXME 2012-06-19 MJC: is there a better way to do complex
        # init of class attributes?
        if pattern_t.first:
            pattern_t.first = False
            self._setup_phys_map(is_3dnow)

        self.ptrn = ii.ipattern_input
        self.ptrn_wrds = self.ptrn.split()
        self.iclass = ii.iclass
        self.legal = True

        #amd 3dnow instructions have nasty 0f 0f ... opcode pattern
        #in which second 0f is not an opcode! This should be treated
        #in a special way
        self.amd3dnow_build = is_3dnow  #this one is NOT used DELETE IT ???

        self.category = ii.category
        #FIXME: remove all members of ii stored directly as members
        self.ii = ii

        #incomplete_opcode is used for expanding opcodes that have registers
        #embedded in them
        self.incomplete_opcode = False

        #number of missing bits in incomplete opcode. usually 0 or 3
        self.missing_bits = 0

        self.insn_map = None
        self.opcode = None

        self.space = None  # LEGACY|VEX|EVEX
        self.has_modrm = False

        self.imm_nt_seq = None

        self.disp_nt_seq = None

        #modrm.reg bits value, set only when it is explicitly
        #e.g. bounded: REG[010]
        self.ext_opcode = None

        #all legal values for MODE operand in this pattern
        self.mode = None

        #an ordered string of EOSZ setting NTs in the pattern
        #we will use it to create the eosz lookup table for the pattern
        self.eosz_nt_seq = None

        #same for EASZ
        self.easz_nt_seq = None

        #operand deciders of the pattern
        #FIXME: not finished yet
        self.constraints = collections.defaultdict(dict)

        insn_map, opcode = self.get_map_opcode()
        self.insn_map = insn_map
        self.opcode = opcode

        self.has_modrm = ild_modrm.get_hasmodrm(self.ptrn)
        self.set_ext_opcode()

        self.set_mode(ii, mode_space)

        self.eosz_nt_seq = ild_eosz.get_eosz_nt_seq(self.ptrn_wrds, eosz_nts)

        self.easz_nt_seq = ild_easz.get_easz_nt_seq(self.ptrn_wrds, easz_nts)

        self.imm_nt_seq = ild_imm.get_imm_nt_seq(self.ptrn_wrds, imm_nts)

        self.disp_nt_seq = ild_disp.get_disp_nt_seq(self.ptrn_wrds,
                                                    disp_nts.union(brdisp_nts))

        self.set_constraints(ii, state_space)
        self.actions = [actions.gen_return_action(ii.inum)]

        #Not implementing this yet.
        #Will implement after code review for has_modrm
        #self.set_hasimm()
        #self.set_pfx_table()

        #FIXME: for anaisys only
        if self.is_3dnow():
            if not self.has_modrm:
                _msg('3DNOW with no MODRM: %s\n' % self)
Пример #4
0
def _get_united_cdict(ptrn_list, state_space, vexvalid, all_ops_widths):
    """@param ptrn_list: list of ild.pattern_t
    @param state_space: all legal values for xed operands:
                        state_space['REXW'][1] = True,
                        state_space['REXW'][0]=True
    @param vexvalid: VEXVALID value we want to filter by. vevxavlid=='0'
                    will include only patterns with vexvalid=='0' constraint
                    value.
    @param all_ops_widths: dict of operands to their bit widths. 

    @return ild_cdict.constrant_dict_t which unites patterns constraint dicts

    This gets called with all the patterns for a specific map &
    opcode, but for all encoding spaces. So first we filter based on
    encoding space (vexvalid).    """
    global mod3_repl, vd7_repl, rm4_repl, masknot0_repl, mask0_repl
    cnames = []

    # FIXME: 2019-10-30: patterns now know their vexvalid value and
    # encspace, and the maps are split by encspace as well, so we can
    # avoid the following filtering by vexvalid.
    
    #filter by encoding space (vexvalid)
    ptrns = []
    ivv = int(vexvalid)
    for ptrn in ptrn_list:
        #FIXME: 2019-10-30: if vexvalid in list(ptrn.special_constraints['VEXVALID'].keys()):
        if ivv == ptrn.vv:
            ptrns.append(ptrn)

    if len(ptrns) == 0:
        return None

    for ptrn in ptrns:
        cnames.extend(list(ptrn.constraints.keys()))
    cnames = set(cnames)

    if _is_binary_MOD3(ptrns):
        mod3_repl += 1
        _replace_MOD_with_MOD3(cnames, ptrns)

    if _has_VEXDEST210_equals_7_restriction(cnames, ptrns): 
        vd7_repl += 1
        _replace_VEXDEST210_with_VD2107(cnames, ptrns)
                
    if _is_binary_RM_4(cnames, ptrns):
        rm4_repl += 1
        _replace_RM_with_RM4(cnames, ptrns)

    if _is_binary_MASK_NOT0(cnames, ptrns):
        masknot0_repl += 1
        _replace_MASK_with_MASK_NOT0(cnames, ptrns)

    if _has_MASK_ZERO_restriction(cnames, ptrns): 
        mask0_repl += 1
        _replace_MASK_with_MASK_ZERO(cnames, ptrns)

    # For each pattern we have a list of constraints. ptrn.constraints
    # is the legal values for those constraints. In each map opcode
    # bin, we have several patterns with different constraints. We
    # want to make one hash table for these different patterns. Thats
    # why we want to take the union of all the constraints and make
    # one dictionary (and ultimately a hash table). Need to add all
    # legal variations of all constraints, cross product. (dangerous)
    #For example if we have two patterns:
    #PATTERN1: MOD=1
    #PATTERN2: REG=2
    #then for PATTERN1 we will create a constraint dictionary with all
    #combinations (MOD=1 REG=0), (MOD=1, REG=1) ,..., (MOD=1, REG=7)
    #and for PATTERN2 we will have (MOD=0 REG=2), (MOD=1 REG=2), ...
    cdicts = []
    for ptrn in ptrns:
        cdict = constraint_dict_t(cnames, ptrn.constraints, state_space, ptrn)
        cdicts.append(cdict)
    insn_map = ptrns[0].insn_map
    opcode = ptrns[0].opcode
    msg = []
    msg.append("cdict conflict in pattern")
    msg.append('MAP:%s OPCODE:%s\n' % (insn_map, opcode))
    msg = "\n".join(msg)
    # now we unite (cross-product) after exploding/back-filling all the
    # constraints. All patterns now have same constraints.
    united_dict = constraint_dict_t.unite_dicts(cdicts, msg, cnames)
    
    #generate the int value for each tuple
    united_dict.create_tuple2int(all_ops_widths)

    #print "UNITED DICT: VV {} OPCODE {} MAP {}:  tuples {}".format(
    #    vexvalid, opcode, insn_map, len(united_dict.tuple2rule) )
    
    #creating the default action that will be taken when we did not hit 
    #a valid hash entry
    default_action = [actions.gen_return_action('0')]
    united_dict.action_codegen = actions_codegen.actions_codegen_t(
        united_dict.tuple2rule,
        default_action,
        united_dict.strings_dict)
    return united_dict
Пример #5
0
def _get_united_cdict(ptrn_list, state_space, vexvalid, all_ops_widths):
    """
    @param ptrn_list: list of ild.pattern_t
    @param state_space: all legal values for xed operands:
                        state_space['REXW'][1] = True,
                        state_space['REXW'][0]=True
    @param vexvalid: VEXVALID value we want to filter by. vevxavlid==0
                    will include only patterns with vexvalid==0 constraint
                    value.
    @param all_ops_widths: dict of operands to their bit widths. 
    @return ild_cdict.constrant_dict_t which unites patterns constraint dicts
    """
    cnames = []

    #take only requested space patterns
    ptrns = []
    for ptrn in ptrn_list:
        if vexvalid in ptrn.constraints['VEXVALID'].keys():
            ptrns.append(ptrn)

    if len(ptrns) == 0:
        return None

    for ptrn in ptrns:
        cnames.extend(ptrn.constraints.keys())
    cnames = set(cnames)

    cdicts = []
    if _is_binary_MOD3(ptrns):
        _replace_MOD_with_MOD3(cnames, ptrns)

    if _is_binary_VEXDEST210_7(cnames, ptrn_list):
        _replace_VEXDEST210_with_VD2107(cnames, ptrn_list)

    if _is_binary_RM_4(cnames, ptrn_list):
        _replace_RM_with_RM4(cnames, ptrn_list)

    if _is_binary_MASK_NOT0(cnames, ptrn_list):
        _replace_MASK_with_MASK_NOT0(cnames, ptrn_list)

    if _is_binary_MASK_ZERO(cnames, ptrn_list):
        _replace_MASK_with_MASK_ZERO(cnames, ptrn_list)

    # For each pattern we have a list of constraints. ptrn.constraints
    # is the legal values for those constraints. In each map opcode
    # bin, we have several patterns with different constraints. We
    # want to make one hash table for these different patterns. Thats
    # why we want to take the union of all the constraints and make
    # one dictionary (and ultimately a hash table). Need to add all
    # legal variations of all constraints, cross product. (dangerous)
    #For example if we have two patterns:
    #PATTERN1: MOD=1
    #PATTERN2: REG=2
    #then for PATTERN1 we will create a constraint dictionary with all
    #combinations (MOD=1 REG=0), (MOD=1, REG=1) ,..., (MOD=1, REG=7)
    #and for PATTERN2 we will have (MOD=0 REG=2), (MOD=1 REG=2), ...
    for ptrn in ptrns:
        cdict = constraint_dict_t(cnames, ptrn.constraints, state_space, ptrn)
        cdicts.append(cdict)
    insn_map = ptrns[0].insn_map
    opcode = ptrns[0].opcode
    msg = []
    msg.append("cdict conflict in pattern")
    msg.append('MAP:%s OPCODE:%s\n' % (insn_map, opcode))
    msg = "\n".join(msg)
    # now we unite (cross-product) after exploding/back-filling all the
    # constraints. All patterns now have same constraints.
    united_dict = constraint_dict_t.unite_dicts(cdicts, msg, cnames)

    #generate the int value for each tuple
    united_dict.create_tuple2int(all_ops_widths)
    united_dict.strings_dict = ild_codegen._dec_strings

    #creating the default action that will be taken when we did not hit
    #a valid hash entry
    default_action = [actions.gen_return_action('0')]
    united_dict.action_codegen = actions_codegen.actions_codegen_t(
        united_dict.tuple2rule, default_action, united_dict.strings_dict)
    return united_dict
Пример #6
0
def parse_encode_lines(lines, state_bits):
    """
    Returns a tuple of two dictionaries: (1) a dictionary of
    sequencer_t's and (2) a dictionary of nonterminal_t's
    """
    nts = {}  # nonterminals_t's
    ntlufs = {}  # nonterminals_t's
    seqs = {}  # sequencer_t's

    repeat_nts = {
    }  # some nt/ntluf/seq has multi definition, so we use three dict to record this
    repeat_ntlufs = {}
    repeat_seqs = {}
    i = 0
    while len(lines) > 0:
        line = lines.pop(0)

        fn = file_pattern.match(line)
        if fn:
            filename = fn.group('file')

        line = comment_pattern.sub("", line)
        line = leading_whitespace_pattern.sub("", line)
        if line == '':
            continue
        line = slash_expand.expand_all_slashes(line)

        c = curly_pattern.search(line)
        if c:
            line = re.sub("{", " { ", line)
            line = re.sub("}", " } ", line)

        sequence = sequence_pattern.match(line)
        if sequence:
            seq = sequencer_t(sequence.group('seqname'), filename)
            if seq.name in seqs:
                if seqs[seq.
                        name]:  # if is not none, shows that this seq only has been defined one time
                    tmp = seqs[seq.name]
                    repeat_seqs[seq.name] = [tmp, seq]
                    seqs[seq.name] = None
                else:
                    repeat_seqs[seq.name].append(seq)
            else:
                seqs[seq.name] = seq
            #msg("SEQ MATCH %s" % seq.name)
            nt = None
            continue

        p = ntluf_pattern.match(line)
        if p:
            nt_name = p.group('ntname')
            ret_type = p.group('rettype')
            # create a new nonterminal to use
            nt = nonterminal_t(nt_name, filename, ret_type)
            if nt_name in ntlufs:
                if ntlufs[
                        nt_name]:  # if is not none, shows that this seq only has been defined one time
                    tmp = ntlufs[nt_name]
                    repeat_ntlufs[nt_name] = [tmp, nt]
                    ntlufs[nt_name] = None
                else:
                    repeat_ntlufs[nt_name].append(nt)
            else:
                ntlufs[nt_name] = nt
            seq = None
            continue

        m = nt_pattern.match(line)
        if m:
            nt_name = m.group('ntname')
            nt = nonterminal_t(nt_name, filename)
            if nt_name in nts:
                if nts[nt_name]:  # if is not none, shows that this seq only has been defined one time
                    tmp = nts[nt_name]
                    repeat_nts[nt_name] = [tmp, nt]
                    nts[nt_name] = None
                else:
                    repeat_nts[nt_name].append(nt)
            else:
                nts[nt_name] = nt
            seq = None
            continue
        a = arrow_pattern.match(line)
        if a:
            conds = a.group('cond').split()
            actns = a.group('action').split()
            #msg("ARROW" + str(conds) + "=>" + str(actions))
            conditions = conditions_t()
            for c in conds:
                conditions.and_cond(c)
            rule = rule_t(conditions, actns, nt_name)
            if seq:
                seq.add(rule)
            else:
                # we do not need the rules otherwise->error/nothing in the
                # new encoding structure (hash tables).
                # instead we are holding this info in a matching attribute
                if rule.conditions.and_conditions[0].is_otherwise():
                    if rule.actions[0].is_nothing():
                        nt.otherwise = [actions.gen_return_action('1')]
                    elif rule.actions[0].is_error():
                        nt.otherwise = [actions.gen_return_action('0')]
                    else:
                        nt.otherwise = [actions.action_t(x) for x in actns]
                        # in case we have valid action for the otherwise
                        # rule we should finish it with returnning 1
                        # which is "not an error"
                        nt.otherwise.append(actions.gen_return_action('1'))
                else:
                    nt.add(rule)
        else:
            for nt in line.split():
                seq.add(nt)
    return (seqs, nts, ntlufs, repeat_seqs, repeat_nts, repeat_ntlufs)