rizin/librz/arch/p/asm/asm_c166.c
SSharshunov eda5e12b56
librz/arch/c166: Coverity fixes
* CID: 909863
* CID: 909871
* CID: 909855
* CID: 909865
* CID: 909864
* CID: 909872
* CID: 909867
* CID: 909843
* CID: 909847
* CID: 909873
* CID 909856
2026-07-09 00:20:49 +08:00

498 lines
13 KiB
C

// SPDX-FileCopyrightText: 2025 Alexandru Aioanei <alex03aioanei@gmail.com>
// SPDX-FileCopyrightText: 2025-2026 Sergey Sharshunov <s.sharshunov@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
/**
* \file asm_c166.c
* \brief Assembly and disassembly plugin for C166 architecture
*
* Provides functionality for disassembling C166 machine code into assembly language
* representation and assembling C166 assembly code into machine code.
*/
#include <stdio.h>
#include <rz_types.h>
#include <rz_util.h>
#include <rz_lib.h>
#include <rz_asm.h>
#include "asm_private.h"
#include "librz/arch/isa/c166/c166_disas.h"
static bool check_unused_opcode(const ut8 opcode) {
switch (opcode) {
case 0x3b:
case 0x44:
case 0x45:
case 0x8B:
case 0x95:
case 0xC1:
case 0xC7:
case 0xE3:
case 0xE5:
case 0xF5:
case 0xF8:
case 0xF9:
return true;
default:
break;
}
return false;
}
static _RzAnalysisOpType c166_analysis_op_type_by_opcode(const ut8 opcode) {
switch (opcode) {
case C166_ADD_Rwn_Rwm:
case C166_ADDB_Rbn_Rbm:
case C166_ADD_reg_mem:
case C166_ADDB_reg_mem:
case C166_ADD_mem_reg:
case C166_ADDB_mem_reg:
case C166_ADD_reg_data16:
case C166_ADDB_reg_data8:
case C166_ADD_Rwn_x:
case C166_ADDB_Rbn_x:
case C166_ADDC_Rwn_Rwm:
case C166_ADDCB_Rbn_Rbm:
case C166_ADDC_reg_mem:
case C166_ADDCB_reg_mem:
case C166_ADDC_mem_reg:
case C166_ADDCB_mem_reg:
case C166_ADDC_reg_data16:
case C166_ADDCB_reg_data8:
case C166_ADDC_Rwn_x:
case C166_ADDCB_Rbn_x:
return RZ_ANALYSIS_OP_TYPE_ADD;
case C166_BFLDL_bitoff_x:
case C166_BCLR_bitoff0:
case C166_BSET_bitoff0:
case C166_BFLDH_bitoff_x:
case C166_BCLR_bitoff1:
case C166_BSET_bitoff1:
case C166_BCLR_bitoff2:
case C166_BSET_bitoff2:
case C166_BCLR_bitoff3:
case C166_BSET_bitoff3:
case C166_BCLR_bitoff4:
case C166_BSET_bitoff4:
case C166_BCLR_bitoff5:
case C166_BSET_bitoff5:
case C166_BCLR_bitoff6:
case C166_BSET_bitoff6:
case C166_BCLR_bitoff7:
case C166_BSET_bitoff7:
case C166_BCLR_bitoff8:
case C166_BSET_bitoff8:
case C166_BCLR_bitoff9:
case C166_BSET_bitoff9:
case C166_BCLR_bitoff10:
case C166_BSET_bitoff10:
case C166_BCLR_bitoff11:
case C166_BSET_bitoff11:
case C166_BCLR_bitoff12:
case C166_BSET_bitoff12:
case C166_BCLR_bitoff13:
case C166_BSET_bitoff13:
case C166_BCLR_bitoff14:
case C166_BSET_bitoff14:
case C166_BCLR_bitoff15:
case C166_BSET_bitoff15:
return RZ_ANALYSIS_OP_TYPE_STORE;
case C166_MUL_Rwn_Rwm:
case C166_MULU_Rwn_Rwm:
return RZ_ANALYSIS_OP_TYPE_MUL;
case C166_ROL_Rwn_Rwm:
case C166_ROL_Rwn_data4:
return RZ_ANALYSIS_OP_TYPE_ROL;
case C166_JMPR_cc_UC_rel:
case C166_JMPR_cc_NET_rel:
case C166_JMPR_cc_EQ_or_Z_rel:
case C166_JMPR_cc_NE_or_NZ_rel:
case C166_JMPR_cc_V_rel:
case C166_JMPR_cc_NV_rel:
case C166_JMPR_cc_N_rel:
case C166_JMPR_cc_NN_rel:
case C166_JMPR_cc_C_or_ULT_rel:
case C166_JMPR_cc_NC_or_NGE_rel:
case C166_JMPR_cc_SGT_rel:
case C166_JMPR_cc_SLE_rel:
case C166_JMPR_cc_SLT_rel:
case C166_JMPR_cc_SGE_rel:
case C166_JMPA_cc_caddr:
case C166_JMPR_cc_UGT_rel:
case C166_JMPS_seg_caddr:
case C166_JMPR_cc_ULE_rel:
case C166_JB_bitaddr_rel:
case C166_JBC_bitaddr_rel:
case C166_JNB_bitaddr_rel:
case C166_JNBS_bitaddr_rel:
return RZ_ANALYSIS_OP_TYPE_CJMP;
case C166_SUB_Rwn_Rwm:
case C166_SUBB_Rbn_Rbm:
case C166_SUB_reg_mem:
case C166_SUBB_reg_mem:
case C166_SUB_mem_reg:
case C166_SUBB_mem_reg:
case C166_SUB_reg_data16:
case C166_SUBB_reg_data8:
case C166_SUB_Rwn_x:
case C166_SUBB_Rbn_x:
case C166_SUBC_Rwn_Rwm:
case C166_SUBCB_Rbn_Rbm:
case C166_SUBC_reg_mem:
case C166_SUBCB_reg_mem:
case C166_SUBC_mem_reg:
case C166_SUBCB_mem_reg:
case C166_SUBC_reg_data16:
case C166_SUBCB_reg_data8:
case C166_SUBC_Rwn_x:
case C166_SUBCB_Rbn_x:
return RZ_ANALYSIS_OP_TYPE_SUB;
case C166_BCMP_bitaddr_bitaddr:
case C166_CMP_Rwn_Rwm:
case C166_CMPB_Rbn_Rbm:
case C166_CMP_reg_mem:
case C166_CMPB_reg_mem:
case C166_CMP_reg_data16:
case C166_CMPB_reg_data8:
case C166_CMP_Rwn_x:
case C166_CMPB_Rbn_x:
case C166_CMPI1_Rwn_data4:
case C166_CMPI1_Rwn_mem:
case C166_CMPI1_Rwn_data16:
case C166_CMPI2_Rwn_data4:
case C166_CMPI2_Rwn_mem:
case C166_CMPI2_Rwn_data16:
case C166_CMPD1_Rwn_data4:
case C166_CMPD1_Rwn_mem:
case C166_CMPD1_Rwn_data16:
case C166_CMPD2_Rwn_data4:
case C166_CMPD2_Rwn_mem:
case C166_CMPD2_Rwn_data16:
return RZ_ANALYSIS_OP_TYPE_CMP;
case C166_XOR_Rwn_Rwm:
case C166_XORB_Rbn_Rbm:
case C166_XOR_reg_mem:
case C166_XORB_reg_mem:
case C166_XOR_mem_reg:
case C166_XORB_mem_reg:
case C166_XOR_reg_data16:
case C166_XORB_reg_data8:
case C166_XOR_Rwn_x:
case C166_XORB_Rbn_x:
return RZ_ANALYSIS_OP_TYPE_XOR;
case C166_AND_Rwn_Rwm:
case C166_ANDB_Rbn_Rbm:
case C166_AND_reg_mem:
case C166_ANDB_reg_mem:
case C166_AND_mem_reg:
case C166_ANDB_mem_reg:
case C166_AND_reg_data16:
case C166_ANDB_reg_data8:
case C166_AND_Rwn_x:
case C166_ANDB_Rbn_x:
return RZ_ANALYSIS_OP_TYPE_AND;
case C166_BMOVN_bitaddr_bitaddr:
case C166_BMOV_bitaddr_bitaddr:
case C166_MOV_oRwn_mem:
case C166_MOV_noRwm_Rwn:
case C166_MOVB_noRwm_Rbn:
case C166_MOV_mem_oRwn:
case C166_MOV_Rwn_oRwmp:
case C166_MOVB_Rbn_oRwmp:
case C166_MOVB_oRwn_mem:
case C166_MOV_Rwn_oRwm:
case C166_MOVB_Rbn_oRwm:
case C166_MOVB_mem_oRwn:
case C166_MOV_oRwm_Rwn:
case C166_MOVB_oRwm_Rbn:
case C166_MOVBZ_Rwn_Rbm:
case C166_MOVBZ_reg_mem:
case C166_MOV_oRwm_data16_Rwn:
case C166_MOVBZ_mem_reg:
case C166_MOV_oRwn_oRwm:
case C166_MOVB_oRwn_oRwm:
case C166_MOVBS_Rwn_Rbm:
case C166_MOVBS_reg_mem:
case C166_MOV_Rwn_oRwm_data16:
case C166_MOVBS_mem_reg:
case C166_MOV_oRwnp_oRwm:
case C166_MOVB_oRwnp_oRwm:
case C166_MOV_Rwn_data4:
case C166_MOVB_Rbn_data4:
case C166_MOVB_oRwm_data16_Rbn:
case C166_MOV_reg_data16:
case C166_MOVB_reg_data8:
case C166_MOV_oRwn_oRwmp:
case C166_MOVB_oRwn_oRwmp:
case C166_MOV_Rwn_Rwm:
case C166_MOVB_Rbn_Rbm:
case C166_MOV_reg_mem:
case C166_MOVB_reg_mem:
case C166_MOVB_Rbn_oRwm_data16:
case C166_MOV_mem_reg:
case C166_MOVB_mem_reg:
return RZ_ANALYSIS_OP_TYPE_MOV;
case C166_OR_Rwn_Rwm:
case C166_ORB_Rbn_Rbm:
case C166_OR_reg_mem:
case C166_ORB_reg_mem:
case C166_OR_mem_reg:
case C166_ORB_mem_reg:
case C166_OR_reg_data16:
case C166_ORB_reg_data8:
case C166_OR_Rwn_x:
case C166_ORB_Rbn_x:
return RZ_ANALYSIS_OP_TYPE_OR;
case C166_RET:
case C166_RETS:
case C166_RETP_reg:
case C166_RETI:
return RZ_ANALYSIS_OP_TYPE_RET;
case C166_DIV_Rwn:
case C166_DIVU_Rwn:
case C166_DIVL_Rwn:
case C166_DIVLU_Rwn:
return RZ_ANALYSIS_OP_TYPE_DIV;
case C166_ROR_Rwn_Rwm:
case C166_ROR_Rwn_data4:
return RZ_ANALYSIS_OP_TYPE_ROR;
case C166_SHL_Rwn_Rwm:
case C166_SHL_Rwn_data4:
return RZ_ANALYSIS_OP_TYPE_SHL;
case C166_SHR_Rwn_Rwm:
case C166_SHR_Rwn_data4:
case C166_ASHR_Rwn_Rwm:
case C166_ASHR_Rwn_data4:
return RZ_ANALYSIS_OP_TYPE_SHR;
case C166_CPL_Rwn:
case C166_NEGB_Rbn:
case C166_CPLB_Rbn:
return RZ_ANALYSIS_OP_TYPE_CPL;
case C166_CALLR_rel:
case C166_CALLS_seg_caddr:
case C166_PCALL_reg_caddr:
return RZ_ANALYSIS_OP_TYPE_CALL;
case C166_TRAP_trap7:
return RZ_ANALYSIS_OP_TYPE_TRAP;
case C166_JMPI_cc_oRwn:
return RZ_ANALYSIS_OP_TYPE_RCJMP;
case C166_CALLI_cc_Rwn:
return RZ_ANALYSIS_OP_TYPE_IRCALL;
case C166_CALLA_cc_caddr:
return RZ_ANALYSIS_OP_TYPE_CCALL;
case C166_NOP:
return RZ_ANALYSIS_OP_TYPE_NOP;
case C166_PUSH_reg:
return RZ_ANALYSIS_OP_TYPE_PUSH;
case C166_POP_reg:
return RZ_ANALYSIS_OP_TYPE_POP;
case C166_PRIOR_Rwn_Rwm: // or RZ_ANALYSIS_OP_TYPE_LOAD,
case C166_BOR_bitaddr_bitaddr:
case C166_BAND_bitaddr_bitaddr:
case C166_BXOR_bitaddr_bitaddr:
case C166_NEG_Rwn:
case C166_CoXXX_83:
case C166_ENWDT:
case C166_IDLE:
case C166_SBRK:
case C166_CoXXX_93:
case C166_PWRDN:
case C166_CoXXX_A3:
case C166_DISWDT:
case C166_SRVWDT:
case C166_CoSTORE_B3:
case C166_EINIT:
case C166_SRST:
case C166_CoSTORE_C3:
case C166_SCXT_reg_data16:
case C166_ATOMIC_or_EXTR_irang2:
case C166_CoMOV:
case C166_SCXT_reg_mem:
case C166_EXTP_or_EXTS_pag10_or_seg8_irang2:
case C166_EXTP_or_EXTS_Rwm_irang2:
return RZ_ANALYSIS_OP_TYPE_UNK;
default:
printf("0x%02x\n", opcode);
rz_warn_if_reached();
return RZ_ANALYSIS_OP_TYPE_UNK;
}
}
/**
* \brief C166 disassembly function
* \param a Pointer to RzAsm structure
* \param op Pointer to RzAsmOp structure to be filled with disassembly data
* \param buf Buffer containing instruction bytes
* \param len Length of the buffer
* \return Length of the disassembled instruction or 0 on failure
*
* Disassembles a single C166 instruction and populates the op->buf_asm with
* human-readable assembly representation. Uses the c166_decode_command helper function
* to perform the actual disassembly.
*/
static st32 disassemble(const RzAsm *a, RzAsmOp *op, const ut8 *buf, st32 len) {
if (!a || !op || !buf) {
return -1;
}
if (len < 2) {
rz_asm_op_setf_asm(op, FMT_WORD, buf[0], 0x00);
op->size = 2;
return op->size;
}
if (!a->plugin_data) {
RZ_LOG_FATAL("C166State was NULL.\n");
return -1;
}
C166State *state = (C166State *)a->plugin_data;
C166_Inst inst = RZ_EMPTY;
inst.addr = (ut32)a->pc;
if (check_unused_opcode(buf[0])) {
rz_asm_op_setf_asm(op, FMT_WORD, buf[0], buf[1]);
op->size = 2;
return op->size;
}
op->size = c166_decode_command(state, &inst, buf, len);
if (op->size == 4 && len == 3) {
rz_asm_op_setf_asm(op, FMT_2WORD, buf[0], buf[1], buf[2], 0x00);
} else if (op->size == 4 && len == 2) {
rz_asm_op_setf_asm(op, FMT_2WORD, buf[0], buf[1], 0x00, 0x00);
} else if (RZ_STR_EQ(inst.instr, "invalid")) {
if (op->size == 2)
rz_asm_op_setf_asm(op, FMT_WORD, buf[0], buf[1]);
else
rz_asm_op_setf_asm(op, FMT_2WORD, buf[0], buf[1], buf[2], buf[3]);
} else {
if (RZ_STR_ISNOTEMPTY(inst.operands)) {
rz_asm_op_setf_asm(op, FMT7, inst.instr, inst.operands);
} else {
rz_asm_op_setf_asm(op, "%s", inst.instr);
}
}
op->asm_toks = rz_asm_tokenize_asm_regex(&op->buf_asm, state->token_patterns);
if (!op->asm_toks) {
return op->size;
}
op->asm_toks->op_type = c166_analysis_op_type_by_opcode(inst.id);
return op->size;
}
#define TOKEN(_type, _pat) \
do { \
RzAsmTokenPattern *pat = RZ_NEW0(RzAsmTokenPattern); \
pat->type = RZ_ASM_TOKEN_##_type; \
pat->pattern = rz_str_dup(_pat); \
rz_pvector_push(pvec, pat); \
} while (0)
static RZ_OWN RzPVector /*<RzAsmTokenPattern *>*/ *get_token_patterns() {
RzPVector *pvec = rz_pvector_new(rz_asm_token_pattern_free);
if (!pvec) {
return NULL;
}
TOKEN(META, "^(.word.*)");
TOKEN(SEPARATOR, "([\\s.,:]+)");
TOKEN(REGISTER, "\\b0x([fF][eEfF][0-9a-fA-F]{2})\\b");
TOKEN(MNEMONIC, "^(jmpa[+-]?)"); ///< jmpa+ jmpa- mnemonics
TOKEN(MNEMONIC, "^(calla[+-]?)"); ///< calla+ calla- mnemonics
TOKEN(META, "^([\\- USR]+[012]?)");
TOKEN(MNEMONIC, "\\b(Co[\\w]+[12]?)"); ///< CoXXX mnemonics
TOKEN(META, "([\\[\\]\\-#])");
// TOKEN(META, "(cc_\\w+)");
TOKEN(META, "(cc_[\\w\\/]+)");
// Hexadecimal numbers
TOKEN(NUMBER, "(0x[0-9a-f]+)");
/**
* Match normal registers which start with small r, optional h or l
* and a number.
* Or match special register names which are always upper case
* and possibly have numbers in it.
*/
TOKEN(REGISTER, "\\b(r[hl]?[0-9]{1,2}|[A-Z]+[A-Z0-9]*)\\b");
TOKEN(MNEMONIC, "^([\\w]+[12]?)");
// TOKEN(SEPARATOR, "([\\s.,:+]+)");
TOKEN(SEPARATOR, "(\\+)");
// Decimal numbers
TOKEN(NUMBER, "(data[2,3,4,5,8])");
TOKEN(NUMBER, "(\\d+)");
/**
* These comments are technical,
* to avoid losing working token versions
* for functions that are not yet fully implemented.
*/
return pvec;
}
static bool c16x_init(void **user) {
C166State *state = RZ_NEW0(C166State);
if (!state) {
RZ_LOG_FATAL("Could not allocate memory for C166State!\n");
return false;
}
const C166ExtState ext = {
.esfr = false,
.mode = C166_EXT_MODE_NONE,
.i = 0,
.value = 0
};
state->ext = ext;
state->last_addr = 0;
state->token_patterns = get_token_patterns();
rz_asm_compile_token_patterns(state->token_patterns);
*user = state; ///< user = RzAsm.plugin_data
return true;
}
static bool c16x_fini(void *user) {
if (!user) {
return false;
}
C166State *state = (C166State *)user;
rz_pvector_free(state->token_patterns);
free(state);
return true;
}
static char **c166_cpu_descriptions() {
static char *cpu_desc[] = {
"c166-generic", "Siemens/Infineon C166 family",
"c166v1", "Siemens/Infineon C16x v1 family",
"c166v2", "Siemens/Infineon C16x v2 family",
NULL
};
return cpu_desc;
}
RzAsmPlugin rz_asm_plugin_c166 = {
.name = "c166",
.arch = "c166",
.bits = 16,
.endian = RZ_SYS_ENDIAN_LITTLE,
.desc = "Siemens/Infineon C166 microcontroller disassembler",
.license = "LGPL3",
.disassemble = &disassemble,
.init = &c16x_init,
.fini = &c16x_fini,
.cpus =
"c166-generic,"
"c166v1,"
"c166v2",
.get_cpu_desc = c166_cpu_descriptions,
};
#ifndef RZ_PLUGIN_INCORE
RZ_API RzLibStruct rizin_plugin = {
.type = RZ_LIB_TYPE_ASM,
.data = rz_asm_plugin_c166,
.version = RZ_VERSION
};
#endif