Pull request linux-user 20211004

Move signal trampolines to new page
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmFasLkSHGxhdXJlbnRA
 dml2aWVyLmV1AAoJEPMMOL0/L7483WwP/jqpk4ZRV8aOzGH6CMEiGzzHl2PdzshO
 lx7LWTgcB74SWohsTKlTviSQj0lc2iVC3LsZ+yFUiVU9kPpWFhtdzbxyvnfm1hyM
 pR80Zc3Paod+Jb9x8eTn0iT/ccP1ySFAoK4TJCuDBfV6lMThmRmBEebAKxc4ZGCk
 pXRxvk1wSIwykPD4Wp7cmSqYJLn2ajMkCn3g+/SWUJ4HMKkEYZMRsB51nl8SrBa4
 /UPdeOaQrtjRY1veOsjmJ16xWyy1YtpDfo41ymST6HDo9yfik/0orX6tvjQhQo4g
 SP6a6Lp528ePa6JacIhs9r7HWMWTm+AhDWjk+N+WS2zp0jMJXF8/0p0NYDYHzH9V
 eRx6zOcDkxfxV2KlQ8fOd8Kmj2d/leORcVOpZpWV3sS3G1/80LyTzeT4kkbRXrzw
 /ujZyPGGy6GX2VQkvA05NPH7Sy/Uv1Oqr7wkCeHQVbvMghjwNAdeIbTQ2hBWJp/D
 S0pw7XS41ktIKYH5ui1EYaRKTIQ0gh5ecbO1CySpVZvgqTOoK2ps0H+nZtgiLySC
 yukNVIkbdODqgeBi19kitqP2eJHIq/SRFp4WTBRgSla4mMorVnfrvDreW6my/aC+
 yK+YVbCYx4vWB7yOWL5SLvb1DcQIqyKeJdN7W3LtkkiBXqUxlb6Dmmr6wrCCOCfP
 qCuRrc/MvzfO
 =59lT
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier/tags/linux-user-for-6.2-pull-request' into staging

Pull request linux-user 20211004

Move signal trampolines to new page

# gpg: Signature made Mon 04 Oct 2021 12:43:53 AM PDT
# gpg:                using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C
# gpg:                issuer "laurent@vivier.eu"
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full]
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>" [full]
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full]

* remotes/vivier/tags/linux-user-for-6.2-pull-request: (26 commits)
  tests/tcg/multiarch: Re-enable signals test for most guests
  linux-user: Remove default for TARGET_ARCH_HAS_SIGTRAMP_PAGE
  linux-user/xtensa: Implement setup_sigtramp
  linux-user/sparc: Implement setup_sigtramp
  linux-user/sh4: Implement setup_sigtramp
  linux-user/s390x: Implement setup_sigtramp
  linux-user/riscv: Implement setup_sigtramp
  linux-user/ppc: Implement setup_sigtramp
  linux-user/ppc: Simplify encode_trampoline
  linux-user/openrisc: Implement setup_sigtramp
  linux-user/nios2: Document non-use of setup_sigtramp
  linux-user/mips: Implement setup_sigtramp
  linux-user/mips: Tidy install_sigtramp
  linux-user/microblaze: Implement setup_sigtramp
  linux-user/m68k: Implement setup_sigtramp
  linux-user/x86_64: Raise SIGSEGV if SA_RESTORER not set
  linux-user/i386: Implement setup_sigtramp
  linux-user/hppa: Document non-use of setup_sigtramp
  linux-user/hexagon: Implement setup_sigtramp
  linux-user/cris: Implement setup_sigtramp
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2021-10-04 14:21:39 -07:00
commit e7ab658478
43 changed files with 613 additions and 604 deletions

View File

@ -109,7 +109,6 @@ struct target_rt_sigframe {
struct target_rt_frame_record {
uint64_t fp;
uint64_t lr;
uint32_t tramp[2];
};
static void target_setup_general_frame(struct target_rt_sigframe *sf,
@ -461,9 +460,9 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
layout.total_size = MAX(layout.total_size,
sizeof(struct target_rt_sigframe));
/* Reserve space for the return code. On a real system this would
* be within the VDSO. So, despite the name this is not a "real"
* record within the frame.
/*
* Reserve space for the standard frame unwind pair: fp, lr.
* Despite the name this is not a "real" record within the frame.
*/
fr_ofs = layout.total_size;
layout.total_size += sizeof(struct target_rt_frame_record);
@ -496,15 +495,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
if (ka->sa_flags & TARGET_SA_RESTORER) {
return_addr = ka->sa_restorer;
} else {
/*
* mov x8,#__NR_rt_sigreturn; svc #0
* Since these are instructions they need to be put as little-endian
* regardless of target default or current CPU endianness.
*/
__put_user_e(0xd2801168, &fr->tramp[0], le);
__put_user_e(0xd4000001, &fr->tramp[1], le);
return_addr = frame_addr + fr_ofs
+ offsetof(struct target_rt_frame_record, tramp);
return_addr = default_rt_sigreturn;
}
env->xregs[0] = usig;
env->xregs[29] = frame_addr + fr_ofs;
@ -577,3 +568,20 @@ long do_sigreturn(CPUARMState *env)
{
return do_rt_sigreturn(env);
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
assert(tramp != NULL);
/*
* mov x8,#__NR_rt_sigreturn; svc #0
* Since these are instructions they need to be put as little-endian
* regardless of target default or current CPU endianness.
*/
__put_user_e(0xd2801168, &tramp[0], le);
__put_user_e(0xd4000001, &tramp[1], le);
default_rt_sigreturn = sigtramp_page;
unlock_user(tramp, sigtramp_page, 8);
}

View File

@ -25,4 +25,6 @@ typedef struct target_sigaltstack {
#define TARGET_SEGV_MTESERR 9 /* Synchronous ARM MTE exception */
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* AARCH64_TARGET_SIGNAL_H */

View File

@ -55,13 +55,11 @@ struct target_ucontext {
struct target_sigframe {
struct target_sigcontext sc;
unsigned int retcode[3];
};
struct target_rt_sigframe {
target_siginfo_t info;
struct target_ucontext uc;
unsigned int retcode[3];
};
#define INSN_MOV_R30_R16 0x47fe0410
@ -142,12 +140,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
if (ka->ka_restorer) {
r26 = ka->ka_restorer;
} else {
__put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
__put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
&frame->retcode[1]);
__put_user(INSN_CALLSYS, &frame->retcode[2]);
/* imb() */
r26 = frame_addr + offsetof(struct target_sigframe, retcode);
r26 = default_sigreturn;
}
unlock_user_struct(frame, frame_addr, 1);
@ -196,12 +189,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
if (ka->ka_restorer) {
r26 = ka->ka_restorer;
} else {
__put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
__put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
&frame->retcode[1]);
__put_user(INSN_CALLSYS, &frame->retcode[2]);
/* imb(); */
r26 = frame_addr + offsetof(struct target_rt_sigframe, retcode);
r26 = default_rt_sigreturn;
}
if (err) {
@ -269,3 +257,21 @@ badframe:
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6 * 4, 0);
assert(tramp != NULL);
default_sigreturn = sigtramp_page;
__put_user(INSN_MOV_R30_R16, &tramp[0]);
__put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, &tramp[1]);
__put_user(INSN_CALLSYS, &tramp[2]);
default_rt_sigreturn = sigtramp_page + 3 * 4;
__put_user(INSN_MOV_R30_R16, &tramp[3]);
__put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, &tramp[4]);
__put_user(INSN_CALLSYS, &tramp[5]);
unlock_user(tramp, sigtramp_page, 6 * 4);
}

View File

