Example #1
0
    def classify(self):
        if patterns.decimal_pattern.match(self.value):
            self.emit_type = 'numeric'
            self.int_value = int(self.value)
            t = hex(self.int_value)
            self.nbits = 4 * len(t[2:])
            if vclassify():
                msgb("CLASSIFY", "%s as decimal values" % (self.value))
            return

        if patterns.hex_pattern.match(self.value):
            self.emit_type = 'numeric'
            self.int_value = int(self.value, 16)
            self.nbits = 4 * (len(self.value) - 2
                              )  # drop the 0x, convert nibbles to bits
            if vclassify():
                msgb("CLASSIFY", "%s as hex" % (self.value))
            return
        if patterns.letter_and_underscore_pattern.match(self.value):
            self.emit_type = 'letters'
            t = self.value
            t = genutil.no_underscores(t)
            self.nbits = len(t)
            if vclassify():
                msgb("CLASSIFY", "%s as letters" % (self.value))
            return
        b = patterns.binary_pattern.match(self.value)  # leading "0b"
        if b:
            self.emit_type = 'numeric'
            t = '0b' + b.group('bits')  # pattern match strips out 0b
            self.int_value = genutil.make_numeric(t)
            bits_str = genutil.make_binary(t)
            self.nbits = len(bits_str)
            if vclassify():
                msgb(
                    "CLASSIFY",
                    "%s as explicit-binary -> int = %d nbits=%d [%s,%s]" %
                    (self.value, self.int_value, self.nbits, t, bits_str))
            return
        if patterns.bits_and_letters_underscore_pattern.match(self.value):
            self.emit_type = 'letters'
            v = genutil.no_underscores(self.value)
            self.nbits = len(v)
            if vclassify():
                msgb("CLASSIFY", "%s as mixed-letters" % (self.value))
            return

        if patterns.simple_number_pattern.match(self.value):
            self.emit_type = 'numeric'
            self.int_value = genutil.make_numeric(self.value)
            t = hex(self.int_value)
            self.nbits = 4 * len(t[2:])
            if vclassify():
                msgb("CLASSIFY", "%s as simple-number" % (self.value))
            return

        genutil.die("unknown pattern")
Example #2
0
def _parse_map_line(s):
    # shlex allows for quoted substrings containing spaces as
    # individual args.
    t = shlex.split(s.strip())
    if len(t) != 10:
        _die("Bad map description line: [{}]".format(s))
    mi = map_info_t()
    mi.map_name = t[0]
    mi.space = t[1]
    mi.legacy_escape = t[2]
    mi.legacy_opcode = t[3]
    mi.map_id = t[4]
    mi.modrm = t[5]
    mi.imm8 = t[6]
    mi.imm32 = t[7]
    mi.opcpos = t[8]
    mi.search_pattern = t[9]

    if mi.space not in ['legacy', 'vex', 'evex', 'xop']:
        _die("Bad map description encoding space [{}]".format(s))
    if mi.space == 'legacy':
        if genutil.is_hex(mi.legacy_escape):
            pass
        elif mi.legacy_escape != 'N/A':
            _die("Bad map description legacy escape [{}]".format(s))
        if genutil.is_hex(mi.legacy_opcode):
            pass
        elif mi.legacy_opcode != 'N/A':
            _die("Bad map description legacy opcode [{}]".format(s))

        if mi.map_id == 'N/A':
            _die("Bad map description map-id [{}]".format(s))
    else:
        if mi.legacy_escape != 'N/A':
            _die("Bad map description legacy escape [{}]".format(s))
        if mi.legacy_opcode != 'N/A':
            _die("Bad map description legacy opcode [{}]".format(s))
        if genutil.numeric(mi.map_id):
            mi.map_id = genutil.make_numeric(mi.map_id)
        else:
            _die("Bad map description map id [{}]".format(s))

    if mi.modrm not in ['var', 'yes', 'no']:
        _die("Bad map description modrm specifier [{}]".format(s))
    if mi.imm8 not in ['var', 'yes', 'no']:
        _die("Bad map description imm8 specifier [{}]".format(s))
    if mi.imm32 not in ['var', 'yes', 'no']:
        _die("Bad map description imm32 specifier [{}]".format(s))
    if genutil.numeric(mi.opcpos):
        mi.opcpos = genutil.make_numeric(mi.opcpos)
    else:
        _die("Bad map description opcode position specifier [{}]".format(s))

    # we want the longer patterns first when we sort the map_info_t.
    mi.priority = 100 - len(mi.search_pattern)
    return mi
