bsd-user: upstream signal implementation

Upstream the bsd-user fork signal implementation, for the most part.  This
 series of commits represents nearly all of the infrastructure that surround
 signals, except the actual system call glue (that was also reworked in the
 fork and needs its own series). In addition, this adds the sigsegv and sigbus
 code to arm. Even in the fork, we don't have good x86 signal implementation,
 so there's little to upstream for that at the moment.
 
 bsd-user's signal implementation is similar to linux-user's. The full context
 can be found in the bsd-user's fork's 'blitz branch' at
 https://github.com/qemu-bsd-user/qemu-bsd-user/tree/blitz which shows how these
 are used to implement various system calls. Since this was built from
 linux-user's stack stuff, evolved for BSD with the passage of a few years, it
 no-doubt missed some bug fixes from linux-user (though nothing obvious stood out
 in the quick comparison I made). After the first round of reviews, many of these
 improvements have been incorporated.
 
 Patchew history: https://patchew.org/QEMU/20220125012947.14974-1-imp@bsdimp.com/
 -----BEGIN PGP SIGNATURE-----
 Comment: GPGTools - https://gpgtools.org
 
 iQIzBAABCgAdFiEEIDX4lLAKo898zeG3bBzRKH2wEQAFAmH4PscACgkQbBzRKH2w
 EQAQew/7BgyFU2IIGqIw6Bu1XKPiBeJsS1n2D5FaUMHgj6a44RLRHURHeHi4PwHj
 D1nT51VeLKo5GfSSwlYS2Tum47fSWBAW/rDuqZ3FMAbsBzOxwEbY+gOhINPEJwSd
 TVzbJOq78IkDAocVCQwH97bd6FYVYVB4PEznU04tAcVd9pR/HQGa/hN5p4h6TeNi
 TL0WOt0IEneiMaEA2kAg9f/AtuRa6f+zzB8u8dN4HmxJ3M2z91fIujHAOg28e136
 Y+XIC5b+4l+q8TrIC+lMhC1VCknQcRDYLR2T9nHuTlKyH57BN8LNfccVQKMsKiuw
 1m+3o1otwYYHnW8UuUutcXLvUYTOKbgm5/hDlrFhx5jEXbYyEXzdkznnuiUhIL1y
 vdgq/O7uSlA0+xdCeUBfvh31+JPlgrcFInXL+moUwFWGpXRYazLme4KTcbm36T0d
 5V8BwDy9aJhquNf/UD0OcpEZ+nLtULuFYHI4ZAT/yZeKXkPfx9cVwWfhwtxYEC5J
 JMyeNWZ+QAO2riq8S2wmkyXmPKPMFS/h9L1X1zWekS8pa1oTa13Na+jzEFZ4+sip
 0KzSTkSkqrpmwjHNRWTDdPF9AKNqMKj1u2xd93L83N1KAJDM3SlLDgCD4C91OVxw
 5XzLcnX5uQsKk8ZcvGP/pongs13tolce3AU4OSHEdygFdTmUsj4=
 =aZPm
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/bsdimp/tags/bsd-user-arm-2022q1-pull-request' into staging

bsd-user: upstream signal implementation

Upstream the bsd-user fork signal implementation, for the most part.  This
series of commits represents nearly all of the infrastructure that surround
signals, except the actual system call glue (that was also reworked in the
fork and needs its own series). In addition, this adds the sigsegv and sigbus
code to arm. Even in the fork, we don't have good x86 signal implementation,
so there's little to upstream for that at the moment.

bsd-user's signal implementation is similar to linux-user's. The full context
can be found in the bsd-user's fork's 'blitz branch' at
https://github.com/qemu-bsd-user/qemu-bsd-user/tree/blitz which shows how these
are used to implement various system calls. Since this was built from
linux-user's stack stuff, evolved for BSD with the passage of a few years, it
no-doubt missed some bug fixes from linux-user (though nothing obvious stood out
in the quick comparison I made). After the first round of reviews, many of these
improvements have been incorporated.