@ -93,6 +93,7 @@ typedef struct target_sigaltstack {
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_KA_RESTORER
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
/* bit-flags */
#define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */

View File

@ -46,15 +46,7 @@ struct target_sigcontext {
abi_ulong fault_address;
};
struct target_ucontext_v1 {
abi_ulong tuc_flags;
abi_ulong tuc_link;
target_stack_t tuc_stack;
struct target_sigcontext tuc_mcontext;
target_sigset_t tuc_sigmask; /* mask last for extensibility */
};
struct target_ucontext_v2 {
struct target_ucontext {
abi_ulong tuc_flags;
abi_ulong tuc_link;
target_stack_t tuc_stack;
@ -98,68 +90,30 @@ struct target_iwmmxt_sigframe {
#define TARGET_VFP_MAGIC 0x56465001
#define TARGET_IWMMXT_MAGIC 0x12ef842a
struct sigframe_v1
struct sigframe
{
struct target_sigcontext sc;
abi_ulong extramask[TARGET_NSIG_WORDS-1];
struct target_ucontext uc;
abi_ulong retcode[4];
};
struct sigframe_v2
{
struct target_ucontext_v2 uc;
abi_ulong retcode[4];
};
struct rt_sigframe_v1
{
abi_ulong pinfo;
abi_ulong puc;
struct target_siginfo info;
struct target_ucontext_v1 uc;
abi_ulong retcode[4];
};
struct rt_sigframe_v2
struct rt_sigframe
{
struct target_siginfo info;
struct target_ucontext_v2 uc;
abi_ulong retcode[4];
struct sigframe sig;
};
static abi_ptr sigreturn_fdpic_tramp;
/*
* For ARM syscalls, we encode the syscall number into the instruction.
* Up to 3 words of 'retcode' in the sigframe are code,
* with retcode[3] being used by fdpic for the function descriptor.
* This code is not actually executed, but is retained for ABI compat.
*
* We will create a table of 8 retcode variants in the sigtramp page.
* Let each table entry use 3 words.
*/
#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
/*
* For Thumb syscalls, we pass the syscall number via r7. We therefore
* need two 16-bit instructions.
*/
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
static const abi_ulong retcodes[4] = {
SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
};
/*
* Stub needed to make sure the FD register (r9) contains the right
* value.
*/
static const unsigned long sigreturn_fdpic_codes[3] = {
0xe59fc004, /* ldr r12, [pc, #4] to read function descriptor */
0xe59c9004, /* ldr r9, [r12, #4] to setup GOT */
0xe59cf000 /* ldr pc, [r12] to jump into restorer */
};
static const unsigned long sigreturn_fdpic_thumb_codes[3] = {
0xc008f8df, /* ldr r12, [pc, #8] to read function descriptor */
0x9004f8dc, /* ldr r9, [r12, #4] to setup GOT */
0xf000f8dc /* ldr pc, [r12] to jump into restorer */
};
#define RETCODE_WORDS 3
#define RETCODE_BYTES (RETCODE_WORDS * 4)
static inline int valid_user_regs(CPUARMState *regs)
{
@ -207,15 +161,15 @@ get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
}
static int
setup_return(CPUARMState *env, struct target_sigaction *ka,
abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
struct sigframe *frame, abi_ulong sp_addr)
{
abi_ulong handler = 0;
abi_ulong handler_fdpic_GOT = 0;
abi_ulong retcode;
int thumb;
int thumb, retcode_idx;
int is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
bool copy_retcode;
if (is_fdpic) {
/* In FDPIC mode, ka->_sa_handler points to a function
@ -232,6 +186,7 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
}
thumb = handler & 1;
retcode_idx = thumb + (ka->sa_flags & TARGET_SA_SIGINFO ? 2 : 0);
uint32_t cpsr = cpsr_read(env);
@ -249,44 +204,29 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
if (ka->sa_flags & TARGET_SA_RESTORER) {
if (is_fdpic) {
/* For FDPIC we ensure that the restorer is called with a
* correct r9 value. For that we need to write code on
* the stack that sets r9 and jumps back to restorer
* value.
*/
if (thumb) {
__put_user(sigreturn_fdpic_thumb_codes[0], rc);
__put_user(sigreturn_fdpic_thumb_codes[1], rc + 1);
__put_user(sigreturn_fdpic_thumb_codes[2], rc + 2);
__put_user((abi_ulong)ka->sa_restorer, rc + 3);
} else {
__put_user(sigreturn_fdpic_codes[0], rc);
__put_user(sigreturn_fdpic_codes[1], rc + 1);
__put_user(sigreturn_fdpic_codes[2], rc + 2);
__put_user((abi_ulong)ka->sa_restorer, rc + 3);
}
retcode = rc_addr + thumb;
__put_user((abi_ulong)ka->sa_restorer, &frame->retcode[3]);
retcode = (sigreturn_fdpic_tramp +
retcode_idx * RETCODE_BYTES + thumb);
copy_retcode = true;
} else {
retcode = ka->sa_restorer;
copy_retcode = false;
}
} else {
unsigned int idx = thumb;
retcode = default_sigreturn + retcode_idx * RETCODE_BYTES + thumb;
copy_retcode = true;
}
if (ka->sa_flags & TARGET_SA_SIGINFO) {
idx += 2;
}
__put_user(retcodes[idx], rc);
retcode = rc_addr + thumb;
/* Copy the code to the stack slot for ABI compatibility. */
if (copy_retcode) {
memcpy(frame->retcode, g2h_untagged(retcode & ~1), RETCODE_BYTES);
}
env->regs[0] = usig;
if (is_fdpic) {
env->regs[9] = handler_fdpic_GOT;
}
env->regs[13] = frame_addr;
env->regs[13] = sp_addr;
env->regs[14] = retcode;
env->regs[15] = handler & (thumb ? ~1 : ~3);
cpsr_write(env, cpsr, CPSR_IT | CPSR_T | CPSR_E, CPSRWriteByInstr);
@ -294,7 +234,7 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
return 0;
}
static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
static abi_ulong *setup_sigframe_vfp(abi_ulong *regspace, CPUARMState *env)
{
int i;
struct target_vfp_sigframe *vfpframe;
@ -311,8 +251,7 @@ static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
return (abi_ulong*)(vfpframe+1);
}
static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
CPUARMState *env)
static abi_ulong *setup_sigframe_iwmmxt(abi_ulong *regspace, CPUARMState *env)
{
int i;
struct target_iwmmxt_sigframe *iwmmxtframe;
@ -331,15 +270,15 @@ static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
return (abi_ulong*)(iwmmxtframe+1);
}
static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
target_sigset_t *set, CPUARMState *env)
static void setup_sigframe(struct target_ucontext *uc,
target_sigset_t *set, CPUARMState *env)
{
struct target_sigaltstack stack;
int i;
abi_ulong *regspace;
/* Clear all the bits of the ucontext we don't use. */
memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
memset(uc, 0, offsetof(struct target_ucontext, tuc_mcontext));
memset(&stack, 0, sizeof(stack));
target_save_altstack(&stack, env);
@ -349,10 +288,10 @@ static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
/* Save coprocessor signal frame. */
regspace = uc->tuc_regspace;
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
regspace = setup_sigframe_v2_vfp(regspace, env);
regspace = setup_sigframe_vfp(regspace, env);
}
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
regspace = setup_sigframe_v2_iwmmxt(regspace, env);
regspace = setup_sigframe_iwmmxt(regspace, env);
}
/* Write terminating magic word */
@ -363,148 +302,23 @@ static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
}
}
/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
static void setup_frame_v1(int usig, struct target_sigaction *ka,
target_sigset_t *set, CPUARMState *regs)
{
struct sigframe_v1 *frame;
abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
int i;
trace_user_setup_frame(regs, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
goto sigsegv;
}
setup_sigcontext(&frame->sc, regs, set->sig[0]);
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
__put_user(set->sig[i], &frame->extramask[i - 1]);
}
if (setup_return(regs, ka, frame->retcode, frame_addr, usig,
frame_addr + offsetof(struct sigframe_v1, retcode))) {
goto sigsegv;
}
unlock_user_struct(frame, frame_addr, 1);
return;
sigsegv:
unlock_user_struct(frame, frame_addr, 1);
force_sigsegv(usig);
}
static void setup_frame_v2(int usig, struct target_sigaction *ka,
target_sigset_t *set, CPUARMState *regs)
{
struct sigframe_v2 *frame;
abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
trace_user_setup_frame(regs, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
goto sigsegv;
}
setup_sigframe_v2(&frame->uc, set, regs);
if (setup_return(regs, ka, frame->retcode, frame_addr, usig,
frame_addr + offsetof(struct sigframe_v2, retcode))) {
goto sigsegv;
}
unlock_user_struct(frame, frame_addr, 1);
return;
sigsegv:
unlock_user_struct(frame, frame_addr, 1);
force_sigsegv(usig);
}
void setup_frame(int usig, struct target_sigaction *ka,
target_sigset_t *set, CPUARMState *regs)
{
if (get_osversion() >= 0x020612) {
setup_frame_v2(usig, ka, set, regs);
} else {
setup_frame_v1(usig, ka, set, regs);
}
}
struct sigframe *frame;
abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUARMState *env)
{
struct rt_sigframe_v1 *frame;
abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
struct target_sigaltstack stack;
int i;
abi_ulong info_addr, uc_addr;
trace_user_setup_rt_frame(env, frame_addr);
trace_user_setup_frame(regs, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
goto sigsegv;
}
info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
__put_user(info_addr, &frame->pinfo);
uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
__put_user(uc_addr, &frame->puc);
tswap_siginfo(&frame->info, info);
setup_sigframe(&frame->uc, set, regs);
/* Clear all the bits of the ucontext we don't use. */
memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
memset(&stack, 0, sizeof(stack));
target_save_altstack(&stack, env);
memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
}
if (setup_return(env, ka, frame->retcode, frame_addr, usig,
frame_addr + offsetof(struct rt_sigframe_v1, retcode))) {
if (setup_return(regs, ka, usig, frame, frame_addr)) {
goto sigsegv;
}
env->regs[1] = info_addr;
env->regs[2] = uc_addr;
unlock_user_struct(frame, frame_addr, 1);
return;
sigsegv:
unlock_user_struct(frame, frame_addr, 1);
force_sigsegv(usig);
}
static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUARMState *env)
{
struct rt_sigframe_v2 *frame;
abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
abi_ulong info_addr, uc_addr;
trace_user_setup_rt_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
goto sigsegv;
}
info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
tswap_siginfo(&frame->info, info);
setup_sigframe_v2(&frame->uc, set, env);
if (setup_return(env, ka, frame->retcode, frame_addr, usig,
frame_addr + offsetof(struct rt_sigframe_v2, retcode))) {
goto sigsegv;
}
env->regs[1] = info_addr;
env->regs[2] = uc_addr;
unlock_user_struct(frame, frame_addr, 1);
return;
sigsegv:
@ -516,11 +330,33 @@ void setup_rt_frame(int usig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUARMState *env)
{
if (get_osversion() >= 0x020612) {
setup_rt_frame_v2(usig, ka, info, set, env);
} else {
setup_rt_frame_v1(usig, ka, info, set, env);
struct rt_sigframe *frame;
abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
abi_ulong info_addr, uc_addr;
trace_user_setup_rt_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
goto sigsegv;
}
info_addr = frame_addr + offsetof(struct rt_sigframe, info);
uc_addr = frame_addr + offsetof(struct rt_sigframe, sig.uc);
tswap_siginfo(&frame->info, info);
setup_sigframe(&frame->sig.uc, set, env);
if (setup_return(env, ka, usig, &frame->sig, frame_addr)) {
goto sigsegv;
}
env->regs[1] = info_addr;
env->regs[2] = uc_addr;
unlock_user_struct(frame, frame_addr, 1);
return;
sigsegv:
unlock_user_struct(frame, frame_addr, 1);
force_sigsegv(usig);
}
static int
@ -553,55 +389,7 @@ restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
return err;
}
static long do_sigreturn_v1(CPUARMState *env)
{
abi_ulong frame_addr;
struct sigframe_v1 *frame = NULL;
target_sigset_t set;
sigset_t host_set;
int i;
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
* not, then the user is trying to mess with us.
*/
frame_addr = env->regs[13];
trace_user_do_sigreturn(env, frame_addr);
if (frame_addr & 7) {
goto badframe;
}
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
}
__get_user(set.sig[0], &frame->sc.oldmask);
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
__get_user(set.sig[i], &frame->extramask[i - 1]);
}
target_to_host_sigset_internal(&host_set, &set);
set_sigmask(&host_set);
if (restore_sigcontext(env, &frame->sc)) {
goto badframe;
}
#if 0
/* Send SIGTRAP if we're single-stepping */
if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
#endif
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
badframe:
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
static abi_ulong *restore_sigframe_vfp(CPUARMState *env, abi_ulong *regspace)
{
int i;
abi_ulong magic, sz;
@ -631,8 +419,8 @@ static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
return (abi_ulong*)(vfpframe + 1);
}
static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
abi_ulong *regspace)
static abi_ulong *restore_sigframe_iwmmxt(CPUARMState *env,
abi_ulong *regspace)
{
int i;
abi_ulong magic, sz;
@ -656,9 +444,9 @@ static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
return (abi_ulong*)(iwmmxtframe + 1);
}
static int do_sigframe_return_v2(CPUARMState *env,
target_ulong context_addr,
struct target_ucontext_v2 *uc)
static int do_sigframe_return(CPUARMState *env,
target_ulong context_addr,
struct target_ucontext *uc)
{
sigset_t host_set;
abi_ulong *regspace;
@ -666,19 +454,20 @@ static int do_sigframe_return_v2(CPUARMState *env,
target_to_host_sigset(&host_set, &uc->tuc_sigmask);
set_sigmask(&host_set);
if (restore_sigcontext(env, &uc->tuc_mcontext))
if (restore_sigcontext(env, &uc->tuc_mcontext)) {
return 1;
}
/* Restore coprocessor signal frame */
regspace = uc->tuc_regspace;
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
regspace = restore_sigframe_v2_vfp(env, regspace);
regspace = restore_sigframe_vfp(env, regspace);
if (!regspace) {
return 1;
}
}
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
regspace = restore_sigframe_v2_iwmmxt(env, regspace);
regspace = restore_sigframe_iwmmxt(env, regspace);
if (!regspace) {
return 1;
}
@ -695,10 +484,10 @@ static int do_sigframe_return_v2(CPUARMState *env,
return 0;
}
static long do_sigreturn_v2(CPUARMState *env)
long do_sigreturn(CPUARMState *env)
{
abi_ulong frame_addr;
struct sigframe_v2 *frame = NULL;
struct sigframe *frame = NULL;
/*
* Since we stacked the signal on a 64-bit boundary,
@ -715,99 +504,9 @@ static long do_sigreturn_v2(CPUARMState *env)
goto badframe;
}
if (do_sigframe_return_v2(env,
frame_addr
+ offsetof(struct sigframe_v2, uc),
&frame->uc)) {
goto badframe;
}
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
long do_sigreturn(CPUARMState *env)
{
if (get_osversion() >= 0x020612) {
return do_sigreturn_v2(env);
} else {
return do_sigreturn_v1(env);
}
}
static long do_rt_sigreturn_v1(CPUARMState *env)
{
abi_ulong frame_addr;
struct rt_sigframe_v1 *frame = NULL;
sigset_t host_set;
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
* not, then the user is trying to mess with us.
*/
frame_addr = env->regs[13];
trace_user_do_rt_sigreturn(env, frame_addr);
if (frame_addr & 7) {
goto badframe;
}
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
}
target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
set_sigmask(&host_set);
if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
goto badframe;
}
target_restore_altstack(&frame->uc.tuc_stack, env);
#if 0
/* Send SIGTRAP if we're single-stepping */
if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
#endif
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
static long do_rt_sigreturn_v2(CPUARMState *env)
{
abi_ulong frame_addr;
struct rt_sigframe_v2 *frame = NULL;
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
* not, then the user is trying to mess with us.
*/
frame_addr = env->regs[13];
trace_user_do_rt_sigreturn(env, frame_addr);
if (frame_addr & 7) {
goto badframe;
}
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
}
if (do_sigframe_return_v2(env,
frame_addr
+ offsetof(struct rt_sigframe_v2, uc),
&frame->uc)) {
if (do_sigframe_return(env,
frame_addr + offsetof(struct sigframe, uc),
&frame->uc)) {
goto badframe;
}
@ -822,9 +521,110 @@ badframe:
long do_rt_sigreturn(CPUARMState *env)
{
if (get_osversion() >= 0x020612) {
return do_rt_sigreturn_v2(env);
} else {
return do_rt_sigreturn_v1(env);
abi_ulong frame_addr;
struct rt_sigframe *frame = NULL;
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
* not, then the user is trying to mess with us.
*/
frame_addr = env->regs[13];
trace_user_do_rt_sigreturn(env, frame_addr);
if (frame_addr & 7) {
goto badframe;
}
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
}
if (do_sigframe_return(env,
frame_addr + offsetof(struct rt_sigframe, sig.uc),
&frame->sig.uc)) {
goto badframe;
}
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
/*
* EABI syscalls pass the number via r7.
* Note that the kernel still adds the OABI syscall number to the trap,
* presumably for backward ABI compatibility with unwinders.
*/
#define ARM_MOV_R7_IMM(X) (0xe3a07000 | (X))
#define ARM_SWI_SYS(X) (0xef000000 | (X) | ARM_SYSCALL_BASE)
#define THUMB_MOVS_R7_IMM(X) (0x2700 | (X))
#define THUMB_SWI_SYS 0xdf00
static void write_arm_sigreturn(uint32_t *rc, int syscall)
{
__put_user(ARM_MOV_R7_IMM(syscall), rc);
__put_user(ARM_SWI_SYS(syscall), rc + 1);
/* Wrote 8 of 12 bytes */
}
static void write_thm_sigreturn(uint32_t *rc, int syscall)
{
__put_user(THUMB_SWI_SYS << 16 | THUMB_MOVS_R7_IMM(syscall), rc);
/* Wrote 4 of 12 bytes */
}
/*
* Stub needed to make sure the FD register (r9) contains the right value.
* Use the same instruction sequence as the kernel.
*/
static void write_arm_fdpic_sigreturn(uint32_t *rc, int ofs)
{
assert(ofs <= 0xfff);
__put_user(0xe59d3000 | ofs, rc + 0); /* ldr r3, [sp, #ofs] */
__put_user(0xe8930908, rc + 1); /* ldm r3, { r3, r9 } */
__put_user(0xe12fff13, rc + 2); /* bx r3 */
/* Wrote 12 of 12 bytes */
}
static void write_thm_fdpic_sigreturn(void *vrc, int ofs)
{
uint16_t *rc = vrc;
assert((ofs & ~0x3fc) == 0);
__put_user(0x9b00 | (ofs >> 2), rc + 0); /* ldr r3, [sp, #ofs] */
__put_user(0xcb0c, rc + 1); /* ldm r3, { r2, r3 } */
__put_user(0x4699, rc + 2); /* mov r9, r3 */
__put_user(0x4710, rc + 3); /* bx r2 */
/* Wrote 8 of 12 bytes */
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t total_size = 8 * RETCODE_BYTES;
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, total_size, 0);
assert(tramp != NULL);
default_sigreturn = sigtramp_page;
write_arm_sigreturn(&tramp[0 * RETCODE_WORDS], TARGET_NR_sigreturn);
write_thm_sigreturn(&tramp[1 * RETCODE_WORDS], TARGET_NR_sigreturn);
write_arm_sigreturn(&tramp[2 * RETCODE_WORDS], TARGET_NR_rt_sigreturn);
write_thm_sigreturn(&tramp[3 * RETCODE_WORDS], TARGET_NR_rt_sigreturn);
sigreturn_fdpic_tramp = sigtramp_page + 4 * RETCODE_BYTES;
write_arm_fdpic_sigreturn(tramp + 4 * RETCODE_WORDS,
offsetof(struct sigframe, retcode[3]));
write_thm_fdpic_sigreturn(tramp + 5 * RETCODE_WORDS,
offsetof(struct sigframe, retcode[3]));
write_arm_fdpic_sigreturn(tramp + 6 * RETCODE_WORDS,
offsetof(struct rt_sigframe, sig.retcode[3]));
write_thm_fdpic_sigreturn(tramp + 7 * RETCODE_WORDS,
offsetof(struct rt_sigframe, sig.retcode[3]));
unlock_user(tramp, sigtramp_page, total_size);
}

View File

@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* ARM_TARGET_SIGNAL_H */

View File

@ -97,6 +97,14 @@ static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
return sp - framesize;
}
static void setup_sigreturn(uint16_t *retcode)
{
/* This is movu.w __NR_sigreturn, r9; break 13; */
__put_user(0x9c5f, retcode + 0);
__put_user(TARGET_NR_sigreturn, retcode + 1);
__put_user(0xe93d, retcode + 2);
}
void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUCRISState *env)
{
@ -112,14 +120,8 @@ void setup_frame(int sig, struct target_sigaction *ka,
/*
* The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
* use this trampoline anymore but it sets it up for GDB.
* In QEMU, using the trampoline simplifies things a bit so we use it.
*
* This is movu.w __NR_sigreturn, r9; break 13;
*/
__put_user(0x9c5f, frame->retcode+0);
__put_user(TARGET_NR_sigreturn,
frame->retcode + 1);
__put_user(0xe93d, frame->retcode + 2);
setup_sigreturn(frame->retcode);
/* Save the mask. */
__put_user(set->sig[0], &frame->sc.oldmask);
@ -135,7 +137,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
env->regs[10] = sig;
env->pc = (unsigned long) ka->_sa_handler;
/* Link SRP so the guest returns through the trampoline. */
env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
env->pregs[PR_SRP] = default_sigreturn;
unlock_user_struct(frame, frame_addr, 1);
return;
@ -187,3 +189,14 @@ long do_rt_sigreturn(CPUCRISState *env)
qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
return -TARGET_ENOSYS;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0);
assert(tramp != NULL);
default_sigreturn = sigtramp_page;
setup_sigreturn(tramp);
unlock_user(tramp, sigtramp_page, 6);
}

