It is easier to recognize the insn from decodetree than it
is from cpu_loop. In particular, there is a BE32 bug in
how we rebuild thumb2 insns in get_user_code_u32.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/arm/cpu_loop.c | 28 ----------------------------
target/arm/tcg/translate.c | 17 +++++++++++++++++
target/arm/tcg/a32.decode | 5 ++++-
target/arm/tcg/t16.decode | 1 +
target/arm/tcg/t32.decode | 5 ++++-
5 files changed, 26 insertions(+), 30 deletions(-)
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index 86f13ad83a..4f7c5dab9c 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -194,24 +194,6 @@ do_kernel_trap(CPUARMState *env)
return 0;
}
-static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb)
-{
- /*
- * Return true if this insn is one of the three magic UDF insns
- * which the kernel treats as breakpoint insns.
- */
- if (!is_thumb) {
- return (opcode & 0x0fffffff) == 0x07f001f0;
- } else {
- /*
- * Note that we get the two halves of the 32-bit T32 insn
- * in the opposite order to the value the kernel uses in
- * its undef_hook struct.
- */
- return ((opcode & 0xffff) == 0xde01) || (opcode == 0xa000f7f0);
- }
-}
-
static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode)
{
TaskState *ts = get_task_state(env_cpu(env));
@@ -291,16 +273,6 @@ void cpu_loop(CPUARMState *env)
/* FIXME - what to do if get_user() fails? */
get_user_code_u32(opcode, env->regs[15], env);
- /*
- * The Linux kernel treats some UDF patterns specially
- * to use as breakpoints (instead of the architectural
- * bkpt insn). These should trigger a SIGTRAP rather
- * than SIGILL.
- */
- if (insn_is_linux_bkpt(opcode, env->thumb)) {
- goto excp_debug;
- }
-
if (!env->thumb && emulate_arm_fpa11(env, opcode)) {
break;
}
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index ec21e33a06..0447be0907 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -4508,6 +4508,23 @@ static bool trans_BFCI(DisasContext *s, arg_BFCI *a)
return true;
}
+static bool trans_LINUX_BKPT(DisasContext *s, arg_LINUX_BKPT *a)
+{
+#ifdef CONFIG_USER_ONLY
+# ifdef CONFIG_LINUX
+ /*
+ * The Linux kernel recognizes 3 UDF patterns as breakpoints.
+ * Recognizing these during translate is much less error prone
+ * than deferring to cpu_loop.
+ */
+ gen_exception_bkpt_insn(s, 0);
+ return true;
+# endif
+#endif
+ /* Fall through to UDF. */
+ return false;
+}
+
static bool trans_UDF(DisasContext *s, arg_UDF *a)
{
unallocated_encoding(s);
diff --git a/target/arm/tcg/a32.decode b/target/arm/tcg/a32.decode
index f2ca480949..c7e8e9803e 100644
--- a/target/arm/tcg/a32.decode
+++ b/target/arm/tcg/a32.decode
@@ -425,7 +425,10 @@ BFCI ---- 0111 110 msb:5 rd:4 lsb:5 001 rn:4 &bfi
# While we could get UDEF by not including this, add the pattern for
# documentation and to conflict with any other typos in this file.
-UDF 1110 0111 1111 ---- ---- ---- 1111 ----
+{
+ LINUX_BKPT 1110 0111 1111 0000 0000 0001 1111 0000
+ UDF 1110 0111 1111 ---- ---- ---- 1111 ----
+}
# Parallel addition and subtraction
diff --git a/target/arm/tcg/t16.decode b/target/arm/tcg/t16.decode
index 778fbf1627..836e929684 100644
--- a/target/arm/tcg/t16.decode
+++ b/target/arm/tcg/t16.decode
@@ -263,6 +263,7 @@ LDM_t16 1011 110 ......... \
%imm8_0x2 0:s8 !function=times_2
{
+ LINUX_BKPT 1101 1110 0000 0001
UDF 1101 1110 ---- ----
SVC 1101 1111 imm:8 &i
B_cond_thumb 1101 cond:4 ........ &ci imm=%imm8_0x2
diff --git a/target/arm/tcg/t32.decode b/target/arm/tcg/t32.decode
index 49b8d0037e..05217da8b3 100644
--- a/target/arm/tcg/t32.decode
+++ b/target/arm/tcg/t32.decode
@@ -418,7 +418,10 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
SMC 1111 0111 1111 imm:4 1000 0000 0000 0000 &i
HVC 1111 0111 1110 .... 1000 .... .... .... \
&i imm=%imm16_16_0
- UDF 1111 0111 1111 ---- 1010 ---- ---- ----
+ {
+ LINUX_BKPT 1111 0111 1111 0000 1010 0000 0000 0000
+ UDF 1111 0111 1111 ---- 1010 ---- ---- ----
+ }
]
B_cond_thumb 1111 0. cond:4 ...... 10.0 ............ &ci imm=%imm21
}
--
2.43.0