Patchew history: https://patchew.org/QEMU/20220125012947.14974-1-imp@bsdimp.com/

# gpg: Signature made Mon 31 Jan 2022 19:55:51 GMT
# gpg:                using RSA key 2035F894B00AA3CF7CCDE1B76C1CD1287DB01100
# gpg: Good signature from "Warner Losh <wlosh@netflix.com>" [unknown]
# gpg:                 aka "Warner Losh <imp@bsdimp.com>" [unknown]
# gpg:                 aka "Warner Losh <imp@freebsd.org>" [unknown]
# gpg:                 aka "Warner Losh <imp@village.org>" [unknown]
# gpg:                 aka "Warner Losh <wlosh@bsdimp.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 2035 F894 B00A A3CF 7CCD  E1B7 6C1C D128 7DB0 1100

* remotes/bsdimp/tags/bsd-user-arm-2022q1-pull-request: (40 commits)
  bsd-user/freebsd/target_os_ucontext.h: Prefer env as arg name for CPUArchState args
  bsd-user: Rename arg name for target_cpu_reset to env
  MAINTAINERS: Add tests/vm/*bsd to the list to get reviews on
  bsd-user/signal.c: do_sigaltstack
  bsd-user/signal.c: implement do_sigaction
  bsd-user/signal.c: implement do_sigreturn
  bsd-user/signal.c: process_pending_signals
  bsd-user/signal.c: tswap_siginfo
  bsd-user/signal.c: handle_pending_signal
  bsd-user/signal.c: setup_frame
  bsd-user/signal.c: sigset manipulation routines.
  bsd-user/signal.c: Fill in queue_signal
  bsd-user/signal.c: Implement dump_core_and_abort
  bsd-user/strace.c: print_taken_signal
  bsd-user/signal.c: Implement host_signal_handler
  bsd-user/signal.c: Implement rewind_if_in_safe_syscall
  bsd-user/signal.c: host_to_target_siginfo_noswap
  bsd-user: Add trace events for bsd-user
  bsd-user: Add host signals to the build
  bsd-user/host/x86_64/host-signal.h: Implement host_signal_*
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
staging
Peter Maydell 2022-01-31 20:20:54 +00:00
commit 5cbe64110d
22 changed files with 1490 additions and 114 deletions

View File

@ -3186,6 +3186,7 @@ R: Kyle Evans <kevans@freebsd.org>
S: Maintained
F: bsd-user/
F: configs/targets/*-bsd-user.mak
F: tests/vm/*bsd
T: git https://github.com/qemu-bsd-user/qemu-bsd-user bsd-user-rebase-3.1
Linux user

View File

@ -59,19 +59,31 @@ abi_long set_sigtramp_args(CPUARMState *env, int sig,
return 0;
}
static abi_long get_vfpcontext(CPUARMState *env, abi_ulong frame_addr,
struct target_sigframe *frame)
{
/* see sendsig and get_vfpcontext in sys/arm/arm/exec_machdep.c */
target_mcontext_vfp_t *vfp = &frame->sf_vfp;
target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
/* Assumes that mcp and vfp are locked */
for (int i = 0; i < 32; i++) {
vfp->mcv_reg[i] = tswap64(*aa32_vfp_dreg(env, i));
}
vfp->mcv_fpscr = tswap32(vfp_get_fpscr(env));
mcp->mc_vfp_size = tswap32(sizeof(*vfp));
mcp->mc_vfp_ptr = tswap32(frame_addr + ((uintptr_t)vfp - (uintptr_t)frame));
return 0;
}
/*
* Compare to arm/arm/machdep.c get_mcontext()
* Compare to arm/arm/exec_machdep.c get_mcontext()
* Assumes that the memory is locked if mcp points to user memory.
*/
abi_long get_mcontext(CPUARMState *env, target_mcontext_t *mcp, int flags)
{
int err = 0;
uint32_t *gr = mcp->__gregs;
if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(target_mcontext_vfp_t)) {
return -TARGET_EINVAL;
}
gr[TARGET_REG_CPSR] = tswap32(cpsr_read(env));
if (flags & TARGET_MC_GET_CLEAR_RET) {
gr[TARGET_REG_R0] = 0;
@ -97,17 +109,30 @@ abi_long get_mcontext(CPUARMState *env, target_mcontext_t *mcp, int flags)
gr[TARGET_REG_LR] = tswap32(env->regs[14]);
gr[TARGET_REG_PC] = tswap32(env->regs[15]);
if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr != 0) {
/* see get_vfpcontext in sys/arm/arm/exec_machdep.c */
target_mcontext_vfp_t *vfp;
vfp = lock_user(VERIFY_WRITE, mcp->mc_vfp_ptr, sizeof(*vfp), 0);
for (int i = 0; i < 32; i++) {
vfp->mcv_reg[i] = tswap64(*aa32_vfp_dreg(env, i));
}
vfp->mcv_fpscr = tswap32(vfp_get_fpscr(env));
unlock_user(vfp, mcp->mc_vfp_ptr, sizeof(*vfp));
}
return err;
/*
* FreeBSD's get_mcontext doesn't save VFP info, but sets the pointer and
* size to zero. Applications that need the VFP state use
* sysarch(ARM_GET_VFPSTATE) and are expected to adjust mcontext after that.
*/
mcp->mc_vfp_size = 0;
mcp->mc_vfp_ptr = 0;
memset(&mcp->mc_spare, 0, sizeof(mcp->mc_spare));
return 0;
}
/*
* Compare to arm/arm/exec_machdep.c sendsig()
* Assumes that the memory is locked if frame points to user memory.
*/
abi_long setup_sigframe_arch(CPUARMState *env, abi_ulong frame_addr,
struct target_sigframe *frame, int flags)
{
target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
get_mcontext(env, mcp, flags);
get_vfpcontext(env, frame_addr, frame);
return 0;
}
/* Compare to arm/arm/exec_machdep.c set_mcontext() */