Example #3
0
def _read_constant_tables(lines, tables):
    """Read lines from lines until a new header or a blank line is reached"""
    nlines = 0
    y = None
    for line in lines:
        nlines += 1
        line = line.strip()
        line = re.sub(r'#.*', '', line)
        m = constant_table_t.match_blank.match(line)
        if m:
            continue
        m = constant_table_t.match_header.match(line)
        if m:  # found next header
            name = m.group('name')
            y = None
            for t in tables:
                if t.name == name:
                    y = t
            if not y:
                y = constant_table_t()
                tables.append(y)
                y.name = name
                y.operand = m.group('operand')
            continue
        m = constant_table_t.match_pair.match(line)
        if m:
            value = m.group('value')
            symbol = m.group('symbol')
            numeric_value = genutil.make_numeric(value)
            #print "INPUT: [%s] [%s]" % (value,symbol)
            if not y:
                genutil.die(
                    "Malformed constant table line {}: [{}]\n\n".format(
                        nlines, line))
            y.value_string_pairs.append((numeric_value, symbol))
            continue
        m = constant_table_t.match_pair_error.match(line)
        if m:
            value = m.group('value')
            numeric_value = genutil.make_numeric(value)
            if not y:
                genutil.die(
                    "Malformed constant table line {}: [{}]\n\n".format(
                        nlines, line))
            y.value_string_pairs.append((numeric_value, None))
            continue
        else:
            genutil.die("Could not parse line {}: [{}]\n\n".format(
                nlines, line))
Example #4
0
    def parse_opcode(self, op_str):
        # has side effects of settting self.missing_bits and self.incomplete
        val = None
        if genutil.numeric(op_str):
            val = genutil.make_numeric(op_str)

            # special check for partial binary numbers as opcodes
            if genutil.is_binary(op_str):
                bin_str = re.sub('^0b', '', op_str)
                bin_str = re.sub('_', '', bin_str)
                #if it is bin string, it might be incomplete, and we
                #assume that given bits are msb. Hence we have to
                #shift left

                if len(bin_str) > 8:
                    ildutil.ild_err("Unexpectedly long binary opcode: %s" %
                             bin_str)

                if len(bin_str) < 8:
                    self.missing_bits = 8-len(bin_str)
                    val = val << (self.missing_bits)
                    self.incomplete_opcode = True
                    _msg('incomplete opcode for iclass %s, pttrn %s' %
                        (self.iclass, self.ptrn))

        return val
Example #5
0
 def set_ext_opcode(self):
    #inline captures MOD[mm] REG[rrr] RM[nnn]
    #or REG[111] etc. -- can be constant
    for w in self.ptrn_wrds:
        pb = reg_binding_pattern.match(w)
        if pb:
            bits = pb.group('bits')
            self.ext_opcode = genutil.make_numeric(bits)
            return
Example #6
0
    def read(self, lines):
        """Read lines from lines until a new header or a blank line is reached"""
        started = False
        while 1:
            if not lines:
                break
            self.nlines += 1            
            line = lines[0]
            line = line.strip()
            line = re.sub(r'#.*','',line)
            m= constant_table_t.match_blank.match(line)
            if m:
                del lines[0]
                continue

            m= constant_table_t.match_header.match(line)
            if m:
                if started:
                    return
                else:
                    started = True
                    del lines[0]
                    self.name = m.group('name')
                    self.operand = m.group('operand')
                    continue
            m = constant_table_t.match_pair.match(line)
            if m:
                value = m.group('value')
                symbol = m.group('symbol')
                numeric_value = genutil.make_numeric(value)
                #print "INPUT: [%s] [%s]" % (value,symbol)
                self.value_string_pairs.append((numeric_value,symbol))
                del lines[0]
                continue
            m = constant_table_t.match_pair_error.match(line)
            if m:
                value = m.group('value')
                numeric_value = genutil.make_numeric(value)
                self.value_string_pairs.append((numeric_value,None))
                del lines[0]
                continue
            else:
                genutil.die("Could not parse line %d: [%s]\n\n" % (self.nlines,line))
