librz/arch: add analysis plugin for MCS96 (#5622)

This commit is contained in:
bubblepipe 2025-12-16 00:09:37 +08:00 committed by GitHub
parent b58e9a6a4a
commit 0321748674
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 1714 additions and 243 deletions

View file

@ -12,6 +12,9 @@
* https://archive.org/details/manualzilla-id-5702485/page/n469/mode/2up
*/
#ifndef MCS96_H
#define MCS96_H
#include <rz_util.h>
#include <rz_types.h>
@ -327,5 +330,407 @@ static Mcs96Op mcs96_op[] = {
{ "rst", MCS96_1B, MCS96_SUPPORT_SINCE_8096 }
};
typedef enum {
MCS96_SKIP_00,
MCS96_CLR_01,
MCS96_NOT_02,
MCS96_NEG_03,
MCS96_XCH_04,
MCS96_DEC_05,
MCS96_EXT_06,
MCS96_INC_07,
MCS96_SHR_08,
MCS96_SHL_09,
MCS96_SHRA_0A,
MCS96_XCH_0B,
MCS96_SHRL_0C,
MCS96_SHLL_0D,
MCS96_SHRAL_0E,
MCS96_NORML_0F,
MCS96_INVALID_10,
MCS96_CLRB_11,
MCS96_NOTB_12,
MCS96_NEGB_13,
MCS96_XCHB_14,
MCS96_DECB_15,
MCS96_EXTB_16,
MCS96_INCB_17,
MCS96_SHRB_18,
MCS96_SHLB_19,
MCS96_SHRAB_1A,
MCS96_XCHB_1B,
MCS96_EST_1C,
MCS96_EST_1D,
MCS96_ESTB_1E,
MCS96_ESTB_1F,
MCS96_SJMP_20,
MCS96_SJMP_21,
MCS96_SJMP_22,
MCS96_SJMP_23,
MCS96_SJMP_24,
MCS96_SJMP_25,
MCS96_SJMP_26,
MCS96_SJMP_27,
MCS96_SCALL_28,
MCS96_SCALL_29,
MCS96_SCALL_2A,
MCS96_SCALL_2B,
MCS96_SCALL_2C,
MCS96_SCALL_2D,
MCS96_SCALL_2E,
MCS96_SCALL_2F,
MCS96_JBC_30,
MCS96_JBC_31,
MCS96_JBC_32,
MCS96_JBC_33,
MCS96_JBC_34,
MCS96_JBC_35,
MCS96_JBC_36,
MCS96_JBC_37,
MCS96_JBS_38,
MCS96_JBS_39,
MCS96_JBS_3A,
MCS96_JBS_3B,
MCS96_JBS_3C,
MCS96_JBS_3D,
MCS96_JBS_3E,
MCS96_JBS_3F,
MCS96_AND_40,
MCS96_AND_41,
MCS96_AND_42,
MCS96_AND_43,
MCS96_ADD_44,
MCS96_ADD_45,
MCS96_ADD_46,
MCS96_ADD_47,
MCS96_SUB_48,
MCS96_SUB_49,
MCS96_SUB_4A,
MCS96_SUB_4B,
MCS96_MULU_4C,
MCS96_MULU_4D,
MCS96_MULU_4E,
MCS96_MULU_4F,
MCS96_ANDB_50,
MCS96_ANDB_51,
MCS96_ANDB_52,
MCS96_ANDB_53,
MCS96_ADDB_54,
MCS96_ADDB_55,
MCS96_ADDB_56,
MCS96_ADDB_57,
MCS96_SUBB_58,
MCS96_SUBB_59,
MCS96_SUBB_5A,
MCS96_SUBB_5B,
MCS96_MULUB_5C,
MCS96_MULUB_5D,
MCS96_MULUB_5E,
MCS96_MULUB_5F,
MCS96_AND_60,
MCS96_AND_61,
MCS96_AND_62,
MCS96_AND_63,
MCS96_ADD_64,
MCS96_ADD_65,
MCS96_ADD_66,
MCS96_ADD_67,
MCS96_SUB_68,
MCS96_SUB_69,
MCS96_SUB_6A,
MCS96_SUB_6B,
MCS96_MULU_6C,
MCS96_MULU_6D,
MCS96_MULU_6E,
MCS96_MULU_6F,
MCS96_ANDB_70,
MCS96_ANDB_71,
MCS96_ANDB_72,
MCS96_ANDB_73,
MCS96_ADDB_74,
MCS96_ADDB_75,
MCS96_ADDB_76,
MCS96_ADDB_77,
MCS96_SUBB_78,
MCS96_SUBB_79,
MCS96_SUBB_7A,
MCS96_SUBB_7B,
MCS96_MULUB_7C,
MCS96_MULUB_7D,
MCS96_MULUB_7E,
MCS96_MULUB_7F,
MCS96_OR_80,
MCS96_OR_81,
MCS96_OR_82,
MCS96_OR_83,
MCS96_XOR_84,
MCS96_XOR_85,
MCS96_XOR_86,
MCS96_XOR_87,
MCS96_CMP_88,
MCS96_CMP_89,
MCS96_CMP_8A,
MCS96_CMP_8B,
MCS96_DIVU_8C,
MCS96_DIVU_8D,
MCS96_DIVU_8E,
MCS96_DIVU_8F,
MCS96_ORB_90,
MCS96_ORB_91,
MCS96_ORB_92,
MCS96_ORB_93,
MCS96_XORB_94,
MCS96_XORB_95,
MCS96_XORB_96,
MCS96_XORB_97,
MCS96_CMPB_98,
MCS96_CMPB_99,
MCS96_CMPB_9A,
MCS96_CMPB_9B,
MCS96_DIVUB_9C,
MCS96_DIVUB_9D,
MCS96_DIVUB_9E,
MCS96_DIVUB_9F,
MCS96_LD_A0,
MCS96_LD_A1,
MCS96_LD_A2,
MCS96_LD_A3,
MCS96_ADDC_A4,
MCS96_ADDC_A5,
MCS96_ADDC_A6,
MCS96_ADDC_A7,
MCS96_SUBC_A8,
MCS96_SUBC_A9,
MCS96_SUBC_AA,
MCS96_SUBC_AB,
MCS96_LDBZE_AC,
MCS96_LDBZE_AD,
MCS96_LDBZE_AE,
MCS96_LDBZE_AF,
MCS96_LDB_B0,
MCS96_LDB_B1,
MCS96_LDB_B2,
MCS96_LDB_B3,
MCS96_ADDCB_B4,
MCS96_ADDCB_B5,
MCS96_ADDCB_B6,
MCS96_ADDCB_B7,
MCS96_SUBCB_B8,
MCS96_SUBCB_B9,
MCS96_SUBCB_BA,
MCS96_SUBCB_BB,
MCS96_LDBSE_BC,
MCS96_LDBSE_BD,
MCS96_LDBSE_BE,
MCS96_LDBSE_BF,
MCS96_ST_C0,
MCS96_BMOV_C1,
MCS96_ST_C2,
MCS96_ST_C3,
MCS96_STB_C4,
MCS96_CMPL_C5,
MCS96_STB_C6,
MCS96_STB_C7,
MCS96_PUSH_C8,
MCS96_PUSH_C9,
MCS96_PUSH_CA,
MCS96_PUSH_CB,
MCS96_POP_CC,
MCS96_BMOVI_CD,
MCS96_POP_CE,
MCS96_POP_CF,
MCS96_JNST_D0,
MCS96_JNH_D1,
MCS96_JGT_D2,
MCS96_JNC_D3,
MCS96_JNVT_D4,
MCS96_JNV_D5,
MCS96_JGE_D6,
MCS96_JNE_D7,
MCS96_JST_D8,
MCS96_JH_D9,
MCS96_JLE_DA,
MCS96_JC_DB,
MCS96_JVT_DC,
MCS96_JV_DD,
MCS96_JLT_DE,
MCS96_JE_DF,
MCS96_DJNZ_E0,
MCS96_DJNZW_E1,
MCS96_TIJMP_E2,
MCS96_BR_E3,
MCS96_EBMOVI_E4,
MCS96_RETI_E5,
MCS96_EJMP_E6,
MCS96_LJMP_E7,
MCS96_ELD_E8,
MCS96_ELD_E9,
MCS96_ELDB_EA,
MCS96_ELDB_EB,
MCS96_DPTS_EC,
MCS96_EPTS_ED,
MCS96_INVALID_EE,
MCS96_LCALL_EF,
MCS96_RET_F0,
MCS96_ECALL_F1,
MCS96_PUSHF_F2,
MCS96_POPF_F3,
MCS96_PUSHA_F4,
MCS96_POPA_F5,
MCS96_IDLPD_F6,
MCS96_TRAP_F7,
MCS96_CLRC_F8,
MCS96_SETC_F9,
MCS96_DI_FA,
MCS96_EI_FB,
MCS96_CLRVT_FC,
MCS96_NOP_FD,
MCS96_MUL_DIV_FE,
MCS96_RST_FF,
} Mcs96Instructions;
static const char *mcs96_fe_op[] = { "mul", "mulb", "mul", "mulb", "div", "divb", "invalid", "invalid" };
// in theory these invalids can never happen
typedef enum {
MCS96_ADDRESSING_REG_DIRECT = 0,
MCS96_ADDRESSING_IMMEDIATE = 1,
MCS96_ADDRESSING_INDIRECT = 2,
MCS96_ADDRESSING_INDEXED = 3,
} Mcs96AddressingMode;
static inline ut32 compute_fe_index(ut8 byte) {
return ((byte & 0x70) >> 4) ^ 0x4;
}
/**
* \brief computes the length of an instruction.
* \return int the length of the instruction. returns -1 when invalid.
*/
static int mcs96_len(ut32 isa_bit, const ut8 *buf, int len) {
if (len < 1) {
return 0;
}
if (!(mcs96_op[buf[0]].isa & isa_bit)) { // unsupported instruction
return -1;
}
int ret = 1;
if (buf[0] == 0xfe) {
if (isa_bit == MCS96_80296) {
return -1;
}
if (len < 2) {
return 0;
}
if (mcs96_op[buf[1]].type & MCS96_FE) {
if (mcs96_op[buf[1]].type & MCS96_5B_OR_6B) {
if (len < 3) {
return 0;
}
ret = 6 + (buf[2] & 0x1);
}
if (mcs96_op[buf[1]].type & MCS96_4B_OR_5B) {
if (len < 3) {
return 0;
}
ret = 5 + (buf[2] & 0x1);
}
if (mcs96_op[buf[1]].type & MCS96_3B_OR_4B) {
if (len < 3) {
return 0;
}
ret = 4 + (buf[1] & 0x1);
}
if (mcs96_op[buf[1]].type & MCS96_5B) {
ret = 6;
}
if (mcs96_op[buf[1]].type & MCS96_4B) {
ret = 5;
}
if (mcs96_op[buf[1]].type & MCS96_3B) {
ret = 4;
}
if (mcs96_op[buf[1]].type & MCS96_2B) {
ret = 3;
}
if (ret > len) {
ret = 0;
}
return ret;
}
}
if (mcs96_op[buf[0]].type & MCS96_5B_OR_6B) {
if (len < 2) {
return 0;
}
ret = 5 + (buf[1] & 0x1);
}
if (mcs96_op[buf[0]].type & MCS96_4B_OR_5B) {
if (len < 2) {
return 0;
}
ret = 4 + (buf[1] & 0x1);
}
if (mcs96_op[buf[0]].type & MCS96_3B_OR_4B) {
if (len < 2) {
return 0;
}
ret = 3 + (buf[1] & 0x1);
}
if (mcs96_op[buf[0]].type & MCS96_6B) {
ret = 6;
}
if (mcs96_op[buf[0]].type & MCS96_5B) {
ret = 5;
}
if (mcs96_op[buf[0]].type & MCS96_4B) {
ret = 4;
}
if (mcs96_op[buf[0]].type & MCS96_3B) {
ret = 3;
}
if (mcs96_op[buf[0]].type & MCS96_2B) {
ret = 2;
}
if (ret > len) {
ret = 0;
}
return ret;
}
/**
* Extract addressing mode from MCS-96 instruction opcode.
* The lower 2 bits (aa) encode the addressing mode for many instructions.
* Format: (xxxxxxaa)
*
* \param opcode The instruction opcode byte
* \return Addressing mode (0-3)
*/
static inline Mcs96AddressingMode extract_addressing_mode(ut8 opcode) {
return (Mcs96AddressingMode)(opcode & 0x03);
}
/**
* Extract 11-bit signed displacement from sjmp/scall instruction.
* Format: (instr|xxx)(disp-low)
*
* \param opcode First byte of the instruction, containing upper 3 bits of the displacement
* \param disp_low Second byte of the instruction, containing lower 8 bits of the displacement
* \return Sign-extended 16-bit displacement (-1024 to +1023)
*/
static inline st16 extract_disp11(ut8 opcode, ut8 disp_low) {
st16 upper3bits = (st16)(opcode & 0x07); // 0b00000111
st16 disp = (upper3bits << 8) | disp_low;
// Sign-extend from 11 bits to 16 bits
if (disp & 0x400) { // Check if bit 10 (sign bit) is set
disp |= 0xF800; // Set bits 15-11 to extend the sign
}
return disp;
}
#endif /* MCS96_H */

File diff suppressed because it is too large Load diff

View file

@ -5,5 +5,6 @@
#include <deprecated_arch_helper.h>
#include "asm/asm_mcs96.c"
#include "analysis/analysis_mcs96.c"
RZ_ARCH_ASM_ONLY_PLUGIN_DEFINE_DEPRECATED(mcs96);
RZ_ARCH_PLUGIN_DEFINE_DEPRECATED(mcs96);

View file

@ -10,13 +10,6 @@
#include "rz_analysis.h"
#include "rz_util/rz_pj.h"
typedef enum {
MCS96_ADDRESSING_REG_DIRECT = 0, // 2 reg
MCS96_ADDRESSING_IMMEDIATE = 1, // 1 reg + 1 imm
MCS96_ADDRESSING_INDIRECT = 2, //
MCS96_ADDRESSING_INDEXED = 3,
} MCS96_ADDRESSING_MODE;
typedef struct {
RzPVector /*<RzAsmTokenPattern *>*/ *token_patterns;
} Mcs96Context;
@ -44,235 +37,6 @@ static RZ_OWN RzPVector /*<RzAsmTokenPattern *>*/ *get_token_patterns() {
return pvec;
}
/**
* @brief computes the length of an instruction.
* @return int the length of the instruction. returns -1 when invalid.
*/
static int mcs96_len(ut32 isa_bit, const ut8 *buf, int len) {
if (len < 1) {
return 0;
}
if (!(mcs96_op[buf[0]].isa & isa_bit)) { // unsupported instruction
return -1;
}
int ret = 1;
if (buf[0] == 0xfe) {
if (isa_bit == MCS96_80296) {
return -1;
}
if (len < 2) {
return 0;
}
if (mcs96_op[buf[1]].type & MCS96_FE) {
if (mcs96_op[buf[1]].type & MCS96_5B_OR_6B) {
if (len < 3) {
return 0;
}
ret = 6 + (buf[2] & 0x1);
}
if (mcs96_op[buf[1]].type & MCS96_4B_OR_5B) {
if (len < 3) {
return 0;
}
ret = 5 + (buf[2] & 0x1);
}
if (mcs96_op[buf[1]].type & MCS96_3B_OR_4B) {
if (len < 3) {
return 0;
}
ret = 4 + (buf[1] & 0x1);
}
if (mcs96_op[buf[1]].type & MCS96_5B) {
ret = 6;
}
if (mcs96_op[buf[1]].type & MCS96_4B) {
ret = 5;
}
if (mcs96_op[buf[1]].type & MCS96_3B) {
ret = 4;
}
if (mcs96_op[buf[1]].type & MCS96_2B) {
ret = 3;
}
if (ret > len) {
ret = 0;
}
return ret;
}
}
if (mcs96_op[buf[0]].type & MCS96_5B_OR_6B) {
if (len < 2) {
return 0;
}
ret = 5 + (buf[1] & 0x1);
}
if (mcs96_op[buf[0]].type & MCS96_4B_OR_5B) {
if (len < 2) {
return 0;
}
ret = 4 + (buf[1] & 0x1);
}
if (mcs96_op[buf[0]].type & MCS96_3B_OR_4B) {
if (len < 2) {
return 0;
}
ret = 3 + (buf[1] & 0x1);
}
if (mcs96_op[buf[0]].type & MCS96_6B) {
ret = 6;
}
if (mcs96_op[buf[0]].type & MCS96_5B) {
ret = 5;
}
if (mcs96_op[buf[0]].type & MCS96_4B) {
ret = 4;
}
if (mcs96_op[buf[0]].type & MCS96_3B) {
ret = 3;
}
if (mcs96_op[buf[0]].type & MCS96_2B) {
ret = 2;
}
if (ret > len) {
ret = 0;
}
return ret;
}
static const char *decode_mnemonic(const ut8 *buf, int size, ut32 isa_bit) {
if (size <= 0) {
return "invalid";
}
if (buf[0] == 0x0d && isa_bit == MCS96_80296 && size == 3) { // SHLL/MVAC/MSAC
ut8 lreg_bits = buf[2] & 0x3;
// lreg.1 lreg.0 Execute
// 0 0 SHLL
// 0 1 MVAC
// 1 0 Reserved
// 1 1 MSAC
switch (lreg_bits) {
case 0x0:
return "shll";
case 0x1:
return "mvac";
case 0x3:
return "msac";
default:
return "invalid";
}
} else if (buf[0] == 0x40 && isa_bit == MCS96_80296 && buf[size - 1] == 0x04 && size == 4) { // AND/RPT/RPTxxx/RPTI/RPTIxxx
// RPT waop
// (010000aa) (waop) (00) (04)
// RPTxxx
// (010000aa) (waop) (10 - 1F) (04)
// RPTI
// (010000aa) (waop) (20) (04)
// RPTIxxx
// (010000aa) (waop) (30 - 3F) (04)
switch (buf[size - 2]) {
case 0x00:
return "rpt";
case 0x10:
return "rptnst";
case 0x11:
return "rptnh";
case 0x12:
return "rptgt";
case 0x13:
return "rptnc";
case 0x14:
return "rptnvt";
case 0x15:
return "rptnv";
case 0x16:
return "rptge";
case 0x17:
return "rptne";
case 0x18:
return "rptst";
case 0x19:
return "rpth";
case 0x1a:
return "rptle";
case 0x1b:
return "rptc";
case 0x1c:
return "rptvt";
case 0x1d:
return "rptv";
case 0x1e:
return "rptlt";
case 0x1f:
return "rpte";
case 0x20:
return "rpti";
case 0x30:
return "rptinst";
case 0x31:
return "rptinh";
case 0x32:
return "rptigt";
case 0x33:
return "rptinc";
case 0x34:
return "rptinvt";
case 0x35:
return "rptinv";
case 0x36:
return "rptige";
case 0x37:
return "rptine";
case 0x38:
return "rptist";
case 0x39:
return "rptih";
case 0x3a:
return "rptile";
case 0x3b:
return "rptic";
case 0x3c:
return "rptivt";
case 0x3d:
return "rptiv";
case 0x3e:
return "rptilt";
case 0x3f:
return "rptie";
default:
return "and";
}
} else if (mcs96_op[buf[1]].type & MCS96_FE && size > 2) {
const ut32 fe_idx = ((buf[1] & 0x70) >> 4) ^ 0x4;
return mcs96_fe_op[fe_idx];
} else {
return mcs96_op[buf[0]].ins;
}
}
/**
* Extract 11-bit signed displacement from sjmp/scall instruction.
* Format: (instr|xxx)(disp-low)
*
* \param opcode First byte of the instruction, containing upper 3 bits of the displacement
* \param disp_low Second byte of the instruction, containing lower 8 bits of the displacement
* \return Sign-extended 16-bit displacement (-1024 to +1023)
*/
static st16 extract_disp11(ut8 opcode, ut8 disp_low) {
st16 upper3bits = (st16)(opcode & 0x07); // 0b00000111
st16 disp = (upper3bits << 8) | disp_low;
// Sign-extend from 11 bits to 16 bits
if (disp & 0x400) { // Check if bit 10 (sign bit) is set
disp |= 0xF800; // Set bits 15-11 to extend the sign
}
return disp;
}
static void decode_operands(RzAsmOp *op, const char *mnemonic, const ut8 *buf, int size, ut32 isa_bit) {
if (size < 1) {
return;
@ -415,6 +179,117 @@ static void decode_operands(RzAsmOp *op, const char *mnemonic, const ut8 *buf, i
}
}
static const char *decode_mnemonic(const ut8 *buf, int size, ut32 isa_bit) {
if (size <= 0) {
return "invalid";
}
if (buf[0] == 0x0d && isa_bit == MCS96_80296 && size == 3) { // SHLL/MVAC/MSAC
ut8 lreg_bits = buf[2] & 0x3;
// lreg.1 lreg.0 Execute
// 0 0 SHLL
// 0 1 MVAC
// 1 0 Reserved
// 1 1 MSAC
switch (lreg_bits) {
case 0x0:
return "shll";
case 0x1:
return "mvac";
case 0x3:
return "msac";
default:
return "invalid";
}
} else if (buf[0] == 0x40 && isa_bit == MCS96_80296 && size == 4 && buf[size - 1] == 0x04) { // AND/RPT/RPTxxx/RPTI/RPTIxxx
// RPT waop
// (010000aa) (waop) (00) (04)
// RPTxxx
// (010000aa) (waop) (10 - 1F) (04)
// RPTI
// (010000aa) (waop) (20) (04)
// RPTIxxx
// (010000aa) (waop) (30 - 3F) (04)
switch (buf[size - 2]) {
case 0x00:
return "rpt";
case 0x10:
return "rptnst";
case 0x11:
return "rptnh";
case 0x12:
return "rptgt";
case 0x13:
return "rptnc";
case 0x14:
return "rptnvt";
case 0x15:
return "rptnv";
case 0x16:
return "rptge";
case 0x17:
return "rptne";
case 0x18:
return "rptst";
case 0x19:
return "rpth";
case 0x1a:
return "rptle";
case 0x1b:
return "rptc";
case 0x1c:
return "rptvt";
case 0x1d:
return "rptv";
case 0x1e:
return "rptlt";
case 0x1f:
return "rpte";
case 0x20:
return "rpti";
case 0x30:
return "rptinst";
case 0x31:
return "rptinh";
case 0x32:
return "rptigt";
case 0x33:
return "rptinc";
case 0x34:
return "rptinvt";
case 0x35:
return "rptinv";
case 0x36:
return "rptige";
case 0x37:
return "rptine";
case 0x38:
return "rptist";
case 0x39:
return "rptih";
case 0x3a:
return "rptile";
case 0x3b:
return "rptic";
case 0x3c:
return "rptivt";
case 0x3d:
return "rptiv";
case 0x3e:
return "rptilt";
case 0x3f:
return "rptie";
default:
return "and";
}
} else if (size > 2 && mcs96_op[buf[1]].type & MCS96_FE) {
const ut32 fe_idx = ((buf[1] & 0x70) >> 4) ^ 0x4;
return mcs96_fe_op[fe_idx];
} else {
return mcs96_op[buf[0]].ins;
}
}
static bool init(void **u) {
if (!u) {
return false;
@ -480,7 +355,7 @@ RzAsmPlugin rz_asm_plugin_mcs96 = {
.license = "LGPL3",
.author = "condret",
.bits = 16,
.endian = RZ_SYS_ENDIAN_NONE,
.endian = RZ_SYS_ENDIAN_LITTLE,
.init = &init,
.fini = &fini,
.disassemble = &disassemble

92
test/db/analysis/mcs96 Normal file
View file

@ -0,0 +1,92 @@
NAME=mcs96 byte tests
FILE=malloc://4096
CMDS=<<EOF
e asm.arch=mcs96
e asm.cpu=8096
ar
echo ----
wx 2010
ao 1~type,jump
echo ----
wx f0
ao 1~type,stackptr
echo ----
wx cc10
ao 1~type,stackptr
echo ----
wx a0010203
ao 1~type,ptr
echo ----
wx a1123412
ao 1~type,val
echo ----
wx 65123401
ao 1~type,val
EOF
EXPECT=<<EOF
pc = 0x0000
sp = 0x0000
psw = 0x0000
garbage = 0x0000
garbage = 0x0000
garbage = 0x0000
----
type: jmp
jump: 0x00000012
----
type: ret
stackptr: 2
----
type: pop
stackptr: 2
----
ptr: 0x00000201
refptr: 2
type: load
----
val: 0x00003412
type: load
----
val: 0x00003412
type: add
EOF
RUN
NAME=mcs96 fib.bin tests
FILE=bins/mcs96/fib.bin
ARGS=-m 0x2080
CMDS=<<EOF
e asm.arch=mcs96
e asm.cpu=8096
aaa
pdf
EOF
EXPECT=<<EOF
; CALL XREFS from fcn.00002080 @ 0x2098, 0x20a7
/ fcn.00002080();
| 0x00002080 push 0x1a ; [0xa31a:2]=0xffff
| 0x00002082 ld 0x1a 0x04[0x18]
| 0x00002086 cmp 0x1a 0x0001
| ,=< 0x0000208a jgt 0x05
| | 0x0000208c ld 0x1c 0x1a ; [0x1c1a:2]=0xffff
| ,==< 0x0000208f sjmp 0x0026
| |`-> 0x00002091 ld 0x1c 0x1a ; [0x1c1a:2]=0xffff
| | 0x00002094 dec 0x1c
| | 0x00002096 push 0x1c ; [0x2f1c:2]=0xffff
| | 0x00002098 scall 0xffe6
| | 0x0000209a add 0x18 0x0002
| | 0x0000209e push 0x1c ; [0x491c:2]=0xffff
| | 0x000020a0 sub 0x1c 0x1a 0x0002
| | 0x000020a5 push 0x1c ; [0x2f1c:2]=0xffff
| | 0x000020a7 scall 0xffd7
| | 0x000020a9 add 0x18 0x0002
| | 0x000020ad pop 0x1e
| | 0x000020af add 0x1e 0x1c ; [0x1e1c:2]=0xffff
| | 0x000020b2 ld 0x1c 0x1e ; [0x1c1e:2]=0xffff
| |,=< 0x000020b5 sjmp 0x0000
| || ; CODE XREFS from fcn.00002080 @ 0x208f, 0x20b5
| ``-> 0x000020b7 pop 0x1a
\ 0x000020b9 ret
EOF
RUN

View file

@ -35,7 +35,7 @@ _dA__ 8 32 m680x BSD Motorola 680X Capstone-based disassembler
_dA__ 32 m68k BSD Motorola 68K Capstone-based disassembler
_dA__ 32 malbolge LGPL3 Malbolge Ternary VM bytecode disassembler (by condret)
_dA__ 32 mcore LGPL3 Motorola MCORE disassembler
_d___ 16 mcs96 LGPL3 Intel MCS-96 disassembler (by condret)
_dA__ 16 mcs96 LGPL3 Intel MCS-96 disassembler (by condret)
adAeI 16 32 64 mips BSD MIPS Capstone-based disassembler
_dA_I 16 msp430 LGPL3 Texas Instruments MSP430 disassembler
adA__ 16 32 64 null MIT NULL (empty) disassembler (by pancake) v1.0.0

File diff suppressed because one or more lines are too long