View File

@ -21,6 +21,7 @@
#define _TARGET_ARCH_CPU_H_
#include "target_arch.h"
#include "signal-common.h"
#define TARGET_DEFAULT_CPU_MODEL "any"
@ -38,8 +39,7 @@ static inline void target_cpu_init(CPUARMState *env,
static inline void target_cpu_loop(CPUARMState *env)
{
int trapnr;
target_siginfo_t info;
int trapnr, si_signo, si_code;
unsigned int n;
CPUState *cs = env_cpu(env);
@ -50,33 +50,22 @@ static inline void target_cpu_loop(CPUARMState *env)
process_queued_cpu_work(cs);
switch (trapnr) {
case EXCP_UDEF:
{
/* See arm/arm/undefined.c undefinedinstruction(); */
info.si_addr = env->regs[15];
/* illegal instruction */
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPC;
queue_signal(env, info.si_signo, &info);
/* TODO: What about instruction emulation? */
}
case EXCP_NOCP:
case EXCP_INVSTATE:
/*
* See arm/arm/undefined.c undefinedinstruction();
*
* A number of details aren't emulated (they likely don't matter):
* o Misaligned PC generates ILL_ILLADR (these can't come from qemu)
* o Thumb-2 instructions generate ILLADR
* o Both modes implement coprocessor instructions, which we don't
* do here. FreeBSD just implements them for the VFP coprocessor
* and special kernel breakpoints, trace points, dtrace, etc.
*/
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->regs[15]);
break;
case EXCP_SWI:
case EXCP_BKPT:
{
/*
* system call
* See arm/arm/trap.c cpu_fetch_syscall_args()
*/
if (trapnr == EXCP_BKPT) {
if (env->thumb) {
env->regs[15] += 2;
} else {
env->regs[15] += 4;
}
}
n = env->regs[7];
if (bsd_type == target_freebsd) {
int ret;
@ -84,7 +73,7 @@ static inline void target_cpu_loop(CPUARMState *env)
int32_t syscall_nr = n;
int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
/* See arm/arm/trap.c cpu_fetch_syscall_args() */
/* See arm/arm/syscall.c cpu_fetch_syscall_args() */
if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
syscall_nr = env->regs[0];
arg1 = env->regs[1];
@ -160,32 +149,52 @@ static inline void target_cpu_loop(CPUARMState *env)
/* just indicate that signals should be handled asap */
break;
case EXCP_PREFETCH_ABORT:
/* See arm/arm/trap.c prefetch_abort_handler() */
case EXCP_DATA_ABORT:
/* See arm/arm/trap.c data_abort_handler() */
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
info.si_code = 0;
info.si_addr = env->exception.vaddress;
queue_signal(env, info.si_signo, &info);
/*
* See arm/arm/trap-v6.c prefetch_abort_handler() and
* data_abort_handler()
*
* However, FreeBSD maps these to a generic value and then uses that
* to maybe fault in pages in vm/vm_fault.c:vm_fault_trap(). I
* believe that the indirection maps the same as Linux, but haven't
* chased down every single possible indirection.
*/
/* For user-only we don't set TTBCR_EAE, so look at the FSR. */
switch (env->exception.fsr & 0x1f) {
case 0x1: /* Alignment */
si_signo = TARGET_SIGBUS;
si_code = TARGET_BUS_ADRALN;
break;
case 0x3: /* Access flag fault, level 1 */
case 0x6: /* Access flag fault, level 2 */
case 0x9: /* Domain fault, level 1 */
case 0xb: /* Domain fault, level 2 */
case 0xd: /* Permission fault, level 1 */
case 0xf: /* Permission fault, level 2 */
si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_ACCERR;
break;
case 0x5: /* Translation fault, level 1 */
case 0x7: /* Translation fault, level 2 */
si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_MAPERR;
break;
default:
g_assert_not_reached();
}
force_sig_fault(si_signo, si_code, env->exception.vaddress);
break;
case EXCP_DEBUG:
{
info.si_signo = TARGET_SIGTRAP;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
info.si_addr = env->exception.vaddress;
queue_signal(env, info.si_signo, &info);
}
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
case EXCP_BKPT:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[15]);
break;
case EXCP_YIELD:
/* nothing to do here for user-mode, just resume guest code */
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
default:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
@ -204,7 +213,7 @@ static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
env->regs[0] = 0;
}
static inline void target_cpu_reset(CPUArchState *cpu)
static inline void target_cpu_reset(CPUArchState *env)
{
}

View File

@ -71,11 +71,24 @@ typedef struct target_siginfo {
int32_t _mqd;
} _mesgp;
/* SIGPOLL */
/* SIGPOLL -- Not really genreated in FreeBSD ??? */
struct {
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
} _poll;
struct {
int _mqd;
} _mesgq;
struct {
/*
* Syscall number for signals delivered as a result of system calls
* denied by Capsicum.
*/
int _syscall;
} _capsicum;
/* Spare for future growth */
struct {
abi_long __spare1__;
int32_t __spare2_[7];

View File

@ -4,6 +4,9 @@
#include "target_os_siginfo.h"
#include "target_arch_signal.h"
abi_long setup_sigframe_arch(CPUArchState *env, abi_ulong frame_addr,
struct target_sigframe *frame, int flags);
/* Compare to sys/signal.h */
#define TARGET_SIGHUP 1 /* hangup */
#define TARGET_SIGINT 2 /* interrupt */

View File

@ -36,9 +36,9 @@ abi_long set_sigtramp_args(CPUArchState *env, int sig,
struct target_sigframe *frame,
abi_ulong frame_addr,
struct target_sigaction *ka);
abi_long get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags);
abi_long set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int srflag);
abi_long get_ucontext_sigreturn(CPUArchState *regs, abi_ulong target_sf,
abi_long get_mcontext(CPUArchState *env, target_mcontext_t *mcp, int flags);
abi_long set_mcontext(CPUArchState *env, target_mcontext_t *mcp, int srflag);
abi_long get_ucontext_sigreturn(CPUArchState *env, abi_ulong target_sf,
abi_ulong *target_uc);
#endif /* TARGET_OS_UCONTEXT_H */

View File

@ -0,0 +1,35 @@
/*
* host-signal.h: signal info dependent on the host architecture
*
* Copyright (c) 2021 Warner Losh
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ARM_HOST_SIGNAL_H
#define ARM_HOST_SIGNAL_H
#include <sys/ucontext.h>
static inline uintptr_t host_signal_pc(ucontext_t *uc)
{
return uc->uc_mcontext.__gregs[_REG_PC];
}
static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
{
uc->uc_mcontext.__gregs[_REG_PC] = pc;
}
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
{
/*
* In the FSR, bit 11 is WnR. FreeBSD returns this as part of the
* si_info.si_trapno.
*/
uint32_t fsr = info->si_trapno;
return extract32(fsr, 11, 1);
}
#endif

View File

@ -0,0 +1,37 @@
/*
* host-signal.h: signal info dependent on the host architecture
*
* Copyright (c) 2021 Warner Losh
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef I386_HOST_SIGNAL_H
#define I386_HOST_SIGNAL_H
#include <sys/ucontext.h>
#include <machine/trap.h>
#include <vm/pmap.h>
#include <machine/pmap.h>
static inline uintptr_t host_signal_pc(ucontext_t *uc)
{
return uc->uc_mcontext.mc_eip;
}
static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
{
uc->uc_mcontext.mc_eip = pc;
}
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
{
/*
* Look in sys/i386/i386/trap.c. NOTE: mc_err == tr_err due to type punning
* between a trapframe and mcontext on FreeBSD/i386.
*/
return uc->uc_mcontext.mc_trapno == T_PAGEFLT &&
uc->uc_mcontext.mc_err & PGEX_W;
}
#endif