Example #7
0
    def _build_constraint(self, nonterminal):
        '''
        build a dict that represents the values that the operands can have.
        e.g.
        for the constraint EASZ=3 MODE!=3
        the cdict is {EASZ:[3],MODE:[0,1,2]}
        '''

        for rule in nonterminal.rules:
            constraints = {}
            for cond in rule.conditions.and_conditions:
                key = cond.field_name
                if cond.equals:
                    if cond.rvalue.null():
                        constraints[key] = [self.reg2int[_xed_reg_invalid]]
                    elif cond.rvalue.any_valid():
                        #will be gathered later
                        continue
                    else:
                        if self._cond_is_UIMM0_1(cond):
                            key = self._replace_UIMM0_1_cond()
                        val = cond.rvalue.value
                        if self._is_reg_type(key):
                            constraints[key] = [self.reg2int[val]]
                        else:
                            constraints[key] = [genutil.make_numeric(val)]
                else:
                    #we have != condition, we need to calculate all the
                    #possible values based on the width of the field and remove
                    #the the unwanted value.
                    #need to deep copy since we modify the list, and we want
                    #to preserve the original
                    all_vals = list(copy.deepcopy(self.state_space[key]))
                    val = genutil.make_numeric(cond.rvalue.value)
                    all_vals.remove(val)
                    constraints[key] = all_vals
            rule.cdict = constraints
Example #8
0
 def expand_partial_opcode(self):
     expanded = []
     if self.incomplete_opcode:
         if 'RM[rrr]' in self.ptrn or 'REG[rrr]' in self.ptrn:
             _msg('Expanding opcode for %s' % self.iclass)
             #FIXME: MJC: was assuming hex for self.opcode (2012-06-19)
             opcode = genutil.make_numeric(self.opcode)
             #iterating through all legal variations of the incomplete
             #opcode.
             #Since the variant with all missing bits == 0 was already
             #created (it is the current self), we need to iterate through
             #1 to 2 ^ (self.missing_bits)
             for i in range(1, 2**self.missing_bits):
                 new_ptrn = copy.deepcopy(self)
                 new_ptrn.opcode = hex(opcode | i)
                 expanded.append(new_ptrn)
     return expanded