View File

@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* CRIS_TARGET_SIGNAL_H */

View File

@ -7,6 +7,7 @@
#include "qemu.h"
#include "user-internals.h"
#include "signal-common.h"
#include "loader.h"
#include "user-mmap.h"
#include "disas/disas.h"
@ -17,6 +18,7 @@
#include "qemu/units.h"
#include "qemu/selfmap.h"
#include "qapi/error.h"
#include "target_signal.h"
#ifdef _ARCH_PPC64
#undef ARCH_DLINFO
@ -3249,6 +3251,18 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
#endif
}
/*
* TODO: load a vdso, which would also contain the signal trampolines.
* Otherwise, allocate a private page to hold them.
*/
if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
abi_ulong tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
setup_sigtramp(tramp_page);
target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
}
bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
info, (elf_interpreter ? &interp_info : NULL));
info->start_stack = bprm->p;

View File

@ -162,6 +162,11 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
setup_ucontext(&frame->uc, env, set);
tswap_siginfo(&frame->info, info);
/*
* The on-stack signal trampoline is no longer executed;
* however, the libgcc signal frame unwinding code checks
* for the presence of these two numeric magic values.
*/
install_sigtramp(frame->tramp);
env->gpr[HEX_REG_PC] = ka->_sa_handler;
@ -171,8 +176,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
frame_addr + offsetof(struct target_rt_sigframe, info);
env->gpr[HEX_REG_R02] =
frame_addr + offsetof(struct target_rt_sigframe, uc);
env->gpr[HEX_REG_LR] =
frame_addr + offsetof(struct target_rt_sigframe, tramp);
env->gpr[HEX_REG_LR] = default_rt_sigreturn;
return;
@ -271,3 +275,14 @@ badframe:
force_sig(TARGET_SIGSEGV);
return 0;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 4 * 2, 0);
assert(tramp != NULL);
default_rt_sigreturn = sigtramp_page;
install_sigtramp(tramp);
unlock_user(tramp, sigtramp_page, 4 * 2);
}