View File

@ -0,0 +1,37 @@
/*
* host-signal.h: signal info dependent on the host architecture
*
* Copyright (c) 2021 Warner Losh
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef X86_64_HOST_SIGNAL_H
#define X86_64_HOST_SIGNAL_H
#include <sys/ucontext.h>
#include <machine/trap.h>
#include <vm/pmap.h>
#include <machine/pmap.h>
static inline uintptr_t host_signal_pc(ucontext_t *uc)
{
return uc->uc_mcontext.mc_rip;
}
static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
{
uc->uc_mcontext.mc_rip = pc;
}
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
{
/*
* Look in sys/amd64/amd64/trap.c. NOTE: mc_err == tr_err due to type
* punning between a trapframe and mcontext on FreeBSD/amd64.
*/
return uc->uc_mcontext.mc_trapno == T_PAGEFLT &&
uc->uc_mcontext.mc_err & PGEX_W;
}
#endif

View File

@ -32,6 +32,19 @@ abi_long set_sigtramp_args(CPUX86State *env, int sig,
return 0;
}
/*
* Compare to i386/i386/exec_machdep.c sendsig()
* Assumes that the memory is locked if frame points to user memory.
*/
abi_long setup_sigframe_arch(CPUX86State *env, abi_ulong frame_addr,
struct target_sigframe *frame, int flags)
{
target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
get_mcontext(env, mcp, flags);
return 0;
}
/* Compare to i386/i386/machdep.c get_mcontext() */
abi_long get_mcontext(CPUX86State *regs, target_mcontext_t *mcp, int flags)
{

View File

@ -20,6 +20,7 @@
#define _TARGET_ARCH_CPU_H_
#include "target_arch.h"
#include "signal-common.h"
#define TARGET_DEFAULT_CPU_MODEL "qemu32"
@ -199,9 +200,9 @@ static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
env->regs[R_EAX] = 0;
}
static inline void target_cpu_reset(CPUArchState *cpu)
static inline void target_cpu_reset(CPUArchState *env)
{
cpu_reset(env_cpu(cpu));
cpu_reset(env_cpu(env));
}
#endif /* ! _TARGET_ARCH_CPU_H_ */