Example #9
0
    def _find_opcodes(self):
        '''augment the records with information found by parsing the pattern'''

        map_pattern = re.compile(r'MAP=(?P<map>[0-6])')
        vex_prefix = re.compile(r'VEX_PREFIX=(?P<prefix>[0-9])')
        rep_prefix = re.compile(r'REP=(?P<prefix>[0-3])')
        osz_prefix = re.compile(r' OSZ=(?P<prefix>[01])')
        no_prefix = re.compile(r'REP=0 OSZ=0')
        rexw_prefix = re.compile(r'REXW=(?P<rexw>[01])')
        reg_required = re.compile(r'REG[\[](?P<reg>[b01]+)]')
        mod_required = re.compile(r'MOD[\[](?P<mod>[b01]+)]')
        mod_mem_required = re.compile(r'MOD!=3')
        mod_reg_required = re.compile(r'MOD=3')
        rm_val_required = re.compile(r'RM=(?P<rm>[0-9]+)')
        rm_required = re.compile(
            r'RM[\[](?P<rm>[b01]+)]')  # RM[...] or SRM[...]
        mode_pattern = re.compile(r' MODE=(?P<mode>[012]+)')
        not64_pattern = re.compile(r' MODE!=2')

        for v in self.recs:

            if not hasattr(v, 'isa_set'):
                v.isa_set = v.extension

            v.undocumented = False
            if hasattr(v, 'comment'):
                if 'UNDOC' in v.comment:
                    v.undocumented = True

            pattern = v.pattern.split()
            p0 = pattern[0]
            v.map = 0
            v.space = 'legacy'
            if p0 == 'VEXVALID=1':
                v.space = 'vex'
                opcode = pattern[1]
            elif p0 == 'VEXVALID=2':
                v.space = 'evex'
                opcode = pattern[1]
            elif p0 == 'VEXVALID=4':  #KNC
                v.space = 'evex.u0'
                opcode = pattern[1]
            elif p0 == 'VEXVALID=3':
                v.space = 'xop'
                opcode = pattern[1]
            else:  # legacy maps and AMD 3dNow (if enabled)
                v.map, opcode = self._find_legacy_map_opcode(pattern)

            v.opcode = opcode
            v.partial_opcode = False

            v.amd_3dnow_opcode = None
            # conditional test avoids prefetches and FEMMS.
            if v.extension == '3DNOW' and v.category == '3DNOW':
                v.amd_3dnow_opcode = pattern[-1]

            mp = map_pattern.search(v.pattern)
            if mp:
                v.map = int(mp.group('map'))

            v.no_prefixes_allowed = False
            if no_prefix.search(v.pattern):
                v.no_prefixes_allowed = True

            v.osz_required = False
            osz = osz_prefix.search(v.pattern)
            if osz:
                if osz.group('prefix') == '1':
                    v.osz_required = True

            v.f2_required = False
            v.f3_required = False
            rep = rep_prefix.search(v.pattern)
            if rep:
                if rep.group('prefix') == '2':
                    v.f2_required = True
                elif rep.group('prefix') == '3':
                    v.f3_required = True

            if v.space in ['evex', 'vex', 'xop']:
                vexp = vex_prefix.search(v.pattern)
                if vexp:
                    if vexp.group('prefix') == '0':
                        v.no_prefixes_allowed = True
                    elif vexp.group('prefix') == '1':
                        v.osz_required = True
                    elif vexp.group('prefix') == '2':
                        v.f2_required = True
                    elif vexp.group('prefix') == '3':
                        v.f3_required = True

            v.rexw_prefix = "unspecified"
            rexw = rexw_prefix.search(v.pattern)
            if rexw:
                v.rexw_prefix = rexw.group('rexw')  # 0 or 1

            v.reg_required = 'unspecified'
            reg = reg_required.search(v.pattern)
            if reg:
                v.reg_required = genutil.make_numeric(reg.group('reg'))

            v.rm_required = 'unspecified'
            rm = rm_required.search(v.pattern)  # bit capture
            if rm:
                v.rm_required = genutil.make_numeric(rm.group('rm'))
            rm = rm_val_required.search(v.pattern)  # equality
            if rm:
                v.rm_required = genutil.make_numeric(rm.group('rm'))

            v.mod_required = 'unspecified'
            mod = mod_required.search(v.pattern)
            if mod:
                v.mod_required = genutil.make_numeric(mod.group('mod'))
            mod = mod_mem_required.search(v.pattern)
            if mod:
                v.mod_required = '00/01/10'
            mod = mod_reg_required.search(v.pattern)
            if mod:
                v.mod_required = 3

            v.has_modrm = False
            if 'MODRM' in v.pattern:  # accounts for normal MODRM and various VSIB types
                v.has_modrm = True
            elif (v.reg_required != 'unspecified'
                  or v.mod_required != 'unspecified'):
                v.has_modrm = True
            elif v.rm_required != 'unspecified':
                # avoid the partial opcode bytes which do not have MODRM
                if 'SRM[' not in v.pattern:
                    v.has_modrm = True

            # 16/32/64b mode restrictions
            v.mode_restriction = 'unspecified'
            if not64_pattern.search(v.pattern):
                v.mode_restriction = 'not64'
            else:
                mode = mode_pattern.search(v.pattern)
                if mode:
                    v.mode_restriction = int(mode.group('mode'))

            easz = 'aszall'
            if 'EASZ=1' in v.pattern:
                easz = 'a16'
            elif 'EASZ=2' in v.pattern:
                easz = 'a32'
            elif 'EASZ=3' in v.pattern:
                easz = 'a64'
            elif 'EASZ!=1' in v.pattern:
                easz = 'asznot16'
            v.easz = easz

            v.default_64b = False
            if 'DF64()' in v.pattern or 'CR_WIDTH()' in v.pattern:
                v.default_64b = True

            _set_eosz(v)

            v.scalar = False
            if hasattr(v, 'attributes'):
                v.attributes = v.attributes.upper()
                if 'SCALAR' in v.attributes:
                    v.scalar = True
            else:
                v.attributes = ''

            if opcode.startswith('0x'):
                v.opcode_base10 = int(opcode, 16)
            elif opcode.startswith('0b'):
                # partial opcode.. 5 bits, shifted
                v.opcode_base10 = genutil.make_numeric(opcode) << 3
                v.partial_opcode = True

            v.upper_nibble = int(v.opcode_base10 / 16)
            v.lower_nibble = v.opcode_base10 & 0xF