View File

@ -31,4 +31,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* TARGET_SIGNAL_H */

View File

@ -71,4 +71,18 @@ typedef struct target_sigaltstack {
/* mask for all SS_xxx flags */
#define TARGET_SS_FLAG_BITS TARGET_SS_AUTODISARM
/*
* We cannot use a bare sigtramp page for hppa-linux.
*
* Unlike other guests where we use the instructions at PC to validate
* an offset from SP, the hppa libgcc signal frame fallback unwinding uses
* the PC address itself to find the frame. This is due to the fact that
* the hppa grows the stack upward, and the frame is of unknown size.
*
* TODO: We should be able to use a VDSO to address this, by providing
* proper unwind info for the sigtramp code, at which point the fallback
* unwinder will not be used.
*/
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
#endif /* HPPA_TARGET_SIGNAL_H */

View File

@ -310,6 +310,22 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
}
#ifndef TARGET_X86_64
static void install_sigtramp(void *tramp)
{
/* This is popl %eax ; movl $syscall,%eax ; int $0x80 */
__put_user(0xb858, (uint16_t *)(tramp + 0));
__put_user(TARGET_NR_sigreturn, (int32_t *)(tramp + 2));
__put_user(0x80cd, (uint16_t *)(tramp + 6));
}
static void install_rt_sigtramp(void *tramp)
{
/* This is movl $syscall,%eax ; int $0x80 */
__put_user(0xb8, (uint8_t *)(tramp + 0));
__put_user(TARGET_NR_rt_sigreturn, (int32_t *)(tramp + 1));
__put_user(0x80cd, (uint16_t *)(tramp + 5));
}
/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUX86State *env)
@ -338,16 +354,9 @@ void setup_frame(int sig, struct target_sigaction *ka,
if (ka->sa_flags & TARGET_SA_RESTORER) {
__put_user(ka->sa_restorer, &frame->pretcode);
} else {
uint16_t val16;
abi_ulong retcode_addr;
retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
__put_user(retcode_addr, &frame->pretcode);
/* This is popl %eax ; movl $,%eax ; int $0x80 */
val16 = 0xb858;
__put_user(val16, (uint16_t *)(frame->retcode+0));
__put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
val16 = 0x80cd;
__put_user(val16, (uint16_t *)(frame->retcode+6));
/* This is no longer used, but is retained for ABI compatibility. */
install_sigtramp(frame->retcode);
__put_user(default_sigreturn, &frame->pretcode);
}
/* Set up registers for signal handler */
@ -412,24 +421,18 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
#ifndef TARGET_X86_64
if (ka->sa_flags & TARGET_SA_RESTORER) {
__put_user(ka->sa_restorer, &frame->pretcode);
} else {
uint16_t val16;
addr = frame_addr + offsetof(struct rt_sigframe, retcode);
__put_user(addr, &frame->pretcode);
/* This is movl $,%eax ; int $0x80 */
__put_user(0xb8, (char *)(frame->retcode+0));
__put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
val16 = 0x80cd;
__put_user(val16, (uint16_t *)(frame->retcode+5));
}
#ifdef TARGET_X86_64
/* For x86_64, SA_RESTORER is required ABI. */
goto give_sigsegv;
#else
/* XXX: Would be slightly better to return -EFAULT here if test fails
assert(ka->sa_flags & TARGET_SA_RESTORER); */
__put_user(ka->sa_restorer, &frame->pretcode);
/* This is no longer used, but is retained for ABI compatibility. */
install_rt_sigtramp(frame->retcode);
__put_user(default_rt_sigreturn, &frame->pretcode);
#endif
}
/* Set up registers for signal handler */
env->regs[R_ESP] = frame_addr;
@ -592,3 +595,19 @@ badframe:
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
#ifndef TARGET_X86_64
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
assert(tramp != NULL);
default_sigreturn = sigtramp_page;
install_sigtramp(tramp);
default_rt_sigreturn = sigtramp_page + 8;
install_rt_sigtramp(tramp + 8);
unlock_user(tramp, sigtramp_page, 2 * 8);
}
#endif