View File

@ -215,15 +215,13 @@ void qemu_cpu_kick(CPUState *cpu)
}
/* Assumes contents are already zeroed. */
void init_task_state(TaskState *ts)
static void init_task_state(TaskState *ts)
{
int i;
ts->first_free = ts->sigqueue_table;
for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
}
ts->sigqueue_table[i].next = NULL;
ts->sigaltstack_used = (struct target_sigaltstack) {
.ss_sp = 0,
.ss_size = 0,
.ss_flags = TARGET_SS_DISABLE,
};
}
void gemu_log(const char *fmt, ...)

View File

@ -70,17 +70,9 @@ struct image_info {
uint32_t elf_flags;
};
#define MAX_SIGQUEUE_SIZE 1024
struct qemu_sigqueue {
struct qemu_sigqueue *next;
target_siginfo_t info;
};
struct emulated_sigtable {
int pending; /* true if signal is pending */
struct qemu_sigqueue *first;
struct qemu_sigqueue info; /* Put first signal info here */
target_siginfo_t info;
};
/*
@ -93,15 +85,39 @@ typedef struct TaskState {
struct bsd_binprm *bprm;
struct image_info *info;
struct emulated_sigtable sync_signal;
/*
* TODO: Since we block all signals while returning to the main CPU
* loop, this needn't be an array
*/
struct emulated_sigtable sigtab[TARGET_NSIG];
struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
int signal_pending; /* non zero if a signal may be pending */
/*
* Nonzero if process_pending_signals() needs to do something (either
* handle a pending signal or unblock signals).
* This flag is written from a signal handler so should be accessed via
* the qatomic_read() and qatomic_set() functions. (It is not accessed
* from multiple threads.)
*/
int signal_pending;
/* True if we're leaving a sigsuspend and sigsuspend_mask is valid. */
bool in_sigsuspend;
/*
* This thread's signal mask, as requested by the guest program.
* The actual signal mask of this thread may differ:
* + we don't let SIGSEGV and SIGBUS be blocked while running guest code
* + sometimes we block all signals to avoid races
*/
sigset_t signal_mask;
/*
* The signal mask imposed by a guest sigsuspend syscall, if we are
* currently in the middle of such a syscall
*/
sigset_t sigsuspend_mask;
uint8_t stack[];
/* This thread's sigaltstack, if it has one */
struct target_sigaltstack sigaltstack_used;
} __attribute__((aligned(16))) TaskState;
void init_task_state(TaskState *ts);
void stop_all_tasks(void);
extern const char *qemu_uname_release;
@ -201,16 +217,18 @@ print_openbsd_syscall(int num,
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6);
void print_openbsd_syscall_ret(int num, abi_long ret);
/**
* print_taken_signal:
* @target_signum: target signal being taken
* @tinfo: target_siginfo_t which will be passed to the guest for the signal
*
* Print strace output indicating that this signal is being taken by the guest,
* in a format similar to:
* --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
*/
void print_taken_signal(int target_signum, const target_siginfo_t *tinfo);
extern int do_strace;
/* signal.c */
void process_pending_signals(CPUArchState *cpu_env);
void signal_init(void);
long do_sigreturn(CPUArchState *env);
long do_rt_sigreturn(CPUArchState *env);
void queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
/* mmap.c */
int target_mprotect(abi_ulong start, abi_ulong len, int prot);
abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
@ -451,4 +469,6 @@ static inline void *lock_user_string(abi_ulong guest_addr)
#include <pthread.h>
#include "user/safe-syscall.h"
#endif /* QEMU_H */

