parser: Use exceptions instead of assertions

This commit is contained in:
Alexis Engelke
2019-11-10 15:54:20 +01:00
parent e73dbb3eea
commit b376d0d0f8

View File

@@ -190,7 +190,8 @@ def parse_opcode(opcode_string):
if opcext: if opcext:
if opcext[1] == "/": if opcext[1] == "/":
opcext = int(opcext[2:], 16) opcext = int(opcext[2:], 16)
assert (0 <= opcext <= 7) or (0xc0 <= opcext <= 0xff) if not (0 <= opcext <= 7) and not (0xc0 <= opcext <= 0xff):
raise Exception("invalid opcext range: {}".format(opcode_string))
if opcext >= 0xc0: if opcext >= 0xc0:
opcext -= 0xb8 opcext -= 0xb8
opcode.append((EntryKind.TABLE72, [opcext])) opcode.append((EntryKind.TABLE72, [opcext]))
@@ -199,8 +200,9 @@ def parse_opcode(opcode_string):
if match.group("extended"): if match.group("extended"):
last_type, last_indices = opcode[-1] last_type, last_indices = opcode[-1]
assert last_type in (EntryKind.TABLE256, EntryKind.TABLE72) if (last_type not in (EntryKind.TABLE256, EntryKind.TABLE72) or
assert len(last_indices) == 1 and last_indices[0] & 7 == 0 len(last_indices) != 1 or last_indices[0] & 7 != 0):
raise Exception("invalid opcode duplication: {}".format(opcode_string))
opcode[-1] = last_type, [last_indices[0] + i for i in range(8)] opcode[-1] = last_type, [last_indices[0] + i for i in range(8)]
@@ -224,6 +226,26 @@ def parse_opcode(opcode_string):
kinds, values = zip(*opcode) kinds, values = zip(*opcode)
return [tuple(zip(kinds, prod)) for prod in product(*values)] return [tuple(zip(kinds, prod)) for prod in product(*values)]
def format_opcode(opcode):
opcode_string = ""
prefix = ""
for kind, byte in opcode:
if kind == EntryKind.TABLE256:
opcode_string += "{:02x}".format(byte)
elif kind in (EntryKind.TABLE8, EntryKind.TABLE72):
opcode_string += "/{:x}".format(byte)
elif kind == EntryKind.TABLE_PREFIX:
if byte & 4:
prefix += "VEX."
prefix += ["NP.", "66.", "F3.", "F2."][byte&3]
elif kind == EntryKind.TABLE_PREFIX_REP:
prefix += ["RNP.", "??.", "RF3.", "RF2."][byte&3]
elif kind == EntryKind.TABLE_VEX:
prefix += "W{}.L{}.".format(byte & 1, byte >> 1)
else:
raise Exception("unsupported opcode kind {}".format(kind))
return prefix + opcode_string
class Table: class Table:
def __init__(self, root_count=1): def __init__(self, root_count=1):
self.data = OrderedDict() self.data = OrderedDict()
@@ -234,24 +256,25 @@ class Table:
self.annotations = {} self.annotations = {}
def add_opcode(self, opcode, instr_encoding, root_idx=0): def add_opcode(self, opcode, instr_encoding, root_idx=0):
opcode = list(opcode) + [(None, None)] name = "t{},{}".format(root_idx, format_opcode(opcode))
opcode = [(opcode[i+1][0], opcode[i][1]) for i in range(len(opcode)-1)]
name, table = "t%d"%root_idx, self.data["root%d"%root_idx] table = self.data["root%d"%root_idx]
for kind, byte in opcode[:-1]: for i in range(len(opcode) - 1):
kind, byte = opcode[i+1][0], opcode[i][1]
if table.items[byte] is None: if table.items[byte] is None:
name += "{:02x}".format(byte) table_name = "t{},{}".format(root_idx, format_opcode(opcode[:i+1]))
self.data[name] = TrieEntry.table(kind) table.items[byte] = table_name
table.items[byte] = name table = self.data[table_name] = TrieEntry.table(kind)
else: else:
name = table.items[byte] table = self.data[table.items[byte]]
table = self.data[name] if table.kind != kind:
assert table.kind == kind raise Exception("have {}, new opcode ({}) has {}".format(
table.kind, name, kind))
# An opcode can occur once only. # An opcode can occur once only.
assert table.items[opcode[-1][1]] is None if table.items[opcode[-1][1]]:
raise Exception("opcode_collision for {}".format(name))
name += "{:02x}/{}".format(opcode[-1][1], "??")
table.items[opcode[-1][1]] = name table.items[opcode[-1][1]] = name
self.data[name] = TrieEntry.instr(instr_encoding) self.data[name] = TrieEntry.instr(instr_encoding)
@@ -279,7 +302,8 @@ class Table:
self.annotations[current] = "%s(%d)" % (name, entry.kind.value) self.annotations[current] = "%s(%d)" % (name, entry.kind.value)
self.offsets[name] = current self.offsets[name] = current
current += (entry.encode_length + 7) & ~7 current += (entry.encode_length + 7) & ~7
assert current < 0x10000 if current >= 0x10000:
raise Exception("maximum table size exceeded: {:x}".format(current))
def encode_item(self, name): def encode_item(self, name):
return self.offsets[name] | self.data[name].kind.value return self.offsets[name] | self.data[name].kind.value