diff options
| author | Alexey Kardashevskiy <aik@linux.ibm.com> | 2021-11-10 16:17:24 +1100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2022-01-20 15:08:31 +0100 |
| commit | 40ca9e722c7319bd41abc0f7d36cd5aedb38cf41 (patch) | |
| tree | ef5ab0c310dcb7ca235eff9c76bf411c2bf9f9e2 /pkg/ifuzz/powerpc/gen | |
| parent | 5da9499f431225d763a8dbb3410ca4856cb865b9 (diff) | |
pkg/ifuzz/powerpc: update few broken instructions
The source PowerISA latex files have updated so refresh the instruction
list. The fixed are not used by syzkaller in macros so there should be
no huge change in behaviour, if any.
While at this, simplify+comment the conversion script and fix handling of
privileged instructions, apparently a debug version of the convertion
script made it to the git repo.
Signed-off-by: Alexey Kardashevskiy <aik@linux.ibm.com>
Diffstat (limited to 'pkg/ifuzz/powerpc/gen')
| -rwxr-xr-x | pkg/ifuzz/powerpc/gen/powerisa31_tex_to_syz | 267 |
1 files changed, 128 insertions, 139 deletions
diff --git a/pkg/ifuzz/powerpc/gen/powerisa31_tex_to_syz b/pkg/ifuzz/powerpc/gen/powerisa31_tex_to_syz index f2c1c8b71..585d9b7ea 100755 --- a/pkg/ifuzz/powerpc/gen/powerisa31_tex_to_syz +++ b/pkg/ifuzz/powerpc/gen/powerisa31_tex_to_syz @@ -21,81 +21,97 @@ def read_file(fname): f.close() return ret +# Returns map<str, str>: 'layoutxxivbform': ([6, 5, 5, 5, 5, 2, 1, 1, 1, 1], +# [None, 'T', A', 'B', 'C', None, 'CX', 'AX', 'BX'm 'TX']) def get_layouts(layout_file): layout_content = read_file(layout_file) - cur_layout = "" last_comment = "" layouts = {} - for i in range(len(layout_content)): - cur = layout_content[i] + for cur in layout_content: if len(cur) > 0 and cur[0] == '%': last_comment = re.sub(r'(^%|bits.*$)', "", cur).strip() continue - # \newcommand{\layoutiform}[4]{ l = re.match(r'\\newcommand{\\(layout\w+)}.*{', cur) if l: - cur_layout = l.group(1) - layouts[cur_layout] = last_comment - continue + a = last_comment.split(" ") + pos = [] + names = [] + for a1 in a: + tmp = re.match(r'(\d+)<(\S+)>', a1) + if tmp: + pos += [int(tmp.group(1), 10)] + names += [tmp.group(2)] + continue + pos += [int(a1, 10)] + names += [None] + layouts[l.group(1)] = (pos, names) +# pe.pprint(layouts) return layouts -def add_insns(st, l): - if len(l) != 1 and len(l) != 2: - pe.pprint("!!!Error: broken layout {} for {}".format(l, st)) - sys.exit(-1) - r = {} -# These lines enable/disable prefixed instrustions -# if len(l) != 1: -# return r - for ins in st: - tmp = ins[0].split(" ", 1) - r[tmp[0]] = ins[1] - r[tmp[0]]["layout"] = l - if len(tmp) > 1: - r[tmp[0]]["par"] = tmp[1] - return r - -def sanitize_layout(a, b): - a = a.strip().split(" ") - b = re.findall(r'{([^}]*)}', b) - aa = [] +# Expands names of fields +# (list<n>, list<n>), string -> list<n> +def complete_layout(layout, insn_layout): bb = [] b_ = 0 - for a1 in a: - tmp = re.match(r'(\d+)<(\S+)>', a1) - if tmp: - aa += [int(tmp.group(1), 10)] - bb += [tmp.group(2)] + b = re.findall(r'{([^}]*)}', insn_layout) + for i in range(len(layout[0])): + if layout[1][i]: + bb += [layout[1][i]] continue - aa += [int(a1, 10)] - bb += [re.sub(r'[{}]+', "", b[b_])] + + # "pnop" is special: {any value\textsuperscript{*} + tmpname = re.sub(r'([{}?]+|any value\\textsuperscript{\*)', "", b[b_]) + tmpname = re.sub(r'/+', '/', tmpname) + bb += [tmpname] b_ += 1 - if b_ != len(b) or len(aa) != len(bb): - pe.pprint("!!!error: broken layout {} --- {} --- {}".format(aa, bb, b_)) - sys.exit(-1) - return aa, bb + return bb +# Finds instructions in a latex file +# Returns map<str, list>: +# 'addc.': [([6, 5, 5, 5, 1, 9, 1], ['31', 'RT', 'RA', 'RB', 'OE', '10', 'Rc'], [-1, -1, -1, -1, 0, -1, 1])], +# layouts: array of tuples def find_insns(tex_file, layouts): + + def add_insns(insn_list, layout): + if len(layout) != 1 and len(layout) != 2: + pe.pprint("!!!Error: broken layout {} for {}".format(layout, insn_list)) + sys.exit(-1) + r = {} + for ins in insn_list: + tmp = ins.split(" ", 1) + + ll = [] + for l in layout: + par = [] + for j in range(len(l[1])): + defval = -1 + # This is dealing with OE/Rc from "addc. RT,RA,RB (OE=0 Rc=1)" + if len(tmp) > 1 and ('?' not in l[1][j]): + ptmp = re.match(r'.*{}=(\d).*'.format(l[1][j]), tmp[1]) + if ptmp: + defval = int(ptmp.group(1), 10) + par += [defval] + ll += [(l[0], l[1], par)] + pe.pprint("{}".format(tmp[0])) + r[tmp[0]] = ll + return r + tex_content = read_file(tex_file) - cur_insn_name = "" - cur_insn = {} ret = {} layout = [] - insns_stack = [] - for i in range(len(tex_content)): - cur = tex_content[i] + insn_list = [] + for cur in tex_content: # \instrsyntax{pmxvf16ger2np AT,XA,XB,XMSK,YMSK,PMSK} l = re.match(r'\\instrsyntax{(.*)}', cur) if l: - if insns_stack != [] and layout != []: - ret.update(add_insns(insns_stack, layout)) - insns_stack = [] + if insn_list != [] and layout != []: + ret.update(add_insns(insn_list, layout)) + insn_list = [] layout = [] - cur_insn_name = l.group(1) - insns_stack += [(cur_insn_name, {"loc": "{}:{}".format(tex_file.rsplit("/", 1)[-1], i)})] + insn_list += [l.group(1)] continue - if not insns_stack: + if not insn_list: continue # \layoutxxiiidform{59}{AT}{//}{A}{B}{82}{AX}{BX}{/} @@ -104,134 +120,110 @@ def find_insns(tex_file, layouts): if len(layout) > 2: pe.pprint("! Wrong layout") sys.exit(-1) - layout += [sanitize_layout(layouts[l.group(1)], l.group(2))] + layout += [(layouts[l.group(1)][0], + complete_layout(layouts[l.group(1)], l.group(2)))] if layout: - ret.update(add_insns(insns_stack, layout)) + ret.update(add_insns(insn_list, layout)) return ret +# Extracts priv. flag from Table H.1: Power ISA Instruction Set Sorted by Mnemonic +# Returns priv insns list def collect_priv(tex_file, insns): tex_cont = read_file(tex_file) - for i in range(len(tex_cont)): - cur = tex_cont[i] - ins = cur.split('}', 1)[0] - if ins not in insns: + ret = [] + cur = "" + for tcur in tex_cont: + if tcur != '\hline': + cur += tcur continue - l = re.match(r'^{}}}.+\\small (P|H|HV|HV\/P|UV|64)}}&.*'.format(ins), cur) - if not l: - continue - insns[ins]["Priv"] = True - -def ppcmask(val, start, len): - return (val & ((1 << len) - 1)) << (31 - (start + len - 1)) + # Merge all lines between \hline and split by tab (which '&' in latex) + cur = re.sub(r'\\&', 'AND', cur) # but '&' may occur in the instruction name + tmp = cur.split('&') + if len(tmp) == 11: + ins = re.sub(r'.*{([^{}]+)}$', r'\1', tmp[5]) + if ins in insns: + if re.match(r'.+{(P|H|HV|HV\/P|UV|64)}$', tmp[7]): + ret += [ins] + cur = "" + return ret -fixed_cases = {} -def add_fixed(field, ins): - global fixed_cases - if field not in fixed_cases: - fixed_cases[field] = [] - fixed_cases[field] += [ins] -def print_fixed(): - pe.pprint(fixed_cases) +def generate_go(insns, priv): + def ppcmask(val, start, len): + return (val & ((1 << len) - 1)) << (31 - (start + len - 1)) -def generate_go(insns): def generate_opcode(ins, layout): + pos_, names_, defval_ = layout[0], layout[1], layout[2] opcode = 0 opmask = 0 - fields = "" pos = 0 bits = 0 fields = {} - for i in range(len(layout[0])): + for i in range(len(pos_)): pos += bits - bits = layout[0][i] + bits = pos_[i] - # "pnop" is special - if layout[1][i].replace('any value\\textsuperscript*', '') == '': + # Fields marked `/` must be 0 + if names_[i] == '/': + opmask |= ppcmask(0xffffffff, pos, pos_[i]) continue - if layout[1][i].replace('/', '') == '': - opmask |= ppcmask(0xffffffff, pos, layout[0][i]) - continue - - if layout[1][i].replace('?', '') == '': - opmask |= ppcmask(0xffffffff, pos, layout[0][i]) + if names_[i] == '': continue try: - num = int(layout[1][i], 10) - opcode |= ppcmask(num, pos, layout[0][i]) - opmask |= ppcmask(0xffffffff, pos, layout[0][i]) + num = int(names_[i], 10) + opcode |= ppcmask(num, pos, pos_[i]) + opmask |= ppcmask(0xffffffff, pos, pos_[i]) continue except: pass - if 'par' in ival: - tmp = re.match(r'.*{}=(\d).*'.format(layout[1][i]), ival['par']) - if tmp: - opcode |= ppcmask(int(tmp.group(1), 10), pos, layout[0][i]) - opmask |= ppcmask(0xffffffff, pos, layout[0][i]) - continue + if defval_[i] >= 0: + opcode |= ppcmask(defval_[i], pos, pos_[i]) + opmask |= ppcmask(0xffffffff, pos, pos_[i]) + continue - if layout[1][i] not in fields: - fields[layout[1][i]] = [] - fields[layout[1][i]] += [(pos, layout[0][i])] + fval = [(pos, pos_[i])] + if (ins in ['rldcl', 'rldcl.', 'rldic', 'rldic.', 'rldicl', 'rldicl.', + 'rldimi', 'rldimi.', 'rldcr', 'rldcr.', 'rldicr', 'rldicr.'] and + names_[i] in ["me", "mb"] and fval == [(21, 6)]): + fval = [(21, 5), (26, 1)] + elif ins in ['mfspr', 'mtspr'] and names_[i] == "spr" and fval == [(11, 10)]: + fval = [(16, 5), (11, 5)] + + if names_[i] not in fields: + fields[names_[i]] = [] + fields[names_[i]] += fval - # Fix up fields - for f in fields: - if (ins in ['mtvsrbmi', 'addpcis', 'xvtstdcdp', 'xvtstdcsp', 'mftb'] and - f in [ - "b0", "b1", "b2", # mtvsrbmi - "dx", "dc", "dm", # xvtstdcdp - "d0", "d1", "d2", # addpcis - "tbr", # mftb - ]): - add_fixed(f, ins) - continue - if (ins in ['extswsli', 'extswsli.', 'rldic', 'rldic.', 'rldicl', 'rldicl.', 'rldicr', 'rldicr.', 'rldimi', 'rldimi.', 'sradi', 'sradi.'] and - f in ["sh"] and fields[f] == [(16, 5), (30, 1)]): - add_fixed(f, ins) - continue - if (ins in ['rldcl', 'rldcl.', 'rldic', 'rldic.', 'rldicl', 'rldicl.', 'rldimi', 'rldimi.', 'rldcr', 'rldcr.', 'rldicr', 'rldicr.'] and - f in ["me", "mb"] and fields[f] == [(21, 6)]): # rldicr - add_fixed(f, ins) - fields[f] = [(21, 5), (26, 1)] - continue - if ins in ['mfspr', 'mtspr'] and f == "spr" and fields[f] == [(11, 10)]: # mfspr - add_fixed(f, ins) - fields[f] = [(16, 5), (11, 5)] - continue - if re.match(r'[a-z]+', f): - add_fixed(f, ins) - continue + # Fix up fields fields_str = "" - for fkey, fval_ in sorted(fields.items()): + for f, fval in sorted(fields.items()): fields_str += '{' - fields_str += 'Name: "{}", Bits: []powerpc.InsnBits'.format(fkey) + fields_str += 'Name: "{}", Bits: []powerpc.InsnBits'.format(f) fields_str += '{' - for fval in fval_: - fields_str += '{{{}, {}}}, '.format(fval[0], fval[1]) - if int(fval[1]) == 0: + for ff in fval: + fields_str += '{{{}, {}}}, '.format(ff[0], ff[1]) + if ff[1] == 0: pe.pprint("!Wrong length!") sys.exit(-1) fields_str = fields_str[:-2] + '}}, ' return opcode, opmask, fields_str[:-2] - for ins, ival in sorted(insns.items()):#, key: lambda x: insns[x].opcode): + for ins, ival in sorted(insns.items()): tmp = '\t{Name: "' tmp += ins tmp += '", ' - if len(ival['layout']) >= 1: - opcode, opmask, fields = generate_opcode(ins, ival['layout'][0]) - if "Priv" in ival: - tmp += 'Opcode: 0x{:08x}, Mask: 0x{:08x}, Priv: true, Fields: []powerpc.InsnField{{{}}}'.format(opcode, opmask, fields) - else: - tmp += 'Opcode: 0x{:08x}, Mask: 0x{:08x}, Fields: []powerpc.InsnField{{{}}}'.format(opcode, opmask, fields) - if len(ival['layout']) == 2: - opcode, opmask, fields = generate_opcode(ins, ival['layout'][1]) + if len(ival) >= 1: + opcode, opmask, fields = generate_opcode(ins, ival[0]) + tmp += 'Opcode: 0x{:08x}, Mask: 0x{:08x}, Fields: []powerpc.InsnField{{{}}}'.format(opcode, opmask, fields) + if ins in priv: + tmp += ', Priv: true' + if len(ival) == 2: + opcode, opmask, fields = generate_opcode(ins, ival[1]) tmp += ',\n\t\tOpcodeSuffix: 0x{:08x}, MaskSuffix: 0x{:08x}, FieldsSuffix: []powerpc.InsnField{{{}}}'.format(opcode, opmask, fields) tmp += "}," @@ -245,8 +237,6 @@ insns = {} for tex in texfiles: insns.update(find_insns(tex, layouts)) -collect_priv(isa_dir + "/Appendices/PPC_ApInstMnem.tex", insns) - print('// Code generated by {}. DO NOT EDIT.'.format(sys.argv[0])) print('') print('//go:build !codeanalysis') @@ -261,8 +251,7 @@ print('\tpowerpc.Register(insns)') print('}') print('') print('var insns = []*powerpc.Insn{') -generate_go(insns) +generate_go(insns, collect_priv(isa_dir + "/Appendices/PPC_ApInstMnem.tex", insns)) print("}") pe.pprint("Processed {} instructions".format(len(insns))) -print_fixed() |