Example #10
0
def parse_one_operand(w, 
                      default_vis='DEFAULT', 
                      xtypes=None, 
                      default_xtypes=None,
                      internal=False):
   """Format examples:
   name=xxxxxy:{r,w,crw,rw,rcw}[:{EXPL,IMPL,SUPP,ECOND}][:{some oc2 code}][:{some xtype code}]
   name=NTLUR():{r,w,crw,rw,rcw}[:{EXPL,IMPL,SUPP,ECOND}][:{some oc2 code}][:{some xtype code}]
          oc2 can be before EXPL/IMPL/SUPP. oc2 is the width code.
          MEM{0,1}, PTR, RELBR, AGEN, IMM{0,1,2,3}

          xtype describes the number of data type and width of each element.
          If the xtype is omitted, xed will attempt to infer it from the oc2 code.

          ECOND is for encoder-only conditions. Completely ignored by the decoder.
          
   Default is read-only

   @param w: string
   @param w: an operand specification string
   
   @rtype operand_info_t
   @return a parsed operand
   """
   
   if vopnd():
      genutil.msge("PARSE-OPND: " + w)

   # get the r/w/rw info, if any
   vis = default_vis
   oc2 = None
   otype = None
   rw = 'r'
   cvt = []
   invert = False
   lookupfn_name=None
   xtype = None
   multireg = 0
   if colon_pattern.search(w):
      chunks = w.split(':')
      if vopnd():
         genutil.msge("CHUNKS [%s]" % (",".join(chunks)))
      for i,c in enumerate(chunks):
         if vopnd():
            genutil.msge("\tCHUNK %d %s" %( i,c))
         if i == 0:
            a = c
         elif i == 1:
            rw = c
            if vopnd():
               genutil.msge("\t\tSET rw to  %s" % (rw))
         elif (i == 2 or i == 3) and (c in ['IMPL', 'SUPP',  'EXPL', 'ECOND']):
            vis = c
            if vopnd():
               genutil.msge("\t\tSET VIS to %s" % (vis))
         else: # FIXME: somewhat sloppy error checking on input
                      
            multi_reg_p=multireg_pattern.match(c)
            cp=convert_pattern.match(c)
            
            if multi_reg_p:
                multireg = int(multi_reg_p.group('nreg')) 
            elif cp:
                cvt.append(cp.group('rhs'))
            elif oc2 == None and oc2_pattern.match(c):
               oc2 = c
               if vopnd():
                  genutil.msge("\t\tSET OC2 to  %s" % (oc2))
            elif oc2 and c in xtypes:
               xtype = c
               if vopnd():
                  genutil.msge("\t\tSET xtype to  %s" % (xtype))
            elif decimal_number_pattern.match(c):
               genutil.die("Bad number in %s" % (w))
            else:
               genutil.die(
                   "Bad oc2 pattern in %s when looking at %d chunk: %s " %
                   (w,i,c) )

   else:
      a = w
      
   if vis == 'ECOND':
      return None
   
      
   # From now on, use a, not w.

   if slash_pattern.search(a):
      genutil.die("Bad slash in operand")

   if xtype == None:
      # need to use the default xtype based on the oc2 width code
      if oc2:
         try:
            xtype = default_xtypes[oc2.upper()]
         except:
            s = ''
            for i,v in default_xtypes.items():
               s += "\t%10s -> %10s\n" % (i,v)
            genutil.die("Parsing operand [%s]. Could not find default type for %s. xtypes=%s\nTypes=%s" % (w, oc2, str(xtypes), s))
      else:
         # there was no oc2 type and no xtype. probably a nonterminal
         # lookup function
         xtype = 'INVALID'

   # look for X=y and X!=y and bare operands like MEM0.

   eqp = equals_pattern.search(a)
   neqp = not_equals_pattern.search(a)
   if eqp:
      (name,rhs)  = eqp.group('lhs','rhs')
      if vopnd():
         genutil.msge("PARSE-OPND:\t" + name + " + " + rhs)
      
      if double_parens_pattern.search(rhs): # NTLUF
         if vopnd():
            genutil.msge("PARSE-OPND:\t nonterminal lookup function "
                 + name + " <- " + rhs)
         # remove the parens
         nt_lookup_fn = double_parens_pattern.sub('',rhs)         
         optype ='nt_lookup_fn'
         rhs = None
         lookupfn_name=nt_lookup_fn
     
      elif reg_pattern.match(rhs):
         optype = 'reg'
      elif error_pattern.match(rhs):
         optype = 'error'
      elif enum_pattern.match(rhs): 
         # for storing XED_* enum values as RHS's of operand bindings
         optype = 'imm_const'
      elif (not genutil.numeric(rhs)) and az_cap_pattern.search(rhs): 
         genutil.die("THIS SHOULD NOT HAPPEN: %s" % (rhs))
      elif letters_underscore_pattern.match(rhs):   
         rhs = list(rhs.replace('_',''))
         optype = 'imm'
      else:
         rhs = hex(genutil.make_numeric(rhs))
         optype = 'imm_const'
   elif neqp:
      (name,rhs)  = neqp.group('lhs','rhs')
      if vopnd():
         genutil.msge("PARSE-OPND: (NOT EQUALS)\t" + name + " + " + rhs)
      invert = True
      if reg_pattern.match(rhs):
         optype = 'reg'
      elif az_cap_pattern.search(rhs): 
          genutil.die("THIS SHOULD NOT HAPPEN")
      elif letters_underscore_pattern.match(rhs): 
          genutil.die("Cannot have a != pattern with don't-care letters")
      else:
          rhs = hex(genutil.make_numeric(rhs))
          optype = 'imm_const'
   elif mem_pattern.search(a):        # memop
      name = a
      optype ='imm_const'
      rhs = '1'
   elif imm_token_pattern.search(a):        # immediate placeholder
      name = a
      optype ='imm_const'
      rhs = '1'
   elif agen_pattern.search(a):        # agen
      name = a
      optype ='imm_const'
      rhs = '1'
   elif relative_branch_pattern.search(a):
      name = a
      optype ='imm_const'
      rhs = '1'
   elif pointer_pattern.search(a): 
      name = a
      optype ='imm_const'
      rhs = '1'
   elif xed_reset_pattern.search(a):
      # special marker that tells the traverser to restart this
      # nonterminal from the current position
      name = a
      optype ='xed_reset'
      rhs = ''
      vis = 'SUPP'
   elif double_parens_pattern.search(a):
      if vopnd():
         genutil.msge("PARSE-OPND:\t unbound nonterminal lookup function " +
                      a)
      # 2007-07-23 this code is not used
      genutil.die("UNBOUND NTLUF!: %s" % (a)) 
               
   else:
      # macros -- these get rewritten later
      if vopnd():
         genutil.msge("PARSE-OPND:\t flag-ish: " + a)
      name = a
      optype = 'flag'
      rhs = ''

   
   xop =  operand_info_t(name, optype, rhs, rw=rw, invert=invert,
                         vis=vis, oc2=oc2, cvt=cvt, xtype=xtype,
                         lookupfn_name=lookupfn_name, internal=internal,
                         multireg=multireg)

   return xop
