diff --git a/librz/arch/isa/mips/mips_esil.c b/librz/arch/isa/mips/mips_esil.c new file mode 100644 index 00000000000..422968f2233 --- /dev/null +++ b/librz/arch/isa/mips/mips_esil.c @@ -0,0 +1,579 @@ +// SPDX-FileCopyrightText: 2013-2019 pancake +// SPDX-License-Identifier: LGPL-3.0-only + +#include "mips_internal.h" +#include +#include + +#define OPCOUNT() insn->detail->mips.op_count +#define REGID(x) insn->detail->mips.operands[x].reg +#define REG(x) cs_reg_name(*handle, insn->detail->mips.operands[x].reg) +#define IMM(x) insn->detail->mips.operands[x].imm + +// ESIL macros: +// put the sign bit on the stack +#define ES_IS_NEGATIVE(arg) "1," arg ",<<<,1,&" + +// call with delay slot +#define ES_CALL_DR(ra, addr) "pc,4,+," ra ",=," ES_J(addr) +#define ES_CALL_D(addr) ES_CALL_DR("ra", addr) + +// call without delay slot +#define ES_CALL_NDR(ra, addr) "pc," ra ",=," ES_J(addr) +#define ES_CALL_ND(addr) ES_CALL_NDR("ra", addr) + +#define USE_DS 0 +#if USE_DS +// emit ERR trap if executed in a delay slot +#define ES_TRAP_DS() "$ds,!,!,?{,$$,1,TRAP,BREAK,}," +// jump to address +#define ES_J(addr) addr ",SETJT,1,SETD" +#else +#define ES_TRAP_DS() "" +#define ES_J(addr) addr ",pc,=" +#endif + +#define ES_B(x) "0xff," x ",&" +#define ES_H(x) "0xffff," x ",&" +#define ES_W(x) "0xffffffff," x ",&" + +// sign extend 32 -> 64 +#define ES_SIGN32_64(arg) es_sign_n_64(a, op, arg, 32) +#define ES_SIGN16_64(arg) es_sign_n_64(a, op, arg, 16) + +#define ES_ADD_CK32_OVERF(x, y, z) es_add_ck(op, x, y, z, 32) +#define ES_ADD_CK64_OVERF(x, y, z) es_add_ck(op, x, y, z, 64) + +static inline void es_sign_n_64(RzAnalysis *a, RzAnalysisOp *op, const char *arg, int bit) { + if (a->bits == 64) { + rz_strbuf_appendf(&op->esil, ",%d,%s,~,%s,=,", bit, arg, arg); + } else { + rz_strbuf_append(&op->esil, ","); + } +} + +static inline void es_add_ck(RzAnalysisOp *op, const char *a1, const char *a2, const char *re, int bit) { + ut64 mask = 1ULL << (bit - 1); + rz_strbuf_appendf(&op->esil, + "%d,0x%" PFMT64x ",%s,%s,^,&,>>,%d,0x%" PFMT64x ",%s,%s,+,&,>>,|,1,==,$z,?{,$$,1,TRAP,}{,%s,%s,+,%s,=,}", + bit - 2, mask, a1, a2, bit - 1, mask, a1, a2, a1, a2, re); +} + +#if CS_NEXT_VERSION < 6 +#define PROTECT_ZERO() \ + if (REGID(0) == MIPS_REG_ZERO) { \ + rz_strbuf_appendf(&op->esil, ","); \ + } else +#else +#define PROTECT_ZERO() \ + if (REGID(0) == MIPS_REG_ZERO || \ + REGID(0) == MIPS_REG_ZERO_64) { \ + rz_strbuf_appendf(&op->esil, ","); \ + } else +#endif // CS_NEXT_VERSION + +#define ESIL_LOAD(size) \ + PROTECT_ZERO() { \ + rz_strbuf_appendf(&op->esil, "%s,[" size "],%s,=", \ + ARG(1), REG(0)); \ + } + +static const char *arg(csh *handle, cs_insn *insn, char *buf, int n) { + *buf = 0; + switch (insn->detail->mips.operands[n].type) { + case MIPS_OP_INVALID: + break; + case MIPS_OP_REG: + sprintf(buf, "%s", + cs_reg_name(*handle, + insn->detail->mips.operands[n].reg)); + break; + case MIPS_OP_IMM: { + st64 x = (st64)insn->detail->mips.operands[n].imm; + sprintf(buf, "%" PFMT64d, x); + } break; + case MIPS_OP_MEM: { + int disp = insn->detail->mips.operands[n].mem.disp; + if (disp < 0) { + sprintf(buf, "%" PFMT64d ",%s,-", + (ut64)-insn->detail->mips.operands[n].mem.disp, + cs_reg_name(*handle, + insn->detail->mips.operands[n].mem.base)); + } else { + sprintf(buf, "0x%" PFMT64x ",%s,+", + (ut64)insn->detail->mips.operands[n].mem.disp, + cs_reg_name(*handle, + insn->detail->mips.operands[n].mem.base)); + } + } break; + } + return buf; +} + +#define ARG(x) (*str[x] != 0) ? str[x] : arg(handle, insn, str[x], x) + +RZ_IPI int analyze_op_esil(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) { + char str[8][32] = { { 0 } }; + + rz_strbuf_init(&op->esil); + rz_strbuf_set(&op->esil, ""); + + if (!insn) { + return 0; + } + + // caching operands + for (int i = 0; i < insn->detail->mips.op_count && i < 8; i++) { + *str[i] = 0; + ARG(i); + } + { + switch (insn->id) { + case MIPS_INS_NOP: + rz_strbuf_setf(&op->esil, ","); + break; + case MIPS_INS_BREAK: + rz_strbuf_setf(&op->esil, "%" PFMT64d ",%" PFMT64d ",TRAP", (st64)IMM(0), (st64)IMM(0)); + break; + case MIPS_INS_SD: + rz_strbuf_appendf(&op->esil, "%s,%s,=[8]", + ARG(0), ARG(1)); + break; + case MIPS_INS_SW: + case MIPS_INS_SWL: + case MIPS_INS_SWR: + rz_strbuf_appendf(&op->esil, "%s,%s,=[4]", + ARG(0), ARG(1)); + break; + case MIPS_INS_SH: + rz_strbuf_appendf(&op->esil, "%s,%s,=[2]", + ARG(0), ARG(1)); + break; + case MIPS_INS_SWC1: + case MIPS_INS_SWC2: + rz_strbuf_setf(&op->esil, "%s,$", ARG(1)); + break; + case MIPS_INS_SB: + rz_strbuf_appendf(&op->esil, "%s,%s,=[1]", + ARG(0), ARG(1)); + break; +#if CS_NEXT_VERSION >= 6 + case MIPS_INS_CMPU_LE_QB: + case MIPS_INS_CMPGU_LE_QB: + case MIPS_INS_CMPGDU_LE_QB: + rz_strbuf_appendf(&op->esil, "%s,%s,<=", ARG(1), ARG(0)); + break; + case MIPS_INS_CMPU_LT_QB: + case MIPS_INS_CMPGU_LT_QB: + case MIPS_INS_CMPGDU_LT_QB: + rz_strbuf_appendf(&op->esil, "%s,%s,<", ARG(1), ARG(0)); + break; +#endif /* CS_NEXT_VERSION */ + case MIPS_INS_CMP: +#if CS_NEXT_VERSION < 6 + case MIPS_INS_CMPU: + case MIPS_INS_CMPGU: + case MIPS_INS_CMPGDU: +#else + case MIPS_INS_CMPU_EQ_QB: + case MIPS_INS_CMPGU_EQ_QB: + case MIPS_INS_CMPGDU_EQ_QB: +#endif /* CS_NEXT_VERSION */ + case MIPS_INS_CMPI: + rz_strbuf_appendf(&op->esil, "%s,%s,==", ARG(1), ARG(0)); + break; + case MIPS_INS_DSRA: + rz_strbuf_appendf(&op->esil, + "%s,%s,>>,31,%s,>>,?{,32,%s,32,-,0xffffffff,<<,0xffffffff,&,<<,}{,0,},|,%s,=", + ARG(2), ARG(1), ARG(1), ARG(2), ARG(0)); + break; +#if CS_NEXT_VERSION < 6 + case MIPS_INS_SHRAV: + case MIPS_INS_SHRAV_R: + case MIPS_INS_SHRA: + case MIPS_INS_SHRA_R: +#else + case MIPS_INS_SHRA_PH: + case MIPS_INS_SHRA_QB: + case MIPS_INS_SHRA_R_PH: + case MIPS_INS_SHRA_R_QB: + case MIPS_INS_SHRA_R_W: + case MIPS_INS_SHRAV_PH: + case MIPS_INS_SHRAV_QB: + case MIPS_INS_SHRAV_R_PH: + case MIPS_INS_SHRAV_R_QB: + case MIPS_INS_SHRAV_R_W: +#endif /* CS_NEXT_VERSION */ + case MIPS_INS_SRA: + rz_strbuf_appendf(&op->esil, + "0xffffffff,%s,%s,>>,&,31,%s,>>,?{,%s,32,-,0xffffffff,<<,0xffffffff,&,}{,0,},|,%s,=", + ARG(2), ARG(1), ARG(1), ARG(2), ARG(0)); + break; +#if CS_NEXT_VERSION < 6 + case MIPS_INS_SHRL: +#else + case MIPS_INS_SHRL_PH: + case MIPS_INS_SHRL_QB: + case MIPS_INS_SHRLV_PH: + case MIPS_INS_SHRLV_QB: +#endif /* CS_NEXT_VERSION */ + // suffix 'S' forces conditional flag to be updated + case MIPS_INS_SRLV: + case MIPS_INS_SRL: + rz_strbuf_appendf(&op->esil, "%s,%s,>>,%s,=", ARG(2), ARG(1), ARG(0)); + break; + case MIPS_INS_SLLV: + case MIPS_INS_SLL: +#if CS_NEXT_VERSION < 6 + rz_strbuf_appendf(&op->esil, "%s,%s,<<,%s,=", ARG(2), ARG(1), ARG(0)); +#else + if (REGID(0) == MIPS_REG_INVALID) { + // NOP + rz_strbuf_setf(&op->esil, ","); + } else { + rz_strbuf_appendf(&op->esil, "%s,%s,<<,%s,=", ARG(2), ARG(1), ARG(0)); + } +#endif /* CS_NEXT_VERSION */ + break; + case MIPS_INS_BAL: + case MIPS_INS_JAL: + rz_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) { + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_CALL_D("%s"), ARG(0)); + } else { + PROTECT_ZERO() { + rz_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) { + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_CALL_ND("%s"), ARG(0)); + } else { + PROTECT_ZERO() { + rz_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 + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,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 + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_J("%s"), ARG(0)); + break; + case MIPS_INS_BNE: // bne $s, $t, offset + case MIPS_INS_BNEL: + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,%s,==,$z,!,?{," ES_J("%s") ",}", + ARG(0), ARG(1), ARG(2)); + break; + case MIPS_INS_BEQ: + case MIPS_INS_BEQL: + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,%s,==,$z,?{," ES_J("%s") ",}", + ARG(0), ARG(1), ARG(2)); + break; +#if CS_NEXT_VERSION < 6 + case MIPS_INS_BZ: +#else + case MIPS_INS_BZ_B: + case MIPS_INS_BZ_D: + case MIPS_INS_BZ_H: + case MIPS_INS_BZ_V: + case MIPS_INS_BZ_W: +#endif /* CS_NEXT_VERSION */ + case MIPS_INS_BEQZ: + case MIPS_INS_BEQZC: + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,0,==,$z,?{," ES_J("%s") ",}", + ARG(0), ARG(1)); + break; + case MIPS_INS_BNEZ: + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,0,==,$z,!,?{," ES_J("%s") ",}", + ARG(0), ARG(1)); + break; + case MIPS_INS_BEQZALC: + rz_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: + case MIPS_INS_BLEZL: + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,%s,==,$z,?{," ES_J("%s") ",BREAK,},", + ARG(0), ARG(1)); + rz_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: + case MIPS_INS_BGEZL: + rz_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: + rz_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: + rz_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: + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,%s,==,$z,?{,BREAK,},", ARG(0)); + rz_strbuf_appendf(&op->esil, "0," ES_IS_NEGATIVE("%s") ",==,$z,?{," ES_CALL_ND("%s") ",}", + ARG(0), ARG(1)); + break; + case MIPS_INS_BLTZAL: + rz_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: + case MIPS_INS_BLTZL: + rz_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: + case MIPS_INS_BGTZL: + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,%s,==,$z,?{,BREAK,},", ARG(0)); + rz_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: + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,t,==,$z,?{," ES_J("%s") ",}", ARG(0)); + break; + case MIPS_INS_BTNEZ: + rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,t,==,$z,!,?{," ES_J("%s") ",}", ARG(0)); + break; +#if CS_NEXT_VERSION < 6 + case MIPS_INS_MOV: +#else + case MIPS_INS_MOV_D: + case MIPS_INS_MOV_S: +#endif /* CS_NEXT_VERSION */ + case MIPS_INS_MOVE: + PROTECT_ZERO() { + rz_strbuf_appendf(&op->esil, "%s,%s,=", ARG(1), REG(0)); + } + break; + case MIPS_INS_MOVZ: + case MIPS_INS_MOVF: + PROTECT_ZERO() { + rz_strbuf_appendf(&op->esil, "0,%s,==,$z,?{,%s,%s,=,}", + ARG(2), ARG(1), REG(0)); + } + break; + case MIPS_INS_MOVT: + PROTECT_ZERO() { + rz_strbuf_appendf(&op->esil, "1,%s,==,$z,?{,%s,%s,=,}", + ARG(2), ARG(1), REG(0)); + } + break; +#if CS_NEXT_VERSION < 6 + case MIPS_INS_FSUB: +#else + case MIPS_INS_FSUB_D: + case MIPS_INS_FSUB_W: +#endif /* CS_NEXT_VERSION */ + case MIPS_INS_SUB: + case MIPS_INS_SUBU: + case MIPS_INS_DSUB: + case MIPS_INS_DSUBU: + PROTECT_ZERO() { + rz_strbuf_appendf(&op->esil, "%s,%s,-,%s,=", + ARG(2), ARG(1), ARG(0)); + } + break; +#if CS_NEXT_VERSION < 6 + case MIPS_INS_NEGU: +#else + case MIPS_INS_NEG_D: + case MIPS_INS_NEG_S: +#endif /* CS_NEXT_VERSION */ + case MIPS_INS_NEG: + rz_strbuf_appendf(&op->esil, "%s,0,-,%s,=,", + ARG(1), ARG(0)); + break; + + /** signed -- sets overflow flag */ + case MIPS_INS_ADD: { + PROTECT_ZERO() { + ES_ADD_CK32_OVERF(ARG(1), ARG(2), ARG(0)); + } + } break; + case MIPS_INS_ADDI: + PROTECT_ZERO() { + ES_ADD_CK32_OVERF(ARG(1), ARG(2), ARG(0)); + } + break; + case MIPS_INS_DADD: + case MIPS_INS_DADDI: + ES_ADD_CK64_OVERF(ARG(1), ARG(2), ARG(0)); + break; + /** unsigned */ + case MIPS_INS_DADDU: + 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 == '-') { + rz_strbuf_appendf(&op->esil, "%s,%s,-,%s,=", + arg2 + 1, arg1, arg0); + } else { + rz_strbuf_appendf(&op->esil, "%s,%s,+,%s,=", + arg2, arg1, arg0); + } + } + } break; + case MIPS_INS_LI: +#if CS_NEXT_VERSION < 6 + case MIPS_INS_LDI: +#else + case MIPS_INS_LDI_B: + case MIPS_INS_LDI_D: + case MIPS_INS_LDI_H: + case MIPS_INS_LDI_W: +#endif /* CS_NEXT_VERSION */ + rz_strbuf_appendf(&op->esil, "0x%" PFMT64x ",%s,=", (ut64)IMM(1), ARG(0)); + break; + case MIPS_INS_LUI: + rz_strbuf_appendf(&op->esil, "0x%" PFMT64x "0000,%s,=", (ut64)IMM(1), ARG(0)); + break; + case MIPS_INS_LB: + op->sign = true; + ESIL_LOAD("1"); + break; + case MIPS_INS_LBU: + case MIPS_INS_LBUX: + // one of these is wrong + ESIL_LOAD("1"); + break; + case MIPS_INS_LL: + 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_LWXC1: + ESIL_LOAD("4"); + break; + + case MIPS_INS_LD: + case MIPS_INS_LDC1: + case MIPS_INS_LDC2: + case MIPS_INS_LDL: + case MIPS_INS_LDR: + case MIPS_INS_LDXC1: + case MIPS_INS_LLD: + ESIL_LOAD("8"); + 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); + if (!strcmp(arg0, arg1)) { + rz_strbuf_appendf(&op->esil, "%s,%s,&=", arg2, arg1); + } else { + rz_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() { + rz_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() { + rz_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() { + rz_strbuf_appendf(&op->esil, "%s,%s,|,0xffffffff,^,%s,=", + arg2, arg1, arg0); + } + } break; + case MIPS_INS_SLT: + case MIPS_INS_SLTI: + if (OPCOUNT() < 3) { + rz_strbuf_appendf(&op->esil, "%s,%s,<,t,=", ARG(1), ARG(0)); + } else { + rz_strbuf_appendf(&op->esil, "%s,%s,<,%s,=", ARG(2), ARG(1), ARG(0)); + } + break; + case MIPS_INS_SLTU: + case MIPS_INS_SLTIU: + if (OPCOUNT() < 3) { + rz_strbuf_appendf(&op->esil, ES_W("%s") "," ES_W("%s") ",<,t,=", + ARG(1), ARG(0)); + } else { + rz_strbuf_appendf(&op->esil, ES_W("%s") "," ES_W("%s") ",<,%s,=", + ARG(2), ARG(1), ARG(0)); + } + break; + case MIPS_INS_MUL: + rz_strbuf_appendf(&op->esil, ES_W("%s,%s,*") ",%s,=", ARG(1), ARG(2), ARG(0)); + ES_SIGN32_64(ARG(0)); + break; + case MIPS_INS_MULT: + case MIPS_INS_MULTU: + rz_strbuf_appendf(&op->esil, ES_W("%s,%s,*") ",lo,=", ARG(0), ARG(1)); + ES_SIGN32_64("lo"); + rz_strbuf_appendf(&op->esil, ES_W("32,%s,%s,*,>>") ",hi,=", ARG(0), ARG(1)); + ES_SIGN32_64("hi"); + break; + case MIPS_INS_MFLO: + PROTECT_ZERO() { + rz_strbuf_appendf(&op->esil, "lo,%s,=", REG(0)); + } + break; + case MIPS_INS_MFHI: + PROTECT_ZERO() { + rz_strbuf_appendf(&op->esil, "hi,%s,=", REG(0)); + } + break; + case MIPS_INS_MTLO: + rz_strbuf_appendf(&op->esil, "%s,lo,=", REG(0)); + ES_SIGN32_64("lo"); + break; + case MIPS_INS_MTHI: + rz_strbuf_appendf(&op->esil, "%s,hi,=", REG(0)); + ES_SIGN32_64("hi"); + break; + default: + return -1; + } + } + return 0; +} diff --git a/librz/arch/isa/mips/mips_internal.h b/librz/arch/isa/mips/mips_internal.h new file mode 100644 index 00000000000..dd2d3e5e40e --- /dev/null +++ b/librz/arch/isa/mips/mips_internal.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2012-2018 pancake +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef MIPS_INTERNAL_H +#define MIPS_INTERNAL_H + +#include +#include +#include + +RZ_IPI int mips_assemble_opcode(const char *str, ut64 pc, ut8 *out); +RZ_IPI int analyze_op_esil(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn); + +#endif /* MIPS_INTERNAL_H */ diff --git a/librz/arch/meson.build b/librz/arch/meson.build index ed380c5ecb5..5b4ea541ab5 100644 --- a/librz/arch/meson.build +++ b/librz/arch/meson.build @@ -218,6 +218,7 @@ arch_isa_sources = [ 'isa/luac/v54/opcode_54.c', 'isa/mcore/mcore.c', 'isa/mips/mips_assembler.c', + 'isa/mips/mips_esil.c', 'isa/msp430/msp430_disas.c', 'isa/msp430/msp430_il.c', 'isa/or1k/or1k_disas.c', diff --git a/librz/arch/p/analysis/analysis_mips_cs.c b/librz/arch/p/analysis/analysis_mips_cs.c index ed64921ff8d..3ceb7e62cd3 100644 --- a/librz/arch/p/analysis/analysis_mips_cs.c +++ b/librz/arch/p/analysis/analysis_mips_cs.c @@ -1,10 +1,10 @@ +// SPDX-FileCopyrightText: 2024 deroad // SPDX-FileCopyrightText: 2013-2019 pancake // SPDX-License-Identifier: LGPL-3.0-only #include #include -#include -#include +#include static ut64 t9_pre = UT64_MAX; // http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html @@ -63,67 +63,6 @@ static ut64 t9_pre = UT64_MAX; SET_SRC_DST_3_REGS(op); \ } -// ESIL macros: - -// put the sign bit on the stack -#define ES_IS_NEGATIVE(arg) "1," arg ",<<<,1,&" - -// call with delay slot -#define ES_CALL_DR(ra, addr) "pc,4,+," ra ",=," ES_J(addr) -#define ES_CALL_D(addr) ES_CALL_DR("ra", addr) - -// call without delay slot -#define ES_CALL_NDR(ra, addr) "pc," ra ",=," ES_J(addr) -#define ES_CALL_ND(addr) ES_CALL_NDR("ra", addr) - -#define USE_DS 0 -#if USE_DS -// emit ERR trap if executed in a delay slot -#define ES_TRAP_DS() "$ds,!,!,?{,$$,1,TRAP,BREAK,}," -// jump to address -#define ES_J(addr) addr ",SETJT,1,SETD" -#else -#define ES_TRAP_DS() "" -#define ES_J(addr) addr ",pc,=" -#endif - -#define ES_B(x) "0xff," x ",&" -#define ES_H(x) "0xffff," x ",&" -#define ES_W(x) "0xffffffff," x ",&" - -// sign extend 32 -> 64 -#define ES_SIGN32_64(arg) es_sign_n_64(a, op, arg, 32) -#define ES_SIGN16_64(arg) es_sign_n_64(a, op, arg, 16) - -#define ES_ADD_CK32_OVERF(x, y, z) es_add_ck(op, x, y, z, 32) -#define ES_ADD_CK64_OVERF(x, y, z) es_add_ck(op, x, y, z, 64) - -static inline void es_sign_n_64(RzAnalysis *a, RzAnalysisOp *op, const char *arg, int bit) { - if (a->bits == 64) { - rz_strbuf_appendf(&op->esil, ",%d,%s,~,%s,=,", bit, arg, arg); - } else { - rz_strbuf_append(&op->esil, ","); - } -} - -static inline void es_add_ck(RzAnalysisOp *op, const char *a1, const char *a2, const char *re, int bit) { - ut64 mask = 1ULL << (bit - 1); - rz_strbuf_appendf(&op->esil, - "%d,0x%" PFMT64x ",%s,%s,^,&,>>,%d,0x%" PFMT64x ",%s,%s,+,&,>>,|,1,==,$z,?{,$$,1,TRAP,}{,%s,%s,+,%s,=,}", - bit - 2, mask, a1, a2, bit - 1, mask, a1, a2, a1, a2, re); -} - -#define PROTECT_ZERO() \ - if (REG(0)[0] == 'z') { \ - rz_strbuf_appendf(&op->esil, ","); \ - } else - -#define ESIL_LOAD(size) \ - PROTECT_ZERO() { \ - rz_strbuf_appendf(&op->esil, "%s,[" size "],%s,=", \ - ARG(1), REG(0)); \ - } - static void opex(RzStrBuf *buf, csh handle, cs_insn *insn) { int i; PJ *pj = pj_new(); @@ -166,439 +105,6 @@ static void opex(RzStrBuf *buf, csh handle, cs_insn *insn) { pj_free(pj); } -static const char *arg(csh *handle, cs_insn *insn, char *buf, int n) { - *buf = 0; - switch (insn->detail->mips.operands[n].type) { - case MIPS_OP_INVALID: - break; - case MIPS_OP_REG: - sprintf(buf, "%s", - cs_reg_name(*handle, - insn->detail->mips.operands[n].reg)); - break; - case MIPS_OP_IMM: { - st64 x = (st64)insn->detail->mips.operands[n].imm; - sprintf(buf, "%" PFMT64d, x); - } break; - case MIPS_OP_MEM: { - int disp = insn->detail->mips.operands[n].mem.disp; - if (disp < 0) { - sprintf(buf, "%" PFMT64d ",%s,-", - (ut64)-insn->detail->mips.operands[n].mem.disp, - cs_reg_name(*handle, - insn->detail->mips.operands[n].mem.base)); - } else { - sprintf(buf, "0x%" PFMT64x ",%s,+", - (ut64)insn->detail->mips.operands[n].mem.disp, - cs_reg_name(*handle, - insn->detail->mips.operands[n].mem.base)); - } - } break; - } - return buf; -} - -#define ARG(x) (*str[x] != 0) ? str[x] : arg(handle, insn, str[x], x) - -static int analyze_op_esil(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) { - char str[8][32] = { { 0 } }; - int i; - - rz_strbuf_init(&op->esil); - rz_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: - rz_strbuf_setf(&op->esil, ","); - break; - case MIPS_INS_BREAK: - rz_strbuf_setf(&op->esil, "%" PFMT64d ",%" PFMT64d ",TRAP", (st64)IMM(0), (st64)IMM(0)); - break; - case MIPS_INS_SD: - rz_strbuf_appendf(&op->esil, "%s,%s,=[8]", - ARG(0), ARG(1)); - break; - case MIPS_INS_SW: - case MIPS_INS_SWL: - case MIPS_INS_SWR: - rz_strbuf_appendf(&op->esil, "%s,%s,=[4]", - ARG(0), ARG(1)); - break; - case MIPS_INS_SH: - rz_strbuf_appendf(&op->esil, "%s,%s,=[2]", - ARG(0), ARG(1)); - break; - case MIPS_INS_SWC1: - case MIPS_INS_SWC2: - rz_strbuf_setf(&op->esil, "%s,$", ARG(1)); - break; - case MIPS_INS_SB: - rz_strbuf_appendf(&op->esil, "%s,%s,=[1]", - ARG(0), ARG(1)); - break; - case MIPS_INS_CMP: -#if CS_NEXT_VERSION < 6 - case MIPS_INS_CMPU: - case MIPS_INS_CMPGU: - case MIPS_INS_CMPGDU: -#endif - case MIPS_INS_CMPI: - rz_strbuf_appendf(&op->esil, "%s,%s,==", ARG(1), ARG(0)); - break; - case MIPS_INS_DSRA: - rz_strbuf_appendf(&op->esil, - "%s,%s,>>,31,%s,>>,?{,32,%s,32,-,0xffffffff,<<,0xffffffff,&,<<,}{,0,},|,%s,=", - ARG(2), ARG(1), ARG(1), ARG(2), ARG(0)); - break; -#if CS_NEXT_VERSION < 6 - case MIPS_INS_SHRAV: - case MIPS_INS_SHRAV_R: - case MIPS_INS_SHRA: - case MIPS_INS_SHRA_R: - case MIPS_INS_SRA: - rz_strbuf_appendf(&op->esil, - "0xffffffff,%s,%s,>>,&,31,%s,>>,?{,%s,32,-,0xffffffff,<<,0xffffffff,&,}{,0,},|,%s,=", - ARG(2), ARG(1), ARG(1), 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: - rz_strbuf_appendf(&op->esil, "%s,%s,>>,%s,=", ARG(2), ARG(1), ARG(0)); - break; -#endif - case MIPS_INS_SLLV: - case MIPS_INS_SLL: - rz_strbuf_appendf(&op->esil, "%s,%s,<<,%s,=", ARG(2), ARG(1), ARG(0)); - break; - case MIPS_INS_BAL: - case MIPS_INS_JAL: - rz_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) { - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_CALL_D("%s"), ARG(0)); - } else { - PROTECT_ZERO() { - rz_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) { - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_CALL_ND("%s"), ARG(0)); - } else { - PROTECT_ZERO() { - rz_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 - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,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 - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_J("%s"), ARG(0)); - break; - case MIPS_INS_BNE: // bne $s, $t, offset - case MIPS_INS_BNEL: - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,%s,==,$z,!,?{," ES_J("%s") ",}", - ARG(0), ARG(1), ARG(2)); - break; - case MIPS_INS_BEQ: - case MIPS_INS_BEQL: - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,%s,==,$z,?{," ES_J("%s") ",}", - ARG(0), ARG(1), ARG(2)); - break; -#if CS_NEXT_VERSION < 6 - case MIPS_INS_BZ: -#endif - case MIPS_INS_BEQZ: - case MIPS_INS_BEQZC: - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,0,==,$z,?{," ES_J("%s") ",}", - ARG(0), ARG(1)); - break; - case MIPS_INS_BNEZ: - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,0,==,$z,!,?{," ES_J("%s") ",}", - ARG(0), ARG(1)); - break; - case MIPS_INS_BEQZALC: - rz_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: - case MIPS_INS_BLEZL: - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,%s,==,$z,?{," ES_J("%s") ",BREAK,},", - ARG(0), ARG(1)); - rz_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: - case MIPS_INS_BGEZL: - rz_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: - rz_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: - rz_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: - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,%s,==,$z,?{,BREAK,},", ARG(0)); - rz_strbuf_appendf(&op->esil, "0," ES_IS_NEGATIVE("%s") ",==,$z,?{," ES_CALL_ND("%s") ",}", - ARG(0), ARG(1)); - break; - case MIPS_INS_BLTZAL: - rz_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: - case MIPS_INS_BLTZL: - rz_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: - case MIPS_INS_BGTZL: - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,%s,==,$z,?{,BREAK,},", ARG(0)); - rz_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: - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,t,==,$z,?{," ES_J("%s") ",}", ARG(0)); - break; - case MIPS_INS_BTNEZ: - rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0,t,==,$z,!,?{," ES_J("%s") ",}", ARG(0)); - break; -#if CS_NEXT_VERSION < 6 - case MIPS_INS_MOV: -#endif - case MIPS_INS_MOVE: - PROTECT_ZERO() { - rz_strbuf_appendf(&op->esil, "%s,%s,=", ARG(1), REG(0)); - } - break; - case MIPS_INS_MOVZ: - case MIPS_INS_MOVF: - PROTECT_ZERO() { - rz_strbuf_appendf(&op->esil, "0,%s,==,$z,?{,%s,%s,=,}", - ARG(2), ARG(1), REG(0)); - } - break; - case MIPS_INS_MOVT: - PROTECT_ZERO() { - rz_strbuf_appendf(&op->esil, "1,%s,==,$z,?{,%s,%s,=,}", - ARG(2), ARG(1), REG(0)); - } - break; -#if CS_NEXT_VERSION < 6 - case MIPS_INS_FSUB: -#endif - case MIPS_INS_SUB: - case MIPS_INS_SUBU: - case MIPS_INS_DSUB: - case MIPS_INS_DSUBU: - PROTECT_ZERO() { - rz_strbuf_appendf(&op->esil, "%s,%s,-,%s,=", - ARG(2), ARG(1), ARG(0)); - } - break; - case MIPS_INS_NEG: -#if CS_NEXT_VERSION < 6 - case MIPS_INS_NEGU: -#endif - rz_strbuf_appendf(&op->esil, "%s,0,-,%s,=,", - ARG(1), ARG(0)); - break; - - /** signed -- sets overflow flag */ - case MIPS_INS_ADD: { - PROTECT_ZERO() { - ES_ADD_CK32_OVERF(ARG(1), ARG(2), ARG(0)); - } - } break; - case MIPS_INS_ADDI: - PROTECT_ZERO() { - ES_ADD_CK32_OVERF(ARG(1), ARG(2), ARG(0)); - } - break; - case MIPS_INS_DADD: - case MIPS_INS_DADDI: - ES_ADD_CK64_OVERF(ARG(1), ARG(2), ARG(0)); - break; - /** unsigned */ - case MIPS_INS_DADDU: - 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 == '-') { - rz_strbuf_appendf(&op->esil, "%s,%s,-,%s,=", - arg2 + 1, arg1, arg0); - } else { - rz_strbuf_appendf(&op->esil, "%s,%s,+,%s,=", - arg2, arg1, arg0); - } - } - } break; - case MIPS_INS_LI: -#if CS_NEXT_VERSION < 6 - case MIPS_INS_LDI: -#endif - rz_strbuf_appendf(&op->esil, "0x%" PFMT64x ",%s,=", (ut64)IMM(1), ARG(0)); - break; - case MIPS_INS_LUI: - rz_strbuf_appendf(&op->esil, "0x%" PFMT64x "0000,%s,=", (ut64)IMM(1), ARG(0)); - break; - case MIPS_INS_LB: - op->sign = true; - ESIL_LOAD("1"); - break; - 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: - ESIL_LOAD("4"); - break; - - case MIPS_INS_LDL: - case MIPS_INS_LDC1: - case MIPS_INS_LDC2: - case MIPS_INS_LLD: - case MIPS_INS_LD: - ESIL_LOAD("8"); - 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); - if (!strcmp(arg0, arg1)) { - rz_strbuf_appendf(&op->esil, "%s,%s,&=", arg2, arg1); - } else { - rz_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() { - rz_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() { - rz_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() { - rz_strbuf_appendf(&op->esil, "%s,%s,|,0xffffffff,^,%s,=", - arg2, arg1, arg0); - } - } break; - case MIPS_INS_SLT: - case MIPS_INS_SLTI: - if (OPCOUNT() < 3) { - rz_strbuf_appendf(&op->esil, "%s,%s,<,t,=", ARG(1), ARG(0)); - } else { - rz_strbuf_appendf(&op->esil, "%s,%s,<,%s,=", ARG(2), ARG(1), ARG(0)); - } - break; - case MIPS_INS_SLTU: - case MIPS_INS_SLTIU: - if (OPCOUNT() < 3) { - rz_strbuf_appendf(&op->esil, ES_W("%s") "," ES_W("%s") ",<,t,=", - ARG(1), ARG(0)); - } else { - rz_strbuf_appendf(&op->esil, ES_W("%s") "," ES_W("%s") ",<,%s,=", - ARG(2), ARG(1), ARG(0)); - } - break; - case MIPS_INS_MUL: - rz_strbuf_appendf(&op->esil, ES_W("%s,%s,*") ",%s,=", ARG(1), ARG(2), ARG(0)); - ES_SIGN32_64(ARG(0)); - break; - case MIPS_INS_MULT: - case MIPS_INS_MULTU: - rz_strbuf_appendf(&op->esil, ES_W("%s,%s,*") ",lo,=", ARG(0), ARG(1)); - ES_SIGN32_64("lo"); - rz_strbuf_appendf(&op->esil, ES_W("32,%s,%s,*,>>") ",hi,=", ARG(0), ARG(1)); - ES_SIGN32_64("hi"); - break; - case MIPS_INS_MFLO: - PROTECT_ZERO() { - rz_strbuf_appendf(&op->esil, "lo,%s,=", REG(0)); - } - break; - case MIPS_INS_MFHI: - PROTECT_ZERO() { - rz_strbuf_appendf(&op->esil, "hi,%s,=", REG(0)); - } - break; - case MIPS_INS_MTLO: - rz_strbuf_appendf(&op->esil, "%s,lo,=", REG(0)); - ES_SIGN32_64("lo"); - break; - case MIPS_INS_MTHI: - rz_strbuf_appendf(&op->esil, "%s,hi,=", REG(0)); - ES_SIGN32_64("hi"); - break; - default: - return -1; - } - } - return 0; -} - static int parse_reg_name(RzRegItem *reg, csh handle, cs_insn *insn, int reg_num) { if (!reg) { return -1; @@ -709,31 +215,11 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u int n = 0, opsize = -1; csh hndl = 0; cs_insn *insn = NULL; - int mode = analysis->big_endian ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN; - - if (analysis->cpu && *analysis->cpu) { - if (!strcmp(analysis->cpu, "micro")) { - mode |= CS_MODE_MICRO; - } else if (!strcmp(analysis->cpu, "r6")) { - mode |= CS_MODE_MIPS32R6; - } else if (!strcmp(analysis->cpu, "v3")) { - mode |= CS_MODE_MIPS3; - } else if (!strcmp(analysis->cpu, "v2")) { - mode |= CS_MODE_MIPS2; - } - } - switch (analysis->bits) { - case 64: - mode |= CS_MODE_MIPS64; - break; - case 32: - mode |= CS_MODE_MIPS32; - break; - default: + cs_mode mode = 0; + if (!cs_mode_from_cpu(analysis->cpu, analysis->bits, analysis->big_endian, &mode)) { return -1; } - // XXX no arch->cpu ?!?! CS_MODE_MICRO, N64 op->addr = addr; if (len < 4) { return -1; @@ -786,12 +272,14 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u case MIPS_INS_LDL: case MIPS_INS_LDR: case MIPS_INS_LDXC1: + op->delay = 1; op->type = RZ_ANALYSIS_OP_TYPE_LOAD; if (!op->refptr) { op->refptr = 8; } switch (OPERAND(1).type) { case MIPS_OP_MEM: +#if CS_NEXT_VERSION < 6 if (OPERAND(1).mem.base == MIPS_REG_GP) { op->ptr = analysis->gp + OPERAND(1).mem.disp; if (REGID(0) == MIPS_REG_T9) { @@ -800,6 +288,19 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u } else if (REGID(0) == MIPS_REG_T9) { t9_pre = UT64_MAX; } +#else + if (OPERAND(1).mem.base == MIPS_REG_GP || + OPERAND(1).mem.base == MIPS_REG_GP_64) { + op->ptr = analysis->gp + OPERAND(1).mem.disp; + if (REGID(0) == MIPS_REG_T9 || + REGID(0) == MIPS_REG_T9_64) { + t9_pre = op->ptr; + } + } else if (REGID(0) == MIPS_REG_T9 || + REGID(0) == MIPS_REG_T9_64) { + t9_pre = UT64_MAX; + } +#endif break; case MIPS_OP_IMM: op->ptr = OPERAND(1).imm; @@ -809,7 +310,6 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u default: break; } - // TODO: fill break; case MIPS_INS_SD: case MIPS_INS_SW: @@ -820,6 +320,7 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u case MIPS_INS_SWL: case MIPS_INS_SWR: case MIPS_INS_SWXC1: + op->delay = 1; op->type = RZ_ANALYSIS_OP_TYPE_STORE; break; case MIPS_INS_NOP: @@ -831,9 +332,16 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u case MIPS_INS_BREAK: op->type = RZ_ANALYSIS_OP_TYPE_TRAP; break; +#if CS_NEXT_VERSION > 5 + case MIPS_INS_JALR_HB: + case MIPS_INS_JALRC: + case MIPS_INS_JALRC_HB: + case MIPS_INS_JALRS: + case MIPS_INS_JALRS16: +#endif /* CS_NEXT_VERSION */ case MIPS_INS_JALR: - op->type = RZ_ANALYSIS_OP_TYPE_UCALL; op->delay = 1; + op->type = RZ_ANALYSIS_OP_TYPE_UCALL; #if CS_NEXT_VERSION < 6 if (REGID(0) == MIPS_REG_25) { op->jump = t9_pre; @@ -849,40 +357,56 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u } #endif break; +#if CS_NEXT_VERSION >= 6 + case MIPS_INS_JRCADDIUSP: + op->delay = 0; + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + op->jump = IMM(0); + break; +#endif case MIPS_INS_JAL: case MIPS_INS_JALS: case MIPS_INS_JALX: case MIPS_INS_JRADDIUSP: case MIPS_INS_BAL: - // (no blezal/bgtzal or blezall/bgtzall, only blezalc/bgtzalc) - case MIPS_INS_BLTZAL: // Branch on <0 and link + op->delay = 1; + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + op->jump = IMM(0); + break; + case MIPS_INS_JIALC: + op->delay = 0; + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + op->jump = IMM(0); + break; case MIPS_INS_BGEZAL: // Branch on >=0 and link + case MIPS_INS_BLTZAL: // Branch on <0 and link case MIPS_INS_BLTZALL: // "likely" versions case MIPS_INS_BGEZALL: - case MIPS_INS_BLTZALC: // compact versions - case MIPS_INS_BLEZALC: + op->delay = 1; + if (OPERAND(0).type == MIPS_OP_IMM) { + // this is a JAL + op->jump = IMM(0); + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + } else { + op->jump = IMM(1); + op->fail = addr + (insn->size << 1); + op->type = RZ_ANALYSIS_OP_TYPE_CCALL; + } + break; case MIPS_INS_BGEZALC: + case MIPS_INS_BLTZALC: + case MIPS_INS_BLEZALC: case MIPS_INS_BGTZALC: - case MIPS_INS_JIALC: - case MIPS_INS_JIC: - op->type = RZ_ANALYSIS_OP_TYPE_CALL; - op->jump = IMM(0); - - switch (insn->id) { - case MIPS_INS_JIALC: - case MIPS_INS_JIC: - case MIPS_INS_BLTZALC: - case MIPS_INS_BLEZALC: - case MIPS_INS_BGEZALC: - case MIPS_INS_BGTZALC: - // compact versions (no delay) - op->delay = 0; - op->fail = addr + 4; - break; - default: - op->delay = 1; - op->fail = addr + 8; - break; + // compact versions + op->delay = 0; + if (OPERAND(0).type == MIPS_OP_IMM) { + // this is a JAL + op->jump = IMM(0); + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + } else { + op->jump = IMM(1); + op->fail = addr + (insn->size << 1); + op->type = RZ_ANALYSIS_OP_TYPE_CCALL; } break; case MIPS_INS_LI: @@ -901,7 +425,7 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u case MIPS_INS_DADDI: case MIPS_INS_DADDIU: SET_VAL(op, 2); - op->sign = (insn->id == MIPS_INS_ADDI || insn->id == MIPS_INS_ADD); + op->sign = (insn->id == MIPS_INS_ADDI || insn->id == MIPS_INS_ADD || insn->id == MIPS_INS_DADD); op->type = RZ_ANALYSIS_OP_TYPE_ADD; if (REGID(0) == MIPS_REG_T9) { t9_pre += IMM(2); @@ -911,6 +435,10 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u op->stackptr = -IMM(2); } break; + case MIPS_INS_SUB: + case MIPS_INS_SUBU: + case MIPS_INS_DSUBU: + case MIPS_INS_DSUB: #if CS_NEXT_VERSION < 6 case MIPS_INS_SUBV: case MIPS_INS_SUBVI: @@ -920,11 +448,30 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u case MIPS_INS_SUBS_U: case MIPS_INS_SUBUH: case MIPS_INS_SUBUH_R: -#endif - case MIPS_INS_SUB: - case MIPS_INS_DSUBU: - case MIPS_INS_SUBU: - case MIPS_INS_DSUB: +#else + case MIPS_INS_SUBV_B: + case MIPS_INS_SUBV_D: + case MIPS_INS_SUBV_H: + case MIPS_INS_SUBV_W: + case MIPS_INS_SUBVI_B: + case MIPS_INS_SUBVI_D: + case MIPS_INS_SUBVI_H: + case MIPS_INS_SUBVI_W: + case MIPS_INS_FSUB_D: + case MIPS_INS_FSUB_W: + case MIPS_INS_FMSUB_D: + case MIPS_INS_FMSUB_W: + case MIPS_INS_SUBS_S_B: + case MIPS_INS_SUBS_S_D: + case MIPS_INS_SUBS_S_H: + case MIPS_INS_SUBS_S_W: + case MIPS_INS_SUBS_U_B: + case MIPS_INS_SUBS_U_D: + case MIPS_INS_SUBS_U_H: + case MIPS_INS_SUBS_U_W: + case MIPS_INS_SUBUH_QB: + case MIPS_INS_SUBUH_R_QB: +#endif /* CS_NEXT_VERSION */ SET_VAL(op, 2); op->sign = insn->id == MIPS_INS_SUB; op->type = RZ_ANALYSIS_OP_TYPE_SUB; @@ -933,7 +480,16 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u case MIPS_INS_MULV: case MIPS_INS_MULSA: case MIPS_INS_FMUL: -#endif +#else + case MIPS_INS_MULV_B: + case MIPS_INS_MULV_D: + case MIPS_INS_MULV_H: + case MIPS_INS_MULV_W: + case MIPS_INS_MULSA_W_PH: + case MIPS_INS_MULSAQ_S_W_PH: + case MIPS_INS_FMUL_D: + case MIPS_INS_FMUL_W: +#endif /* CS_NEXT_VERSION */ case MIPS_INS_MULT: case MIPS_INS_MUL: case MIPS_INS_DMULT: @@ -965,28 +521,149 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u case MIPS_INS_DIVU: case MIPS_INS_DDIV: case MIPS_INS_DDIVU: - case MIPS_INS_DIV_S: #if CS_NEXT_VERSION < 6 case MIPS_INS_FDIV: case MIPS_INS_DIV_U: -#endif +#else + case MIPS_INS_FDIV_D: + case MIPS_INS_FDIV_W: + case MIPS_INS_DIV_U_B: + case MIPS_INS_DIV_U_D: + case MIPS_INS_DIV_U_H: + case MIPS_INS_DIV_U_W: +#endif /* CS_NEXT_VERSION */ + case MIPS_INS_DIV_S: op->type = RZ_ANALYSIS_OP_TYPE_DIV; break; #if CS_NEXT_VERSION < 6 - case MIPS_INS_CMPGDU: - case MIPS_INS_CMPGU: case MIPS_INS_CMPU: -#endif + case MIPS_INS_CMPGU: + case MIPS_INS_CMPGDU: +#else + case MIPS_INS_CMPU_EQ_QB: + case MIPS_INS_CMPGU_EQ_QB: + case MIPS_INS_CMPGDU_EQ_QB: +#endif /* CS_NEXT_VERSION */ case MIPS_INS_CMPI: + case MIPS_INS_CMP: op->type = RZ_ANALYSIS_OP_TYPE_CMP; break; + case MIPS_INS_JIC: + op->delay = 0; + op->jump = IMM(0); + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + break; + case MIPS_INS_J: + op->delay = 1; + op->jump = IMM(0); + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + break; #if CS_NEXT_VERSION < 6 case MIPS_INS_BZ: case MIPS_INS_BNZ: case MIPS_INS_BNEG: case MIPS_INS_BNEGI: -#endif - case MIPS_INS_J: +#else + case MIPS_INS_BZ_B: + case MIPS_INS_BZ_D: + case MIPS_INS_BZ_H: + case MIPS_INS_BZ_V: + case MIPS_INS_BZ_W: + case MIPS_INS_BNZ_B: + case MIPS_INS_BNZ_D: + case MIPS_INS_BNZ_H: + case MIPS_INS_BNZ_V: + case MIPS_INS_BNZ_W: + case MIPS_INS_BNEG_B: + case MIPS_INS_BNEG_D: + case MIPS_INS_BNEG_H: + case MIPS_INS_BNEG_W: + case MIPS_INS_BNEGI_B: + case MIPS_INS_BNEGI_D: + case MIPS_INS_BNEGI_H: + case MIPS_INS_BNEGI_W: + case MIPS_INS_BGE: + case MIPS_INS_BGEL: + case MIPS_INS_BGEU: + case MIPS_INS_BGEUL: + case MIPS_INS_BGT: + case MIPS_INS_BGTL: + case MIPS_INS_BGTU: + case MIPS_INS_BGTUL: + case MIPS_INS_BLE: + case MIPS_INS_BLEL: + case MIPS_INS_BLEU: + case MIPS_INS_BLEUL: + case MIPS_INS_BLT: + case MIPS_INS_BLTL: + case MIPS_INS_BLTU: + case MIPS_INS_BLTUL: + case MIPS_INS_B16: + case MIPS_INS_BADDU: + case MIPS_INS_BALC: + case MIPS_INS_BALIGN: + case MIPS_INS_BALRSC: + case MIPS_INS_BBEQZC: + case MIPS_INS_BBIT0: + case MIPS_INS_BBIT032: + case MIPS_INS_BBIT1: + case MIPS_INS_BBIT132: + case MIPS_INS_BBNEZC: + case MIPS_INS_BC: + case MIPS_INS_BC16: + case MIPS_INS_BC1EQZ: + case MIPS_INS_BC1EQZC: + case MIPS_INS_BC1F: + case MIPS_INS_BC1FL: + case MIPS_INS_BC1NEZ: + case MIPS_INS_BC1NEZC: + case MIPS_INS_BC1T: + case MIPS_INS_BC1TL: + case MIPS_INS_BC2EQZ: + case MIPS_INS_BC2EQZC: + case MIPS_INS_BC2NEZ: + case MIPS_INS_BC2NEZC: + case MIPS_INS_BCLRI_B: + case MIPS_INS_BCLRI_D: + case MIPS_INS_BCLRI_H: + case MIPS_INS_BCLRI_W: + case MIPS_INS_BCLR_B: + case MIPS_INS_BCLR_D: + case MIPS_INS_BCLR_H: + case MIPS_INS_BCLR_W: + case MIPS_INS_BEQC: + case MIPS_INS_BEQIC: + case MIPS_INS_BEQZ16: + case MIPS_INS_BEQZALC: + case MIPS_INS_BEQZC: + case MIPS_INS_BEQZC16: + case MIPS_INS_BGEC: + case MIPS_INS_BGEIC: + case MIPS_INS_BGEIUC: + case MIPS_INS_BGEUC: + case MIPS_INS_BGEZALS: + case MIPS_INS_BLTC: + case MIPS_INS_BLTIC: + case MIPS_INS_BLTIUC: + case MIPS_INS_BLTUC: + case MIPS_INS_BLTZALS: + case MIPS_INS_BMNZI_B: + case MIPS_INS_BMNZ_V: + case MIPS_INS_BMZI_B: + case MIPS_INS_BMZ_V: + case MIPS_INS_BNEC: + case MIPS_INS_BNEIC: + case MIPS_INS_BNEZ16: + case MIPS_INS_BNEZALC: + case MIPS_INS_BNEZC: + case MIPS_INS_BNEZC16: + case MIPS_INS_BNVC: + case MIPS_INS_BOVC: + case MIPS_INS_BPOSGE32: + case MIPS_INS_BPOSGE32C: + case MIPS_INS_BREAK16: + case MIPS_INS_BRSC: +#endif /* CS_NEXT_VERSION */ case MIPS_INS_B: case MIPS_INS_BEQ: case MIPS_INS_BNE: @@ -1008,12 +685,6 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u case MIPS_INS_BGEZC: case MIPS_INS_BLTZC: case MIPS_INS_BGTZC: - if (insn->id == MIPS_INS_J || insn->id == MIPS_INS_B) { - op->type = RZ_ANALYSIS_OP_TYPE_JMP; - } else { - op->type = RZ_ANALYSIS_OP_TYPE_CJMP; - } - if (OPERAND(0).type == MIPS_OP_IMM) { op->jump = IMM(0); } else if (OPERAND(1).type == MIPS_OP_IMM) { @@ -1021,27 +692,81 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u } else if (OPERAND(2).type == MIPS_OP_IMM) { op->jump = IMM(2); } + op->fail = addr + insn->size; + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + op->delay = 1; switch (insn->id) { +#if CS_NEXT_VERSION >= 6 + case MIPS_INS_B16: +#endif + case MIPS_INS_B: + op->fail = UT64_MAX; + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + break; + case MIPS_INS_BEQ: + if (OPCOUNT() == 1) { + // BEQ $zero $zero is B + op->fail = UT64_MAX; + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + } + break; +#if CS_NEXT_VERSION >= 6 + case MIPS_INS_BALC: + case MIPS_INS_BC16: + case MIPS_INS_BEQC: + case MIPS_INS_BEQIC: + case MIPS_INS_BEQZALC: + case MIPS_INS_BEQZC: + case MIPS_INS_BGEC: + case MIPS_INS_BGEIC: + case MIPS_INS_BGEIUC: + case MIPS_INS_BGEUC: + case MIPS_INS_BLTC: + case MIPS_INS_BLTIC: + case MIPS_INS_BLTIUC: + case MIPS_INS_BLTUC: + case MIPS_INS_BNEC: + case MIPS_INS_BNEIC: + case MIPS_INS_BNEZALC: + case MIPS_INS_BNEZC: + case MIPS_INS_BNVC: + case MIPS_INS_BOVC: + case MIPS_INS_BRSC: + case MIPS_INS_BEQZC16: + case MIPS_INS_BNEZC16: +#endif case MIPS_INS_BLEZC: case MIPS_INS_BGEZC: case MIPS_INS_BLTZC: case MIPS_INS_BGTZC: // compact versions (no delay) op->delay = 0; - op->fail = addr + 4; break; default: - op->delay = 1; - op->fail = addr + 8; break; } break; +#if CS_NEXT_VERSION >= 6 + case MIPS_INS_JRC16: + case MIPS_INS_JR16: + case MIPS_INS_JR_HB: +#endif case MIPS_INS_JR: case MIPS_INS_JRC: +#if CS_NEXT_VERSION < 6 + if (insn->id == MIPS_INS_JRC) { +#else + if (insn->id == MIPS_INS_JRC || + insn->id == MIPS_INS_JRC16) { +#endif + // compact versions (no delay) + op->delay = 0; + } else { + op->delay = 1; + } op->type = RZ_ANALYSIS_OP_TYPE_RJMP; - op->delay = 1; // register is $ra, so jmp is a return if (insn->detail->mips.operands[0].reg == MIPS_REG_RA) { op->type = RZ_ANALYSIS_OP_TYPE_RET; @@ -1049,17 +774,13 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u } #if CS_NEXT_VERSION < 6 if (REGID(0) == MIPS_REG_25) { - op->jump = t9_pre; - t9_pre = UT64_MAX; - } #else if (REGID(0) == MIPS_REG_T9 || REGID(0) == MIPS_REG_T9_64) { +#endif op->jump = t9_pre; t9_pre = UT64_MAX; - op->type = RZ_ANALYSIS_OP_TYPE_RCALL; } -#endif break; case MIPS_INS_SLT: @@ -1070,24 +791,67 @@ static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const u case MIPS_INS_SLTIU: SET_VAL(op, 2); break; + case MIPS_INS_SRA: #if CS_NEXT_VERSION < 6 case MIPS_INS_SHRAV: case MIPS_INS_SHRAV_R: case MIPS_INS_SHRA: case MIPS_INS_SHRA_R: - case MIPS_INS_SRA: +#else + case MIPS_INS_SHRA_PH: + case MIPS_INS_SHRA_QB: + case MIPS_INS_SHRA_R_PH: + case MIPS_INS_SHRA_R_QB: + case MIPS_INS_SHRA_R_W: + case MIPS_INS_SHRAV_PH: + case MIPS_INS_SHRAV_QB: + case MIPS_INS_SHRAV_R_PH: + case MIPS_INS_SHRAV_R_QB: + case MIPS_INS_SHRAV_R_W: + case MIPS_INS_SRA_B: + case MIPS_INS_SRA_D: + case MIPS_INS_SRA_H: + case MIPS_INS_SRA_W: + case MIPS_INS_SRAI_B: + case MIPS_INS_SRAI_D: + case MIPS_INS_SRAI_H: + case MIPS_INS_SRAI_W: + case MIPS_INS_SRAR_B: + case MIPS_INS_SRAR_D: + case MIPS_INS_SRAR_H: + case MIPS_INS_SRAR_W: + case MIPS_INS_SRARI_B: + case MIPS_INS_SRARI_D: + case MIPS_INS_SRARI_H: + case MIPS_INS_SRARI_W: + case MIPS_INS_SRAV: +#endif /* CS_NEXT_VERSION */ op->type = RZ_ANALYSIS_OP_TYPE_SAR; SET_VAL(op, 2); break; +#if CS_NEXT_VERSION < 6 case MIPS_INS_SHRL: - case MIPS_INS_SRL: -#endif +#else + case MIPS_INS_SHRL_PH: + case MIPS_INS_SHRL_QB: + case MIPS_INS_SHRLV_PH: + case MIPS_INS_SHRLV_QB: +#endif /* CS_NEXT_VERSION */ case MIPS_INS_SRLV: + case MIPS_INS_SRL: op->type = RZ_ANALYSIS_OP_TYPE_SHR; SET_VAL(op, 2); break; case MIPS_INS_SLLV: case MIPS_INS_SLL: +#if CS_NEXT_VERSION >= 6 + op->delay = 0; + if (REGID(0) == MIPS_REG_INVALID) { + // NOP + op->type = RZ_ANALYSIS_OP_TYPE_NOP; + break; + } +#endif /* CS_NEXT_VERSION */ op->type = RZ_ANALYSIS_OP_TYPE_SHL; SET_VAL(op, 2); break; @@ -1220,11 +984,13 @@ static char *get_reg_profile(RzAnalysis *analysis) { static int archinfo(RzAnalysis *a, RzAnalysisInfoType query) { switch (query) { case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE: - /* fall-thru */ + // mips-16, micromips, nanomips uses 16-bits + return 2; case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE: - /* fall-thru */ + // nanomips uses 48-bits + return 6; case RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN: - /* fall-thru */ + return 2; case RZ_ANALYSIS_ARCHINFO_DATA_ALIGN: return 4; case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS: diff --git a/librz/arch/p/arch_mips_cs.c b/librz/arch/p/arch_mips_cs.c index 17e9614c4dd..04878970eca 100644 --- a/librz/arch/p/arch_mips_cs.c +++ b/librz/arch/p/arch_mips_cs.c @@ -1,8 +1,160 @@ // SPDX-FileCopyrightText: 2024 RizinOrg -// SPDX-FileCopyrightText: 2024 deroad +// SPDX-FileCopyrightText: 2024 deroad // SPDX-License-Identifier: LGPL-3.0-only #include +#include + +#define EXTRA_CPUS "r2300,r2600,r2800,r2000a,r2000,r3000a,r3000,r10000" + +#if CS_NEXT_VERSION < 6 +#define CAPSTONE_CPUS "micromips,mips1,mips2,mips3,mips4,mips16,mips32,mips32r6,mips64" +#define CAPSTONE_FEATURES "" +#else +#define CAPSTONE_CPUS "micromips,mips1,mips2,mips32r2,mips32r3,mips32r5,mips32r6,mips3,mips4,mips5,mips64r2,mips64r3,mips64r5,mips64r6,octeon,octeonp,nanomips,nms1,i7200,micro32r3,micro32r6" +#define CAPSTONE_FEATURES "noptr64,nofloat" +#endif + +#define MIPS_CPUS CAPSTONE_CPUS "," EXTRA_CPUS +#define MIPS_FEATURES CAPSTONE_FEATURES + +#define return_on_cpu(cpu_name, mode_flag) \ + do { \ + if (!strcmp(cpu, cpu_name)) { \ + *mode = _mode | mode_flag; \ + return true; \ + } \ + } while (0) + +static bool cs_mode_from_cpu(const char *cpu, int bits, bool big_endian, cs_mode *mode) { + cs_mode _mode = (big_endian) ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN; +#if CS_NEXT_VERSION < 6 + + switch (bits) { + case 64: + _mode |= CS_MODE_MIPS64; + break; + case 32: + _mode |= CS_MODE_MIPS32; + break; + default: + return false; + } + *mode = _mode; + + if (RZ_STR_ISNOTEMPTY(cpu)) { + return_on_cpu("micromips", CS_MODE_MICRO); + return_on_cpu("mips1", CS_MODE_MIPS2); // mips1 is subset of mips2 + return_on_cpu("mips2", CS_MODE_MIPS2); + return_on_cpu("mips3", CS_MODE_MIPS3); + return_on_cpu("mips4", CS_MODE_MIPS32); // old capstone uses the same + return_on_cpu("mips16", CS_MODE_MIPS32); // old capstone uses the same + return_on_cpu("mips32", CS_MODE_MIPS32); + return_on_cpu("mips32r6", CS_MODE_MIPS32R6); + return_on_cpu("mips64", CS_MODE_MIPS64); + return_on_cpu("mips64r2", CS_MODE_MIPS64); // fallback to mips64 + return_on_cpu("mips64r3", CS_MODE_MIPS64); // fallback to mips64 + return_on_cpu("mips64r5", CS_MODE_MIPS64); // fallback to mips64 + return_on_cpu("mips64r6", CS_MODE_MIPS64); // fallback to mips64 + + // extra cpus + return_on_cpu("r2300", CS_MODE_MIPS2); + return_on_cpu("r2600", CS_MODE_MIPS2); + return_on_cpu("r2800", CS_MODE_MIPS2); + return_on_cpu("r2000a", CS_MODE_MIPS2); + return_on_cpu("r2000", CS_MODE_MIPS2); + return_on_cpu("r3000a", CS_MODE_MIPS2); // ISA mips2 + return_on_cpu("r3000", CS_MODE_MIPS2); // ISA mips2 + return_on_cpu("r10000", CS_MODE_MIPS32); // old capstone uses the same + } + +#else // CS_NEXT_VERSION >= 6 +#define return_or_add_on_cpu(cpu_name, mode_flag) \ + do { \ + if (!strcmp(cpu, cpu_name)) { \ + *mode = _mode | mode_flag; \ + return true; \ + } \ + const size_t cpu_name_len = strlen(cpu_name); \ + const char *p = strstr(cpu, cpu_name); \ + if (p && (p[cpu_name_len] == '\0' || p[cpu_name_len] == ' ')) { \ + _add_mode |= mode_flag; \ + } \ + } while (0) + + bool is_noptr64 = RZ_STR_ISNOTEMPTY(cpu) && strstr(cpu, "+noptr64"); + if (!is_noptr64 && bits > 16) { + _mode |= CS_MODE_MIPS_PTR64; + } + + bool is_nofloat = RZ_STR_ISNOTEMPTY(cpu) && strstr(cpu, "+nofloat"); + if (is_nofloat) { + _mode |= CS_MODE_MIPS_NOFLOAT; + } + + if (RZ_STR_ISNOTEMPTY(cpu)) { + cs_mode _add_mode = 0; + return_or_add_on_cpu("micromips", CS_MODE_MICRO); + return_or_add_on_cpu("mips1", CS_MODE_MIPS1); + return_or_add_on_cpu("mips2", CS_MODE_MIPS2); + return_or_add_on_cpu("mips16", CS_MODE_MIPS16); + return_or_add_on_cpu("mips32", CS_MODE_MIPS3); // we always map the generic mips32 as mips3 + return_or_add_on_cpu("mips32r2", CS_MODE_MIPS32R2); + return_or_add_on_cpu("mips32r3", CS_MODE_MIPS32R3); + return_or_add_on_cpu("mips32r5", CS_MODE_MIPS32R5); + return_or_add_on_cpu("mips32r6", CS_MODE_MIPS32R6); + return_or_add_on_cpu("mips3", CS_MODE_MIPS3); + return_or_add_on_cpu("mips4", CS_MODE_MIPS4); + return_or_add_on_cpu("mips5", CS_MODE_MIPS5); + return_or_add_on_cpu("mips64", CS_MODE_MIPS64); + return_or_add_on_cpu("mips64r2", CS_MODE_MIPS64); // fallback to mips64 + return_or_add_on_cpu("mips64r3", CS_MODE_MIPS64R3); + return_or_add_on_cpu("mips64r5", CS_MODE_MIPS64R5); + return_or_add_on_cpu("mips64r6", CS_MODE_MIPS64R6); + return_or_add_on_cpu("octeon", CS_MODE_OCTEON); + return_or_add_on_cpu("octeonp", CS_MODE_OCTEONP); + return_or_add_on_cpu("nanomips", CS_MODE_NANOMIPS); + return_or_add_on_cpu("nms1", CS_MODE_NMS1); + return_or_add_on_cpu("i7200", CS_MODE_I7200); +#undef return_or_add_on_cpu + + if (_add_mode) { + *mode = _add_mode; + return true; + } + + // special cpus. + return_on_cpu("micro32r3", CS_MODE_MICRO32R3); + return_on_cpu("micro32r6", CS_MODE_MICRO32R6); + + // extra cpus + return_on_cpu("r2300", CS_MODE_MIPS2); + return_on_cpu("r2600", CS_MODE_MIPS2); + return_on_cpu("r2800", CS_MODE_MIPS2); + return_on_cpu("r2000a", CS_MODE_MIPS2); + return_on_cpu("r2000", CS_MODE_MIPS2); + return_on_cpu("r3000a", CS_MODE_MIPS2); // ISA mips2 + return_on_cpu("r3000", CS_MODE_MIPS2); // ISA mips2 + return_on_cpu("r10000", CS_MODE_MIPS4); + } + + switch (bits) { + case 64: // generic mips64 + *mode = _mode | CS_MODE_MIPS64; + break; + case 32: // generic mips32 + *mode = _mode | CS_MODE_MIPS3; + break; + case 16: // generic mips16 + *mode = _mode | CS_MODE_MIPS16; + break; + default: + return false; + } +#endif /* CS_NEXT_VERSION */ + return true; +} +#undef return_on_cpu #include "analysis/analysis_mips_cs.c" #include "asm/asm_mips_cs.c" diff --git a/librz/arch/p/asm/asm_mips_cs.c b/librz/arch/p/asm/asm_mips_cs.c index 94c675c24c4..89d110d07d8 100644 --- a/librz/arch/p/asm/asm_mips_cs.c +++ b/librz/arch/p/asm/asm_mips_cs.c @@ -1,9 +1,11 @@ +// SPDX-FileCopyrightText: 2024 deroad // SPDX-FileCopyrightText: 2013-2018 pancake // SPDX-License-Identifier: LGPL-3.0-only #include #include -#include +#include +#include #include "cs_helper.h" CAPSTONE_DEFINE_PLUGIN_FUNCTIONS(mips_asm); @@ -12,23 +14,17 @@ static int mips_disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) { CapstoneContext *ctx = (CapstoneContext *)a->plugin_data; cs_insn *insn; - int mode, n, ret = -1; - mode = (a->big_endian) ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN; + cs_mode mode = 0; + int n, ret = -1; if (!op) { return 0; } - if (a->cpu && *a->cpu) { - if (!strcmp(a->cpu, "micro")) { - mode |= CS_MODE_MICRO; - } else if (!strcmp(a->cpu, "r6")) { - mode |= CS_MODE_MIPS32R6; - } else if (!strcmp(a->cpu, "v3")) { - mode |= CS_MODE_MIPS3; - } else if (!strcmp(a->cpu, "v2")) { - mode |= CS_MODE_MIPS2; - } + + if (!cs_mode_from_cpu(a->cpu, a->bits, a->big_endian, &mode)) { + rz_asm_op_set_asm(op, "invalid"); + return -1; } - mode |= (a->bits == 64) ? CS_MODE_MIPS64 : CS_MODE_MIPS32; + memset(op, 0, sizeof(RzAsmOp)); op->size = 4; if (ctx->omode != mode) { @@ -39,10 +35,14 @@ static int mips_disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) { if (!ctx->handle) { ret = cs_open(CS_ARCH_MIPS, mode, &ctx->handle); if (ret) { + RZ_LOG_ERROR("failed to open capstone\n"); goto fin; } ctx->omode = mode; cs_option(ctx->handle, CS_OPT_DETAIL, CS_OPT_OFF); +#if CS_NEXT_VERSION > 5 + cs_option(ctx->handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_NO_DOLLAR); +#endif } if (a->syntax == RZ_ASM_SYNTAX_REGNUM) { cs_option(ctx->handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_NOREGNAME); @@ -52,7 +52,11 @@ static int mips_disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) { n = cs_disasm(ctx->handle, (ut8 *)buf, len, a->pc, 1, &insn); if (n < 1) { rz_asm_op_set_asm(op, "invalid"); - op->size = 4; +#if CS_NEXT_VERSION < 6 + op->size = mode & CS_MODE_MICRO ? 2 : 4; +#else + op->size = mode & (CS_MODE_MICRO | CS_MODE_NANOMIPS | CS_MODE_MIPS16) ? 2 : 4; +#endif goto fin; } if (insn->size < 1) { @@ -60,11 +64,15 @@ static int mips_disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) { } op->size = insn->size; rz_asm_op_setf_asm(op, "%s%s%s", insn->mnemonic, insn->op_str[0] ? " " : "", insn->op_str); + +#if CS_NEXT_VERSION < 6 + // CS_OPT_SYNTAX_NO_DOLLAR is not available before capstone 6 char *str = rz_asm_op_get_asm(op); if (str) { // remove the '$' in the string rz_str_replace_char(str, '$', 0); } +#endif cs_free(insn, n); fin: return op->size; diff --git a/librz/bin/format/elf/elf_info.c b/librz/bin/format/elf/elf_info.c index dd01264f9d0..de5c8cb112e 100644 --- a/librz/bin/format/elf/elf_info.c +++ b/librz/bin/format/elf/elf_info.c @@ -6,10 +6,6 @@ #include "elf.h" -#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ -#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */ -#define EF_MIPS_ABI 0x0000f000 - #define VERSYM_VERSION 0x7fff struct mips_bits_translation { @@ -47,18 +43,6 @@ struct ver_flags_translation { const char *name; }; -static const struct mips_bits_translation mips_bits_translation_table[] = { - { EF_MIPS_ARCH_1, 32 }, - { EF_MIPS_ARCH_2, 32 }, - { EF_MIPS_ARCH_3, 32 }, - { EF_MIPS_ARCH_4, 32 }, - { EF_MIPS_ARCH_5, 32 }, - { EF_MIPS_ARCH_32, 32 }, - { EF_MIPS_ARCH_64, 64 }, - { EF_MIPS_ARCH_32R2, 32 }, - { EF_MIPS_ARCH_64R2, 64 } -}; - static const struct section_note_osabi_translation section_note_osabi_translation_table[] = { { ".note.openbsd.ident", "openbsd" }, { ".note.minix.ident", "minix" }, @@ -74,7 +58,7 @@ static const struct machine_name_translation machine_name_translation_table[] = { EM_68K, "Motorola m68k family" }, { EM_88K, "Motorola m88k family" }, { EM_860, "Intel 80860" }, - { EM_MIPS, "MIPS R3000" }, + { EM_MIPS, "MIPS R3000 big-endian" }, { EM_S370, "IBM System/370" }, { EM_MIPS_RS3_LE, "MIPS R3000 little-endian" }, { EM_PARISC, "HPPA" }, @@ -230,8 +214,53 @@ static const struct class_translation class_translation_table[] = { { ELFCLASS64, "ELF64" } }; -static const struct cpu_mips_translation cpu_mips_translation_table[] = { - { EF_MIPS_ARCH_1, "mips1" }, +static const struct cpu_mips_translation gnu_mips_mach_translation_table[] = { + { EF_MIPS_MACH_3900, "3900 " }, + { EF_MIPS_MACH_4010, "4010 " }, + { EF_MIPS_MACH_4100, "4100 " }, + { EF_MIPS_MACH_ALLEGREX, "allegrex " }, + { EF_MIPS_MACH_4650, "4650 " }, + { EF_MIPS_MACH_4120, "4120 " }, + { EF_MIPS_MACH_4111, "4111 " }, + { EF_MIPS_MACH_SB1, "sb1 " }, + { EF_MIPS_MACH_OCTEON, "octeon " }, + { EF_MIPS_MACH_XLR, "xlr " }, + { EF_MIPS_MACH_OCTEON2, "octeon2 " }, + { EF_MIPS_MACH_OCTEON3, "octeon3 " }, + { EF_MIPS_MACH_5400, "5400 " }, + { EF_MIPS_MACH_5900, "5900 " }, + { EF_MIPS_MACH_IAMR2, "iamr2 " }, + { EF_MIPS_MACH_5500, "5500 " }, + { EF_MIPS_MACH_9000, "9000 " }, + { EF_MIPS_MACH_LS2E, "ls2e " }, + { EF_MIPS_MACH_LS2F, "ls2f " }, + { EF_MIPS_MACH_GS464, "gs464 " }, + { EF_MIPS_MACH_GS464E, "gs464e " }, + { EF_MIPS_MACH_GS264E, "gs264e " }, +}; + +static const struct cpu_mips_translation gnu_mips_ase_translation_table[] = { + { EF_MIPS_ARCH_ASE_MDMX, "mdmx " }, + { EF_MIPS_ARCH_ASE_M16, "mips16 " }, + { EF_MIPS_ARCH_ASE_MICROMIPS, "micromips " }, +}; + +static const struct mips_bits_translation mips_bits_translation_table[] = { + { EF_MIPS_ARCH_1, 32 }, + { EF_MIPS_ARCH_2, 32 }, + { EF_MIPS_ARCH_3, 32 }, + { EF_MIPS_ARCH_4, 32 }, + { EF_MIPS_ARCH_5, 32 }, + { EF_MIPS_ARCH_32, 32 }, + { EF_MIPS_ARCH_64, 64 }, + { EF_MIPS_ARCH_32R2, 32 }, + { EF_MIPS_ARCH_64R2, 64 }, + { EF_MIPS_ARCH_32R6, 32 }, + { EF_MIPS_ARCH_64R6, 64 }, +}; + +static const struct cpu_mips_translation gnu_mips_arch_translation_table32[] = { + { EF_MIPS_ARCH_1, "mips5" }, // also used for generic mips, so we default to mips5 { EF_MIPS_ARCH_2, "mips2" }, { EF_MIPS_ARCH_3, "mips3" }, { EF_MIPS_ARCH_4, "mips4" }, @@ -240,6 +269,22 @@ static const struct cpu_mips_translation cpu_mips_translation_table[] = { { EF_MIPS_ARCH_64, "mips64" }, { EF_MIPS_ARCH_32R2, "mips32r2" }, { EF_MIPS_ARCH_64R2, "mips64r2" }, + { EF_MIPS_ARCH_32R6, "mips32r6" }, + { EF_MIPS_ARCH_64R6, "mips64r6" }, +}; + +static const struct cpu_mips_translation gnu_mips_arch_translation_table64[] = { + { EF_MIPS_ARCH_1, "mips64" }, // also used for generic mips, so we default to mips64 + { EF_MIPS_ARCH_2, "mips64r2" }, + { EF_MIPS_ARCH_3, "mips64r3" }, + { EF_MIPS_ARCH_4, "mips64r5" }, + { EF_MIPS_ARCH_5, "mips64r6" }, + { EF_MIPS_ARCH_32, "mips64" }, + { EF_MIPS_ARCH_64, "mips64" }, + { EF_MIPS_ARCH_32R2, "mips64r2" }, // should never happen but default to 64bit + { EF_MIPS_ARCH_64R2, "mips64r2" }, + { EF_MIPS_ARCH_32R6, "mips64r6" }, // should never happen but default to 64bit + { EF_MIPS_ARCH_64R6, "mips64r6" }, }; static const struct arch_translation arch_translation_table[] = { @@ -634,17 +679,20 @@ static int get_bits_mips_common(Elf_(Word) mips_type) { return 32; } -static int is_playstation_hack(ELFOBJ *bin, Elf_(Word) mips_type) { - return Elf_(rz_bin_elf_is_executable)(bin) && Elf_(rz_bin_elf_is_static)(bin) && mips_type == EF_MIPS_ARCH_3; +static inline bool is_elf_class64(ELFOBJ *bin) { + return bin->ehdr.e_ident[EI_CLASS] == ELFCLASS64; } -static int get_bits_mips(ELFOBJ *bin) { - const Elf_(Word) mips_type = bin->ehdr.e_flags & EF_MIPS_ARCH; +static inline bool is_elf_class32(ELFOBJ *bin) { + return bin->ehdr.e_ident[EI_CLASS] == ELFCLASS32; +} - if (is_playstation_hack(bin, mips_type)) { +static int get_bits_mips(ELFOBJ *bin) { + if (is_elf_class64(bin)) { return 64; } + const Elf_(Word) mips_type = bin->ehdr.e_flags & EF_MIPS_ARCH; return get_bits_mips_common(mips_type); } @@ -838,62 +886,111 @@ static char *get_file_type_basic(RZ_NONNULL ELFOBJ *bin) { static char *get_cpu_mips(ELFOBJ *bin) { Elf_(Word) mips_arch = bin->ehdr.e_flags & EF_MIPS_ARCH; + Elf_(Word) mips_ase = bin->ehdr.e_flags & EF_MIPS_ARCH_ASE; + Elf_(Word) mips_mach = bin->ehdr.e_flags & EF_MIPS_MACH; - for (size_t i = 0; i < RZ_ARRAY_SIZE(cpu_mips_translation_table); i++) { - if (mips_arch == cpu_mips_translation_table[i].arch) { - return rz_str_dup(cpu_mips_translation_table[i].name); + RzStrBuf sb; + rz_strbuf_init(&sb); + + for (size_t i = 0; i < RZ_ARRAY_SIZE(gnu_mips_mach_translation_table); i++) { + if (mips_mach == gnu_mips_mach_translation_table[i].arch) { + rz_strbuf_append(&sb, gnu_mips_mach_translation_table[i].name); + break; } } - return rz_str_dup(" Unknown mips ISA"); -} + for (size_t i = 0; i < RZ_ARRAY_SIZE(gnu_mips_ase_translation_table); i++) { + if (mips_ase == gnu_mips_ase_translation_table[i].arch) { + rz_strbuf_append(&sb, gnu_mips_ase_translation_table[i].name); + break; + } + } -static bool is_elf_class64(ELFOBJ *bin) { - return bin->ehdr.e_ident[EI_CLASS] == ELFCLASS64; + if (is_elf_class64(bin)) { + for (size_t i = 0; i < RZ_ARRAY_SIZE(gnu_mips_arch_translation_table64); i++) { + if (mips_arch == gnu_mips_arch_translation_table64[i].arch) { + rz_strbuf_append(&sb, gnu_mips_arch_translation_table64[i].name); + break; + } + } + } else { + for (size_t i = 0; i < RZ_ARRAY_SIZE(gnu_mips_arch_translation_table32); i++) { + if (mips_arch == gnu_mips_arch_translation_table32[i].arch) { + rz_strbuf_append(&sb, gnu_mips_arch_translation_table32[i].name); + break; + } + } + } + + return rz_strbuf_drain_nofree(&sb); } -static bool is_mips_o32(ELFOBJ *bin) { - if (bin->ehdr.e_ident[EI_CLASS] != ELFCLASS32) { - return false; +static char *get_abi_mips(ELFOBJ *bin) { + Elf_(Word) mips_eflags = bin->ehdr.e_flags; + Elf_(Word) mips_abi = mips_eflags & EF_MIPS_ABI; + + RzStrBuf sb; + rz_strbuf_init(&sb); + + if (mips_eflags & EF_MIPS_NOREORDER) { + rz_strbuf_append(&sb, "noreorder "); } - if ((bin->ehdr.e_flags & EF_MIPS_ABI2) != 0) { - return false; + if (mips_eflags & EF_MIPS_PIC) { + rz_strbuf_append(&sb, "pic "); } - if ((bin->ehdr.e_flags & EF_MIPS_ABI) != 0 && (bin->ehdr.e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32) { - return false; + if (mips_eflags & EF_MIPS_CPIC) { + rz_strbuf_append(&sb, "cpic "); } - return true; -} + if (mips_eflags & EF_MIPS_XGOT) { + rz_strbuf_append(&sb, "xgot "); + } -static bool is_mips_n32(ELFOBJ *bin) { - if (bin->ehdr.e_ident[EI_CLASS] != ELFCLASS32) { - return false; + if (mips_eflags & EF_MIPS_UCODE) { + rz_strbuf_append(&sb, "ucode "); } - if ((bin->ehdr.e_flags & EF_MIPS_ABI2) == 0 || (bin->ehdr.e_flags & EF_MIPS_ABI) != 0) { - return false; + if (mips_eflags & EF_MIPS_ABI2) { + rz_strbuf_append(&sb, "abi2 "); } - return true; -} + if (mips_eflags & EF_MIPS_FP64) { + rz_strbuf_append(&sb, "fp64 "); + } -static char *get_abi_mips(ELFOBJ *bin) { - if (is_elf_class64(bin)) { - return rz_str_dup("n64"); + if (mips_eflags & EF_MIPS_NAN2008) { + rz_strbuf_append(&sb, "nan2008 "); } - if (is_mips_n32(bin)) { - return rz_str_dup("n32"); + if (mips_abi == EF_MIPS_ABI_O32) { + rz_strbuf_append(&sb, "o32 "); } - if (is_mips_o32(bin)) { - return rz_str_dup("o32"); + if (mips_abi == EF_MIPS_ABI_O64) { + rz_strbuf_append(&sb, "o64 "); } - return NULL; + if (mips_abi == EF_MIPS_ABI_EABI32) { + rz_strbuf_append(&sb, "eabi32 "); + } + + if (mips_abi == EF_MIPS_ABI_EABI64) { + rz_strbuf_append(&sb, "eabi64 "); + } + + if (is_elf_class64(bin)) { + rz_strbuf_append(&sb, "n64"); + } else if (is_elf_class32(bin)) { + rz_strbuf_append(&sb, "n32"); + } + + if (rz_strbuf_is_empty(&sb)) { + return rz_str_dup("Unknown ABI"); + } + + return rz_strbuf_drain_nofree(&sb); } /** @@ -1468,10 +1565,6 @@ RZ_OWN char *Elf_(rz_bin_elf_get_arch)(RZ_NONNULL ELFOBJ *bin) { RZ_OWN char *Elf_(rz_bin_elf_get_cpu)(RZ_NONNULL ELFOBJ *bin) { rz_return_val_if_fail(bin, NULL); - if (!Elf_(rz_bin_elf_has_segments)(bin)) { - return NULL; - } - if (bin->ehdr.e_machine == EM_MIPS) { return get_cpu_mips(bin); } diff --git a/librz/bin/format/elf/glibc_elf.h b/librz/bin/format/elf/glibc_elf.h index 070db55d1ba..b4a65074a6e 100644 --- a/librz/bin/format/elf/glibc_elf.h +++ b/librz/bin/format/elf/glibc_elf.h @@ -1624,18 +1624,38 @@ typedef struct /* MIPS R3000 specific definitions. */ -/* Legal values for e_flags field of Elf32_Ehdr. */ - -#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */ -#define EF_MIPS_PIC 2 /* Contains PIC code. */ -#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */ -#define EF_MIPS_XGOT 8 -#define EF_MIPS_64BIT_WHIRL 16 -#define EF_MIPS_ABI2 32 -#define EF_MIPS_ABI_ON32 64 -#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */ -#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */ -#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */ +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_MIPS_NOREORDER 0x00000001 /* At least one .noreorder directive appears in the source. */ +#define EF_MIPS_PIC 0x00000002 /* File contains position independent code. */ +#define EF_MIPS_CPIC 0x00000004 /* Code in file uses the standard calling sequence for calling position independent code. */ +#define EF_MIPS_XGOT 0x00000008 /* ??? Unknown flag, set in IRIX 6's BSDdup2.o in libbsd.a. */ +#define EF_MIPS_UCODE 0x00000010 /* Code in file uses UCODE (obsolete) */ +#define EF_MIPS_ABI2 0x00000020 /* Code in file uses new ABI (-n32 on Irix 6). */ +#define EF_MIPS_OPTIONS_FIRST 0x00000080 /* Process the .MIPS.options section first by ld */ +#define EF_MIPS_32BITMODE 0x00000100 /* Indicates code compiled for a 64-bit machine in 32-bit mode (regs are 32-bits wide). */ +#define EF_MIPS_FP64 0x00000200 /* 32-bit machine but FP registers are 64 bit (-mfp64). */ +#define EF_MIPS_NAN2008 0x00000400 /* Code in file uses the IEEE 754-2008 NaN encoding convention. */ +#define EF_MIPS_ARCH_ASE 0x0f000000 /* Architectural Extensions used by this file */ +#define EF_MIPS_ARCH_ASE_MDMX 0x08000000 /* Use MDMX multimedia extensions */ +#define EF_MIPS_ARCH_ASE_M16 0x04000000 /* Use MIPS-16 ISA extensions */ +#define EF_MIPS_ARCH_ASE_MICROMIPS 0x02000000 /* Use MICROMIPS ISA extensions. */ +#define EF_MIPS_ARCH 0xf0000000 /* Four bit MIPS architecture field. */ +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x50000000 /* -mips32 code. */ +#define EF_MIPS_ARCH_64 0x60000000 /* -mips64 code. */ +#define EF_MIPS_ARCH_32R2 0x70000000 /* -mips32r2 code. */ +#define EF_MIPS_ARCH_64R2 0x80000000 /* -mips64r2 code. */ +#define EF_MIPS_ARCH_32R6 0x90000000 /* -mips32r6 code. */ +#define EF_MIPS_ARCH_64R6 0xa0000000 /* -mips64r6 code. */ +#define EF_MIPS_ABI 0x0000F000 /* The ABI of the file. Also see EF_MIPS_ABI2 above. */ +#define EF_MIPS_ABI_O32 0x00001000 /* The original o32 abi. */ +#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended to work on 64 bit architectures */ +#define EF_MIPS_ABI_EABI32 0x00003000 /* EABI in 32 bit mode */ +#define EF_MIPS_ABI_EABI64 0x00004000 /* EABI in 64 bit mode */ /* Legal values for MIPS architecture level. */ @@ -1649,15 +1669,80 @@ typedef struct #define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */ #define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */ -/* The following are unofficial names and should not be used. */ - -#define E_MIPS_ARCH_1 EF_MIPS_ARCH_1 -#define E_MIPS_ARCH_2 EF_MIPS_ARCH_2 -#define E_MIPS_ARCH_3 EF_MIPS_ARCH_3 -#define E_MIPS_ARCH_4 EF_MIPS_ARCH_4 -#define E_MIPS_ARCH_5 EF_MIPS_ARCH_5 -#define E_MIPS_ARCH_32 EF_MIPS_ARCH_32 -#define E_MIPS_ARCH_64 EF_MIPS_ARCH_64 +/*In order to support backwards compatibility we also + define the old versions of some of these constants. */ +#define E_MIPS_ARCH_1 EF_MIPS_ARCH_1 +#define E_MIPS_ARCH_2 EF_MIPS_ARCH_2 +#define E_MIPS_ARCH_3 EF_MIPS_ARCH_3 +#define E_MIPS_ARCH_4 EF_MIPS_ARCH_4 +#define E_MIPS_ARCH_5 EF_MIPS_ARCH_5 +#define E_MIPS_ARCH_32 EF_MIPS_ARCH_32 +#define E_MIPS_ARCH_64 EF_MIPS_ARCH_64 +#define E_MIPS_ARCH_32R2 EF_MIPS_ARCH_32R2 +#define E_MIPS_ARCH_64R2 EF_MIPS_ARCH_64R2 +#define E_MIPS_ARCH_32R6 EF_MIPS_ARCH_32R6 +#define E_MIPS_ARCH_64R6 EF_MIPS_ARCH_64R6 +#define E_MIPS_ABI_O32 EF_MIPS_ABI_O32 +#define E_MIPS_ABI_O64 EF_MIPS_ABI_O64 +#define E_MIPS_ABI_EABI32 EF_MIPS_ABI_EABI32 +#define E_MIPS_ABI_EABI64 EF_MIPS_ABI_EABI64 + +/* Machine variant if we know it. This field was invented at Cygnus, + but it is hoped that other vendors will adopt it. If some standard + is developed, this code should be changed to follow it. */ +#define EF_MIPS_MACH 0x00FF0000 + +/* Cygnus is choosing values between 80 and 9F; + 00 - 7F should be left for a future standard; + the rest are open. */ + +#define EF_MIPS_MACH_3900 0x00810000 +#define EF_MIPS_MACH_4010 0x00820000 +#define EF_MIPS_MACH_4100 0x00830000 +#define EF_MIPS_MACH_ALLEGREX 0x00840000 +#define EF_MIPS_MACH_4650 0x00850000 +#define EF_MIPS_MACH_4120 0x00870000 +#define EF_MIPS_MACH_4111 0x00880000 +#define EF_MIPS_MACH_SB1 0x008a0000 +#define EF_MIPS_MACH_OCTEON 0x008b0000 +#define EF_MIPS_MACH_XLR 0x008c0000 +#define EF_MIPS_MACH_OCTEON2 0x008d0000 +#define EF_MIPS_MACH_OCTEON3 0x008e0000 +#define EF_MIPS_MACH_5400 0x00910000 +#define EF_MIPS_MACH_5900 0x00920000 +#define EF_MIPS_MACH_IAMR2 0x00930000 +#define EF_MIPS_MACH_5500 0x00980000 +#define EF_MIPS_MACH_9000 0x00990000 +#define EF_MIPS_MACH_LS2E 0x00A00000 +#define EF_MIPS_MACH_LS2F 0x00A10000 +#define EF_MIPS_MACH_GS464 0x00A20000 +#define EF_MIPS_MACH_GS464E 0x00A30000 +#define EF_MIPS_MACH_GS264E 0x00A40000 + +/* In order to support backwards compatibility we also + define the old versions of some of these constants. */ +#define E_MIPS_MACH_3900 EF_MIPS_MACH_3900 +#define E_MIPS_MACH_4010 EF_MIPS_MACH_4010 +#define E_MIPS_MACH_4100 EF_MIPS_MACH_4100 +#define E_MIPS_MACH_ALLEGREX EF_MIPS_MACH_ALLEGREX +#define E_MIPS_MACH_4650 EF_MIPS_MACH_4650 +#define E_MIPS_MACH_4120 EF_MIPS_MACH_4120 +#define E_MIPS_MACH_4111 EF_MIPS_MACH_4111 +#define E_MIPS_MACH_SB1 EF_MIPS_MACH_SB1 +#define E_MIPS_MACH_OCTEON EF_MIPS_MACH_OCTEON +#define E_MIPS_MACH_XLR EF_MIPS_MACH_XLR +#define E_MIPS_MACH_OCTEON2 EF_MIPS_MACH_OCTEON2 +#define E_MIPS_MACH_OCTEON3 EF_MIPS_MACH_OCTEON3 +#define E_MIPS_MACH_5400 EF_MIPS_MACH_5400 +#define E_MIPS_MACH_5900 EF_MIPS_MACH_5900 +#define E_MIPS_MACH_IAMR2 EF_MIPS_MACH_IAMR2 +#define E_MIPS_MACH_5500 EF_MIPS_MACH_5500 +#define E_MIPS_MACH_9000 EF_MIPS_MACH_9000 +#define E_MIPS_MACH_LS2E EF_MIPS_MACH_LS2E +#define E_MIPS_MACH_LS2F EF_MIPS_MACH_LS2F +#define E_MIPS_MACH_GS464 EF_MIPS_MACH_GS464 +#define E_MIPS_MACH_GS464E EF_MIPS_MACH_GS464E +#define E_MIPS_MACH_GS264E EF_MIPS_MACH_GS264E /* Special section indices. */ @@ -1667,21 +1752,20 @@ typedef struct #define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols. */ #define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols. */ -/* Legal values for sh_type field of Elf32_Shdr. */ - -#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link. */ -#define SHT_MIPS_MSYM 0x70000001 -#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols. */ -#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes. */ -#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ -#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging info. */ -#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information. */ +/* Processor specific section types. Legal values for sh_type field of Elf32_Shdr. */ +#define SHT_MIPS_LIBLIST 0x70000000 /* Section contains the set of dynamic shared objects used when statically linking. */ +#define SHT_MIPS_MSYM 0x70000001 /* I'm not sure what this is, but it's used on Irix 5. */ +#define SHT_MIPS_CONFLICT 0x70000002 /* Section contains list of symbols whose definitions conflict with symbols defined in shared objects. */ +#define SHT_MIPS_GPTAB 0x70000003 /* Section contains the global pointer table. */ +#define SHT_MIPS_UCODE 0x70000004 /* Section contains microcode information. The exact format is unspecified. */ +#define SHT_MIPS_DEBUG 0x70000005 /* Section contains some sort of debugging information. The exact format is unspecified. It's probably ECOFF symbols. */ +#define SHT_MIPS_REGINFO 0x70000006 /* Section contains register usage information. */ #define SHT_MIPS_PACKAGE 0x70000007 #define SHT_MIPS_PACKSYM 0x70000008 #define SHT_MIPS_RELD 0x70000009 -#define SHT_MIPS_IFACE 0x7000000b -#define SHT_MIPS_CONTENT 0x7000000c -#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_IFACE 0x7000000b /* Section contains interface information. */ +#define SHT_MIPS_CONTENT 0x7000000c /* Section contains description of contents of another section. */ +#define SHT_MIPS_OPTIONS 0x7000000d /* Section contains miscellaneous options. */ #define SHT_MIPS_SHDR 0x70000010 #define SHT_MIPS_FDESC 0x70000011 #define SHT_MIPS_EXTSYM 0x70000012 @@ -1693,33 +1777,33 @@ typedef struct #define SHT_MIPS_LOCSTR 0x70000018 #define SHT_MIPS_LINE 0x70000019 #define SHT_MIPS_RFDESC 0x7000001a -#define SHT_MIPS_DELTASYM 0x7000001b -#define SHT_MIPS_DELTAINST 0x7000001c -#define SHT_MIPS_DELTACLASS 0x7000001d -#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ -#define SHT_MIPS_DELTADECL 0x7000001f -#define SHT_MIPS_SYMBOL_LIB 0x70000020 -#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_DELTASYM 0x7000001b /* Delta C++: symbol table */ +#define SHT_MIPS_DELTAINST 0x7000001c /* Delta C++: instance table */ +#define SHT_MIPS_DELTACLASS 0x7000001d /* Delta C++: class table */ +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging section. */ +#define SHT_MIPS_DELTADECL 0x7000001f /* Delta C++: declarations */ +#define SHT_MIPS_SYMBOL_LIB 0x70000020 /* List of libraries the binary depends on. Includes a time stamp, version number. */ +#define SHT_MIPS_EVENTS 0x70000021 /* Events section. */ #define SHT_MIPS_TRANSLATE 0x70000022 -#define SHT_MIPS_PIXIE 0x70000023 -#define SHT_MIPS_XLATE 0x70000024 -#define SHT_MIPS_XLATE_DEBUG 0x70000025 -#define SHT_MIPS_WHIRL 0x70000026 -#define SHT_MIPS_EH_REGION 0x70000027 -#define SHT_MIPS_XLATE_OLD 0x70000028 -#define SHT_MIPS_PDR_EXCEPTION 0x70000029 -#define SHT_MIPS_XHASH 0x7000002b +#define SHT_MIPS_PIXIE 0x70000023 /* Special pixie sections */ +#define SHT_MIPS_XLATE 0x70000024 /* Address translation table (for debug info) */ +#define SHT_MIPS_XLATE_DEBUG 0x70000025 /* SGI internal address translation table (for debug info) */ +#define SHT_MIPS_WHIRL 0x70000026 /* Intermediate code */ +#define SHT_MIPS_EH_REGION 0x70000027 /* C++ exception handling region info */ +#define SHT_MIPS_XLATE_OLD 0x70000028 /* Obsolete address translation table (for debug info) */ +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 /* Runtime procedure descriptor table exception information (ucode) ??? */ +#define SHT_MIPS_ABIFLAGS 0x7000002a /* ABI related flags section. */ +#define SHT_MIPS_XHASH 0x7000002b /* GNU style symbol hash table with xlat. */ /* Legal values for sh_flags field of Elf32_Shdr. */ - -#define SHF_MIPS_GPREL 0x10000000 /* Must be in global data area. */ -#define SHF_MIPS_MERGE 0x20000000 -#define SHF_MIPS_ADDR 0x40000000 -#define SHF_MIPS_STRINGS 0x80000000 -#define SHF_MIPS_NOSTRIP 0x08000000 -#define SHF_MIPS_LOCAL 0x04000000 -#define SHF_MIPS_NAMES 0x02000000 -#define SHF_MIPS_NODUPE 0x01000000 +#define SHF_MIPS_GPREL 0x10000000 /* This section must be in the global data area. */ +#define SHF_MIPS_MERGE 0x20000000 /* This section should be merged. */ +#define SHF_MIPS_ADDR 0x40000000 /* This section contains address data of size implied by section element size. */ +#define SHF_MIPS_STRING 0x80000000 /* This section contains string data. */ +#define SHF_MIPS_NOSTRIP 0x08000000 /* This section may not be stripped. */ +#define SHF_MIPS_LOCAL 0x04000000 /* This section is local to threads. */ +#define SHF_MIPS_NAMES 0x02000000 /* Linker should generate implicit weak names for this section. */ +#define SHF_MIPS_NODUPES 0x01000000 /* Section contais text/data which may be replicated in other sections. Linker should retain only one copy. */ /* Symbol tables. */ diff --git a/librz/bin/format/te/te.c b/librz/bin/format/te/te.c index 9ff212b8edc..baaa1982504 100644 --- a/librz/bin/format/te/te.c +++ b/librz/bin/format/te/te.c @@ -214,8 +214,31 @@ ut64 rz_bin_te_get_image_base(struct rz_bin_te_obj_t *bin) { return 0LL; } +char *rz_bin_te_get_cpu(struct rz_bin_te_obj_t *bin) { + if (!bin) { + return NULL; + } + switch (bin->header->Machine) { + case TE_IMAGE_FILE_MACHINE_MIPS16: + return rz_str_dup("mips16"); + case TE_IMAGE_FILE_MACHINE_MIPSFPU: + return rz_str_dup("mips32"); + case TE_IMAGE_FILE_MACHINE_MIPSFPU16: + return rz_str_dup("mips16"); + case TE_IMAGE_FILE_MACHINE_R10000: + return rz_str_dup("r10000"); + case TE_IMAGE_FILE_MACHINE_R3000: + return rz_str_dup("r3000"); + case TE_IMAGE_FILE_MACHINE_R4000: + return rz_str_dup("r4000"); + case TE_IMAGE_FILE_MACHINE_WCEMIPSV2: + return rz_str_dup("mips2"); + default: + return NULL; + } +} + char *rz_bin_te_get_machine(struct rz_bin_te_obj_t *bin) { - char *machine; if (!bin) { return NULL; } @@ -279,7 +302,6 @@ char *rz_bin_te_get_machine(struct rz_bin_te_obj_t *bin) { default: return rz_str_dup("unknown"); } - return machine; } char *rz_bin_te_get_os(struct rz_bin_te_obj_t *bin) { diff --git a/librz/bin/format/te/te.h b/librz/bin/format/te/te.h index a146755adcd..1fb3501b34c 100644 --- a/librz/bin/format/te/te.h +++ b/librz/bin/format/te/te.h @@ -50,6 +50,7 @@ ut64 rz_bin_te_get_main_paddr(struct rz_bin_te_obj_t *bin); ut64 rz_bin_te_get_image_base(struct rz_bin_te_obj_t *bin); int rz_bin_te_get_image_size(struct rz_bin_te_obj_t *bin); char *rz_bin_te_get_machine(struct rz_bin_te_obj_t *bin); +char *rz_bin_te_get_cpu(struct rz_bin_te_obj_t *bin); int rz_bin_te_get_bits(struct rz_bin_te_obj_t *bin); char *rz_bin_te_get_os(struct rz_bin_te_obj_t *bin); struct rz_bin_te_section_t *rz_bin_te_get_sections(struct rz_bin_te_obj_t *bin); diff --git a/librz/bin/p/bin_coff.c b/librz/bin/p/bin_coff.c index b1e9c5b12cf..1693700f5a8 100644 --- a/librz/bin/p/bin_coff.c +++ b/librz/bin/p/bin_coff.c @@ -416,11 +416,20 @@ static RzBinInfo *info(RzBinFile *bf) { switch (obj->hdr.f_magic) { case COFF_FILE_MACHINE_R4000: + ret->cpu = rz_str_dup("mips4"); + /* fall-thru */ case COFF_FILE_MACHINE_MIPS16: + if (!ret->cpu) { + ret->cpu = rz_str_dup("mips16"); + } + /* fall-thru */ case COFF_FILE_MACHINE_MIPSFPU: case COFF_FILE_MACHINE_MIPSFPU16: ret->machine = rz_str_dup("mips"); ret->arch = rz_str_dup("mips"); + if (!ret->cpu) { + ret->cpu = rz_str_dup("mips32"); + } ret->bits = 32; break; case COFF_FILE_MACHINE_I386: diff --git a/librz/bin/p/bin_elf.inc b/librz/bin/p/bin_elf.inc index 5f330b736d5..72c47d1094a 100644 --- a/librz/bin/p/bin_elf.inc +++ b/librz/bin/p/bin_elf.inc @@ -2100,6 +2100,10 @@ static RzBinInfo *info(RzBinFile *bf) { } if ((str = Elf_(rz_bin_elf_get_abi)(obj))) { ret->features = str; + if (!ret->has_pi) { + // Elf MIPS PIE flag is in features. + ret->has_pi = (strstr(str, "pic ")) ? 1 : 0; + } } ret->rclass = rz_str_dup("elf"); diff --git a/librz/bin/p/bin_mach0.c b/librz/bin/p/bin_mach0.c index 0ff3b3ee246..841a5e429d4 100644 --- a/librz/bin/p/bin_mach0.c +++ b/librz/bin/p/bin_mach0.c @@ -470,7 +470,8 @@ static RzBinInfo *info(RzBinFile *bf) { ret->rclass = rz_str_dup("mach0"); ret->os = rz_str_dup("darwin"); ret->subsystem = rz_str_dup(MACH0_(get_platform)(bf->o->bin_obj)); - ret->arch = rz_str_dup(MACH0_(get_cputype)(bf->o->bin_obj)); + ret->arch = strdup(MACH0_(get_cputype)(bf->o->bin_obj)); + ret->cpu = MACH0_(get_cpusubtype)(bf->o->bin_obj); ret->machine = MACH0_(get_cpusubtype)(bf->o->bin_obj); ret->type = MACH0_(get_filetype)(bf->o->bin_obj); ret->big_endian = MACH0_(is_big_endian)(bf->o->bin_obj); diff --git a/librz/bin/p/bin_psxexe.c b/librz/bin/p/bin_psxexe.c index 92116989a6a..fd9cd2f7762 100644 --- a/librz/bin/p/bin_psxexe.c +++ b/librz/bin/p/bin_psxexe.c @@ -39,6 +39,7 @@ static RzBinInfo *info(RzBinFile *bf) { ret->machine = rz_str_dup("Sony PlayStation 1"); ret->os = rz_str_dup("psx"); ret->arch = rz_str_dup("mips"); + ret->cpu = strdup("mips3"); ret->bits = 32; ret->has_va = true; return ret; diff --git a/librz/bin/p/bin_te.c b/librz/bin/p/bin_te.c index cd69afcdd4a..78800d18004 100644 --- a/librz/bin/p/bin_te.c +++ b/librz/bin/p/bin_te.c @@ -128,6 +128,7 @@ static RzBinInfo *info(RzBinFile *bf) { ret->os = rz_bin_te_get_os(bf->o->bin_obj); ret->arch = rz_bin_te_get_arch(bf->o->bin_obj); ret->machine = rz_bin_te_get_machine(bf->o->bin_obj); + ret->cpu = rz_bin_te_get_cpu(bf->o->bin_obj); ret->subsystem = rz_bin_te_get_subsystem(bf->o->bin_obj); ret->type = rz_str_dup("EXEC (Executable file)"); ret->bits = rz_bin_te_get_bits(bf->o->bin_obj); diff --git a/librz/core/cbin.c b/librz/core/cbin.c index d9af06a80da..656a6f60b80 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -304,7 +304,7 @@ RZ_API bool rz_core_bin_apply_all_info(RzCore *r, RzBinFile *binfile) { rz_config_set(r->config, "asm.arch", arch); rz_config_set_i(r->config, "asm.bits", bits); rz_config_set(r->config, "analysis.arch", arch); - if (info->cpu && *info->cpu) { + if (RZ_STR_ISNOTEMPTY(info->cpu)) { rz_config_set(r->config, "analysis.cpu", info->cpu); } else { rz_config_set(r->config, "analysis.cpu", arch); @@ -585,10 +585,10 @@ RZ_API bool rz_core_bin_apply_config(RzCore *r, RzBinFile *binfile) { rz_config_set(r->config, "analysis.cpp.abi", "itanium"); } rz_config_set(r->config, "asm.arch", info->arch); - if (info->cpu && *info->cpu) { + if (RZ_STR_ISNOTEMPTY(info->cpu)) { rz_config_set(r->config, "asm.cpu", info->cpu); } - if (info->features && *info->features) { + if (RZ_STR_ISNOTEMPTY(info->features)) { rz_config_set(r->config, "asm.features", info->features); } rz_config_set(r->config, "analysis.arch", info->arch); @@ -3092,6 +3092,7 @@ RZ_API bool rz_core_bin_info_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile case RZ_OUTPUT_MODE_QUIET: rz_cons_printf("arch %s\n", info->arch); rz_cons_printf("cpu %s\n", str2na(info->cpu)); + rz_cons_printf("features %s\n", str2na(info->features)); rz_cons_printf("bits %d\n", bits); rz_cons_printf("os %s\n", info->os); rz_cons_printf("endian %s\n", info->big_endian ? "big" : "little"); @@ -3116,6 +3117,9 @@ RZ_API bool rz_core_bin_info_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile if (RZ_STR_ISNOTEMPTY(info->cpu)) { pj_ks(pj, "cpu", info->cpu); } + if (RZ_STR_ISNOTEMPTY(info->features)) { + pj_ks(pj, "features", info->features); + } pj_kn(pj, "baddr", rz_bin_get_baddr(core->bin)); pj_kn(pj, "binsz", rz_bin_get_size(core->bin)); if (RZ_STR_ISNOTEMPTY(info->rclass)) { @@ -3249,6 +3253,7 @@ RZ_API bool rz_core_bin_info_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBinFile rz_table_add_rowf(t, "ss", "arch", str2na(info->arch)); rz_table_add_rowf(t, "ss", "cpu", str2na(info->cpu)); + rz_table_add_rowf(t, "ss", "features", str2na(info->features)); rz_table_add_rowf(t, "sX", "baddr", rz_bin_get_baddr(core->bin)); rz_table_add_rowf(t, "sX", "binsz", rz_bin_get_size(core->bin)); rz_table_add_rowf(t, "ss", "bintype", str2na(info->rclass)); @@ -5265,8 +5270,8 @@ static void print_arch(RzBin *bin, RzCmdStateOutput *state, struct arch_ctx *ctx pj_ki(state->d.pj, "bits", ctx->bits); pj_kn(state->d.pj, "offset", ctx->offset); pj_kn(state->d.pj, "size", ctx->size); - if (info && !strcmp(ctx->arch, "mips")) { - pj_ks(state->d.pj, "isa", info->cpu); + if (info) { + pj_ks(state->d.pj, "cpu", info->cpu); pj_ks(state->d.pj, "features", info->features); } if (ctx->machine) { diff --git a/librz/core/cesil.c b/librz/core/cesil.c index 111deb6182d..25192c37520 100644 --- a/librz/core/cesil.c +++ b/librz/core/cesil.c @@ -200,7 +200,7 @@ RZ_API int rz_core_esil_step(RzCore *core, ut64 until_addr, const char *until_ex // branches are illegal in a delay slot esil->trap = RZ_ANALYSIS_TRAP_EXEC_ERR; esil->trap_code = addr; - RZ_LOG_WARN("core: ESIL: Trap, trying to execute a branch in a delay slot\n"); + RZ_LOG_INFO("core: ESIL: Trap, trying to execute a branch in a delay slot\n"); return_tail(1); break; } diff --git a/librz/core/golang.c b/librz/core/golang.c index 5a6094bdd67..c0797332786 100644 --- a/librz/core/golang.c +++ b/librz/core/golang.c @@ -1870,6 +1870,7 @@ RZ_API void rz_core_analysis_resolve_golang_strings(RzCore *core) { recover_cb = &golang_recover_string_x64; break; default: + RZ_LOG_WARN("golang: string recovery for %s bits %d is not implemented.\n", asm_arch, asm_bits); break; } } else if (!strcmp(asm_arch, "arm")) { @@ -1881,6 +1882,7 @@ RZ_API void rz_core_analysis_resolve_golang_strings(RzCore *core) { recover_cb = &golang_recover_string_arm64; break; default: + RZ_LOG_WARN("golang: string recovery for %s bits %d is not implemented.\n", asm_arch, asm_bits); break; } } else if (!strcmp(asm_arch, "mips")) { @@ -1892,6 +1894,7 @@ RZ_API void rz_core_analysis_resolve_golang_strings(RzCore *core) { recover_cb = &golang_recover_string_mips64; break; default: + RZ_LOG_WARN("golang: string recovery for %s bits %d is not implemented.\n", asm_arch, asm_bits); break; } } else if (!strcmp(asm_arch, "riscv")) { @@ -1900,6 +1903,7 @@ RZ_API void rz_core_analysis_resolve_golang_strings(RzCore *core) { recover_cb = &golang_recover_string_riscv64; break; default: + RZ_LOG_WARN("golang: string recovery for %s bits %d is not implemented.\n", asm_arch, asm_bits); break; } } else if (!strcmp(asm_arch, "ppc")) { @@ -1908,6 +1912,7 @@ RZ_API void rz_core_analysis_resolve_golang_strings(RzCore *core) { recover_cb = &golang_recover_string_ppc64; break; default: + RZ_LOG_WARN("golang: string recovery for %s bits %d is not implemented.\n", asm_arch, asm_bits); break; } } else if (!strcmp(asm_arch, "sysz")) { diff --git a/test/db/abi/platforms/platform_detect b/test/db/abi/platforms/platform_detect index 2e987fe794f..cb14fa60e40 100644 --- a/test/db/abi/platforms/platform_detect +++ b/test/db/abi/platforms/platform_detect @@ -42,7 +42,7 @@ vaddr paddr hvaddr haddr type 0x004006a0 0x000006a0 0x00400018 0x00000018 program arch mips bits 32 -machine MIPS R3000 +machine MIPS R3000 big-endian EOF RUN @@ -58,7 +58,7 @@ vaddr paddr hvaddr haddr type 0x120000af0 0x00000af0 0x120000018 0x00000018 program arch mips bits 64 -machine MIPS R3000 +machine MIPS R3000 big-endian EOF RUN diff --git a/test/db/analysis/mips b/test/db/analysis/mips index 06890837d71..4f98f39153b 100644 --- a/test/db/analysis/mips +++ b/test/db/analysis/mips @@ -1,3 +1,80 @@ +NAME=mips ensure correct cpu is selected +FILE=bins/elf/analysis/mips-hello +CMDS=< 0x000804fc b 0x804fc +\ 0x00080500 nop + ; UNKNOWN XREF from section..dynsym @ +0xb4 + ; DATA XREF from sym.do_mips_start @ 0x80544 +/ int main(int argc, char **argv, char **envp); +| ; arg int argc @ a0 +| ; var int32_t var_10h @ stack - 0x10 +| ; var int32_t var_8h @ stack - 0x8 +| ; var int32_t var_4h @ stack - 0x4 +| ; arg int32_t arg_10h @ stack + 0x10 +| 0x000805a0 lui gp, 2 +| 0x000805a4 addiu gp, gp, -0x75a0 +| 0x000805a8 addu gp, gp, t9 +| 0x000805ac addiu sp, sp, -0x20 +| 0x000805b0 sw ra, (var_4h) +| 0x000805b4 sw fp, (var_8h) +| 0x000805b8 move fp, sp +| 0x000805bc sw gp, (var_10h) +| 0x000805c0 lw v0, -segment.LOAD0(gp) ; [data.0009103c:4]=0x80000 segment.ehdr +| 0x000805c4 addiu a0, v0, 0x640 ; 0x80640 ; "Hello World" ; argc ; str.Hello_World +| 0x000805c8 lw v0, -sym._MIPS_STUBS(gp) ; [data.00091048:4]=0x80600 sym.imp.puts +| 0x000805cc move t9, v0 +| 0x000805d0 jalr t9 +| 0x000805d4 nop +| 0x000805d8 lw gp, (arg_10h) +| 0x000805dc move sp, fp +| 0x000805e0 lw ra, (var_4h) +| 0x000805e4 lw fp, (var_8h) +| 0x000805e8 addiu sp, sp, 0x20 +| 0x000805ec jr ra +\ 0x000805f0 nop +address: 0x804fc +opcode: b 0x804fc +disasm: b 0x804fc +pseudo: goto 0x804fc +jump: 0x000804fc +EOF +RUN + + NAME=mips hello reference analysis FILE=bins/elf/analysis/mips-hello CMDS=< /dev/null +aa pdf EOF EXPECT=< /dev/null +af pd 10 afl EOF @@ -282,14 +356,15 @@ CMDS=</dev/null +af pdf EOF EXPECT=< /dev/null +af pdf EOF EXPECT=< /dev/null +af pdf + EOF EXPECT=< /dev/null +af pdf EOF EXPECT=< /dev/null +af pdf EOF EXPECT=< /dev/null +af pdf EOF EXPECT=< /dev/null +aa pd 38 EOF EXPECT=< /dev/null -pd 38 -EOF -EXPECT=< /dev/null -pd 38 -EOF -EXPECT=< /dev/null +aa pd 38 EOF EXPECT=<