Skip to content

Commit 64fdf17

Browse files
committed
correctly decode 12-byte extended FPU immediates
1 parent 2cf71bf commit 64fdf17

7 files changed

Lines changed: 127 additions & 0 deletions

File tree

arch/M68K/M68KDisassembler.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,18 @@ static uint64_t m68k_read_safe_64(const m68k_info *info, const uint64_t address)
218218
return m68k_read_disassembler_64(info, addr);
219219
}
220220

221+
static void m68k_read_safe_96(const m68k_info *info, const uint64_t address,
222+
uint8_t *dst)
223+
{
224+
const uint64_t addr = (address - info->baseAddress) &
225+
info->address_mask;
226+
if (info->code_len < addr + 12) {
227+
memset(dst, 0xaa, 12);
228+
return;
229+
}
230+
memcpy(dst, info->code + addr, 12);
231+
}
232+
221233
/* ======================================================================== */
222234
/* =============================== PROTOTYPES ============================= */
223235
/* ======================================================================== */
@@ -306,6 +318,10 @@ static unsigned long long peek_imm_64(const m68k_info *info)
306318
{
307319
return m68k_read_safe_64((info), (info)->pc);
308320
}
321+
static void peek_imm_96(const m68k_info *info, uint8_t *dst)
322+
{
323+
m68k_read_safe_96(info, info->pc, dst);
324+
}
309325

310326
static unsigned int read_imm_8(m68k_info *info)
311327
{
@@ -331,6 +347,11 @@ static unsigned long long read_imm_64(m68k_info *info)
331347
(info)->pc += 8;
332348
return value & 0xffffffffffffffff;
333349
}
350+
static void read_imm_96(m68k_info *info, uint8_t *dst)
351+
{
352+
peek_imm_96(info, dst);
353+
info->pc += 12;
354+
}
334355

