Skip to content

Commit

Permalink
Fix tricore UB (capstone-engine#2204)
Browse files Browse the repository at this point in the history
  • Loading branch information
imbillow authored Nov 29, 2023
1 parent d432c35 commit ce0b1b6
Show file tree
Hide file tree
Showing 14 changed files with 135 additions and 103 deletions.
189 changes: 108 additions & 81 deletions arch/TriCore/TriCoreInstPrinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,11 @@
#ifdef CAPSTONE_HAS_TRICORE

#include <platform.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../../MCInst.h"
#include "../../MCRegisterInfo.h"
#include "../../Mapping.h"
#include "../../MathExtras.h"
#include "../../SStream.h"
#include "../../utils.h"

#include "TriCoreMapping.h"
#include "TriCoreLinkage.h"

Expand All @@ -44,9 +39,41 @@ static void printOperand(MCInst *MI, int OpNum, SStream *O);

#include "TriCoreGenRegisterInfo.inc"

static bool fill_mem(MCInst *MI, unsigned int reg, int32_t disp);
static uint32_t to_u32(int64_t x)
{
if (x > UINT32_MAX || x < -(int64_t)(UINT32_MAX)) {
abort();
}
return (uint32_t)x;
}

static inline unsigned int get_msb(uint64_t value)
{
unsigned int msb = 0;
while (value > 0) {
value >>= 1; // Shift bits to the right
msb++; // Increment the position of the MSB
}
return msb;
}

static inline int64_t sign_ext64(int64_t imm, unsigned n)
{
n = get_msb(imm) > n ? get_msb(imm) : n;
int64_t mask = 1 << (n - 1);
return (imm ^ mask) - mask;
}

static inline int32_t sign_ext32(int32_t imm, unsigned n)
{
n = get_msb(imm) > n ? get_msb(imm) : n;
int32_t mask = 1 << (n - 1);
return (imm ^ mask) - mask;
}

static bool fill_mem(MCInst *MI, unsigned int reg, int64_t disp);

static inline void set_mem(cs_tricore_op *op, uint8_t base, int32_t disp)
static inline void set_mem(cs_tricore_op *op, uint8_t base, int64_t disp)
{
op->type |= TRICORE_OP_MEM;
op->mem.base = base;
Expand All @@ -63,7 +90,7 @@ static inline void fill_reg(MCInst *MI, uint32_t reg)
TriCore_inc_op_count(MI);
}

static inline void fill_imm(MCInst *MI, int32_t imm)
static inline void fill_imm(MCInst *MI, int64_t imm)
{
if (!detail_is_set(MI))
return;
Expand All @@ -80,7 +107,7 @@ static inline void fill_imm(MCInst *MI, int32_t imm)
tricore->op_count++;
}

static bool fill_mem(MCInst *MI, unsigned int reg, int32_t disp)
static bool fill_mem(MCInst *MI, unsigned int reg, int64_t disp)
{
if (!detail_is_set(MI))
return false;
Expand Down Expand Up @@ -166,42 +193,24 @@ static void printOperand(MCInst *MI, int OpNum, SStream *O)
fill_reg(MI, reg);
} else if (MCOperand_isImm(Op)) {
int64_t Imm = MCOperand_getImm(Op);
printInt64Bang(O, Imm);
fill_imm(MI, (int32_t)Imm);
printUInt32Bang(O, to_u32(Imm));
fill_imm(MI, Imm);
}
}

static inline unsigned int get_msb(unsigned int value)
{
unsigned int msb = 0;
while (value > 0) {
value >>= 1; // Shift bits to the right
msb++; // Increment the position of the MSB
}
return msb;
}

static inline int32_t sign_ext_n(int32_t imm, unsigned n)
{
n = get_msb(imm) > n ? get_msb(imm) : n;
int32_t mask = 1 << (n - 1);
int32_t sign_extended = (imm ^ mask) - mask;
return sign_extended;
}

static void print_sign_ext(MCInst *MI, int OpNum, SStream *O, unsigned n)
{
MCOperand *MO = MCInst_getOperand(MI, OpNum);
if (MCOperand_isImm(MO)) {
int32_t imm = (int32_t)MCOperand_getImm(MO);
imm = sign_ext_n(imm, n);
printInt32Bang(O, imm);
fill_imm(MI, imm);
int64_t imm = MCOperand_getImm(MO);
int32_t res = sign_ext32(to_u32(imm), n);
printInt32Bang(O, res);
fill_imm(MI, res);
} else
printOperand(MI, OpNum, O);
}

static void off4_fixup(MCInst *MI, uint64_t *off4)
static void off4_fixup(MCInst *MI, int64_t *off4)
{
switch (MCInst_getOpcode(MI)) {
case TRICORE_LD_A_slro:
Expand All @@ -212,27 +221,27 @@ static void off4_fixup(MCInst *MI, uint64_t *off4)
case TRICORE_ST_A_ssro:
case TRICORE_ST_W_sro:
case TRICORE_ST_W_ssro: {
*off4 *= 4;
*off4 = *off4 * 4;
break;
}
case TRICORE_LD_H_sro:
case TRICORE_LD_H_slro:
case TRICORE_ST_H_sro:
case TRICORE_ST_H_ssro: {
*off4 *= 2;
*off4 = *off4 * 2;
break;
}
}
}

