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
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
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
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