Example #11
0
    def __init__(self, arg_action):
        # field bindings (FB) are OD=value
        self.type = None #  'FB', 'emit', 'nt', 'error', 'nothing', 'return'
        self.field_name = None
        self.value = None
        self.nt = None
        self.ntluf = None
        self.int_value = None
        self.emit_type = None # 'numeric', 'letters', 'reg'
        self.nbits = 0
        if vaction():
            msgb("ARGACTION", arg_action)
        if arg_action in ['nothing', "NOTHING"]:
            self.type = 'nothing'
            return
        
        b = patterns.return_pattern.search(arg_action)
        if b:
            self.type = 'return'
            self.value = b.group('retval')
            return 
        
        # in the inputs, "error" gets expanded to "ERROR=1" via the statebits.
        if arg_action == 'error' or arg_action == "ERROR" or arg_action == 'ERROR=1':
            self.type = 'error'
            return

        b = patterns.bit_expand_pattern.search(arg_action)
        if b:
            expanded = b.group('bitname') * int(b.group('count'))
            action = patterns.bit_expand_pattern.sub(expanded,arg_action)
        else:
            action = arg_action
            
        #msgerr("CHECKING: %s" % action)

        a = patterns.equals_pattern.search(action)
        if a:
            # field binding
            #msgerr("FIELD BINDING: %s" % action)
            self.field_name = a.group('lhs')
            rhs = a.group('rhs')
            if patterns.decimal_pattern.match(rhs) or \
               patterns.binary_pattern.match(rhs) or \
               patterns.hex_pattern.match(rhs):
                self.int_value = genutil.make_numeric(rhs)
                self.value = str(self.int_value)
                #msgb("SET RHS", "%s -> %s" % (rhs,self.value))
            else:
                self.value = rhs
                
            self.type = 'FB'
            return
        
        nt = patterns.nt_name_pattern.match(action)
        if nt:
            # NTLUF or NT. Only shows up on decode-oriented rules
            self.nt = nt.group('ntname')
            self.type = 'nt'
            return
        ntluf = patterns.ntluf_name_pattern.match(action)
        if ntluf:
            # NTLUF or NT. Only shows up on decode-oriented rules
            self.ntluf = ntluf.group('ntname')
            self.type = 'ntluf'
            return
        
        cp = patterns.lhs_capture_pattern_end.match(action) 
        if cp:
            self.type = 'emit'
            self.value = cp.group('bits')
            self.field_name = cp.group('name').lower()
            #msgerr("EMIT ACTION %s" % action)
            self.classify()
            return 
        
        # simple byte encoding
        self.type = 'emit'
        self.field_name = None
        #msgerr("EMIT ACTION %s" % action)
        self.value = action
        self.classify()
