Skip to content

Commit e7ad2fd

Browse files
committed
Further fix MIPS delay slot
1 parent 0f45f15 commit e7ad2fd

File tree

5 files changed

+59
-28
lines changed

5 files changed

+59
-28
lines changed

include/uc_priv.h

+8
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,14 @@ static inline uc_err break_translation_loop(uc_engine *uc)
534534
return UC_ERR_OK;
535535
}
536536

537+
static inline void revert_uc_emu_stop(uc_engine *uc)
538+
{
539+
uc->stop_request = 0;
540+
uc->cpu->exit_request = 0;
541+
uc->cpu->tcg_exit_req = 0;
542+
uc->cpu->icount_decr_ptr->u16.high = 0;
543+
}
544+
537545
#ifdef UNICORN_TRACER
538546
#define UC_TRACE_START(loc) trace_start(get_tracer(), loc)
539547
#define UC_TRACE_END(loc, fmt, ...) \

qemu/include/tcg/tcg-op.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, int32_t t
4747
};
4848

4949
const int hook_type = type & UC_HOOK_IDX_MASK;
50-
if (puc->hooks_count[hook_type] == 1) {
50+
if (puc->hooks_count[hook_type] == 1 && !(type & UC_HOOK_FLAG_NO_STOP)) {
5151
cur = puc->hook[hook_type].head;
5252

5353
while (cur) {

qemu/target/mips/translate.c

+34-23
Original file line numberDiff line numberDiff line change
@@ -30924,7 +30924,7 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
3092430924
DisasContext *ctx = container_of(dcbase, DisasContext, base);
3092530925
struct uc_struct *uc = cs->uc;
3092630926
TCGContext *tcg_ctx = uc->tcg_ctx;
30927-
TCGOp *tcg_op, *prev_op = NULL;
30927+
TCGOp *tcg_op, *prev_op = NULL, *slot_op = NULL;
3092830928
int insn_bytes;
3092930929
int is_slot;
3093030930
bool hook_insn = false;
@@ -30949,11 +30949,17 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
3094930949
prev_op = tcg_last_op(tcg_ctx);
3095030950
hook_insn = true;
3095130951
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, uc, ctx->base.pc_next);
30952-
// Don't let unicorn stop at the branch delay slot.
30953-
if (!is_slot) {
30954-
// the callback might want to stop emulation immediately
30955-
check_exit_request(tcg_ctx);
30956-
}
30952+
30953+
// TODO: Memory hooks, maybe use icount_decr.low?
30954+
TCGLabel *skip_label = gen_new_label(tcg_ctx);
30955+
TCGv_i32 dyn_is_slot = tcg_const_i32(tcg_ctx, 0);
30956+
slot_op = tcg_last_op(tcg_ctx);
30957+
// if slot, skip exit_request
30958+
// tcg is smart enough to optimize this branch away
30959+
tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_GT, dyn_is_slot, 0, skip_label);
30960+
tcg_temp_free_i32(tcg_ctx, dyn_is_slot);
30961+
check_exit_request(tcg_ctx);
30962+
gen_set_label(tcg_ctx, skip_label);
3095730963
}
3095830964

3095930965
if (ctx->insn_flags & ISA_NANOMIPS32) {
@@ -30975,23 +30981,6 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
3097530981
return;
3097630982
}
3097730983

