/src/capstonenext/arch/M680X/M680XInstPrinter.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* Capstone Disassembly Engine */ | 
| 2 |  | /* M680X Backend by Wolfgang Schwotzer <wolfgang.schwotzer@gmx.net> 2017 */ | 
| 3 |  |  | 
| 4 |  | #ifdef CAPSTONE_HAS_M680X | 
| 5 |  | #include <stdio.h> | 
| 6 |  | #include <stdlib.h> | 
| 7 |  | #include <string.h> | 
| 8 |  | #include <capstone/platform.h> | 
| 9 |  |  | 
| 10 |  | #include "../../cs_priv.h" | 
| 11 |  | #include "../../MCInst.h" | 
| 12 |  | #include "../../SStream.h" | 
| 13 |  | #include "../../MCRegisterInfo.h" | 
| 14 |  | #include "../../Mapping.h" | 
| 15 |  | #include "../../MCInstPrinter.h" | 
| 16 |  | #include "../../utils.h" | 
| 17 |  | #include "M680XInstPrinter.h" | 
| 18 |  | #include "M680XDisassembler.h" | 
| 19 |  | #include "M680XDisassemblerInternals.h" | 
| 20 |  |  | 
| 21 |  | #ifndef CAPSTONE_DIET | 
| 22 |  | static const char s_reg_names[][10] = { | 
| 23 |  |   "<invalid>", "a", "b", "e", "f", "0", "d", "w", "cc", "dp", "md", | 
| 24 |  |   "hx", "h", "x", "y", "s", "u", "v", "q", "pc", "tmp2", "tmp3", | 
| 25 |  | }; | 
| 26 |  |  | 
| 27 |  | static const char s_instruction_names[][6] = { | 
| 28 |  |   "invld", "aba", "abx", "aby", "adc", "adca", "adcb", "adcd", "adcr", | 
| 29 |  |   "add", "adda", "addb", "addd", "adde", "addf", "addr", "addw", | 
| 30 |  |   "aim", "ais", "aix", "and", "anda", "andb", "andcc", "andd", "andr", | 
| 31 |  |   "asl", "asla", "aslb", "asld", | 
| 32 |  |   "asr", "asra", "asrb", "asrd", "asrx", | 
| 33 |  |   "band", | 
| 34 |  |   "bcc", "bclr", "bcs", "beor", "beq", "bge", "bgnd", "bgt", "bhcc", | 
| 35 |  |   "bhcs", "bhi", | 
| 36 |  |   "biand", "bieor", "bih", "bil", | 
| 37 |  |   "bior", "bit", "bita", "bitb", "bitd", "bitmd", "ble", "bls", "blt", | 
| 38 |  |   "bmc", | 
| 39 |  |   "bmi", "bms", | 
| 40 |  |   "bne", "bor", "bpl", "brclr", "brset", "bra", "brn", "bset", "bsr", | 
| 41 |  |   "bvc", "bvs", | 
| 42 |  |   "call", "cba", "cbeq", "cbeqa", "cbeqx", "clc", "cli", | 
| 43 |  |   "clr", "clra", "clrb", "clrd", "clre", "clrf", "clrh", "clrw", "clrx", | 
| 44 |  |   "clv", "cmp", | 
| 45 |  |   "cmpa", "cmpb", "cmpd", "cmpe", "cmpf", "cmpr", "cmps", "cmpu", "cmpw", | 
| 46 |  |   "cmpx", "cmpy", | 
| 47 |  |   "com", "coma", "comb", "comd", "come", "comf", "comw", "comx", "cpd", | 
| 48 |  |   "cphx", "cps", "cpx", "cpy", | 
| 49 |  |   "cwai", "daa", "dbeq", "dbne", "dbnz", "dbnza", "dbnzx", | 
| 50 |  |   "dec", "deca", "decb", "decd", "dece", "decf", "decw", | 
| 51 |  |   "decx", "des", "dex", "dey", | 
| 52 |  |   "div", "divd", "divq", "ediv", "edivs", "eim", "emacs", "emaxd", | 
| 53 |  |   "emaxm", "emind", "eminm", "emul", "emuls", | 
| 54 |  |   "eor", "eora", "eorb", "eord", "eorr", "etbl", | 
| 55 |  |   "exg", "fdiv", "ibeq", "ibne", "idiv", "idivs", "illgl", | 
| 56 |  |   "inc", "inca", "incb", "incd", "ince", "incf", "incw", "incx", | 
| 57 |  |   "ins", "inx", "iny", | 
| 58 |  |   "jmp", "jsr", | 
| 59 |  |   "lbcc", "lbcs", "lbeq", "lbge", "lbgt", "lbhi", "lble", "lbls", "lblt", | 
| 60 |  |   "lbmi", "lbne", "lbpl", "lbra", "lbrn", "lbsr", "lbvc", "lbvs", | 
| 61 |  |   "lda", "ldaa", "ldab", "ldb", "ldbt", "ldd", "lde", "ldf", "ldhx", | 
| 62 |  |   "ldmd", | 
| 63 |  |   "ldq", "lds", "ldu", "ldw", "ldx", "ldy", | 
| 64 |  |   "leas", "leau", "leax", "leay", | 
| 65 |  |   "lsl", "lsla", "lslb", "lsld", "lslx", | 
| 66 |  |   "lsr", "lsra", "lsrb", "lsrd", "lsrw", "lsrx", | 
| 67 |  |   "maxa", "maxm", "mem", "mina", "minm", "mov", "movb", "movw", "mul", | 
| 68 |  |   "muld", | 
| 69 |  |   "neg", "nega", "negb", "negd", "negx", | 
| 70 |  |   "nop", "nsa", "oim", "ora", "oraa", "orab", "orb", "orcc", "ord", "orr", | 
| 71 |  |   "psha", "pshb", "pshc", "pshd", "pshh", "pshs", "pshsw", "pshu", | 
| 72 |  |   "pshuw", "pshx", "pshy", | 
| 73 |  |   "pula", "pulb", "pulc", "puld", "pulh", "puls", "pulsw", "pulu", | 
| 74 |  |   "puluw", "pulx", "puly", "rev", "revw", | 
| 75 |  |   "rol", "rola", "rolb", "rold", "rolw", "rolx", | 
| 76 |  |   "ror", "rora", "rorb", "rord", "rorw", "rorx", | 
| 77 |  |   "rsp", "rtc", "rti", "rts", "sba", "sbc", "sbca", "sbcb", "sbcd", | 
| 78 |  |   "sbcr", | 
| 79 |  |   "sec", "sei", "sev", "sex", "sexw", "slp", "sta", "staa", "stab", "stb", | 
| 80 |  |   "stbt", "std", "ste", "stf", "stop", "sthx", | 
| 81 |  |   "stq", "sts", "stu", "stw", "stx", "sty", | 
| 82 |  |   "sub", "suba", "subb", "subd", "sube", "subf", "subr", "subw", | 
| 83 |  |   "swi", "swi2", "swi3", | 
| 84 |  |   "sync", "tab", "tap", "tax", "tba", "tbeq", "tbl", "tbne", "test", | 
| 85 |  |   "tfm", "tfr", | 
| 86 |  |   "tim", "tpa", | 
| 87 |  |   "tst", "tsta", "tstb", "tstd", "tste", "tstf", "tstw", "tstx", | 
| 88 |  |   "tsx", "tsy", "txa", "txs", "tys", "wai", "wait", "wav", "wavr", | 
| 89 |  |   "xgdx", "xgdy", | 
| 90 |  | }; | 
| 91 |  |  | 
| 92 |  | static const name_map s_group_names[] = { | 
| 93 |  |   { M680X_GRP_INVALID, "<invalid>" }, | 
| 94 |  |   { M680X_GRP_JUMP,  "jump" }, | 
| 95 |  |   { M680X_GRP_CALL,  "call" }, | 
| 96 |  |   { M680X_GRP_RET, "return" }, | 
| 97 |  |   { M680X_GRP_INT, "interrupt" }, | 
| 98 |  |   { M680X_GRP_IRET,  "interrupt_return" }, | 
| 99 |  |   { M680X_GRP_PRIV,  "privileged" }, | 
| 100 |  |   { M680X_GRP_BRAREL,  "branch_relative" }, | 
| 101 |  | }; | 
| 102 |  | #endif | 
| 103 |  |  | 
| 104 |  | static void printRegName(cs_struct *handle, SStream *OS, unsigned int reg) | 
| 105 | 112k | { | 
| 106 | 112k | #ifndef CAPSTONE_DIET | 
| 107 | 112k |   SStream_concat0(OS, handle->reg_name((csh)handle, reg)); | 
| 108 | 112k | #endif | 
| 109 | 112k | } | 
| 110 |  |  | 
| 111 |  | static void printInstructionName(cs_struct *handle, SStream *OS, | 
| 112 |  |   unsigned int insn) | 
| 113 | 285k | { | 
| 114 | 285k | #ifndef CAPSTONE_DIET | 
| 115 | 285k |   SStream_concat0(OS, handle->insn_name((csh)handle, insn)); | 
| 116 | 285k | #endif | 
| 117 | 285k | } | 
| 118 |  |  | 
| 119 |  | static uint32_t get_unsigned(int32_t value, int byte_size) | 
| 120 | 0 | { | 
| 121 | 0 |   switch (byte_size) { | 
| 122 | 0 |   case 1: | 
| 123 | 0 |     return (uint32_t)(value & 0xff); | 
| 124 |  |  | 
| 125 | 0 |   case 2: | 
| 126 | 0 |     return (uint32_t)(value & 0xffff); | 
| 127 |  |  | 
| 128 | 0 |   default: | 
| 129 | 0 |   case 4: | 
| 130 | 0 |     return (uint32_t)value; | 
| 131 | 0 |   } | 
| 132 | 0 | } | 
| 133 |  |  | 
| 134 |  | static void printIncDec(bool isPost, SStream *O, m680x_info *info, | 
| 135 |  |   cs_m680x_op *op) | 
| 136 | 167k | { | 
| 137 | 167k |   static const char s_inc_dec[][3] = { "--", "-", "", "+", "++" }; | 
| 138 |  |  | 
| 139 | 167k |   if (!op->idx.inc_dec) | 
| 140 | 131k |     return; | 
| 141 |  |  | 
| 142 | 35.4k |   if ((!isPost && !(op->idx.flags & M680X_IDX_POST_INC_DEC)) || | 
| 143 | 35.4k |     (isPost && (op->idx.flags & M680X_IDX_POST_INC_DEC))) { | 
| 144 | 17.7k |     const char *prePostfix = ""; | 
| 145 |  |  | 
| 146 | 17.7k |     if (info->cpu_type == M680X_CPU_TYPE_CPU12) | 
| 147 | 11.7k |       prePostfix = (op->idx.inc_dec < 0) ? "-" : "+"; | 
| 148 | 5.96k |     else if (op->idx.inc_dec >= -2 && (op->idx.inc_dec <= 2)) { | 
| 149 | 5.96k |       prePostfix = (char *)s_inc_dec[op->idx.inc_dec + 2]; | 
| 150 | 5.96k |     } | 
| 151 |  |  | 
| 152 | 17.7k |     SStream_concat0(O, prePostfix); | 
| 153 | 17.7k |   } | 
| 154 | 35.4k | } | 
| 155 |  |  | 
| 156 |  | static void printOperand(MCInst *MI, SStream *O, m680x_info *info, | 
| 157 |  |   cs_m680x_op *op) | 
| 158 | 258k | { | 
| 159 | 258k |   switch (op->type) { | 
| 160 | 22.6k |   case M680X_OP_REGISTER: | 
| 161 | 22.6k |     printRegName(MI->csh, O, op->reg); | 
| 162 | 22.6k |     break; | 
| 163 |  |  | 
| 164 | 10.8k |   case M680X_OP_CONSTANT: | 
| 165 | 10.8k |     SStream_concat(O, "%u", op->const_val); | 
| 166 | 10.8k |     break; | 
| 167 |  |  | 
| 168 | 29.3k |   case M680X_OP_IMMEDIATE: | 
| 169 | 29.3k |     if (MI->csh->imm_unsigned) | 
| 170 | 0 |       SStream_concat(O, "#%u", | 
| 171 | 0 |         get_unsigned(op->imm, op->size)); | 
| 172 | 29.3k |     else | 
| 173 | 29.3k |       SStream_concat(O, "#%d", op->imm); | 
| 174 |  |  | 
| 175 | 29.3k |     break; | 
| 176 |  |  | 
| 177 | 83.7k |   case M680X_OP_INDEXED: | 
| 178 | 83.7k |     if (op->idx.flags & M680X_IDX_INDIRECT) | 
| 179 | 7.53k |       SStream_concat0(O, "["); | 
| 180 |  |  | 
| 181 | 83.7k |     if (op->idx.offset_reg != M680X_REG_INVALID) | 
| 182 | 6.51k |       printRegName(MI->csh, O, op->idx.offset_reg); | 
| 183 | 77.1k |     else if (op->idx.offset_bits > 0) { | 
| 184 | 50.6k |       if (op->idx.base_reg == M680X_REG_PC) | 
| 185 | 6.31k |         SStream_concat(O, "$%04x", op->idx.offset_addr); | 
| 186 | 44.3k |       else | 
| 187 | 44.3k |         SStream_concat(O, "%d", op->idx.offset); | 
| 188 | 50.6k |     } | 
| 189 | 26.5k |     else if (op->idx.inc_dec != 0 && | 
| 190 | 26.5k |       info->cpu_type == M680X_CPU_TYPE_CPU12) | 
| 191 | 11.7k |       SStream_concat(O, "%d", abs(op->idx.inc_dec)); | 
| 192 |  |  | 
| 193 | 83.7k |     if (!(op->idx.flags & M680X_IDX_NO_COMMA)) | 
| 194 | 81.8k |       SStream_concat(O, ", "); | 
| 195 |  |  | 
| 196 | 83.7k |     printIncDec(false, O, info, op); | 
| 197 |  |  | 
| 198 | 83.7k |     printRegName(MI->csh, O, op->idx.base_reg); | 
| 199 |  |  | 
| 200 | 83.7k |     if (op->idx.base_reg == M680X_REG_PC && | 
| 201 | 83.7k |       (op->idx.offset_bits > 0)) | 
| 202 | 6.31k |       SStream_concat(O, "r"); | 
| 203 |  |  | 
| 204 | 83.7k |     printIncDec(true, O, info, op); | 
| 205 |  |  | 
| 206 | 83.7k |     if (op->idx.flags & M680X_IDX_INDIRECT) | 
| 207 | 7.53k |       SStream_concat(O, "]"); | 
| 208 |  |  | 
| 209 | 83.7k |     break; | 
| 210 |  |  | 
| 211 | 26.1k |   case M680X_OP_RELATIVE: | 
| 212 | 26.1k |     SStream_concat(O, "$%04x", op->rel.address); | 
| 213 | 26.1k |     break; | 
| 214 |  |  | 
| 215 | 45.0k |   case M680X_OP_DIRECT: | 
| 216 | 45.0k |     SStream_concat(O, "$%02x", op->direct_addr); | 
| 217 | 45.0k |     break; | 
| 218 |  |  | 
| 219 | 40.5k |   case M680X_OP_EXTENDED: | 
| 220 | 40.5k |     if (op->ext.indirect) | 
| 221 | 284 |       SStream_concat(O, "[$%04x]", op->ext.address); | 
| 222 | 40.2k |     else { | 
| 223 | 40.2k |       if (op->ext.address < 256) { | 
| 224 | 2.18k |         SStream_concat(O, ">$%04x", op->ext.address); | 
| 225 | 2.18k |       } | 
| 226 | 38.0k |       else { | 
| 227 | 38.0k |         SStream_concat(O, "$%04x", op->ext.address); | 
| 228 | 38.0k |       } | 
| 229 | 40.2k |     } | 
| 230 |  |  | 
| 231 | 40.5k |     break; | 
| 232 |  |  | 
| 233 | 0 |   default: | 
| 234 | 0 |     SStream_concat0(O, "<invalid_operand>"); | 
| 235 | 0 |     break; | 
| 236 | 258k |   } | 
| 237 | 258k | } | 
| 238 |  |  | 
| 239 |  | static const char *getDelimiter(m680x_info *info, cs_m680x *m680x) | 
| 240 | 323k | { | 
| 241 | 323k |   bool indexed = false; | 
| 242 | 323k |   int count = 0; | 
| 243 | 323k |   int i; | 
| 244 |  |  | 
| 245 | 323k |   if (info->insn == M680X_INS_TFM) | 
| 246 | 479 |     return ", "; | 
| 247 |  |  | 
| 248 | 322k |   if (m680x->op_count > 1) { | 
| 249 | 461k |     for (i  = 0; i < m680x->op_count; ++i) { | 
| 250 | 314k |       if (m680x->operands[i].type == M680X_OP_INDEXED) | 
| 251 | 59.4k |         indexed = true; | 
| 252 |  |  | 
| 253 | 314k |       if (m680x->operands[i].type != M680X_OP_REGISTER) | 
| 254 | 170k |         count++; | 
| 255 | 314k |     } | 
| 256 | 146k |   } | 
| 257 |  |  | 
| 258 | 322k |   return (indexed && (count >= 1)) ? "; " : ", "; | 
| 259 | 323k | }; | 
| 260 |  |  | 
| 261 |  | void M680X_printInst(MCInst *MI, SStream *O, void *PrinterInfo) | 
| 262 | 323k | { | 
| 263 | 323k |   m680x_info *info = (m680x_info *)PrinterInfo; | 
| 264 | 323k |   cs_m680x *m680x = &info->m680x; | 
| 265 | 323k |   cs_detail *detail = MI->flat_insn->detail; | 
| 266 | 323k |   int suppress_operands = 0; | 
| 267 | 323k |   const char *delimiter = getDelimiter(info, m680x); | 
| 268 | 323k |   int i; | 
| 269 |  |  | 
| 270 | 323k |   if (detail != NULL) | 
| 271 | 323k |     memcpy(&detail->m680x, m680x, sizeof(cs_m680x)); | 
| 272 |  |  | 
| 273 | 323k |   if (info->insn == M680X_INS_INVLD || info->insn == M680X_INS_ILLGL) { | 
| 274 | 38.1k |     if (m680x->op_count) | 
| 275 | 38.1k |       SStream_concat(O, "fcb $%02x", m680x->operands[0].imm); | 
| 276 | 0 |     else | 
| 277 | 0 |       SStream_concat0(O, "fcb $<unknown>"); | 
| 278 |  |  | 
| 279 | 38.1k |     return; | 
| 280 | 38.1k |   } | 
| 281 |  |  | 
| 282 | 285k |   printInstructionName(MI->csh, O, info->insn); | 
| 283 | 285k |   SStream_concat0(O, " "); | 
| 284 |  |  | 
| 285 | 285k |   if ((m680x->flags & M680X_FIRST_OP_IN_MNEM) != 0) | 
| 286 | 146k |     suppress_operands++; | 
| 287 |  |  | 
| 288 | 285k |   if ((m680x->flags & M680X_SECOND_OP_IN_MNEM) != 0) | 
| 289 | 5.10k |     suppress_operands++; | 
| 290 |  |  | 
| 291 | 694k |   for (i  = 0; i < m680x->op_count; ++i) { | 
| 292 | 409k |     if (i >= suppress_operands) { | 
| 293 | 258k |       printOperand(MI, O, info, &m680x->operands[i]); | 
| 294 |  |  | 
| 295 | 258k |       if ((i + 1) != m680x->op_count) | 
| 296 | 51.7k |         SStream_concat0(O, delimiter); | 
| 297 | 258k |     } | 
| 298 | 409k |   } | 
| 299 | 285k | } | 
| 300 |  |  | 
| 301 |  | const char *M680X_reg_name(csh handle, unsigned int reg) | 
| 302 | 971k | { | 
| 303 | 971k | #ifndef CAPSTONE_DIET | 
| 304 |  |  | 
| 305 | 971k |   if (reg >= ARR_SIZE(s_reg_names)) | 
| 306 | 0 |     return NULL; | 
| 307 |  |  | 
| 308 | 971k |   return s_reg_names[(int)reg]; | 
| 309 |  | #else | 
| 310 |  |   return NULL; | 
| 311 |  | #endif | 
| 312 | 971k | } | 
| 313 |  |  | 
| 314 |  | const char *M680X_insn_name(csh handle, unsigned int id) | 
| 315 | 608k | { | 
| 316 | 608k | #ifndef CAPSTONE_DIET | 
| 317 |  |  | 
| 318 | 608k |   if (id >= ARR_SIZE(s_instruction_names)) | 
| 319 | 0 |     return NULL; | 
| 320 | 608k |   else | 
| 321 | 608k |     return s_instruction_names[(int)id]; | 
| 322 |  |  | 
| 323 |  | #else | 
| 324 |  |   return NULL; | 
| 325 |  | #endif | 
| 326 | 608k | } | 
| 327 |  |  | 
| 328 |  | const char *M680X_group_name(csh handle, unsigned int id) | 
| 329 | 71.8k | { | 
| 330 | 71.8k | #ifndef CAPSTONE_DIET | 
| 331 | 71.8k |   return id2name(s_group_names, ARR_SIZE(s_group_names), id); | 
| 332 |  | #else | 
| 333 |  |   return NULL; | 
| 334 |  | #endif | 
| 335 | 71.8k | } | 
| 336 |  |  | 
| 337 |  | cs_err M680X_instprinter_init(cs_struct *ud) | 
| 338 | 2.88k | { | 
| 339 | 2.88k | #ifndef CAPSTONE_DIET | 
| 340 |  |  | 
| 341 | 2.88k |   if (M680X_REG_ENDING != ARR_SIZE(s_reg_names)) { | 
| 342 | 0 |     CS_ASSERT(M680X_REG_ENDING == ARR_SIZE(s_reg_names)); | 
| 343 | 0 |     return CS_ERR_MODE; | 
| 344 | 0 |   } | 
| 345 |  |  | 
| 346 | 2.88k |   if (M680X_INS_ENDING != ARR_SIZE(s_instruction_names)) { | 
| 347 | 0 |     CS_ASSERT(M680X_INS_ENDING == ARR_SIZE(s_instruction_names)); | 
| 348 | 0 |     return CS_ERR_MODE; | 
| 349 | 0 |   } | 
| 350 |  |  | 
| 351 | 2.88k |   if (M680X_GRP_ENDING != ARR_SIZE(s_group_names)) { | 
| 352 | 0 |     CS_ASSERT(M680X_GRP_ENDING == ARR_SIZE(s_group_names)); | 
| 353 | 0 |     return CS_ERR_MODE; | 
| 354 | 0 |   } | 
| 355 |  |  | 
| 356 | 2.88k | #endif | 
| 357 |  |  | 
| 358 | 2.88k |   return CS_ERR_OK; | 
| 359 | 2.88k | } | 
| 360 |  |  | 
| 361 |  | #endif | 
| 362 |  |  |