static void const8_fixup(MCInst *MI, uint64_t *const8)
static void const8_fixup(MCInst *MI, int64_t *const8)
{
switch (MCInst_getOpcode(MI)) {
case TRICORE_LD_A_sc:
case TRICORE_ST_A_sc:
case TRICORE_ST_W_sc:
case TRICORE_LD_W_sc: {
*const8 *= 4;
*const8 = *const8 * 4;
break;
}
}
Expand All @@ -242,9 +251,9 @@ static void print_zero_ext(MCInst *MI, int OpNum, SStream *O, unsigned n)
{
MCOperand *MO = MCInst_getOperand(MI, OpNum);
if (MCOperand_isImm(MO)) {
uint64_t imm = MCOperand_getImm(MO);
int64_t imm = MCOperand_getImm(MO);
for (unsigned i = n + 1; i < 32; ++i) {
imm &= ~(1 << i);
imm &= ~(1LL << i);
}
if (n == 4) {
off4_fixup(MI, &imm);
Expand All @@ -253,7 +262,7 @@ static void print_zero_ext(MCInst *MI, int OpNum, SStream *O, unsigned n)
const8_fixup(MI, &imm);
}

printInt64Bang(O, imm);
printUInt32Bang(O, to_u32(imm));
fill_imm(MI, imm);
} else
printOperand(MI, OpNum, O);
Expand All @@ -263,41 +272,47 @@ static void printOff18Imm(MCInst *MI, int OpNum, SStream *O)
{
MCOperand *MO = MCInst_getOperand(MI, OpNum);
if (MCOperand_isImm(MO)) {
uint32_t imm = (uint32_t)MCOperand_getImm(MO);
imm = ((imm & 0x3C000) << 14) | (imm & 0x3fff);
printUInt32Bang(O, imm);
fill_imm(MI, (int32_t)imm);
int64_t imm = MCOperand_getImm(MO);
imm = ((to_u32(imm) & 0x3C000) << 14) | (to_u32(imm) & 0x3fff);
printUInt32Bang(O, to_u32(imm));
fill_imm(MI, imm);
} else
printOperand(MI, OpNum, O);
}

// PC + sext(2 * disp)
#define DISP1(N) ((int64_t)(MI->address) + sign_ext64(disp * 2, N))
// PC + sext(disp) * 2
#define DISP2(N) ((int64_t)(MI->address) + sign_ext64(disp, N) * 2)

static void printDisp24Imm(MCInst *MI, int OpNum, SStream *O)
{
MCOperand *MO = MCInst_getOperand(MI, OpNum);
if (MCOperand_isImm(MO)) {
uint32_t disp = MCOperand_getImm(MO);
int64_t disp = MCOperand_getImm(MO);
int64_t res = 0;
switch (MCInst_getOpcode(MI)) {
case TRICORE_CALL_b:
case TRICORE_FCALL_b: {
disp = (int32_t)MI->address + sign_ext_n(disp * 2, 24);
res = DISP1(24);
break;
}
case TRICORE_CALLA_b:
case TRICORE_FCALLA_b:
case TRICORE_JA_b:
case TRICORE_JLA_b:
// = {disp24[23:20], 7’b0000000, disp24[19:0], 1’b0};
disp = ((disp & 0xf00000) << 28) |
((disp & 0xfffff) << 1);
res = ((to_u32(disp) & 0xf00000) << 28) |
((to_u32(disp) & 0xfffff) << 1);
break;
case TRICORE_J_b:
case TRICORE_JL_b:
disp = (int32_t)MI->address + sign_ext_n(disp, 24) * 2;
res = DISP2(24);
break;
}

printUInt32Bang(O, disp);
fill_imm(MI, disp);
printUInt32Bang(O, to_u32(res));
fill_imm(MI, res);
} else
printOperand(MI, OpNum, O);
}
Expand All @@ -306,8 +321,13 @@ static void printDisp15Imm(MCInst *MI, int OpNum, SStream *O)
{
MCOperand *MO = MCInst_getOperand(MI, OpNum);
if (MCOperand_isImm(MO)) {
uint32_t disp = MCOperand_getImm(MO);
int64_t disp = MCOperand_getImm(MO);
int64_t res = 0;
switch (MCInst_getOpcode(MI)) {
case TRICORE_LOOP_brr:
case TRICORE_LOOPU_brr:
res = DISP1(15);
break;
case TRICORE_JEQ_brc:
case TRICORE_JEQ_brr:
case TRICORE_JEQ_A_brr:
Expand All @@ -330,19 +350,15 @@ static void printDisp15Imm(MCInst *MI, int OpNum, SStream *O)
case TRICORE_JNZ_T_brn:
case TRICORE_JZ_A_brr:
case TRICORE_JZ_T_brn:
disp = (int32_t)MI->address + sign_ext_n(disp, 15) * 2;
break;
case TRICORE_LOOP_brr:
case TRICORE_LOOPU_brr:
disp = (int32_t)MI->address + sign_ext_n(disp * 2, 15);
res = DISP2(15);
break;
default:
// handle other cases, if any
break;
}

printUInt32Bang(O, disp);
fill_imm(MI, disp);
printUInt32Bang(O, to_u32(res));
fill_imm(MI, res);
} else
printOperand(MI, OpNum, O);
}
Expand All @@ -351,23 +367,24 @@ static void printDisp8Imm(MCInst *MI, int OpNum, SStream *O)
{
MCOperand *MO = MCInst_getOperand(MI, OpNum);
if (MCOperand_isImm(MO)) {
uint32_t disp = MCOperand_getImm(MO);
int64_t disp = MCOperand_getImm(MO);
int64_t res = 0;
switch (MCInst_getOpcode(MI)) {
case TRICORE_CALL_sb:
disp = (int32_t)MI->address + sign_ext_n(2 * disp, 8);
disp = DISP1(8);
break;
case TRICORE_J_sb:
case TRICORE_JNZ_sb:
case TRICORE_JZ_sb:
disp = (int32_t)MI->address + sign_ext_n(disp, 8) * 2;
res = DISP2(8);
break;
default:
// handle other cases, if any
break;
}

printUInt32Bang(O, disp);
fill_imm(MI, disp);
printUInt32Bang(O, to_u32(res));
fill_imm(MI, res);
} else
printOperand(MI, OpNum, O);
}
Expand All @@ -376,7 +393,8 @@ static void printDisp4Imm(MCInst *MI, int OpNum, SStream *O)
{
MCOperand *MO = MCInst_getOperand(MI, OpNum);
if (MCOperand_isImm(MO)) {
uint32_t disp = MCOperand_getImm(MO);
int64_t disp = MCOperand_getImm(MO);
int64_t res = 0;
switch (MCInst_getOpcode(MI)) {
case TRICORE_JEQ_sbc1:
case TRICORE_JEQ_sbr1:
Expand All @@ -392,27 +410,29 @@ static void printDisp4Imm(MCInst *MI, int OpNum, SStream *O)
case TRICORE_JZ_sbr:
case TRICORE_JZ_A_sbr:
case TRICORE_JZ_T_sbrn:
disp = (int32_t)MI->address + disp * 2;
// PC + zero_ext(disp4) * 2;
res = (int64_t)(MI->address) + disp * 2;
break;
case TRICORE_JEQ_sbc2:
case TRICORE_JEQ_sbr2:
case TRICORE_JNE_sbc2:
case TRICORE_JNE_sbr2:
disp = (int32_t)MI->address + (disp + 16) * 2;
// PC + zero_ext(disp4 + 16) * 2;
res = (int64_t)(MI->address) + ((disp + 16) * 2);
break;
case TRICORE_LOOP_sbr:
// {27b’111111111111111111111111111, disp4, 0};
disp = (int32_t)MI->address +
((0b111111111111111111111111111 << 5) |
(disp << 1));
// PC + {27b’111111111111111111111111111, disp4, 0};
res = (int64_t)(MI->address) +
((0b111111111111111111111111111LL << 5) |
(to_u32(disp) << 1));
break;
default:
// handle other cases, if any
break;
}

printUInt32Bang(O, disp);
fill_imm(MI, disp);
printUInt32Bang(O, to_u32(res));
fill_imm(MI, res);
} else
printOperand(MI, OpNum, O);
}
Expand All @@ -432,14 +452,21 @@ static void printDisp4Imm(MCInst *MI, int OpNum, SStream *O)
// clang-format off

printSExtImm_(16)

printSExtImm_(10)

printSExtImm_(9)

printSExtImm_(4)

printZExtImm_(16)

printZExtImm_(9)

printZExtImm_(8)

printZExtImm_(4)

printZExtImm_(2);

// clang-format on
Expand All @@ -448,12 +475,12 @@ static void printOExtImm_4(MCInst *MI, int OpNum, SStream *O)
{
MCOperand *MO = MCInst_getOperand(MI, OpNum);
if (MCOperand_isImm(MO)) {
uint32_t imm = MCOperand_getImm(MO);
// {27b’111111111111111111111111111, disp4, 0};
imm = 0b11111111111111111111111111100000 | (imm << 1);

printInt32Bang(O, imm);
fill_imm(MI, imm);
int64_t disp = MCOperand_getImm(MO);
int64_t res = (int64_t)(MI->address) +
((0b111111111111111111111111111 << 5) |
(to_u32(disp) << 1));
printUInt32Bang(O, to_u32(res));
fill_imm(MI, res);
} else
printOperand(MI, OpNum, O);
}
Expand Down
Loading

0 comments on commit ce0b1b6

Please sign in to comment.