Refactored all plugins to use get_reg_profile instead, which simply returns the register profile instead of applying it as a side-effect.
1204 lines
30 KiB
C
1204 lines
30 KiB
C
// SPDX-FileCopyrightText: 2015-2018 oddcoder <ahmedsoliman@oddcoder.com>
|
|
// SPDX-FileCopyrightText: 2015-2018 thestr4ng3r <info@florianmaerkl.de>
|
|
// SPDX-FileCopyrightText: 2015-2018 courk <courk@courk.cc>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_types.h>
|
|
#include <rz_analysis.h>
|
|
#include <rz_lib.h>
|
|
|
|
#include "../../asm/arch/pic/pic_midrange.h"
|
|
|
|
typedef struct _pic_midrange_op_args_val {
|
|
ut16 f;
|
|
ut16 k;
|
|
ut8 d;
|
|
ut8 m;
|
|
ut8 n;
|
|
ut8 b;
|
|
} PicMidrangeOpArgsVal;
|
|
|
|
typedef void (*pic_midrange_inst_handler_t)(RzAnalysis *analysis, RzAnalysisOp *op,
|
|
ut64 addr,
|
|
PicMidrangeOpArgsVal *args);
|
|
|
|
typedef struct _pic_midrange_op_analysis_info {
|
|
PicMidrangeOpcode opcode;
|
|
PicMidrangeOpArgs args;
|
|
pic_midrange_inst_handler_t handler;
|
|
} PicMidrangeOpAnalInfo;
|
|
|
|
#define INST_HANDLER(OPCODE_NAME) \
|
|
static void _inst__##OPCODE_NAME(RzAnalysis *analysis, RzAnalysisOp *op, \
|
|
ut64 addr, \
|
|
PicMidrangeOpArgsVal *args)
|
|
#define INST_DECL(NAME, ARGS) \
|
|
{ \
|
|
PIC_MIDRANGE_OPCODE_##NAME, PIC_MIDRANGE_OP_ARGS_##ARGS, \
|
|
_inst__##NAME \
|
|
}
|
|
|
|
#define e(frag) rz_strbuf_append(&op->esil, frag)
|
|
#define ef(frag, ...) rz_strbuf_appendf(&op->esil, frag, __VA_ARGS__)
|
|
|
|
#define PIC_MIDRANGE_ESIL_SRAM_START (1 << 16)
|
|
#define PIC_MIDRANGE_ESIL_CSTACK_TOP ((1 << 16) + (1 << 12))
|
|
|
|
#define PIC_MIDRANGE_ESIL_BSR_ADDR "bsr,0x80,*,0x%x,+,_sram,+"
|
|
|
|
#define PIC_MIDRANGE_ESIL_OPTION_ADDR "0x95,_sram,+"
|
|
|
|
#define PIC_MIDRANGE_ESIL_UPDATE_FLAGS \
|
|
"$z,z,:=," \
|
|
"7,$c,c,:=," \
|
|
"4,$c,dc,:=,"
|
|
|
|
#define PIC_MIDRANGE_ESIL_LW_OP(O) \
|
|
"0x%x,wreg," #O "=," PIC_MIDRANGE_ESIL_UPDATE_FLAGS
|
|
|
|
#define PIC_MIDRANGE_ESIL_FWF_OP(O) \
|
|
"wreg," PIC_MIDRANGE_ESIL_BSR_ADDR "," #O \
|
|
"=[1]," PIC_MIDRANGE_ESIL_UPDATE_FLAGS
|
|
|
|
#define PIC_MIDRANGE_ESIL_WWF_OP(O) \
|
|
PIC_MIDRANGE_ESIL_BSR_ADDR \
|
|
",[1]," \
|
|
"wreg," #O "=," PIC_MIDRANGE_ESIL_UPDATE_FLAGS
|
|
|
|
#define PIC_MIDRANGE_ESIL_FWF_OP_C(O) \
|
|
"c,wreg," \
|
|
"+," PIC_MIDRANGE_ESIL_BSR_ADDR "," #O \
|
|
"=[1]," PIC_MIDRANGE_ESIL_UPDATE_FLAGS
|
|
|
|
#define PIC_MIDRANGE_ESIL_WWF_OP_C(O) \
|
|
"c," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1]," #O "," \
|
|
"wreg," #O "=," PIC_MIDRANGE_ESIL_UPDATE_FLAGS
|
|
|
|
INST_HANDLER(NOP) {}
|
|
|
|
INST_HANDLER(RETFIE) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
}
|
|
|
|
INST_HANDLER(OPTION) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
}
|
|
|
|
INST_HANDLER(TRIS) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
}
|
|
|
|
INST_HANDLER(RETURN) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
e("0x1f,stkptr,==,$z,?{,BREAK,},");
|
|
e("_stack,stkptr,2,*,+,[2],2,*,pc,=,");
|
|
e("0x01,stkptr,-=,");
|
|
e("0xff,stkptr,==,$z,?{,0x1f,stkptr,=,},");
|
|
}
|
|
|
|
INST_HANDLER(CALL) {
|
|
ut64 pclath;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
|
|
rz_analysis_esil_reg_read(analysis->esil, "pclath", &pclath, NULL);
|
|
op->jump = 2 * (((pclath & 0x78) << 8) + args->k);
|
|
ef("8,pclath,0x78,&,<<,0x%x,+,2,*,pc,=,", args->k);
|
|
e("0x1f,stkptr,==,$z,?{,0xff,stkptr,=,},");
|
|
e("0x0f,stkptr,==,$z,?{,0xff,stkptr,=,},");
|
|
e("0x01,stkptr,+=,");
|
|
ef("0x%" PFMT64x ",_stack,stkptr,2,*,+,=[2],", (addr + 2) / 2);
|
|
}
|
|
|
|
INST_HANDLER(GOTO) {
|
|
ut64 pclath;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
|
|
rz_analysis_esil_reg_read(analysis->esil, "pclath", &pclath, NULL);
|
|
op->jump = 2 * (((pclath & 0x78) << 8) + args->k);
|
|
ef("8,pclath,0x78,&,<<,0x%x,+,2,*,pc,=,", args->k);
|
|
}
|
|
|
|
INST_HANDLER(BCF) {
|
|
ut8 mask = ~(1 << args->b);
|
|
ef(PIC_MIDRANGE_ESIL_BSR_ADDR
|
|
",[1],0x%x,&," PIC_MIDRANGE_ESIL_BSR_ADDR ",=[1],",
|
|
args->f, mask, args->f);
|
|
}
|
|
|
|
INST_HANDLER(BSF) {
|
|
ut8 mask = (1 << args->b);
|
|
ef(PIC_MIDRANGE_ESIL_BSR_ADDR
|
|
",[1],0x%x,|," PIC_MIDRANGE_ESIL_BSR_ADDR ",=[1],",
|
|
args->f, mask, args->f);
|
|
}
|
|
|
|
INST_HANDLER(BTFSC) {
|
|
ut8 mask = (1 << args->b);
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = addr + 4;
|
|
op->fail = addr + 2;
|
|
ef(PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],0x%x,&,!,?{,0x%" PFMT64x ",pc,=,},",
|
|
args->f, mask, op->jump);
|
|
}
|
|
|
|
INST_HANDLER(BTFSS) {
|
|
ut8 mask = (1 << args->b);
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = addr + 4;
|
|
op->fail = addr + 2;
|
|
ef(PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],0x%x,&,?{,0x%" PFMT64x ",pc,=,},", args->f,
|
|
mask, op->jump);
|
|
}
|
|
|
|
INST_HANDLER(BRA) {
|
|
st16 branch = args->k;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
|
|
branch |= ((branch & 0x100) ? 0xfe00 : 0);
|
|
op->jump = addr + 2 * (branch + 1);
|
|
ef("%s0x%x,1,+,2,*,pc,+=,", branch < 0 ? "-" : "",
|
|
branch < 0 ? -branch : branch);
|
|
}
|
|
|
|
INST_HANDLER(BRW) {
|
|
ut64 wreg;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UJMP;
|
|
rz_analysis_esil_reg_read(analysis->esil, "wreg", &wreg, NULL);
|
|
op->jump = addr + 2 * (wreg + 1);
|
|
e("wreg,1,+,2,*,pc,+=,");
|
|
}
|
|
|
|
INST_HANDLER(CLR) {
|
|
if (args->d) {
|
|
ef("0x00," PIC_MIDRANGE_ESIL_BSR_ADDR ",=[1],", args->f);
|
|
} else {
|
|
e("0x00,wreg,=,");
|
|
}
|
|
e("1,z,=,");
|
|
}
|
|
|
|
INST_HANDLER(SUBWF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
if (args->d) {
|
|
ef(PIC_MIDRANGE_ESIL_FWF_OP(-), args->f);
|
|
} else {
|
|
ef(PIC_MIDRANGE_ESIL_WWF_OP(-), args->f);
|
|
e("wreg,0x00,-,wreg,=,c,!=,dc,!=,");
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(DECFSZ) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = addr + 4;
|
|
op->fail = addr + 2;
|
|
if (args->d) {
|
|
ef("0x01," PIC_MIDRANGE_ESIL_BSR_ADDR ",-=[1],", args->f);
|
|
} else {
|
|
ef("0x01," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],-,wreg,=,",
|
|
args->f);
|
|
}
|
|
ef(PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],!,?{,0x%" PFMT64x ",pc,=,},", args->f,
|
|
op->jump);
|
|
}
|
|
|
|
INST_HANDLER(INCFSZ) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = addr + 4;
|
|
op->fail = addr + 2;
|
|
if (args->d) {
|
|
ef("0x01," PIC_MIDRANGE_ESIL_BSR_ADDR ",+=[1],", args->f);
|
|
} else {
|
|
ef("0x01," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],+,wreg,=,",
|
|
args->f);
|
|
}
|
|
ef(PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],!,?{,0x%" PFMT64x ",pc,=,},", args->f,
|
|
op->jump);
|
|
}
|
|
|
|
INST_HANDLER(INCF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
if (args->d) {
|
|
ef("0x01," PIC_MIDRANGE_ESIL_BSR_ADDR ",+=[1],", args->f);
|
|
} else {
|
|
ef("0x01," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],+,wreg,=,",
|
|
args->f);
|
|
}
|
|
e("$z,z,:=,");
|
|
}
|
|
|
|
INST_HANDLER(DECF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
if (args->d) {
|
|
ef("0x01," PIC_MIDRANGE_ESIL_BSR_ADDR ",-=[1],", args->f);
|
|
} else {
|
|
ef("0x01," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],-,wreg,=,",
|
|
args->f);
|
|
}
|
|
e("$z,z,:=,");
|
|
}
|
|
|
|
INST_HANDLER(IORWF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_OR;
|
|
if (args->d) {
|
|
ef(PIC_MIDRANGE_ESIL_FWF_OP(|), args->f);
|
|
} else {
|
|
ef(PIC_MIDRANGE_ESIL_WWF_OP(|), args->f);
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(ANDWF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
if (args->d) {
|
|
ef(PIC_MIDRANGE_ESIL_FWF_OP(&), args->f);
|
|
} else {
|
|
ef(PIC_MIDRANGE_ESIL_WWF_OP(&), args->f);
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(XORWF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
|
|
if (args->d) {
|
|
ef(PIC_MIDRANGE_ESIL_FWF_OP(^), args->f);
|
|
} else {
|
|
ef(PIC_MIDRANGE_ESIL_WWF_OP(^), args->f);
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(ADDWF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
if (args->d) {
|
|
ef(PIC_MIDRANGE_ESIL_FWF_OP(+), args->f);
|
|
} else {
|
|
ef(PIC_MIDRANGE_ESIL_WWF_OP(+), args->f);
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(SUBLW) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
ef(PIC_MIDRANGE_ESIL_LW_OP(-), args->k);
|
|
}
|
|
|
|
INST_HANDLER(ADDLW) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
ef(PIC_MIDRANGE_ESIL_LW_OP(+), args->k);
|
|
}
|
|
|
|
INST_HANDLER(IORLW) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_OR;
|
|
ef(PIC_MIDRANGE_ESIL_LW_OP(|), args->k);
|
|
}
|
|
|
|
INST_HANDLER(ANDLW) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
ef(PIC_MIDRANGE_ESIL_LW_OP(&), args->k);
|
|
}
|
|
|
|
INST_HANDLER(XORLW) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
|
|
ef(PIC_MIDRANGE_ESIL_LW_OP(^), args->k);
|
|
}
|
|
|
|
INST_HANDLER(MOVLW) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
ef("0x%x,wreg,=,", args->k);
|
|
}
|
|
|
|
INST_HANDLER(RETLW) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
ef("0x%x,wreg,=,", args->k);
|
|
e("0x1f,stkptr,==,$z,?{,BREAK,},");
|
|
e("_stack,stkptr,2,*,+,[2],2,*,pc,=,");
|
|
e("0x01,stkptr,-=,");
|
|
e("0xff,stkptr,==,$z,?{,0x1f,stkptr,=,},");
|
|
}
|
|
|
|
INST_HANDLER(MOVLP) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
ef("0x%x,pclath,=,", args->f);
|
|
}
|
|
|
|
INST_HANDLER(MOVLB) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
ef("0x%x,bsr,=,", args->k);
|
|
}
|
|
|
|
INST_HANDLER(CALLW) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UCALL;
|
|
e("8,pclath,<<,0x%x,+,wreg,2,*,pc,=,");
|
|
e("0x1f,stkptr,==,$z,?{,0xff,stkptr,=,},");
|
|
e("0x0f,stkptr,==,$z,?{,0xff,stkptr,=,},");
|
|
e("0x01,stkptr,+=,");
|
|
ef("0x%" PFMT64x ",_stack,stkptr,2,*,+,=[2],", (addr + 2) / 2);
|
|
}
|
|
|
|
INST_HANDLER(MOVWF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
ef("wreg," PIC_MIDRANGE_ESIL_BSR_ADDR ",=[1],", args->f);
|
|
}
|
|
|
|
INST_HANDLER(MOVF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
if (args->d) {
|
|
ef(PIC_MIDRANGE_ESIL_BSR_ADDR
|
|
",[1]," PIC_MIDRANGE_ESIL_BSR_ADDR ",=[1],",
|
|
args->f, args->f);
|
|
} else {
|
|
ef(PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],wreg,=,", args->f);
|
|
}
|
|
e("$z,z,:=,");
|
|
}
|
|
|
|
INST_HANDLER(SWAPF) {
|
|
ef("4," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],>>,0x0f,&,", args->f);
|
|
ef("4," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],<<,0xf0,&,", args->f);
|
|
e("|,");
|
|
ef(PIC_MIDRANGE_ESIL_BSR_ADDR ",=[1],", args->f);
|
|
}
|
|
|
|
INST_HANDLER(LSLF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SHL;
|
|
ef("7," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],>>,c,=,", args->f);
|
|
if (args->d) {
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",<<=[1],", args->f);
|
|
} else {
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],<<,wreg,=,",
|
|
args->f);
|
|
}
|
|
e("$z,z,:=,");
|
|
}
|
|
|
|
INST_HANDLER(LSRF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SHR;
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],&,c,=,", args->f);
|
|
if (args->d) {
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",>>=[1],", args->f);
|
|
} else {
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],>>,wreg,=,",
|
|
args->f);
|
|
}
|
|
e("$z,z,:=,");
|
|
}
|
|
|
|
INST_HANDLER(ASRF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SHR;
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],&,c,=,", args->f);
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],>>,", args->f);
|
|
ef("0x80," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],&,", args->f);
|
|
if (args->d) {
|
|
ef("|," PIC_MIDRANGE_ESIL_BSR_ADDR ",=[1],", args->f);
|
|
} else {
|
|
e("|,wreg,=,");
|
|
}
|
|
e("$z,z,:=,");
|
|
}
|
|
|
|
INST_HANDLER(RRF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROR;
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],&,", args->f);
|
|
if (args->d) {
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",>>=[1],"
|
|
"c," PIC_MIDRANGE_ESIL_BSR_ADDR ",|=[1],",
|
|
args->f, args->f);
|
|
} else {
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],>>,wreg,=,"
|
|
"c,wreg,|=[1],",
|
|
args->f);
|
|
}
|
|
e("c,=,");
|
|
}
|
|
|
|
INST_HANDLER(RLF) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
|
|
ef("7," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],>>,", args->f);
|
|
if (args->d) {
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",<<=[1],"
|
|
"c," PIC_MIDRANGE_ESIL_BSR_ADDR ",|=[1],",
|
|
args->f, args->f);
|
|
} else {
|
|
ef("1," PIC_MIDRANGE_ESIL_BSR_ADDR ",[1],<<,wreg,=,"
|
|
"c,wreg,|=[1],",
|
|
args->f);
|
|
}
|
|
e("c,=,");
|
|
}
|
|
|
|
INST_HANDLER(COMF) {
|
|
if (args->d) {
|
|
ef("0xff," PIC_MIDRANGE_ESIL_BSR_ADDR ",^=[1],", args->f);
|
|
} else {
|
|
ef("0xff," PIC_MIDRANGE_ESIL_BSR_ADDR ",^,wreg,=,", args->f);
|
|
}
|
|
e("$z,z,:=,");
|
|
}
|
|
|
|
INST_HANDLER(RESET) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
|
|
op->jump = 0;
|
|
e("0x0,pc,=,");
|
|
e("0x1f,stkptr,=,");
|
|
}
|
|
|
|
INST_HANDLER(ADDFSR) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
if (args->n == 0) {
|
|
ef("0x%x,fsr0l,+=,", args->k);
|
|
e("7,$c,?{,0x01,fsr0h,+=,},");
|
|
} else {
|
|
ef("0x%x,fsr1l,+=,", args->k);
|
|
e("7,$c,?{,0x01,fsr1h,+=,},");
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(CLRWDT) {
|
|
e("1,to,=,");
|
|
e("1,pd,=,");
|
|
}
|
|
|
|
INST_HANDLER(SLEEP) {
|
|
e("1,to,=,");
|
|
e("0,pd,=,");
|
|
}
|
|
|
|
INST_HANDLER(SUBWFB) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
e("c,!=,");
|
|
if (args->d) {
|
|
ef(PIC_MIDRANGE_ESIL_FWF_OP_C(-), args->f);
|
|
} else {
|
|
ef(PIC_MIDRANGE_ESIL_WWF_OP_C(-), args->f);
|
|
e("wreg,0x00,-,wreg,=,c,!=,dc,!=,");
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(ADDWFC) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
if (args->d) {
|
|
ef(PIC_MIDRANGE_ESIL_FWF_OP_C(+), args->f);
|
|
} else {
|
|
ef(PIC_MIDRANGE_ESIL_WWF_OP_C(+), args->f);
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(MOVIW_1) {
|
|
if (args->n == 0) {
|
|
if (!(args->m & 2)) {
|
|
ef("1,fsr0l,%s=,", (args->m & 1) ? "-" : "+");
|
|
ef("7,$c%s,fsr0h,%s,", (args->m & 1) ? ",!" : "",
|
|
(args->m & 1) ? "-" : "+");
|
|
}
|
|
e("indf0,wreg,=,");
|
|
e("$z,z,:=,");
|
|
if (args->m & 2) {
|
|
ef("1,fsr0l,%s=,", (args->m & 1) ? "-" : "+");
|
|
ef("7,$c%s,fsr0h,%s,", (args->m & 1) ? ",!" : "",
|
|
(args->m & 1) ? "-" : "+");
|
|
}
|
|
} else {
|
|
if (!(args->m & 2)) {
|
|
ef("1,fsr1l,%s=,", (args->m & 1) ? "-" : "+");
|
|
ef("7,$c%s,fsr1h,%s,", (args->m & 1) ? ",!" : "",
|
|
(args->m & 1) ? "-" : "+");
|
|
}
|
|
e("indf1,wreg,=,");
|
|
e("$z,z,:=,");
|
|
if (args->m & 2) {
|
|
ef("1,fsr1l,%s=,", (args->m & 1) ? "-" : "+");
|
|
ef("7,$c%s,fsr1h,%s,", (args->m & 1) ? ",!" : "",
|
|
(args->m & 1) ? "-" : "+");
|
|
}
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(MOVWI_1) {
|
|
if (args->n == 0) {
|
|
if (!(args->m & 2)) {
|
|
ef("1,fsr0l,%s=,", (args->m & 1) ? "-" : "+");
|
|
ef("$c7%s,fsr0h,%s,", (args->m & 1) ? ",!" : "",
|
|
(args->m & 1) ? "-" : "+");
|
|
}
|
|
e("wreg,indf0=,");
|
|
e("$z,z,:=,");
|
|
if (args->m & 2) {
|
|
ef("1,fsr0l,%s=,", (args->m & 1) ? "-" : "+");
|
|
ef("$c7%s,fsr0h,%s,", (args->m & 1) ? ",!" : "",
|
|
(args->m & 1) ? "-" : "+");
|
|
}
|
|
} else {
|
|
if (!(args->m & 2)) {
|
|
ef("1,fsr1l,%s=,", (args->m & 1) ? "-" : "+");
|
|
ef("$c7,fsr1h,%s,", (args->m & 1) ? ",!" : "");
|
|
}
|
|
e("wreg,indf1=,");
|
|
e("$z,z,:=,");
|
|
if (args->m & 2) {
|
|
ef("1,fsr1l,%s=,", (args->m & 1) ? "-" : "+");
|
|
ef("$c7%s,fsr1h,%s,", (args->m & 1) ? ",!" : "",
|
|
(args->m & 1) ? "-" : "+");
|
|
}
|
|
}
|
|
}
|
|
|
|
INST_HANDLER(MOVIW_2) {
|
|
if (args->n == 0) {
|
|
e("fsr0l,8,fsr0h,<<,+,");
|
|
} else {
|
|
e("fsr1l,8,fsr1h,<<,+,");
|
|
}
|
|
ef("0x%x,+,[1],wreg,=,", args->k);
|
|
}
|
|
|
|
INST_HANDLER(MOVWI_2) {
|
|
e("wreg,");
|
|
if (args->n == 0) {
|
|
e("fsr0l,8,fsr0h,<<,+,");
|
|
} else {
|
|
e("fsr1l,8,fsr1h,<<,+,");
|
|
}
|
|
e("=[1],");
|
|
}
|
|
|
|
#define PIC_MIDRANGE_OPINFO_LEN 52
|
|
static const PicMidrangeOpAnalInfo pic_midrange_op_analysis_info[PIC_MIDRANGE_OPINFO_LEN] = {
|
|
INST_DECL(NOP, NONE), INST_DECL(RETURN, NONE),
|
|
INST_DECL(RETFIE, NONE), INST_DECL(OPTION, NONE),
|
|
INST_DECL(SLEEP, NONE), INST_DECL(CLRWDT, NONE),
|
|
INST_DECL(TRIS, 2F), INST_DECL(MOVWF, 7F),
|
|
INST_DECL(CLR, 1D_7F), INST_DECL(SUBWF, 1D_7F),
|
|
INST_DECL(DECF, 1D_7F), INST_DECL(IORWF, 1D_7F),
|
|
INST_DECL(ANDWF, 1D_7F), INST_DECL(XORWF, 1D_7F),
|
|
INST_DECL(ADDWF, 1D_7F), INST_DECL(MOVF, 1D_7F),
|
|
INST_DECL(COMF, 1D_7F), INST_DECL(INCF, 1D_7F),
|
|
INST_DECL(DECFSZ, 1D_7F), INST_DECL(RRF, 1D_7F),
|
|
INST_DECL(RLF, 1D_7F), INST_DECL(SWAPF, 1D_7F),
|
|
INST_DECL(INCFSZ, 1D_7F), INST_DECL(BCF, 3B_7F),
|
|
INST_DECL(BSF, 3B_7F), INST_DECL(BTFSC, 3B_7F),
|
|
INST_DECL(BTFSS, 3B_7F), INST_DECL(CALL, 11K),
|
|
INST_DECL(GOTO, 11K), INST_DECL(MOVLW, 8K),
|
|
INST_DECL(RETLW, 8K), INST_DECL(IORLW, 8K),
|
|
INST_DECL(ANDLW, 8K), INST_DECL(XORLW, 8K),
|
|
INST_DECL(SUBLW, 8K), INST_DECL(ADDLW, 8K),
|
|
INST_DECL(RESET, NONE), INST_DECL(CALLW, NONE),
|
|
INST_DECL(BRW, NONE), INST_DECL(MOVIW_1, 1N_2M),
|
|
INST_DECL(MOVWI_1, 1N_2M), INST_DECL(MOVLB, 4K),
|
|
INST_DECL(LSLF, 1D_7F), INST_DECL(LSRF, 1D_7F),
|
|
INST_DECL(ASRF, 1D_7F), INST_DECL(SUBWFB, 1D_7F),
|
|
INST_DECL(ADDWFC, 1D_7F), INST_DECL(ADDFSR, 1N_6K),
|
|
INST_DECL(MOVLP, 7F), INST_DECL(BRA, 9K),
|
|
INST_DECL(MOVIW_2, 1N_6K), INST_DECL(MOVWI_2, 1N_6K)
|
|
};
|
|
|
|
static void analysis_pic_midrange_extract_args(ut16 instr,
|
|
PicMidrangeOpArgs args,
|
|
PicMidrangeOpArgsVal *args_val) {
|
|
|
|
memset(args_val, 0, sizeof(PicMidrangeOpArgsVal));
|
|
|
|
switch (args) {
|
|
case PIC_MIDRANGE_OP_ARGS_NONE: return;
|
|
case PIC_MIDRANGE_OP_ARGS_2F:
|
|
args_val->f = instr & PIC_MIDRANGE_OP_ARGS_2F_MASK_F;
|
|
return;
|
|
case PIC_MIDRANGE_OP_ARGS_7F:
|
|
args_val->f = instr & PIC_MIDRANGE_OP_ARGS_7F_MASK_F;
|
|
return;
|
|
case PIC_MIDRANGE_OP_ARGS_1D_7F:
|
|
args_val->f = instr & PIC_MIDRANGE_OP_ARGS_1D_7F_MASK_F;
|
|
args_val->d =
|
|
(instr & PIC_MIDRANGE_OP_ARGS_1D_7F_MASK_D) >> 7;
|
|
return;
|
|
case PIC_MIDRANGE_OP_ARGS_1N_6K:
|
|
args_val->n =
|
|
(instr & PIC_MIDRANGE_OP_ARGS_1N_6K_MASK_N) >> 6;
|
|
args_val->k = instr & PIC_MIDRANGE_OP_ARGS_1N_6K_MASK_K;
|
|
return;
|
|
case PIC_MIDRANGE_OP_ARGS_3B_7F:
|
|
args_val->b =
|
|
(instr & PIC_MIDRANGE_OP_ARGS_3B_7F_MASK_B) >> 7;
|
|
args_val->f = instr & PIC_MIDRANGE_OP_ARGS_3B_7F_MASK_F;
|
|
return;
|
|
case PIC_MIDRANGE_OP_ARGS_4K:
|
|
args_val->k = instr & PIC_MIDRANGE_OP_ARGS_4K_MASK_K;
|
|
return;
|
|
case PIC_MIDRANGE_OP_ARGS_8K:
|
|
args_val->k = instr & PIC_MIDRANGE_OP_ARGS_8K_MASK_K;
|
|
return;
|
|
case PIC_MIDRANGE_OP_ARGS_9K:
|
|
args_val->k = instr & PIC_MIDRANGE_OP_ARGS_9K_MASK_K;
|
|
return;
|
|
case PIC_MIDRANGE_OP_ARGS_11K:
|
|
args_val->k = instr & PIC_MIDRANGE_OP_ARGS_11K_MASK_K;
|
|
return;
|
|
case PIC_MIDRANGE_OP_ARGS_1N_2M:
|
|
args_val->n =
|
|
(instr & PIC_MIDRANGE_OP_ARGS_1N_2M_MASK_N) >> 2;
|
|
args_val->m = instr & PIC_MIDRANGE_OP_ARGS_1N_2M_MASK_M;
|
|
return;
|
|
}
|
|
}
|
|
|
|
static RzIODesc *mem_sram = 0;
|
|
static RzIODesc *mem_stack = 0;
|
|
|
|
static RzIODesc *cpu_memory_map(RzIOBind *iob, RzIODesc *desc, ut32 addr,
|
|
ut32 size) {
|
|
char *mstr = rz_str_newf("malloc://%d", size);
|
|
if (desc && iob->fd_get_name(iob->io, desc->fd)) {
|
|
iob->fd_remap(iob->io, desc->fd, addr);
|
|
} else {
|
|
desc = iob->open_at(iob->io, mstr, RZ_PERM_RW, 0, addr, NULL);
|
|
}
|
|
free(mstr);
|
|
return desc;
|
|
}
|
|
|
|
static bool pic_midrange_reg_write(RzReg *reg, const char *regname, ut32 num) {
|
|
if (reg) {
|
|
RzRegItem *item = rz_reg_get(reg, regname, RZ_REG_TYPE_GPR);
|
|
if (item) {
|
|
rz_reg_set_value(reg, item, num);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void analysis_pic_midrange_malloc(RzAnalysis *analysis, bool force) {
|
|
static bool init_done = false;
|
|
|
|
if (!init_done || force) {
|
|
// Allocate memory as needed.
|
|
// We assume that code is already allocated with firmware
|
|
// image
|
|
mem_sram =
|
|
cpu_memory_map(&analysis->iob, mem_sram,
|
|
PIC_MIDRANGE_ESIL_SRAM_START, 0x1000);
|
|
mem_stack =
|
|
cpu_memory_map(&analysis->iob, mem_stack,
|
|
PIC_MIDRANGE_ESIL_CSTACK_TOP, 0x20);
|
|
|
|
pic_midrange_reg_write(analysis->reg, "_sram",
|
|
PIC_MIDRANGE_ESIL_SRAM_START);
|
|
pic_midrange_reg_write(analysis->reg, "_stack",
|
|
PIC_MIDRANGE_ESIL_CSTACK_TOP);
|
|
pic_midrange_reg_write(analysis->reg, "stkptr", 0x1f);
|
|
|
|
init_done = true;
|
|
}
|
|
}
|
|
|
|
static int analysis_pic_midrange_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
|
|
const ut8 *buf, int len) {
|
|
|
|
ut16 instr;
|
|
int i;
|
|
|
|
analysis_pic_midrange_malloc(analysis, false);
|
|
|
|
if (!buf || len < 2) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
|
|
return op->size;
|
|
}
|
|
|
|
instr = rz_read_le16(buf);
|
|
|
|
// Default op params
|
|
op->size = 2;
|
|
op->cycles = 1;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
|
|
PicMidrangeOpcode opcode = pic_midrange_get_opcode(instr);
|
|
PicMidrangeOpArgsVal args_val;
|
|
|
|
for (i = 0; i < PIC_MIDRANGE_OPINFO_LEN; i++) {
|
|
if (pic_midrange_op_analysis_info[i].opcode == opcode) {
|
|
analysis_pic_midrange_extract_args(
|
|
instr, pic_midrange_op_analysis_info[i].args,
|
|
&args_val);
|
|
pic_midrange_op_analysis_info[i].handler(analysis, op, addr,
|
|
&args_val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return op->size;
|
|
}
|
|
|
|
static void pic18_cond_branch(RzAnalysisOp *op, ut64 addr, const ut8 *buf, char *flag) {
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
op->jump = addr + 2 + 2 * (*(ut16 *)buf & 0xff);
|
|
op->fail = addr + op->size;
|
|
op->cycles = 2;
|
|
rz_strbuf_setf(&op->esil, "%s,?,{,0x%" PFMT64x ",pc,=,}", flag, op->jump);
|
|
}
|
|
|
|
static int analysis_pic_pic18_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len) {
|
|
// TODO code should be refactored and broken into smaller chunks!!
|
|
// TODO complete the esil emitter
|
|
if (len < 2) {
|
|
op->size = len;
|
|
goto beach; // pancake style :P
|
|
}
|
|
op->size = 2;
|
|
ut16 b = *(ut16 *)buf;
|
|
ut32 dword_instr = 0;
|
|
memcpy(&dword_instr, buf, RZ_MIN(sizeof(dword_instr), len));
|
|
switch (b >> 9) {
|
|
case 0x76: // call
|
|
if (len < 4) {
|
|
goto beach;
|
|
}
|
|
if (dword_instr >> 28 != 0xf) {
|
|
goto beach;
|
|
}
|
|
op->size = 4;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
|
|
return op->size;
|
|
};
|
|
switch (b >> 11) { // NEX_T
|
|
case 0x1b: // rcall
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
|
|
return op->size;
|
|
case 0x1a: // bra
|
|
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
|
|
op->cycles = 2;
|
|
op->jump = addr + 2 + 2 * (*(ut16 *)buf & 0x7ff);
|
|
rz_strbuf_setf(&op->esil, "0x%" PFMT64x ",pc,=", op->jump);
|
|
return op->size;
|
|
}
|
|
switch (b >> 12) { // NOP,movff,BAF_T
|
|
case 0xf: // nop
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
op->cycles = 1;
|
|
rz_strbuf_setf(&op->esil, ",");
|
|
return op->size;
|
|
case 0xc: // movff
|
|
if (len < 4) {
|
|
goto beach;
|
|
}
|
|
if (dword_instr >> 28 != 0xf) {
|
|
goto beach;
|
|
}
|
|
op->size = 4;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
return op->size;
|
|
case 0xb: // btfsc
|
|
case 0xa: // btfss
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
return op->size;
|
|
case 0x9: // bcf
|
|
case 0x8: // bsf
|
|
case 0x7: // btg
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
|
|
return op->size;
|
|
};
|
|
|
|
switch (b >> 8) { // GOTO_T,N_T,K_T
|
|
case 0xe0: // bz
|
|
pic18_cond_branch(op, addr, buf, "z");
|
|
return op->size;
|
|
case 0xe1: // bnz
|
|
pic18_cond_branch(op, addr, buf, "z,!");
|
|
return op->size;
|
|
case 0xe3: // bnc
|
|
pic18_cond_branch(op, addr, buf, "c,!");
|
|
return op->size;
|
|
case 0xe4: // bov
|
|
pic18_cond_branch(op, addr, buf, "ov");
|
|
return op->size;
|
|
case 0xe5: // bnov
|
|
pic18_cond_branch(op, addr, buf, "ov,!");
|
|
return op->size;
|
|
case 0xe6: // bn
|
|
pic18_cond_branch(op, addr, buf, "n");
|
|
return op->size;
|
|
case 0xe7: // bnn
|
|
pic18_cond_branch(op, addr, buf, "n,!");
|
|
return op->size;
|
|
case 0xe2: // bc
|
|
pic18_cond_branch(op, addr, buf, "c");
|
|
return op->size;
|
|
case 0xef: // goto
|
|
if (len < 4) {
|
|
goto beach;
|
|
}
|
|
if (dword_instr >> 28 != 0xf) {
|
|
goto beach;
|
|
}
|
|
op->size = 4;
|
|
op->cycles = 2;
|
|
op->jump = ((dword_instr & 0xff) | ((dword_instr & 0xfff0000) >> 8)) * 2;
|
|
rz_strbuf_setf(&op->esil, "0x%" PFMT64x ",pc,=", op->jump);
|
|
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
|
|
return op->size;
|
|
case 0xf: // addlw
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
op->cycles = 1;
|
|
// TODO add support for dc flag
|
|
rz_strbuf_setf(&op->esil, "0x%x,wreg,+=,$z,z,:=,7,$s,n,:=,7,$c,c,:=,7,$o,ov,:=,", *(ut16 *)buf & 0xff);
|
|
return op->size;
|
|
case 0xe: // movlw
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
op->cycles = 1;
|
|
rz_strbuf_setf(&op->esil, "0x%x,wreg,=,", *(ut16 *)buf & 0xff);
|
|
return op->size;
|
|
case 0xd: // mullw
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
|
|
op->cycles = 1;
|
|
rz_strbuf_setf(&op->esil, "0x%x,wreg,*,prod,=", *(ut16 *)buf & 0xff);
|
|
return op->size;
|
|
case 0xc: // retlw
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
op->cycles = 2;
|
|
rz_strbuf_setf(&op->esil, "0x%x,wreg,=,tos,pc,=,", *(ut16 *)buf & 0xff);
|
|
return op->size;
|
|
case 0xb: // andlw
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
op->cycles = 1;
|
|
rz_strbuf_setf(&op->esil, "0x%x,wreg,&=,$z,z,:=,7,$s,n,:=,", *(ut16 *)buf & 0xff);
|
|
return op->size;
|
|
case 0xa: // xorlw
|
|
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
|
|
op->cycles = 1;
|
|
rz_strbuf_setf(&op->esil, "0x%x,wreg,^=,$z,z,:=,7,$s,n,:=,", *(ut16 *)buf & 0xff);
|
|
return op->size;
|
|
case 0x9: // iorlw
|
|
op->type = RZ_ANALYSIS_OP_TYPE_OR;
|
|
op->cycles = 1;
|
|
rz_strbuf_setf(&op->esil, "0x%x,wreg,^=,$z,z,:=,7,$s,n,:=,", *(ut16 *)buf & 0xff);
|
|
return op->size;
|
|
case 0x8: // sublw
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
op->cycles = 1;
|
|
// TODO add support for dc flag
|
|
rz_strbuf_setf(&op->esil, "wreg,0x%x,-,wreg,=,$z,z,:=,7,$s,n,:=,7,$c,c,:=,7,$o,ov,:=,", *(ut16 *)buf & 0xff);
|
|
return op->size;
|
|
};
|
|
|
|
switch (b >> 6) { // LFSR
|
|
case 0x3b8: // lfsr
|
|
if (len < 4) {
|
|
goto beach;
|
|
}
|
|
if (dword_instr >> 28 != 0xf) {
|
|
goto beach;
|
|
}
|
|
op->size = 4;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
return op->size;
|
|
};
|
|
switch (b >> 10) { // DAF_T
|
|
case 0x17: // subwf
|
|
case 0x16: // subwfb
|
|
case 0x15: // subfwb
|
|
case 0x13: // dcfsnz
|
|
case 0xb: // decfsz
|
|
case 0x1: // decf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
|
return op->size;
|
|
case 0x14: // movf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
|
return op->size;
|
|
case 0x12: // infsnz
|
|
case 0xf: // incfsz
|
|
case 0xa: // incf
|
|
case 0x8: // addwfc
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
return op->size;
|
|
case 0x9: // addwf
|
|
op->cycles = 1;
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
|
return op->size;
|
|
case 0x11: // rlncf
|
|
case 0xd: // rlcf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
|
|
return op->size;
|
|
case 0x10: // rrncf
|
|
case 0xc: // rrcf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ROR;
|
|
return op->size;
|
|
case 0xe: // swapf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
|
|
return op->size;
|
|
case 0x7: // comf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CPL;
|
|
return op->size;
|
|
case 0x6: // xorwf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
|
|
return op->size;
|
|
case 0x5: // andwf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_AND;
|
|
return op->size;
|
|
case 0x4: // iorwf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_OR;
|
|
return op->size;
|
|
};
|
|
switch (b >> 9) { // AF_T
|
|
case 0x37: // movwf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
return op->size;
|
|
case 0x36: // negf
|
|
case 0x35: // clrf
|
|
case 0x34: // setf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
|
|
return op->size;
|
|
case 0x33: // tstfsz
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
|
return op->size;
|
|
case 0x32: // cpfsgt
|
|
case 0x31: // cpfseq
|
|
case 0x30: // cpfslt
|
|
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
|
|
return op->size;
|
|
case 0x1: // mulwf
|
|
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
|
|
return op->size;
|
|
};
|
|
switch (b >> 4) {
|
|
case 0x10: // movlb
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
op->cycles = 1;
|
|
rz_strbuf_setf(&op->esil, "0x%x,bsr,=,", *(ut16 *)buf & 0xf);
|
|
return op->size;
|
|
};
|
|
switch (b) {
|
|
case 0xff: // reset
|
|
case 0x7: // daw
|
|
case 0x4: // clwdt
|
|
case 0x3: // sleep
|
|
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
|
|
return op->size;
|
|
case 0x13: // return
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
op->cycles = 2;
|
|
rz_strbuf_setf(&op->esil, "tos,pc,=,");
|
|
return op->size;
|
|
case 0x12: // return
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
op->cycles = 2;
|
|
rz_strbuf_setf(&op->esil, "tos,pc,=");
|
|
return op->size;
|
|
case 0x11: // retfie
|
|
case 0x10: // retfie
|
|
op->type = RZ_ANALYSIS_OP_TYPE_RET;
|
|
return op->size;
|
|
case 0xf: // tblwt
|
|
case 0xe: // tblwt
|
|
case 0xd: // tblwt
|
|
case 0xc: // tblwt
|
|
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
|
return op->size;
|
|
case 0xb: // tblrd
|
|
case 0xa: // tblrd
|
|
case 0x9: // tblrd
|
|
case 0x8: // tblrd
|
|
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
|
return op->size;
|
|
case 0x6: // pop
|
|
op->type = RZ_ANALYSIS_OP_TYPE_POP;
|
|
return op->size;
|
|
case 0x5: // push
|
|
op->type = RZ_ANALYSIS_OP_TYPE_PUSH;
|
|
return op->size;
|
|
case 0x0: // nop
|
|
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
|
op->cycles = 1;
|
|
rz_strbuf_setf(&op->esil, ",");
|
|
return op->size;
|
|
};
|
|
beach:
|
|
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
|
|
return op->size;
|
|
}
|
|
|
|
static char *analysis_pic_midrange_get_reg_profile(RzAnalysis *esil) {
|
|
const char *p =
|
|
"=PC pc\n"
|
|
"=SP stkptr\n"
|
|
"=A0 porta\n"
|
|
"=A1 portb\n"
|
|
"gpr indf0 .8 0 0\n"
|
|
"gpr indf1 .8 1 0\n"
|
|
"gpr pcl .8 2 0\n"
|
|
"gpr status .8 3 0\n"
|
|
"flg c .1 3.0 0\n"
|
|
"flg dc .1 3.1 0\n"
|
|
"flg z .1 3.2 0\n"
|
|
"flg pd .1 3.3 0\n"
|
|
"flg to .1 3.4 0\n"
|
|
"gpr fsr0l .8 4 0\n"
|
|
"gpr fsr0h .8 5 0\n"
|
|
"gpr fsr1l .8 6 0\n"
|
|
"gpr fsr1h .8 7 0\n"
|
|
"gpr bsr .8 8 0\n"
|
|
"gpr wreg .8 9 0\n"
|
|
"gpr pclath .8 10 0\n"
|
|
"gpr intcon .8 11 0\n"
|
|
"gpr pc .16 12 0\n"
|
|
"gpr stkptr .8 14 0\n"
|
|
"gpr _sram .32 15 0\n"
|
|
"gpr _stack .32 19 0\n";
|
|
return strdup(p);
|
|
}
|
|
|
|
static char *analysis_pic_pic18_get_reg_profile(RzAnalysis *esil) {
|
|
const char *p =
|
|
"#pc lives in nowhere actually"
|
|
"=PC pc\n"
|
|
"=SP tos\n"
|
|
"=A0 porta\n"
|
|
"=A1 portb\n"
|
|
"gpr pc .32 0 0\n"
|
|
"gpr pcl .8 0 0\n"
|
|
"gpr pclath .8 1 0\n"
|
|
"gpr pclatu .8 2 0\n"
|
|
"#bsr max is 0b111\n"
|
|
"gpr bsr .8 4 0\n"
|
|
"#tos doesn't exist\n"
|
|
"#general rule of thumb any register of size >8 bits has no existence\n"
|
|
"gpr tos .32 5 0\n"
|
|
"gpr tosl .8 5 0\n"
|
|
"gpr tosh .8 6 0\n"
|
|
"gpr tosu .8 7 0\n"
|
|
|
|
"gpr indf0 .16 9 0\n"
|
|
"gpr fsr0 .12 9 0\n"
|
|
"gpr fsr0l .8 9 0\n"
|
|
"gpr fsr0h .8 10 0\n"
|
|
"gpr indf1 .16 11 0\n"
|
|
"gpr fsr1 .12 11 0\n"
|
|
"gpr fsr1l .8 11 0\n"
|
|
"gpr fsr1h .8 12 0\n"
|
|
"gpr indf2 .16 13 0\n"
|
|
"gpr fsr2 .12 13 0\n"
|
|
"gpr frs2l .8 13 0\n"
|
|
"gpr fsr2h .8 14 0\n"
|
|
"gpr tblptr .22 15 0\n"
|
|
"gpr tblptrl .8 15 0\n"
|
|
"gpr tblptrh .8 16 0\n"
|
|
"gpr tblptru .8 17 0\n"
|
|
"gpr rcon .8 18 0\n"
|
|
"gpr memcon .8 19 0\n"
|
|
"gpr intcon .8 20 0\n"
|
|
"gpr intcon2 .8 21 0\n"
|
|
"gpr intcon3 .8 22 0\n"
|
|
"gpr pie1 .8 23 0\n"
|
|
"gpr porta .7 29 0\n"
|
|
"gpr trisa .8 30 0\n"
|
|
"gpr portb .8 33 0\n"
|
|
"gpr tisb .8 34 0\n"
|
|
"gpr latb .8 35 0\n"
|
|
"gpr portc .8 36 0\n"
|
|
"gpr trisc .8 37 0\n"
|
|
"gpr latc .8 38 0\n"
|
|
"gpr portd .8 39 0\n"
|
|
"gpr trisd .8 40 0\n"
|
|
"gpr latd .8 41 0\n"
|
|
"gpr pspcon .8 42 0\n"
|
|
"gpr porte .8 43 0\n"
|
|
"gpr trise .8 44 0\n"
|
|
"gpr late .8 45 0\n"
|
|
"gpr t0con .8 46 0\n"
|
|
"gpr t1con .8 47 0\n"
|
|
"gpr t2con .8 48 0\n"
|
|
"gpr tmr1h .8 50 0\n"
|
|
"gpr tmr0h .8 51 0\n"
|
|
"gpr tmr1l .8 52 0\n"
|
|
"gpr tmr2 .8 53 0\n"
|
|
"gpr pr2 .8 54 0\n"
|
|
"gpr ccpr1h .8 55 0\n"
|
|
"gpr postinc2 .8 56 0\n"
|
|
"gpr ccpr1l .8 57 0\n"
|
|
"gpr postdec2 .8 58 0\n"
|
|
"gpr ccp1con .8 59 0\n"
|
|
"gpr preinc2 .8 60 0\n"
|
|
"gpr ccpr2h .8 61 0\n"
|
|
"gpr plusw2 .8 62 0\n"
|
|
"gpr ccpr2l .8 63 0\n"
|
|
"gpr ccp2con .8 64 0\n"
|
|
"gpr status .8 65 0\n"
|
|
"flg c .1 .520 0\n"
|
|
"flg dc .1 .521 0\n"
|
|
"flg z .1 .522 0\n"
|
|
"flg ov .1 .523 0\n"
|
|
"flg n .1 .524 0\n"
|
|
"gpr prod .16 66 0\n"
|
|
"gpr prodl .8 66 0\n"
|
|
"gpr prodh .8 67 0\n"
|
|
"gpr osccon .8 68 0\n"
|
|
"gpr tmr3h .8 69 0\n"
|
|
"gpr lvdcon .8 70 0\n"
|
|
"gpr tmr3l .8 71 0\n"
|
|
"gpr wdtcon .8 72 0\n"
|
|
"gpr t3con .8 73 0\n"
|
|
"gpr spbrg .8 74 0\n"
|
|
"gpr postinc0 .8 75 0\n"
|
|
"gpr rcreg .8 76 0\n"
|
|
"gpr postdec0 .8 77 0\n"
|
|
"gpr txreg .8 78 0\n"
|
|
"gpr preinc0 .8 79 0\n"
|
|
"gpr txsta .8 80 0\n"
|
|
"gpr plusw0 .8 81 0\n"
|
|
"gpr rcsta .8 82 0\n"
|
|
"gpr sspbuf .8 83 0\n"
|
|
"gpr wreg .8 84 0\n"
|
|
"gpr sspadd .8 85 0\n"
|
|
"gpr sspstat .8 86 0\n"
|
|
"gpr postinc1 .8 87 0\n"
|
|
"gpr sspcon1 .8 88 0\n"
|
|
"gpr postdec1 .8 89 0\n"
|
|
"gpr sspcon2 .8 90 0\n"
|
|
"gpr preinc1 .8 91 0\n"
|
|
"gpr adresh .8 92 0\n"
|
|
"gpr plusw1 .8 93 0\n"
|
|
"gpr adresl .8 94 0\n"
|
|
"gpr adcon0 .8 95 0\n"
|
|
"#stkprt max is 0b11111\n"
|
|
"gpr stkptr .8 96 0\n"
|
|
"gpr tablat .8 14 0\n";
|
|
|
|
return strdup(p);
|
|
}
|
|
|
|
static int analysis_pic_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) {
|
|
if (analysis->cpu && strcasecmp(analysis->cpu, "baseline") == 0) {
|
|
// TODO: implement
|
|
return -1;
|
|
}
|
|
if (analysis->cpu && strcasecmp(analysis->cpu, "midrange") == 0) {
|
|
return analysis_pic_midrange_op(analysis, op, addr, buf, len);
|
|
}
|
|
if (analysis->cpu && strcasecmp(analysis->cpu, "pic18") == 0) {
|
|
return analysis_pic_pic18_op(analysis, op, addr, buf, len);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static char *analysis_pic_get_reg_profile(RzAnalysis *analysis) {
|
|
if (analysis->cpu && strcasecmp(analysis->cpu, "baseline") == 0) {
|
|
// TODO: We are using the midrange profile as the baseline
|
|
return analysis_pic_midrange_get_reg_profile(analysis);
|
|
}
|
|
if (analysis->cpu && strcasecmp(analysis->cpu, "midrange") == 0) {
|
|
return analysis_pic_midrange_get_reg_profile(analysis);
|
|
}
|
|
if (analysis->cpu && strcasecmp(analysis->cpu, "pic18") == 0) {
|
|
return analysis_pic_pic18_get_reg_profile(analysis);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
RzAnalysisPlugin rz_analysis_plugin_pic = {
|
|
.name = "pic",
|
|
.desc = "PIC analysis plugin",
|
|
.license = "LGPL3",
|
|
.arch = "pic",
|
|
.bits = 8,
|
|
.op = &analysis_pic_op,
|
|
.get_reg_profile = &analysis_pic_get_reg_profile,
|
|
.esil = true
|
|
};
|
|
|
|
#ifndef RZ_PLUGIN_INCORE
|
|
RZ_API RzLibStruct rizin_plugin = {
|
|
.type = RZ_LIB_TYPE_ANALYSIS,
|
|
.data = &rz_analysis_plugin_pic,
|
|
.version = RZ_VERSION
|
|
};
|
|
#endif
|