static void parse_localvar (RParse *p, char *newstr, size_t newstr_len, const char *var, const char *reg, char sign, char *ireg, bool att) { RStrBuf *sb = r_strbuf_new (""); if (att) { if (p->localvar_only) { if (ireg) { r_strbuf_setf (sb, "(%%%s)", ireg); } snprintf (newstr, newstr_len - 1, "%s%s", var, r_strbuf_get (sb)); } else { if (ireg) { r_strbuf_setf (sb, ", %%%s", ireg); } snprintf (newstr, newstr_len - 1, "%s(%%%s%s)", var, reg, r_strbuf_get (sb)); } } else { if (ireg) { r_strbuf_setf (sb, " + %s", ireg); } if (p->localvar_only) { snprintf (newstr, newstr_len - 1, "[%s%s]", var, r_strbuf_get (sb)); } else { snprintf (newstr, newstr_len - 1, "[%s%s %c %s]", reg, r_strbuf_get (sb), sign, var); } } r_strbuf_free (sb); }
static void _6502_anal_esil_push(RAnalOp *op, ut8 data0) { // case 0x08: // php // case 0x48: // pha char *reg = (data0==0x08) ? "flags" : "a"; // stack is on page one: sp + 0x100 r_strbuf_setf (&op->esil, "%s,sp,0x100,+,=[1],sp,--=", reg); }
static void _6502_anal_esil_ccall(RAnalOp *op, ut8 data0) { char *flag; switch(data0) { case 0x10: // bpl $ffff flag = "N,!"; break; case 0x30: // bmi $ffff flag = "N"; break; case 0x50: // bvc $ffff flag = "V,!"; break; case 0x70: // bvs $ffff flag = "V"; break; case 0x90: // bcc $ffff flag = "C,!"; break; case 0xb0: // bcs $ffff flag = "C"; break; case 0xd0: // bne $ffff flag = "Z,!"; break; case 0xf0: // beq $ffff flag = "Z"; break; default: // FIXME: should not happen flag = "unk"; break; } r_strbuf_setf (&op->esil, "%s,?{,0x%04x,pc,=,}", flag, (op->jump & 0xffff)); }
static void _6502_anal_esil_pop(RAnalOp *op, ut8 data0) { // case 0x28: // plp // case 0x68: // pla char *reg = (data0==0x28) ? "flags" : "a"; // stack is on page one: sp + 0x100 r_strbuf_setf (&op->esil, "sp,++=,sp,0x100,+,[1],%s,=", reg); if (data0==0x68) _6502_anal_update_flags (op, _6502_FLAGS_NZ); }
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 bcl_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { int i; char cache[256] = {0}; ut64 dst = 0LL; if (op == NULL) return 1; int base = *buf & 3; memset (op, 0, sizeof (RAnalOp)); r_strbuf_init (&op->esil); op->size = 1; if (*buf == 0) { op->type = R_ANAL_OP_TYPE_NOP; return 0; } switch (base) { case 0: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = addr + findpair (addr, buf, len, 3); op->fail = addr + 1; r_strbuf_setf (&op->esil, "A,++="); break; case 1: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = addr + findpair(addr, buf, len, 2); op->fail = addr + 1; r_strbuf_setf (&op->esil, "C,++="); break; case 2: op->type = R_ANAL_OP_TYPE_CMP; r_strbuf_setf (&op->esil, "G,++="); break; case 3: op->type = R_ANAL_OP_TYPE_MOV; r_strbuf_setf (&op->esil, "T,++="); break; } return op->size; }
static inline void mk_reg_str(const char *regname, int delta, bool sign, bool att, char *ireg, char *dest, int len) { RStrBuf *sb = r_strbuf_new (""); if (att) { if (ireg) { r_strbuf_setf (sb, ", %%%s", ireg); } if (delta < 10) { snprintf (dest, len - 1, "%s%d(%%%s%s)", sign ? "" : "-", delta, regname, r_strbuf_get (sb)); } else { snprintf (dest, len - 1, "%s0x%x(%%%s%s)", sign ? "" : "-", delta, regname, r_strbuf_get (sb)); } } else { if (ireg) { r_strbuf_setf (sb, " + %s", ireg); } if (delta < 10) { snprintf (dest, len - 1, "[%s%s %c %d]", regname, r_strbuf_get (sb), sign ? '+':'-', delta); } else { snprintf (dest, len - 1, "[%s%s %c 0x%x]", regname, r_strbuf_get (sb), sign ? '+':'-', delta); } } r_strbuf_free (sb); }
// inc register static void _6502_anal_esil_inc_reg(RAnalOp *op, ut8 data0, char* sign) { char* reg = NULL; switch(data0) { case 0xe8: // inx case 0xca: // dex reg = "x"; break; case 0xc8: // iny case 0x88: // dey reg = "y"; break; } r_strbuf_setf (&op->esil, "%s,%s%s=", reg, sign, sign); _6502_anal_update_flags (op, _6502_FLAGS_NZ); }
static void _6502_anal_esil_mov(RAnalOp *op, ut8 data0) { const char* src="unk"; const char* dst="unk"; switch(data0) { case 0xaa: // tax src="a"; dst="x"; break; case 0x8a: // txa src="x"; dst="a"; break; case 0xa8: // tay src="a"; dst="y"; break; case 0x98: // tya src="y"; dst="a"; break; case 0x9a: // txs src="x"; dst="sp"; break; case 0xba: // tsx src="sp"; dst="x"; break; default: // FIXME: should not happen break; } r_strbuf_setf (&op->esil, "%s,%s,=",src,dst); // don't update NZ on txs if (data0 != 0x9a) _6502_anal_update_flags (op, _6502_FLAGS_NZ); }
static void _6502_anal_esil_flags(RAnalOp *op, ut8 data0) { int enabled=0; char flag ='u'; switch(data0) { case 0x78: // sei enabled = 1; flag = 'I'; break; case 0x58: // cli enabled = 0; flag = 'I'; break; case 0x38: // sec enabled = 1; flag = 'C'; break; case 0x18: // clc enabled = 0; flag = 'C'; break; case 0xf8: // sed enabled = 1; flag = 'D'; break; case 0xd8: // cld enabled = 0; flag = 'D'; break; case 0xb8: // clv enabled = 0; flag = 'V'; break; break; } r_strbuf_setf (&op->esil, "%d,%c,=", enabled, flag); }
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; }
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; }
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 baleful_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { const ut8 *r = 0; const ut8 *r0 = 0; const ut8 *r1 = 0; const ut8 *p = 0; const ut32 *imm = 0; const ut32 *imm1 = 0; const ut8 p0[16]; const ut8 p1[16]; const ut8 p2[16]; const ut8 p3[16]; if (op == NULL) return 1; memset (op, 0, sizeof (RAnalOp)); op->type = R_ANAL_OP_TYPE_NULL; op->delay = 0; op->jump = op->fail = -1; op->ptr = op->val = -1; op->refptr = 0; r_strbuf_init (&op->esil); switch (buf[0]) { case 2: // 8 8 11 5 ADD + op->type = R_ANAL_OP_TYPE_ADD; op->size = getp(buf,p0,p1,p2,p3,0); r_strbuf_setf (&op->esil, "%s,%s,+,%s,=",p2,p1,p0); break; case 3: // 8 8 11 5 SUB - op->type = R_ANAL_OP_TYPE_SUB; op->size = getp(buf,p0,p1,p2,p3,0); r_strbuf_setf (&op->esil, "%s,%s,-,%s,=",p2,p1,p0); break; case 4: // 8 8 11 5 MUL * op->type = R_ANAL_OP_TYPE_MUL; op->size = getp(buf,p0,p1,p2,p3,0); r_strbuf_setf (&op->esil, "%s,%s,*,%s,=",p2,p1,p0); break; case 6: // 8 8 11 5 XOR ^ op->type = R_ANAL_OP_TYPE_XOR; op->size = getp(buf,p0,p1,p2,p3,0); r_strbuf_setf (&op->esil, "%s,%s,^,%s,=",p2,p1,p0); break; case 9: // 8 8 11 5 AND & op->type = R_ANAL_OP_TYPE_AND; op->size = getp(buf,p0,p1,p2,p3,0); r_strbuf_setf (&op->esil, "%s,%s,&,%s,=",p2,p1,p0); break; case 10: // 8 8 11 5 OR | op->type = R_ANAL_OP_TYPE_OR; op->size = getp(buf,p0,p1,p2,p3,0); r_strbuf_setf (&op->esil, "%s,%s,|,%s,=",p2,p1,p0); break; case 12: // 8 8 11 5 ROL <<<< op->type = R_ANAL_OP_TYPE_ROL; op->size = getp(buf,p0,p1,p2,p3,0); r_strbuf_setf (&op->esil, "%s,%s,<<<<,%s,=",p2,p1,p0); break; case 13: // 8 8 11 5 ROR >>>> op->type = R_ANAL_OP_TYPE_ROR; op->size = getp(buf,p0,p1,p2,p3,0); r_strbuf_setf (&op->esil, "%s,%s,>>>>,%s,=",p2,p1,p0); break; case 25: // ++ op->type = R_ANAL_OP_TYPE_ADD; op->size = getp(buf,p0,p1,p2,p3,6); r_strbuf_setf (&op->esil, "%s,++,=",p1); break; case 26: // -- op->type = R_ANAL_OP_TYPE_SUB; op->size = getp(buf,p0,p1,p2,p3,6); r_strbuf_setf (&op->esil, "%s,--,=",p1); break; ////////////////////////////////////////// SPECIAL DIV/MOD //////////////////////////////// case 5: // 9 9 12 6 DIV op->type = R_ANAL_OP_TYPE_DIV; op->size = getp(buf,p0,p1,p2,p3,1); r_strbuf_setf (&op->esil, "%s,%s,/,%s,=,%s,%s,%%,%s,=",p2,p1,p0,p2,p1,p3); break; ////////////////////////////////// MOVS /////////////////////////////////////////////////// case 24: //7 4 MOV op->type = R_ANAL_OP_TYPE_MOV; op->size = getp(buf,p0,p1,p2,p3,3); r_strbuf_setf (&op->esil, "%s,%s,=",p2,p1); break; case 27: // MOV r,[r] r = buf + 1; r1 = buf + 2; op->type = R_ANAL_OP_TYPE_MOV; op->size = 3; r_strbuf_setf (&op->esil, "r_%02x,[4],r_%02x,=",*r1,*r); break; case 28:// MOV [r],r1 r = buf + 1; r1 = buf + 2; op->type = R_ANAL_OP_TYPE_MOV; op->size = 3; r_strbuf_setf (&op->esil, "r_%02x,r_%02x,=[4]",*r1,*r); break; ///////////////////////////////// JUMPS ///////////////////////////////////////////////// case 14: //5 JMP imm = (ut32 *)(buf + 1); op->type = R_ANAL_OP_TYPE_JMP; op->size = getp(buf,p0,p1,p2,p3,5); r_strbuf_setf(&op->esil,"%s,pc,=",p1); break; case 16: //5 JZ op->type = R_ANAL_OP_TYPE_CJMP; op->size = getp(buf,p0,p1,p2,p3,5); r_strbuf_setf(&op->esil, "zf,?{,%s,pc,=,}",p1); break; case 21: //5 JNZ op->type = R_ANAL_OP_TYPE_CJMP; op->size = getp(buf,p0,p1,p2,p3,5); r_strbuf_setf(&op->esil, "zf,!,?{,%s,pc,=,}",p1); break; case 17: //5 JS op->type = R_ANAL_OP_TYPE_CJMP; op->size = getp(buf,p0,p1,p2,p3,5); r_strbuf_setf(&op->esil, "sf,?{,%s,pc,=,}",p1); break; case 20: //5 JNS op->type = R_ANAL_OP_TYPE_CJMP; op->size = getp(buf,p0,p1,p2,p3,5); r_strbuf_setf(&op->esil, "sf,!,?{,%s,pc,=,}",p1); break; case 19: //5 JG op->type = R_ANAL_OP_TYPE_CJMP; op->size = getp(buf,p0,p1,p2,p3,5); r_strbuf_setf(&op->esil, "gf,?{,%s,pc,=,}",p1); break; case 18: //5 JBE op->type = R_ANAL_OP_TYPE_CJMP; op->size = getp(buf,p0,p1,p2,p3,5); r_strbuf_setf(&op->esil, "gf,!,?{,%s,pc,=,}",p1); break; //////////////////////////////// EFLAGS WRITER /////////////////////////////////////////////////////////// // http://www.read.seas.harvard.edu/~kohler/class/aosref/i386/appc.htm //http://sourceforge.net/p/fake86/code/ci/master/tree/src/fake86/cpu.c case 22: // 7 7 10 4 AND op->type = R_ANAL_OP_TYPE_AND; op->size = getp(buf,p0,p1,p2,p3,2); break; case 23: // 7 7 10 4 CMP op->type = R_ANAL_OP_TYPE_SUB; op->size = getp(buf,p0,p1,p2,p3,2); r_strbuf_setf(&op->esil,"0,sf,=,%s,%s,<,sf,=,0,zf,=,%s,%s,==,%%z,zf,=,0,gf,=,%s,%s,>,gf,=",p1,p2,p1,p2,p1,p2); //"0,sf,=,%s,%s,<,sf,=" //SF //"0,zf,=,%s,%s,==,%%z,zf,=" //ZF //"0,gf,=,%s,%s,>,gf,=" //GF break; /////////////////////////////////////// STACK //////////////////////////////////////////////////////////// case 30: //6 3 PUSH p = buf + 1; op->type = R_ANAL_OP_TYPE_PUSH; op->size = getp(buf,p0,p1,p2,p3,4); r_strbuf_setf(&op->esil,"%s,stk,=[4],4,stk,+=",p1); break; case 31: // POP op->type = R_ANAL_OP_TYPE_POP; op->size = getp(buf,p0,p1,p2,p3,6); r_strbuf_setf(&op->esil,"4,stk,-=,stk,[4],%s,=",p1); break; case 15: //5 CALL imm = (ut32 *)(buf + 1); op->type = R_ANAL_OP_TYPE_CALL; op->size = getp(buf,p0,p1,p2,p3,5); r_strbuf_setf(&op->esil,"%04x,pc,+,stk,=[4],4,stk,+=,%s,pc,=",op->size,p1); break; case 1: // RET op->type = R_ANAL_OP_TYPE_RET; op->size = 1; r_strbuf_setf(&op->esil,"4,stk,-=,stk,[4],pc,="); break; /////////////////////////////////////////////////////////////////////////////////////////////////////////// case 11: r_strbuf_setf (&op->esil, "regX = regY==0"); op->size = 3; break; case 7: r_strbuf_setf (&op->esil, "regX = NEG regY"); op->size = 3; break; case 8: r_strbuf_setf (&op->esil, "regX = NOT regY"); op->size = 3; break; /////////////////////////////////////////////////////////////////////////////////////////////////////////// case 32: // SYSCALL p = buf + 1; op->type = R_ANAL_OP_TYPE_CALL; op->size = 2; r_strbuf_setf (&op->esil, "%x,$",*p); /*if (*p==0) r_strbuf_setf (&op->esil, "apicall: putchar()"); else r_strbuf_setf (&op->esil, "apicall: %02x",*p);*/ break; case 29:// VMEND op->type = R_ANAL_OP_TYPE_NOP; op->size = 1; r_strbuf_setf (&op->esil, "end virtual"); break; case 0:// NOP default: op->type = R_ANAL_OP_TYPE_NOP; op->size = 1; r_strbuf_setf (&op->esil, "nop"); break; } return op->size; }
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 avr_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { short ofst; int imm = 0, d, r, k; ut8 kbuf[4]; ut16 ins = AVR_SOFTCAST (buf[0], buf[1]); char *arg, str[32]; if (op == NULL) { return 2; } memset (op, '\0', sizeof (RAnalOp)); op->type = R_ANAL_OP_TYPE_UNK; op->ptr = UT64_MAX; op->val = UT64_MAX; op->jump = UT64_MAX; op->fail = UT64_MAX; op->refptr = 0; op->nopcode = 1; // Necessary?? op->size = avrdis (str, addr, buf, len); r_strbuf_init (&op->esil); arg = strchr (str, ' '); if (arg) { arg++; imm = (int)r_num_get (NULL, arg); } op->delay = 0; op->type = R_ANAL_OP_TYPE_UNK; if (!strncmp (str, "st", 2)) { op->type = R_ANAL_OP_TYPE_STORE; } else if (str[0] == 'l') { op->type = R_ANAL_OP_TYPE_LOAD; } else if (str[0] == 's') { op->type = R_ANAL_OP_TYPE_SUB; } else if (!strncmp (str, "inv", 3)) { op->type = R_ANAL_OP_TYPE_ILL; } else if (!strncmp (str, "ser ", 4)) { op->type = R_ANAL_OP_TYPE_MOV; } else if (!strncmp (str, "and", 3)) { op->type = R_ANAL_OP_TYPE_AND; } else if (!strncmp (str, "mul", 3)) { op->type = R_ANAL_OP_TYPE_MUL; } else if (!strncmp (str, "out ", 4)) { op->type = R_ANAL_OP_TYPE_IO; op->type2 = 1; op->val = imm; } else if (!strncmp (str, "in ", 3)) { op->type = R_ANAL_OP_TYPE_IO; op->type2 = 0; op->val = imm; } else if (!strncmp (str, "push ", 5)) { op->type = R_ANAL_OP_TYPE_PUSH; } if (ins == 0) { op->type = R_ANAL_OP_TYPE_NOP; op->cycles = 1; } if (buf[1] == 1) { //MOVW d = (buf[0] & 0xf0) >> 3; r = (buf[0] & 0x0f) << 1; op->type = R_ANAL_OP_TYPE_MOV; op->cycles = 1; r_strbuf_setf (&op->esil, "r%d,r%d,=,r%d,r%d,=", r, d, r+1, d+1); }
// analyzes the wasm opcode. static int wasm_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) { WasmOp wop = {{0}}; RAnalHint *hint = NULL; memset (op, '\0', sizeof (RAnalOp)); int ret = wasm_dis (&wop, data, len); op->jump = UT64_MAX; op->fail = UT64_MAX; op->ptr = op->val = UT64_MAX; op->size = ret; op->addr = addr; op->sign = true; op->type = R_ANAL_OP_TYPE_UNK; switch (wop.type) { case WASM_TYPE_OP_CORE: op->id = wop.op.core; break; case WASM_TYPE_OP_ATOMIC: op->id = (0xfe << 8) | wop.op.atomic; break; } if (!wop.txt || !strncmp (wop.txt, "invalid", 7)) { op->type = R_ANAL_OP_TYPE_ILL; free (wop.txt); return -1; } if (addr_old == addr && (wop.type != WASM_TYPE_OP_CORE || wop.op.core != WASM_OP_END)) { goto anal_end; } switch (wop.type) { case WASM_TYPE_OP_CORE: switch (wop.op.core) { /* Calls here are using index instead of address */ case WASM_OP_LOOP: op->type = R_ANAL_OP_TYPE_NOP; if (!(hint = r_anal_hint_get (anal, addr))) { scope_hint--; r_anal_hint_set_opcode (anal, scope_hint, "loop"); r_anal_hint_set_jump (anal, scope_hint, addr); } break; case WASM_OP_BLOCK: op->type = R_ANAL_OP_TYPE_NOP; if (!(hint = r_anal_hint_get (anal, addr))) { scope_hint--; r_anal_hint_set_opcode (anal, scope_hint, "block"); r_anal_hint_set_jump (anal, scope_hint, addr); } break; case WASM_OP_IF: if (!(hint = r_anal_hint_get (anal, addr))) { scope_hint--; r_anal_hint_set_opcode (anal, scope_hint, "if"); r_anal_hint_set_jump (anal, scope_hint, addr); if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_CJMP, 0, true)) { op->fail = addr + op->size; } } else { op->type = R_ANAL_OP_TYPE_CJMP; op->jump = hint->jump; op->fail = addr + op->size; } break; case WASM_OP_ELSE: // get if and set hint. if (!(hint = r_anal_hint_get (anal, addr))) { advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_JMP, 0, true); } else { op->type = R_ANAL_OP_TYPE_JMP; op->jump = hint->jump; } break; case WASM_OP_BR: { RAnalHint *hint2 = NULL; ut32 val; read_u32_leb128 (data + 1, data + len, &val); if ((hint2 = r_anal_hint_get (anal, addr)) && hint2->jump != UT64_MAX) { op->type = R_ANAL_OP_TYPE_JMP; op->jump = hint2->jump; } else if ((hint = r_anal_hint_get (anal, scope_hint))) { if (hint->opcode && !strncmp ("loop", hint->opcode, 4)) { op->type = R_ANAL_OP_TYPE_JMP; op->jump = hint->jump; r_anal_hint_set_jump (anal, addr, op->jump); } else { if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_JMP, val, false)) { r_anal_hint_set_jump (anal, addr, op->jump); } } } else { if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_JMP, val, false)) { eprintf ("[wasm] cannot find jump type for br (using block type)\n"); r_anal_hint_set_jump (anal, addr, op->jump); } else { eprintf ("[wasm] cannot find jump for br\n"); } } r_anal_hint_free (hint2); } break; case WASM_OP_BRIF: { RAnalHint *hint2 = NULL; ut32 val; read_u32_leb128 (data + 1, data + len, &val); if ((hint2 = r_anal_hint_get (anal, addr)) && hint2->jump != UT64_MAX) { op->type = R_ANAL_OP_TYPE_CJMP; op->jump = hint2->jump; op->fail = addr + op->size; } else if ((hint = r_anal_hint_get (anal, scope_hint))) { if (hint->opcode && !strncmp ("loop", hint->opcode, 4)) { op->fail = addr + op->size; op->jump = hint->jump; r_anal_hint_set_jump (anal, addr, op->jump); } else { if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_CJMP, val, false)) { op->fail = addr + op->size; r_anal_hint_set_jump (anal, addr, op->jump); } } } else { if (advance_till_scope_end (anal, op, addr + op->size, R_ANAL_OP_TYPE_CJMP, val, false)) { eprintf ("[wasm] cannot find jump type for br_if (using block type)\n"); op->fail = addr + op->size; r_anal_hint_set_jump (anal, addr, op->jump); } else { eprintf ("[wasm] cannot find jump for br_if\n"); } } r_anal_hint_free (hint2); } break; case WASM_OP_END: { op->type = R_ANAL_OP_TYPE_NOP; if (scope_hint < UT64_MAX) { hint = r_anal_hint_get (anal, scope_hint); if (hint && !strncmp ("loop", hint->opcode, 4)) { r_anal_hint_set_jump (anal, addr, op->jump); r_anal_hint_set_jump (anal, op->jump, addr); } else if (hint && !strncmp ("block", hint->opcode, 5)) { // if/else/block r_anal_hint_set_jump (anal, hint->jump, addr); r_anal_hint_set_jump (anal, addr, UT64_MAX); } if (hint) { r_anal_hint_set_opcode (anal, scope_hint, "invalid"); r_anal_hint_set_jump (anal, scope_hint, UT64_MAX); r_anal_hint_del (anal, scope_hint, 1); scope_hint++; } else { // all wasm routines ends with an end. op->eob = true; op->type = R_ANAL_OP_TYPE_RET; scope_hint = UT64_MAX; } } else { if (!(hint = r_anal_hint_get (anal, addr))) { // all wasm routines ends with an end. op->eob = true; op->type = R_ANAL_OP_TYPE_RET; } } } break; case WASM_OP_I32REMS: case WASM_OP_I32REMU: op->type = R_ANAL_OP_TYPE_MOD; break; case WASM_OP_GETLOCAL: case WASM_OP_I32LOAD: case WASM_OP_I64LOAD: case WASM_OP_F32LOAD: case WASM_OP_F64LOAD: case WASM_OP_I32LOAD8S: case WASM_OP_I32LOAD8U: case WASM_OP_I32LOAD16S: case WASM_OP_I32LOAD16U: case WASM_OP_I64LOAD8S: case WASM_OP_I64LOAD8U: case WASM_OP_I64LOAD16S: case WASM_OP_I64LOAD16U: case WASM_OP_I64LOAD32S: case WASM_OP_I64LOAD32U: op->type = R_ANAL_OP_TYPE_LOAD; break; case WASM_OP_SETLOCAL: case WASM_OP_TEELOCAL: op->type = R_ANAL_OP_TYPE_STORE; break; case WASM_OP_I32EQZ: case WASM_OP_I32EQ: case WASM_OP_I32NE: case WASM_OP_I32LTS: case WASM_OP_I32LTU: case WASM_OP_I32GTS: case WASM_OP_I32GTU: case WASM_OP_I32LES: case WASM_OP_I32LEU: case WASM_OP_I32GES: case WASM_OP_I32GEU: case WASM_OP_I64EQZ: case WASM_OP_I64EQ: case WASM_OP_I64NE: case WASM_OP_I64LTS: case WASM_OP_I64LTU: case WASM_OP_I64GTS: case WASM_OP_I64GTU: case WASM_OP_I64LES: case WASM_OP_I64LEU: case WASM_OP_I64GES: case WASM_OP_I64GEU: case WASM_OP_F32EQ: case WASM_OP_F32NE: case WASM_OP_F32LT: case WASM_OP_F32GT: case WASM_OP_F32LE: case WASM_OP_F32GE: case WASM_OP_F64EQ: case WASM_OP_F64NE: case WASM_OP_F64LT: case WASM_OP_F64GT: case WASM_OP_F64LE: case WASM_OP_F64GE: op->type = R_ANAL_OP_TYPE_CMP; break; case WASM_OP_I64OR: case WASM_OP_I32OR: op->type = R_ANAL_OP_TYPE_OR; break; case WASM_OP_I64XOR: case WASM_OP_I32XOR: op->type = R_ANAL_OP_TYPE_XOR; break; case WASM_OP_I32CONST: case WASM_OP_I64CONST: case WASM_OP_F32CONST: case WASM_OP_F64CONST: op->type = R_ANAL_OP_TYPE_MOV; { ut8 arg = data[1]; r_strbuf_setf (&op->esil, "4,sp,-=,%d,sp,=[4]", arg); } break; case WASM_OP_I64ADD: case WASM_OP_I32ADD: case WASM_OP_F32ADD: case WASM_OP_F64ADD: op->type = R_ANAL_OP_TYPE_ADD; break; case WASM_OP_I64SUB: case WASM_OP_I32SUB: case WASM_OP_F32SUB: case WASM_OP_F64SUB: op->type = R_ANAL_OP_TYPE_SUB; break; case WASM_OP_NOP: op->type = R_ANAL_OP_TYPE_NOP; r_strbuf_setf (&op->esil, ""); break; case WASM_OP_CALL: case WASM_OP_CALLINDIRECT: op->type = R_ANAL_OP_TYPE_CALL; op->jump = get_cf_offset (anal, data, len); op->fail = addr + op->size; if (op->jump != UT64_MAX) { op->ptr = op->jump; } r_strbuf_setf (&op->esil, "4,sp,-=,0x%"PFMT64x",sp,=[4],0x%"PFMT64x",pc,=", op->fail, op->jump); break; case WASM_OP_RETURN: // should be ret, but if there the analisys is stopped. op->type = R_ANAL_OP_TYPE_CRET; default: break; } break; case WASM_TYPE_OP_ATOMIC: switch (wop.op.atomic) { case WASM_OP_I32ATOMICLOAD: case WASM_OP_I64ATOMICLOAD: case WASM_OP_I32ATOMICLOAD8U: case WASM_OP_I32ATOMICLOAD16U: case WASM_OP_I64ATOMICLOAD8U: case WASM_OP_I64ATOMICLOAD16U: case WASM_OP_I64ATOMICLOAD32U: op->type = R_ANAL_OP_TYPE_LOAD; break; case WASM_OP_I32ATOMICSTORE: case WASM_OP_I64ATOMICSTORE: case WASM_OP_I32ATOMICSTORE8: case WASM_OP_I32ATOMICSTORE16: case WASM_OP_I64ATOMICSTORE8: case WASM_OP_I64ATOMICSTORE16: case WASM_OP_I64ATOMICSTORE32: op->type = R_ANAL_OP_TYPE_STORE; break; case WASM_OP_I32ATOMICRMWADD: case WASM_OP_I64ATOMICRMWADD: case WASM_OP_I32ATOMICRMW8UADD: case WASM_OP_I32ATOMICRMW16UADD: case WASM_OP_I64ATOMICRMW8UADD: case WASM_OP_I64ATOMICRMW16UADD: case WASM_OP_I64ATOMICRMW32UADD: op->type = R_ANAL_OP_TYPE_ADD; break; case WASM_OP_I32ATOMICRMW8USUB: case WASM_OP_I32ATOMICRMW16USUB: case WASM_OP_I32ATOMICRMWSUB: case WASM_OP_I64ATOMICRMW8USUB: case WASM_OP_I64ATOMICRMW16USUB: case WASM_OP_I64ATOMICRMW32USUB: case WASM_OP_I64ATOMICRMWSUB: op->type = R_ANAL_OP_TYPE_SUB; break; case WASM_OP_I32ATOMICRMWAND: case WASM_OP_I64ATOMICRMWAND: case WASM_OP_I32ATOMICRMW8UAND: case WASM_OP_I32ATOMICRMW16UAND: case WASM_OP_I64ATOMICRMW8UAND: case WASM_OP_I64ATOMICRMW16UAND: case WASM_OP_I64ATOMICRMW32UAND: op->type = R_ANAL_OP_TYPE_AND; break; case WASM_OP_I32ATOMICRMWOR: case WASM_OP_I64ATOMICRMWOR: case WASM_OP_I32ATOMICRMW8UOR: case WASM_OP_I32ATOMICRMW16UOR: case WASM_OP_I64ATOMICRMW8UOR: case WASM_OP_I64ATOMICRMW16UOR: case WASM_OP_I64ATOMICRMW32UOR: op->type = R_ANAL_OP_TYPE_OR; break; case WASM_OP_I32ATOMICRMWXOR: case WASM_OP_I64ATOMICRMWXOR: case WASM_OP_I32ATOMICRMW8UXOR: case WASM_OP_I32ATOMICRMW16UXOR: case WASM_OP_I64ATOMICRMW8UXOR: case WASM_OP_I64ATOMICRMW16UXOR: case WASM_OP_I64ATOMICRMW32UXOR: op->type = R_ANAL_OP_TYPE_XOR; break; case WASM_OP_I32ATOMICRMWXCHG: case WASM_OP_I64ATOMICRMWXCHG: case WASM_OP_I32ATOMICRMW8UXCHG: case WASM_OP_I32ATOMICRMW16UXCHG: case WASM_OP_I64ATOMICRMW8UXCHG: case WASM_OP_I64ATOMICRMW16UXCHG: case WASM_OP_I64ATOMICRMW32UXCHG: op->type = R_ANAL_OP_TYPE_XCHG; break; default: break; } default: break; } anal_end: addr_old = addr; free (wop.txt); r_anal_hint_free (hint); return op->size; }
// analyzes the wasm opcode. static int wasm_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) { ut64 addr2 = UT64_MAX; int i; WasmOp wop = {0}; memset (op, '\0', sizeof (RAnalOp)); int ret = wasm_dis (&wop, data, len); op->jump = UT64_MAX; op->fail = UT64_MAX; op->ptr = op->val = UT64_MAX; op->size = ret; op->addr = addr; op->sign = true; op->type = R_ANAL_OP_TYPE_UNK; op->id = wop.op; if (!wop.txt || !strncmp (wop.txt, "invalid", 7)) { op->type = R_ANAL_OP_TYPE_ILL; wasm_stack_ptr = 0; free (wop.txt); return -1; } if (wasm_stack_ptr >= WASM_STACK_SIZE) { wasm_stack_ptr = 0; op->type = R_ANAL_OP_TYPE_NULL; free (wop.txt); return -1; } switch (wop.op) { /* Calls here are using index instead of address */ case WASM_OP_LOOP: addr2 = find_scope (addr + op->size, data + op->size, len - op->size, true); op->type = R_ANAL_OP_TYPE_NOP; if (addr2 != UT64_MAX && addr_old != addr) { //eprintf("0x%016x > stack %u (loop)\n", addr, wasm_stack_ptr); wasm_stack[wasm_stack_ptr].loop = addr; wasm_stack[wasm_stack_ptr].end = addr2; wasm_stack[wasm_stack_ptr].size = wop.len; wasm_stack_ptr++; } //op->fail = addr + op->size; break; case WASM_OP_BLOCK: op->type = R_ANAL_OP_TYPE_NOP; addr2 = find_scope (addr + op->size, data + op->size, len - op->size, true); if (addr2 != UT64_MAX && addr_old != addr) { //eprintf("0x%016x > stack %u (block)\n", addr, wasm_stack_ptr); wasm_stack[wasm_stack_ptr].loop = UT64_MAX; wasm_stack[wasm_stack_ptr].end = addr2; wasm_stack[wasm_stack_ptr].size = wop.len; wasm_stack_ptr++; } break; case WASM_OP_IF: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = find_scope (addr + op->size, data + op->size, len - op->size, false); op->fail = addr + op->size; if (op->jump != UT64_MAX && addr_old != addr) { //eprintf("0x%016x > stack %u (if)\n", addr, wasm_stack_ptr); wasm_stack[wasm_stack_ptr].loop = UT64_MAX; wasm_stack[wasm_stack_ptr].end = op->fail; wasm_stack[wasm_stack_ptr].size = wop.len; wasm_stack_ptr++; } break; case WASM_OP_ELSE: op->type = R_ANAL_OP_TYPE_JMP; op->jump = find_scope (addr + op->size, data + op->size, len - op->size, false); break; case WASM_OP_I32REMS: case WASM_OP_I32REMU: op->type = R_ANAL_OP_TYPE_MOD; break; case WASM_OP_END: //eprintf("0x%016x < stack %u (end)\n", addr, wasm_stack_ptr); if (wasm_stack_ptr > 0) { op->type = R_ANAL_OP_TYPE_NOP; if (addr != UT64_MAX) { for (i = wasm_stack_ptr - 1; i > 0; i--) { if (wasm_stack[i].end == addr && wasm_stack[i].loop != UT64_MAX) { op->type = R_ANAL_OP_TYPE_CJMP; op->jump = wasm_stack[i].loop; op->fail = addr + op->size; break; } } } wasm_stack_ptr--; } else { // all wasm routines ends with an end. op->eob = true; op->type = R_ANAL_OP_TYPE_RET; } break; case WASM_OP_GETLOCAL: case WASM_OP_I32LOAD: case WASM_OP_I64LOAD: case WASM_OP_F32LOAD: case WASM_OP_F64LOAD: case WASM_OP_I32LOAD8S: case WASM_OP_I32LOAD8U: case WASM_OP_I32LOAD16S: case WASM_OP_I32LOAD16U: case WASM_OP_I64LOAD8S: case WASM_OP_I64LOAD8U: case WASM_OP_I64LOAD16S: case WASM_OP_I64LOAD16U: case WASM_OP_I64LOAD32S: case WASM_OP_I64LOAD32U: op->type = R_ANAL_OP_TYPE_LOAD; break; case WASM_OP_SETLOCAL: case WASM_OP_TEELOCAL: op->type = R_ANAL_OP_TYPE_STORE; break; case WASM_OP_I32EQZ: case WASM_OP_I32EQ: case WASM_OP_I32NE: case WASM_OP_I32LTS: case WASM_OP_I32LTU: case WASM_OP_I32GTS: case WASM_OP_I32GTU: case WASM_OP_I32LES: case WASM_OP_I32LEU: case WASM_OP_I32GES: case WASM_OP_I32GEU: case WASM_OP_I64EQZ: case WASM_OP_I64EQ: case WASM_OP_I64NE: case WASM_OP_I64LTS: case WASM_OP_I64LTU: case WASM_OP_I64GTS: case WASM_OP_I64GTU: case WASM_OP_I64LES: case WASM_OP_I64LEU: case WASM_OP_I64GES: case WASM_OP_I64GEU: case WASM_OP_F32EQ: case WASM_OP_F32NE: case WASM_OP_F32LT: case WASM_OP_F32GT: case WASM_OP_F32LE: case WASM_OP_F32GE: case WASM_OP_F64EQ: case WASM_OP_F64NE: case WASM_OP_F64LT: case WASM_OP_F64GT: case WASM_OP_F64LE: case WASM_OP_F64GE: op->type = R_ANAL_OP_TYPE_CMP; break; case WASM_OP_I64OR: case WASM_OP_I32OR: op->type = R_ANAL_OP_TYPE_OR; break; case WASM_OP_I64XOR: case WASM_OP_I32XOR: op->type = R_ANAL_OP_TYPE_XOR; break; case WASM_OP_I32CONST: case WASM_OP_I64CONST: case WASM_OP_F32CONST: case WASM_OP_F64CONST: op->type = R_ANAL_OP_TYPE_MOV; { ut8 arg = data[1]; r_strbuf_setf (&op->esil, "4,sp,-=,%d,sp,=[4]", arg); } break; case WASM_OP_I64ADD: case WASM_OP_I32ADD: case WASM_OP_F32ADD: case WASM_OP_F64ADD: op->type = R_ANAL_OP_TYPE_ADD; break; case WASM_OP_I64SUB: case WASM_OP_I32SUB: case WASM_OP_F32SUB: case WASM_OP_F64SUB: op->type = R_ANAL_OP_TYPE_SUB; break; case WASM_OP_NOP: op->type = R_ANAL_OP_TYPE_NOP; r_strbuf_setf (&op->esil, ""); break; case WASM_OP_CALL: case WASM_OP_CALLINDIRECT: op->type = R_ANAL_OP_TYPE_CALL; op->jump = get_cf_offset (anal, data); op->fail = addr + op->size; if (op->jump != UT64_MAX) { op->ptr = op->jump; } r_strbuf_setf (&op->esil, "4,sp,-=,0x%"PFMT64x",sp,=[4],0x%"PFMT64x",pc,=", op->fail, op->jump); break; case WASM_OP_BR: op->type = R_ANAL_OP_TYPE_JMP; set_br_jump(op, data, len - op->size); break; case WASM_OP_BRIF: op->fail = addr + op->size; op->type = R_ANAL_OP_TYPE_CJMP; set_br_jump(op, data, len - op->size); break; case WASM_OP_RETURN: // should be ret, but if there the analisys is stopped. op->type = R_ANAL_OP_TYPE_CRET; default: break; } op_old = wop.op; addr_old = addr; free (wop.txt); return op->size; }
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 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; }