linux-user/arm: Deliver SIGTRAP for UDF patterns used as breakpoints
The Linux kernel doesn't use the official bkpt insn for breakpoints; instead it uses three instructions in the guaranteed-to-UNDEF space, and generates SIGTRAP for these rather than the SIGILL that most UNDEF insns generate: https://elixir.bootlin.com/linux/v5.9.8/source/arch/arm/kernel/ptrace.c#L197 Make QEMU treat these insns specially too. The main benefit of this is that if you're running a debugger on a guest program that runs into a GCC __builtin_trap() or LLVM "trap because execution should never reach here" then you'll get the expected signal rather than a SIGILL. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201117155634.6924-1-peter.maydell@linaro.org
This commit is contained in:
parent
6951595183
commit
acebed948c
@ -205,6 +205,24 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_loop(CPUARMState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
@ -234,6 +252,16 @@ 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;
|
||||
}
|
||||
|
||||
rc = EmulateAll(opcode, &ts->fpa, env);
|
||||
if (rc == 0) { /* illegal instruction */
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
|
Loading…
Reference in New Issue
Block a user