Example #12
0
    def _find_opcodes(self):
        '''augment the records with information found by parsing the pattern'''

        map_pattern = re.compile(r'MAP=(?P<map>[0-6])')
        vex_prefix = re.compile(r'VEX_PREFIX=(?P<prefix>[0-9])')
        rep_prefix = re.compile(r'REP=(?P<prefix>[0-3])')
        osz_prefix = re.compile(r'OSZ=(?P<prefix>[01])')
        no_prefix = re.compile(r'REP=0 OSZ=0')
        rexw_prefix = re.compile(r'REXW=(?P<rexw>[01])')
        reg_required = re.compile(r'REG[[](?P<reg>[b01]+)]')
        mod_required = re.compile(r'MOD[[](?P<mod>[b01]+)]')
        mod_mem_required = re.compile(r'MOD!=3')
        rm_required = re.compile(r'RM[[](?P<rm>[b01]+)]')
        mode_pattern = re.compile(r' MODE=(?P<mode>[012]+)')
        not64_pattern = re.compile(r' MODE!=2')

        for v in self.recs:

            if not hasattr(v, 'isa_set'):
                v.isa_set = v.extension

            v.undocumented = False
            if hasattr(v, 'comment'):
                if 'UNDOC' in v.comment:
                    v.undocumented = True

            pattern = v.pattern.split()
            p0 = pattern[0]
            v.map = 0
            v.space = 'legacy'
            if p0 in ['0x0F']:
                if pattern[1] == '0x38':
                    v.map = 2
                    opcode = pattern[2]
                elif pattern[1] == '0x3A':
                    v.map = 3
                    opcode = pattern[2]
                else:
                    v.map = 1
                    opcode = pattern[1]
            elif p0 == 'VEXVALID=1':
                v.space = 'vex'
                opcode = pattern[1]
            elif p0 == 'VEXVALID=2':
                v.space = 'evex'
                opcode = pattern[1]
            elif p0 == 'VEXVALID=4':  #KNC
                v.space = 'evex.u0'
                opcode = pattern[1]
            elif p0 == 'VEXVALID=3':
                v.space = 'xop'
                opcode = pattern[1]
            else:
                opcode = p0
            v.opcode = opcode
            v.partial_opcode = False

            mp = map_pattern.search(v.pattern)
            if mp:
                v.map = int(mp.group('map'))

            v.no_prefixes_allowed = False
            if no_prefix.search(v.pattern):
                v.no_prefixes_allowed = True

            v.osz_required = False
            osz = osz_prefix.search(v.pattern)
            if osz:
                if osz.group('prefix') == '1':
                    v.osz_required = True

            v.f2_required = False
            v.f3_required = False
            rep = rep_prefix.search(v.pattern)
            if rep:
                if rep.group('prefix') == '2':
                    v.f2_required = True
                elif rep.group('prefix') == '3':
                    v.f3_required = True

            if v.space in ['evex', 'vex', 'xop']:
                vexp = vex_prefix.search(v.pattern)
                if vexp:
                    if vexp.group('prefix') == '0':
                        v.no_prefixes_allowed = True
                    elif vexp.group('prefix') == '1':
                        v.osz_required = True
                    elif vexp.group('prefix') == '2':
                        v.f2_required = True
                    elif vexp.group('prefix') == '3':
                        v.f3_required = True

            v.rexw_prefix = "unspecified"
            rexw = rexw_prefix.search(v.pattern)
            if rexw:
                v.rexw_prefix = rexw.group('rexw')  # 0 or 1

            v.reg_required = 'unspecified'
            reg = reg_required.search(v.pattern)
            if reg:
                v.reg_required = genutil.make_numeric(reg.group('reg'))

            v.rm_required = 'unspecified'
            rm = rm_required.search(v.pattern)
            if rm:
                v.rm_required = genutil.make_numeric(rm.group('rm'))

            v.mod_required = 'unspecified'
            mod = mod_required.search(v.pattern)
            if mod:
                v.mod_required = genutil.make_numeric(mod.group('mod'))
            mod = mod_mem_required.search(v.pattern)
            if mod:
                v.mod_required = '00/01/10'

            # 16/32/64b mode restrictions
            v.mode_restriction = 'unspecified'
            if not64_pattern.search(v.pattern):
                v.mode_restriction = 'not64'
            else:
                mode = mode_pattern.search(v.pattern)
                if mode:
                    v.mode_restriction = int(mode.group('mode'))

            v.scalar = False
            if hasattr(v, 'attributes'):
                v.attributes = v.attributes.upper()
                if 'SCALAR' in v.attributes:
                    v.scalar = True

            if opcode.startswith('0x'):
                nopcode = int(opcode, 16)
            elif opcode.startswith('0b'):
                # partial opcode.. 5 bits, shifted
                nopcode = genutil.make_numeric(opcode) << 3
                v.partial_opcode = True

            v.upper_nibble = int(nopcode / 16)
            v.lower_nibble = nopcode & 0xF