View File

@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* I386_TARGET_SIGNAL_H */

View File

@ -39,7 +39,6 @@ struct target_sigframe
int sig;
int code;
abi_ulong psc;
char retcode[8];
abi_ulong extramask[TARGET_NSIG_WORDS-1];
struct target_sigcontext sc;
};
@ -76,7 +75,6 @@ struct target_rt_sigframe
int sig;
abi_ulong pinfo;
abi_ulong puc;
char retcode[8];
struct target_siginfo info;
struct target_ucontext uc;
};
@ -130,7 +128,6 @@ void setup_frame(int sig, struct target_sigaction *ka,
{
struct target_sigframe *frame;
abi_ulong frame_addr;
abi_ulong retcode_addr;
abi_ulong sc_addr;
int i;
@ -152,16 +149,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
}
/* Set up to return from userspace. */
retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
__put_user(retcode_addr, &frame->pretcode);
/* moveq #,d0; trap #0 */
__put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
(uint32_t *)(frame->retcode));
/* Set up to return from userspace */
__put_user(default_sigreturn, &frame->pretcode);
env->aregs[7] = frame_addr;
env->pc = ka->_sa_handler;
@ -288,7 +276,6 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
{
struct target_rt_sigframe *frame;
abi_ulong frame_addr;
abi_ulong retcode_addr;
abi_ulong info_addr;
abi_ulong uc_addr;
int err = 0;
@ -325,17 +312,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
}
/* Set up to return from userspace. */
retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
__put_user(retcode_addr, &frame->pretcode);
/* moveq #,d0; notb d0; trap #0 */
__put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
(uint32_t *)(frame->retcode + 0));
__put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
/* Set up to return from userspace */
__put_user(default_rt_sigreturn, &frame->pretcode);
env->aregs[7] = frame_addr;
env->pc = ka->_sa_handler;
@ -411,3 +388,23 @@ badframe:
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
void *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 4 + 6, 0);
assert(tramp != NULL);
default_sigreturn = sigtramp_page;
/* moveq #,d0; trap #0 */
__put_user(0x70004e40 + (TARGET_NR_sigreturn << 16), (uint32_t *)tramp);
default_rt_sigreturn = sigtramp_page + 4;
/* moveq #,d0; notb d0; trap #0 */
__put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
(uint32_t *)(tramp + 4));
__put_user(0x4e40, (uint16_t *)(tramp + 8));
unlock_user(tramp, sigtramp_page, 4 + 6);
}