View File

@ -0,0 +1,70 @@
/*
* Emulation of BSD signals
*
* Copyright (c) 2013 Stacey Son
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef SIGNAL_COMMON_H
#define SIGNAL_COMMON_H
/**
* block_signals: block all signals while handling this guest syscall
*
* Block all signals, and arrange that the signal mask is returned to
* its correct value for the guest before we resume execution of guest code.
* If this function returns non-zero, then the caller should immediately
* return -TARGET_ERESTARTSYS to the main loop, which will take the pending
* signal and restart execution of the syscall.
* If block_signals() returns zero, then the caller can continue with
* emulation of the system call knowing that no signals can be taken
* (and therefore that no race conditions will result).
* This should only be called once, because if it is called a second time
* it will always return non-zero. (Think of it like a mutex that can't
* be recursively locked.)
* Signals will be unblocked again by process_pending_signals().
*
* Return value: non-zero if there was a pending signal, zero if not.
*/
int block_signals(void); /* Returns non zero if signal pending */
long do_rt_sigreturn(CPUArchState *env);
int do_sigaction(int sig, const struct target_sigaction *act,
struct target_sigaction *oact);
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
long do_sigreturn(CPUArchState *env, abi_ulong addr);
void force_sig_fault(int sig, int code, abi_ulong addr);
int host_to_target_signal(int sig);
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
void process_pending_signals(CPUArchState *env);
void queue_signal(CPUArchState *env, int sig, int si_type,
target_siginfo_t *info);
void signal_init(void);
int target_to_host_signal(int sig);
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
/*
* Within QEMU the top 8 bits of si_code indicate which of the parts of the
* union in target_siginfo is valid. This only applies between
* host_to_target_siginfo_noswap() and tswap_siginfo(); it does not appear
* either within host siginfo_t or in target_siginfo structures which we get
* from the guest userspace program. Linux kenrels use this internally, but BSD
* kernels don't do this, but its a useful abstraction.
*
* The linux-user version of this uses the top 16 bits, but FreeBSD's SI_USER
* and other signal indepenent SI_ codes have bit 16 set, so we only use the top
* byte instead.
*
* For FreeBSD, we have si_pid, si_uid, si_status, and si_addr always. Linux and
* {Open,Net}BSD have a different approach (where their reason field is larger,
* but whose siginfo has fewer fields always).
*/
#define QEMU_SI_NOINFO 0 /* nothing other than si_signo valid */
#define QEMU_SI_FAULT 1 /* _fault is valid in _reason */
#define QEMU_SI_TIMER 2 /* _timer is valid in _reason */
#define QEMU_SI_MESGQ 3 /* _mesgq is valid in _reason */
#define QEMU_SI_POLL 4 /* _poll is valid in _reason */
#define QEMU_SI_CAPSICUM 5 /* _capsicum is valid in _reason */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,24 @@ int do_strace;
/*
* Utility functions
*/
static const char *
get_comma(int last)
{
return (last) ? "" : ",";
}
/*
* Prints out raw parameter using given format. Caller needs
* to do byte swapping if needed.
*/
static void
print_raw_param(const char *fmt, abi_long param, int last)
{
char format[64];
(void)snprintf(format, sizeof(format), "%s%s", fmt, get_comma(last));
gemu_log(format, param);
}
static void print_sysctl(const struct syscallname *name, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
@ -239,3 +257,82 @@ void print_openbsd_syscall_ret(int num, abi_long ret)
print_syscall_ret(num, ret, openbsd_scnames, ARRAY_SIZE(openbsd_scnames));
}
static void
print_signal(abi_ulong arg, int last)
{
const char *signal_name = NULL;
switch (arg) {
case TARGET_SIGHUP:
signal_name = "SIGHUP";
break;
case TARGET_SIGINT:
signal_name = "SIGINT";
break;
case TARGET_SIGQUIT:
signal_name = "SIGQUIT";
break;
case TARGET_SIGILL:
signal_name = "SIGILL";
break;
case TARGET_SIGABRT:
signal_name = "SIGABRT";
break;
case TARGET_SIGFPE:
signal_name = "SIGFPE";
break;
case TARGET_SIGKILL:
signal_name = "SIGKILL";
break;
case TARGET_SIGSEGV:
signal_name = "SIGSEGV";
break;
case TARGET_SIGPIPE:
signal_name = "SIGPIPE";
break;
case TARGET_SIGALRM:
signal_name = "SIGALRM";
break;
case TARGET_SIGTERM:
signal_name = "SIGTERM";
break;
case TARGET_SIGUSR1:
signal_name = "SIGUSR1";
break;
case TARGET_SIGUSR2:
signal_name = "SIGUSR2";
break;
case TARGET_SIGCHLD:
signal_name = "SIGCHLD";
break;
case TARGET_SIGCONT:
signal_name = "SIGCONT";
break;
case TARGET_SIGSTOP:
signal_name = "SIGSTOP";
break;
case TARGET_SIGTTIN:
signal_name = "SIGTTIN";
break;
case TARGET_SIGTTOU:
signal_name = "SIGTTOU";
break;
}
if (signal_name == NULL) {
print_raw_param("%ld", arg, last);
return;
}
gemu_log("%s%s", signal_name, get_comma(last));
}
void print_taken_signal(int target_signum, const target_siginfo_t *tinfo)
{
/*
* Print the strace output for a signal being taken:
* --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
*/
gemu_log("%d ", getpid());
gemu_log("--- ");
print_signal(target_signum, 1);
gemu_log(" ---\n");
}

