parseinstrs: Propagate unpacked data for trie

This commit is contained in:
Alexis Engelke
2020-06-17 16:34:27 +02:00
parent 545ec30ad0
commit 1fedc069b6

View File

@@ -113,16 +113,22 @@ OPKIND_LOOKUP = {
class InstrDesc(NamedTuple):
mnemonic: str
encoding: str
operands: Tuple[str, ...]
flags: FrozenSet[str]
encoding: bitstruct
@classmethod
def parse(cls, desc):
desc = desc.split()
flags = copy(ENCODINGS[desc[0]])
operands = tuple(op for op in desc[1:5] if op != "-")
return cls(desc[5], desc[0], operands, frozenset(desc[6:]))
def encode(self, mnemonics_lut):
flags = copy(ENCODINGS[self.encoding])
flags.mnemonic = mnemonics_lut[self.mnemonic]
fixed_opsz = set()
for i, opkind in enumerate(desc[1:5]):
for i, opkind in enumerate(self.operands):
enc_size, fixed_size, reg_type = OPKIND_LOOKUP[opkind]
if enc_size == 1: fixed_opsz.add(fixed_size)
setattr(flags, "op%d_size"%i, enc_size)
@@ -131,18 +137,16 @@ class InstrDesc(NamedTuple):
if fixed_opsz: flags.gp_fixed_operand_size = next(iter(fixed_opsz))
# Miscellaneous Flags
if "DEF64" in desc[6:]: flags.gp_size_def64 = 1
if "SIZE_8" in desc[6:]: flags.gp_size_8 = 1
if "INSTR_WIDTH" in desc[6:]: flags.gp_instr_width = 1
if "IMM_8" in desc[6:]: flags.imm_byte = 1
if "LOCK" in desc[6:]: flags.lock = 1
if "VSIB" in desc[6:]: flags.vsib = 1
if "MUSTMEM" in desc[6:]: setattr(flags, "op%d_regty"%(flags.modrm_idx^3), 0xf)
if "DEF64" in self.flags: flags.gp_size_def64 = 1
if "SIZE_8" in self.flags: flags.gp_size_8 = 1
if "INSTR_WIDTH" in self.flags: flags.gp_instr_width = 1
if "IMM_8" in self.flags: flags.imm_byte = 1
if "LOCK" in self.flags: flags.lock = 1
if "VSIB" in self.flags: flags.vsib = 1
if "MUSTMEM" in self.flags: setattr(flags, "op%d_regty"%(flags.modrm_idx^3), 0xf)
return cls(desc[5], frozenset(desc[6:]), flags)
def encode(self, mnemonics_lut):
self.encoding.mnemonic = mnemonics_lut[self.mnemonic]
return self.encoding._encode(8)
enc = flags._encode(8)
return tuple(int.from_bytes(enc[i:i+2], "little") for i in range(0, 8, 2))
class EntryKind(Enum):
NONE = 0
@@ -158,7 +162,7 @@ class EntryKind(Enum):
class TrieEntry(NamedTuple):
kind: EntryKind
items: Union[List[Optional[str]], Tuple[Optional[str]]]
payload: ByteString
payload: Tuple[int]
TABLE_LENGTH = {
EntryKind.TABLE256: 256,
@@ -171,17 +175,18 @@ class TrieEntry(NamedTuple):
}
@classmethod
def table(cls, kind):
return cls(kind, [None] * cls.TABLE_LENGTH[kind], b"")
return cls(kind, [None] * cls.TABLE_LENGTH[kind], ())
@classmethod
def instr(cls, payload):
return cls(EntryKind.INSTR, [], payload)
@property
def encode_length(self):
return len(self.payload) + 2 * len(self.items)
def encode(self, encode_item):
return len(self.payload) + len(self.items)
def encode(self, encode_item) -> Tuple[int]:
enc_items = (encode_item(item) if item else 0 for item in self.items)
return self.payload + struct.pack("<%dH"%len(self.items), *enc_items)
print(self)
return self.payload + tuple(enc_items)
def readonly(self):
return TrieEntry(self.kind, tuple(self.items), self.payload)
@@ -331,7 +336,7 @@ class Table:
for name, entry in self.data.items():
self.annotations[current] = "%s(%d)" % (name, entry.kind.value)
self.offsets[name] = current
current += (entry.encode_length + 7) & ~7
current += (2*entry.encode_length + 7) & ~7
if current >= 0x10000:
raise Exception("maximum table size exceeded: {:x}".format(current))
@@ -342,9 +347,11 @@ class Table:
self.calc_offsets()
ordered = sorted((off, self.data[k]) for k, off in self.offsets.items())
data = b""
data = ()
for off, entry in ordered:
data += b"\x00" * (off - len(data)) + entry.encode(self.encode_item)
data += (0,) * (off//2 - len(data)) + entry.encode(self.encode_item)
data = struct.pack("<%dH"%len(data), *data)
stats = dict(Counter(entry.kind for entry in self.data.values()))
print("%d bytes" % len(data), stats)