View File

@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* M68K_TARGET_SIGNAL_H */

View File

@ -161,17 +161,11 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
/* Kernel does not use SA_RESTORER. */
/* addi r12, r0, __NR_sigreturn */
__put_user(0x31800000U | TARGET_NR_rt_sigreturn, frame->tramp + 0);
/* brki r14, 0x8 */
__put_user(0xb9cc0008U, frame->tramp + 1);
/*
* Return from sighandler will jump to the tramp.
* Negative 8 offset because return is rtsd r15, 8
*/
env->regs[15] =
frame_addr + offsetof(struct target_rt_sigframe, tramp) - 8;
env->regs[15] = default_rt_sigreturn - 8;
/* Set up registers for signal handler */
env->regs[1] = frame_addr;
@ -220,3 +214,19 @@ long do_rt_sigreturn(CPUMBState *env)
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
assert(tramp != NULL);
/*
* addi r12, r0, __NR_rt_sigreturn
* brki r14, 0x8
*/
__put_user(0x31800000U | TARGET_NR_rt_sigreturn, tramp);
__put_user(0xb9cc0008U, tramp + 1);
default_rt_sigreturn = sigtramp_page;
unlock_user(tramp, sigtramp_page, 8);
}

View File

@ -21,4 +21,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* MICROBLAZE_TARGET_SIGNAL_H */

View File

@ -87,10 +87,8 @@ struct target_rt_sigframe {
};
/* Install trampoline to jump back from signal handler */
static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
static void install_sigtramp(uint32_t *tramp, unsigned int syscall)
{
int err = 0;
/*
* Set up the return code ...
*
@ -100,7 +98,6 @@ static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
__put_user(0x24020000 + syscall, tramp + 0);
__put_user(0x0000000c , tramp + 1);
return err;
}
static inline void setup_sigcontext(CPUMIPSState *regs,
@ -212,8 +209,6 @@ void setup_frame(int sig, struct target_sigaction * ka,
goto give_sigsegv;
}
install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
setup_sigcontext(regs, &frame->sf_sc);
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
@ -234,7 +229,7 @@ void setup_frame(int sig, struct target_sigaction * ka,
regs->active_tc.gpr[ 5] = 0;
regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
regs->active_tc.gpr[29] = frame_addr;
regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
regs->active_tc.gpr[31] = default_sigreturn;
/* The original kernel code sets CP0_EPC to the handler
* since it returns to userland using eret
* we cannot do this here, and we must set PC directly */
@ -308,8 +303,6 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
goto give_sigsegv;
}
install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
tswap_siginfo(&frame->rs_info, info);
__put_user(0, &frame->rs_uc.tuc_flags);
@ -338,11 +331,13 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
env->active_tc.gpr[ 6] = frame_addr
+ offsetof(struct target_rt_sigframe, rs_uc);
env->active_tc.gpr[29] = frame_addr;
env->active_tc.gpr[31] = frame_addr
+ offsetof(struct target_rt_sigframe, rs_code);
/* The original kernel code sets CP0_EPC to the handler
* since it returns to userland using eret
* we cannot do this here, and we must set PC directly */
env->active_tc.gpr[31] = default_rt_sigreturn;
/*
* The original kernel code sets CP0_EPC to the handler
* since it returns to userland using eret
* we cannot do this here, and we must set PC directly
*/
env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
mips_set_hflags_isa_mode_from_pc(env);
unlock_user_struct(frame, frame_addr, 1);
@ -382,3 +377,19 @@ badframe:
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
assert(tramp != NULL);
#ifdef TARGET_ARCH_HAS_SETUP_FRAME
default_sigreturn = sigtramp_page;
install_sigtramp(tramp, TARGET_NR_sigreturn);
#endif
default_rt_sigreturn = sigtramp_page + 8;
install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);
unlock_user(tramp, sigtramp_page, 2 * 8);
}

View File

