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