class Mode(enum.Enum):
+ ASM_GEN_C = "opid-asm-gen.c"
DIS_GEN_C = "opid-dis-gen.c"
OPC_GEN_C = "opid-opc-gen.c"
cache = Cache()
codegen = {
+ Mode.ASM_GEN_C: AsmGenSource,
Mode.DIS_GEN_C: DisGenSource,
Mode.OPC_GEN_C: OpcGenSource,
}[self](cache=cache, **arguments)
dynamic_operand_ids: DynamicOperandIds
+class AsmGenSource(Source):
+ @mdis.dispatcher.Hook(DynamicOperands)
+ @contextlib.contextmanager
+ def dispatch_operands(self, node):
+ self.emit("static inline enum opid_state")
+ self.emit("opid_assemble_operand(uint64_t *insn,")
+ with self:
+ with self:
+ self.emit("size_t category,")
+ self.emit("struct opid_operand *operand,")
+ self.emit("void *uctx,")
+ self.emit("enum opid_state (*operand_cb)(void *uctx, struct opid_operand *operand)) {")
+ self.emit("enum opid_state state;")
+ self.emit("")
+ self.emit("state = operand_cb(uctx, operand);")
+ self.emit("if (state != OPID_SUCCESS)")
+ with self:
+ self.emit("return state;")
+ self.emit("")
+ self.emit(f"switch (category) {{")
+ yield node
+ self.emit("default:")
+ with self:
+ self.emit("return OPID_ERROR_OPERAND_0_LOOKUP;")
+ self.emit("}")
+ self.emit("")
+ with self:
+ self.emit("return OPID_SUCCESS;")
+ self.emit("}")
+
+ @mdis.dispatcher.Hook(DynamicOperand)
+ @contextlib.contextmanager
+ def dispatch_operand(self, node, *, path, pathcls):
+ def generic_handler(span, flags="UINT64_C(0)"):
+ limit = f"UINT64_C({((1 << len(span)) - 1)})"
+ yield f"if (operand->value > {limit})"
+ with self:
+ yield "return OPID_ERROR_OPERAND_0_RANGE;"
+ yield f"*insn |= ("
+ with self:
+ yield from store(span)
+ yield f");"
+ yield f"operand->flags = {flags};"
+ self.emit("break;")
+
+ def nonzero_handler(span):
+ yield "--operand->value;"
+ yield "*insn |= ("
+ with self:
+ yield from store(span)
+ yield ");"
+ yield "++operand->value;"
+ yield "operand->flags = OPID_OPERAND_NONZERO;"
+ self.emit("break;")
+
+ def signed_handler(span, flags="OPID_OPERAND_SIGNED"):
+ limit = ((1 << len(span)) - 1)
+ lolimit = f"INT64_C(-{((limit // 2) + 1)})"
+ hilimit = f"INT64_C({(limit // 2)})"
+ yield f"if (((int64_t)operand->value < {lolimit}) ||"
+ with self:
+ with self:
+ yield f"((int64_t)operand->value > {hilimit}))"
+ yield "return OPID_ERROR_OPERAND_0_RANGE;"
+ yield f"*insn |= ("
+ with self:
+ yield from store(span)
+ yield f");"
+ yield f"operand->flags = {flags};"
+ self.emit("break;")
+
+ def address_handler(span):
+ yield from signed_handler(span, "(OPID_OPERAND_ADDRESS | OPID_OPERAND_SIGNED)")
+
+ def gpr_handler(span, pair=False):
+ if not pair:
+ yield from generic_handler(span, "OPID_OPERAND_GPR")
+ else:
+ yield from generic_handler(span, "(OPID_OPERAND_GPR | OPID_OPERAND_PAIR)")
+
+ def fpr_handler(span, pair=False):
+ if not pair:
+ yield from generic_handler(span, "OPID_OPERAND_FPR")
+ else:
+ yield from generic_handler(span, "(OPID_OPERAND_FPR | OPID_OPERAND_PAIR)")
+
+ def cr3_handler(span):
+ yield from generic_handler(span, "OPID_OPERAND_CR3")
+
+ def cr5_handler(span):
+ yield from generic_handler(span, "OPID_OPERAND_CR5")
+
+ handlers = {
+ insndb.GPRPairOperand: lambda span: gpr_handler(span, True),
+ insndb.FPRPairOperand: lambda span: fpr_handler(span, True),
+ insndb.GPROperand: gpr_handler,
+ insndb.FPROperand: fpr_handler,
+ insndb.CR3Operand: cr3_handler,
+ insndb.CR5Operand: cr5_handler,
+ insndb.TargetAddrOperand: address_handler,
+ insndb.SignedOperand: signed_handler,
+ insndb.NonZeroOperand: nonzero_handler,
+ insndb.DynamicOperand: generic_handler,
+ object: None,
+ }
+ self.emit(f"case 0x{(path + 1):02x}: /* {', '.join(node.names)} */")
+ with self:
+ for (cls, handler) in handlers.items():
+ if issubclass(node.cls, cls):
+ break
+ if handler is None:
+ raise ValueError("unknown handler")
+ for line in handler(span=node.span):
+ self.emit(line)
+ self.emit("")
+ yield node
+
+
class DisGenSource(Source):
class Walker(Walker):
@mdis.dispatcher.Hook(DynamicOperand, RecordTable)
@mdis.dispatcher.Hook(OpcodeTable)
@contextlib.contextmanager
- def dispatch_potable(self, node):
+ def dispatch_opcode_table(self, node):
heads = ([0] * (1 << 6))
tails = ([0] * (1 << 6))
for (index, counter) in enumerate(itertools.accumulate(node)):
--- /dev/null
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "opid.h"
+
+static inline enum opid_state
+opid_assemble_operand(uint64_t *insn,
+ size_t category,
+ struct opid_operand *operand,
+ void *uctx,
+ enum opid_state (*operand_cb)(void *uctx, struct opid_operand *operand));
+
+#include "opid-asm-gen.c"
+
+static inline enum opid_state
+opid_assemble_operands(struct opid_ctx *ctx,
+ struct opid_record const *record,
+ uint64_t *insn,
+ void *uctx,
+ enum opid_state (*operand_cb)(void *uctx, struct opid_operand *operand)) {
+ enum opid_state state;
+ struct opid_opcode const *opcode = &record->opcode;
+
+ *insn = (opcode->value & opcode->mask);
+
+ for (size_t id = 0; ((id != OPID_OPERANDS_NR) && record->operands[id]); ++id) {
+ state = opid_assemble_operand(insn,
+ record->operands[id],
+ &ctx->operands[id],
+ uctx,
+ operand_cb);
+ if (state != OPID_SUCCESS)
+ return state;
+ }
+
+ return state;
+}
+
+enum opid_state
+opid_assemble(struct opid_ctx *ctx,
+ char const *name,
+ uint64_t *insn,
+ void *uctx,
+ enum opid_state (*operand_cb)(void *uctx, struct opid_operand *operand)) {
+ struct opid_record const *record;
+
+ record = opid_lookup_name(name);
+ if (record == NULL)
+ return OPID_ERROR_LOOKUP;
+
+ _Static_assert(sizeof(record->name) == sizeof(ctx->name),
+ "record name length does not match context name length");
+ memcpy(ctx->name, record->name, sizeof(record->name));
+
+ return opid_assemble_operands(ctx, record, insn, uctx, operand_cb);
+}
OPID_ERROR_OPERAND_5_LOOKUP,
OPID_ERROR_OPERAND_6_LOOKUP,
OPID_ERROR_OPERAND_7_LOOKUP,
+ OPID_ERROR_OPERAND_0_RANGE,
+ OPID_ERROR_OPERAND_1_RANGE,
+ OPID_ERROR_OPERAND_2_RANGE,
+ OPID_ERROR_OPERAND_3_RANGE,
+ OPID_ERROR_OPERAND_4_RANGE,
+ OPID_ERROR_OPERAND_5_RANGE,
+ OPID_ERROR_OPERAND_6_RANGE,
+ OPID_ERROR_OPERAND_7_RANGE,
};
#define OPID_NAME_BYTES 16
((id != OPID_OPERANDS_NR) && (id != (ctx)->nr_operands))); \
operand = &(ctx)->operands[++id])
+enum opid_state
+opid_assemble(struct opid_ctx *ctx,
+ char const *name,
+ uint64_t *insn,
+ void *uctx,
+ enum opid_state (*operand_cb)(void *uctx, struct opid_operand *operand));
+
enum opid_state
opid_disassemble(struct opid_ctx *ctx, uint64_t insn);
struct opid_record const *
opid_lookup_insn(uint64_t insn);
+
+struct opid_record const *
+opid_lookup_name(char const *name);