- Add LICENSES directory - Download additional licenses used - Add .reuse directory - Add doc about SPDX/reuse Co-authored-by: Florian Märkl <info@florianmaerkl.de>
1785 lines
41 KiB
C
1785 lines
41 KiB
C
// SPDX-FileCopyrightText: 2010-2015 pancake <pancake@nopcode.org>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <string.h>
|
|
#include <rz_types.h>
|
|
#include <rz_lib.h>
|
|
#include <rz_asm.h>
|
|
#include <rz_analysis.h>
|
|
|
|
static ut64 t9_pre = UT64_MAX;
|
|
#define REG_BUF_MAX 32
|
|
// ESIL macros:
|
|
|
|
// put the sign bit on the stack
|
|
#define ES_IS_NEGATIVE(arg) "1," arg ",<<<,1,&"
|
|
|
|
#define ES_B(x) "0xff," x ",&"
|
|
#define ES_H(x) "0xffff," x ",&"
|
|
#define ES_W(x) "0xffffffff," x ",&"
|
|
// 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_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);
|
|
}
|
|
// MIPS instruction
|
|
typedef enum mips_insn {
|
|
MIPS_INS_INVALID = 0,
|
|
|
|
MIPS_INS_ABSQ_S,
|
|
MIPS_INS_ADD,
|
|
MIPS_INS_ADDIUPC,
|
|
MIPS_INS_ADDIUR1SP,
|
|
MIPS_INS_ADDIUR2,
|
|
MIPS_INS_ADDIUS5,
|
|
MIPS_INS_ADDIUSP,
|
|
MIPS_INS_ADDQH,
|
|
MIPS_INS_ADDQH_R,
|
|
MIPS_INS_ADDQ,
|
|
MIPS_INS_ADDQ_S,
|
|
MIPS_INS_ADDSC,
|
|
MIPS_INS_ADDS_A,
|
|
MIPS_INS_ADDS_S,
|
|
MIPS_INS_ADDS_U,
|
|
MIPS_INS_ADDU16,
|
|
MIPS_INS_ADDUH,
|
|
MIPS_INS_ADDUH_R,
|
|
MIPS_INS_ADDU,
|
|
MIPS_INS_ADDU_S,
|
|
MIPS_INS_ADDVI,
|
|
MIPS_INS_ADDV,
|
|
MIPS_INS_ADDWC,
|
|
MIPS_INS_ADD_A,
|
|
MIPS_INS_ADDI,
|
|
MIPS_INS_ADDIU,
|
|
MIPS_INS_ALIGN,
|
|
MIPS_INS_ALUIPC,
|
|
MIPS_INS_AND,
|
|
MIPS_INS_AND16,
|
|
MIPS_INS_ANDI16,
|
|
MIPS_INS_ANDI,
|
|
MIPS_INS_APPEND,
|
|
MIPS_INS_ASUB_S,
|
|
MIPS_INS_ASUB_U,
|
|
MIPS_INS_AUI,
|
|
MIPS_INS_AUIPC,
|
|
MIPS_INS_AVER_S,
|
|
MIPS_INS_AVER_U,
|
|
MIPS_INS_AVE_S,
|
|
MIPS_INS_AVE_U,
|
|
MIPS_INS_B16,
|
|
MIPS_INS_BADDU,
|
|
MIPS_INS_BAL,
|
|
MIPS_INS_BALC,
|
|
MIPS_INS_BALIGN,
|
|
MIPS_INS_BBIT0,
|
|
MIPS_INS_BBIT032,
|
|
MIPS_INS_BBIT1,
|
|
MIPS_INS_BBIT132,
|
|
MIPS_INS_BC,
|
|
MIPS_INS_BC0F,
|
|
MIPS_INS_BC0FL,
|
|
MIPS_INS_BC0T,
|
|
MIPS_INS_BC0TL,
|
|
MIPS_INS_BC1EQZ,
|
|
MIPS_INS_BC1F,
|
|
MIPS_INS_BC1FL,
|
|
MIPS_INS_BC1NEZ,
|
|
MIPS_INS_BC1T,
|
|
MIPS_INS_BC1TL,
|
|
MIPS_INS_BC2EQZ,
|
|
MIPS_INS_BC2F,
|
|
MIPS_INS_BC2FL,
|
|
MIPS_INS_BC2NEZ,
|
|
MIPS_INS_BC2T,
|
|
MIPS_INS_BC2TL,
|
|
MIPS_INS_BC3F,
|
|
MIPS_INS_BC3FL,
|
|
MIPS_INS_BC3T,
|
|
MIPS_INS_BC3TL,
|
|
MIPS_INS_BCLRI,
|
|
MIPS_INS_BCLR,
|
|
MIPS_INS_BEQ,
|
|
MIPS_INS_BEQC,
|
|
MIPS_INS_BEQL,
|
|
MIPS_INS_BEQZ16,
|
|
MIPS_INS_BEQZALC,
|
|
MIPS_INS_BEQZC,
|
|
MIPS_INS_BGEC,
|
|
MIPS_INS_BGEUC,
|
|
MIPS_INS_BGEZ,
|
|
MIPS_INS_BGEZAL,
|
|
MIPS_INS_BGEZALC,
|
|
MIPS_INS_BGEZALL,
|
|
MIPS_INS_BGEZALS,
|
|
MIPS_INS_BGEZC,
|
|
MIPS_INS_BGEZL,
|
|
MIPS_INS_BGTZ,
|
|
MIPS_INS_BGTZALC,
|
|
MIPS_INS_BGTZC,
|
|
MIPS_INS_BGTZL,
|
|
MIPS_INS_BINSLI,
|
|
MIPS_INS_BINSL,
|
|
MIPS_INS_BINSRI,
|
|
MIPS_INS_BINSR,
|
|
MIPS_INS_BITREV,
|
|
MIPS_INS_BITSWAP,
|
|
MIPS_INS_BLEZ,
|
|
MIPS_INS_BLEZALC,
|
|
MIPS_INS_BLEZC,
|
|
MIPS_INS_BLEZL,
|
|
MIPS_INS_BLTC,
|
|
MIPS_INS_BLTUC,
|
|
MIPS_INS_BLTZ,
|
|
MIPS_INS_BLTZAL,
|
|
MIPS_INS_BLTZALC,
|
|
MIPS_INS_BLTZALL,
|
|
MIPS_INS_BLTZALS,
|
|
MIPS_INS_BLTZC,
|
|
MIPS_INS_BLTZL,
|
|
MIPS_INS_BMNZI,
|
|
MIPS_INS_BMNZ,
|
|
MIPS_INS_BMZI,
|
|
MIPS_INS_BMZ,
|
|
MIPS_INS_BNE,
|
|
MIPS_INS_BNEC,
|
|
MIPS_INS_BNEGI,
|
|
MIPS_INS_BNEG,
|
|
MIPS_INS_BNEL,
|
|
MIPS_INS_BNEZ16,
|
|
MIPS_INS_BNEZALC,
|
|
MIPS_INS_BNEZC,
|
|
MIPS_INS_BNVC,
|
|
MIPS_INS_BNZ,
|
|
MIPS_INS_BOVC,
|
|
MIPS_INS_BPOSGE32,
|
|
MIPS_INS_BREAK,
|
|
MIPS_INS_BREAK16,
|
|
MIPS_INS_BSELI,
|
|
MIPS_INS_BSEL,
|
|
MIPS_INS_BSETI,
|
|
MIPS_INS_BSET,
|
|
MIPS_INS_BZ,
|
|
MIPS_INS_BEQZ,
|
|
MIPS_INS_B,
|
|
MIPS_INS_BNEZ,
|
|
MIPS_INS_BTEQZ,
|
|
MIPS_INS_BTNEZ,
|
|
MIPS_INS_CACHE,
|
|
MIPS_INS_CEIL,
|
|
MIPS_INS_CEQI,
|
|
MIPS_INS_CEQ,
|
|
MIPS_INS_CFC1,
|
|
MIPS_INS_CFCMSA,
|
|
MIPS_INS_CINS,
|
|
MIPS_INS_CINS32,
|
|
MIPS_INS_CLASS,
|
|
MIPS_INS_CLEI_S,
|
|
MIPS_INS_CLEI_U,
|
|
MIPS_INS_CLE_S,
|
|
MIPS_INS_CLE_U,
|
|
MIPS_INS_CLO,
|
|
MIPS_INS_CLTI_S,
|
|
MIPS_INS_CLTI_U,
|
|
MIPS_INS_CLT_S,
|
|
MIPS_INS_CLT_U,
|
|
MIPS_INS_CLZ,
|
|
MIPS_INS_CMPGDU,
|
|
MIPS_INS_CMPGU,
|
|
MIPS_INS_CMPU,
|
|
MIPS_INS_CMP,
|
|
MIPS_INS_COPY_S,
|
|
MIPS_INS_COPY_U,
|
|
MIPS_INS_CTC1,
|
|
MIPS_INS_CTCMSA,
|
|
MIPS_INS_CVT,
|
|
MIPS_INS_C,
|
|
MIPS_INS_CMPI,
|
|
MIPS_INS_DADD,
|
|
MIPS_INS_DADDI,
|
|
MIPS_INS_DADDIU,
|
|
MIPS_INS_DADDU,
|
|
MIPS_INS_DAHI,
|
|
MIPS_INS_DALIGN,
|
|
MIPS_INS_DATI,
|
|
MIPS_INS_DAUI,
|
|
MIPS_INS_DBITSWAP,
|
|
MIPS_INS_DCLO,
|
|
MIPS_INS_DCLZ,
|
|
MIPS_INS_DDIV,
|
|
MIPS_INS_DDIVU,
|
|
MIPS_INS_DERET,
|
|
MIPS_INS_DEXT,
|
|
MIPS_INS_DEXTM,
|
|
MIPS_INS_DEXTU,
|
|
MIPS_INS_DI,
|
|
MIPS_INS_DINS,
|
|
MIPS_INS_DINSM,
|
|
MIPS_INS_DINSU,
|
|
MIPS_INS_DIV,
|
|
MIPS_INS_DIVU,
|
|
MIPS_INS_DIV_S,
|
|
MIPS_INS_DIV_U,
|
|
MIPS_INS_DLSA,
|
|
MIPS_INS_DMFC0,
|
|
MIPS_INS_DMFC1,
|
|
MIPS_INS_DMFC2,
|
|
MIPS_INS_DMOD,
|
|
MIPS_INS_DMODU,
|
|
MIPS_INS_DMTC0,
|
|
MIPS_INS_DMTC1,
|
|
MIPS_INS_DMTC2,
|
|
MIPS_INS_DMUH,
|
|
MIPS_INS_DMUHU,
|
|
MIPS_INS_DMUL,
|
|
MIPS_INS_DMULT,
|
|
MIPS_INS_DMULTU,
|
|
MIPS_INS_DMULU,
|
|
MIPS_INS_DOTP_S,
|
|
MIPS_INS_DOTP_U,
|
|
MIPS_INS_DPADD_S,
|
|
MIPS_INS_DPADD_U,
|
|
MIPS_INS_DPAQX_SA,
|
|
MIPS_INS_DPAQX_S,
|
|
MIPS_INS_DPAQ_SA,
|
|
MIPS_INS_DPAQ_S,
|
|
MIPS_INS_DPAU,
|
|
MIPS_INS_DPAX,
|
|
MIPS_INS_DPA,
|
|
MIPS_INS_DPOP,
|
|
MIPS_INS_DPSQX_SA,
|
|
MIPS_INS_DPSQX_S,
|
|
MIPS_INS_DPSQ_SA,
|
|
MIPS_INS_DPSQ_S,
|
|
MIPS_INS_DPSUB_S,
|
|
MIPS_INS_DPSUB_U,
|
|
MIPS_INS_DPSU,
|
|
MIPS_INS_DPSX,
|
|
MIPS_INS_DPS,
|
|
MIPS_INS_DROTR,
|
|
MIPS_INS_DROTR32,
|
|
MIPS_INS_DROTRV,
|
|
MIPS_INS_DSBH,
|
|
MIPS_INS_DSHD,
|
|
MIPS_INS_DSLL,
|
|
MIPS_INS_DSLL32,
|
|
MIPS_INS_DSLLV,
|
|
MIPS_INS_DSRA,
|
|
MIPS_INS_DSRA32,
|
|
MIPS_INS_DSRAV,
|
|
MIPS_INS_DSRL,
|
|
MIPS_INS_DSRL32,
|
|
MIPS_INS_DSRLV,
|
|
MIPS_INS_DSUB,
|
|
MIPS_INS_DSUBU,
|
|
MIPS_INS_EHB,
|
|
MIPS_INS_EI,
|
|
MIPS_INS_ERET,
|
|
MIPS_INS_EXT,
|
|
MIPS_INS_EXTP,
|
|
MIPS_INS_EXTPDP,
|
|
MIPS_INS_EXTPDPV,
|
|
MIPS_INS_EXTPV,
|
|
MIPS_INS_EXTRV_RS,
|
|
MIPS_INS_EXTRV_R,
|
|
MIPS_INS_EXTRV_S,
|
|
MIPS_INS_EXTRV,
|
|
MIPS_INS_EXTR_RS,
|
|
MIPS_INS_EXTR_R,
|
|
MIPS_INS_EXTR_S,
|
|
MIPS_INS_EXTR,
|
|
MIPS_INS_EXTS,
|
|
MIPS_INS_EXTS32,
|
|
MIPS_INS_ABS,
|
|
MIPS_INS_FADD,
|
|
MIPS_INS_FCAF,
|
|
MIPS_INS_FCEQ,
|
|
MIPS_INS_FCLASS,
|
|
MIPS_INS_FCLE,
|
|
MIPS_INS_FCLT,
|
|
MIPS_INS_FCNE,
|
|
MIPS_INS_FCOR,
|
|
MIPS_INS_FCUEQ,
|
|
MIPS_INS_FCULE,
|
|
MIPS_INS_FCULT,
|
|
MIPS_INS_FCUNE,
|
|
MIPS_INS_FCUN,
|
|
MIPS_INS_FDIV,
|
|
MIPS_INS_FEXDO,
|
|
MIPS_INS_FEXP2,
|
|
MIPS_INS_FEXUPL,
|
|
MIPS_INS_FEXUPR,
|
|
MIPS_INS_FFINT_S,
|
|
MIPS_INS_FFINT_U,
|
|
MIPS_INS_FFQL,
|
|
MIPS_INS_FFQR,
|
|
MIPS_INS_FILL,
|
|
MIPS_INS_FLOG2,
|
|
MIPS_INS_FLOOR,
|
|
MIPS_INS_FMADD,
|
|
MIPS_INS_FMAX_A,
|
|
MIPS_INS_FMAX,
|
|
MIPS_INS_FMIN_A,
|
|
MIPS_INS_FMIN,
|
|
MIPS_INS_MOV,
|
|
MIPS_INS_FMSUB,
|
|
MIPS_INS_FMUL,
|
|
MIPS_INS_MUL,
|
|
MIPS_INS_NEG,
|
|
MIPS_INS_FRCP,
|
|
MIPS_INS_FRINT,
|
|
MIPS_INS_FRSQRT,
|
|
MIPS_INS_FSAF,
|
|
MIPS_INS_FSEQ,
|
|
MIPS_INS_FSLE,
|
|
MIPS_INS_FSLT,
|
|
MIPS_INS_FSNE,
|
|
MIPS_INS_FSOR,
|
|
MIPS_INS_FSQRT,
|
|
MIPS_INS_SQRT,
|
|
MIPS_INS_FSUB,
|
|
MIPS_INS_SUB,
|
|
MIPS_INS_FSUEQ,
|
|
MIPS_INS_FSULE,
|
|
MIPS_INS_FSULT,
|
|
MIPS_INS_FSUNE,
|
|
MIPS_INS_FSUN,
|
|
MIPS_INS_FTINT_S,
|
|
MIPS_INS_FTINT_U,
|
|
MIPS_INS_FTQ,
|
|
MIPS_INS_FTRUNC_S,
|
|
MIPS_INS_FTRUNC_U,
|
|
MIPS_INS_HADD_S,
|
|
MIPS_INS_HADD_U,
|
|
MIPS_INS_HSUB_S,
|
|
MIPS_INS_HSUB_U,
|
|
MIPS_INS_ILVEV,
|
|
MIPS_INS_ILVL,
|
|
MIPS_INS_ILVOD,
|
|
MIPS_INS_ILVR,
|
|
MIPS_INS_INS,
|
|
MIPS_INS_INSERT,
|
|
MIPS_INS_INSV,
|
|
MIPS_INS_INSVE,
|
|
MIPS_INS_J,
|
|
MIPS_INS_JAL,
|
|
MIPS_INS_JALR,
|
|
MIPS_INS_JALRS16,
|
|
MIPS_INS_JALRS,
|
|
MIPS_INS_JALS,
|
|
MIPS_INS_JALX,
|
|
MIPS_INS_JIALC,
|
|
MIPS_INS_JIC,
|
|
MIPS_INS_JR,
|
|
MIPS_INS_JR16,
|
|
MIPS_INS_JRADDIUSP,
|
|
MIPS_INS_JRC,
|
|
MIPS_INS_JALRC,
|
|
MIPS_INS_LB,
|
|
MIPS_INS_LBU16,
|
|
MIPS_INS_LBUX,
|
|
MIPS_INS_LBU,
|
|
MIPS_INS_LD,
|
|
MIPS_INS_LDC1,
|
|
MIPS_INS_LDC2,
|
|
MIPS_INS_LDC3,
|
|
MIPS_INS_LDI,
|
|
MIPS_INS_LDL,
|
|
MIPS_INS_LDPC,
|
|
MIPS_INS_LDR,
|
|
MIPS_INS_LDXC1,
|
|
MIPS_INS_LH,
|
|
MIPS_INS_LHU16,
|
|
MIPS_INS_LHX,
|
|
MIPS_INS_LHU,
|
|
MIPS_INS_LI16,
|
|
MIPS_INS_LL,
|
|
MIPS_INS_LLD,
|
|
MIPS_INS_LSA,
|
|
MIPS_INS_LUXC1,
|
|
MIPS_INS_LUI,
|
|
MIPS_INS_LW,
|
|
MIPS_INS_LW16,
|
|
MIPS_INS_LWC1,
|
|
MIPS_INS_LWC2,
|
|
MIPS_INS_LWC3,
|
|
MIPS_INS_LWL,
|
|
MIPS_INS_LWM16,
|
|
MIPS_INS_LWM32,
|
|
MIPS_INS_LWPC,
|
|
MIPS_INS_LWP,
|
|
MIPS_INS_LWR,
|
|
MIPS_INS_LWUPC,
|
|
MIPS_INS_LWU,
|
|
MIPS_INS_LWX,
|
|
MIPS_INS_LWXC1,
|
|
MIPS_INS_LWXS,
|
|
MIPS_INS_LI,
|
|
MIPS_INS_MADD,
|
|
MIPS_INS_MADDF,
|
|
MIPS_INS_MADDR_Q,
|
|
MIPS_INS_MADDU,
|
|
MIPS_INS_MADDV,
|
|
MIPS_INS_MADD_Q,
|
|
MIPS_INS_MAQ_SA,
|
|
MIPS_INS_MAQ_S,
|
|
MIPS_INS_MAXA,
|
|
MIPS_INS_MAXI_S,
|
|
MIPS_INS_MAXI_U,
|
|
MIPS_INS_MAX_A,
|
|
MIPS_INS_MAX,
|
|
MIPS_INS_MAX_S,
|
|
MIPS_INS_MAX_U,
|
|
MIPS_INS_MFC0,
|
|
MIPS_INS_MFC1,
|
|
MIPS_INS_MFC2,
|
|
MIPS_INS_MFHC1,
|
|
MIPS_INS_MFHI,
|
|
MIPS_INS_MFLO,
|
|
MIPS_INS_MINA,
|
|
MIPS_INS_MINI_S,
|
|
MIPS_INS_MINI_U,
|
|
MIPS_INS_MIN_A,
|
|
MIPS_INS_MIN,
|
|
MIPS_INS_MIN_S,
|
|
MIPS_INS_MIN_U,
|
|
MIPS_INS_MOD,
|
|
MIPS_INS_MODSUB,
|
|
MIPS_INS_MODU,
|
|
MIPS_INS_MOD_S,
|
|
MIPS_INS_MOD_U,
|
|
MIPS_INS_MOVE,
|
|
MIPS_INS_MOVEP,
|
|
MIPS_INS_MOVF,
|
|
MIPS_INS_MOVN,
|
|
MIPS_INS_MOVT,
|
|
MIPS_INS_MOVZ,
|
|
MIPS_INS_MSUB,
|
|
MIPS_INS_MSUBF,
|
|
MIPS_INS_MSUBR_Q,
|
|
MIPS_INS_MSUBU,
|
|
MIPS_INS_MSUBV,
|
|
MIPS_INS_MSUB_Q,
|
|
MIPS_INS_MTC0,
|
|
MIPS_INS_MTC1,
|
|
MIPS_INS_MTC2,
|
|
MIPS_INS_MTHC1,
|
|
MIPS_INS_MTHI,
|
|
MIPS_INS_MTHLIP,
|
|
MIPS_INS_MTLO,
|
|
MIPS_INS_MTM0,
|
|
MIPS_INS_MTM1,
|
|
MIPS_INS_MTM2,
|
|
MIPS_INS_MTP0,
|
|
MIPS_INS_MTP1,
|
|
MIPS_INS_MTP2,
|
|
MIPS_INS_MUH,
|
|
MIPS_INS_MUHU,
|
|
MIPS_INS_MULEQ_S,
|
|
MIPS_INS_MULEU_S,
|
|
MIPS_INS_MULQ_RS,
|
|
MIPS_INS_MULQ_S,
|
|
MIPS_INS_MULR_Q,
|
|
MIPS_INS_MULSAQ_S,
|
|
MIPS_INS_MULSA,
|
|
MIPS_INS_MULT,
|
|
MIPS_INS_MULTU,
|
|
MIPS_INS_MULU,
|
|
MIPS_INS_MULV,
|
|
MIPS_INS_MUL_Q,
|
|
MIPS_INS_MUL_S,
|
|
MIPS_INS_NLOC,
|
|
MIPS_INS_NLZC,
|
|
MIPS_INS_NMADD,
|
|
MIPS_INS_NMSUB,
|
|
MIPS_INS_NOR,
|
|
MIPS_INS_NORI,
|
|
MIPS_INS_NOT16,
|
|
MIPS_INS_NOT,
|
|
MIPS_INS_OR,
|
|
MIPS_INS_OR16,
|
|
MIPS_INS_ORI,
|
|
MIPS_INS_PACKRL,
|
|
MIPS_INS_PAUSE,
|
|
MIPS_INS_PCKEV,
|
|
MIPS_INS_PCKOD,
|
|
MIPS_INS_PCNT,
|
|
MIPS_INS_PICK,
|
|
MIPS_INS_POP,
|
|
MIPS_INS_PRECEQU,
|
|
MIPS_INS_PRECEQ,
|
|
MIPS_INS_PRECEU,
|
|
MIPS_INS_PRECRQU_S,
|
|
MIPS_INS_PRECRQ,
|
|
MIPS_INS_PRECRQ_RS,
|
|
MIPS_INS_PRECR,
|
|
MIPS_INS_PRECR_SRA,
|
|
MIPS_INS_PRECR_SRA_R,
|
|
MIPS_INS_PREF,
|
|
MIPS_INS_PREPEND,
|
|
MIPS_INS_RADDU,
|
|
MIPS_INS_RDDSP,
|
|
MIPS_INS_RDHWR,
|
|
MIPS_INS_REPLV,
|
|
MIPS_INS_REPL,
|
|
MIPS_INS_RINT,
|
|
MIPS_INS_ROTR,
|
|
MIPS_INS_ROTRV,
|
|
MIPS_INS_ROUND,
|
|
MIPS_INS_SAT_S,
|
|
MIPS_INS_SAT_U,
|
|
MIPS_INS_SB,
|
|
MIPS_INS_SB16,
|
|
MIPS_INS_SC,
|
|
MIPS_INS_SCD,
|
|
MIPS_INS_SD,
|
|
MIPS_INS_SDBBP,
|
|
MIPS_INS_SDBBP16,
|
|
MIPS_INS_SDC1,
|
|
MIPS_INS_SDC2,
|
|
MIPS_INS_SDC3,
|
|
MIPS_INS_SDL,
|
|
MIPS_INS_SDR,
|
|
MIPS_INS_SDXC1,
|
|
MIPS_INS_SEB,
|
|
MIPS_INS_SEH,
|
|
MIPS_INS_SELEQZ,
|
|
MIPS_INS_SELNEZ,
|
|
MIPS_INS_SEL,
|
|
MIPS_INS_SEQ,
|
|
MIPS_INS_SEQI,
|
|
MIPS_INS_SH,
|
|
MIPS_INS_SH16,
|
|
MIPS_INS_SHF,
|
|
MIPS_INS_SHILO,
|
|
MIPS_INS_SHILOV,
|
|
MIPS_INS_SHLLV,
|
|
MIPS_INS_SHLLV_S,
|
|
MIPS_INS_SHLL,
|
|
MIPS_INS_SHLL_S,
|
|
MIPS_INS_SHRAV,
|
|
MIPS_INS_SHRAV_R,
|
|
MIPS_INS_SHRA,
|
|
MIPS_INS_SHRA_R,
|
|
MIPS_INS_SHRLV,
|
|
MIPS_INS_SHRL,
|
|
MIPS_INS_SLDI,
|
|
MIPS_INS_SLD,
|
|
MIPS_INS_SLL,
|
|
MIPS_INS_SLL16,
|
|
MIPS_INS_SLLI,
|
|
MIPS_INS_SLLV,
|
|
MIPS_INS_SLT,
|
|
MIPS_INS_SLTI,
|
|
MIPS_INS_SLTIU,
|
|
MIPS_INS_SLTU,
|
|
MIPS_INS_SNE,
|
|
MIPS_INS_SNEI,
|
|
MIPS_INS_SPLATI,
|
|
MIPS_INS_SPLAT,
|
|
MIPS_INS_SRA,
|
|
MIPS_INS_SRAI,
|
|
MIPS_INS_SRARI,
|
|
MIPS_INS_SRAR,
|
|
MIPS_INS_SRAV,
|
|
MIPS_INS_SRL,
|
|
MIPS_INS_SRL16,
|
|
MIPS_INS_SRLI,
|
|
MIPS_INS_SRLRI,
|
|
MIPS_INS_SRLR,
|
|
MIPS_INS_SRLV,
|
|
MIPS_INS_SSNOP,
|
|
MIPS_INS_ST,
|
|
MIPS_INS_SUBQH,
|
|
MIPS_INS_SUBQH_R,
|
|
MIPS_INS_SUBQ,
|
|
MIPS_INS_SUBQ_S,
|
|
MIPS_INS_SUBSUS_U,
|
|
MIPS_INS_SUBSUU_S,
|
|
MIPS_INS_SUBS_S,
|
|
MIPS_INS_SUBS_U,
|
|
MIPS_INS_SUBU16,
|
|
MIPS_INS_SUBUH,
|
|
MIPS_INS_SUBUH_R,
|
|
MIPS_INS_SUBU,
|
|
MIPS_INS_SUBU_S,
|
|
MIPS_INS_SUBVI,
|
|
MIPS_INS_SUBV,
|
|
MIPS_INS_SUXC1,
|
|
MIPS_INS_SW,
|
|
MIPS_INS_SW16,
|
|
MIPS_INS_SWC1,
|
|
MIPS_INS_SWC2,
|
|
MIPS_INS_SWC3,
|
|
MIPS_INS_SWL,
|
|
MIPS_INS_SWM16,
|
|
MIPS_INS_SWM32,
|
|
MIPS_INS_SWP,
|
|
MIPS_INS_SWR,
|
|
MIPS_INS_SWXC1,
|
|
MIPS_INS_SYNC,
|
|
MIPS_INS_SYNCI,
|
|
MIPS_INS_SYSCALL,
|
|
MIPS_INS_TEQ,
|
|
MIPS_INS_TEQI,
|
|
MIPS_INS_TGE,
|
|
MIPS_INS_TGEI,
|
|
MIPS_INS_TGEIU,
|
|
MIPS_INS_TGEU,
|
|
MIPS_INS_TLBP,
|
|
MIPS_INS_TLBR,
|
|
MIPS_INS_TLBWI,
|
|
MIPS_INS_TLBWR,
|
|
MIPS_INS_TLT,
|
|
MIPS_INS_TLTI,
|
|
MIPS_INS_TLTIU,
|
|
MIPS_INS_TLTU,
|
|
MIPS_INS_TNE,
|
|
MIPS_INS_TNEI,
|
|
MIPS_INS_TRUNC,
|
|
MIPS_INS_V3MULU,
|
|
MIPS_INS_VMM0,
|
|
MIPS_INS_VMULU,
|
|
MIPS_INS_VSHF,
|
|
MIPS_INS_WAIT,
|
|
MIPS_INS_WRDSP,
|
|
MIPS_INS_WSBH,
|
|
MIPS_INS_XOR,
|
|
MIPS_INS_XOR16,
|
|
MIPS_INS_XORI,
|
|
|
|
//> some alias instructions
|
|
MIPS_INS_NOP,
|
|
MIPS_INS_NEGU,
|
|
|
|
//> special instructions
|
|
MIPS_INS_JALR_HB, // jump and link with Hazard Barrier
|
|
MIPS_INS_JR_HB, // jump register with Hazard Barrier
|
|
|
|
MIPS_INS_ENDING,
|
|
} mips_insn;
|
|
|
|
struct gnu_rreg {
|
|
const char *rs;
|
|
const char *rt;
|
|
const char *rd;
|
|
ut8 sa[REG_BUF_MAX];
|
|
};
|
|
|
|
struct gnu_jreg {
|
|
ut8 jump[REG_BUF_MAX];
|
|
};
|
|
|
|
struct gnu_ireg {
|
|
const char *rs;
|
|
const char *rt;
|
|
union {
|
|
ut8 imm[REG_BUF_MAX];
|
|
ut8 jump[REG_BUF_MAX];
|
|
};
|
|
};
|
|
|
|
typedef struct gnu_insn {
|
|
ut8 optype;
|
|
ut32 id;
|
|
union {
|
|
struct gnu_rreg r_reg;
|
|
struct gnu_ireg i_reg;
|
|
struct gnu_jreg j_reg;
|
|
};
|
|
} gnu_insn;
|
|
|
|
#define R_REG(x) ((const char *)insn->r_reg.x)
|
|
#define I_REG(x) ((const char *)insn->i_reg.x)
|
|
#define J_REG(x) ((const char *)insn->j_reg.x)
|
|
|
|
/* Return a mapping from the register number i.e. $0 .. $31 to string name */
|
|
static const char *mips_reg_decode(ut32 reg_num) {
|
|
/* See page 36 of "See Mips Run Linux, 2e, D. Sweetman, 2007"*/
|
|
static const char *REGISTERS[32] = {
|
|
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
|
|
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
|
|
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
|
|
"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
|
|
};
|
|
if (reg_num < 32) {
|
|
return REGISTERS[reg_num];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int analop_esil(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, gnu_insn *insn) {
|
|
|
|
switch (insn->id) {
|
|
case MIPS_INS_NOP:
|
|
rz_strbuf_setf(&op->esil, ",");
|
|
break;
|
|
case MIPS_INS_BREAK:
|
|
//rz_strbuf_setf (&op->esil, "%d,%d,TRAP", IMM (0), IMM (0));
|
|
break;
|
|
case MIPS_INS_SD:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,%s,+,=[8]",
|
|
I_REG(rt), I_REG(imm), I_REG(rs));
|
|
break;
|
|
case MIPS_INS_SW:
|
|
case MIPS_INS_SWL:
|
|
case MIPS_INS_SWR:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,%s,+,=[4]",
|
|
I_REG(rt), I_REG(imm), I_REG(rs));
|
|
break;
|
|
case MIPS_INS_SH:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,%s,+,=[2]",
|
|
I_REG(rt), I_REG(imm), I_REG(rs));
|
|
break;
|
|
case MIPS_INS_SWC1:
|
|
case MIPS_INS_SWC2:
|
|
break;
|
|
case MIPS_INS_SB:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,%s,+,=[1]",
|
|
I_REG(rt), I_REG(imm), I_REG(rs));
|
|
break;
|
|
case MIPS_INS_CMP:
|
|
case MIPS_INS_CMPU:
|
|
case MIPS_INS_CMPGU:
|
|
case MIPS_INS_CMPGDU:
|
|
case MIPS_INS_CMPI:
|
|
break;
|
|
case MIPS_INS_SHRAV:
|
|
case MIPS_INS_SHRAV_R:
|
|
case MIPS_INS_SHRA:
|
|
case MIPS_INS_SHRA_R:
|
|
break;
|
|
case MIPS_INS_SRA:
|
|
rz_strbuf_appendf(&op->esil,
|
|
ES_W("%s,%s") ",>>,31,%s,>>,?{,%s,32,-,0xffffffff,<<,0xffffffff,&,}{,0,},|,%s,=",
|
|
R_REG(sa), R_REG(rt), R_REG(rt), R_REG(sa), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_DSRA:
|
|
rz_strbuf_appendf(&op->esil,
|
|
"%s,%s,>>,31,%s,>>,?{,32,%s,32,-,0xffffffff,<<,0xffffffff,&,<<,}{,0,},|,%s,=",
|
|
R_REG(sa), R_REG(rt), R_REG(rt), R_REG(sa), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_SHRL:
|
|
// suffix 'S' forces conditional flag to be updated
|
|
break;
|
|
case MIPS_INS_SRLV:
|
|
case MIPS_INS_SRL:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,>>,%s,=",
|
|
R_REG(rs) ? R_REG(rs) : R_REG(sa), R_REG(rt), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_SLLV:
|
|
case MIPS_INS_SLL:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,<<,%s,=",
|
|
R_REG(rs) ? R_REG(rs) : R_REG(sa), R_REG(rt), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_BAL:
|
|
case MIPS_INS_JAL:
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_CALL_D("%s"), I_REG(jump));
|
|
break;
|
|
case MIPS_INS_JALR:
|
|
case MIPS_INS_JALRS:
|
|
if (strcmp(R_REG(rd), "rd") == 0) {
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_CALL_D("%s"), R_REG(rs));
|
|
} else {
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_CALL_DR("%s", "%s"), R_REG(rd), R_REG(rs));
|
|
}
|
|
break;
|
|
case MIPS_INS_JR:
|
|
case MIPS_INS_JRC:
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_J("%s"), R_REG(rs));
|
|
break;
|
|
case MIPS_INS_J:
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_J("%s"), J_REG(jump));
|
|
case MIPS_INS_B:
|
|
// jump to address with conditional
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "" ES_J("%s"), I_REG(jump));
|
|
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") ",}",
|
|
I_REG(rs), I_REG(rt), I_REG(jump));
|
|
break;
|
|
case MIPS_INS_BEQ:
|
|
case MIPS_INS_BEQL:
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,%s,==,$z,?{," ES_J("%s") ",}",
|
|
I_REG(rs), I_REG(rt), I_REG(jump));
|
|
break;
|
|
case MIPS_INS_BZ:
|
|
case MIPS_INS_BEQZ:
|
|
case MIPS_INS_BEQZC:
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,0,==,$z,?{," ES_J("%s") ",}",
|
|
I_REG(rs), I_REG(jump));
|
|
break;
|
|
case MIPS_INS_BNEZ:
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "%s,0,==,$z,!,?{," ES_J("%s") ",}",
|
|
I_REG(rs), I_REG(jump));
|
|
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,},",
|
|
I_REG(rs), I_REG(jump));
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "1," ES_IS_NEGATIVE("%s") ",==,$z,?{," ES_J("%s") ",}",
|
|
I_REG(rs), I_REG(jump));
|
|
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") ",}",
|
|
I_REG(rs), I_REG(jump));
|
|
break;
|
|
case MIPS_INS_BGEZAL:
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0," ES_IS_NEGATIVE("%s") ",==,$z,?{," ES_CALL_D("%s") ",}",
|
|
I_REG(rs), I_REG(jump));
|
|
break;
|
|
case MIPS_INS_BLTZAL:
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "1," ES_IS_NEGATIVE("%s") ",==,$z,?{," ES_CALL_D("%s") ",}",
|
|
I_REG(rs), I_REG(jump));
|
|
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") ",}",
|
|
I_REG(rs), I_REG(jump));
|
|
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,},", I_REG(rs));
|
|
rz_strbuf_appendf(&op->esil, ES_TRAP_DS() "0," ES_IS_NEGATIVE("%s") ",==,$z,?{," ES_J("%s") ",}",
|
|
I_REG(rs), I_REG(jump));
|
|
break;
|
|
case MIPS_INS_BTEQZ:
|
|
break;
|
|
case MIPS_INS_BTNEZ:
|
|
break;
|
|
case MIPS_INS_MOV:
|
|
case MIPS_INS_MOVE:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,=", R_REG(rs), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_MOVZ:
|
|
case MIPS_INS_MOVF:
|
|
rz_strbuf_appendf(&op->esil, "0,%s,==,$z,?{,%s,%s,=,}",
|
|
R_REG(rt), R_REG(rs), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_MOVT:
|
|
rz_strbuf_appendf(&op->esil, "1,%s,==,$z,?{,%s,%s,=,}",
|
|
R_REG(rt), R_REG(rs), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_FSUB:
|
|
case MIPS_INS_SUB:
|
|
case MIPS_INS_SUBU:
|
|
case MIPS_INS_DSUB:
|
|
case MIPS_INS_DSUBU:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,-,%s,=",
|
|
R_REG(rt), R_REG(rs), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_NEG:
|
|
case MIPS_INS_NEGU:
|
|
break;
|
|
/** signed -- sets overflow flag */
|
|
case MIPS_INS_ADD:
|
|
ES_ADD_CK32_OVERF(R_REG(rs), R_REG(rt), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_ADDI:
|
|
ES_ADD_CK32_OVERF(I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_DADD:
|
|
ES_ADD_CK64_OVERF(R_REG(rs), R_REG(rt), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_DADDU:
|
|
case MIPS_INS_ADDU:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,+,%s,=",
|
|
R_REG(rt), R_REG(rs), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_DADDI:
|
|
ES_ADD_CK64_OVERF(I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_ADDIU:
|
|
case MIPS_INS_DADDIU:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,+,%s,=",
|
|
I_REG(imm), I_REG(rs), I_REG(rt));
|
|
ES_SIGN32_64(I_REG(rt));
|
|
break;
|
|
case MIPS_INS_LI:
|
|
case MIPS_INS_LDI:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,=", I_REG(imm), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_LUI:
|
|
rz_strbuf_appendf(&op->esil, "%s0000,%s,=", I_REG(imm), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_LB:
|
|
op->sign = true; //To load a byte from memory as a signed value
|
|
/* fallthrough */
|
|
case MIPS_INS_LBU:
|
|
//one of these is wrong
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,+,[1],%s,=",
|
|
I_REG(imm), I_REG(rs), I_REG(rt));
|
|
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:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,+,[4],%s,=",
|
|
I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_LDL:
|
|
case MIPS_INS_LDC1:
|
|
case MIPS_INS_LDC2:
|
|
case MIPS_INS_LLD:
|
|
case MIPS_INS_LD:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,+,[8],%s,=",
|
|
I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_LH:
|
|
op->sign = true; //To load a byte from memory as a signed value
|
|
/* fallthrough */
|
|
case MIPS_INS_LHU:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,+,[2],%s,=",
|
|
I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_LHX:
|
|
case MIPS_INS_LWX:
|
|
break;
|
|
case MIPS_INS_AND:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,&,%s,=", R_REG(rt), R_REG(rs), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_ANDI:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,&,%s,=", I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_OR:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,|,%s,=", R_REG(rt), R_REG(rs), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_ORI:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,|,%s,=", I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_XOR:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,^,%s,=", R_REG(rt), R_REG(rs), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_XORI:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,^,%s,=", I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_NOR:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,|,0xffffffff,^,%s,=", R_REG(rs), R_REG(rt), R_REG(rd));
|
|
break;
|
|
case MIPS_INS_SLT:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,<,t,=", R_REG(rs), R_REG(rt));
|
|
break;
|
|
case MIPS_INS_SLTI:
|
|
rz_strbuf_appendf(&op->esil, "%s,%s,<,%s,=", I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_SLTU:
|
|
rz_strbuf_appendf(&op->esil, "%s,0xffffffff,&,%s,0xffffffff,&,<,t,=",
|
|
R_REG(rs), R_REG(rt));
|
|
break;
|
|
case MIPS_INS_SLTIU:
|
|
rz_strbuf_appendf(&op->esil, "%s,0xffffffff,&,%s,0xffffffff,&,<,%s,=",
|
|
I_REG(imm), I_REG(rs), I_REG(rt));
|
|
break;
|
|
case MIPS_INS_MUL:
|
|
rz_strbuf_appendf(&op->esil, ES_W("%s,%s,*") ",%s,=", R_REG(rs), R_REG(rt), R_REG(rd));
|
|
ES_SIGN32_64(R_REG(rd));
|
|
break;
|
|
case MIPS_INS_MULT:
|
|
case MIPS_INS_MULTU:
|
|
rz_strbuf_appendf(&op->esil, ES_W("%s,%s,*") ",lo,=", R_REG(rs), R_REG(rt));
|
|
ES_SIGN32_64("lo");
|
|
rz_strbuf_appendf(&op->esil, ES_W("32,%s,%s,*,>>") ",hi,=", R_REG(rs), R_REG(rt));
|
|
ES_SIGN32_64("hi");
|
|
break;
|
|
case MIPS_INS_MFLO:
|
|
rz_strbuf_appendf(&op->esil, "lo,%s,=", R_REG(rd));
|
|
break;
|
|
case MIPS_INS_MFHI:
|
|
rz_strbuf_appendf(&op->esil, "hi,%s,=", R_REG(rd));
|
|
break;
|
|
case MIPS_INS_MTLO:
|
|
rz_strbuf_appendf(&op->esil, "%s,lo,=,", R_REG(rs));
|
|
ES_SIGN32_64("lo");
|
|
break;
|
|
case MIPS_INS_MTHI:
|
|
rz_strbuf_appendf(&op->esil, "%s,hi,=,", R_REG(rs));
|
|
ES_SIGN32_64("hi");
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mips_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *b, int len, RzAnalysisOpMask mask) {
|
|
ut32 opcode;
|
|
// WIP char buf[10]; int reg; int family;
|
|
int optype, oplen = (analysis->bits == 16) ? 2 : 4;
|
|
const ut8 *buf;
|
|
gnu_insn insn;
|
|
|
|
if (!op) {
|
|
return oplen;
|
|
}
|
|
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
|
|
op->size = oplen;
|
|
op->addr = addr;
|
|
// Be endian aware
|
|
opcode = rz_read_ble32(b, analysis->big_endian);
|
|
|
|
// eprintf ("MIPS: %02x %02x %02x %02x (after endian: big=%d)\n", buf[0], buf[1], buf[2], buf[3], analysis->big_endian);
|
|
if (opcode == 0) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
return oplen;
|
|
}
|
|
|
|
opcode = rz_swap_ut32(opcode);
|
|
buf = (ut8 *)&opcode;
|
|
|
|
optype = (buf[0] >> 2);
|
|
insn.optype = optype;
|
|
insn.id = 0;
|
|
|
|
if (optype == 0) {
|
|
/*
|
|
R-TYPE
|
|
======
|
|
opcode (6) rs (5) rt (5) rd (5) sa (5) function (6)
|
|
rs = register source
|
|
rt = register target
|
|
rd = register destination
|
|
sa =
|
|
fu =
|
|
|--[0]--| |--[1]--| |--[2]--| |--[3]--|
|
|
1111 1111 1111 1111 1111 1111 1111 1111
|
|
\_op__/\_rs__/\_rt_/ \_rd_/\_sa__/\_fun_/
|
|
| | | | | |
|
|
buf[0]>>2 | (buf[1]&31) | | buf[3]&63
|
|
| (buf[2]>>3) |
|
|
(buf[0]&3)<<3)+(buf[1]>>5) (buf[2]&7)+(buf[3]>>6)
|
|
*/
|
|
int rs = ((buf[0] & 3) << 3) + (buf[1] >> 5);
|
|
int rt = buf[1] & 31;
|
|
int rd = buf[2] >> 3;
|
|
int sa = ((buf[2] & 7) << 2) + (buf[3] >> 6);
|
|
int fun = buf[3] & 63;
|
|
|
|
insn.r_reg.rs = mips_reg_decode(rs);
|
|
insn.r_reg.rd = mips_reg_decode(rd);
|
|
insn.r_reg.rt = mips_reg_decode(rt);
|
|
snprintf((char *)insn.r_reg.sa, REG_BUF_MAX, "%" PFMT32d, sa);
|
|
|
|
switch (fun) {
|
|
case 0: // sll
|
|
insn.id = MIPS_INS_SLL;
|
|
insn.r_reg.rs = NULL;
|
|
op->val = sa;
|
|
case 4: // sllv
|
|
insn.id = MIPS_INS_SLLV;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SHL;
|
|
break;
|
|
case 2: // srl
|
|
insn.id = MIPS_INS_SRL;
|
|
insn.r_reg.rs = NULL;
|
|
op->val = sa;
|
|
case 6: // srlv
|
|
insn.id = MIPS_INS_SRLV;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SHR;
|
|
break;
|
|
case 3: // sra
|
|
insn.id = MIPS_INS_SRA;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SAR;
|
|
break;
|
|
case 7: // srav
|
|
insn.id = MIPS_INS_SRAV;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SAR;
|
|
break;
|
|
case 59: // dsra
|
|
insn.id = MIPS_INS_DSRA; //TODO double
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SAR;
|
|
break;
|
|
case 63: // dsra32
|
|
insn.id = MIPS_INS_DSRA32;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SAR;
|
|
break;
|
|
case 8: // jr
|
|
//eprintf ("%llx jr\n", addr);
|
|
// TODO: check return value
|
|
op->delay = 1;
|
|
insn.id = MIPS_INS_JR;
|
|
if (rs == 31) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
} else if (rs == 25) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RJMP;
|
|
op->jump = t9_pre;
|
|
break;
|
|
} else {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RJMP;
|
|
}
|
|
break;
|
|
case 9: // jalr
|
|
//eprintf ("%llx jalr\n", addr);
|
|
op->delay = 1;
|
|
insn.id = MIPS_INS_JALR;
|
|
if (rs == 25) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RCALL;
|
|
op->jump = t9_pre;
|
|
break;
|
|
}
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UCALL;
|
|
break;
|
|
case 10: //movz
|
|
insn.id = MIPS_INS_MOVZ;
|
|
break;
|
|
case 12: // syscall
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SWI;
|
|
break;
|
|
case 13: // break
|
|
op->type = RZ_ANALYSIS_OP_TYPE_TRAP;
|
|
break;
|
|
case 16: // mfhi
|
|
insn.id = MIPS_INS_MFHI;
|
|
break;
|
|
case 18: // mflo
|
|
insn.id = MIPS_INS_MFLO;
|
|
break;
|
|
case 17: // mthi
|
|
insn.id = MIPS_INS_MTHI;
|
|
break;
|
|
case 19: // mtlo
|
|
insn.id = MIPS_INS_MTLO;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
break;
|
|
case 24: // mult
|
|
insn.id = MIPS_INS_MULT;
|
|
case 25: // multu
|
|
insn.id = MIPS_INS_MULTU;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
|
|
break;
|
|
case 26: // div
|
|
case 27: // divu
|
|
op->type = RZ_ANALYSIS_OP_TYPE_DIV;
|
|
insn.id = MIPS_INS_DIV;
|
|
break;
|
|
case 32: // add
|
|
insn.id = MIPS_INS_ADD;
|
|
case 33: // addu //TODO:表明位数
|
|
insn.id = MIPS_INS_ADDU;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
break;
|
|
case 44: //dadd
|
|
insn.id = MIPS_INS_DADD;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
break;
|
|
case 45: //daddu move
|
|
if (rt == 0) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
insn.id = MIPS_INS_MOV;
|
|
break;
|
|
}
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
insn.id = MIPS_INS_DADDU;
|
|
break;
|
|
case 34: // sub
|
|
case 35: // subu
|
|
insn.id = MIPS_INS_SUB;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
break;
|
|
case 46: //dsub
|
|
insn.id = MIPS_INS_SUB;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
break;
|
|
case 47: //dsubu
|
|
insn.id = MIPS_INS_SUB;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
break;
|
|
case 36: // and
|
|
insn.id = MIPS_INS_AND;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
break;
|
|
case 37: // or
|
|
insn.id = MIPS_INS_OR;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_OR;
|
|
break;
|
|
case 38: // xor
|
|
insn.id = MIPS_INS_XOR;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
|
|
break;
|
|
case 39: // nor
|
|
insn.id = MIPS_INS_NOR;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOR;
|
|
break;
|
|
case 42: // slt
|
|
insn.id = MIPS_INS_SLT;
|
|
break;
|
|
case 43: // sltu
|
|
insn.id = MIPS_INS_SLTU;
|
|
break;
|
|
default:
|
|
// eprintf ("%llx %d\n", addr, optype);
|
|
break;
|
|
}
|
|
//family = 'R';
|
|
} else if ((optype & 0x3e) == 2) {
|
|
/*
|
|
// J-TYPE
|
|
|--[0]--| |--[1]--| |--[2]--| |--[3]--|
|
|
1111 1111 1111 1111 1111 1111 1111 1111
|
|
\_op__/\______address____________________/
|
|
| |
|
|
(buf[0]>>2) ((buf[0]&3)<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3]
|
|
*/
|
|
// FIXME: what happens when addr is using a virtual map?
|
|
// ANS: address will be E 0x000000..0x0ffffffc
|
|
// but addr could be anywhere
|
|
// so address needs to be adjusted for that, somehow...
|
|
// MIPS is strange. For example, the same code memory may be
|
|
// mapped simultaneously to 0x00600000 and 0x80600000. The program is
|
|
// executing at 0x80600000 if we are operating in 'KSEG0' space
|
|
// (unmapped cached mode) vs 0x00600000 (KUSEG or user space)
|
|
// An immediate jump can only reach within 2^28 bits.
|
|
// HACK: if the user specified a mapping for the program
|
|
// then assume that they know which MIPS segment they
|
|
// are analysing in, and use the high order bits of addr
|
|
// to be add to the jump.
|
|
// WARNING: it is possible that this may not be the case
|
|
// in all situations!
|
|
// Maybe better solution: use a cfg. variable to do
|
|
// the offset... but I dont yet know how to get to that
|
|
// from this static function
|
|
int address = (((buf[0] & 3) << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]) << 2;
|
|
ut64 page_hack = addr & 0xf0000000;
|
|
|
|
switch (optype) {
|
|
case 2: // j
|
|
insn.id = MIPS_INS_J;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
|
|
op->jump = page_hack + address;
|
|
op->delay = 1;
|
|
snprintf((char *)insn.j_reg.jump, REG_BUF_MAX, "0x%" PFMT64x, op->jump);
|
|
break;
|
|
case 3: // jal
|
|
insn.id = MIPS_INS_JAL;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
|
|
op->jump = page_hack + address;
|
|
op->fail = addr + 8;
|
|
op->delay = 1;
|
|
snprintf((char *)insn.j_reg.jump, REG_BUF_MAX, "0x%" PFMT64x, op->jump);
|
|
break;
|
|
}
|
|
//family = 'J';
|
|
} else if ((optype & 0x3c) == 0x10) {
|
|
/*
|
|
C-TYPE
|
|
======
|
|
opcode (6) format (5) ft (5) fs (5) fd (5) function (6)
|
|
|
|
|--[0]--| |--[1]--| |--[2]--| |--[3]--|
|
|
1111 1111 1111 1111 1111 1111 1111 1111
|
|
\_op__/\_fmt_/\_ft_/ \_fs_/\_fd__/\_fun_/
|
|
| | | | | |
|
|
buf[0]>>2 | (buf[1]&31) | | buf[3]&63
|
|
| (buf[2]>>3) |
|
|
(buf[0]&3)<<3)+(buf[1]>>5) (buf[2]&7)+(buf[3]>>6)
|
|
*/
|
|
#if WIP
|
|
int fmt = ((buf[0] & 3) << 3) + (buf[1] >> 5);
|
|
int ft = (buf[1] & 31);
|
|
int fs = (buf[2] >> 3);
|
|
int fd = (buf[2] & 7) + (buf[3] >> 6);
|
|
#endif
|
|
int fun = (buf[3] & 63);
|
|
//family = 'C';
|
|
switch (fun) {
|
|
case 0: // mtc1
|
|
break;
|
|
case 1: // sub.s
|
|
break;
|
|
case 2: // mul.s
|
|
break;
|
|
case 3: // div.s
|
|
break;
|
|
// ....
|
|
}
|
|
} else {
|
|
/*
|
|
I-TYPE
|
|
======
|
|
all opcodes but 000000 000001x and 0100xx
|
|
opcode (6) rs (5) rt (5) immediate (16)
|
|
|
|
|--[0]--| |--[1]--| |--[2]--| |--[3]--|
|
|
1111 1111 1111 1111 1111 1111 1111 1111
|
|
\_op__/\_rs__/\_rt_/ \_______imm________/
|
|
| | | |
|
|
buf[0]>>2 | (buf[1]&31) |
|
|
| |
|
|
((buf[0]&3)<<3)+(buf[1]>>5) (buf[2]<<8)+buf[3]
|
|
*/
|
|
op->refptr = 0;
|
|
int rs = ((buf[0] & 3) << 3) + (buf[1] >> 5);
|
|
int rt = buf[1] & 31;
|
|
int imm = (buf[2] << 8) + buf[3];
|
|
if (((optype >> 2) ^ 0x3) && (imm & 0x8000)) {
|
|
imm = 0 - (0x10000 - imm);
|
|
}
|
|
|
|
insn.i_reg.rs = mips_reg_decode(rs);
|
|
insn.i_reg.rt = mips_reg_decode(rt);
|
|
snprintf((char *)insn.i_reg.imm, REG_BUF_MAX, "%" PFMT32d, imm);
|
|
|
|
switch (optype) {
|
|
case 1:
|
|
switch (rt) {
|
|
case 0: //bltz
|
|
insn.id = MIPS_INS_BLTZ;
|
|
break;
|
|
case 1: //bgez
|
|
insn.id = MIPS_INS_BGEZ;
|
|
break;
|
|
case 17: //bal bgezal
|
|
if (rs == 0) {
|
|
op->jump = addr + (imm << 2) + 4;
|
|
snprintf((char *)insn.i_reg.jump, REG_BUF_MAX, "0x%" PFMT64x, op->jump);
|
|
insn.id = MIPS_INS_BAL;
|
|
} else {
|
|
op->fail = addr + 8;
|
|
insn.id = MIPS_INS_BGEZAL;
|
|
}
|
|
op->delay = 1;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
|
|
break;
|
|
default:
|
|
op->delay = 1;
|
|
op->fail = addr + 8;
|
|
break;
|
|
}
|
|
break;
|
|
case 4: // beq
|
|
if (!insn.id) {
|
|
insn.id = MIPS_INS_BEQ;
|
|
if (rt == 0) {
|
|
insn.id = MIPS_INS_BEQZ;
|
|
}
|
|
}
|
|
case 5: // bne // also bnez
|
|
if (!insn.id) {
|
|
insn.id = MIPS_INS_BNE;
|
|
if (rt == 0) {
|
|
insn.id = MIPS_INS_BNEZ;
|
|
}
|
|
}
|
|
case 6: // blez
|
|
if (!insn.id) {
|
|
insn.id = MIPS_INS_BLEZ;
|
|
}
|
|
case 7: // bgtz
|
|
// XXX: use imm here
|
|
if (!insn.id) {
|
|
insn.id = MIPS_INS_BGTZ;
|
|
}
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = addr + (imm << 2) + 4;
|
|
op->fail = addr + 8;
|
|
op->delay = 1;
|
|
|
|
snprintf((char *)insn.i_reg.jump, REG_BUF_MAX, "0x%" PFMT64x, op->jump);
|
|
break;
|
|
// The following idiom is very common in mips 32 bit:
|
|
//
|
|
// lui a0,0x8123
|
|
// ; maybe other opcodes
|
|
// ; maybe even a jump with branch delay
|
|
// addui a0,a0,-12345
|
|
//
|
|
// Here, a0 might typically be any a0 or s0 register, and -12345 is a signed 16-bit number
|
|
// This is used to address const or static data in a 64kb page
|
|
// 0x8123 is the upper 16 bits of the register
|
|
// The net result: a0 := 0x8122cfc7
|
|
// The cases vary, so for now leave the smarts in a human generated macro to decide
|
|
// but the macro needs the opcode values as input
|
|
//
|
|
// TODO: this is a stop-gap. Really we need some smarts in here to tie this into the
|
|
// flags directly, as suggested here: https://github.com/rizinorg/rizin/issues/949#issuecomment-43654922
|
|
case 15: // lui
|
|
insn.id = MIPS_INS_LUI;
|
|
snprintf((char *)insn.i_reg.imm, REG_BUF_MAX, "0x%" PFMT32x, imm);
|
|
op->dst = rz_analysis_value_new();
|
|
op->dst->reg = rz_reg_get(analysis->reg, mips_reg_decode(rt), RZ_REG_TYPE_GPR);
|
|
// TODO: currently there is no way for the macro to get access to this register
|
|
op->val = imm;
|
|
break;
|
|
case 9: // addiu
|
|
insn.id = MIPS_INS_ADDIU;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
op->dst = rz_analysis_value_new();
|
|
op->dst->reg = rz_reg_get(analysis->reg, mips_reg_decode(rt), RZ_REG_TYPE_GPR);
|
|
// TODO: currently there is no way for the macro to get access to this register
|
|
op->src[0] = rz_analysis_value_new();
|
|
op->src[0]->reg = rz_reg_get(analysis->reg, mips_reg_decode(rs), RZ_REG_TYPE_GPR);
|
|
op->val = imm; // Beware: this one is signed... use `?vi $v`
|
|
if (rs == 0) {
|
|
insn.id = MIPS_INS_LI;
|
|
snprintf((char *)insn.i_reg.imm, REG_BUF_MAX, "0x%" PFMT32x, imm);
|
|
}
|
|
break;
|
|
case 8: // addi
|
|
insn.id = MIPS_INS_ADDI;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
break;
|
|
case 10: // slti
|
|
insn.id = MIPS_INS_SLTI;
|
|
break;
|
|
case 11: // sltiu
|
|
insn.id = MIPS_INS_SLTIU;
|
|
break;
|
|
case 12: // andi
|
|
insn.id = MIPS_INS_ANDI;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
break;
|
|
case 13: // ori
|
|
insn.id = MIPS_INS_ORI;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_OR;
|
|
break;
|
|
case 14: // xori
|
|
insn.id = MIPS_INS_XORI;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
|
|
break;
|
|
case 24: // daddi
|
|
insn.id = MIPS_INS_DADDI;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
break;
|
|
case 25: // daddiu
|
|
insn.id = MIPS_INS_DADDIU;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
if (rs == 0) {
|
|
insn.id = MIPS_INS_LDI;
|
|
snprintf((char *)insn.i_reg.imm, REG_BUF_MAX, "0x%" PFMT32x, imm);
|
|
}
|
|
break;
|
|
case 32: // lb
|
|
op->refptr = 1;
|
|
insn.id = MIPS_INS_LB;
|
|
/* fallthrough */
|
|
case 33: // lh
|
|
if (!op->refptr) {
|
|
op->refptr = 2;
|
|
insn.id = MIPS_INS_LB;
|
|
}
|
|
/* fallthrough */
|
|
case 35: // lw
|
|
if (!op->refptr) {
|
|
op->refptr = 4;
|
|
insn.id = MIPS_INS_LW;
|
|
}
|
|
/* fallthrough */
|
|
case 55: // ld
|
|
if (!op->refptr) {
|
|
op->refptr = 8;
|
|
insn.id = MIPS_INS_LD;
|
|
}
|
|
|
|
if (rs == 28) {
|
|
op->ptr = analysis->gp + imm;
|
|
} else {
|
|
op->ptr = imm;
|
|
}
|
|
if (rt == 25) {
|
|
t9_pre = op->ptr;
|
|
}
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
break;
|
|
case 36: // lbu
|
|
insn.id = MIPS_INS_LBU;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
break;
|
|
case 37: // lhu
|
|
insn.id = MIPS_INS_LHU;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
break;
|
|
case 40: // sb
|
|
insn.id = MIPS_INS_SB;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
break;
|
|
case 41: // sh
|
|
insn.id = MIPS_INS_SH;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
break;
|
|
case 43: // sw
|
|
insn.id = MIPS_INS_SW;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
break;
|
|
case 63: //sd
|
|
insn.id = MIPS_INS_SD;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
break;
|
|
case 49: // lwc1
|
|
case 57: // swc1
|
|
break;
|
|
case 29: // jalx
|
|
insn.id = MIPS_INS_JALX;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
|
|
op->jump = addr + 4 * ((buf[3] | buf[2] << 8 | buf[1] << 16));
|
|
op->fail = addr + 8;
|
|
op->delay = 1;
|
|
snprintf((char *)insn.i_reg.jump, REG_BUF_MAX, "0x%" PFMT64x, op->jump);
|
|
|
|
break;
|
|
}
|
|
//family = 'I';
|
|
}
|
|
|
|
if (mask & RZ_ANALYSIS_OP_MASK_ESIL) {
|
|
if (analop_esil(analysis, op, addr, &insn)) {
|
|
rz_strbuf_fini(&op->esil);
|
|
}
|
|
}
|
|
if (mask & RZ_ANALYSIS_OP_MASK_VAL) {
|
|
//TODO: add op_fillval (analysis, op, &insn);
|
|
}
|
|
return oplen;
|
|
}
|
|
|
|
/*
|
|
R - all instructions that only take registers as arguments (jalr, jr)
|
|
opcode 000000
|
|
opcode (6) rs (5) rt (5) rd (5) sa (5) function (6)
|
|
add rd, rs, rt 100000
|
|
addu rd, rs, rt 100001
|
|
and rd, rs, rt 100100
|
|
break 001101
|
|
div rs, rt 011010
|
|
divu rs, rt 011011
|
|
jalr rd, rs 001001
|
|
jr rs 001000
|
|
|
|
mfhi rd 010000
|
|
mflo rd 010010
|
|
mthi rs 010001
|
|
mtlo rs 010011
|
|
mult rs, rt 011000
|
|
multu rs, rt 011001
|
|
|
|
nor rd, rs, rt 100111
|
|
or rd, rs, rt 100101
|
|
sll rd, rt, sa 000000
|
|
sllv rd, rt, rs 000100
|
|
slt rd, rs, rt 101010
|
|
sltu rd, rs, rt 101011
|
|
|
|
sra rd, rt, sa 000011
|
|
srav rd, rt, rs 000111
|
|
|
|
srl rd, rt, sa 000010
|
|
srlv rd, rt, rs 000110
|
|
|
|
sub rd, rs, rt 100010
|
|
subu rd, rs, rt 100011
|
|
syscall 001100
|
|
xor rd, rs, rt 100110
|
|
I - instructions with immediate operand, load/store/..
|
|
all opcodes but 000000 000001x and 0100xx
|
|
opcode (6) rs (5) rt (5) immediate (16)
|
|
addi rt, rs, immediate 001000
|
|
addiu rt, rs, immediate 001001
|
|
andi rt, rs, immediate 001100
|
|
beq rs, rt, label 000100
|
|
|
|
bgez rs, label 000001 rt = 00001
|
|
|
|
bgtz rs, label 000111 rt = 00000
|
|
blez rs, label 000110 rt = 00000
|
|
|
|
bltz rs, label 000001 rt = 00000
|
|
bne rs, rt, label 000101
|
|
lb rt, immediate(rs) 100000
|
|
lbu rt, immediate(rs) 100100
|
|
|
|
lh rt, immediate(rs) 100001
|
|
lhu rt, immediate(rs) 100101
|
|
|
|
lui rt, immediate 001111
|
|
|
|
lw rt, immediate(rs) 100011
|
|
lwc1 rt, immediate(rs) 110001
|
|
|
|
ori rt, rs, immediate 001101
|
|
sb rt, immediate(rs) 101000
|
|
|
|
slti rt, rs, immediate 001010
|
|
sltiu rt, rs, immediate 001011
|
|
sh rt, immediate(rs) 101001
|
|
sw rt, immediate(rs) 101011
|
|
swc1 rt, immediate(rs) 111001
|
|
xori rt, rs, immediate 001110
|
|
J - require memory address like j, jal
|
|
00001x
|
|
opcode (6) target (26)
|
|
j label 000010 coded address of label
|
|
jal label 000011 coded address of label
|
|
C - coprocessor insutrctions that use cp0, cp1, ..
|
|
0100xx
|
|
opcode (6) format (5) ft (5) fs (5) fd (5) function (6)
|
|
add.s fd, fs, ft 000000 10000
|
|
cvt.s.w fd, fs, ft 100000 10100
|
|
cvt.w.s fd, fs, ft 100100 10000
|
|
div.s fd, fs, ft 000011 10000
|
|
mfc1 ft, fs 000000 00000
|
|
mov.s fd, fs 000110 10000
|
|
mtc1 ft, fs 000000 00100
|
|
mul.s fd, fs, ft 000010 10000
|
|
sub.s fd, fs, ft 000001 10000
|
|
*/
|
|
|
|
/* Set the profile register */
|
|
static bool mips_set_reg_profile(RzAnalysis *analysis) {
|
|
const char *p =
|
|
#if 0
|
|
"=PC pc\n"
|
|
"=SP sp\n"
|
|
"=A0 a0\n"
|
|
"=A1 a1\n"
|
|
"=A2 a2\n"
|
|
"=A3 a3\n"
|
|
"gpr zero .32 0 0\n"
|
|
"gpr at .32 4 0\n"
|
|
"gpr v0 .32 8 0\n"
|
|
"gpr v1 .32 12 0\n"
|
|
"gpr a0 .32 16 0\n"
|
|
"gpr a1 .32 20 0\n"
|
|
"gpr a2 .32 24 0\n"
|
|
"gpr a3 .32 28 0\n"
|
|
"gpr t0 .32 32 0\n"
|
|
"gpr t1 .32 36 0\n"
|
|
"gpr t2 .32 40 0\n"
|
|
"gpr t3 .32 44 0\n"
|
|
"gpr t4 .32 48 0\n"
|
|
"gpr t5 .32 52 0\n"
|
|
"gpr t6 .32 56 0\n"
|
|
"gpr t7 .32 60 0\n"
|
|
"gpr s0 .32 64 0\n"
|
|
"gpr s1 .32 68 0\n"
|
|
"gpr s2 .32 72 0\n"
|
|
"gpr s3 .32 76 0\n"
|
|
"gpr s4 .32 80 0\n"
|
|
"gpr s5 .32 84 0\n"
|
|
"gpr s6 .32 88 0\n"
|
|
"gpr s7 .32 92 0\n"
|
|
"gpr t8 .32 96 0\n"
|
|
"gpr t9 .32 100 0\n"
|
|
"gpr k0 .32 104 0\n"
|
|
"gpr k1 .32 108 0\n"
|
|
"gpr gp .32 112 0\n"
|
|
"gpr sp .32 116 0\n"
|
|
"gpr fp .32 120 0\n"
|
|
"gpr ra .32 124 0\n"
|
|
"gpr pc .32 128 0\n";
|
|
#else
|
|
// take the one from the debugger //
|
|
"=PC pc\n"
|
|
"=SP sp\n"
|
|
"=BP fp\n"
|
|
"=A0 a0\n"
|
|
"=A1 a1\n"
|
|
"=A2 a2\n"
|
|
"=A3 a3\n"
|
|
"gpr zero .64 0 0\n"
|
|
// XXX DUPPED CAUSES FAILURE "gpr at .32 8 0\n"
|
|
"gpr at .64 8 0\n"
|
|
"gpr v0 .64 16 0\n"
|
|
"gpr v1 .64 24 0\n"
|
|
/* args */
|
|
"gpr a0 .64 32 0\n"
|
|
"gpr a1 .64 40 0\n"
|
|
"gpr a2 .64 48 0\n"
|
|
"gpr a3 .64 56 0\n"
|
|
/* tmp */
|
|
"gpr t0 .64 64 0\n"
|
|
"gpr t1 .64 72 0\n"
|
|
"gpr t2 .64 80 0\n"
|
|
"gpr t3 .64 88 0\n"
|
|
"gpr t4 .64 96 0\n"
|
|
"gpr t5 .64 104 0\n"
|
|
"gpr t6 .64 112 0\n"
|
|
"gpr t7 .64 120 0\n"
|
|
/* saved */
|
|
"gpr s0 .64 128 0\n"
|
|
"gpr s1 .64 136 0\n"
|
|
"gpr s2 .64 144 0\n"
|
|
"gpr s3 .64 152 0\n"
|
|
"gpr s4 .64 160 0\n"
|
|
"gpr s5 .64 168 0\n"
|
|
"gpr s6 .64 176 0\n"
|
|
"gpr s7 .64 184 0\n"
|
|
"gpr t8 .64 192 0\n"
|
|
"gpr t9 .64 200 0\n"
|
|
/* special */
|
|
"gpr k0 .64 208 0\n"
|
|
"gpr k1 .64 216 0\n"
|
|
"gpr gp .64 224 0\n"
|
|
"gpr sp .64 232 0\n"
|
|
"gpr fp .64 240 0\n"
|
|
"gpr ra .64 248 0\n"
|
|
/* extra */
|
|
"gpr pc .64 272 0\n";
|
|
#endif
|
|
return rz_reg_set_profile_string(analysis->reg, p);
|
|
}
|
|
|
|
static int archinfo(RzAnalysis *analysis, int q) {
|
|
return 4;
|
|
}
|
|
|
|
RzAnalysisPlugin rz_analysis_plugin_mips_gnu = {
|
|
.name = "mips.gnu",
|
|
.desc = "MIPS code analysis plugin",
|
|
.license = "LGPL3",
|
|
.arch = "mips",
|
|
.bits = 32,
|
|
.esil = true,
|
|
.archinfo = archinfo,
|
|
.op = &mips_op,
|
|
.set_reg_profile = mips_set_reg_profile,
|
|
};
|
|
|
|
#ifndef RZ_PLUGIN_INCORE
|
|
RZ_API RzLibStruct rizin_plugin = {
|
|
.type = RZ_LIB_TYPE_ANALYSIS,
|
|
.data = &rz_analysis_plugin_mips_gnu
|
|
};
|
|
#endif
|