Example #13
0
def _parse_map_line(s):
    global _map_info_fields
    # shlex allows for quoted substrings containing spaces as
    # individual args.
    t = shlex.split(s.strip())
    if len(t) != len(_map_info_fields):
        _die("Bad map description line: [{}]".format(s))
    mi = map_info_t()
    for i, fld in enumerate(_map_info_fields):
        setattr(mi, fld, t[i])
    # this gets used in function names so must only be legal characters
    mi.map_name = re.sub('-', '_', mi.map_name)
    if mi.space == 'legacy':
        if mi.legacy_escape != 'N/A':
            mi.legacy_escape_int = int(mi.legacy_escape, 16)
            if mi.legacy_opcode != 'N/A':
                mi.legacy_opcode_int = int(mi.legacy_opcode, 16)
            else:
                mi.legacy_opcode_int = None

    mi.map_id_fixup = False

    if mi.space not in ['legacy', 'vex', 'evex', 'xop', 'knc']:
        _die("Bad map description encoding space [{}]".format(s))
    if mi.space == 'legacy':
        if genutil.is_hex(mi.legacy_escape):
            pass
        elif mi.legacy_escape != 'N/A':
            _die("Bad map description legacy escape [{}]".format(s))
        if genutil.is_hex(mi.legacy_opcode):
            pass
        elif mi.legacy_opcode != 'N/A':
            _die("Bad map description legacy opcode [{}]".format(s))

        if mi.map_id == 'N/A':
            _die("Bad map description map-id [{}]".format(s))
        elif genutil.numeric(mi.map_id):
            mi.map_id = genutil.make_numeric(mi.map_id)
        else:
            mi.map_id_fixup = True

    else:
        if mi.legacy_escape != 'N/A':
            _die("Bad map description legacy escape [{}]".format(s))
        if mi.legacy_opcode != 'N/A':
            _die("Bad map description legacy opcode [{}]".format(s))
        if genutil.numeric(mi.map_id):
            mi.map_id = genutil.make_numeric(mi.map_id)
        else:
            _die("Bad map description map id [{}]".format(s))

    if mi.disp not in ['var', 'no']:
        _die("Bad map description disp specifier [{}]".format(s))
    if mi.modrm not in ['var', 'yes', 'no']:
        _die("Bad map description modrm specifier [{}]".format(s))
    if mi.imm not in ['var', '0', '1', '2', '4']:
        _die("Bad map description imm specifier [{}]".format(s))
    if genutil.numeric(mi.opcpos):
        mi.opcpos = genutil.make_numeric(mi.opcpos)
    else:
        _die("Bad map description opcode position specifier [{}]".format(s))

    # we want the longer patterns first when we sort the map_info_t.
    mi.priority = 100 - len(mi.search_pattern)
    return mi