Merge commit '802798ce3c8baa4697120580f87bc1ee377306d3' as 'external/capstone'

This commit is contained in:
2026-05-11 11:55:07 +02:00
3968 changed files with 2967598 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+301
View File
@@ -0,0 +1,301 @@
/* Capstone Disassembly Engine */
/* M68K Backend by Daniel Collin <daniel@collin.com> 2015-2016 */
#ifndef CS_M68KDISASSEMBLER_H
#define CS_M68KDISASSEMBLER_H
#include "../../MCInst.h"
/* ======================================================================== */
/* ============================ GENERAL DEFINES =========================== */
/* ======================================================================== */
/* Bit Isolation Functions */
#define BIT_0(A) ((A) & 0x00000001)
#define BIT_1(A) ((A) & 0x00000002)
#define BIT_2(A) ((A) & 0x00000004)
#define BIT_3(A) ((A) & 0x00000008)
#define BIT_4(A) ((A) & 0x00000010)
#define BIT_5(A) ((A) & 0x00000020)
#define BIT_6(A) ((A) & 0x00000040)
#define BIT_7(A) ((A) & 0x00000080)
#define BIT_8(A) ((A) & 0x00000100)
#define BIT_9(A) ((A) & 0x00000200)
#define BIT_A(A) ((A) & 0x00000400)
#define BIT_B(A) ((A) & 0x00000800)
#define BIT_C(A) ((A) & 0x00001000)
#define BIT_D(A) ((A) & 0x00002000)
#define BIT_E(A) ((A) & 0x00004000)
#define BIT_F(A) ((A) & 0x00008000)
#define BIT_10(A) ((A) & 0x00010000)
#define BIT_11(A) ((A) & 0x00020000)
#define BIT_12(A) ((A) & 0x00040000)
#define BIT_13(A) ((A) & 0x00080000)
#define BIT_14(A) ((A) & 0x00100000)
#define BIT_15(A) ((A) & 0x00200000)
#define BIT_16(A) ((A) & 0x00400000)
#define BIT_17(A) ((A) & 0x00800000)
#define BIT_18(A) ((A) & 0x01000000)
#define BIT_19(A) ((A) & 0x02000000)
#define BIT_1A(A) ((A) & 0x04000000)
#define BIT_1B(A) ((A) & 0x08000000)
#define BIT_1C(A) ((A) & 0x10000000)
#define BIT_1D(A) ((A) & 0x20000000)
#define BIT_1E(A) ((A) & 0x40000000)
#define BIT_1F(A) ((A) & 0x80000000)
/* These are the CPU types understood by this disassembler */
#define TYPE_68000 1
#define TYPE_68010 2
#define TYPE_68020 4
#define TYPE_68030 8
#define TYPE_68040 16
#define TYPE_68060 32
#define TYPE_CPU32 64
#define M68000_ONLY TYPE_68000
#define M68010_ONLY TYPE_68010
#define M68010_LESS (TYPE_68000 | TYPE_68010)
#define M68010_PLUS \
(TYPE_68010 | TYPE_68020 | TYPE_68030 | TYPE_68040 | TYPE_68060)
#define M68020_ONLY TYPE_68020
#define M68020_LESS (TYPE_68010 | TYPE_68020)
#define M68020_PLUS (TYPE_68020 | TYPE_68030 | TYPE_68040 | TYPE_68060)
#define M68030_ONLY TYPE_68030
#define M68030_LESS (TYPE_68010 | TYPE_68020 | TYPE_68030)
#define M68030_PLUS (TYPE_68030 | TYPE_68040 | TYPE_68060)
#define M68040_PLUS (TYPE_68040 | TYPE_68060)
/* Extension word formats */
#define EXT_8BIT_DISPLACEMENT(A) ((A) & 0xff)
#define EXT_FULL(A) BIT_8(A)
#define EXT_EFFECTIVE_ZERO(A) (((A) & 0xe4) == 0xc4 || ((A) & 0xe2) == 0xc0)
#define EXT_BASE_REGISTER_PRESENT(A) (!BIT_7(A))
#define EXT_INDEX_REGISTER_PRESENT(A) (!BIT_6(A))
#define EXT_INDEX_REGISTER(A) (((A) >> 12) & 7)
#define EXT_INDEX_PRE_POST(A) (EXT_INDEX_REGISTER_PRESENT(A) && (A) & 3)
#define EXT_INDEX_PRE(A) \
(EXT_INDEX_REGISTER_PRESENT(A) && ((A) & 7) < 4 && ((A) & 7) != 0)
#define EXT_INDEX_POST(A) (EXT_INDEX_REGISTER_PRESENT(A) && ((A) & 7) > 4)
#define EXT_INDEX_SCALE(A) (((A) >> 9) & 3)
#define EXT_INDEX_LONG(A) BIT_B(A)
#define EXT_INDEX_AR(A) BIT_F(A)
#define EXT_BASE_DISPLACEMENT_PRESENT(A) (((A) & 0x30) > 0x10)
#define EXT_BASE_DISPLACEMENT_WORD(A) (((A) & 0x30) == 0x20)
#define EXT_BASE_DISPLACEMENT_LONG(A) (((A) & 0x30) == 0x30)
/* Outer displacement is present when I/IS[1:0] (bits 1-0) is 2 (word) or 3 (long).
* This applies regardless of the IS bit (bit 6): when index is suppressed,
* I/IS values 5-7 mirror 1-3 (just indirect instead of postindexed).
* The old check ((A) & 0x47) < 0x44 incorrectly excluded IS=1 cases
* (I/IS=6,7) which DO have outer displacements per the M68K spec.
*/
#define EXT_OUTER_DISPLACEMENT_PRESENT(A) (((A) & 3) > 1)
#define EXT_OUTER_DISPLACEMENT_WORD(A) (((A) & 3) == 2)
#define EXT_OUTER_DISPLACEMENT_LONG(A) (((A) & 3) == 3)
#define IS_BITSET(val, b) ((val) & (1 << (b)))
#define BITFIELD_MASK(sb, eb) (((1 << ((sb) + 1)) - 1) & (~((1 << (eb)) - 1)))
#define BITFIELD(val, sb, eb) ((BITFIELD_MASK(sb, eb) & (val)) >> (eb))
/* Bitfield offset/width encoding.
* Public decode macros (M68K_BF_*) live in <capstone/m68k.h>.
* Internal aliases kept for brevity within arch code. */
#define M68K_BITFIELD_REG_FLAG M68K_BF_REG_FLAG
#define M68K_BITFIELD_IS_REG(v) M68K_BF_IS_REG(v)
#define M68K_BITFIELD_REG_NUM(v) M68K_BF_REG_NUM(v)
#define M68K_BITFIELD_ENCODE_REG(regnum) (((regnum) & 7) | M68K_BF_REG_FLAG)
/* ── Coprocessor ID (CpID) ───────────────────────────────────────────
* Bits 11:9 of the F-line instruction word select the coprocessor. */
#define M68K_CPID(info) (((info)->ir >> 9) & 7)
#define M68K_CPID_MMU 0 /* PMMU (68030/68851) */
#define M68K_CPID_FPU 1 /* FPU (68881/68882/internal) */
#define M68K_CPID_CACHE 2 /* Cache ops -- cinvl/cpushl on 68040+ */
/* ── IR bit-field helpers ────────────────────────────────────────────
* Extract commonly-used fields from the first instruction word. */
/* 6-bit coprocessor condition (bits 5:0 of IR). */
#define M68K_IR_CONDITION(info) ((info)->ir & 0x3f)
/* cinv/cpush: select cpush(1) vs cinv(0) -- bit 5 of IR. */
#define M68K_IR_IS_CPUSH(info) (((info)->ir >> 5) & 1)
/* cinv/cpush: cache scope -- bits 4:3 of IR (0=invalid,1=line,2=page,3=all). */
#define M68K_IR_CACHE_SCOPE(info) (((info)->ir >> 3) & 3)
/* cinv/cpush: cache selector -- bits 7:6 of IR (DC/IC/BC). */
#define M68K_IR_CACHE_SEL(info) (((info)->ir >> 6) & 3)
/* ── FPU extension-word bit-field helpers ────────────────────────────
* The FPU command word is the 16-bit extension following the F-line. */
/* R/M bit (bit 14): 1 = source from EA, 0 = source from FP register. */
#define M68K_FEXT_RM(ext) (((ext) >> 14) & 1)
/* Type / command class (bits 15:13). */
#define M68K_FEXT_TYPE(ext) (((ext) >> 13) & 7)
/* Source specifier (bits 12:10) -- data format when R/M=1. */
#define M68K_FEXT_SRC(ext) (((ext) >> 10) & 7)
/* Destination FP register (bits 9:7). */
#define M68K_FEXT_DST(ext) (((ext) >> 7) & 7)
/* Opmode (bits 5:0) -- FPU operation selector. */
#define M68K_FEXT_OPMODE(ext) ((ext) & 0x3f)
/* Single/double precision flag (bit 6) -- 68040+ only. */
#define M68K_FEXT_SD_FLAG(ext) (((ext) >> 6) & 1)
/* FMOVECR signature: bits 15:10 == 0x17 (010111b). */
#define M68K_FEXT_IS_FMOVECR(ext) (BITFIELD((ext), 15, 10) == 0x17)
/* Register-select field for FMOVE to/from FPCR/FPSR/FPIAR (bits 12:10). */
#define M68K_FEXT_REGSEL(ext) (((ext) >> 10) & 7)
/* Direction bit for FMOVE FPCR (bit 13): 0 = ea->fpcr, 1 = fpcr->ea. */
#define M68K_FEXT_DIR(ext) (((ext) >> 13) & 1)
/* ── FPU condition-code mask ─────────────────────────────────────────
* FBcc/FDBcc/FScc/FTRAPcc encode the FP condition in bits 5,3:0
* of the extension word (or IR for FBcc). Bit 4 is always 0,
* yielding the 0x2f mask. */
#define M68K_FP_COND(x) ((x) & 0x2f)
/* Maximum valid condition codes per coprocessor. */
#define M68K_PMMU_MAX_COND 16
#define M68K_FPU_MAX_COND 32
/* ── FPU source-format constants (bits 12:10 of ext word) ───────────*/
#define M68K_FPSRC_LONG 0x00 /* .l -- 32-bit integer */
#define M68K_FPSRC_SINGLE 0x01 /* .s -- 32-bit IEEE single */
#define M68K_FPSRC_EXTENDED 0x02 /* .x -- 96-bit extended real */
#define M68K_FPSRC_PACKED 0x03 /* .p -- 96-bit packed decimal */
#define M68K_FPSRC_WORD 0x04 /* .w -- 16-bit integer */
#define M68K_FPSRC_DOUBLE 0x05 /* .d -- 64-bit IEEE double */
#define M68K_FPSRC_BYTE 0x06 /* .b -- 8-bit integer */
/* ── FPU special raw opmodes (before SD-flag masking) ───────────────
* FSSQRT/FDSQRT have raw 7-bit opmodes 0x41/0x45. After the 6-bit
* truncation (& 0x3f) they become 0x01/0x05 with the SD flag set. */
#define M68K_FPOP_FSSQRT_RAW 0x01 /* 0x41 & 0x3f */
#define M68K_FPOP_FDSQRT_RAW 0x05 /* 0x45 & 0x3f */
/* ── CPU-type guard macros ───────────────────────────────────────────
* These reference the `info` parameter available at each call site.
* They early-return from the calling function on type mismatch. */
#define LIMIT_CPU_TYPES(info, ALLOWED_CPU_TYPES) \
do { \
if (!(info->type & ALLOWED_CPU_TYPES)) { \
d68000_invalid(info); \
return; \
} \
} while (0)
/* Like LIMIT_CPU_TYPES but also reverses the instruction word consumption,
* so the invalid instruction produces size=0 (not decoded) instead of size=2.
* Use for handlers that replace d68000_invalid in the dispatch table. */
#define LIMIT_CPU_TYPES_UNDECODED(info, ALLOWED_CPU_TYPES) \
do { \
if (!(info->type & ALLOWED_CPU_TYPES)) { \
info->pc -= 2; \
d68000_invalid(info); \
return; \
} \
} while (0)
/* Like LIMIT_CPU_TYPES but also rejects CPU32. CPU32 shares TYPE_68020 but
* lacks some 68020 instructions (CAS, CAS2, CHK.L, PACK, UNPK). */
#define LIMIT_CPU_TYPES_NOT_CPU32(info, ALLOWED_CPU_TYPES) \
do { \
if (!(info->type & (ALLOWED_CPU_TYPES)) || \
(info->type & TYPE_CPU32)) { \
d68000_invalid(info); \
return; \
} \
} while (0)
/* Require CpID == FPU. Rejects all other coprocessor IDs.
* Used by cpDBcc, cpScc, cpTRAPcc handlers. */
#define REQUIRE_CPID_FPU(info) \
do { \
if (M68K_CPID(info) != M68K_CPID_FPU) { \
d68000_invalid(info); \
return; \
} \
} while (0)
/* Require CpID == MMU or CpID == FPU.
* CpID MMU is rejected on CPU32 (no PMMU). Used by cpSAVE/cpRESTORE. */
#define REQUIRE_CPID_FPU_OR_PMMU(info) \
do { \
int _cpid = M68K_CPID(info); \
if (_cpid == M68K_CPID_MMU && ((info)->type & TYPE_CPU32)) { \
d68000_invalid(info); \
return; \
} \
if (_cpid != M68K_CPID_MMU && _cpid != M68K_CPID_FPU) { \
d68000_invalid(info); \
return; \
} \
} while (0)
/* ── EA / immediate convenience aliases ─────────────────────────────
* Shorthand wrappers around the sized get_ea_mode_str / get_imm_str
* functions. These expand at the call site where 'info' is in scope. */
/* Fake a split interface */
#define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0)
#define get_ea_mode_str_16(instruction) get_ea_mode_str(instruction, 1)
#define get_ea_mode_str_32(instruction) get_ea_mode_str(instruction, 2)
#define get_imm_str_s8() get_imm_str_s(0)
#define get_imm_str_s16() get_imm_str_s(1)
#define get_imm_str_s32() get_imm_str_s(2)
#define get_imm_str_u8() get_imm_str_u(0)
#define get_imm_str_u16() get_imm_str_u(1)
#define get_imm_str_u32() get_imm_str_u(2)
/* ── Operand access shorthands ──────────────────────────────────────
* Quick access to the operand array and instruction size via `info`. */
#define IOPS(I) (&info->extension.operands[(I)])
#define ISIZE (info->extension.op_size.cpu_size)
/* ======================================================================== */
/* ============================ INTERNAL TYPES ============================ */
/* ======================================================================== */
/* Private, For internal use only */
typedef struct m68k_info {
const uint8_t *code;
size_t code_len;
uint64_t baseAddress;
MCInst *inst;
unsigned int pc; /* program counter */
unsigned int ir; /* instruction register */
unsigned int type;
unsigned int address_mask; /* Address mask to simulate address lines */
cs_m68k extension;
uint16_t regs_read
[MAX_IMPL_R_REGS]; // list of implicit registers read by this insn
uint8_t regs_read_count; // number of implicit registers read by this insn
uint16_t regs_write
[MAX_IMPL_W_REGS]; // list of implicit registers modified by this insn
uint8_t regs_write_count; // number of implicit registers modified by this insn
uint8_t groups[MAX_NUM_GROUPS];
uint8_t groups_count;
} m68k_info;
bool M68K_getInstruction(csh ud, const uint8_t *code, size_t code_len,
MCInst *instr, uint16_t *size, uint64_t address,
void *info);
#endif
+588
View File
@@ -0,0 +1,588 @@
/* Capstone Disassembly Engine */
/* M68K Backend by Daniel Collin <daniel@collin.com> 2015-2016 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "M68KInstPrinter.h"
#include "M68KDisassembler.h"
#include "../../Mapping.h"
#include "../../cs_priv.h"
#include "../../utils.h"
#include "../../MCInst.h"
#include "../../MCInstrDesc.h"
#include "../../MCRegisterInfo.h"
#ifndef CAPSTONE_DIET
static const char s_spacing[] = " ";
static const char *const s_reg_names[] = {
"invalid", "d0", "d1", "d2", "d3", "d4", "d5", "d6",
"d7", "a0", "a1", "a2", "a3", "a4", "a5", "a6",
"a7", "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6",
"fp7", "pc", "sr", "ccr", "sfc", "dfc", "usp", "vbr",
"cacr", "caar", "msp", "isp", "tc", "itt0", "itt1", "dtt0",
"dtt1", "mmusr", "urp", "srp",
"fpcr", "fpsr", "fpiar",
"tt0", "tt1", "crp",
};
static const char *const s_instruction_names[] = {
"invalid", "abcd", "add", "adda", "addi", "addq",
"addx", "and", "andi", "asl", "asr", "bhs",
"blo", "bhi", "bls", "bcc", "bcs", "bne",
"beq", "bvc", "bvs", "bpl", "bmi", "bge",
"blt", "bgt", "ble", "bra", "bsr", "bchg",
"bclr", "bset", "btst", "bfchg", "bfclr", "bfexts",
"bfextu", "bfffo", "bfins", "bfset", "bftst", "bkpt",
"callm", "cas", "cas2", "chk", "chk2", "clr",
"cmp", "cmpa", "cmpi", "cmpm", "cmp2", "cinvl",
"cinvp", "cinva", "cpushl", "cpushp", "cpusha", "dbt",
"dbf", "dbhi", "dbls", "dbcc", "dbcs", "dbne",
"dbeq", "dbvc", "dbvs", "dbpl", "dbmi", "dbge",
"dblt", "dbgt", "dble", "dbra", "divs", "divsl",
"divu", "divul", "eor", "eori", "exg", "ext",
"extb", "fabs", "fsabs", "fdabs", "facos", "fadd",
"fsadd", "fdadd", "fasin", "fatan", "fatanh", "fbf",
"fbeq", "fbogt", "fboge", "fbolt", "fbole", "fbogl",
"fbor", "fbun", "fbueq", "fbugt", "fbuge", "fbult",
"fbule", "fbne", "fbt", "fbsf", "fbseq", "fbgt",
"fbge", "fblt", "fble", "fbgl", "fbgle", "fbngle",
"fbngl", "fbnle", "fbnlt", "fbnge", "fbngt", "fbsne",
"fbst", "fcmp", "fcos", "fcosh", "fdbf", "fdbeq",
"fdbogt", "fdboge", "fdbolt", "fdbole", "fdbogl", "fdbor",
"fdbun", "fdbueq", "fdbugt", "fdbuge", "fdbult", "fdbule",
"fdbne", "fdbt", "fdbsf", "fdbseq", "fdbgt", "fdbge",
"fdblt", "fdble", "fdbgl", "fdbgle", "fdbngle", "fdbngl",
"fdbnle", "fdbnlt", "fdbnge", "fdbngt", "fdbsne", "fdbst",
"fdiv", "fsdiv", "fddiv", "fetox", "fetoxm1", "fgetexp",
"fgetman", "fint", "fintrz", "flog10", "flog2", "flogn",
"flognp1", "fmod", "fmove", "fsmove", "fdmove", "fmovecr",
"fmovem", "fmul", "fsmul", "fdmul", "fneg", "fsneg",
"fdneg", "fnop", "frem", "frestore", "fsave", "fscale",
"fsgldiv", "fsglmul", "fsin", "fsincos", "fsinh", "fsqrt",
"fssqrt", "fdsqrt", "fsf", "fseq", "fsogt", "fsoge",
"fsolt", "fsole", "fsogl", "fsor", "fsun", "fsueq",
"fsugt", "fsuge", "fsult", "fsule", "fsne", "fst",
"fssf", "fsseq", "fsgt", "fsge", "fslt", "fsle",
"fsgl", "fsgle", "fsngle", "fsngl", "fsnle", "fsnlt",
"fsnge", "fsngt", "fssne", "fsst", "fsub", "fssub",
"fdsub", "ftan", "ftanh", "ftentox", "ftrapf", "ftrapeq",
"ftrapogt", "ftrapoge", "ftrapolt", "ftrapole", "ftrapogl", "ftrapor",
"ftrapun", "ftrapueq", "ftrapugt", "ftrapuge", "ftrapult", "ftrapule",
"ftrapne", "ftrapt", "ftrapsf", "ftrapseq", "ftrapgt", "ftrapge",
"ftraplt", "ftraple", "ftrapgl", "ftrapgle", "ftrapngle", "ftrapngl",
"ftrapnle", "ftrapnlt", "ftrapnge", "ftrapngt", "ftrapsne", "ftrapst",
"ftst", "ftwotox", "halt", "illegal", "jmp", "jsr",
"lea", "link", "lpstop", "lsl", "lsr", "move",
"movea", "movec", "movem", "movep", "moveq", "moves",
"move16", "muls", "mulu", "nbcd", "neg", "negx",
"nop", "not", "or", "ori", "pack", "pea",
"pflush", "pflusha", "pflushan", "pflushn", "ploadr", "ploadw",
"plpar", "plpaw", "pmove", "pmovefd", "ptestr", "ptestw",
"pulse", "rems", "remu", "reset", "rol", "ror",
"roxl", "roxr", "rtd", "rte", "rtm", "rtr",
"rts", "sbcd", "st", "sf", "shi", "sls",
"scc", "shs", "scs", "slo", "sne", "seq",
"svc", "svs", "spl", "smi", "sge", "slt",
"sgt", "sle", "stop", "sub", "suba", "subi",
"subq", "subx", "swap", "tas", "trap", "trapv",
"trapt", "trapf", "traphi", "trapls", "trapcc", "traphs",
"trapcs", "traplo", "trapne", "trapeq", "trapvc", "trapvs",
"trappl", "trapmi", "trapge", "traplt", "trapgt", "traple",
"tst", "unlk", "unpk", "bgnd", "tbls", "tblu",
"tblsn", "tblun",
};
#endif
#ifndef CAPSTONE_DIET
static const char *getRegName(m68k_reg reg)
{
return s_reg_names[(int)reg];
}
static void printRegbits(SStream *O, bool *need_sep, uint32_t data,
const char *prefix)
{
unsigned int first;
int i;
for (i = 0; i < 8; ++i) {
if (!(data & (1 << i)))
continue;
first = i;
while (i < 7 && (data & (1 << (i + 1))))
i++;
if (*need_sep)
SStream_concat1(O, '/');
*need_sep = true;
SStream_concat(O, "%s%" PRIu32, prefix, first);
if ((unsigned int)i > first)
SStream_concat(O, "-%s%" PRIu32, prefix,
(unsigned int)i);
}
}
static void registerBits(SStream *O, const cs_m68k_op *op)
{
unsigned int data = op->register_bits;
bool need_sep = false;
if (!data) {
SStream_concat(O, "%s", "#$0");
return;
}
printRegbits(O, &need_sep, data & 0xff, "d");
printRegbits(O, &need_sep, (data >> 8) & 0xff, "a");
printRegbits(O, &need_sep, (data >> 16) & 0xff, "fp");
}
static void registerPair(SStream *O, const cs_m68k_op *op)
{
SStream_concat(O, "%s:%s", s_reg_names[op->reg_pair.reg_0],
s_reg_names[op->reg_pair.reg_1]);
}
static void printScaleFactor(SStream *O, uint8_t scale, int threshold)
{
if (scale > threshold)
SStream_concat(O, "%s*%s%" PRId8, s_spacing, s_spacing, scale);
}
static void printIndexReg(SStream *O, const cs_m68k_op *op)
{
SStream_concat(O, "%s.%c", getRegName(op->mem.index_reg),
op->mem.index_size ? 'l' : 'w');
}
static void printBitfield(SStream *O, const cs_m68k_op *op)
{
if (!op->mem.bitfield)
return;
SStream_concat0(O, "{");
if (M68K_BF_IS_REG(op->mem.offset))
SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.offset));
else
SStream_concat(O, "%" PRId8, op->mem.offset);
SStream_concat0(O, ":");
if (M68K_BF_IS_REG(op->mem.width))
SStream_concat(O, "d%" PRId8, M68K_BF_REG_NUM(op->mem.width));
else
SStream_concat(O, "%" PRId8, op->mem.width);
SStream_concat0(O, "}");
}
static void printImmediate(SStream *O, const cs_m68k *inst,
const cs_m68k_op *op)
{
if (inst->op_size.type == M68K_SIZE_TYPE_FPU) {
#if defined(_KERNEL_MODE)
SStream_concat(O, "#<float_point_unsupported>");
return;
#else
if (inst->op_size.fpu_size == M68K_FPU_SIZE_SINGLE)
SStream_concat(O, "#%f", op->simm);
else if (inst->op_size.fpu_size == M68K_FPU_SIZE_DOUBLE)
SStream_concat(O, "#%f", op->dimm);
else
SStream_concat(O, "#<unsupported>");
return;
#endif
}
SStream_concat(O, "#$%" PRIx64, op->imm);
}
static void printIndex8BitDisp(SStream *O, unsigned int pc,
const cs_m68k_op *op)
{
if (op->address_mode == M68K_AM_PCI_INDEX_8_BIT_DISP) {
SStream_concat(O, "$%" PRIx32 "(pc,%s", pc + 2 + op->mem.disp,
s_spacing);
} else {
SStream_concat(O, "%s$%" PRIx16 "(%s,%s",
op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
getRegName(op->mem.base_reg), s_spacing);
}
printIndexReg(O, op);
printScaleFactor(O, op->mem.scale, 1);
SStream_concat0(O, ")");
}
static void printRegAddrMode(SStream *O, unsigned int pc, const cs_m68k_op *op)
{
switch (op->address_mode) {
case M68K_AM_REG_DIRECT_DATA:
SStream_concat(O, "d%" PRId32, (op->reg - M68K_REG_D0));
break;
case M68K_AM_REG_DIRECT_ADDR:
SStream_concat(O, "a%" PRId32, (op->reg - M68K_REG_A0));
break;
case M68K_AM_REGI_ADDR:
SStream_concat(O, "(a%" PRId32 ")", (op->reg - M68K_REG_A0));
break;
case M68K_AM_REGI_ADDR_POST_INC:
SStream_concat(O, "(a%" PRId32 ")+", (op->reg - M68K_REG_A0));
break;
case M68K_AM_REGI_ADDR_PRE_DEC:
SStream_concat(O, "-(a%" PRId32 ")", (op->reg - M68K_REG_A0));
break;
case M68K_AM_REGI_ADDR_DISP:
SStream_concat(O, "%s$%" PRIx16 "(a%" PRId32 ")",
op->mem.disp < 0 ? "-" : "", abs(op->mem.disp),
(op->mem.base_reg - M68K_REG_A0));
break;
case M68K_AM_PCI_DISP:
SStream_concat(O, "$%" PRIx32 "(pc)", pc + 2 + op->mem.disp);
break;
default:
break;
}
}
static void printBaseDisp(SStream *O, unsigned int pc, const cs_m68k_op *op)
{
int is_pc = (op->address_mode == M68K_AM_PCI_INDEX_BASE_DISP);
if (is_pc) {
SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
} else if (op->mem.in_disp != 0) {
SStream_concat(O, "%s$%" PRIx32,
op->mem.in_disp >= 0 ? "" : "-",
abs(op->mem.in_disp));
}
SStream_concat0(O, "(");
if (is_pc) {
SStream_concat0(O, "pc");
} else if (op->mem.base_reg != M68K_REG_INVALID) {
SStream_concat(O, "a%" PRId32, op->mem.base_reg - M68K_REG_A0);
}
if ((is_pc || op->mem.base_reg != M68K_REG_INVALID) &&
op->mem.index_reg != M68K_REG_INVALID)
SStream_concat(O, ",%s", s_spacing);
if (op->mem.index_reg != M68K_REG_INVALID) {
printIndexReg(O, op);
printScaleFactor(O, op->mem.scale, 0);
}
SStream_concat0(O, ")");
}
static void printMemIndirect(SStream *O, unsigned int pc, const cs_m68k_op *op)
{
int is_pc = (op->address_mode == M68K_AM_PC_MEMI_POST_INDEX ||
op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
int is_post = (op->address_mode == M68K_AM_MEMI_POST_INDEX ||
op->address_mode == M68K_AM_PC_MEMI_POST_INDEX);
int is_pre = (op->address_mode == M68K_AM_MEMI_PRE_INDEX ||
op->address_mode == M68K_AM_PC_MEMI_PRE_INDEX);
SStream_concat0(O, "([");
if (is_pc) {
SStream_concat(O, "$%" PRIx32, pc + 2 + op->mem.in_disp);
} else if (op->mem.in_disp != 0) {
SStream_concat(O, "%s$%" PRIx32,
op->mem.in_disp >= 0 ? "" : "-",
abs(op->mem.in_disp));
}
if (op->mem.base_reg != M68K_REG_INVALID) {
if (op->mem.in_disp != 0)
SStream_concat(O, ",%s%s", s_spacing,
getRegName(op->mem.base_reg));
else
SStream_concat(O, "%s", getRegName(op->mem.base_reg));
}
if (is_post)
SStream_concat0(O, "]");
if (op->mem.index_reg != M68K_REG_INVALID) {
SStream_concat(O, ",%s", s_spacing);
printIndexReg(O, op);
}
printScaleFactor(O, op->mem.scale, 0);
if (is_pre)
SStream_concat0(O, "]");
if (op->mem.out_disp != 0) {
SStream_concat(O, ",%s%s$%" PRIx32, s_spacing,
op->mem.out_disp >= 0 ? "" : "-",
abs(op->mem.out_disp));
}
SStream_concat0(O, ")");
}
static void printAddressingMode(SStream *O, unsigned int pc,
const cs_m68k *inst, const cs_m68k_op *op)
{
switch (op->address_mode) {
case M68K_AM_NONE:
switch (op->type) {
case M68K_OP_REG_BITS:
registerBits(O, op);
break;
case M68K_OP_REG_PAIR:
registerPair(O, op);
break;
case M68K_OP_REG:
SStream_concat(O, "%s", s_reg_names[op->reg]);
break;
default:
break;
}
break;
case M68K_AM_REG_DIRECT_DATA:
case M68K_AM_REG_DIRECT_ADDR:
case M68K_AM_REGI_ADDR:
case M68K_AM_REGI_ADDR_POST_INC:
case M68K_AM_REGI_ADDR_PRE_DEC:
case M68K_AM_REGI_ADDR_DISP:
case M68K_AM_PCI_DISP:
printRegAddrMode(O, pc, op);
break;
case M68K_AM_ABSOLUTE_DATA_SHORT:
SStream_concat(O, "$%" PRIx32 ".w", (uint32_t)op->imm);
break;
case M68K_AM_ABSOLUTE_DATA_LONG:
SStream_concat(O, "$%" PRIx64 ".l", (uint64_t)op->imm);
break;
case M68K_AM_IMMEDIATE:
printImmediate(O, inst, op);
break;
case M68K_AM_PCI_INDEX_8_BIT_DISP:
case M68K_AM_AREGI_INDEX_8_BIT_DISP:
printIndex8BitDisp(O, pc, op);
break;
case M68K_AM_PCI_INDEX_BASE_DISP:
case M68K_AM_AREGI_INDEX_BASE_DISP:
printBaseDisp(O, pc, op);
break;
case M68K_AM_PC_MEMI_POST_INDEX:
case M68K_AM_PC_MEMI_PRE_INDEX:
case M68K_AM_MEMI_PRE_INDEX:
case M68K_AM_MEMI_POST_INDEX:
printMemIndirect(O, pc, op);
break;
case M68K_AM_BRANCH_DISPLACEMENT:
SStream_concat(O, "$%" PRIx32, pc + 2 + op->br_disp.disp);
default:
break;
}
printBitfield(O, op);
}
static void printCAS2(SStream *O, unsigned int pc, const cs_m68k *ext)
{
printAddressingMode(O, pc, ext, &ext->operands[0]);
SStream_concat0(O, ",");
printAddressingMode(O, pc, ext, &ext->operands[1]);
SStream_concat0(O, ",");
SStream_concat(O, "(%s):(%s)",
s_reg_names[ext->operands[2].reg_pair.reg_0],
s_reg_names[ext->operands[2].reg_pair.reg_1]);
}
static void printCacheOp(SStream *O, unsigned int pc, const cs_m68k *ext)
{
static const char *const cache_names[] = { "nc", "dc", "ic", "bc" };
unsigned int sel = (unsigned int)ext->operands[0].imm;
int i;
if (sel < ARR_SIZE(cache_names))
SStream_concat0(O, cache_names[sel]);
else
SStream_concat(O, "#$%" PRIx64, ext->operands[0].imm);
for (i = 1; i < ext->op_count; ++i) {
SStream_concat(O, ",%s", s_spacing);
printAddressingMode(O, pc, ext, &ext->operands[i]);
}
}
#endif
static void printOpSize(SStream *O, const cs_m68k *ext)
{
switch (ext->op_size.type) {
case M68K_SIZE_TYPE_INVALID:
break;
case M68K_SIZE_TYPE_CPU:
switch (ext->op_size.cpu_size) {
case M68K_CPU_SIZE_BYTE:
SStream_concat0(O, ".b");
break;
case M68K_CPU_SIZE_WORD:
SStream_concat0(O, ".w");
break;
case M68K_CPU_SIZE_LONG:
SStream_concat0(O, ".l");
break;
case M68K_CPU_SIZE_NONE:
break;
}
break;
case M68K_SIZE_TYPE_FPU:
switch (ext->op_size.fpu_size) {
case M68K_FPU_SIZE_SINGLE:
SStream_concat0(O, ".s");
break;
case M68K_FPU_SIZE_DOUBLE:
SStream_concat0(O, ".d");
break;
case M68K_FPU_SIZE_EXTENDED:
SStream_concat0(O, ".x");
break;
case M68K_FPU_SIZE_NONE:
break;
}
break;
}
}
void M68K_printInst(MCInst *MI, SStream *O, void *PrinterInfo)
{
#ifndef CAPSTONE_DIET
m68k_info *info = (m68k_info *)PrinterInfo;
cs_m68k *ext = &info->extension;
cs_detail *detail = NULL;
int i = 0;
if (detail_is_set(MI)) {
detail = get_detail(MI);
int regs_read_count = MIN((int)ARR_SIZE(detail->regs_read),
info->regs_read_count);
int regs_write_count = MIN((int)ARR_SIZE(detail->regs_write),
info->regs_write_count);
int groups_count =
MIN((int)ARR_SIZE(detail->groups), info->groups_count);
memcpy(&detail->m68k, ext, sizeof(cs_m68k));
memcpy(&detail->regs_read, &info->regs_read,
regs_read_count * sizeof(info->regs_read[0]));
detail->regs_read_count = regs_read_count;
memcpy(&detail->regs_write, &info->regs_write,
regs_write_count * sizeof(info->regs_write[0]));
detail->regs_write_count = regs_write_count;
memcpy(&detail->groups, &info->groups, groups_count);
detail->groups_count = groups_count;
}
if (MI->Opcode == M68K_INS_INVALID) {
if (ext->op_count)
SStream_concat(O, "dc.w $%" PRIx32,
(uint32_t)ext->operands[0].imm);
else
SStream_concat(O, "dc.w $<unknown>");
return;
}
SStream_concat0(O, (char *)s_instruction_names[MI->Opcode]);
printOpSize(O, ext);
SStream_concat0(O, " ");
if (MI->Opcode == M68K_INS_CAS2) {
printCAS2(O, info->pc, ext);
return;
}
if (MI->Opcode >= M68K_INS_CINVL && MI->Opcode <= M68K_INS_CPUSHA) {
printCacheOp(O, info->pc, ext);
return;
}
for (i = 0; i < ext->op_count; ++i) {
printAddressingMode(O, info->pc, ext, &ext->operands[i]);
if ((i + 1) != ext->op_count)
SStream_concat(O, ",%s", s_spacing);
}
#endif
}
const char *M68K_reg_name(csh handle, unsigned int reg)
{
#ifdef CAPSTONE_DIET
return NULL;
#else
if (reg >= ARR_SIZE(s_reg_names)) {
return NULL;
}
return s_reg_names[(int)reg];
#endif
}
void M68K_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
{
insn->id = id; // These id's matches for 68k
}
const char *M68K_insn_name(csh handle, unsigned int id)
{
#ifdef CAPSTONE_DIET
return NULL;
#else
return s_instruction_names[id];
#endif
}
#ifndef CAPSTONE_DIET
static const name_map group_name_maps[] = {
{ M68K_GRP_INVALID, NULL },
{ M68K_GRP_JUMP, "jump" },
{ M68K_GRP_RET, "ret" },
{ M68K_GRP_IRET, "iret" },
{ M68K_GRP_BRANCH_RELATIVE, "branch_relative" },
};
#endif
const char *M68K_group_name(csh handle, unsigned int id)
{
#ifndef CAPSTONE_DIET
return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
#else
return NULL;
#endif
}
#ifndef CAPSTONE_DIET
void M68K_reg_access(const cs_insn *insn, cs_regs regs_read,
uint8_t *regs_read_count, cs_regs regs_write,
uint8_t *regs_write_count)
{
uint8_t read_count, write_count;
read_count = insn->detail->regs_read_count;
write_count = insn->detail->regs_write_count;
// implicit registers
memcpy(regs_read, insn->detail->regs_read,
read_count * sizeof(insn->detail->regs_read[0]));
memcpy(regs_write, insn->detail->regs_write,
write_count * sizeof(insn->detail->regs_write[0]));
*regs_read_count = read_count;
*regs_write_count = write_count;
}
#endif
+27
View File
@@ -0,0 +1,27 @@
/* Capstone Disassembly Engine */
/* M68K Backend by Daniel Collin <daniel@collin.com> 2015 */
#ifndef CS_M68KINSTPRINTER_H
#define CS_M68KINSTPRINTER_H
#include "capstone/capstone.h"
#include "../../MCRegisterInfo.h"
#include "../../MCInst.h"
struct SStream;
void M68K_init(MCRegisterInfo *MRI);
void M68K_printInst(MCInst *MI, struct SStream *O, void *Info);
const char *M68K_reg_name(csh handle, unsigned int reg);
void M68K_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id);
const char *M68K_insn_name(csh handle, unsigned int id);
const char *M68K_group_name(csh handle, unsigned int id);
void M68K_post_printer(csh handle, cs_insn *flat_insn, char *insn_asm,
MCInst *mci);
#ifndef CAPSTONE_DIET
void M68K_reg_access(const cs_insn *insn, cs_regs regs_read,
uint8_t *regs_read_count, cs_regs regs_write,
uint8_t *regs_write_count);
#endif
#endif
File diff suppressed because it is too large Load Diff
+44
View File
@@ -0,0 +1,44 @@
/* Capstone Disassembly Engine */
/* M68K Backend by Daniel Collin <daniel@collin.com> 2015 */
#ifdef CAPSTONE_HAS_M68K
#include "../../utils.h"
#include "../../MCRegisterInfo.h"
#include "M68KDisassembler.h"
#include "M68KInstPrinter.h"
#include "M68KModule.h"
cs_err M68K_global_init(cs_struct *ud)
{
m68k_info *info;
info = cs_mem_calloc(sizeof(m68k_info), 1);
if (!info) {
return CS_ERR_MEM;
}
ud->printer = M68K_printInst;
ud->printer_info = info;
ud->getinsn_info = NULL;
ud->disasm = M68K_getInstruction;
ud->skipdata_size = 2;
ud->post_printer = NULL;
ud->reg_name = M68K_reg_name;
ud->insn_id = M68K_get_insn_id;
ud->insn_name = M68K_insn_name;
ud->group_name = M68K_group_name;
#ifndef CAPSTONE_DIET
ud->reg_access = M68K_reg_access;
#endif
return CS_ERR_OK;
}
cs_err M68K_option(cs_struct *handle, cs_opt_type type, size_t value)
{
return CS_ERR_OK;
}
#endif
+12
View File
@@ -0,0 +1,12 @@
/* Capstone Disassembly Engine */
/* By Travis Finkenauer <tmfinken@gmail.com>, 2018 */
#ifndef CS_M68K_MODULE_H
#define CS_M68K_MODULE_H
#include "../../utils.h"
cs_err M68K_global_init(cs_struct *ud);
cs_err M68K_option(cs_struct *handle, cs_opt_type type, size_t value);
#endif