View File

@ -21,6 +21,7 @@
#define _SYSCALL_DEFS_H_
#include <sys/syscall.h>
#include <sys/resource.h>
#include "errno_defs.h"

View File

@ -0,0 +1,11 @@
# See docs/tracing.txt for syntax documentation.
# bsd-user/signal.c
user_setup_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
user_setup_rt_frame(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
user_do_rt_sigreturn(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
user_do_sigreturn(void *env, uint64_t frame_addr) "env=%p frame_addr=0x%"PRIx64
user_dump_core_and_abort(void *env, int target_sig, int host_sig) "env=%p signal %d (host %d)"
user_handle_signal(void *env, int target_sig) "env=%p signal %d"
user_host_signal(void *env, int host_sig, int target_sig) "env=%p signal %d (target %d("
user_queue_signal(void *env, int target_sig) "env=%p signal %d"

1
bsd-user/trace.h 100644
View File

@ -0,0 +1 @@
#include "trace/trace-bsd_user.h"

View File

@ -30,6 +30,19 @@ abi_long set_sigtramp_args(CPUX86State *regs,
return 0;
}
/*
* Compare to amd64/amd64/exec_machdep.c sendsig()
* Assumes that the memory is locked if frame points to user memory.
*/
abi_long setup_sigframe_arch(CPUX86State *env, abi_ulong frame_addr,
struct target_sigframe *frame, int flags)
{
target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
get_mcontext(env, mcp, flags);
return 0;
}
/* Compare to amd64/amd64/machdep.c get_mcontext() */
abi_long get_mcontext(CPUX86State *regs,
target_mcontext_t *mcp, int flags)

View File

@ -20,6 +20,7 @@
#define _TARGET_ARCH_CPU_H_
#include "target_arch.h"
#include "signal-common.h"
#define TARGET_DEFAULT_CPU_MODEL "qemu64"
@ -237,9 +238,9 @@ static inline void target_cpu_clone_regs(CPUX86State *env, target_ulong newsp)
env->regs[R_EAX] = 0;
}
static inline void target_cpu_reset(CPUArchState *cpu)
static inline void target_cpu_reset(CPUArchState *env)
{
cpu_reset(env_cpu(cpu));
cpu_reset(env_cpu(env));
}
#endif /* ! _TARGET_ARCH_CPU_H_ */

View File

@ -2458,9 +2458,12 @@ trace_events_subdirs = [
'monitor',
'util',
]
if have_user
if have_linux_user
trace_events_subdirs += [ 'linux-user' ]
endif
if have_bsd_user
trace_events_subdirs += [ 'bsd-user' ]
endif
if have_block
trace_events_subdirs += [
'authz',
@ -2947,6 +2950,7 @@ foreach target : target_dirs
if 'CONFIG_BSD_USER' in config_target
base_dir = 'bsd-user'
target_inc += include_directories('bsd-user/' / targetos)
target_inc += include_directories('bsd-user/host/' / host_arch)
dir = base_dir / abi
arch_srcs += files(dir / 'signal.c', dir / 'target_arch_cpu.c')
endif