30978-
if (hook_insn) {
30979-
// Unicorn: patch the callback to have the proper instruction size.
30980-
if (prev_op) {
30981-
// As explained further up in the function where prev_op is
30982-
// assigned, we move forward in the tail queue, so we're modifying the
30983-
// move instruction generated by gen_uc_tracecode() that contains
30984-
// the instruction size to assign the proper size (replacing 0xF1F1F1F1).
30985-
tcg_op = QTAILQ_NEXT(prev_op, link);
30986-
} else {
30987-
// this instruction is the first emulated code ever,
30988-
// so the instruction operand is the first operand
30989-
tcg_op = QTAILQ_FIRST(&tcg_ctx->ops);
30990-
}
30991-
30992-
tcg_op->args[1] = insn_bytes;
30993-
}
30994-
3099530984
if (ctx->hflags & MIPS_HFLAG_BMASK) {
3099630985
if (!(ctx->hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32 |
3099730986
MIPS_HFLAG_FBNSLOT))) {
@@ -31010,6 +30999,28 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
3101030999
is_slot = 1;
3101131000
}
3101231001
}
31002+
31003+
if (hook_insn) {
31004+
// Unicorn: patch the callback to have the proper instruction size.
31005+
if (prev_op) {
31006+
// As explained further up in the function where prev_op is
31007+
// assigned, we move forward in the tail queue, so we're modifying the
31008+
// move instruction generated by gen_uc_tracecode() that contains
31009+
// the instruction size to assign the proper size (replacing 0xF1F1F1F1).
31010+
tcg_op = QTAILQ_NEXT(prev_op, link);
31011+
} else {
31012+
// this instruction is the first emulated code ever,
31013+
// so the instruction operand is the first operand
31014+
tcg_op = QTAILQ_FIRST(&tcg_ctx->ops);
31015+
}
31016+
31017+
tcg_op->args[1] = insn_bytes;
31018+
}
31019+
31020+
if (slot_op) {
31021+
slot_op->args[1] = is_slot;
31022+
}
31023+
3101331024
if (is_slot) {
3101431025
gen_branch(ctx, insn_bytes);
3101531026
}

tests/unit/test_mips.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,24 @@ static void test_mips_stop_at_branch(void)
5353
{
5454
uc_engine *uc;
5555
char code[] =
56-
"\x02\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"; // j 0x8; nop;
56+
"\x02\x00\x00\x08\x21\x10\x62\x00"; // j 0x8; addu $v0, $v1, $v0;
5757
int r_pc = 0x0;
58+
uint32_t v1 = 5;
5859

5960
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_MIPS32 | UC_MODE_LITTLE_ENDIAN,
6061
code, sizeof(code) - 1);
6162

63+
OK(uc_reg_write(uc, UC_MIPS_REG_V1, &v1));
6264
// Execute one instruction with branch delay slot.
6365
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 1));
6466

6567
OK(uc_reg_read(uc, UC_MIPS_REG_PC, &r_pc));
68+
OK(uc_reg_read(uc, UC_MIPS_REG_V0, &v1));
6669

6770
// Even if we just execute one instruction, the instruction in the
6871
// delay slot would also be executed.
6972
TEST_CHECK(r_pc == code_start + 0x8);
73+
TEST_CHECK(v1 == 0x5);
7074

7175
OK(uc_close(uc));
7276
}

uc.c

+11-3
Original file line numberDiff line numberDiff line change
@@ -1978,8 +1978,12 @@ void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle,
19781978
index &
19791979
UC_HOOK_FLAG_MASK; // The index here may contain additional flags. See
19801980
// the comments of uc_hook_idx for details.
1981-
1981+
// bool not_allow_stop = (size & UC_HOOK_FLAG_NO_STOP) || (hook_flags & UC_HOOK_FLAG_NO_STOP);
1982+
bool not_allow_stop = hook_flags & UC_HOOK_FLAG_NO_STOP;
1983+
19821984
index = index & UC_HOOK_IDX_MASK;
1985+
// // Like hook index, only low 6 bits of size is used for representing sizes.
1986+
// size = size & UC_HOOK_IDX_MASK;
19831987

19841988
// This has been done in tcg code.
19851989
// sync PC in CPUArchState with address
@@ -1988,8 +1992,10 @@ void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle,
19881992
// }
19891993

19901994
// the last callback may already asked to stop emulation
1991-
if (uc->stop_request && !(hook_flags & UC_HOOK_FLAG_NO_STOP)) {
1995+
if (uc->stop_request && !not_allow_stop) {
19921996
return;
1997+
} else if (not_allow_stop && uc->stop_request) {
1998+
revert_uc_emu_stop(uc);
19931999
}
19942000

19952001
for (cur = uc->hook[index].head;
@@ -2021,7 +2027,9 @@ void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle,
20212027
// normally. No check_exit_request is generated and the hooks are
20222028
// triggered normally. In other words, the whole IT block is treated
20232029
// as a single instruction.
2024-
if (uc->stop_request && !(hook_flags & UC_HOOK_FLAG_NO_STOP)) {
2030+
if (not_allow_stop && uc->stop_request) {
2031+
revert_uc_emu_stop(uc);
2032+
} else if (!not_allow_stop && uc->stop_request) {
20252033
break;
20262034
}
20272035
}

0 commit comments

Comments
 (0)