R_API bool r_strbuf_setf(RStrBuf *sb, const char *fmt, ...) { int rc; bool ret; char string[1024]; va_list ap; if (!sb || !fmt) return false; va_start (ap, fmt); rc = vsnprintf (string, sizeof (string), fmt, ap); if (rc >= sizeof (string)) { char *p = malloc (rc + 2); if (!p) { va_end (ap); return false; } vsnprintf (p, rc + 1, fmt, ap); ret = r_strbuf_set (sb, p); free (p); } else { ret = r_strbuf_set (sb, string); } va_end (ap); return ret; }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { static struct disassemble_info disasm_obj; if (len < 2) { return -1; } buf_global = r_strbuf_get (&op->buf_asm); Offset = a->pc; if (len > sizeof (bytes)) { len = sizeof (bytes); } memcpy (bytes, buf, len); // TODO handle compact buf_len = len; /* prepare disassembler */ memset (&disasm_obj,'\0', sizeof (struct disassemble_info)); disasm_obj.buffer = bytes; disasm_obj.buffer_length = len; disasm_obj.read_memory_func = &arc_buffer_read_memory; disasm_obj.symbol_at_address_func = &symbol_at_address; disasm_obj.memory_error_func = &memory_error_func; disasm_obj.print_address_func = &print_address; disasm_obj.endian = !a->big_endian; disasm_obj.fprintf_func = &buf_fprintf; disasm_obj.stream = stdout; disasm_obj.mach = 0; r_strbuf_set (&op->buf_asm, ""); if (a->bits == 16) { op->size = ARCompact_decodeInstr ((bfd_vma)Offset, &disasm_obj); } else { op->size = ARCTangent_decodeInstr ((bfd_vma)Offset, &disasm_obj); } if (op->size == -1) { r_strbuf_set (&op->buf_asm, "(data)"); } return op->size; }
static int bf_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { ut64 dst = 0LL; if (op == NULL) return 1; /* Ayeeee! What's inside op? Do we have an initialized RAnalOp? Are we going to have a leak here? :-( */ memset (op, 0, sizeof (RAnalOp)); /* We need to refactorize this. Something like r_anal_op_init would be more appropiate */ r_strbuf_init (&op->esil); op->size = 1; switch (buf[0]) { case '[': op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr+1; { const ut8 *p = buf + 1; int lev = 0, i = 1; while (*p && i<len) { if (*p == '[') lev++; if (*p == ']') { lev--; if (lev==-1) { dst = addr + (size_t)(p-buf); op->jump = dst; r_strbuf_setf (&op->esil, "if (!*ptr) pc=0x%"PFMT64x, dst); break; } } p++; i++; } } // ?1[ptr],pc=${NEW_PC break; case ']': op->type = R_ANAL_OP_TYPE_UJMP; break; case '>': op->type = R_ANAL_OP_TYPE_ADD; r_strbuf_set (&op->esil, "ptr++"); break; case '<': op->type = R_ANAL_OP_TYPE_SUB; r_strbuf_set (&op->esil, "ptr--"); break; case '+': op->type = R_ANAL_OP_TYPE_ADD; r_strbuf_set (&op->esil, "*ptr++"); break; case '-': op->type = R_ANAL_OP_TYPE_SUB; r_strbuf_set (&op->esil, "*ptr--"); break; case '.': op->type = R_ANAL_OP_TYPE_STORE; r_strbuf_set (&op->esil, "=*ptr"); break; case ',': op->type = R_ANAL_OP_TYPE_LOAD; break; case 0x00: case 0xff: op->type = R_ANAL_OP_TYPE_TRAP; break; default: op->type = R_ANAL_OP_TYPE_NOP; break; } return op->size; }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { struct disassemble_info disasm_obj; if (len < 4) { return -1; } buf_global = &op->buf_asm; Offset = a->pc; memcpy (bytes, buf, 4); // TODO handle thumb /* prepare disassembler */ memset (&disasm_obj, '\0', sizeof (struct disassemble_info)); disasm_obj.disassembler_options = (a->bits==64)? "64": ""; disasm_obj.buffer = bytes; disasm_obj.read_memory_func = &lanai_buffer_read_memory; disasm_obj.symbol_at_address_func = &symbol_at_address; disasm_obj.memory_error_func = &memory_error_func; disasm_obj.print_address_func = &generic_print_address_func; disasm_obj.endian = BFD_ENDIAN_BIG; disasm_obj.fprintf_func = &generic_fprintf_func; disasm_obj.stream = stdout; op->size = print_insn_lanai ((bfd_vma)Offset, &disasm_obj); if (op->size == -1) { r_strbuf_set (&op->buf_asm, "(data)"); } return op->size; }
static int disassemble(struct r_asm_t *a, struct r_asm_op_t *op, const ut8 *buf, int len) { static struct disassemble_info disasm_obj; if (len < 4) { return -1; } buf_global = r_strbuf_get (&op->buf_asm); Offset = a->pc; memcpy (bytes, buf, 4); // TODO handle thumb /* prepare disassembler */ memset (&disasm_obj,'\0', sizeof (struct disassemble_info)); mips_mode = a->bits; disasm_obj.arch = CPU_LOONGSON_2F; disasm_obj.buffer = bytes; disasm_obj.read_memory_func = &mips_buffer_read_memory; disasm_obj.symbol_at_address_func = &symbol_at_address; disasm_obj.memory_error_func = &memory_error_func; disasm_obj.print_address_func = &print_address; disasm_obj.buffer_vma = Offset; disasm_obj.buffer_length = 4; disasm_obj.endian = !a->big_endian; disasm_obj.fprintf_func = &buf_fprintf; disasm_obj.stream = stdout; op->size = (disasm_obj.endian == BFD_ENDIAN_LITTLE) ? print_insn_little_mips ((bfd_vma)Offset, &disasm_obj) : print_insn_big_mips ((bfd_vma)Offset, &disasm_obj); if (op->size == -1) { r_strbuf_set (&op->buf_asm, "(data)"); } return op->size; }
/* apply hint to op, return the number of hints applied */ R_API int r_anal_op_hint(RAnalOp *op, RAnalHint *hint) { int changes = 0; if (hint) { if (hint->jump != UT64_MAX) { changes++; op->jump = hint->jump; } if (hint->fail != UT64_MAX) { changes++; op->fail = hint->fail; } if (hint->opcode) { changes++; /* XXX: this is not correct */ free (op->mnemonic); op->mnemonic = strdup (hint->opcode); } if (hint->esil) { changes++; r_strbuf_set (&op->esil, hint->esil); } if (hint->size) { changes++; op->size = hint->size; } } return changes; }
R_API int r_strbuf_setf(RStrBuf *sb, const char *fmt, ...) { int ret; char string[4096]; va_list ap; va_start (ap, fmt); ret = vsnprintf (string, sizeof (string), fmt, ap); if (ret>=sizeof (string)) { char *p = malloc (ret+2); if (!p) return R_FALSE; vsnprintf (p, ret+1, fmt, ap); ret = r_strbuf_set (sb, p); free (p); } else ret = r_strbuf_set (sb, string); va_end (ap); return ret; }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { if (len > 1 && !memcmp (buf, "\xff\xff", 2)) { return -1; } r_strbuf_set (&op->buf_asm, mcs96_op[buf[0]].ins); op->size = mcs96_len (buf[0]); return op->size; }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { RAsmLm32Instruction instr = {0}; instr.value = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; instr.addr = a->pc; if (r_asm_lm32_decode (&instr)) { r_strbuf_set (&op->buf_asm, "invalid"); a->invhex = 1; return -1; } //op->buf_asm is 256 chars long, which is more than sufficient if (r_asm_lm32_stringify (&instr, r_strbuf_get (&op->buf_asm))) { r_strbuf_set (&op->buf_asm, "invalid"); a->invhex = 1; return -1; } return 4; }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { char buf_asm[32]; if (len < 2) { return -1; // at least 2 bytes! } op->size = dcpu16_disasm (buf_asm, (const ut16*)buf, len, NULL); r_strbuf_set (&op->buf_asm, (op->size > 0) ? buf_asm: "(data)"); return op->size; }
static int disassemble(RAsm *as, RAsmOp *op, const ut8 *buf, int len) { struct lh5801_insn insn; if (!op) { return 0; } int consumed = lh5801_decode (&insn, buf, len); if (consumed == -1 || consumed == 0) { r_strbuf_set (&op->buf_asm, "invalid"); op->size = 1; return 0; } char buf_asm[128] = {0}; lh5801_print_insn (buf_asm, sizeof (buf_asm), &insn); r_strbuf_set (&op->buf_asm, buf_asm); op->size = consumed; //op->payload = lh5801_insn_descs[insn.type].format & 3; // ^ MAYBE? return op->size; }
static int py_anal(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) { PyObject *tmpreg = NULL; int size = 0; int seize = -1; int i = 0; if (!op) return -1; if (py_anal_cb) { memset(op, 0, sizeof (RAnalOp)); // anal(addr, buf) - returns size + dictionary (structure) for RAnalOp Py_buffer pybuf = { .buf = (void *) buf, // Warning: const is lost when casting .len = len, .readonly = 1, .ndim = 1, .itemsize = 1, }; PyObject *memview = PyMemoryView_FromBuffer (&pybuf); PyObject *arglist = Py_BuildValue ("(NK)", memview, addr); PyObject *result = PyEval_CallObject (py_anal_cb, arglist); if (result && PyList_Check (result)) { PyObject *len = PyList_GetItem (result, 0); PyObject *dict = PyList_GetItem (result, 1); if (dict && PyDict_Check (dict)) { seize = PyNumber_AsSsize_t (len, NULL); op->type = getI (dict, "type"); op->cycles = getI (dict, "cycles"); op->size = seize; op->addr = getI (dict, "addr"); op->jump = getI (dict, "jump"); op->fail = getI (dict, "fail"); op->stackop = getI (dict, "stackop"); op->stackptr = getI (dict, "stackptr"); op->ptr = getI (dict, "ptr"); op->eob = getB (dict, "eob"); // Loading 'src' and 'dst' values // SRC is is a list of 3 elements PyObject *tmpsrc = getO (dict, "src"); if (tmpsrc && PyList_Check (tmpsrc)) { for (i = 0; i < 3; i++) { PyObject *tmplst = PyList_GetItem (tmpsrc, i); // Read value and underlying regs READ_VAL(tmplst, op->src[i], tmpreg) } } PyObject *tmpdst = getO (dict, "dst"); // Read value and underlying regs READ_VAL(tmpdst, op->dst, tmpreg) // Loading 'var' value if presented r_strbuf_set (&op->esil, getS (dict, "esil")); // TODO: Add opex support here Py_DECREF (dict); } Py_DECREF (result); } else {
R_API RAnalOp *r_anal_op_copy (RAnalOp *op) { RAnalOp *nop = R_NEW (RAnalOp); *nop = *op; nop->mnemonic = strdup (op->mnemonic); nop->src[0] = r_anal_value_copy (op->src[0]); nop->src[1] = r_anal_value_copy (op->src[1]); nop->src[2] = r_anal_value_copy (op->src[2]); nop->dst = r_anal_value_copy (op->dst); r_strbuf_init (&nop->esil); r_strbuf_set (&nop->esil, r_strbuf_get (&op->esil)); return nop; }
R_API int r_asm_op_set_hex(RAsmOp *op, const char *str) { r_strbuf_set (&op->buf_hex, str); ut8 *bin = (ut8*)strdup (str); if (bin) { int len = r_hex_str2bin (str, bin); if (len > 0) { r_strbuf_setbin (&op->buf, bin, len); } free (bin); return len; } return 0; }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { struct disassemble_info disasm_obj; int mode = 2; if (len < 4) { return -1; } buf_global = &op->buf_asm; Offset = a->pc; memcpy (bytes, buf, R_MIN (len, 8)); // TODO handle thumb /* prepare disassembler */ memset (&disasm_obj, '\0', sizeof (struct disassemble_info)); disasm_obj.disassembler_options=(a->bits==64)?"64":""; disasm_obj.buffer = bytes; disasm_obj.read_memory_func = &cris_buffer_read_memory; disasm_obj.symbol_at_address_func = &symbol_at_address; disasm_obj.memory_error_func = &memory_error_func; disasm_obj.print_address_func = &generic_print_address_func; disasm_obj.endian = !a->big_endian; disasm_obj.fprintf_func = &generic_fprintf_func; disasm_obj.stream = stdout; if (a->cpu && *a->cpu) { if (!strcmp (a->cpu, "v10+v32")) { mode = 1; } else if (!strcmp (a->cpu, "v10")) { mode = 0; } else { mode = 2; } } else { mode = 2; } (void)cris_parse_disassembler_options (&disasm_obj, mode); if (a->syntax == R_ASM_SYNTAX_ATT) { op->size = print_insn_crisv10_v32_with_register_prefix ( (bfd_vma)Offset, &disasm_obj); } else { op->size = print_insn_crisv10_v32_without_register_prefix ( (bfd_vma)Offset, &disasm_obj); } if (op->size == -1) { r_strbuf_set (&op->buf_asm, "(data)"); } return op->size; }
R_API RAnalOp *r_anal_op_copy (RAnalOp *op) { RAnalOp *nop = R_NEW0 (RAnalOp); if (!nop) return NULL; *nop = *op; if (op->mnemonic) { nop->mnemonic = strdup (op->mnemonic); if (!nop->mnemonic) { free (nop); return NULL; } } else { nop->mnemonic = NULL; } nop->src[0] = r_anal_value_copy (op->src[0]); nop->src[1] = r_anal_value_copy (op->src[1]); nop->src[2] = r_anal_value_copy (op->src[2]); nop->dst = r_anal_value_copy (op->dst); r_strbuf_init (&nop->esil); r_strbuf_set (&nop->esil, r_strbuf_get (&op->esil)); return nop; }
static void analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf) { r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); switch (buf[0]) { // Irregulars sorted by lower nibble case 0x00: /* nop */ emit (","); break; case 0x10: /* jbc bit, offset */ k (BIT_R "?{," BIT_MASK XI(BIT, "&") JMP ",}"); break; case 0x20: /* jb bit, offset */ k (BIT_R CJMP); break; case 0x30: /* jnb bit, offset */ k (BIT_R "!," CJMP); break; case 0x40: /* jc offset */ h ("c,1,&," CJMP); break; case 0x50: /* jnc offset */ h ("c,1,&,!," CJMP ); break; case 0x60: /* jz offset */ h ("a,0,==," CJMP); break; case 0x70: /* jnz offset */ h ("a,0,==,!," CJMP); break; case 0x11: case 0x31: case 0x51: case 0x71: case 0x91: case 0xB1: case 0xD1: case 0xF1: /* acall addr11 */ case 0x12: /* lcall addr16 */ j (CALL); /* fall through */ case 0x01: case 0x21: case 0x41: case 0x61: case 0x81: case 0xA1: case 0xC1: case 0xE1: /* ajmp addr11 */ case 0x02: /* ljmp addr16 */ case 0x80: /* sjmp offset */ j (JMP); break; case 0x22: /* ret */ case 0x32: /* reti */ emitf (POP2 "pc,="); break; case 0x03: /* rr a */ emit ("1,a,0x101,*,>>,a,=," FLAG_P); break; case 0x04: /* inc a */ h (XI(A, "++") FLAG_P); break; case 0x05: /* inc direct */ h (XI(IB1, "++")); break; case 0x06: case 0x07: /* inc @Ri */ j (XI(RI, "++")); break; case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: /* dec @Rn */ h (XI(RN, "++")); break; case 0x13: /* rrc a */ emit ("7,c,<<,1,a,&,c,=,0x7f,1,a,>>,&,+,a,=," FLAG_P); break; case 0x14: /* dec a */ h (XI(A, "--") FLAG_P); break; case 0x15: /* dec direct */ h (XI(IB1, "--")); break; case 0x16: case 0x17: /* dec @Ri */ j (XI(RI, "--")); break; case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: /* dec @Rn */ h (XI(RN, "--")); break; case 0x23: /* rl a */ h ("7,a,0x101,*,>>,a,=," FLAG_P); break; TEMPLATE_ALU (0x20, "+", FLAG_C FLAG_AC FLAG_OV FLAG_P) /* 0x24..0x2f add a,.. */ case 0x33: /* rlc a */ h ("c,1,&,a,a,+=,$c7,c,=,a,+=," FLAG_P); break; TEMPLATE_ALU_C (0x30, "+", FLAG_C FLAG_AC FLAG_OV FLAG_P) /* 0x34..0x2f addc a,.. */ case 0x42: /* orl direct, a */ h (XR(A) XI(IB1, "|")); break; case 0x43: /* orl direct, imm */ h (XR(L2) XI(IB1, "|")); break; TEMPLATE_ALU (0x40, "|", FLAG_P) /* 0x44..0x4f orl a,.. */ case 0x52: /* anl direct, a */ h (XR(A) XI(IB1, "&")); break; case 0x53: /* anl direct, imm */ h (XR(L2) XI(IB1, "&")); break; TEMPLATE_ALU (0x50, "&", FLAG_P) /* 0x54..0x5f anl a,.. */ case 0x62: /* xrl direct, a */ h (XR(A) XI(IB1, "^")); break; case 0x63: /* xrl direct, imm */ h (XR(L2) XI(IB1, "^")); break; TEMPLATE_ALU (0x60, "^", FLAG_P) /* 0x64..0x6f xrl a,.. */ case 0x72: /* orl C, bit */ k (BIT_R XI(C, "|")); break; case 0x73: /* jmp @a+dptr */ emit ("dptr,a,+,pc,="); break; case 0x74: /* mov a, imm */ h (XR(L1) XW(A) FLAG_P); break; case 0x75: /* mov direct, imm */ h (XR(L2) XW(IB1)); break; case 0x76: case 0x77: /* mov @Ri, imm */ j (XR(L1) XW(RI)); break; case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: /* mov Rn, imm */ h (XR(L1) XW(RN)); break; case 0x82: /* anl C, bit */ k (BIT_R XI(C, "&")); break; case 0x83: /* movc a, @a+pc */ emit ("a,pc,--,+,[1]," XW(A) FLAG_P); break; case 0x84: /* div ab */ emit ("b,!,OV,=,0,a,b,a,/=,a,b,*,-,-,b,=,0,c,="); break; case 0x85: /* mov direct, direct */ h (XR(IB1) XW(IB2)); break; case 0x86: case 0x87: /* mov direct, @Ri */ j (XR(RI) XW(IB1)); break; case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: /* mov direct, Rn */ h (XR(RN) XW(IB1)); break; case 0x90: /* mov dptr, imm */ h (XR(L16) XW(DP)); break; case 0x92: /* mov bit, C */ k (BIT_C BIT_MASK XR(BIT) "&,|," XW(BIT)); break; case 0x93: /* movc a, @a+dptr */ h ("a,dptr,+,[1]," XW(A) FLAG_P); break; TEMPLATE_ALU_C (0x90, "-", FLAG_B FLAG_AB FLAG_OB FLAG_P) /* 0x94..0x9f subb a,.. */ case 0xA0: /* orl C, /bit */ k (BIT_R "!," XI(C, "|")); break; case 0xA2: /* mov C, bit */ k (BIT_R XW(C)); break; case 0xA3: /* inc dptr */ h (XI(DP, "++")); break; case 0xA4: /* mul ab */ emit ("8,a,b,*,NUM,>>,NUM,!,!,ov,=,b,=,a,=,0,c,="); break; case 0xA5: /* "reserved" */ emit ("0,trap"); break; case 0xA6: case 0xA7: /* mov @Ri, direct */ j (XR(IB1) XW(RI)); break; case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: /* mov Rn, direct */ h (XR(IB1) XW(RN)); break; case 0xB0: /* anl C, /bit */ k (BIT_R "!," XI(C, "&")); break; case 0xB2: /* cpl bit */ k (BIT_SET XI(BIT, "^")); break; case 0xB3: /* cpl C */ h ("1," XI(C, "^")); break; case 0xB4: /* cjne a, imm, offset */ h (XR(L1) XR(A) "-," CJMP); break; case 0xB5: /* cjne a, direct, offset */ h (XR(IB1) XR(A) "-," CJMP); break; case 0xB6: case 0xB7: /* cjne @ri, imm, offset */ j (XR(L1) XR(RI) "-," CJMP); break; case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: /* cjne Rn, imm, offset */ h (XR(L1) XR(RN) "-," CJMP); break; case 0xC0: /* push direct */ h (XR(IB1) PUSH1); break; case 0xC2: /* clr bit */ k (BIT_MASK XI(BIT, "&")); break; case 0xC3: /* clr C */ h ("0," XW(C)); break; case 0xC4: /* swap a */ h ("0xff,4,a,0x101,*,>>,&," XW(A) FLAG_P); break; case 0xC5: /* xch a, direct */ h (XR(A) "0,+," XR(IB1) XW(A) XW(IB1) FLAG_P); break; case 0xC6: case 0xC7: /* xch a, @Ri */ j (XR(A) "0,+," XR(RI) XW(A) XW(RI) FLAG_P); break; case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: /* xch a, Rn */ h (XR(A) "0,+," XR(RN) XW(A) XW(RN) FLAG_P); break; case 0xD0: /* pop direct */ h (POP1 XW(IB1)); break; case 0xD2: /* setb bit */ k (BIT_SET XI(BIT, "|")); break; case 0xD3: /* setb C */ h ("1," XW(C)); break; case 0xD4: /* da a */ // BCD adjust after add: // if (lower nibble > 9) or (AC == 1) add 6 // if (higher nibble > 9) or (C == 1) add 0x60 // carry |= carry caused by this operation emit ("a,0x0f,&,9,<,ac,|,?{,6,a,+=,$c7,c,|=,},a,0xf0,&,0x90,<,c,|,?{,0x60,a,+=,$c7,c,|=,}," FLAG_P); break; case 0xD5: /* djnz direct, offset */ h (XI(IB1, "--") XR(IB1) "0,==,!," CJMP); break; case 0xD6: case 0xD7: /* xchd a, @Ri*/ j (XR(A) "0xf0,&," XR(RI) "0x0f,&,|," XR(RI) "0xf0,&," XR(A) "0x0f,&,|," XW(RI) XW(A) FLAG_P); break; case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: /* djnz Rn, offset */ h (XI(RN, "--") XR(RN) "0,==,!," CJMP); break; case 0xE0: /* movx a, @dptr */ h (XR(DPX) XW(A) FLAG_P); break; case 0xE2: case 0xE3: /* movx a, @Ri */ j (XR(R0X) XW(A) FLAG_P); break; case 0xE4: /* clr a */ emit ("0," XW(A) FLAG_P); break; case 0xE5: /* mov a, direct */ h (XR(IB1) XW(A) FLAG_P); break; case 0xE6: case 0xE7: /* mov a, @Ri */ j (XR(RI) XW(A) FLAG_P); break; case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: case 0xEF: /* mov a, Rn */ h (XR(RN) XW(A) FLAG_P); break; case 0xF0: /* movx @dptr, a */ h (XR(A) XW(DPX)); break; case 0xF2: case 0xF3: /* movx @Ri, a */ j (XR(A) XW(R0X)); break; case 0xF4: /* cpl a */ h ("255," XI(A, "^") FLAG_P); break; case 0xF5: /* mov direct, a */ h (XR(A) XW(IB1)); break; case 0xF6: case 0xF7: /* mov @Ri, a */ j (XR(A) XW(RI)); break; case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: /* mov Rn, a */ h (XR(A) XW(RN)); break; default: break; } }
static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) { int i; char str[32][32]; r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); switch (insn->detail->arm.cc) { case ARM_CC_AL: // no condition break; case ARM_CC_EQ: r_strbuf_setf (&op->esil, "zf,0,?,"); break; case ARM_CC_NE: r_strbuf_setf (&op->esil, "zf,!,0,?,"); break; case ARM_CC_GT: case ARM_CC_LE: break; default: break; } // TODO: PREFIX CONDITIONAL switch (insn->id) { case ARM_INS_PUSH: // TODO: increment stack case ARM_INS_STM: for (i=1; i<insn->detail->arm.op_count; i++) { r_strbuf_appendf (&op->esil, "%s,%s,%d,+,=[4],", REG (i), ARG (0), i*4); } break; case ARM_INS_POP: // TODO: decrement stack case ARM_INS_LDM: for (i=1; i<insn->detail->arm.op_count; i++) { r_strbuf_appendf (&op->esil, "%s,%d,+,[4],%s,=", ARG (0), i*4, REG (i)); } break; case ARM_INS_CMP: r_strbuf_appendf (&op->esil, "%s,%s,==", ARG(1), ARG(0)); break; case ARM_INS_LSL: // suffix 'S' forces conditional flag to be updated r_strbuf_appendf (&op->esil, "%s,%s,<<=", ARG(1), ARG(0)); break; case ARM_INS_LSR: // suffix 'S' forces conditional flag to be updated r_strbuf_appendf (&op->esil, "%s,%s,>>=", ARG(1), ARG(0)); break; case ARM_INS_B: r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0)); break; case ARM_INS_BL: case ARM_INS_BLX: r_strbuf_appendf (&op->esil, "4,pc,+,lr,=,%s,pc,=", ARG(0)); break; case ARM_INS_MOV: case ARM_INS_MOVS: r_strbuf_appendf (&op->esil, "%s,%s,=", ARG(1), REG(0)); break; case ARM_INS_SSUB16: case ARM_INS_SSUB8: case ARM_INS_SUB: r_strbuf_appendf (&op->esil, "%s,%s,-=", ARG(1), ARG(0)); break; case ARM_INS_SADD16: case ARM_INS_SADD8: case ARM_INS_ADD: if (!strcmp (ARG(0),ARG(1))) { r_strbuf_appendf (&op->esil, "%s,%s,+=", ARG(2), ARG(0)); } else if (!strcmp (ARG(2),"0")) { r_strbuf_appendf (&op->esil, "%s,%s,=", ARG(1), ARG(0)); } else { r_strbuf_appendf (&op->esil, "%s,%s,+,%s,=", ARG(2), ARG(1), ARG(0)); } break; case ARM_INS_STR: r_strbuf_appendf (&op->esil, "%s,%s,%d,+,=[4]", REG(0), MEMBASE(1), MEMDISP(1)); break; case ARM_INS_STRB: r_strbuf_appendf (&op->esil, "%s,%s,%d,+,=[1]", REG(0), MEMBASE(1), MEMDISP(1)); break; case ARM_INS_LDR: if (MEMDISP(1)<0) { if (REGBASE(1) == ARM_REG_PC) { r_strbuf_appendf (&op->esil, "8,%s,+,%d,-,[4],%s,=", MEMBASE(1), -MEMDISP(1), REG(0)); switch (a->bits) { case 32: op->ptr = addr + 8 - MEMDISP(1); op->refptr = 4; break; case 16: if ( (addr % 4) == 0 ) { op->ptr = addr + 4 - MEMDISP(1); op->refptr = 4; } else { op->ptr = addr + 2 - MEMDISP(1); op->refptr = 4; } break; } } else { r_strbuf_appendf (&op->esil, "%s,%d,-,[4],%s,=", MEMBASE(1), -MEMDISP(1), REG(0)); } } else { if (REGBASE(1) == ARM_REG_PC) { r_strbuf_appendf (&op->esil, "8,%s,+,%d,+,[4],%s,=", MEMBASE(1), MEMDISP(1), REG(0)); if (a->bits==32) { op->ptr = addr + 8 + MEMDISP(1); op->refptr = 4; } else if (a->bits==16) { if ( (addr % 4) == 0 ) { op->ptr = addr + 4 + MEMDISP(1); op->refptr = 4; } else { op->ptr = addr + 2 + MEMDISP(1); op->refptr = 4; } } } else { r_strbuf_appendf (&op->esil, "%s,%d,+,[4],%s,=", MEMBASE(1), MEMDISP(1), REG(0)); } op->refptr = 4; } break; case ARM_INS_LDRD: case ARM_INS_LDRB: r_strbuf_appendf (&op->esil, "%s,%d,+,[1],%s,=", MEMBASE(1), MEMDISP(1), REG(0)); break; default: break; } return 0; }
R_API void r_asm_op_set_asm(RAsmOp *op, const char *str) { r_return_if_fail (op && str); r_strbuf_set (&op->buf_asm, str); }
static int bf_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { ut64 dst = 0LL; if (op == NULL) return 1; /* Ayeeee! What's inside op? Do we have an initialized RAnalOp? Are we going to have a leak here? :-( */ memset (op, 0, sizeof (RAnalOp)); /* We need to refactorize this. Something like r_anal_op_init would be more appropiate */ r_strbuf_init (&op->esil); op->size = 1; switch (buf[0]) { case '[': op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr+1; { const ut8 *p = buf + 1; int lev = 0, i = 1; while (*p && i<len) { if (*p == '[') lev++; if (*p == ']') { lev--; if (lev==-1) { dst = addr + (size_t)(p-buf); dst ++; op->jump = dst; r_strbuf_setf (&op->esil, "pc,brk,=[1],brk,++=," "ptr,[1],!,?{,0x%"PFMT64x",pc,=,}", dst); break; } } p++; i++; } } // ?1[ptr],pc=${NEW_PC break; case ']': op->type = R_ANAL_OP_TYPE_UJMP; // XXX This is wrong esil r_strbuf_set (&op->esil, "brk,--=,brk,[1],pc,="); break; case '>': op->type = R_ANAL_OP_TYPE_ADD; r_strbuf_set (&op->esil, "ptr,++="); break; case '<': op->type = R_ANAL_OP_TYPE_SUB; r_strbuf_set (&op->esil, "ptr,--="); break; case '+': op->size = countChar (buf, len, '+'); op->type = R_ANAL_OP_TYPE_ADD; r_strbuf_setf (&op->esil, "ptr,[1],%d,+,ptr,=[1]", op->size); break; case '-': op->type = R_ANAL_OP_TYPE_SUB; op->size = countChar (buf, len, '-'); r_strbuf_setf (&op->esil, "ptr,[1],%d,-,ptr,=[1]", op->size); break; case '.': // print element in stack to screen op->type = R_ANAL_OP_TYPE_STORE; r_strbuf_set (&op->esil, "ptr,[1],scr,=[1],scr,++="); break; case ',': op->type = R_ANAL_OP_TYPE_LOAD; r_strbuf_set (&op->esil, "kbd,[1],ptr,=[1],kbd,++="); break; case 0x00: case 0xff: op->type = R_ANAL_OP_TYPE_TRAP; break; default: op->type = R_ANAL_OP_TYPE_NOP; r_strbuf_set (&op->esil, ","); break; } return op->size; }
R_API RStrBuf *r_strbuf_new(const char *str) { RStrBuf *s = R_NEW0 (RStrBuf); if (str) r_strbuf_set (s, str); return s; }
static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf) { int ret = -1; ut8 opcode = buf[0]; if (!op) { return 2; } r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); switch (opcode >> 4) { case H8300_CMP_4BIT: //acc. to manual this is how it's done, could use == in esil r_strbuf_appendf(&op->esil, "0x%02x,r%u%c,-", imm, rdB(0)); //setZ setV("%o"); setN; setHb_B; setCb_B; maskB(0); setZ; return 0; case H8300_OR_4BIT: r_strbuf_appendf(&op->esil, "0x%02x,r%u%c,|=", imm, rdB(0)); //setZ setV("0"); setN; maskB(0); setZ; return 0; case H8300_XOR_4BIT: r_strbuf_appendf(&op->esil, "0x%02x,r%u%c,^=", imm, rdB(0)); //setZ setN; setV("0"); maskB(0); setZ; return 0; case H8300_AND_4BIT: r_strbuf_appendf(&op->esil, "0x%02x,r%u%c,&=", imm, rdB(0)); //setZ setN; setV("0"); maskB(0); setZ; return 0; case H8300_ADD_4BIT: r_strbuf_appendf(&op->esil, "0x%02x,r%u%c,+=", imm, rdB(0)); //setZ setV("%o"); setN; setH_B; setC_B; maskB(0); setZ; return 0; case H8300_ADDX_4BIT: r_strbuf_appendf(&op->esil, "0x%02x,C,+,r%u%c,+= ", imm, rdB(0), rdB(0)); //setZ setV("%o"); setN; setH_B; setC_B; maskB(0); setZ; return 0; case H8300_SUBX_4BIT: //Rd – imm – C → Rd r_strbuf_appendf(&op->esil, "0x%02x,r%u%c,-=,C,r%u%c,-=", imm, rdB(0), rdB(0)); //setZ setV("%o"); setN; setHb_B; setCb_B; maskB(0); setZ; return 0; case H8300_MOV_4BIT_2: /*TODO*/ case H8300_MOV_4BIT_3: /*TODO*/ case H8300_MOV_4BIT: /*TODO*/ return 0; default: break; }; switch (opcode) { case H8300_NOP: r_strbuf_set (&op->esil, ","); return 0; case H8300_SLEEP: /* TODO */ return 0; case H8300_STC: r_strbuf_appendf(&op->esil, "ccr,r%u%c,=", rdB(1)); return 0; case H8300_LDC: r_strbuf_appendf(&op->esil, "r%u%c,ccr,=", rdB(1)); return 0; case H8300_ORC: r_strbuf_appendf(&op->esil, "0x%02x,ccr,|=", imm); return 0; case H8300_XORC: r_strbuf_appendf(&op->esil, "0x%02x,ccr,^=", imm); return 0; case H8300_ANDC: r_strbuf_appendf(&op->esil, "0x%02x,ccr,&=", imm); return 0; case H8300_LDC_2: r_strbuf_appendf(&op->esil, "0x%02x,ccr,=", imm); return 0; case H8300_ADDB_DIRECT: r_strbuf_appendf(&op->esil, "r%u%c,r%u%c,+=", rsB(), rdB(1)); setH_B; setV("%o"); setC_B ; setN; //setZ; maskB(1); setZ; return 0; case H8300_ADDW_DIRECT: r_strbuf_appendf (&op->esil, "r%u,r%u,+=", rs(), rd()); setH_W; setV("%o"); setC_W; setN; mask(); setZ; return 0; case H8300_INC: r_strbuf_appendf(&op->esil, "1,r%u%c,+=", rdB(1)); //setZ setV("%o") ; setN; maskB(1); setZ; return 0; case H8300_ADDS: r_strbuf_appendf (&op->esil, "%d,r%u,+=", ((buf[1] & 0xf0) == 0x80) ? 2 : 1, rd()); return 0; case H8300_MOV_1: /*TODO check if flags are set internally or not*/ r_strbuf_appendf (&op->esil, "r%u%c,r%u%c,=", rsB(), rdB(1)); //setZ setN; maskB(1); setZ; return 0; case H8300_MOV_2: r_strbuf_appendf(&op->esil, "r%u,r%u,=", rs(), rd()); //setZ setN; mask(); setZ; return 0; case H8300_ADDX: //Rd + (Rs) + C → Rd r_strbuf_appendf (&op->esil, "r%u%c,C,+,r%u%c,+=", rsB(), rdB(1), rdB(1)); //setZ setV("%o"); setN; setH_B ; setC_B; maskB(1); setZ; return 0; case H8300_DAA: /*TODO*/ return 0; case H8300_SHL: /*TODO*/ return 0; case H8300_SHR: /*TODO*/ return 0; case H8300_ROTL: /*TODO*/ return 0; case H8300_ROTR: /*TODO*/ return 0; case H8300_OR: r_strbuf_appendf(&op->esil, "r%u%c,r%u%c,|=", rsB(), rdB(1)); //setZ setV("0"); setN; maskB(1); setZ; return 0; case H8300_XOR: r_strbuf_appendf(&op->esil, "r%u%c,r%u%c,^=", rsB(), rdB(1)); //setZ setV("0") ; setN; maskB(1); setZ; return 0; case H8300_AND: r_strbuf_appendf(&op->esil, "r%u%c,r%u%c,&=", rsB(), rdB(1)); //setZ setV("0"); setN; maskB(1); setZ; return 0; case H8300_NOT_NEG: if ((buf[1] & 0xf0) == 0x80) { //NEG r_strbuf_appendf(&op->esil, "r%u%c,0,-,r%u%c,=", rdB(1), rdB(1)); //setZ setHb_B; setV("%o") ; setCb_B ; setN; maskB(1); setZ; } else if ((buf[1] & 0xf0) == 0x00) { //NOT r_strbuf_appendf(&op->esil, "r%u%c,!=", rdB(1)); //setZ setV("0"); setN; maskB(1); setZ; } return 0; case H8300_SUB_1: r_strbuf_appendf(&op->esil, "r%u%c,r%u%c,-=", rsB(), rdB(1)); //setZ setHb_B; setV("%o"); setCb_B; setN; maskB(1); setZ; return 0; case H8300_SUBW: r_strbuf_appendf (&op->esil, "r%u,r%u,-=", rs(), rd()); setHb_W; setV ("%o"); setCb_W; setN; mask(); setZ; return 0; case H8300_DEC: r_strbuf_appendf (&op->esil, "1,r%u%c,-=", rdB(1)); //setZ setV("%o"); setN; maskB(1); setZ; return 0; case H8300_SUBS: r_strbuf_appendf(&op->esil, "%d,r%u,-=", ( (buf[1] & 0xf0) == 0x80) ? 2 : 1, rd()); return 0; case H8300_CMP_1: r_strbuf_appendf(&op->esil, "r%u%c,r%u%c,-", rsB(), rdB(1)); //setZ setHb_B; setV("%o"); setCb_B; setN; maskB(1); setZ; return 0; case H8300_CMP_2: r_strbuf_appendf(&op->esil, "r%u,r%u,-", rs(), rd()); //setZ setHb_W; setV("%o"); setCb_W; setN; mask(); setZ; return 0; case H8300_SUBX: //Rd – (Rs) – C → Rd r_strbuf_appendf(&op->esil, "r%u%c,r%u%c,-=,C,r%u%c,-=", rsB(), rdB(1), rdB(1)); //setZ setHb_B; setV("%o"); setCb_B; setN; maskB(1); setZ; return 0; case H8300_DAS: /*TODO*/ return 0; case H8300_BRA: r_strbuf_appendf(&op->esil, "0x%02x,pc,+=", buf[1]); return 0; case H8300_BRN: r_strbuf_appendf(&op->esil,","); return 0; case H8300_BHI: r_strbuf_appendf(&op->esil, "C,Z,|,!,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BLS: r_strbuf_appendf(&op->esil, "C,Z,|,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BCC: r_strbuf_appendf(&op->esil, "C,!,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BCS: r_strbuf_appendf(&op->esil, "C,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BNE: r_strbuf_appendf(&op->esil, "Z,!,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BEQ: r_strbuf_appendf(&op->esil, "Z,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BVC: r_strbuf_appendf(&op->esil, "V,!,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BVS: r_strbuf_appendf(&op->esil, "V,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BPL: r_strbuf_appendf(&op->esil, "N,!,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BMI: r_strbuf_appendf(&op->esil, "N,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BGE: r_strbuf_appendf(&op->esil, "N,V,^,!,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BLT: r_strbuf_appendf(&op->esil, "N,V,^,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BGT: r_strbuf_appendf(&op->esil, "Z,N,V,^,|,!,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_BLE: r_strbuf_appendf(&op->esil, "Z,N,V,^,|,?{0x%02x,pc,+=}", buf[1]); return 0; case H8300_MULXU: //Refer to pg. 100 of the manual linked at the beginning r_strbuf_appendf(&op->esil, "r%u%c,r%ul,*,r%u,=", rsB(), rd(), rd()); return 0; case H8300_DIVXU: /*TODO*/ return 0; case H8300_RTS: /*TODO*/ return 0; case H8300_BSR: /*TODO*/ return 0; case H8300_RTE: /*TODO*/ return 0; case H8300_JMP_1: /*TODO*/ return 0; case H8300_JMP_2: /*TODO*/ return 0; case H8300_JMP_3: /*TODO*/ return 0; case H8300_JSR_1: /*TODO*/ return 0; case H8300_JSR_2: /*TODO*/ return 0; case H8300_JSR_3: /*TODO*/ return 0; //NOTE - cases marked with TODO have mem. access also(not impl.) case H8300_BSET_1: /*TODO*/ //set rs&0x7th bit of rd. expr.- rd|= 1<<(rs&0x07) r_strbuf_appendf(&op->esil, "0x7,r%u%c,&,1,<<,r%u%c,|=", rsB(), rdB(1)); return 0; case H8300_BNOT_1: /*TODO*/ //invert rs&0x7th bit of rd. expr.- rd^= 1<<(rs&0x07) r_strbuf_appendf(&op->esil,"0x07,r%u%c,&,1,<<,r%u%c,^=", rsB(), rdB(1)); return 0; case H8300_BCLR_R2R8: /*TODO*/ //clear rs&0x7th bit of rd. expr.- rd&= !(1<<(rs&0x07)) r_strbuf_appendf(&op->esil, "0x7,r%u%c,&,1,<<,!,r%u%c,&=", rsB(), rdB(1)); return 0; case H8300_BTST_R2R8: /*TODO*/ //¬ (<Bit No.> of <EAd>) → Z, extract bit value and shift it back r_strbuf_appendf(&op->esil, "0x7,r%u%c,&,0x7,r%u%c,&,1,<<,r%u%c,&,>>,!,Z,=", rsB(), rsB(), rdB(1)); return 0; case H8300_BST_BIST: /*TODO*/ if (!(buf[1] & 0x80)) { //BST r_strbuf_appendf(&op->esil,"%d,C,<<,r%u%c,|=",rs(),rdB(1)); } else { //BIST r_strbuf_appendf (&op->esil, "%d,C,!,<<,r%u%c,|=", rs (), rdB (1)); } return 0; case H8300_MOV_R82IND16: /*TODO*/ return 0; case H8300_MOV_IND162R16: /*TODO*/ return 0; case H8300_MOV_R82ABS16: /*TODO*/ return 0; case H8300_MOV_ABS162R16: /*TODO*/ return 0; case H8300_MOV_R82RDEC16: /*TODO*/ return 0; case H8300_MOV_INDINC162R16: /*TODO*/ return 0; case H8300_MOV_R82DISPR16: /*TODO*/ return 0; case H8300_MOV_DISP162R16: /*TODO*/ return 0; case H8300_BSET_2: /*TODO*/ //set imm bit of rd. expr.- rd|= (1<<imm) r_strbuf_appendf(&op->esil, "%d,1,<<,r%u%c,|=", rs(), rdB(1)); return 0; case H8300_BNOT_2: /*TODO*/ //inv. imm bit of rd. expr.- rd^= (1<<imm) r_strbuf_appendf(&op->esil,"%d,1,<<,r%u%c,^=",rs(),rdB(1)); return 0; case H8300_BCLR_IMM2R8: //clear imm bit of rd. expr.- rd&= !(1<<imm) r_strbuf_appendf(&op->esil, "%d,1,<<,!,r%u%c,&=", rs(), rdB(1)); return 0; case H8300_BTST: /*TODO*/ //see BTST above r_strbuf_appendf(&op->esil, "%d,%d,1,<<,r%u%c,&,>>,!,Z,=", rs(), rs(), rdB(1)); return 0; case H8300_BOR_BIOR: /*TODO*/ if (!(buf[1] & 0x80)) { //BOR //C|=(rd&(1<<imm))>>imm r_strbuf_appendf(&op->esil, "%d,%d,1,<<,r%u%c,&,>>,C,|=", rs(), rs(), rdB(1)); } else { //BIOR //C|=!(rd&(1<<imm))>>imm r_strbuf_appendf (&op->esil, "%d,%d,1,<<,r%u%c,&,>>,!,C,|=", rs (), rs (), rdB (1)); } return 0; case H8300_BXOR_BIXOR: /*TODO*/ if (!(buf[1] & 0x80)) { //BXOR //C^=(rd&(1<<imm))>>imm r_strbuf_appendf(&op->esil, "%d,%d,1,<<,r%u%c,&,>>,C,^=", rs(), rs(), rdB(1)); } else { //BIXOR r_strbuf_appendf (&op->esil, "%d,%d,1,<<,r%u%c,&,>>,!,C,^=", rs (), rs (), rdB (1)); } return 0; case H8300_BAND_BIAND: /*TODO check functionality*/ //C&=(rd&(1<<imm))>>imm if (!(buf[1] & 0x80)) { //BAND r_strbuf_appendf(&op->esil, "%d,%d,1,<<,r%u%c,&,>>,C,&=", rs(), rs(), rdB(1)); } else { //BIAND r_strbuf_appendf (&op->esil, "%d,%d,1,<<,r%u%c,&,>>,!,C,&=", rs (), rs (), rdB (1)); } return 0; case H8300_BILD_IMM2R8: /*TODO*/ if (!(buf[1] & 0x80)) { //BLD r_strbuf_appendf(&op->esil, "%d,%d,1,<<,r%u%c,&,>>,C,=", rs(), rs(), rdB(1)); } else { //BILD r_strbuf_appendf (&op->esil, "%d,%d,1,<<,r%u%c,&,>>,!,C,=", rs (), rs (), rdB (1)); } return 0; case H8300_MOV_IMM162R16: /*TODO*/ return 0; case H8300_EEPMOV: /*TODO*/ return 0; case H8300_BIAND_IMM2IND16: /*TODO*/ return 0; case H8300_BCLR_R2IND16: /*TODO*/ return 0; case H8300_BIAND_IMM2ABS8: /*TODO*/ return 0; case H8300_BCLR_R2ABS8: /*TODO*/ return 0; default: break; }; return ret; }
static void analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf) { r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); switch (buf[0]) { // Irregulars sorted by lower nibble case 0x00: /* nop */ e (","); break; case 0x10: /* jbc bit, offset */ bit_r; e ("?{,"); bit_mask; xi (bit, "&"); jmp; e (",}"); break; case 0x20: /* jb bit, offset */ bit_r; cjmp; break; case 0x30: /* jnb bit, offset */ bit_r; e ("!,"); cjmp; break; case 0x40: /* jc offset */ e ("c,1,&,"); cjmp; break; case 0x50: /* jnc offset */ e ("c,1,&,!,"); cjmp; break; case 0x60: /* jz offset */ e ("a,0,==,"); cjmp; break; case 0x70: /* jnz offset */ e ("a,0,==,!,"); cjmp; break; case 0x11: case 0x31: case 0x51: case 0x71: case 0x91: case 0xB1: case 0xD1: case 0xF1: /* acall addr11 */ case 0x12: /* lcall addr16 */ call; break; case 0x01: case 0x21: case 0x41: case 0x61: case 0x81: case 0xA1: case 0xC1: case 0xE1: /* ajmp addr11 */ case 0x02: /* ljmp addr16 */ case 0x80: /* sjmp offset */ jmp; break; case 0x22: /* ret */ case 0x32: /* reti */ xr (sp2); e ("pc,="); break; case 0x03: /* rr a */ e ("1,a,0x101,*,>>,a,=," flag_p); break; case 0x04: /* inc a */ xi (a, "++"); e (flag_p); break; case 0x05: /* inc direct */ xi (dir1, "++"); break; case 0x06: case 0x07: /* inc @Ri */ xi (ri, "++"); break; case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: /* inc @Rn */ xi (rn, "++"); break; case 0x13: /* rrc a */ e ("7,c,<<,1,a,&,c,=,0x7f,1,a,>>,&,+,a,=," flag_p); break; case 0x14: /* dec a */ xi (a, "--"); e (flag_p); break; case 0x15: /* dec direct */ xi (dir1, "--"); e (flag_p); break; case 0x16: case 0x17: /* dec @Ri */ xi (ri, "--"); break; case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: /* dec @Rn */ xi (rn, "--"); break; case 0x23: /* rl a */ e ("7,a,0x101,*,>>,a,=," flag_p); break; template_alu4 (0x20, "+", flag_c flag_ac flag_ov flag_p) /* 0x24..0x2f add a,.. */ case 0x33: /* rlc a */ e ("c,1,&,a,a,+=,$c7,c,=,a,+=," flag_p); break; template_alu4_c (0x30, "+", flag_c flag_ac flag_ov flag_p) /* 0x34..0x3f addc a,.. */ template_alu2 (0x40, "|") /* 0x42..0x43 orl direct,.. */ template_alu4 (0x40, "|", flag_p) /* 0x44..0x4f orl a,.. */ template_alu2 (0x50, "&") /* 0x52..0x53 anl direct,.. */ template_alu4 (0x50, "&", flag_p) /* 0x54..0x5f anl a,.. */ template_alu2 (0x60, "^") /* 0x62..0x63 xrl direct,.. */ template_alu4 (0x60, "^", flag_p) /* 0x64..0x6f xrl a,.. */ case 0x72: /* orl C, bit */ bit_r; xi (c, "|"); break; case 0x73: /* jmp @a+dptr */ e ("dptr,a,+,pc,="); break; case 0x74: /* mov a, imm */ xr (imm1); xw (a); e (flag_p); break; case 0x75: /* mov direct, imm */ xr (imm2); xw (dir1); break; case 0x76: case 0x77: /* mov @Ri, imm */ xr (imm1); xw (ri); break; case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: /* mov Rn, imm */ xr (imm1); xw (rn); break; case 0x82: /* anl C, bit */ bit_r; xi (c, "&"); break; case 0x83: /* movc a, @a+pc */ e ("a,pc,--,+,[1],a,=," flag_p); break; case 0x84: /* div ab */ // note: escape % if this becomes a format string e ("b,0,==,ov,=,b,a,%,b,a,/=,b,=,0,c,=," flag_p); break; case 0x85: /* mov direct, direct */ xr (dir1); xw (dir2); break; case 0x86: case 0x87: /* mov direct, @Ri */ xr (ri); xw (dir1); break; case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: /* mov direct, Rn */ xr (rn); xw (dir1); break; case 0x90: /* mov dptr, imm */ xr (imm16); xw (dp); break; case 0x92: /* mov bit, C */ bit_c; bit_mask; xr (bit); e ("&,|,"); xw(bit); break; case 0x93: /* movc a, @a+dptr */ e ("a,dptr,+,[1],a,=," flag_p); break; template_alu4_c (0x90, "-", flag_b flag_ab flag_ob flag_p) /* 0x94..0x9f subb a,.. */ case 0xA0: /* orl C, /bit */ bit_r; e ("!,"); xi (c, "|"); break; case 0xA2: /* mov C, bit */ bit_r; xw (c); break; case 0xA3: /* inc dptr */ xi (dp, "++"); break; case 0xA4: /* mul ab */ e ("8,a,b,*,DUP,a,=,>>,DUP,b,=,0,==,!,ov,=,0,c,=," flag_p); break; case 0xA5: /* "reserved" */ e ("0,trap"); break; case 0xA6: case 0xA7: /* mov @Ri, direct */ xr (dir1); xw (ri); break; case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: /* mov Rn, direct */ xr (dir1); xw (rn); break; case 0xB0: /* anl C, /bit */ bit_r; e ("!,"); xi (c, "&"); break; case 0xB2: /* cpl bit */ bit_set; xi (bit, "^"); break; case 0xB3: /* cpl C */ e ("1,"); xi (c, "^"); break; case 0xB4: /* cjne a, imm, offset */ xr (imm1); xr (a); e ("-," flag_b); cjmp; break; case 0xB5: /* cjne a, direct, offset */ xr (dir1); xr (a); e ("-," flag_b); cjmp; break; case 0xB6: case 0xB7: /* cjne @ri, imm, offset */ xr (imm1); xr (ri); e ("-," flag_b); cjmp; break; case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: /* cjne Rn, imm, offset */ xr (imm1); xr (rn); e ("-," flag_b); cjmp; break; case 0xC0: /* push direct */ xr (dir1); xw (sp1); break; case 0xC2: /* clr bit */ bit_mask; xi (bit, "&"); break; case 0xC3: /* clr C */ e ("0,"); xw (c); break; case 0xC4: /* swap a */ e ("0xff,4,a,0x101,*,>>,&,a,=," flag_p); break; case 0xC5: /* xch a, direct */ xr (a); e ("0,+,"); xr (dir1); xw (a); xw (dir1); e (flag_p); break; case 0xC6: case 0xC7: /* xch a, @Ri */ xr (a); e ("0,+,"); xr (ri); xw (a); xw (ri); e (flag_p); break; case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: /* xch a, Rn */ xr (a); e ("0,+,"); xr (rn); xw (a); xw (rn); e (flag_p); break; case 0xD0: /* pop direct */ xr (sp1); xw (dir1); break; case 0xD2: /* setb bit */ bit_set; xi (bit, "|"); break; case 0xD3: /* setb C */ e ("1,"); xw (c); break; case 0xD4: /* da a */ // BCD adjust after add: // if (lower nibble > 9) or (AC == 1) add 6 // if (higher nibble > 9) or (C == 1) add 0x60 // carry |= carry caused by this operation e ("a,0x0f,&,9,<,ac,|,?{,6,a,+=,$c7,c,|=,},a,0xf0,&,0x90,<,c,|,?{,0x60,a,+=,$c7,c,|=,}," flag_p); break; case 0xD5: /* djnz direct, offset */ xi (dir1, "--"); xr (dir1); e ("0,==,!,"); cjmp; break; case 0xD6: case 0xD7: /* xchd a, @Ri*/ xr (a); e ("0xf0,&,"); xr (ri); e ("0x0f,&,|,"); xr (ri); e ("0xf0,&,"); xr (a); e ("0x0f,&,|,"); xw (ri); xw (a); e (flag_p); break; case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: /* djnz Rn, offset */ xi (rn, "--"); xr (rn); e ("0,==,!,"); cjmp; break; case 0xE0: /* movx a, @dptr */ xr (dpx); xw (a); e (flag_p); break; case 0xE2: case 0xE3: /* movx a, @Ri */ xr (rix); xw (a); e (flag_p); break; case 0xE4: /* clr a */ e ("0,"); xw (a); e (flag_p); break; case 0xE5: /* mov a, direct */ xr (dir1); xw (a); e (flag_p); break; case 0xE6: case 0xE7: /* mov a, @Ri */ xr (ri); xw (a); e (flag_p); break; case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: case 0xEF: /* mov a, Rn */ xr (rn); xw (a); e (flag_p); break; case 0xF0: /* movx @dptr, a */ xr (a); xw (dpx); break; case 0xF2: case 0xF3: /* movx @Ri, a */ xr (a); xw (rix); break; case 0xF4: /* cpl a */ e ("255,"); xi (a, "^"); e (flag_p); break; case 0xF5: /* mov direct, a */ xr (a); xw (dir1); break; case 0xF6: case 0xF7: /* mov @Ri, a */ xr (a); xw (ri); break; case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: /* mov Rn, a */ xr (a); xw (rn); break; default: break; } }
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { struct h8300_cmd cmd; int ret = h8300_decode_command(buf, &cmd); r_strbuf_set (&op->buf_asm, sdb_fmt ("%s %s", cmd.instr, cmd.operands)); return op->size = ret; }
static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) { int i; char str[32][32]; r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); switch (insn->detail->arm.cc) { case ARM_CC_AL: // no condition break; case ARM_CC_EQ: r_strbuf_setf (&op->esil, "zf,0,?,"); break; case ARM_CC_NE: r_strbuf_setf (&op->esil, "zf,!,0,?,"); break; case ARM_CC_GT: case ARM_CC_LE: break; } // TODO: PREFIX CONDITIONAL switch (insn->id) { case ARM_INS_PUSH: // TODO: increment stack case ARM_INS_STM: for (i=1; i<insn->detail->arm.op_count; i++) { r_strbuf_appendf (&op->esil, "%s,%s,%d,+,=[4],", REG (i), ARG (0), i*4); } break; case ARM_INS_POP: // TODO: decrement stack case ARM_INS_LDM: for (i=1; i<insn->detail->arm.op_count; i++) { r_strbuf_appendf (&op->esil, "%s,%d,+,[4],%s,=", ARG (0), i*4, REG (i)); } break; case ARM_INS_CMP: r_strbuf_appendf (&op->esil, "%s,%s,==", ARG(1), ARG(0)); break; case ARM_INS_LSL: // suffix 'S' forces conditional flag to be updated r_strbuf_appendf (&op->esil, "%s,%s,<<=", ARG(1), ARG(0)); break; case ARM_INS_LSR: // suffix 'S' forces conditional flag to be updated r_strbuf_appendf (&op->esil, "%s,%s,>>=", ARG(1), ARG(0)); break; case ARM_INS_B: case ARM_INS_BL: case ARM_INS_BLX: r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0)); break; case ARM_INS_MOV: case ARM_INS_MOVS: r_strbuf_appendf (&op->esil, "%s,%s,=", ARG(1), REG(0)); break; case ARM_INS_SSUB16: case ARM_INS_SSUB8: case ARM_INS_SUB: r_strbuf_appendf (&op->esil, "%s,%s,-=", ARG(1), ARG(0)); break; case ARM_INS_SADD16: case ARM_INS_SADD8: case ARM_INS_ADD: r_strbuf_appendf (&op->esil, "%s,%s,+=", ARG(1), ARG(0)); break; case ARM_INS_LDR: r_strbuf_appendf (&op->esil, "%s,%d,+,[4],%s,=", MEMBASE(1), MEMDISP(1), REG(0)); break; case ARM_INS_LDRB: r_strbuf_appendf (&op->esil, "%s,%d,+,[1],%s,=", MEMBASE(1), MEMDISP(1), REG(0)); break; } return 0; }
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { static csh handle = 0; static int omode = -1, obits = -1; int n, ret; cs_insn *insn; int mode = (a->bits == 64) ? CS_MODE_64 : (a->bits == 32) ? CS_MODE_32 : 0; mode |= a->big_endian ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN; op->delay = 0; op->type = R_ANAL_OP_TYPE_NULL; op->jump = UT64_MAX; op->fail = UT64_MAX; op->ptr = op->val = UT64_MAX; if (a->cpu && strncmp (a->cpu, "vle", 3) == 0) { // vle is big-endian only if (!a->big_endian) { return -1; } ret = analop_vle (a, op, addr, buf, len); if (ret >= 0) { return op->size; } } if (mode != omode || a->bits != obits) { cs_close (&handle); handle = 0; omode = mode; obits = a->bits; } if (handle == 0) { ret = cs_open (CS_ARCH_PPC, mode, &handle); if (ret != CS_ERR_OK) { return -1; } cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON); } op->size = 4; r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); // capstone-next n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn); if (n < 1) { op->type = R_ANAL_OP_TYPE_ILL; } else { opex (&op->opex, handle, insn); struct Getarg gop = { .handle = handle, .insn = insn, .bits = a->bits }; op->size = insn->size; op->id = insn->id; switch (insn->id) { #if CS_API_MAJOR >= 4 case PPC_INS_CMPB: #endif case PPC_INS_CMPD: case PPC_INS_CMPDI: case PPC_INS_CMPLD: case PPC_INS_CMPLDI: case PPC_INS_CMPLW: case PPC_INS_CMPLWI: case PPC_INS_CMPW: case PPC_INS_CMPWI: op->type = R_ANAL_OP_TYPE_CMP; op->sign = true; if (ARG (2)[0] == '\0') esilprintf (op, "%s,%s,-,0xff,&,cr0,=", ARG (1), ARG (0)); else esilprintf (op, "%s,%s,-,0xff,&,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_MFLR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "lr,%s,=", ARG (0)); break; case PPC_INS_MTLR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,lr,=", ARG (0)); break; case PPC_INS_MR: case PPC_INS_LI: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,%s,=", ARG (1), ARG (0)); break; case PPC_INS_LIS: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s0000,%s,=", ARG (1), ARG (0)); break; case PPC_INS_CLRLWI: op->type = R_ANAL_OP_TYPE_AND; esilprintf (op, "%s,%s,&,%s,=", ARG (1), cmask32 (ARG (2), "0x1F"), ARG (0)); break; case PPC_INS_RLWINM: op->type = R_ANAL_OP_TYPE_ROL; esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask32 (ARG (3), ARG (4)), ARG (0)); break; case PPC_INS_SC: op->type = R_ANAL_OP_TYPE_SWI; esilprintf (op, "0,$"); break; case PPC_INS_EXTSB: op->sign = true; op->type = R_ANAL_OP_TYPE_MOV; if (a->bits == 64) esilprintf (op, "%s,0x80,&,?{,0xFFFFFFFFFFFFFF00,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); else esilprintf (op, "%s,0x80,&,?{,0xFFFFFF00,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); break; case PPC_INS_EXTSH: op->sign = true; if (a->bits == 64) esilprintf (op, "%s,0x8000,&,?{,0xFFFFFFFFFFFF0000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); else esilprintf (op, "%s,0x8000,&,?{,0xFFFF0000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); break; case PPC_INS_EXTSW: op->sign = true; esilprintf (op, "%s,0x80000000,&,?{,0xFFFFFFFF00000000,%s,|,%s,=,}", ARG (1), ARG (1), ARG (0)); break; case PPC_INS_SYNC: case PPC_INS_ISYNC: case PPC_INS_LWSYNC: case PPC_INS_MSYNC: case PPC_INS_PTESYNC: case PPC_INS_TLBSYNC: case PPC_INS_SLBIA: case PPC_INS_SLBIE: case PPC_INS_SLBMFEE: case PPC_INS_SLBMTE: case PPC_INS_EIEIO: case PPC_INS_NOP: op->type = R_ANAL_OP_TYPE_NOP; esilprintf (op, ","); break; case PPC_INS_STW: case PPC_INS_STWU: case PPC_INS_STWUX: case PPC_INS_STWX: case PPC_INS_STWCX: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[4]")); break; case PPC_INS_STWBRX: op->type = R_ANAL_OP_TYPE_STORE; break; case PPC_INS_STB: case PPC_INS_STBU: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[1]")); break; case PPC_INS_STH: case PPC_INS_STHU: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[2]")); break; case PPC_INS_STD: case PPC_INS_STDU: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, "=[8]")); break; case PPC_INS_LBZ: #if CS_API_MAJOR >= 4 case PPC_INS_LBZCIX: #endif case PPC_INS_LBZU: case PPC_INS_LBZUX: case PPC_INS_LBZX: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[1]"), ARG (0)); break; case PPC_INS_LD: case PPC_INS_LDARX: #if CS_API_MAJOR >= 4 case PPC_INS_LDCIX: #endif case PPC_INS_LDU: case PPC_INS_LDUX: case PPC_INS_LDX: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[8]"), ARG (0)); break; case PPC_INS_LDBRX: op->type = R_ANAL_OP_TYPE_LOAD; break; case PPC_INS_LFD: case PPC_INS_LFDU: case PPC_INS_LFDUX: case PPC_INS_LFDX: case PPC_INS_LFIWAX: case PPC_INS_LFIWZX: case PPC_INS_LFS: case PPC_INS_LFSU: case PPC_INS_LFSUX: case PPC_INS_LFSX: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[4]"), ARG (0)); break; case PPC_INS_LHA: case PPC_INS_LHAU: case PPC_INS_LHAUX: case PPC_INS_LHAX: case PPC_INS_LHZ: case PPC_INS_LHZU: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[2]"), ARG (0)); break; case PPC_INS_LHBRX: op->type = R_ANAL_OP_TYPE_LOAD; break; case PPC_INS_LWA: case PPC_INS_LWARX: case PPC_INS_LWAUX: case PPC_INS_LWAX: case PPC_INS_LWZ: #if CS_API_MAJOR >= 4 case PPC_INS_LWZCIX: #endif case PPC_INS_LWZU: case PPC_INS_LWZUX: case PPC_INS_LWZX: op->type = R_ANAL_OP_TYPE_LOAD; esilprintf (op, "%s,%s,=", ARG2 (1, "[4]"), ARG (0)); break; case PPC_INS_LWBRX: op->type = R_ANAL_OP_TYPE_LOAD; break; case PPC_INS_SLW: case PPC_INS_SLWI: op->type = R_ANAL_OP_TYPE_SHL; esilprintf (op, "%s,%s,<<,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_SRW: case PPC_INS_SRWI: op->type = R_ANAL_OP_TYPE_SHR; esilprintf (op, "%s,%s,>>,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_MULLI: op->sign = true; case PPC_INS_MULLW: case PPC_INS_MULLD: op->type = R_ANAL_OP_TYPE_MUL; esilprintf (op, "%s,%s,*,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_SUB: case PPC_INS_SUBC: case PPC_INS_SUBF: case PPC_INS_SUBFIC: case PPC_INS_SUBFZE: op->type = R_ANAL_OP_TYPE_SUB; esilprintf (op, "%s,%s,-,%s,=", ARG (1), ARG (2), ARG (0)); break; case PPC_INS_ADD: case PPC_INS_ADDI: op->sign = true; op->type = R_ANAL_OP_TYPE_ADD; esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_ADDC: case PPC_INS_ADDIC: op->type = R_ANAL_OP_TYPE_ADD; esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_ADDE: case PPC_INS_ADDIS: case PPC_INS_ADDME: case PPC_INS_ADDZE: op->type = R_ANAL_OP_TYPE_ADD; esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_MTSPR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,%s,=", ARG (1), PPCSPR (0)); break; case PPC_INS_BCTR: // switch table here op->type = R_ANAL_OP_TYPE_UJMP; esilprintf (op, "ctr,pc,="); break; case PPC_INS_BCTRL: // switch table here op->type = R_ANAL_OP_TYPE_CALL; esilprintf (op, "pc,lr,=,ctr,pc,="); break; case PPC_INS_B: case PPC_INS_BC: op->jump = ARG (1)[0] == '\0' ? IMM (0) : IMM (1); op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; switch (insn->detail->ppc.bc) { case PPC_BC_LT: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,<,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,<,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_LE: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,<=,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,<=,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_EQ: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,==,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,==,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_GE: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,>=,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,>=,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_GT: if (ARG (1)[0] == '\0') { esilprintf (op, "0,cr0,>,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "0,%s,>,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_NE: if (ARG (1)[0] == '\0') { esilprintf (op, "cr0,?{,%s,pc,=,},", ARG (0)); } else { esilprintf (op, "%s,?{,%s,pc,=,},", ARG (0), ARG (1)); } break; case PPC_BC_INVALID: op->type = R_ANAL_OP_TYPE_JMP; esilprintf (op, "%s,pc,=", ARG (0)); case PPC_BC_UN: // unordered case PPC_BC_NU: // not unordered case PPC_BC_SO: // summary overflow case PPC_BC_NS: // not summary overflow default: break; } break; case PPC_INS_BA: switch (insn->detail->ppc.operands[0].type) { case PPC_OP_CRX: op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; break; case PPC_OP_REG: if (op->type == R_ANAL_OP_TYPE_CJMP) { op->type = R_ANAL_OP_TYPE_UCJMP; } else { op->type = R_ANAL_OP_TYPE_CJMP; } op->jump = IMM (1); op->fail = addr + op->size; //op->type = R_ANAL_OP_TYPE_UJMP; default: break; } break; case PPC_INS_BDNZ: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; esilprintf (op, "1,ctr,-=,ctr,?{,%s,pc,=,}", ARG (0)); break; case PPC_INS_BDNZA: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDNZL: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDNZLA: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDNZLR: op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; esilprintf (op, "1,ctr,-=,ctr,?{,lr,pc,=,},"); break; case PPC_INS_BDNZLRL: op->fail = addr + op->size; op->type = R_ANAL_OP_TYPE_CJMP; break; case PPC_INS_BDZ: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; esilprintf (op, "1,ctr,-=,ctr,0,==,?{,%s,pc,=,}", ARG (0)); break; case PPC_INS_BDZA: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDZL: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDZLA: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = IMM (0); op->fail = addr + op->size; break; case PPC_INS_BDZLR: op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; esilprintf (op, "1,ctr,-=,ctr,0,==,?{,lr,pc,=,}"); break; case PPC_INS_BDZLRL: op->type = R_ANAL_OP_TYPE_CJMP; op->fail = addr + op->size; break; case PPC_INS_BLR: case PPC_INS_BLRL: case PPC_INS_BCLR: case PPC_INS_BCLRL: op->type = R_ANAL_OP_TYPE_CRET; op->fail = addr + op->size; switch (insn->detail->ppc.bc) { case PPC_BC_INVALID: op->type = R_ANAL_OP_TYPE_RET; esilprintf (op, "lr,pc,="); break; case PPC_BC_LT: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,<,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,<,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_LE: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,<=,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,<=,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_EQ: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,==,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,==,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_GE: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,>=,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,>=,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_GT: if (ARG (0)[0] == '\0') { esilprintf (op, "0,cr0,>,?{,lr,pc,=,},"); } else { esilprintf (op, "0,%s,>,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_NE: if (ARG (0)[0] == '\0') { esilprintf (op, "cr0,?{,lr,pc,=,},"); } else { esilprintf (op, "%s,?{,lr,pc,=,},", ARG (0)); } break; case PPC_BC_UN: // unordered case PPC_BC_NU: // not unordered case PPC_BC_SO: // summary overflow case PPC_BC_NS: // not summary overflow default: break; } break; case PPC_INS_NOR: op->type = R_ANAL_OP_TYPE_NOR; esilprintf (op, "%s,%s,|,!,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_XOR: case PPC_INS_XORI: op->type = R_ANAL_OP_TYPE_XOR; esilprintf (op, "%s,%s,^,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_XORIS: op->type = R_ANAL_OP_TYPE_XOR; esilprintf (op, "16,%s,<<,%s,^,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_DIVD: case PPC_INS_DIVW: op->sign = true; op->type = R_ANAL_OP_TYPE_DIV; esilprintf (op, "%s,%s,/,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_DIVDU: case PPC_INS_DIVWU: op->type = R_ANAL_OP_TYPE_DIV; esilprintf (op, "%s,%s,/,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_BL: case PPC_INS_BLA: op->type = R_ANAL_OP_TYPE_CALL; op->jump = IMM (0); op->fail = addr + op->size; esilprintf (op, "pc,lr,=,%s,pc,=", ARG (0)); break; case PPC_INS_TRAP: op->sign = true; op->type = R_ANAL_OP_TYPE_TRAP; break; case PPC_INS_AND: case PPC_INS_NAND: case PPC_INS_ANDI: op->type = R_ANAL_OP_TYPE_AND; esilprintf (op, "%s,%s,&,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_ANDIS: op->type = R_ANAL_OP_TYPE_AND; esilprintf (op, "16,%s,<<,%s,&,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_OR: case PPC_INS_ORI: op->type = R_ANAL_OP_TYPE_OR; esilprintf (op, "%s,%s,|,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_ORIS: op->type = R_ANAL_OP_TYPE_OR; esilprintf (op, "16,%s,<<,%s,|,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_MFPVR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "pvr,%s,=", ARG (0)); break; case PPC_INS_MFSPR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,%s,=", PPCSPR (1), ARG (0)); break; case PPC_INS_MFCTR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "ctr,%s,=", ARG (0)); break; case PPC_INS_MFDCCR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "dccr,%s,=", ARG (0)); break; case PPC_INS_MFICCR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "iccr,%s,=", ARG (0)); break; case PPC_INS_MFDEAR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "dear,%s,=", ARG (0)); break; case PPC_INS_MFMSR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "msr,%s,=", ARG (0)); break; case PPC_INS_MTCTR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,ctr,=", ARG (0)); break; case PPC_INS_MTDCCR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,dccr,=", ARG (0)); break; case PPC_INS_MTICCR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,iccr,=", ARG (0)); break; case PPC_INS_MTDEAR: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,dear,=", ARG (0)); break; case PPC_INS_MTMSR: case PPC_INS_MTMSRD: op->type = R_ANAL_OP_TYPE_MOV; esilprintf (op, "%s,msr,=", ARG (0)); break; // Data Cache Block Zero case PPC_INS_DCBZ: op->type = R_ANAL_OP_TYPE_STORE; esilprintf (op, "%s,%s", ARG (0), ARG2 (1, ",=[128]")); break; case PPC_INS_CLRLDI: op->type = R_ANAL_OP_TYPE_AND; esilprintf (op, "%s,%s,&,%s,=", ARG (1), cmask64 (ARG (2), "0x3F"), ARG (0)); break; case PPC_INS_ROTLDI: op->type = R_ANAL_OP_TYPE_ROL; esilprintf (op, "%s,%s,<<<,%s,=", ARG (2), ARG (1), ARG (0)); break; case PPC_INS_RLDCL: case PPC_INS_RLDICL: op->type = R_ANAL_OP_TYPE_ROL; esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask64 (ARG (3), "0x3F"), ARG (0)); break; case PPC_INS_RLDCR: case PPC_INS_RLDICR: op->type = R_ANAL_OP_TYPE_ROL; esilprintf (op, "%s,%s,<<<,%s,&,%s,=", ARG (2), ARG (1), cmask64 (0, ARG (3)), ARG (0)); break; } if (a->fillval) { op_fillval (op, handle, insn); } r_strbuf_fini (&op->esil); cs_free (insn, n); //cs_close (&handle); } return op->size; } static int archinfo(RAnal *a, int q) { if (a->cpu && !strncmp (a->cpu, "vle", 3)) { return 2; } return 4; } RAnalPlugin r_anal_plugin_ppc_cs = { .name = "ppc", .desc = "Capstone PowerPC analysis", .license = "BSD", .esil = true, .arch = "ppc", .bits = 32 | 64, .archinfo = archinfo, .op = &analop, .set_reg_profile = &set_reg_profile, }; #ifndef CORELIB RLibStruct radare_plugin = { .type = R_LIB_TYPE_ANAL, .data = &r_anal_plugin_ppc_cs, .version = R2_VERSION };
static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) { char str[8][32]; int i; r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); if (insn) { // caching operands for (i=0; i<insn->detail->mips.op_count && i<8; i++) { *str[i]=0; ARG (i); } } if (insn) switch (insn->id) { case MIPS_INS_NOP: r_strbuf_setf (&op->esil, ","); break; case MIPS_INS_BREAK: r_strbuf_setf (&op->esil, "%s,%s,TRAP", ARG (0), ARG (0)); break; case MIPS_INS_SW: case MIPS_INS_SWL: case MIPS_INS_SWR: r_strbuf_appendf (&op->esil, "%s,%s,=[4]", ARG (0), ARG (1)); break; case MIPS_INS_SH: r_strbuf_appendf (&op->esil, "%s,%s,=[2]", ARG (0), ARG (1)); break; case MIPS_INS_SWC1: case MIPS_INS_SWC2: r_strbuf_setf (&op->esil, "%s,$", ARG (1)); break; case MIPS_INS_SB: r_strbuf_appendf (&op->esil, "%s,%s,=[1]", ARG (0), ARG (1)); break; case MIPS_INS_CMP: case MIPS_INS_CMPU: case MIPS_INS_CMPGU: case MIPS_INS_CMPGDU: case MIPS_INS_CMPI: r_strbuf_appendf (&op->esil, "%s,%s,==", ARG (1), ARG (0)); break; case MIPS_INS_SHRAV: case MIPS_INS_SHRAV_R: case MIPS_INS_SHRA: case MIPS_INS_SHRA_R: case MIPS_INS_SRA: r_strbuf_appendf (&op->esil, "%s,%s,>>,31,%s,>>,?{,32,%s,-,%s,1,<<,1,-,<<,}{,0,},|,%s,=,", ARG (2), ARG (1), ARG (1), ARG (2), ARG (2), ARG (0)); break; case MIPS_INS_SHRL: // suffix 'S' forces conditional flag to be updated case MIPS_INS_SRLV: case MIPS_INS_SRL: r_strbuf_appendf (&op->esil, "%s,%s,>>,%s,=", ARG (2), ARG (1), ARG (0)); break; case MIPS_INS_SLLV: case MIPS_INS_SLL: r_strbuf_appendf (&op->esil, "%s,%s,<<,%s,=", ARG (2), ARG (1), ARG (0)); break; case MIPS_INS_BAL: case MIPS_INS_JAL: r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_D ("%s"), ARG (0)); break; case MIPS_INS_JALR: case MIPS_INS_JALRS: if (OPCOUNT () < 2) { r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_D ("%s"), ARG (0)); } else { PROTECT_ZERO () { r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_DR ("%s","%s"), ARG (0), ARG (1)); } } break; case MIPS_INS_JALRC: // no delay if (OPCOUNT () < 2) { r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_ND ("%s"), ARG (0)); } else { PROTECT_ZERO () { r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_CALL_NDR ("%s","%s"), ARG (0), ARG (1)); } } break; case MIPS_INS_JRADDIUSP: // increment stackpointer in X and jump to %ra r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%d,sp,+=,"ES_J ("ra"), ARG (0)); break; case MIPS_INS_JR: case MIPS_INS_JRC: case MIPS_INS_J: case MIPS_INS_B: // ??? // jump to address with conditional r_strbuf_appendf (&op->esil, ES_TRAP_DS () "," ES_J ("%s"), ARG (0)); break; case MIPS_INS_BNE: // bne $s, $t, offset r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,%s,==,$z,!,?{,"ES_J ("%s")",}", ARG (0), ARG (1), ARG (2)); break; case MIPS_INS_BEQ: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,%s,==,$z,?{,"ES_J ("%s")",}", ARG (0), ARG (1), ARG (2)); break; case MIPS_INS_BZ: case MIPS_INS_BEQZ: case MIPS_INS_BEQZC: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,0,==,$z,?{,"ES_J ("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BNEZ: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,0,==,$z,!,?{,"ES_J ("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BEQZALC: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",%s,0,==,$z,?{,"ES_CALL_ND ("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BLEZ: case MIPS_INS_BLEZC: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,%s,==,$z,?{,"ES_J ("%s")",BREAK,},", ARG (0), ARG (1)); r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",1,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_J ("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BGEZ: case MIPS_INS_BGEZC: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_J ("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BGEZAL: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_CALL_D ("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BGEZALC: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_CALL_ND ("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BGTZALC: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,%s,==,$z,?{,BREAK,},", ARG(0)); r_strbuf_appendf (&op->esil, "0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_CALL_ND ("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BLTZAL: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",1,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_CALL_D ("%s")",}", ARG(0), ARG(1)); break; case MIPS_INS_BLTZ: case MIPS_INS_BLTZC: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",1,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_J ("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BGTZ: case MIPS_INS_BGTZC: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,%s,==,$z,?{,BREAK,},", ARG (0)); r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,"ES_IS_NEGATIVE ("%s")",==,$z,?{,"ES_J("%s")",}", ARG (0), ARG (1)); break; case MIPS_INS_BTEQZ: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,t,==,$z,?{,"ES_J ("%s")",}", ARG (0)); break; case MIPS_INS_BTNEZ: r_strbuf_appendf (&op->esil, ES_TRAP_DS () ",0,t,==,$z,!,?{,"ES_J ("%s")",}", ARG (0)); break; case MIPS_INS_MOV: case MIPS_INS_MOVE: PROTECT_ZERO () { r_strbuf_appendf (&op->esil, "%s,%s,=", ARG (1), REG (0)); } break; case MIPS_INS_MOVZ: case MIPS_INS_MOVF: PROTECT_ZERO () { r_strbuf_appendf (&op->esil, "0,%s,==,$z,?{,%s,%s,=,}", ARG (2), ARG (1), REG (0)); } break; case MIPS_INS_MOVT: PROTECT_ZERO () { r_strbuf_appendf (&op->esil, "1,%s,==,$z,?{,%s,%s,=,}", ARG (2), ARG (1), REG (0)); } break; case MIPS_INS_FSUB: case MIPS_INS_SUB: PROTECT_ZERO () { r_strbuf_appendf(&op->esil, "%s,%s,-,%s,=", ARG (1), ARG (2), ARG (0)); //r_strbuf_appendf(&op->esil, "%s,%s,>,?{,1,TRAP,}{,%s,%s,-,%s,=", // ARG (1), ARG (2), ARG (1), ARG (2), ARG (0)); } break; case MIPS_INS_SUBU: case MIPS_INS_DSUB: case MIPS_INS_DSUBU: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); r_strbuf_appendf (&op->esil, "%s,%s,-,%s,=", arg2, arg1, arg0); } break; case MIPS_INS_NEG: case MIPS_INS_NEGU: r_strbuf_appendf (&op->esil, "%s,0,-,%s,=,", ARG (1), ARG (0)); break; /** signed -- sets overflow flag */ case MIPS_INS_ADD: { PROTECT_ZERO () { r_strbuf_appendf(&op->esil, "%s,%s,-,%s,=", ARG (1), ARG (2), ARG (0)); #if 0 r_strbuf_appendf (&op->esil, "0,32,%s,%s,+,>>,>,?{,1,TRAP,}{,%s,%s,+,%s,=,}", ARG(2), ARG(1), ARG(2), ARG(1), ARG(0)); #endif } } break; case MIPS_INS_ADDI: PROTECT_ZERO () { r_strbuf_appendf (&op->esil, "0,32,%s,0xffffffff,&,%s,+,>>,>,?{,1,TRAP,}{,%s,%s,+,%s,=,}", ARG(2), ARG(1), ARG(2), ARG(1), ARG(0)); } break; case MIPS_INS_DADD: case MIPS_INS_DADDI: /** unsigned */ case MIPS_INS_ADDU: case MIPS_INS_ADDIU: case MIPS_INS_DADDIU: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); PROTECT_ZERO () { if (*arg2 == '-') { r_strbuf_appendf (&op->esil, "%s,%s,-,%s,=", arg2+1, arg1, arg0); } else { r_strbuf_appendf (&op->esil, "%s,%s,+,%s,=", arg2, arg1, arg0); } } } break; case MIPS_INS_LI: r_strbuf_appendf (&op->esil, "0x%"PFMT64x",%s,=", IMM(1), ARG(0)); break; case MIPS_INS_LUI: r_strbuf_appendf (&op->esil, "0x%"PFMT64x"0000,%s,=", IMM(1), ARG(0)); break; case MIPS_INS_LB: case MIPS_INS_LBU: //one of these is wrong ESIL_LOAD ("1"); break; case MIPS_INS_LW: case MIPS_INS_LWC1: case MIPS_INS_LWC2: case MIPS_INS_LWL: case MIPS_INS_LWR: case MIPS_INS_LWU: case MIPS_INS_LL: case MIPS_INS_LLD: case MIPS_INS_LD: case MIPS_INS_LDI: case MIPS_INS_LDL: case MIPS_INS_LDC1: case MIPS_INS_LDC2: ESIL_LOAD ("4"); break; case MIPS_INS_LWX: case MIPS_INS_LH: case MIPS_INS_LHU: case MIPS_INS_LHX: ESIL_LOAD ("2"); break; case MIPS_INS_AND: case MIPS_INS_ANDI: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); r_strbuf_appendf (&op->esil, "%s,%s,&,%s,=", arg2, arg1, arg0); } break; case MIPS_INS_OR: case MIPS_INS_ORI: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); PROTECT_ZERO () { r_strbuf_appendf (&op->esil, "%s,%s,|,%s,=", arg2, arg1, arg0); } } break; case MIPS_INS_XOR: case MIPS_INS_XORI: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); PROTECT_ZERO () { r_strbuf_appendf (&op->esil, "%s,%s,^,%s,=", arg2, arg1, arg0); } } break; case MIPS_INS_NOR: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); PROTECT_ZERO () { r_strbuf_appendf (&op->esil, "%s,%s,|,0xffffffff,^,%s,=", arg2, arg1, arg0); } } break; case MIPS_INS_SLT: case MIPS_INS_SLTI: if (OPCOUNT () < 3) { r_strbuf_appendf (&op->esil, ES_IS_NEGATIVE ("%s")"," ES_IS_NEGATIVE ("%s")"," "==,$z,?{," "%s,%s,<,t,=," "}{," "%s,%s,>=,t,=," "}", ARG (1), ARG (0), ARG (1), ARG (0), ARG (1), ARG (0)); } else { r_strbuf_appendf (&op->esil, ES_IS_NEGATIVE ("%s")"," ES_IS_NEGATIVE ("%s")"," "==,$z,?{," "%s,%s,<,%s,=," "}{," "%s,%s,>=,%s,=," "}", ARG (2), ARG (1), ARG (2), ARG (1), ARG (0), ARG (2), ARG (1), ARG (0)); } break; case MIPS_INS_SLTU: case MIPS_INS_SLTIU: if (OPCOUNT () < 3) { r_strbuf_appendf (&op->esil, "%s,0xffffffff,&,%s,0xffffffff,&,<,t,=", ARG (1), ARG (0)); } else { r_strbuf_appendf (&op->esil, "%s,0xffffffff,&,%s,0xffffffff,&,<,%s,=", ARG (2), ARG (1), ARG (0)); } break; case MIPS_INS_MULT: case MIPS_INS_MULTU: r_strbuf_appendf (&op->esil, "%s,%s,*,0xffffffff,&,lo,=," ES_SIGN_EXT64 ("lo") ",32,%s,%s,*,>>,0xffffffff,&,hi,=," ES_SIGN_EXT64 ("hi"), ARG (0), ARG (1), ARG (0), ARG (1)); break; case MIPS_INS_MFLO: PROTECT_ZERO () { r_strbuf_appendf (&op->esil, "lo,%s,=", REG (0)); } break; case MIPS_INS_MFHI: PROTECT_ZERO () { r_strbuf_appendf (&op->esil, "hi,%s,=", REG (0)); } break; case MIPS_INS_MTLO: r_strbuf_appendf (&op->esil, "%s,lo,=,"ES_SIGN_EXT64 ("lo"), REG (0)); break; case MIPS_INS_MTHI: r_strbuf_appendf (&op->esil, "%s,hi,=,"ES_SIGN_EXT64 ("hi"), REG (0)); break; #if 0 // could not test div case MIPS_INS_DIV: case MIPS_INS_DIVU: case MIPS_INS_DDIV: case MIPS_INS_DDIVU: PROTECT_ZERO () { // 32 bit needs sign extend r_strbuf_appendf (&op->esil, "%s,%s,/,lo,=,%s,%s,%%,hi,=", REG(1), REG(0), REG(1), REG(0)); } break; #endif default: return -1; } return 0; }
static int _6502_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) { char addrbuf[64]; const int buffsize = sizeof(addrbuf)-1; memset (op, '\0', sizeof (RAnalOp)); op->size = snes_op[data[0]].len; //snes-arch is similiar to nes/6502 op->addr = addr; op->type = R_ANAL_OP_TYPE_UNK; r_strbuf_init (&op->esil); switch (data[0]) { case 0x02: case 0x03: case 0x04: case 0x07: case 0x0b: case 0x0c: case 0x0f: case 0x12: case 0x13: case 0x14: case 0x17: case 0x1a: case 0x1b: case 0x1c: case 0x1f: case 0x22: case 0x23: case 0x27: case 0x2b: case 0x2f: case 0x32: case 0x33: case 0x34: case 0x37: case 0x3a: case 0x3b: case 0x3c: case 0x3f: case 0x42: case 0x43: case 0x44: case 0x47: case 0x4b: case 0x4f: case 0x52: case 0x53: case 0x54: case 0x57: case 0x5a: case 0x5b: case 0x5c: case 0x5f: case 0x62: case 0x63: case 0x64: case 0x67: case 0x6b: case 0x6f: case 0x72: case 0x73: case 0x74: case 0x77: case 0x7a: case 0x7b: case 0x7c: case 0x7f: case 0x80: case 0x82: case 0x83: case 0x87: case 0x89: case 0x8b: case 0x8f: case 0x92: case 0x93: case 0x97: case 0x9b: case 0x9c: case 0x9e: case 0x9f: case 0xa3: case 0xa7: case 0xab: case 0xaf: case 0xb2: case 0xb3: case 0xb7: case 0xbb: case 0xbf: case 0xc2: case 0xc3: case 0xc7: case 0xcb: case 0xcf: case 0xd2: case 0xd3: case 0xd4: case 0xd7: case 0xda: case 0xdb: case 0xdc: case 0xdf: case 0xe2: case 0xe3: case 0xe7: case 0xeb: case 0xef: case 0xf2: case 0xf3: case 0xf4: case 0xf7: case 0xfa: case 0xfb: case 0xfc: case 0xff: // undocumented or not-implemented opcodes for 6502. // some of them might be implemented in 65816 op->size = 1; op->type = R_ANAL_OP_TYPE_ILL; break; // BRK case 0x00: // brk op->cycles = 7; op->type = R_ANAL_OP_TYPE_SWI; // override 65816 code which seems to be wrong: size is 1, but pc = pc + 2 op->size = 1; // PC + 2 to Stack, P to Stack B=1 D=0 I=1. "B" is not a flag. Only its bit is pushed on the stack // PC was already incremented by one at this point. Needs to incremented once more // New PC is Interrupt Vector: $fffe. (FIXME: Confirm this is valid for all 6502) r_strbuf_set (&op->esil, ",1,I,=,0,D,=,flags,0x10,|,0x100,sp,+,=[1],pc,1,+,0xfe,sp,+,=[2],3,sp,-=,0xfffe,[2],pc,="); break; // FLAGS case 0x78: // sei case 0x58: // cli case 0x38: // sec case 0x18: // clc case 0xf8: // sed case 0xd8: // cld case 0xb8: // clv op->cycles = 2; // FIXME: what opcode for this? op->type = R_ANAL_OP_TYPE_NOP; _6502_anal_esil_flags (op, data[0]); break; // BIT case 0x24: // bit $ff case 0x2c: // bit $ffff op->type = R_ANAL_OP_TYPE_MOV; _6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 0); r_strbuf_setf (&op->esil, "a,%s,[1],&,0x80,&,!,!,N,=,a,%s,[1],&,0x40,&,!,!,V,=,a,%s,[1],&,0xff,&,!,Z,=",addrbuf, addrbuf, addrbuf); break; // ADC case 0x69: // adc #$ff case 0x65: // adc $ff case 0x75: // adc $ff,x case 0x6d: // adc $ffff case 0x7d: // adc $ffff,x case 0x79: // adc $ffff,y case 0x61: // adc ($ff,x) case 0x71: // adc ($ff,y) // FIXME: update V // FIXME: support BCD mode op->type = R_ANAL_OP_TYPE_ADD; _6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize); if (data[0] == 0x69) // immediate mode r_strbuf_setf (&op->esil, "%s,a,+=,C,NUM,$c7,C,=,a,+=,$c7,C,|=", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],a,+=,C,NUM,$c7,C,=,a,+=,$c7,C,|=", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_NZ); // fix Z r_strbuf_append (&op->esil, ",a,a,=,$z,Z,="); break; // SBC case 0xe9: // sbc #$ff case 0xe5: // sbc $ff case 0xf5: // sbc $ff,x case 0xed: // sbc $ffff case 0xfd: // sbc $ffff,x case 0xf9: // sbc $ffff,y case 0xe1: // sbc ($ff,x) case 0xf1: // sbc ($ff,y) // FIXME: update V // FIXME: support BCD mode op->type = R_ANAL_OP_TYPE_SUB; _6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize); if (data[0] == 0xe9) // immediate mode r_strbuf_setf (&op->esil, "C,!,%s,+,a,-=", addrbuf); else r_strbuf_setf (&op->esil, "C,!,%s,[1],+,a,-=", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_BNZ); // fix Z and revert C r_strbuf_append (&op->esil, ",a,a,=,$z,Z,=,C,!="); break; // ORA case 0x09: // ora #$ff case 0x05: // ora $ff case 0x15: // ora $ff,x case 0x0d: // ora $ffff case 0x1d: // ora $ffff,x case 0x19: // ora $ffff,y case 0x01: // ora ($ff,x) case 0x11: // ora ($ff),y op->type = R_ANAL_OP_TYPE_OR; _6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize); if (data[0] == 0x09) // immediate mode r_strbuf_setf (&op->esil, "%s,a,|=", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],a,|=", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // AND case 0x29: // and #$ff case 0x25: // and $ff case 0x35: // and $ff,x case 0x2d: // and $ffff case 0x3d: // and $ffff,x case 0x39: // and $ffff,y case 0x21: // and ($ff,x) case 0x31: // and ($ff),y op->type = R_ANAL_OP_TYPE_AND; _6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize); if (data[0] == 0x29) // immediate mode r_strbuf_setf (&op->esil, "%s,a,&=", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],a,&=", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // EOR case 0x49: // eor #$ff case 0x45: // eor $ff case 0x55: // eor $ff,x case 0x4d: // eor $ffff case 0x5d: // eor $ffff,x case 0x59: // eor $ffff,y case 0x41: // eor ($ff,x) case 0x51: // eor ($ff),y op->type = R_ANAL_OP_TYPE_XOR; _6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize); if (data[0] == 0x49) // immediate mode r_strbuf_setf (&op->esil, "%s,a,^=", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],a,^=", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // ASL case 0x0a: // asl a case 0x06: // asl $ff case 0x16: // asl $ff,x case 0x0e: // asl $ffff case 0x1e: // asl $ffff,x op->type = R_ANAL_OP_TYPE_SHL; if (data[0] == 0x0a) { r_strbuf_set (&op->esil, "1,a,<<=,$c7,C,=,a,a,="); } else { _6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x'); r_strbuf_setf (&op->esil, "1,%s,[1],<<,%s,=[1],$c7,C,=", addrbuf, addrbuf); } _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // LSR case 0x4a: // lsr a case 0x46: // lsr $ff case 0x56: // lsr $ff,x case 0x4e: // lsr $ffff case 0x5e: // lsr $ffff,x op->type = R_ANAL_OP_TYPE_SHR; if (data[0] == 0x4a) { r_strbuf_set (&op->esil, "1,a,&,C,=,1,a,>>="); } else { _6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x'); r_strbuf_setf (&op->esil, "1,%s,[1],&,C,=,1,%s,[1],>>,%s,=[1]", addrbuf, addrbuf, addrbuf); } _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // ROL case 0x2a: // rol a case 0x26: // rol $ff case 0x36: // rol $ff,x case 0x2e: // rol $ffff case 0x3e: // rol $ffff,x op->type = R_ANAL_OP_TYPE_ROL; if (data[0] == 0x2a) { r_strbuf_set (&op->esil, "1,a,<<,C,|,a,=,$c7,C,=,a,a,="); } else { _6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x'); r_strbuf_setf (&op->esil, "1,%s,[1],<<,C,|,%s,=[1],$c7,C,=", addrbuf, addrbuf); } _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // ROR case 0x6a: // ror a case 0x66: // ror $ff case 0x76: // ror $ff,x case 0x6e: // ror $ffff case 0x7e: // ror $ffff,x // uses N as temporary to hold C value. but in fact, // it is not temporary since in all ROR ops, N will have the value of C op->type = R_ANAL_OP_TYPE_ROR; if (data[0] == 0x6a) { r_strbuf_set (&op->esil, "C,N,=,1,a,&,C,=,1,a,>>,7,N,<<,|,a,="); } else { _6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x'); r_strbuf_setf (&op->esil, "C,N,=,1,%s,[1],&,C,=,1,%s,[1],>>,7,N,<<,|,%s,=[1]", addrbuf, addrbuf, addrbuf); } _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // INC case 0xe6: // inc $ff case 0xf6: // inc $ff,x case 0xee: // inc $ffff case 0xfe: // inc $ffff,x op->type = R_ANAL_OP_TYPE_STORE; _6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x'); r_strbuf_setf (&op->esil, "%s,++=[1]", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // DEC case 0xc6: // dec $ff case 0xd6: // dec $ff,x case 0xce: // dec $ffff case 0xde: // dec $ffff,x op->type = R_ANAL_OP_TYPE_STORE; _6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'x'); r_strbuf_setf (&op->esil, "%s,--=[1]", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // INX, INY case 0xe8: // inx case 0xc8: // iny op->cycles = 2; op->type = R_ANAL_OP_TYPE_STORE; _6502_anal_esil_inc_reg (op, data[0], "+"); break; // DEX, DEY case 0xca: // dex case 0x88: // dey op->cycles = 2; op->type = R_ANAL_OP_TYPE_STORE; _6502_anal_esil_inc_reg (op, data[0], "-"); break; // CMP case 0xc9: // cmp #$ff case 0xc5: // cmp $ff case 0xd5: // cmp $ff,x case 0xcd: // cmp $ffff case 0xdd: // cmp $ffff,x case 0xd9: // cmp $ffff,y case 0xc1: // cmp ($ff,x) case 0xd1: // cmp ($ff),y op->type = R_ANAL_OP_TYPE_CMP; _6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize); if (data[0] == 0xc9) // immediate mode r_strbuf_setf (&op->esil, "%s,a,==", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],a,==", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_BNZ); // invert C, since C=1 when A-M >= 0 r_strbuf_append (&op->esil, ",C,!,C,="); break; // CPX case 0xe0: // cpx #$ff case 0xe4: // cpx $ff case 0xec: // cpx $ffff op->type = R_ANAL_OP_TYPE_CMP; _6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 0); if (data[0] == 0xe0) // immediate mode r_strbuf_setf (&op->esil, "%s,x,==", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],x,==", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_BNZ); // invert C, since C=1 when A-M >= 0 r_strbuf_append (&op->esil, ",C,!,C,="); break; // CPY case 0xc0: // cpy #$ff case 0xc4: // cpy $ff case 0xcc: // cpy $ffff op->type = R_ANAL_OP_TYPE_CMP; _6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 0); if (data[0] == 0xc0) // immediate mode r_strbuf_setf (&op->esil, "%s,y,==", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],y,==", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_BNZ); // invert C, since C=1 when A-M >= 0 r_strbuf_append (&op->esil, ",C,!,C,="); break; // BRANCHES case 0x10: // bpl $ffff case 0x30: // bmi $ffff case 0x50: // bvc $ffff case 0x70: // bvs $ffff case 0x90: // bcc $ffff case 0xb0: // bcs $ffff case 0xd0: // bne $ffff case 0xf0: // beq $ffff // FIXME: Add 1 if branch occurs to same page. // FIXME: Add 2 if branch occurs to different page op->cycles = 2; op->failcycles = 3; op->type = R_ANAL_OP_TYPE_CJMP; if (data[1] <= 127) op->jump = addr + data[1] + op->size; else op->jump = addr - (256 - data[1]) + op->size; op->fail = addr + op->size; // FIXME: add a type of conditional // op->cond = R_ANAL_COND_LE; _6502_anal_esil_ccall (op, data[0]); break; // JSR case 0x20: // jsr $ffff op->cycles = 6; op->type = R_ANAL_OP_TYPE_CALL; op->jump = data[1] | data[2] << 8; op->stackop = R_ANAL_STACK_INC; op->stackptr = 2; // JSR pushes the address-1 of the next operation on to the stack before transferring program // control to the following address // stack is on page one and sp is an 8-bit reg: operations must be done like: sp + 0x100 r_strbuf_setf (&op->esil, "1,pc,-,0xff,sp,+,=[2],0x%04x,pc,=,2,sp,-=", op->jump); break; // JMP case 0x4c: // jmp $ffff op->cycles = 3; op->type = R_ANAL_OP_TYPE_JMP; op->jump = data[1] | data[2] << 8; r_strbuf_setf (&op->esil, "0x%04x,pc,=", op->jump); break; case 0x6c: // jmp ($ffff) op->cycles = 5; op->type = R_ANAL_OP_TYPE_UJMP; // FIXME: how to read memory? // op->jump = data[1] | data[2] << 8; r_strbuf_setf (&op->esil, "0x%04x,[2],pc,=", data[1] | data[2] << 8); break; // RTS case 0x60: // rts op->eob = 1; op->type = R_ANAL_OP_TYPE_RET; op->cycles = 6; op->stackop = R_ANAL_STACK_INC; op->stackptr = -2; // Operation: PC from Stack, PC + 1 -> PC // stack is on page one and sp is an 8-bit reg: operations must be done like: sp + 0x100 r_strbuf_set (&op->esil, "0x101,sp,+,[2],pc,=,pc,++=,2,sp,+="); break; // RTI case 0x40: // rti op->eob = 1; op->type = R_ANAL_OP_TYPE_RET; op->cycles = 6; op->stackop = R_ANAL_STACK_INC; op->stackptr = -3; // Operation: P from Stack, PC from Stack // stack is on page one and sp is an 8-bit reg: operations must be done like: sp + 0x100 r_strbuf_set (&op->esil, "0x101,sp,+,[1],flags,=,0x102,sp,+,[2],pc,=,3,sp,+="); break; // NOP case 0xea: // nop op->type = R_ANAL_OP_TYPE_NOP; op->cycles = 2; break; // LDA case 0xa9: // lda #$ff case 0xa5: // lda $ff case 0xb5: // lda $ff,x case 0xad: // lda $ffff case 0xbd: // lda $ffff,x case 0xb9: // lda $ffff,y case 0xa1: // lda ($ff,x) case 0xb1: // lda ($ff),y op->type = R_ANAL_OP_TYPE_LOAD; _6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize); if (data[0] == 0xa9) // immediate mode r_strbuf_setf (&op->esil, "%s,a,=", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],a,=", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // LDX case 0xa2: // ldx #$ff case 0xa6: // ldx $ff case 0xb6: // ldx $ff,y case 0xae: // ldx $ffff case 0xbe: // ldx $ffff,y op->type = R_ANAL_OP_TYPE_LOAD; _6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'y'); if (data[0] == 0xa2) // immediate mode r_strbuf_setf (&op->esil, "%s,x,=", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],x,=", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // LDY case 0xa0: // ldy #$ff case 0xa4: // ldy $ff case 0xb4: // ldy $ff,x case 0xac: // ldy $ffff case 0xbc: // ldy $ffff,x op->type = R_ANAL_OP_TYPE_LOAD; _6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 'x'); if (data[0] == 0xa0) // immediate mode r_strbuf_setf (&op->esil, "%s,y,=", addrbuf); else r_strbuf_setf (&op->esil, "%s,[1],y,=", addrbuf); _6502_anal_update_flags (op, _6502_FLAGS_NZ); break; // STA case 0x85: // sta $ff case 0x95: // sta $ff,x case 0x8d: // sta $ffff case 0x9d: // sta $ffff,x case 0x99: // sta $ffff,y case 0x81: // sta ($ff,x) case 0x91: // sta ($ff),y op->type = R_ANAL_OP_TYPE_STORE; _6502_anal_esil_get_addr_pattern1 (op, data, addrbuf, buffsize); r_strbuf_setf (&op->esil, "a,%s,=[1]", addrbuf); break; // STX case 0x86: // stx $ff case 0x96: // stx $ff,y case 0x8e: // stx $ffff op->type = R_ANAL_OP_TYPE_STORE; _6502_anal_esil_get_addr_pattern2 (op, data, addrbuf, buffsize, 'y'); r_strbuf_setf (&op->esil, "x,%s,=[1]", addrbuf); break; // STY case 0x84: // sty $ff case 0x94: // sty $ff,x case 0x8c: // sty $ffff op->type = R_ANAL_OP_TYPE_STORE; _6502_anal_esil_get_addr_pattern3 (op, data, addrbuf, buffsize, 'x'); r_strbuf_setf (&op->esil, "y,%s,=[1]", addrbuf); break; // PHP/PHA case 0x08: // php case 0x48: // pha op->type = R_ANAL_OP_TYPE_PUSH; op->cycles = 3; op->stackop = R_ANAL_STACK_INC; op->stackptr = 1; _6502_anal_esil_push (op, data[0]); break; // PLP,PLA case 0x28: // plp case 0x68: // plp op->type = R_ANAL_OP_TYPE_POP; op->cycles = 4; op->stackop = R_ANAL_STACK_INC; op->stackptr = -1; _6502_anal_esil_pop (op, data[0]); break; // TAX,TYA,... case 0xaa: // tax case 0x8a: // txa case 0xa8: // tay case 0x98: // tya op->type = R_ANAL_OP_TYPE_MOV; op->cycles = 2; _6502_anal_esil_mov (op, data[0]); break; case 0x9a: // txs op->type = R_ANAL_OP_TYPE_MOV; op->cycles = 2; op->stackop = R_ANAL_STACK_SET; // FIXME: should I get register X a place it here? // op->stackptr = get_register_x(); _6502_anal_esil_mov (op, data[0]); break; case 0xba: // tsx op->type = R_ANAL_OP_TYPE_MOV; op->cycles = 2; op->stackop = R_ANAL_STACK_GET; _6502_anal_esil_mov (op, data[0]); break; } return op->size; }
static void analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, const char *buf_asm) { r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); switch (buf[0]) { // Irregulars sorted by lower nibble case 0x00: /* nop */ emit(","); break; case 0x10: /* jbc */ k(BIT_R "&,?{,%2$d,1,<<,255,^,%1$d,&=[1],%3$hhd,3,+,pc,+=,}"); break; case 0x20: /* jb */ k(BIT_R "&,?{,%3$hhd,3,+,pc,+=,}"); break; case 0x30: /* jnb */ k(BIT_R "&,!,?{,%3$hhd,3,+,pc,+=,}"); break; case 0x40: /* jc */ emitf("C,!,?{,%hhd,2,+,pc,+=,}", buf[1]); break; case 0x50: /* jnc */ emitf("C,""?{,%hhd,2,+,pc,+=,}", buf[1]); break; case 0x60: /* jz */ emitf("A,!,?{,%hhd,2,+,pc,+=,}", buf[1]); break; case 0x70: /* jnz */ emitf("A,""?{,%hhd,2,+,pc,+=,}", buf[1]); break; case 0x80: /* sjmp */ j(ESX_L1 JMP("2")); break; case 0x90: /* mov */ emitf("%d,dptr,=", (buf[1]<<8) + buf[2]); break; case 0xA0: /* orl */ k(BIT_R "C,|="); break; case 0xB0: /* anl */ k(BIT_R "C,&="); break; case 0xC0: /* push */ h(XR(IB1) PUSH1); break; case 0xD0: /* pop */ h(POP1 XW(IB1)); break; case 0xE0: /* movx */ /* TODO */ break; case 0xF0: /* movx */ /* TODO */ break; case 0x11: case 0x31: case 0x51: case 0x71: case 0x91: case 0xB1: case 0xD1: case 0xF1: emit(CALL("2")); // fall through case 0x01: case 0x21: case 0x41: case 0x61: case 0x81: case 0xA1: case 0xC1: case 0xE1: emitf("0x%x,pc,=", (addr & 0xF800) | ((((unsigned short)buf[0])<<3) & 0x0700) | buf[1]); break; case 0x02: /* ljmp */ emitf( "%d,pc,=", (unsigned int)((buf[1]<<8)+buf[2])); break; case 0x12: /* lcall */ emitf(CALL("3")",%d,pc,=", (unsigned int)((buf[1]<<8)+buf[2])); break; case 0x22: /* ret */ emitf(POP2 "pc,="); break; case 0x32: /* reti */ /* TODO */ break; case 0x72: /* orl */ /* TODO */ break; case 0x82: /* anl */ /* TODO */ break; case 0x92: /* mov */ /* TODO */ break; case 0xA2: /* mov */ /* TODO */ break; case 0xB2: /* cpl */ k("%2$d,1,<<,%1$d,^=[1]"); break; case 0xC2: /* clr */ /* TODO */ break; case 0x03: /* rr */ emit("1,A,0x101,*,>>,A,="); break; case 0x13: /* rrc */ /* TODO */ break; case 0x23: /* rl */ emit("7,A,0x101,*,>>,A,="); break; case 0x33: /* rlc */ /* TODO */ break; case 0x73: /* jmp */ emit("dptr,A,+,pc,="); break; case 0x83: /* movc */ emit("A,dptr,+,[1],A,="); break; case 0x93: /* movc */ emit("A,pc,+,[1],A,="); break; case 0xA3: /* inc */ h(XI(IB1, "++")); break; case 0xB3: /* cpl */ emit("1," XI(C, "^")); break; case 0xC3: /* clr */ emit("0,C,="); break; // Regulars sorted by upper nibble OP_GROUP_UNARY_4(0x00, "++") OP_GROUP_UNARY_4(0x10, "--") OP_GROUP_INPLACE_LHS_4(0x20, A, "+") case 0x34: h (XR(L1) "C,+," XI(A, "+")) break; case 0x35: h (XR(IB1) "C,+," XI(A, "+")) break; case 0x36: case 0x37: j (XR(R0I) "C,+," XI(A, "+")) break; case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: h (XR(R0) "C,+," XI(A, "+")) break; OP_GROUP_INPLACE_LHS_4(0x40, A, "|") OP_GROUP_INPLACE_LHS_4(0x50, A, "&") OP_GROUP_INPLACE_LHS_4(0x60, A, "^") case 0x74: h (XR(L1) XW(A)) break; case 0x75: h (XR(L2) XW(IB1)) break; case 0x76: case 0x77: j (XR(L1) XW(R0I)) break; case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: h (XR(L1) XW(R0)) break; case 0x84: /* div */ emit("B,!,OV,=,0,A,B,A,/=,A,B,*,-,-,B,=,0,C,="); break; case 0x85: /* mov */ h(IRAM_BASE ",%2$d,+,[1]," IRAM_BASE ",%2$d,+,=[1]"); break; case 0x86: case 0x87: j (XR(R0I) XW(IB1)) break; case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: h (XR(R0) XW(IB1)) break; OP_GROUP_INPLACE_LHS_4(0x90, A, ".") case 0xA4: /* mul */ emit("8,A,B,*,DUP,>>,DUP,!,!,OV,=,B,=,A,=,0,C,="); break; case 0xA5: /* ??? */ emit("0,TRAP"); break; case 0xA6: case 0xA7: j (XR(IB1) XW(R0I)) break; case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: h (XR(IB1) XW(R0)) break; case 0xB4: h (XR(L1) XR(A) "!=,?{,%3$hhd,2,+pc,+=,}") break; case 0xB5: h (XR(IB1) XR(A) "!=,?{,%3$hhd,2,+pc,+=,}") break; case 0xB6: case 0xB7: j (XR(L1) XR(R0I) "!=,?{,%3$hhd,2,+pc,+=,}") break; case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: h (XR(L1) XR(R0) "!=,?{,%3$hhd,2,+pc,+=,}") break; case 0xC4: /* swap */ emit("4,A,0x101,*,>>,A,="); break; case 0xC5: /* xch */ /* TODO */ break; case 0xC6: case 0xC7: /* xch */ /* TODO */ break; case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: /* xch */ h (XR(A) XR(R0) XW(A) "," XW(R0)); break; case 0xD2: /* setb */ /* TODO */ break; case 0xD3: /* setb */ /* TODO */ break; case 0xD4: /* da */ emit("A,--="); break; case 0xD5: /* djnz */ h(XI(R0I, "--") "," XR(R0I) CJMP(L2, "2")); break; case 0xD6: /* xchd */ /* TODO */ break; case 0xD7: /* xchd */ /* TODO */ break; case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: /* djnz */ h(XI(R0, "--") "," XR(R0) CJMP(L1, "2")); break; case 0xE2: case 0xE3: /* movx */ j(XRAM_BASE "r%0$d,+,[1]," XW(A)); break; case 0xE4: /* clr */ emit("0,A,="); break; case 0xE5: /* mov */ h (XR(IB1) XW(A)) break; case 0xE6: case 0xE7: /* mov */ j (XR(R0I) XW(A)) break; case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: case 0xEF: /* mov */ h (XR(R0) XW(A)) break; case 0xF2: case 0xF3: /* movx */ j(XR(A) XRAM_BASE "r%0$d,+,=[1]"); case 0xF4: /* cpl */ h ("255" XI(A, "^")) break; case 0xF5: /* mov */ h (XR(A) XW(IB1)) break; case 0xF6: case 0xF7: /* mov */ j (XR(A) XW(R0I)) break; case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: /* mov */ h (XR(A) XW(R0)) break; default: break; } }
static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) { char str[32][32]; r_strbuf_init (&op->esil); r_strbuf_set (&op->esil, ""); if (insn) switch (insn->id) { case MIPS_INS_NOP: r_strbuf_setf (&op->esil, ","); break; case MIPS_INS_SW: r_strbuf_appendf (&op->esil, "%s,%s,=[4]", ARG(0), ARG(1)); break; case MIPS_INS_SWC1: case MIPS_INS_SWC2: r_strbuf_setf (&op->esil, "%s,$", ARG(1)); break; case MIPS_INS_SB: r_strbuf_appendf (&op->esil, "%s,%s,=[1]", ARG(0), ARG(1)); break; case MIPS_INS_CMP: case MIPS_INS_CMPU: case MIPS_INS_CMPGU: case MIPS_INS_CMPGDU: case MIPS_INS_CMPI: r_strbuf_appendf (&op->esil, "%s,%s,==", ARG(1), ARG(0)); break; case MIPS_INS_SHRAV: case MIPS_INS_SHRAV_R: case MIPS_INS_SHRA: case MIPS_INS_SHRA_R: case MIPS_INS_SRA: r_strbuf_appendf (&op->esil, "%s,%s,>>,31,%s,>>,?{,32,%s,-,%s,1,<<,1,-,<<,}{,0,},|,%s,=,", ARG(2), ARG(1), ARG(1), ARG(2), ARG(2), ARG(0)); break; case MIPS_INS_SHRL: // suffix 'S' forces conditional flag to be updated case MIPS_INS_SRLV: case MIPS_INS_SRL: r_strbuf_appendf (&op->esil, "%s,%s,>>,%s,=", ARG(2), ARG(1), ARG(0)); break; case MIPS_INS_SLLV: case MIPS_INS_SLL: r_strbuf_appendf (&op->esil, "%s,%s,<<,%s,=", ARG(2), ARG(1), ARG(0)); break; case MIPS_INS_BAL: case MIPS_INS_JAL: case MIPS_INS_JALR: case MIPS_INS_JALRS: case MIPS_INS_JALRC: case MIPS_INS_BLTZAL: // Branch on less than zero and link r_strbuf_appendf (&op->esil, "pc,8,+,ra,=,%s,pc,=", ARG(0)); break; case MIPS_INS_JR: case MIPS_INS_JRC: case MIPS_INS_J: // jump to address with conditional r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0)); break; case MIPS_INS_B: // ??? case MIPS_INS_BZ: case MIPS_INS_BGTZ: case MIPS_INS_BGTZC: case MIPS_INS_BGTZALC: case MIPS_INS_BGEZ: case MIPS_INS_BGEZC: case MIPS_INS_BGEZAL: // Branch on less than zero and link case MIPS_INS_BGEZALC: r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0)); break; case MIPS_INS_BNE: // bne $s, $t, offset case MIPS_INS_BNEZ: r_strbuf_appendf (&op->esil, "%s,%s,==,!,?{,%s,pc,=,}", ARG(0), ARG(1), ARG(2)); break; case MIPS_INS_BEQ: case MIPS_INS_BEQZ: case MIPS_INS_BEQZC: case MIPS_INS_BEQZALC: r_strbuf_appendf (&op->esil, "%s,%s,==,?{,%s,pc,=,}", ARG(0), ARG(1), ARG(2)); break; case MIPS_INS_BTEQZ: case MIPS_INS_BTNEZ: r_strbuf_appendf (&op->esil, "%s,pc,=", ARG(0)); break; case MIPS_INS_MOV: case MIPS_INS_MOVE: case MIPS_INS_MOVF: case MIPS_INS_MOVT: case MIPS_INS_MOVZ: if (REG(0)[0]!='z'){ r_strbuf_appendf (&op->esil, "%s,%s,=", ARG(1), REG(0)); } else { r_strbuf_appendf (&op->esil, ","); } break; case MIPS_INS_FSUB: case MIPS_INS_SUB: if (REG(0)[0]!='z'){ r_strbuf_appendf(&op->esil, "%s,%s,>,?{,$$,}{,%s,%s,-,%s,=",ARG(2), ARG(1), ARG(1), ARG(2), ARG(0)); } else { r_strbuf_appendf (&op->esil, ","); } break; case MIPS_INS_SUBU: case MIPS_INS_NEGU: case MIPS_INS_DSUB: case MIPS_INS_DSUBU: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); r_strbuf_appendf (&op->esil, "%s,%s,-,%s,=", arg1, arg2, arg0); } break; /** signed -- sets overflow flag */ case MIPS_INS_ADD: { if (REG(0)[0]!='z'){ r_strbuf_appendf (&op->esil, "32,%s,%s,+,>>,0,>,?{,$$,}{,%s,%s,+,%s,=,}", ARG(2), ARG(1), ARG(2), ARG(1), ARG(0)); } else { r_strbuf_appendf (&op->esil, ","); } } break; case MIPS_INS_ADDI: if (REG(0)[0]!='z'){ r_strbuf_appendf (&op->esil, "32,%s,0xffffffff,&,%s,+,>>,0,>,?{,$$,}{,%s,%s,+,%s,=,}", ARG(2), ARG(1), ARG(2), ARG(1), ARG(0)); } else { r_strbuf_appendf (&op->esil, ","); } break; case MIPS_INS_DADD: case MIPS_INS_DADDI: /** unsigned */ case MIPS_INS_ADDU: case MIPS_INS_ADDIU: case MIPS_INS_DADDIU: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); if (REG(0)[0]!='z'){ r_strbuf_appendf (&op->esil, "%s,%s,+,%s,=", arg2, arg1, arg0); } else { r_strbuf_appendf (&op->esil, ","); } } break; case MIPS_INS_LI: r_strbuf_appendf (&op->esil, "0x%"PFMT64x",%s,=", IMM(1), ARG(0)); break; case MIPS_INS_LUI: r_strbuf_appendf (&op->esil, "0x%"PFMT64x"0000,%s,=", IMM(1), ARG(0)); break; case MIPS_INS_LB: case MIPS_INS_LBU: //one of these is wrong r_strbuf_appendf (&op->esil, "%s,[1],%s,=", ARG(1), REG(0)); break; case MIPS_INS_LW: case MIPS_INS_LWC1: case MIPS_INS_LWC2: case MIPS_INS_LWL: case MIPS_INS_LWR: case MIPS_INS_LWU: case MIPS_INS_LWX: case MIPS_INS_LH: case MIPS_INS_LHX: case MIPS_INS_LL: case MIPS_INS_LLD: case MIPS_INS_LD: case MIPS_INS_LDI: case MIPS_INS_LDL: case MIPS_INS_LDC1: case MIPS_INS_LDC2: r_strbuf_appendf (&op->esil, "%s,[4],%s,=", ARG(1), REG(0)); break; case MIPS_INS_AND: case MIPS_INS_ANDI: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); r_strbuf_appendf (&op->esil, "%s,%s,&,%s,=", arg2, arg1, arg0); } break; case MIPS_INS_OR: case MIPS_INS_ORI: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); if (REG(0)[0]!='z'){ r_strbuf_appendf (&op->esil, "%s,%s,|,%s,=", arg2, arg1, arg0); } else { r_strbuf_appendf (&op->esil, ","); } } break; case MIPS_INS_XOR: case MIPS_INS_XORI: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); if (REG(0)[0]!='z'){ r_strbuf_appendf (&op->esil, "%s,%s,^,%s,=", arg2, arg1, arg0); } else { r_strbuf_appendf (&op->esil, ","); } } break; case MIPS_INS_NOR: { const char *arg0 = ARG(0); const char *arg1 = ARG(1); const char *arg2 = ARG(2); if (REG(0)[0]!='z'){ r_strbuf_appendf (&op->esil, "%s,%s,|,0xffffffff,^,%s,=", arg2, arg1, arg0); } else { r_strbuf_appendf (&op->esil, ","); } } break; case MIPS_INS_SLTU: r_strbuf_appendf (&op->esil, "%s,%s,<,%s,=", ARG(1), ARG(2), ARG(0)); break; case MIPS_INS_SLTIU: { r_strbuf_appendf (&op->esil, "%s,0xffffffff,&,%s,0xffffffff,<,?{%s,1,=,}{,%s,0,=,}", ARG(1), ARG(2), ARG(0), ARG(0)); } break; } return 0; }