@ -73,6 +73,7 @@ typedef struct target_sigaltstack {
/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
#define TARGET_ARCH_HAS_SETUP_FRAME
#endif
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
/* bit-flags */
#define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */

View File

@ -76,4 +76,6 @@ typedef struct target_sigaltstack {
/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
#define TARGET_ARCH_HAS_SETUP_FRAME
#endif
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* MIPS64_TARGET_SIGNAL_H */

View File

@ -19,4 +19,7 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
/* Nios2 uses a fixed address on the kuser page for sigreturn. */
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
#endif /* NIOS2_TARGET_SIGNAL_H */

View File

@ -38,7 +38,6 @@ typedef struct target_ucontext {
typedef struct target_rt_sigframe {
struct target_siginfo info;
target_ucontext uc;
uint32_t retcode[4]; /* trampoline code */
} target_rt_sigframe;
static void restore_sigcontext(CPUOpenRISCState *env, target_sigcontext *sc)
@ -116,14 +115,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
}
/* This is l.ori r11,r0,__NR_sigreturn; l.sys 1; l.nop; l.nop */
__put_user(0xa9600000 | TARGET_NR_rt_sigreturn, frame->retcode + 0);
__put_user(0x20000001, frame->retcode + 1);
__put_user(0x15000000, frame->retcode + 2);
__put_user(0x15000000, frame->retcode + 3);
/* Set up registers for signal handler */
cpu_set_gpr(env, 9, frame_addr + offsetof(target_rt_sigframe, retcode));
cpu_set_gpr(env, 9, default_rt_sigreturn);
cpu_set_gpr(env, 3, sig);
cpu_set_gpr(env, 4, frame_addr + offsetof(target_rt_sigframe, info));
cpu_set_gpr(env, 5, frame_addr + offsetof(target_rt_sigframe, uc));
@ -169,3 +162,16 @@ long do_rt_sigreturn(CPUOpenRISCState *env)
force_sig(TARGET_SIGSEGV);
return 0;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
assert(tramp != NULL);
/* This is l.ori r11,r0,__NR_sigreturn; l.sys 1 */
__put_user(0xa9600000 | TARGET_NR_rt_sigreturn, tramp + 0);
__put_user(0x20000001, tramp + 1);
default_rt_sigreturn = sigtramp_page;
unlock_user(tramp, sigtramp_page, 8);
}

View File

@ -26,4 +26,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* OPENRISC_TARGET_SIGNAL_H */

View File

@ -203,9 +203,6 @@ struct target_func_ptr {
#endif
/* We use the mc_pad field for the signal return trampoline. */
#define tramp mc_pad
/* See arch/powerpc/kernel/signal.c. */
static target_ulong get_sigframe(struct target_sigaction *ka,
CPUPPCState *env,
@ -309,10 +306,8 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
static void encode_trampoline(int sigret, uint32_t *tramp)
{
/* Set up the sigreturn trampoline: li r0,sigret; sc. */
if (sigret) {
__put_user(0x38000000 | sigret, &tramp[0]);
__put_user(0x44000002, &tramp[1]);
}
__put_user(0x38000000 | sigret, &tramp[0]);
__put_user(0x44000002, &tramp[1]);
}
static void restore_user_regs(CPUPPCState *env,
@ -438,12 +433,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
/* Save user regs. */
save_user_regs(env, &frame->mctx);
/* Construct the trampoline code on the stack. */
encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
/* The kernel checks for the presence of a VDSO here. We don't
emulate a vdso, so use a sigreturn system call. */
env->lr = (target_ulong) h2g(frame->mctx.tramp);
env->lr = default_sigreturn;
/* Turn off all fp exceptions. */
env->fpscr = 0;
@ -479,7 +469,6 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUPPCState *env)
{
struct target_rt_sigframe *rt_sf;
uint32_t *trampptr = 0;
struct target_mcontext *mctx = 0;
target_ulong rt_sf_addr, newsp = 0;
int i, err = 0;
@ -509,22 +498,17 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
#if defined(TARGET_PPC64)
mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
trampptr = &rt_sf->trampoline[0];
sc = &rt_sf->uc.tuc_sigcontext;
__put_user(h2g(mctx), &sc->regs);
__put_user(sig, &sc->signal);
#else
mctx = &rt_sf->uc.tuc_mcontext;
trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
#endif
save_user_regs(env, mctx);
encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
/* The kernel checks for the presence of a VDSO here. We don't
emulate a vdso, so use a sigreturn system call. */
env->lr = (target_ulong) h2g(trampptr);
env->lr = default_rt_sigreturn;
/* Turn off all fp exceptions. */
env->fpscr = 0;
@ -722,3 +706,19 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
return 0;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
assert(tramp != NULL);
#ifdef TARGET_ARCH_HAS_SETUP_FRAME
default_sigreturn = sigtramp_page;
encode_trampoline(TARGET_NR_sigreturn, tramp + 0);
#endif
default_rt_sigreturn = sigtramp_page + 8;
encode_trampoline(TARGET_NR_rt_sigreturn, tramp + 2);
unlock_user(tramp, sigtramp_page, 2 * 8);
}

View File

@ -24,4 +24,6 @@ typedef struct target_sigaltstack {
#if !defined(TARGET_PPC64)
#define TARGET_ARCH_HAS_SETUP_FRAME
#endif
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* PPC_TARGET_SIGNAL_H */

View File

@ -47,7 +47,6 @@ struct target_ucontext {
};
struct target_rt_sigframe {
uint32_t tramp[2]; /* not in kernel, which uses VDSO instead */
struct target_siginfo info;
struct target_ucontext uc;
};
@ -105,12 +104,6 @@ static void setup_ucontext(struct target_ucontext *uc,
setup_sigcontext(&uc->uc_mcontext, env);
}
static inline void install_sigtramp(uint32_t *tramp)
{
__put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
__put_user(0x00000073, tramp + 1); /* ecall */
}
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPURISCVState *env)
@ -127,14 +120,13 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
setup_ucontext(&frame->uc, env, set);
tswap_siginfo(&frame->info, info);
install_sigtramp(frame->tramp);
env->pc = ka->_sa_handler;
env->gpr[xSP] = frame_addr;
env->gpr[xA0] = sig;
env->gpr[xA1] = frame_addr + offsetof(struct target_rt_sigframe, info);
env->gpr[xA2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
env->gpr[xRA] = frame_addr + offsetof(struct target_rt_sigframe, tramp);
env->gpr[xRA] = default_rt_sigreturn;
return;
@ -203,3 +195,15 @@ badframe:
force_sig(TARGET_SIGSEGV);
return 0;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
assert(tramp != NULL);
__put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
__put_user(0x00000073, tramp + 1); /* ecall */
default_rt_sigreturn = sigtramp_page;
unlock_user(tramp, sigtramp_page, 8);
}

View File

@ -15,4 +15,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* RISCV_TARGET_SIGNAL_H */

View File

@ -68,7 +68,6 @@ typedef struct {
target_sigregs sregs;
int signo;
target_sigregs_ext sregs_ext;
uint16_t retcode;
} sigframe;
#define TARGET_UC_VXRS 2
@ -85,7 +84,6 @@ struct target_ucontext {
typedef struct {
uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
uint16_t retcode;
struct target_siginfo info;
struct target_ucontext uc;
} rt_sigframe;
@ -209,9 +207,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
if (ka->sa_flags & TARGET_SA_RESTORER) {
restorer = ka->sa_restorer;
} else {
restorer = frame_addr + offsetof(sigframe, retcode);
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
&frame->retcode);
restorer = default_sigreturn;
}
/* Set up registers for signal handler */
@ -262,9 +258,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
if (ka->sa_flags & TARGET_SA_RESTORER) {
restorer = ka->sa_restorer;
} else {
restorer = frame_addr + offsetof(typeof(*frame), retcode);
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
&frame->retcode);
restorer = default_rt_sigreturn;
}
/* Create siginfo on the signal stack. */
@ -405,3 +399,17 @@ long do_rt_sigreturn(CPUS390XState *env)
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 + 2, 0);
assert(tramp != NULL);
default_sigreturn = sigtramp_page;
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, &tramp[0]);
default_rt_sigreturn = sigtramp_page + 2;
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn, &tramp[1]);
unlock_user(tramp, sigtramp_page, 2 + 2);
}

View File

@ -19,4 +19,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* S390X_TARGET_SIGNAL_H */

View File

@ -52,7 +52,6 @@ struct target_sigframe
{
struct target_sigcontext sc;
target_ulong extramask[TARGET_NSIG_WORDS-1];
uint16_t retcode[3];
};
@ -68,7 +67,6 @@ struct target_rt_sigframe
{
struct target_siginfo info;
struct target_ucontext uc;
uint16_t retcode[3];
};
@ -190,15 +188,9 @@ void setup_frame(int sig, struct target_sigaction *ka,
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa_flags & TARGET_SA_RESTORER) {
regs->pr = (unsigned long) ka->sa_restorer;
regs->pr = ka->sa_restorer;
} else {
/* Generate return code (system call to sigreturn) */
abi_ulong retcode_addr = frame_addr +
offsetof(struct target_sigframe, retcode);
__put_user(MOVW(2), &frame->retcode[0]);
__put_user(TRAP_NOARG, &frame->retcode[1]);
__put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
regs->pr = (unsigned long) retcode_addr;
regs->pr = default_sigreturn;
}
/* Set up registers for signal handler */
@ -248,15 +240,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa_flags & TARGET_SA_RESTORER) {
regs->pr = (unsigned long) ka->sa_restorer;
regs->pr = ka->sa_restorer;
} else {
/* Generate return code (system call to sigreturn) */
abi_ulong retcode_addr = frame_addr +
offsetof(struct target_rt_sigframe, retcode);
__put_user(MOVW(2), &frame->retcode[0]);
__put_user(TRAP_NOARG, &frame->retcode[1]);
__put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
regs->pr = (unsigned long) retcode_addr;
regs->pr = default_rt_sigreturn;
}
/* Set up registers for signal handler */
@ -334,3 +320,21 @@ badframe:
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 6, 0);
assert(tramp != NULL);
default_sigreturn = sigtramp_page;
__put_user(MOVW(2), &tramp[0]);
__put_user(TRAP_NOARG, &tramp[1]);
__put_user(TARGET_NR_sigreturn, &tramp[2]);
default_rt_sigreturn = sigtramp_page + 6;
__put_user(MOVW(2), &tramp[3]);
__put_user(TRAP_NOARG, &tramp[4]);
__put_user(TARGET_NR_rt_sigreturn, &tramp[5]);
unlock_user(tramp, sigtramp_page, 2 * 6);
}

View File

@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif /* SH4_TARGET_SIGNAL_H */

View File

@ -20,6 +20,12 @@
#ifndef SIGNAL_COMMON_H
#define SIGNAL_COMMON_H
/* Fallback addresses into sigtramp page. */
extern abi_ulong default_sigreturn;
extern abi_ulong default_rt_sigreturn;
void setup_sigtramp(abi_ulong tramp_page);
int on_sig_stack(unsigned long sp);
int sas_ss_flags(unsigned long sp);
abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka);

View File