335356
/* Fake a split interface */
336357
#define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0)
@@ -611,6 +632,8 @@ static void get_ea_mode_op(m68k_info *info, cs_m68k_op *op,
611632
op->imm = read_imm_16(info);
612633
else if (size == 4)
613634
op->imm = read_imm_32(info);
635+
else if (size == 12)
636+
read_imm_96(info, op->fp_ext.ximm);
614637
else
615638
op->imm = read_imm_64(info);
616639

@@ -2374,12 +2397,16 @@ static void d68020_fpu(m68k_info *info)
23742397
ext->op_size.type = M68K_SIZE_TYPE_FPU;
23752398
ext->op_size.fpu_size = M68K_FPU_SIZE_EXTENDED;
23762399
get_ea_mode_op(info, op0, info->ir, 12);
2400+
if (op0->type == M68K_OP_IMM)
2401+
op0->type = M68K_OP_FP_EXTENDED;
23772402
break;
23782403

23792404
case 0x03: // packed decimal
23802405
ext->op_size.type = M68K_SIZE_TYPE_FPU_PACKED;
23812406
ext->op_size.fpu_size = M68K_FPU_SIZE_PACKED;
23822407
get_ea_mode_op(info, op0, info->ir, 12);
2408+
if (op0->type == M68K_OP_IMM)
2409+
op0->type = M68K_OP_FP_EXTENDED;
23832410
break;
23842411

23852412
default:

arch/M68K/M68KInstPrinter.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,13 @@ static void printAddressingMode(SStream *O, unsigned int pc,
224224
SStream_concat(O, "$%" PRIx64 ".l", op->imm);
225225
break;
226226
case M68K_AM_IMMEDIATE:
227+
if (op->type == M68K_OP_FP_EXTENDED) {
228+
int i;
229+
SStream_concat0(O, "#$");
230+
for (i = 0; i < 12; i++)
231+
SStream_concat(O, "%02x", op->fp_ext.ximm[i]);
232+
break;
233+
}
227234
if (inst->op_size.type == M68K_SIZE_TYPE_FPU) {
228235
#if defined(_KERNEL_MODE)
229236
// Issue #681: Windows kernel does not support formatting float point

include/capstone/m68k.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ typedef enum m68k_op_type {
126126
CS_OP_SPECIAL +
127127
3, ///< Register pair in the same op (upper 4 bits for first reg, lower for second)
128128
M68K_OP_BR_DISP = CS_OP_SPECIAL + 4, ///< Branch displacement
129+
M68K_OP_FP_EXTENDED =
130+
CS_OP_SPECIAL + 5, ///< extended precision / packed decimal Floating-Point operand (ximm)
129131
M68K_OP_MEM = CS_OP_MEM, ///< = CS_OP_MEM (Memory operand).
130132
} m68k_op_type;
131133

@@ -167,6 +169,11 @@ typedef struct cs_m68k_op_reg_pair {
167169
m68k_reg reg_1;
168170
} cs_m68k_op_reg_pair;
169171

172+
/// 96-bit extended-precision / packed-decimal FPU immediate.
173+
typedef struct m68k_op_fp_ext {
174+
uint8_t ximm[12]; ///< Raw big-endian M68K byte order.
175+
} m68k_op_fp_ext;
176+
170177
/// Instruction operand
171178
typedef struct cs_m68k_op {
172179
union {
@@ -187,6 +194,8 @@ typedef struct cs_m68k_op {
187194
///< For branch displacement: target = instruction_addr + disp_offset + disp
188195
///< Typically 2 (displacement follows opword), but 4 when an extension
189196
///< word sits between the opword and the displacement.
197+
m68k_op_fp_ext fp_ext; ///< 96-bit extended-precision / packed-decimal immediate.
198+
///< Valid when type is M68K_OP_FP_EXTENDED.
190199
} cs_m68k_op;
191200

192201
/// Operation size of the CPU instructions

suite/cstest/include/test_detail_m68k.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ typedef struct {
8080
double dimm;
8181
float simm;
8282

83+
char *ximm; ///< hex string for 96-bit extended/packed immediate
84+
8385
TestDetailM68KOpMem *mem;
8486
} TestDetailM68KOp;
8587

@@ -112,6 +114,8 @@ static const cyaml_schema_field_t test_detail_m68k_op_mapping_schema[] = {
112114
register_bits),
113115
CYAML_FIELD_FLOAT("dimm", CYAML_FLAG_OPTIONAL, TestDetailM68KOp, dimm),
114116
CYAML_FIELD_FLOAT("simm", CYAML_FLAG_OPTIONAL, TestDetailM68KOp, simm),
117+
CYAML_FIELD_STRING_PTR("ximm", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
118+
TestDetailM68KOp, ximm, 0, CYAML_UNLIMITED),
115119
CYAML_FIELD_MAPPING_PTR("mem", CYAML_FLAG_OPTIONAL, TestDetailM68KOp,
116120
mem, test_detail_m68k_op_mem_mapping_schema),
117121
CYAML_FIELD_END

suite/cstest/include/test_mapping.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,7 @@ static const cs_enum_id_map cs_enum_map[] = {
902902
{ .str = "M68K_FPU_SIZE_DOUBLE", .val = M68K_FPU_SIZE_DOUBLE },
903903
{ .str = "M68K_FPU_SIZE_EXTENDED", .val = M68K_FPU_SIZE_EXTENDED },
904904
{ .str = "M68K_FPU_SIZE_NONE", .val = M68K_FPU_SIZE_NONE },
905+
{ .str = "M68K_FPU_SIZE_PACKED", .val = M68K_FPU_SIZE_PACKED },
905906
{ .str = "M68K_FPU_SIZE_SINGLE", .val = M68K_FPU_SIZE_SINGLE },
906907
{ .str = "M68K_GRP_BRANCH_RELATIVE", .val = M68K_GRP_BRANCH_RELATIVE },
907908
{ .str = "M68K_GRP_IRET", .val = M68K_GRP_IRET },
@@ -915,6 +916,7 @@ static const cs_enum_id_map cs_enum_map[] = {
915916
{ .str = "M68K_OP_BR_DISP_SIZE_WORD",
916917
.val = M68K_OP_BR_DISP_SIZE_WORD },
917918
{ .str = "M68K_OP_FP_DOUBLE", .val = M68K_OP_FP_DOUBLE },
919+
{ .str = "M68K_OP_FP_EXTENDED", .val = M68K_OP_FP_EXTENDED },
918920
{ .str = "M68K_OP_FP_SINGLE", .val = M68K_OP_FP_SINGLE },
919921
{ .str = "M68K_OP_IMM", .val = M68K_OP_IMM },
920922
{ .str = "M68K_OP_MEM", .val = M68K_OP_MEM },

suite/cstest/src/test_detail_m68k.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ TestDetailM68KOp *test_detail_m68k_op_clone(TestDetailM68KOp *op)
109109
clone->imm = op->imm;
110110
clone->dimm = op->dimm;
111111
clone->simm = op->simm;
112+
clone->ximm = op->ximm ? strdup(op->ximm) : NULL;
112113
clone->br_disp = op->br_disp;
113114
clone->br_disp_size = op->br_disp_size;
114115
clone->disp_offset = op->disp_offset;
@@ -128,6 +129,7 @@ void test_detail_m68k_op_free(TestDetailM68KOp *op)
128129
cs_mem_free(op->reg_pair_0);
129130
cs_mem_free(op->reg_pair_1);
130131
cs_mem_free(op->address_mode);
132+
cs_mem_free(op->ximm);
131133
test_detail_m68k_op_mem_free(op->mem);
132134
cs_mem_free(op);
133135
}
@@ -176,6 +178,21 @@ bool test_expected_m68k(csh *handle, cs_m68k *actual, TestDetailM68K *expected)
176178
case M68K_OP_FP_DOUBLE:
177179
compare_fp_ret(op->dimm, eop->dimm, false);
178180
break;
181+
case M68K_OP_FP_EXTENDED:
182+
if (eop->ximm) {
183+
char actual_hex[25]; // 12*2 chars + \0
184+
for (int j = 0; j < 12; j++)
185+
snprintf(actual_hex + j * 2, 3,
186+
"%02x", op->fp_ext.ximm[j]);
187+
actual_hex[24] = '\0';
188+
if (strcmp(actual_hex, eop->ximm) != 0) {
189+
fprintf(stderr,
190+
"ximm mismatch: got %s, expected %s\n",
191+
actual_hex, eop->ximm);
192+
return false;
193+
}
194+
}
195+
break;
179196
case M68K_OP_REG_BITS:
180197
compare_uint32_ret(op->register_bits,
181198
eop->register_bits, false);

tests/details/m68k.yaml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,3 +1386,64 @@ test_cases:
13861386
-
13871387
type: M68K_OP_REG
13881388
reg: fp1
1389+
-
1390+
input:
1391+
bytes: [ 0xf2, 0x3c, 0x48, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x3c, 0x48, 0x80, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
1392+
arch: "m68k"
1393+
options: [ CS_OPT_DETAIL, CS_MODE_BIG_ENDIAN, CS_MODE_M68K_040 ]
1394+
address: 0x3000
1395+
expected:
1396+
insns:
1397+
-
1398+
asm_text: "fmove.x #$3fff00008000000000000000, fp0"
1399+
details:
1400+
regs_write: [ fp0 ]
1401+
m68k:
1402+
op_size_type: M68K_SIZE_TYPE_FPU
1403+
op_size_fpu: M68K_FPU_SIZE_EXTENDED
1404+
operands:
1405+
-
1406+
type: M68K_OP_FP_EXTENDED
1407+
address_mode: M68K_AM_IMMEDIATE
1408+
ximm: "3fff00008000000000000000"
1409+
-
1410+
type: M68K_OP_REG
1411+
reg: fp0
1412+
-
1413+
asm_text: "fmove.x #$c0000000a000000000000000, fp1"
1414+
details:
1415+
regs_write: [ fp1 ]
1416+
m68k:
1417+
op_size_type: M68K_SIZE_TYPE_FPU
1418+
op_size_fpu: M68K_FPU_SIZE_EXTENDED
1419+
operands:
1420+
-
1421+
type: M68K_OP_FP_EXTENDED
1422+
address_mode: M68K_AM_IMMEDIATE
1423+
ximm: "c0000000a000000000000000"
1424+
-
1425+
type: M68K_OP_REG
1426+
reg: fp1
1427+
-
1428+
input:
1429+
bytes: [ 0xf2, 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
1430+
arch: "m68k"
1431+
options: [ CS_OPT_DETAIL, CS_MODE_BIG_ENDIAN, CS_MODE_M68K_040 ]
1432+
address: 0x4000
1433+
expected:
1434+
insns:
1435+
-
1436+
asm_text: "fmove.p #$000100001000000000000000, fp0"
1437+
details:
1438+
regs_write: [ fp0 ]
1439+
m68k:
1440+
op_size_type: M68K_SIZE_TYPE_FPU_PACKED
1441+
op_size_fpu: M68K_FPU_SIZE_PACKED
1442+
operands:
1443+
-
1444+
type: M68K_OP_FP_EXTENDED
1445+
address_mode: M68K_AM_IMMEDIATE
1446+
ximm: "000100001000000000000000"
1447+
-
1448+
type: M68K_OP_REG
1449+
reg: fp0

0 commit comments

Comments
 (0)