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