@ -35,6 +35,9 @@ static struct target_sigaction sigact_table[TARGET_NSIG];
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc);
/* Fallback addresses into sigtramp page. */
abi_ulong default_sigreturn;
abi_ulong default_rt_sigreturn;
/*
* System includes define _NSIG as SIGRTMAX + 1,

View File

@ -242,6 +242,12 @@ static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env)
}
#ifdef TARGET_ARCH_HAS_SETUP_FRAME
static void install_sigtramp(uint32_t *tramp, int syscall)
{
__put_user(0x82102000u + syscall, &tramp[0]); /* mov syscall, %g1 */
__put_user(0x91d02010u, &tramp[1]); /* t 0x10 */
}
void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUSPARCState *env)
{
@ -291,13 +297,9 @@ void setup_frame(int sig, struct target_sigaction *ka,
if (ka->ka_restorer) {
env->regwptr[WREG_O7] = ka->ka_restorer;
} else {
env->regwptr[WREG_O7] = sf_addr +
offsetof(struct target_signal_frame, insns) - 2 * 4;
/* mov __NR_sigreturn, %g1 */
__put_user(0x821020d8u, &sf->insns[0]);
/* t 0x10 */
__put_user(0x91d02010u, &sf->insns[1]);
/* Not used, but retain for ABI compatibility. */
install_sigtramp(sf->insns, TARGET_NR_sigreturn);
env->regwptr[WREG_O7] = default_sigreturn;
}
unlock_user(sf, sf_addr, sf_size);
}
@ -358,13 +360,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
if (ka->ka_restorer) {
env->regwptr[WREG_O7] = ka->ka_restorer;
} else {
env->regwptr[WREG_O7] =
sf_addr + offsetof(struct target_rt_signal_frame, insns) - 2 * 4;
/* mov __NR_rt_sigreturn, %g1 */
__put_user(0x82102065u, &sf->insns[0]);
/* t 0x10 */
__put_user(0x91d02010u, &sf->insns[1]);
/* Not used, but retain for ABI compatibility. */
install_sigtramp(sf->insns, TARGET_NR_rt_sigreturn);
env->regwptr[WREG_O7] = default_rt_sigreturn;
}
#else
env->regwptr[WREG_O7] = ka->ka_restorer;
@ -775,4 +773,18 @@ do_sigsegv:
unlock_user_struct(ucp, ucp_addr, 1);
force_sig(TARGET_SIGSEGV);
}
#else
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
assert(tramp != NULL);
default_sigreturn = sigtramp_page;
install_sigtramp(tramp, TARGET_NR_sigreturn);
default_rt_sigreturn = sigtramp_page + 8;
install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);
unlock_user(tramp, sigtramp_page, 2 * 8);
}
#endif

View File

@ -69,6 +69,10 @@ typedef struct target_sigaltstack {
#ifdef TARGET_ABI32
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#else
/* For sparc64, use of KA_RESTORER is mandatory. */
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
#endif
/* bit-flags */

View File

@ -21,4 +21,7 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
/* For x86_64, use of SA_RESTORER is mandatory. */
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
#endif /* X86_64_TARGET_SIGNAL_H */

View File

@ -128,6 +128,29 @@ static int setup_sigcontext(struct target_rt_sigframe *frame,
return 1;
}
static void install_sigtramp(uint8_t *tramp)
{
#ifdef TARGET_WORDS_BIGENDIAN
/* Generate instruction: MOVI a2, __NR_rt_sigreturn */
__put_user(0x22, &tramp[0]);
__put_user(0x0a, &tramp[1]);
__put_user(TARGET_NR_rt_sigreturn, &tramp[2]);
/* Generate instruction: SYSCALL */
__put_user(0x00, &tramp[3]);
__put_user(0x05, &tramp[4]);
__put_user(0x00, &tramp[5]);
#else
/* Generate instruction: MOVI a2, __NR_rt_sigreturn */
__put_user(0x22, &tramp[0]);
__put_user(0xa0, &tramp[1]);
__put_user(TARGET_NR_rt_sigreturn, &tramp[2]);
/* Generate instruction: SYSCALL */
__put_user(0x00, &tramp[3]);
__put_user(0x50, &tramp[4]);
__put_user(0x00, &tramp[5]);
#endif
}
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUXtensaState *env)
@ -164,26 +187,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
if (ka->sa_flags & TARGET_SA_RESTORER) {
ra = ka->sa_restorer;
} else {
ra = frame_addr + offsetof(struct target_rt_sigframe, retcode);
#ifdef TARGET_WORDS_BIGENDIAN
/* Generate instruction: MOVI a2, __NR_rt_sigreturn */
__put_user(0x22, &frame->retcode[0]);
__put_user(0x0a, &frame->retcode[1]);
__put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
/* Generate instruction: SYSCALL */
__put_user(0x00, &frame->retcode[3]);
__put_user(0x05, &frame->retcode[4]);
__put_user(0x00, &frame->retcode[5]);
#else
/* Generate instruction: MOVI a2, __NR_rt_sigreturn */
__put_user(0x22, &frame->retcode[0]);
__put_user(0xa0, &frame->retcode[1]);
__put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
/* Generate instruction: SYSCALL */
__put_user(0x00, &frame->retcode[3]);
__put_user(0x50, &frame->retcode[4]);
__put_user(0x00, &frame->retcode[5]);
#endif
/* Not used, but retain for ABI compatibility. */
install_sigtramp(frame->retcode);
ra = default_rt_sigreturn;
}
memset(env->regs, 0, sizeof(env->regs));
env->pc = ka->_sa_handler;
@ -264,3 +270,13 @@ badframe:
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
void setup_sigtramp(abi_ulong sigtramp_page)
{
uint8_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0);
assert(tramp != NULL);
default_rt_sigreturn = sigtramp_page;
install_sigtramp(tramp);
unlock_user(tramp, sigtramp_page, 6);
}

View File

@ -20,4 +20,6 @@ typedef struct target_sigaltstack {
#include "../generic/signal.h"
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
#endif

View File

@ -5,3 +5,10 @@
# On parisc Linux supports 4K/16K/64K (but currently only 4k works)
EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-16384 run-test-mmap-65536
# This triggers failures for hppa-linux about 1% of the time
# HPPA is the odd target that can't use the sigtramp page;
# it requires the full vdso with dwarf2 unwind info.
run-signals: signals
$(call skip-test, $<, "BROKEN awaiting vdso support")
run-plugin-signals-with-%:
$(call skip-test, $<, "BROKEN awaiting vdso support")

View File

@ -65,9 +65,6 @@ run-plugin-%-with-libinsn.so:
-d plugin -D $*-with-libinsn.so.pout $*, \
"$* (inline) on $(TARGET_NAME)")
run-plugin-signals-with-libinsn.so:
$(call skip-test, $<, "BROKEN awaiting sigframe clean-ups and vdso support")
# Update TESTS
I386_TESTS:=$(filter-out $(SKIP_I386_TESTS), $(ALL_X86_TESTS))
TESTS=$(MULTIARCH_TESTS) $(I386_TESTS)

View File

@ -32,14 +32,6 @@ threadcount: LDFLAGS+=-lpthread
signals: LDFLAGS+=-lrt -lpthread
# This triggers failures on s390x hosts about 4% of the time
# This triggers failures for hppa-linux about 1% of the time
run-signals: signals
$(call skip-test, $<, "BROKEN awaiting sigframe clean-ups and vdso support")
run-plugin-signals-with-%:
$(call skip-test, $<, "BROKEN awaiting sigframe clean-ups and vdso support")
# We define the runner for test-mmap after the individual
# architectures have defined their supported pages sizes. If no
# additional page sizes are defined we only run the default test.

View File

@ -5,3 +5,10 @@
# On sh Linux supports 4k, 8k, 16k and 64k pages (but only 4k currently works)
EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-8192 run-test-mmap-16384 run-test-mmap-65536
# This triggers failures for sh4-linux about 10% of the time.
# Random SIGSEGV at unpredictable guest address, cause unknown.
run-signals: signals
$(call skip-test, $<, "BROKEN")
run-plugin-signals-with-%:
$(call skip-test, $<, "BROKEN")