bsd-user/signal.c: setup_frame

setup_frame sets up a signalled stack frame. Associated routines to
extract the pointer to the stack frame and to support alternate stacks.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@freebsd.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
staging
Warner Losh 2022-01-08 21:40:28 -07:00
parent c93cbac1f4
commit 46f4f76d33
3 changed files with 90 additions and 1 deletions

View File

@ -217,6 +217,11 @@ void qemu_cpu_kick(CPUState *cpu)
/* Assumes contents are already zeroed. */
static void init_task_state(TaskState *ts)
{
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

@ -107,7 +107,8 @@ typedef struct TaskState {
*/
sigset_t signal_mask;
uint8_t stack[];
/* This thread's sigaltstack, if it has one */
struct target_sigaltstack sigaltstack_used;
} __attribute__((aligned(16))) TaskState;
void stop_all_tasks(void);

View File

@ -35,6 +35,16 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc);
static void target_to_host_sigset_internal(sigset_t *d,
const target_sigset_t *s);
static inline int on_sig_stack(TaskState *ts, unsigned long sp)
{
return sp - ts->sigaltstack_used.ss_sp < ts->sigaltstack_used.ss_size;
}
static inline int sas_ss_flags(TaskState *ts, unsigned long sp)
{
return ts->sigaltstack_used.ss_size == 0 ? SS_DISABLE :
on_sig_stack(ts, sp) ? SS_ONSTACK : 0;
}
/*
* The BSD ABIs use the same singal numbers across all the CPU architectures, so
@ -491,6 +501,79 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
cpu_exit(thread_cpu);
}
static inline abi_ulong get_sigframe(struct target_sigaction *ka,
CPUArchState *env, size_t frame_size)
{
TaskState *ts = (TaskState *)thread_cpu->opaque;
abi_ulong sp;
/* Use default user stack */
sp = get_sp_from_cpustate(env);
if ((ka->sa_flags & TARGET_SA_ONSTACK) && sas_ss_flags(ts, sp) == 0) {
sp = ts->sigaltstack_used.ss_sp + ts->sigaltstack_used.ss_size;
}
/* TODO: make this a target_arch function / define */
#if defined(TARGET_ARM)
return (sp - frame_size) & ~7;
#elif defined(TARGET_AARCH64)
return (sp - frame_size) & ~15;
#else
return sp - frame_size;
#endif
}
/* compare to $M/$M/exec_machdep.c sendsig and sys/kern/kern_sig.c sigexit */
static void setup_frame(int sig, int code, struct target_sigaction *ka,
target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *env)
{
struct target_sigframe *frame;
abi_ulong frame_addr;
int i;
frame_addr = get_sigframe(ka, env, sizeof(*frame));
trace_user_setup_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
unlock_user_struct(frame, frame_addr, 1);
dump_core_and_abort(TARGET_SIGILL);
return;
}
memset(frame, 0, sizeof(*frame));
setup_sigframe_arch(env, frame_addr, frame, 0);
for (i = 0; i < TARGET_NSIG_WORDS; i++) {
__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i]);
}
if (tinfo) {
frame->sf_si.si_signo = tinfo->si_signo;
frame->sf_si.si_errno = tinfo->si_errno;
frame->sf_si.si_code = tinfo->si_code;
frame->sf_si.si_pid = tinfo->si_pid;
frame->sf_si.si_uid = tinfo->si_uid;
frame->sf_si.si_status = tinfo->si_status;
frame->sf_si.si_addr = tinfo->si_addr;
/* see host_to_target_siginfo_noswap() for more details */
frame->sf_si.si_value.sival_ptr = tinfo->si_value.sival_ptr;
/*
* At this point, whatever is in the _reason union is complete
* and in target order, so just copy the whole thing over, even
* if it's too large for this specific signal.
* host_to_target_siginfo_noswap() and tswap_siginfo() have ensured
* that's so.
*/
memcpy(&frame->sf_si._reason, &tinfo->_reason,
sizeof(tinfo->_reason));
}
set_sigtramp_args(env, sig, frame, frame_addr, ka);
unlock_user_struct(frame, frame_addr, 1);
}
void signal_init(void)
{
TaskState *ts = (TaskState *)thread_cpu->opaque;