mirror of https://github.com/xemu-project/xemu.git
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>
This commit is contained in:
parent
c93cbac1f4
commit
46f4f76d33
|
@ -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, ...)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue