// SPDX-FileCopyrightText: 2010-2020 pancake // SPDX-FileCopyrightText: 2010-2020 nibble // SPDX-License-Identifier: LGPL-3.0-only #include #include #include RZ_API RzAnalysisOp *rz_analysis_op_new(void) { RzAnalysisOp *op = RZ_NEW(RzAnalysisOp); rz_analysis_op_init(op); return op; } RZ_API RzList *rz_analysis_op_list_new(void) { RzList *list = rz_list_new(); if (list) { list->free = &rz_analysis_op_free; } return list; } RZ_API void rz_analysis_op_init(RzAnalysisOp *op) { if (op) { memset(op, 0, sizeof(*op)); op->addr = UT64_MAX; op->jump = UT64_MAX; op->fail = UT64_MAX; op->ptr = UT64_MAX; op->refptr = 0; op->val = UT64_MAX; op->disp = UT64_MAX; } } RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op) { if (!op) { return false; } rz_analysis_value_free(op->src[0]); rz_analysis_value_free(op->src[1]); rz_analysis_value_free(op->src[2]); op->src[0] = NULL; op->src[1] = NULL; op->src[2] = NULL; rz_analysis_value_free(op->dst); op->dst = NULL; rz_list_free(op->access); op->access = NULL; rz_strbuf_fini(&op->opex); rz_strbuf_fini(&op->esil); rz_analysis_switch_op_free(op->switch_op); op->switch_op = NULL; RZ_FREE(op->mnemonic); return true; } RZ_API void rz_analysis_op_free(void *_op) { if (!_op) { return; } rz_analysis_op_fini(_op); memset(_op, 0, sizeof(RzAnalysisOp)); free(_op); } static int defaultCycles(RzAnalysisOp *op) { switch (op->type) { case RZ_ANALYSIS_OP_TYPE_PUSH: case RZ_ANALYSIS_OP_TYPE_POP: case RZ_ANALYSIS_OP_TYPE_STORE: case RZ_ANALYSIS_OP_TYPE_LOAD: return 2; case RZ_ANALYSIS_OP_TYPE_LEA: case RZ_ANALYSIS_OP_TYPE_MOV: case RZ_ANALYSIS_OP_TYPE_NOP: return 1; case RZ_ANALYSIS_OP_TYPE_TRAP: case RZ_ANALYSIS_OP_TYPE_SWI: return 4; case RZ_ANALYSIS_OP_TYPE_SYNC: return 4; case RZ_ANALYSIS_OP_TYPE_RET: case RZ_ANALYSIS_OP_TYPE_JMP: case RZ_ANALYSIS_OP_TYPE_RJMP: case RZ_ANALYSIS_OP_TYPE_CALL: return 4; default: return 1; } } RZ_API int rz_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask) { rz_analysis_op_init(op); rz_return_val_if_fail(analysis && op && len > 0, -1); int ret = RZ_MIN(2, len); if (len > 0 && analysis->cur && analysis->cur->op) { //use core binding to set asm.bits correctly based on the addr //this is because of the hassle of arm/thumb if (analysis && analysis->coreb.archbits) { analysis->coreb.archbits(analysis->coreb.core, addr); } if (analysis->pcalign && addr % analysis->pcalign) { op->type = RZ_ANALYSIS_OP_TYPE_ILL; op->addr = addr; // eprintf ("Unaligned instruction for %d bits at 0x%"PFMT64x"\n", analysis->bits, addr); op->size = 1; return -1; } ret = analysis->cur->op(analysis, op, addr, data, len, mask); if (ret < 1) { op->type = RZ_ANALYSIS_OP_TYPE_ILL; } op->addr = addr; /* consider at least 1 byte to be part of the opcode */ if (op->nopcode < 1) { op->nopcode = 1; } } else if (!memcmp(data, "\xff\xff\xff\xff", RZ_MIN(4, len))) { op->type = RZ_ANALYSIS_OP_TYPE_ILL; } else { op->type = RZ_ANALYSIS_OP_TYPE_MOV; if (op->cycles == 0) { op->cycles = defaultCycles(op); } } if (!op->mnemonic && (mask & RZ_ANALYSIS_OP_MASK_DISASM)) { if (analysis->verbose) { eprintf("Warning: unhandled RZ_ANALYSIS_OP_MASK_DISASM in rz_analysis_op\n"); } } if (mask & RZ_ANALYSIS_OP_MASK_HINT) { RzAnalysisHint *hint = rz_analysis_hint_get(analysis, addr); if (hint) { rz_analysis_op_hint(op, hint); rz_analysis_hint_free(hint); } } return ret; } RZ_API RzAnalysisOp *rz_analysis_op_copy(RzAnalysisOp *op) { RzAnalysisOp *nop = RZ_NEW0(RzAnalysisOp); 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] = rz_analysis_value_copy(op->src[0]); nop->src[1] = rz_analysis_value_copy(op->src[1]); nop->src[2] = rz_analysis_value_copy(op->src[2]); nop->dst = rz_analysis_value_copy(op->dst); if (op->access) { RzListIter *it; RzAnalysisValue *val; RzList *naccess = rz_list_newf((RzListFree)rz_analysis_value_free); rz_list_foreach (op->access, it, val) { rz_list_append(naccess, rz_analysis_value_copy(val)); } nop->access = naccess; } rz_strbuf_init(&nop->esil); rz_strbuf_copy(&nop->esil, &op->esil); return nop; } RZ_API bool rz_analysis_op_nonlinear(int t) { t &= RZ_ANALYSIS_OP_TYPE_MASK; switch (t) { //call case RZ_ANALYSIS_OP_TYPE_CALL: case RZ_ANALYSIS_OP_TYPE_RCALL: case RZ_ANALYSIS_OP_TYPE_ICALL: case RZ_ANALYSIS_OP_TYPE_UCALL: case RZ_ANALYSIS_OP_TYPE_IRCALL: case RZ_ANALYSIS_OP_TYPE_UCCALL: // jmp case RZ_ANALYSIS_OP_TYPE_JMP: case RZ_ANALYSIS_OP_TYPE_MJMP: case RZ_ANALYSIS_OP_TYPE_UJMP: case RZ_ANALYSIS_OP_TYPE_CJMP: case RZ_ANALYSIS_OP_TYPE_UCJMP: case RZ_ANALYSIS_OP_TYPE_RJMP: case RZ_ANALYSIS_OP_TYPE_IJMP: case RZ_ANALYSIS_OP_TYPE_IRJMP: // trap| ill| unk case RZ_ANALYSIS_OP_TYPE_TRAP: case RZ_ANALYSIS_OP_TYPE_ILL: case RZ_ANALYSIS_OP_TYPE_UNK: case RZ_ANALYSIS_OP_TYPE_SWI: case RZ_ANALYSIS_OP_TYPE_RET: return true; default: return false; } } RZ_API bool rz_analysis_op_ismemref(int t) { t &= RZ_ANALYSIS_OP_TYPE_MASK; switch (t) { case RZ_ANALYSIS_OP_TYPE_LOAD: case RZ_ANALYSIS_OP_TYPE_MOV: case RZ_ANALYSIS_OP_TYPE_STORE: case RZ_ANALYSIS_OP_TYPE_LEA: case RZ_ANALYSIS_OP_TYPE_CMP: return true; default: return false; } } static struct optype { int type; const char *name; } optypes[] = { { RZ_ANALYSIS_OP_TYPE_IO, "io" }, { RZ_ANALYSIS_OP_TYPE_ACMP, "acmp" }, { RZ_ANALYSIS_OP_TYPE_ADD, "add" }, { RZ_ANALYSIS_OP_TYPE_SYNC, "sync" }, { RZ_ANALYSIS_OP_TYPE_AND, "and" }, { RZ_ANALYSIS_OP_TYPE_CALL, "call" }, { RZ_ANALYSIS_OP_TYPE_CCALL, "ccall" }, { RZ_ANALYSIS_OP_TYPE_CJMP, "cjmp" }, { RZ_ANALYSIS_OP_TYPE_MJMP, "mjmp" }, { RZ_ANALYSIS_OP_TYPE_CMP, "cmp" }, { RZ_ANALYSIS_OP_TYPE_IO, "cret" }, { RZ_ANALYSIS_OP_TYPE_ILL, "ill" }, { RZ_ANALYSIS_OP_TYPE_JMP, "jmp" }, { RZ_ANALYSIS_OP_TYPE_LEA, "lea" }, { RZ_ANALYSIS_OP_TYPE_LEAVE, "leave" }, { RZ_ANALYSIS_OP_TYPE_LOAD, "load" }, { RZ_ANALYSIS_OP_TYPE_NEW, "new" }, { RZ_ANALYSIS_OP_TYPE_MOD, "mod" }, { RZ_ANALYSIS_OP_TYPE_CMOV, "cmov" }, { RZ_ANALYSIS_OP_TYPE_MOV, "mov" }, { RZ_ANALYSIS_OP_TYPE_CAST, "cast" }, { RZ_ANALYSIS_OP_TYPE_MUL, "mul" }, { RZ_ANALYSIS_OP_TYPE_DIV, "div" }, { RZ_ANALYSIS_OP_TYPE_NOP, "nop" }, { RZ_ANALYSIS_OP_TYPE_NOT, "not" }, { RZ_ANALYSIS_OP_TYPE_NULL, "null" }, { RZ_ANALYSIS_OP_TYPE_OR, "or" }, { RZ_ANALYSIS_OP_TYPE_POP, "pop" }, { RZ_ANALYSIS_OP_TYPE_PUSH, "push" }, { RZ_ANALYSIS_OP_TYPE_REP, "rep" }, { RZ_ANALYSIS_OP_TYPE_RET, "ret" }, { RZ_ANALYSIS_OP_TYPE_ROL, "rol" }, { RZ_ANALYSIS_OP_TYPE_ROR, "ror" }, { RZ_ANALYSIS_OP_TYPE_SAL, "sal" }, { RZ_ANALYSIS_OP_TYPE_SAR, "sar" }, { RZ_ANALYSIS_OP_TYPE_SHL, "shl" }, { RZ_ANALYSIS_OP_TYPE_SHR, "shr" }, { RZ_ANALYSIS_OP_TYPE_STORE, "store" }, { RZ_ANALYSIS_OP_TYPE_SUB, "sub" }, { RZ_ANALYSIS_OP_TYPE_SWI, "swi" }, { RZ_ANALYSIS_OP_TYPE_CSWI, "cswi" }, { RZ_ANALYSIS_OP_TYPE_SWITCH, "switch" }, { RZ_ANALYSIS_OP_TYPE_TRAP, "trap" }, { RZ_ANALYSIS_OP_TYPE_UCALL, "ucall" }, { RZ_ANALYSIS_OP_TYPE_RCALL, "rcall" }, // needs to be changed { RZ_ANALYSIS_OP_TYPE_ICALL, "ucall" }, // needs to be changed { RZ_ANALYSIS_OP_TYPE_IRCALL, "ucall" }, // needs to be changed { RZ_ANALYSIS_OP_TYPE_UCCALL, "uccall" }, { RZ_ANALYSIS_OP_TYPE_UCJMP, "ucjmp" }, { RZ_ANALYSIS_OP_TYPE_UJMP, "ujmp" }, { RZ_ANALYSIS_OP_TYPE_RJMP, "rjmp" }, // needs to be changed { RZ_ANALYSIS_OP_TYPE_IJMP, "ujmp" }, // needs to be changed { RZ_ANALYSIS_OP_TYPE_IRJMP, "ujmp" }, // needs to be changed { RZ_ANALYSIS_OP_TYPE_UNK, "unk" }, { RZ_ANALYSIS_OP_TYPE_UPUSH, "upush" }, { RZ_ANALYSIS_OP_TYPE_RPUSH, "rpush" }, { RZ_ANALYSIS_OP_TYPE_XCHG, "xchg" }, { RZ_ANALYSIS_OP_TYPE_XOR, "xor" }, { RZ_ANALYSIS_OP_TYPE_CASE, "case" }, { RZ_ANALYSIS_OP_TYPE_CPL, "cpl" }, { RZ_ANALYSIS_OP_TYPE_CRYPTO, "crypto" }, { 0, NULL } }; RZ_API int rz_analysis_optype_from_string(const char *type) { int i; for (i = 0; optypes[i].name; i++) { if (!strcmp(optypes[i].name, type)) { return optypes[i].type; } } return -1; } RZ_API const char *rz_analysis_optype_to_string(int t) { bool once = true; repeat: // TODO: delete switch (t) { case RZ_ANALYSIS_OP_TYPE_IO: return "io"; case RZ_ANALYSIS_OP_TYPE_ACMP: return "acmp"; case RZ_ANALYSIS_OP_TYPE_ADD: return "add"; case RZ_ANALYSIS_OP_TYPE_SYNC: return "sync"; case RZ_ANALYSIS_OP_TYPE_AND: return "and"; case RZ_ANALYSIS_OP_TYPE_CALL: return "call"; case RZ_ANALYSIS_OP_TYPE_CCALL: return "ccall"; case RZ_ANALYSIS_OP_TYPE_CJMP: return "cjmp"; case RZ_ANALYSIS_OP_TYPE_MJMP: return "mjmp"; case RZ_ANALYSIS_OP_TYPE_CMP: return "cmp"; case RZ_ANALYSIS_OP_TYPE_CRET: return "cret"; case RZ_ANALYSIS_OP_TYPE_DIV: return "div"; case RZ_ANALYSIS_OP_TYPE_ILL: return "ill"; case RZ_ANALYSIS_OP_TYPE_JMP: return "jmp"; case RZ_ANALYSIS_OP_TYPE_LEA: return "lea"; case RZ_ANALYSIS_OP_TYPE_LEAVE: return "leave"; case RZ_ANALYSIS_OP_TYPE_LOAD: return "load"; case RZ_ANALYSIS_OP_TYPE_NEW: return "new"; case RZ_ANALYSIS_OP_TYPE_MOD: return "mod"; case RZ_ANALYSIS_OP_TYPE_CMOV: return "cmov"; case RZ_ANALYSIS_OP_TYPE_MOV: return "mov"; case RZ_ANALYSIS_OP_TYPE_CAST: return "cast"; case RZ_ANALYSIS_OP_TYPE_MUL: return "mul"; case RZ_ANALYSIS_OP_TYPE_NOP: return "nop"; case RZ_ANALYSIS_OP_TYPE_NOT: return "not"; case RZ_ANALYSIS_OP_TYPE_NULL: return "null"; case RZ_ANALYSIS_OP_TYPE_OR: return "or"; case RZ_ANALYSIS_OP_TYPE_POP: return "pop"; case RZ_ANALYSIS_OP_TYPE_PUSH: return "push"; case RZ_ANALYSIS_OP_TYPE_RPUSH: return "rpush"; case RZ_ANALYSIS_OP_TYPE_REP: return "rep"; case RZ_ANALYSIS_OP_TYPE_RET: return "ret"; case RZ_ANALYSIS_OP_TYPE_ROL: return "rol"; case RZ_ANALYSIS_OP_TYPE_ROR: return "ror"; case RZ_ANALYSIS_OP_TYPE_SAL: return "sal"; case RZ_ANALYSIS_OP_TYPE_SAR: return "sar"; case RZ_ANALYSIS_OP_TYPE_SHL: return "shl"; case RZ_ANALYSIS_OP_TYPE_SHR: return "shr"; case RZ_ANALYSIS_OP_TYPE_STORE: return "store"; case RZ_ANALYSIS_OP_TYPE_SUB: return "sub"; case RZ_ANALYSIS_OP_TYPE_SWI: return "swi"; case RZ_ANALYSIS_OP_TYPE_CSWI: return "cswi"; case RZ_ANALYSIS_OP_TYPE_SWITCH: return "switch"; case RZ_ANALYSIS_OP_TYPE_TRAP: return "trap"; case RZ_ANALYSIS_OP_TYPE_UCALL: return "ucall"; case RZ_ANALYSIS_OP_TYPE_RCALL: return "rcall"; // needs to be changed case RZ_ANALYSIS_OP_TYPE_ICALL: return "ucall"; // needs to be changed case RZ_ANALYSIS_OP_TYPE_IRCALL: return "ucall"; // needs to be changed case RZ_ANALYSIS_OP_TYPE_UCCALL: return "uccall"; case RZ_ANALYSIS_OP_TYPE_UCJMP: return "ucjmp"; case RZ_ANALYSIS_OP_TYPE_UJMP: return "ujmp"; case RZ_ANALYSIS_OP_TYPE_RJMP: return "rjmp"; // needs to be changed case RZ_ANALYSIS_OP_TYPE_IJMP: return "ujmp"; // needs to be changed case RZ_ANALYSIS_OP_TYPE_IRJMP: return "ujmp"; // needs to be changed case RZ_ANALYSIS_OP_TYPE_UNK: return "unk"; case RZ_ANALYSIS_OP_TYPE_UPUSH: return "upush"; case RZ_ANALYSIS_OP_TYPE_XCHG: return "xchg"; case RZ_ANALYSIS_OP_TYPE_XOR: return "xor"; case RZ_ANALYSIS_OP_TYPE_CASE: return "case"; case RZ_ANALYSIS_OP_TYPE_CPL: return "cpl"; case RZ_ANALYSIS_OP_TYPE_CRYPTO: return "crypto"; } if (once) { once = false; t &= RZ_ANALYSIS_OP_TYPE_MASK; // ignore the modifier bits... we don't want this! goto repeat; } return "undefined"; } RZ_API const char *rz_analysis_op_to_esil_string(RzAnalysis *analysis, RzAnalysisOp *op) { return rz_strbuf_get(&op->esil); } // TODO: use esil here? RZ_API char *rz_analysis_op_to_string(RzAnalysis *analysis, RzAnalysisOp *op) { RzAnalysisBlock *bb; RzAnalysisFunction *f; char *cstr, ret[128]; char *r0 = rz_analysis_value_to_string(op->dst); char *a0 = rz_analysis_value_to_string(op->src[0]); char *a1 = rz_analysis_value_to_string(op->src[1]); if (!r0) { r0 = strdup("?"); } if (!a0) { a0 = strdup("?"); } if (!a1) { a1 = strdup("?"); } switch (op->type) { case RZ_ANALYSIS_OP_TYPE_MOV: snprintf(ret, sizeof(ret), "%s = %s", r0, a0); break; case RZ_ANALYSIS_OP_TYPE_CJMP: if ((bb = rz_analysis_find_most_relevant_block_in(analysis, op->addr))) { cstr = rz_analysis_cond_to_string(bb->cond); snprintf(ret, sizeof(ret), "if (%s) goto 0x%" PFMT64x, cstr, op->jump); free(cstr); } else { snprintf(ret, sizeof(ret), "if (%s) goto 0x%" PFMT64x, "?", op->jump); } break; case RZ_ANALYSIS_OP_TYPE_JMP: snprintf(ret, sizeof(ret), "goto 0x%" PFMT64x, op->jump); break; case RZ_ANALYSIS_OP_TYPE_UJMP: case RZ_ANALYSIS_OP_TYPE_RJMP: case RZ_ANALYSIS_OP_TYPE_IJMP: case RZ_ANALYSIS_OP_TYPE_IRJMP: snprintf(ret, sizeof(ret), "goto %s", r0); break; case RZ_ANALYSIS_OP_TYPE_PUSH: case RZ_ANALYSIS_OP_TYPE_UPUSH: case RZ_ANALYSIS_OP_TYPE_RPUSH: snprintf(ret, sizeof(ret), "push %s", a0); break; case RZ_ANALYSIS_OP_TYPE_POP: snprintf(ret, sizeof(ret), "pop %s", r0); break; case RZ_ANALYSIS_OP_TYPE_UCALL: case RZ_ANALYSIS_OP_TYPE_RCALL: case RZ_ANALYSIS_OP_TYPE_ICALL: case RZ_ANALYSIS_OP_TYPE_IRCALL: snprintf(ret, sizeof(ret), "%s()", r0); break; case RZ_ANALYSIS_OP_TYPE_CALL: f = rz_analysis_get_fcn_in(analysis, op->jump, RZ_ANALYSIS_FCN_TYPE_NULL); if (f) { snprintf(ret, sizeof(ret), "%s()", f->name); } else { snprintf(ret, sizeof(ret), "0x%" PFMT64x "()", op->jump); } break; case RZ_ANALYSIS_OP_TYPE_CCALL: f = rz_analysis_get_fcn_in(analysis, op->jump, RZ_ANALYSIS_FCN_TYPE_NULL); if ((bb = rz_analysis_find_most_relevant_block_in(analysis, op->addr))) { cstr = rz_analysis_cond_to_string(bb->cond); if (f) { snprintf(ret, sizeof(ret), "if (%s) %s()", cstr, f->name); } else { snprintf(ret, sizeof(ret), "if (%s) 0x%" PFMT64x "()", cstr, op->jump); } free(cstr); } else { if (f) { snprintf(ret, sizeof(ret), "if (unk) %s()", f->name); } else { snprintf(ret, sizeof(ret), "if (unk) 0x%" PFMT64x "()", op->jump); } } break; case RZ_ANALYSIS_OP_TYPE_ADD: if (!a1 || !strcmp(a0, a1)) { snprintf(ret, sizeof(ret), "%s += %s", r0, a0); } else { snprintf(ret, sizeof(ret), "%s = %s + %s", r0, a0, a1); } break; case RZ_ANALYSIS_OP_TYPE_SUB: if (!a1 || !strcmp(a0, a1)) { snprintf(ret, sizeof(ret), "%s -= %s", r0, a0); } else { snprintf(ret, sizeof(ret), "%s = %s - %s", r0, a0, a1); } break; case RZ_ANALYSIS_OP_TYPE_MUL: if (!a1 || !strcmp(a0, a1)) { snprintf(ret, sizeof(ret), "%s *= %s", r0, a0); } else { snprintf(ret, sizeof(ret), "%s = %s * %s", r0, a0, a1); } break; case RZ_ANALYSIS_OP_TYPE_DIV: if (!a1 || !strcmp(a0, a1)) { snprintf(ret, sizeof(ret), "%s /= %s", r0, a0); } else { snprintf(ret, sizeof(ret), "%s = %s / %s", r0, a0, a1); } break; case RZ_ANALYSIS_OP_TYPE_AND: if (!a1 || !strcmp(a0, a1)) { snprintf(ret, sizeof(ret), "%s &= %s", r0, a0); } else { snprintf(ret, sizeof(ret), "%s = %s & %s", r0, a0, a1); } break; case RZ_ANALYSIS_OP_TYPE_OR: if (!a1 || !strcmp(a0, a1)) { snprintf(ret, sizeof(ret), "%s |= %s", r0, a0); } else { snprintf(ret, sizeof(ret), "%s = %s | %s", r0, a0, a1); } break; case RZ_ANALYSIS_OP_TYPE_XOR: if (!a1 || !strcmp(a0, a1)) { snprintf(ret, sizeof(ret), "%s ^= %s", r0, a0); } else { snprintf(ret, sizeof(ret), "%s = %s ^ %s", r0, a0, a1); } break; case RZ_ANALYSIS_OP_TYPE_LEA: snprintf(ret, sizeof(ret), "%s -> %s", r0, a0); break; case RZ_ANALYSIS_OP_TYPE_CMP: memcpy(ret, ";", 2); break; case RZ_ANALYSIS_OP_TYPE_NOP: memcpy(ret, "nop", 4); break; case RZ_ANALYSIS_OP_TYPE_RET: memcpy(ret, "ret", 4); break; case RZ_ANALYSIS_OP_TYPE_CRET: if ((bb = rz_analysis_find_most_relevant_block_in(analysis, op->addr))) { cstr = rz_analysis_cond_to_string(bb->cond); snprintf(ret, sizeof(ret), "if (%s) ret", cstr); free(cstr); } else { strcpy(ret, "if (unk) ret"); } break; case RZ_ANALYSIS_OP_TYPE_LEAVE: memcpy(ret, "leave", 6); break; case RZ_ANALYSIS_OP_TYPE_MOD: if (!a1 || !strcmp(a0, a1)) { snprintf(ret, sizeof(ret), "%s %%= %s", r0, a0); } else { snprintf(ret, sizeof(ret), "%s = %s %% %s", r0, a0, a1); } break; case RZ_ANALYSIS_OP_TYPE_XCHG: if (!a1 || !strcmp(a0, a1)) { snprintf(ret, sizeof(ret), "tmp = %s; %s = %s; %s = tmp", r0, r0, a0, a0); } else { snprintf(ret, sizeof(ret), "%s = %s ^ %s", r0, a0, a1); } break; case RZ_ANALYSIS_OP_TYPE_ROL: case RZ_ANALYSIS_OP_TYPE_ROR: case RZ_ANALYSIS_OP_TYPE_SWITCH: case RZ_ANALYSIS_OP_TYPE_CASE: eprintf("Command not implemented.\n"); free(r0); free(a0); free(a1); return NULL; default: free(r0); free(a0); free(a1); return NULL; } free(r0); free(a0); free(a1); return strdup(ret); } RZ_API const char *rz_analysis_stackop_tostring(int s) { switch (s) { case RZ_ANALYSIS_STACK_NULL: return "null"; case RZ_ANALYSIS_STACK_NOP: return "nop"; case RZ_ANALYSIS_STACK_INC: return "inc"; case RZ_ANALYSIS_STACK_GET: return "get"; case RZ_ANALYSIS_STACK_SET: return "set"; case RZ_ANALYSIS_STACK_RESET: return "reset"; } return "unk"; } RZ_API const char *rz_analysis_op_family_to_string(int n) { switch (n) { case RZ_ANALYSIS_OP_FAMILY_UNKNOWN: return "unk"; case RZ_ANALYSIS_OP_FAMILY_CPU: return "cpu"; case RZ_ANALYSIS_OP_FAMILY_SECURITY: return "sec"; case RZ_ANALYSIS_OP_FAMILY_FPU: return "fpu"; case RZ_ANALYSIS_OP_FAMILY_MMX: return "mmx"; case RZ_ANALYSIS_OP_FAMILY_SSE: return "sse"; case RZ_ANALYSIS_OP_FAMILY_PRIV: return "priv"; case RZ_ANALYSIS_OP_FAMILY_THREAD: return "thrd"; case RZ_ANALYSIS_OP_FAMILY_CRYPTO: return "crpt"; case RZ_ANALYSIS_OP_FAMILY_IO: return "io"; case RZ_ANALYSIS_OP_FAMILY_VIRT: return "virt"; } return NULL; } RZ_API int rz_analysis_op_family_from_string(const char *f) { struct op_family { const char *name; int id; }; static const struct op_family of[] = { { "cpu", RZ_ANALYSIS_OP_FAMILY_CPU }, { "fpu", RZ_ANALYSIS_OP_FAMILY_FPU }, { "mmx", RZ_ANALYSIS_OP_FAMILY_MMX }, { "sse", RZ_ANALYSIS_OP_FAMILY_SSE }, { "priv", RZ_ANALYSIS_OP_FAMILY_PRIV }, { "virt", RZ_ANALYSIS_OP_FAMILY_VIRT }, { "crpt", RZ_ANALYSIS_OP_FAMILY_CRYPTO }, { "io", RZ_ANALYSIS_OP_FAMILY_IO }, { "sec", RZ_ANALYSIS_OP_FAMILY_SECURITY }, { "thread", RZ_ANALYSIS_OP_FAMILY_THREAD }, }; int i; for (i = 0; i < sizeof(of) / sizeof(of[0]); i++) { if (!strcmp(f, of[i].name)) { return of[i].id; } } return RZ_ANALYSIS_OP_FAMILY_UNKNOWN; } /* apply hint to op, return the number of hints applied */ RZ_API int rz_analysis_op_hint(RzAnalysisOp *op, RzAnalysisHint *hint) { int changes = 0; if (hint) { if (hint->val != UT64_MAX) { op->val = hint->val; changes++; } if (hint->type > 0) { op->type = hint->type; changes++; } if (hint->jump != UT64_MAX) { op->jump = hint->jump; changes++; } if (hint->fail != UT64_MAX) { op->fail = hint->fail; changes++; } if (hint->opcode) { /* XXX: this is not correct */ free(op->mnemonic); op->mnemonic = strdup(hint->opcode); changes++; } if (hint->esil) { rz_strbuf_set(&op->esil, hint->esil); changes++; } if (hint->size) { op->size = hint->size; changes++; } } return changes; } // returns the '33' in 'rax + 33' // returns value for the given register name in specific address / range RZ_API int rz_analysis_op_reg_delta(RzAnalysis *analysis, ut64 addr, const char *name) { int delta = 0; ut8 buf[32]; analysis->iob.read_at(analysis->iob.io, addr, buf, sizeof(buf)); RzAnalysisOp op; rz_analysis_op_init(&op); if (rz_analysis_op(analysis, &op, addr, buf, sizeof(buf), RZ_ANALYSIS_OP_MASK_ALL) > 0) { if (op.dst && op.dst->reg && op.dst->reg->name && (!name || !strcmp(op.dst->reg->name, name))) { if (op.src[0]) { delta = op.src[0]->delta; } } } rz_analysis_op_fini(&op); return delta; }