diff --git a/arch/Mips/MipsDisassembler.c b/arch/Mips/MipsDisassembler.c index 7196de3db..8267542e7 100644 --- a/arch/Mips/MipsDisassembler.c +++ b/arch/Mips/MipsDisassembler.c @@ -1406,14 +1406,14 @@ static DecodeStatus readInstruction32(const uint8_t *Bytes, size_t BytesLen, if (IsBigEndian) { // Encoded as a big-endian 32-bit word in the stream. *Insn = (Bytes[3] << 0) | (Bytes[2] << 8) | (Bytes[1] << 16) | - (Bytes[0] << 24); + ((unsigned)Bytes[0] << 24); } else { if (IsMicroMips) { *Insn = (Bytes[2] << 0) | (Bytes[3] << 8) | - (Bytes[0] << 16) | (Bytes[1] << 24); + (Bytes[0] << 16) | ((unsigned)Bytes[1] << 24); } else { *Insn = (Bytes[0] << 0) | (Bytes[1] << 8) | - (Bytes[2] << 16) | (Bytes[3] << 24); + (Bytes[2] << 16) | ((unsigned)Bytes[3] << 24); } } diff --git a/arch/Mips/MipsInstPrinter.c b/arch/Mips/MipsInstPrinter.c index eda806294..514a3df30 100644 --- a/arch/Mips/MipsInstPrinter.c +++ b/arch/Mips/MipsInstPrinter.c @@ -204,7 +204,10 @@ static void printJumpOperand(MCInst *MI, unsigned OpNo, SStream *O) if (MCOperand_isReg(Op)) return printRegName(MI, O, MCOperand_getReg(Op)); - printInt64(O, MCOperand_getImm(Op)); + // only the upper bits are needed. + uint64_t Base = MI->address & ~0x0fffffffull; + uint64_t Target = MCOperand_getImm(Op); + printInt64(O, Base | Target); } static void printBranchOperand(MCInst *MI, uint64_t Address, unsigned OpNo, SStream *O) diff --git a/arch/Mips/MipsMapping.c b/arch/Mips/MipsMapping.c index 3f1ec49ce..01d511177 100644 --- a/arch/Mips/MipsMapping.c +++ b/arch/Mips/MipsMapping.c @@ -296,12 +296,26 @@ static void Mips_set_detail_op_operand(MCInst *MI, unsigned OpNum) printf("Operand type %d not handled!\n", op_type); } +static void Mips_set_detail_op_jump(MCInst *MI, unsigned OpNum) +{ + cs_op_type op_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM; + if (op_type == CS_OP_IMM) { + uint64_t Base = MI->address & ~0x0fffffffull; + uint64_t Target = Base | (uint64_t)MCInst_getOpVal(MI, OpNum); + Mips_set_detail_op_uimm(MI, OpNum, Target); + } else if (op_type == CS_OP_REG) { + Mips_set_detail_op_reg(MI, OpNum, MCInst_getOpVal(MI, OpNum), + false); + } else + printf("Operand type %d not handled!\n", op_type); +} + static void Mips_set_detail_op_branch(MCInst *MI, unsigned OpNum) { cs_op_type op_type = map_get_op_type(MI, OpNum) & ~CS_OP_MEM; if (op_type == CS_OP_IMM) { - uint64_t Target = (uint64_t)MCInst_getOpVal(MI, OpNum); - Mips_set_detail_op_uimm(MI, OpNum, Target + MI->address); + uint64_t Target = MI->address + MCInst_getOpVal(MI, OpNum); + Mips_set_detail_op_uimm(MI, OpNum, Target); } else if (op_type == CS_OP_REG) { Mips_set_detail_op_reg(MI, OpNum, MCInst_getOpVal(MI, OpNum), false); @@ -374,9 +388,9 @@ void Mips_add_cs_detail(MCInst *MI, mips_op_group op_group, va_list args) // this is only used by nanoMips. return Mips_set_detail_op_mem_nanomips(MI, OpNum); case Mips_OP_GROUP_BranchOperand: - /* fall-thru */ - case Mips_OP_GROUP_JumpOperand: return Mips_set_detail_op_branch(MI, OpNum); + case Mips_OP_GROUP_JumpOperand: + return Mips_set_detail_op_jump(MI, OpNum); case Mips_OP_GROUP_Operand: return Mips_set_detail_op_operand(MI, OpNum); case Mips_OP_GROUP_UImm_1_0: diff --git a/tests/issues/issues.yaml b/tests/issues/issues.yaml index 4cddcb054..26d8f1b20 100644 --- a/tests/issues/issues.yaml +++ b/tests/issues/issues.yaml @@ -4958,8 +4958,102 @@ test_cases: insns: - asm_text: "jalrc $t9" - - - input: + - input: + name: "Mips32 jumps with base offset" + bytes: [ 0x40, 0x04, 0x04, 0x08 ] + arch: "CS_ARCH_MIPS" + options: [ CS_MODE_LITTLE_ENDIAN, CS_MODE_MIPS5, CS_OPT_DETAIL ] + address: 0x8060b53c + expected: + insns: + # 8060b53c: 40040408 j 0x80101100 + - asm_text: "j 0x80101100" + details: + mips: + operands: + - type: MIPS_OP_IMM + imm: 0x80101100 + + - input: + name: "Mips32 jumps with base offset (lower limit)" + bytes: [ 0x40, 0x04, 0x04, 0x08 ] + arch: "CS_ARCH_MIPS" + options: [ CS_MODE_LITTLE_ENDIAN, CS_MODE_MIPS5, CS_OPT_DETAIL ] + address: 0xFF000000 + expected: + insns: + # ff000000: 40040408 j 0xf0101100 + - asm_text: "j 0xf0101100" + details: + mips: + operands: + - type: MIPS_OP_IMM + imm: 0xf0101100 + + - input: + name: "Mips64 jumps with base offset" + bytes: [ 0x40, 0x04, 0x04, 0x08 ] + arch: "CS_ARCH_MIPS" + options: [ CS_MODE_LITTLE_ENDIAN, CS_MODE_MIPS64R5, CS_OPT_DETAIL ] + address: 0x8060b53c + expected: + insns: + # 8060b53c: 40040408 j 0x80101100 + - asm_text: "j 0x80101100" + details: + mips: + operands: + - type: MIPS_OP_IMM + imm: 0x80101100 + + - input: + name: "Mips64 jumps with base offset (lower limit)" + bytes: [ 0x40, 0x04, 0x04, 0x08 ] + arch: "CS_ARCH_MIPS" + options: [ CS_MODE_LITTLE_ENDIAN, CS_MODE_MIPS64R5, CS_OPT_DETAIL ] + address: 0xFF000000 + expected: + insns: + # ff000000: 40040408 j 0xf0101100 + - asm_text: "j 0xf0101100" + details: + mips: + operands: + - type: MIPS_OP_IMM + imm: 0xf0101100 + + - input: + name: "micromips beqz16" + bytes: [ 0x8d, 0x7f ] + arch: "CS_ARCH_MIPS" + options: [ CS_MODE_BIG_ENDIAN, CS_MODE_MICRO, CS_MODE_MIPS32R3, CS_OPT_DETAIL ] + address: 0x80600000 + expected: + insns: + - asm_text: "beqz16 $v0, 0x805ffffe" + details: + mips: + operands: + - type: MIPS_OP_REG + reg: v0 + - type: MIPS_OP_IMM + imm: 0x805ffffe + + - input: + name: "micromips b16" + bytes: [ 0xcf, 0xff ] + arch: "CS_ARCH_MIPS" + options: [ CS_MODE_BIG_ENDIAN, CS_MODE_MICRO, CS_MODE_MIPS32R3, CS_OPT_DETAIL ] + address: 0x80600000 + expected: + insns: + - asm_text: "b16 0x805ffffe" + details: + mips: + operands: + - type: MIPS_OP_IMM + imm: 0x805ffffe + - input: name: "issue 2471 -- max operands overflow" bytes: [ 0xff, 0x00, 0x08, 0xc0 ] arch: "CS_ARCH_AARCH64"