From a99856cd7f30b8c64cfaf97791dc5d462dabad6e Mon Sep 17 00:00:00 2001 From: Christophe Lyon Date: Mon, 30 Apr 2018 10:03:41 +0200 Subject: [PATCH 1/6] Remove CONFIG_USE_FDPIC. We want to avoid code disabled by default, because it ends up less tested. This patch removes all instances of #ifdef CONFIG_USE_FDPIC, most of which can be safely kept. For the ones that should be conditionally executed, we define elf_is_fdpic(). Without this patch, defining CONFIG_USE_FDPIC would prevent QEMU from building precisely because elf_is_fdpic is not defined. Signed-off-by: Christophe Lyon Reviewed-by: Peter Maydell Message-Id: <20180430080404.7323-2-christophe.lyon@st.com> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 18 +++++++----------- linux-user/qemu.h | 4 ++-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index c77ed1bb01..bbe93b03b6 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1681,7 +1681,12 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot) } } -#ifdef CONFIG_USE_FDPIC +/* Default implementation, always false. */ +static int elf_is_fdpic(struct elfhdr *exec) +{ + return 0; +} + static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp) { uint16_t n; @@ -1706,7 +1711,6 @@ static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong s return sp; } -#endif static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, struct elfhdr *exec, @@ -1725,7 +1729,6 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, sp = p; -#ifdef CONFIG_USE_FDPIC /* Needs to be before we load the env/argc/... */ if (elf_is_fdpic(exec)) { /* Need 4 byte alignment for these structs */ @@ -1737,7 +1740,6 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, sp = loader_build_fdpic_loadmap(interp_info, sp); } } -#endif u_platform = 0; k_platform = ELF_PLATFORM; @@ -2153,10 +2155,8 @@ static void load_elf_image(const char *image_name, int image_fd, } bswap_phdr(phdr, ehdr->e_phnum); -#ifdef CONFIG_USE_FDPIC info->nsegs = 0; info->pt_dynamic_addr = 0; -#endif mmap_lock(); @@ -2173,9 +2173,7 @@ static void load_elf_image(const char *image_name, int image_fd, if (a > hiaddr) { hiaddr = a; } -#ifdef CONFIG_USE_FDPIC ++info->nsegs; -#endif } } @@ -2200,8 +2198,7 @@ static void load_elf_image(const char *image_name, int image_fd, } load_bias = load_addr - loaddr; -#ifdef CONFIG_USE_FDPIC - { + if (elf_is_fdpic(ehdr)) { struct elf32_fdpic_loadseg *loadsegs = info->loadsegs = g_malloc(sizeof(*loadsegs) * info->nsegs); @@ -2219,7 +2216,6 @@ static void load_elf_image(const char *image_name, int image_fd, } } } -#endif info->load_bias = load_bias; info->load_addr = load_addr; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 192a0d2fef..da3b51724c 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -51,13 +51,13 @@ struct image_info { abi_ulong file_string; uint32_t elf_flags; int personality; -#ifdef CONFIG_USE_FDPIC + + /* The fields below are used in FDPIC mode. */ abi_ulong loadmap_addr; uint16_t nsegs; void *loadsegs; abi_ulong pt_dynamic_addr; struct image_info *other_info; -#endif }; #ifdef TARGET_I386 From cf58affecc67e1b22bdbd3dc90e19ad2d4b1ce3d Mon Sep 17 00:00:00 2001 From: Christophe Lyon Date: Mon, 30 Apr 2018 10:03:42 +0200 Subject: [PATCH 2/6] linux-user: ARM-FDPIC: Identify ARM FDPIC binaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define an ARM-specific version of elf_is_fdpic: FDPIC ELF objects are identified with e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC. Co-Authored-By: Mickaël Guêné Signed-off-by: Christophe Lyon Reviewed-by: Peter Maydell Message-Id: <20180430080404.7323-3-christophe.lyon@st.com> Signed-off-by: Laurent Vivier --- include/elf.h | 1 + linux-user/elfload.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/elf.h b/include/elf.h index c0dc9bb5fd..934dbbd6b3 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1483,6 +1483,7 @@ typedef struct elf64_shdr { #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ #define ELFOSABI_MODESTO 11 /* Novell Modesto. */ #define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM_FDPIC 65 /* ARM FDPIC */ #define ELFOSABI_ARM 97 /* ARM */ #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index bbe93b03b6..76d7718b3d 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1681,11 +1681,18 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot) } } +#ifdef TARGET_ARM +static int elf_is_fdpic(struct elfhdr *exec) +{ + return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC; +} +#else /* Default implementation, always false. */ static int elf_is_fdpic(struct elfhdr *exec) { return 0; } +#endif static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp) { From 3cb10cfafd83b9d7b3867b7deae29b8da3b5fe39 Mon Sep 17 00:00:00 2001 From: Christophe Lyon Date: Mon, 30 Apr 2018 10:03:43 +0200 Subject: [PATCH 3/6] linux-user: ARM-FDPIC: Add support of FDPIC for ARM. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add FDPIC info into image_info structure since interpreter info is on stack and needs to be saved to be accessed later on. Co-Authored-By: Mickaël Guêné Signed-off-by: Christophe Lyon Reviewed-by: Peter Maydell Message-Id: <20180430080404.7323-4-christophe.lyon@st.com> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 29 +++++++++++++++++++++++++++++ linux-user/qemu.h | 9 +++++++++ 2 files changed, 38 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 76d7718b3d..36d52194bc 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -78,6 +78,11 @@ enum { */ #define personality(pers) (pers & PER_MASK) +int info_is_fdpic(struct image_info *info) +{ + return info->personality == PER_LINUX_FDPIC; +} + /* this flag is uneffective under linux too, should be deleted */ #ifndef MAP_DENYWRITE #define MAP_DENYWRITE 0 @@ -287,6 +292,25 @@ static inline void init_thread(struct target_pt_regs *regs, /* For uClinux PIC binaries. */ /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ regs->uregs[10] = infop->start_data; + + /* Support ARM FDPIC. */ + if (info_is_fdpic(infop)) { + /* As described in the ABI document, r7 points to the loadmap info + * prepared by the kernel. If an interpreter is needed, r8 points + * to the interpreter loadmap and r9 points to the interpreter + * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and + * r9 points to the main program PT_DYNAMIC info. + */ + regs->uregs[7] = infop->loadmap_addr; + if (infop->interpreter_loadmap_addr) { + /* Executable is dynamically loaded. */ + regs->uregs[8] = infop->interpreter_loadmap_addr; + regs->uregs[9] = infop->interpreter_pt_dynamic_addr; + } else { + regs->uregs[8] = 0; + regs->uregs[9] = infop->pt_dynamic_addr; + } + } } #define ELF_NREG 18 @@ -1745,6 +1769,11 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, if (interp_info) { interp_info->other_info = info; sp = loader_build_fdpic_loadmap(interp_info, sp); + info->interpreter_loadmap_addr = interp_info->loadmap_addr; + info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr; + } else { + info->interpreter_loadmap_addr = 0; + info->interpreter_pt_dynamic_addr = 0; } } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index da3b51724c..c55c8e294b 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -57,6 +57,8 @@ struct image_info { uint16_t nsegs; void *loadsegs; abi_ulong pt_dynamic_addr; + abi_ulong interpreter_loadmap_addr; + abi_ulong interpreter_pt_dynamic_addr; struct image_info *other_info; }; @@ -183,6 +185,13 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp, struct target_pt_regs * regs, struct image_info *infop, struct linux_binprm *); +/* Returns true if the image uses the FDPIC ABI. If this is the case, + * we have to provide some information (loadmap, pt_dynamic_info) such + * that the program can be relocated adequately. This is also useful + * when handling signals. + */ +int info_is_fdpic(struct image_info *info); + uint32_t get_elf_eflags(int fd); int load_elf_binary(struct linux_binprm *bprm, struct image_info *info); int load_flt_binary(struct linux_binprm *bprm, struct image_info *info); From e8fa72957419c11984608062c7dcb204a6003a06 Mon Sep 17 00:00:00 2001 From: Christophe Lyon Date: Mon, 30 Apr 2018 10:03:44 +0200 Subject: [PATCH 4/6] linux-user: ARM-FDPIC: Add support for signals for FDPIC targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FDPIC restorer needs to deal with a function descriptor, hence we have to extend 'retcode' such that it can hold the instructions needed to perform this. The restorer sequence uses the same thumbness as the exception handler (mainly to support Thumb-only architectures). Co-Authored-By: Mickaël Guêné Signed-off-by: Christophe Lyon Reviewed-by: Peter Maydell Message-Id: <20180430080404.7323-5-christophe.lyon@st.com> [lv: moved the change to linux-user/arm/signal.c] Signed-off-by: Laurent Vivier --- linux-user/arm/signal.c | 105 ++++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 16 deletions(-) diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index 0c1ec53025..eb72be5dd0 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -102,13 +102,13 @@ struct sigframe_v1 { struct target_sigcontext sc; abi_ulong extramask[TARGET_NSIG_WORDS-1]; - abi_ulong retcode; + abi_ulong retcode[4]; }; struct sigframe_v2 { struct target_ucontext_v2 uc; - abi_ulong retcode; + abi_ulong retcode[4]; }; struct rt_sigframe_v1 @@ -117,14 +117,14 @@ struct rt_sigframe_v1 abi_ulong puc; struct target_siginfo info; struct target_ucontext_v1 uc; - abi_ulong retcode; + abi_ulong retcode[4]; }; struct rt_sigframe_v2 { struct target_siginfo info; struct target_ucontext_v2 uc; - abi_ulong retcode; + abi_ulong retcode[4]; }; #define TARGET_CONFIG_CPU_32 1 @@ -147,6 +147,21 @@ static const abi_ulong retcodes[4] = { 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 */ +}; static inline int valid_user_regs(CPUARMState *regs) { @@ -200,13 +215,33 @@ get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize) return (sp - framesize) & ~7; } -static void +static int setup_return(CPUARMState *env, struct target_sigaction *ka, abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr) { - abi_ulong handler = ka->_sa_handler; + abi_ulong handler = 0; + abi_ulong handler_fdpic_GOT = 0; abi_ulong retcode; - int thumb = handler & 1; + + int thumb; + int is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info); + + if (is_fdpic) { + /* In FDPIC mode, ka->_sa_handler points to a function + * descriptor (FD). The first word contains the address of the + * handler. The second word contains the value of the PIC + * register (r9). */ + abi_ulong funcdesc_ptr = ka->_sa_handler; + if (get_user_ual(handler, funcdesc_ptr) + || get_user_ual(handler_fdpic_GOT, funcdesc_ptr + 4)) { + return 1; + } + } else { + handler = ka->_sa_handler; + } + + thumb = handler & 1; + uint32_t cpsr = cpsr_read(env); cpsr &= ~CPSR_IT; @@ -217,7 +252,28 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, } if (ka->sa_flags & TARGET_SA_RESTORER) { - retcode = ka->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; + } else { + retcode = ka->sa_restorer; + } } else { unsigned int idx = thumb; @@ -231,10 +287,15 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, } env->regs[0] = usig; + if (is_fdpic) { + env->regs[9] = handler_fdpic_GOT; + } env->regs[13] = frame_addr; env->regs[14] = retcode; env->regs[15] = handler & (thumb ? ~1 : ~3); cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr); + + return 0; } static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env) @@ -327,12 +388,15 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka, __put_user(set->sig[i], &frame->extramask[i - 1]); } - setup_return(regs, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct sigframe_v1, retcode)); + 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); } @@ -349,12 +413,15 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka, setup_sigframe_v2(&frame->uc, set, regs); - setup_return(regs, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct sigframe_v2, retcode)); + 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); } @@ -404,8 +471,10 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); } - setup_return(env, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct rt_sigframe_v1, retcode)); + if (setup_return(env, ka, frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct rt_sigframe_v1, retcode))) { + goto sigsegv; + } env->regs[1] = info_addr; env->regs[2] = uc_addr; @@ -413,6 +482,7 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; sigsegv: + unlock_user_struct(frame, frame_addr, 1); force_sigsegv(usig); } @@ -435,8 +505,10 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, setup_sigframe_v2(&frame->uc, set, env); - setup_return(env, ka, &frame->retcode, frame_addr, usig, - frame_addr + offsetof(struct rt_sigframe_v2, retcode)); + 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; @@ -444,6 +516,7 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; sigsegv: + unlock_user_struct(frame, frame_addr, 1); force_sigsegv(usig); } From 465e237bf7cb6a9d8f9f137508125a14efcce1d6 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 11 Apr 2018 21:23:47 +0200 Subject: [PATCH 5/6] linux-user: introduce target_sigsp() and target_save_altstack() Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180411192347.30228-1-laurent@vivier.eu> --- linux-user/aarch64/signal.c | 13 ++----------- linux-user/alpha/signal.c | 17 ++++++----------- linux-user/arm/signal.c | 17 ++++------------- linux-user/hppa/signal.c | 14 ++++---------- linux-user/i386/signal.c | 12 +++--------- linux-user/m68k/signal.c | 15 +++------------ linux-user/microblaze/signal.c | 4 +--- linux-user/mips/signal.c | 15 ++------------- linux-user/nios2/signal.c | 21 ++------------------- linux-user/openrisc/signal.c | 14 +++----------- linux-user/ppc/signal.c | 15 ++------------- linux-user/riscv/signal.c | 28 +++++++++------------------- linux-user/s390x/signal.c | 12 +++--------- linux-user/sh4/signal.c | 11 ++--------- linux-user/signal-common.h | 15 ++++----------- linux-user/signal.c | 32 ++++++++++++++++++++++++++++++++ linux-user/sparc/signal.c | 28 +++++++++++++++++++--------- linux-user/tilegx/signal.c | 13 +++---------- linux-user/xtensa/signal.c | 15 ++++----------- 19 files changed, 108 insertions(+), 203 deletions(-) diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index d90e10a113..f95dc61dfb 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -120,9 +120,7 @@ static void target_setup_general_frame(struct target_rt_sigframe *sf, __put_user(0, &sf->uc.tuc_flags); __put_user(0, &sf->uc.tuc_link); - __put_user(target_sigaltstack_used.ss_sp, &sf->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(env->xregs[31]), &sf->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, &sf->uc.tuc_stack.ss_size); + target_save_altstack(&sf->uc.tuc_stack, env); for (i = 0; i < 31; i++) { __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]); @@ -372,14 +370,7 @@ static abi_ulong get_sigframe(struct target_sigaction *ka, { abi_ulong sp; - sp = env->xregs[31]; - - /* - * This is the X/Open sanctioned signal stack switching. - */ - if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } + sp = target_sigsp(get_sp_from_cpustate(env), ka); sp = (sp - size) & ~15; diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c index a8c718f2c6..f24de02c6f 100644 --- a/linux-user/alpha/signal.c +++ b/linux-user/alpha/signal.c @@ -117,12 +117,10 @@ static inline abi_ulong get_sigframe(struct target_sigaction *sa, CPUAlphaState *env, unsigned long framesize) { - abi_ulong sp = env->ir[IR_SP]; + abi_ulong sp; + + sp = target_sigsp(get_sp_from_cpustate(env), sa); - /* This is the X/Open sanctioned signal stack switching. */ - if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } return (sp - framesize) & -32; } @@ -187,12 +185,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(0, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_link); __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask); - __put_user(target_sigaltstack_used.ss_sp, - &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(env->ir[IR_SP]), - &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, - &frame->uc.tuc_stack.ss_size); + + target_save_altstack(&frame->uc.tuc_stack, env); + setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set); for (i = 0; i < TARGET_NSIG_WORDS; ++i) { __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index eb72be5dd0..59b5b65ed1 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -201,14 +201,9 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ static inline abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize) { - unsigned long sp = regs->regs[13]; + unsigned long sp; - /* - * This is the X/Open sanctioned signal stack switching. - */ - if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } + sp = target_sigsp(get_sp_from_cpustate(regs), ka); /* * ATPCS B01 mandates 8-byte alignment */ @@ -346,9 +341,7 @@ static void setup_sigframe_v2(struct target_ucontext_v2 *uc, memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext)); memset(&stack, 0, sizeof(stack)); - __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); - __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); - __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); + target_save_altstack(&stack, env); memcpy(&uc->tuc_stack, &stack, sizeof(stack)); setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]); @@ -461,9 +454,7 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext)); memset(&stack, 0, sizeof(stack)); - __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); - __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); - __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); + target_save_altstack(&stack, env); memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]); diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c index 585af3a37f..6e7a295aee 100644 --- a/linux-user/hppa/signal.c +++ b/linux-user/hppa/signal.c @@ -113,11 +113,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, struct target_rt_sigframe *frame; int i; - sp = env->gr[30]; - if (ka->sa_flags & TARGET_SA_ONSTACK) { - if (sas_ss_flags(sp) == 0) { - sp = (target_sigaltstack_used.ss_sp + 0x7f) & ~0x3f; - } + sp = get_sp_from_cpustate(env); + if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) { + sp = (target_sigaltstack_used.ss_sp + 0x7f) & ~0x3f; } frame_addr = QEMU_ALIGN_UP(sp, 64); sp = frame_addr + PARISC_RT_SIGFRAME_SIZE32; @@ -132,11 +130,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, frame->uc.tuc_flags = 0; frame->uc.tuc_link = 0; - __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(get_sp_from_cpustate(env)), - &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, - &frame->uc.tuc_stack.ss_size); + target_save_altstack(&frame->uc.tuc_stack, env); for (i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 4a190e6435..e9a23a2dec 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -283,16 +283,14 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size) unsigned long esp; /* Default to using normal stack */ - esp = env->regs[R_ESP]; + esp = get_sp_from_cpustate(env); #ifdef TARGET_X86_64 esp -= 128; /* this is the redzone */ #endif /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa_flags & TARGET_SA_ONSTACK) { - if (sas_ss_flags(esp) == 0) { - esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } + esp = target_sigsp(esp, ka); } else { #ifndef TARGET_X86_64 /* This is the legacy signal stack switching. */ @@ -404,11 +402,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /* Create the ucontext. */ __put_user(0, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_link); - __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(get_sp_from_cpustate(env)), - &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, - &frame->uc.tuc_stack.ss_size); + target_save_altstack(&frame->uc.tuc_stack, env); setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env, set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate)); diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c index fc72468a81..5dd8bb5f99 100644 --- a/linux-user/m68k/signal.c +++ b/linux-user/m68k/signal.c @@ -117,14 +117,10 @@ static inline abi_ulong get_sigframe(struct target_sigaction *ka, CPUM68KState *regs, size_t frame_size) { - unsigned long sp; + abi_ulong sp; - sp = regs->aregs[7]; + sp = target_sigsp(get_sp_from_cpustate(regs), ka); - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } return ((sp - frame_size) & -8UL); } @@ -318,12 +314,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(0, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_link); - __put_user(target_sigaltstack_used.ss_sp, - &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(env->aregs[7]), - &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, - &frame->uc.tuc_stack.ss_size); + target_save_altstack(&frame->uc.tuc_stack, env); err |= target_rt_setup_ucontext(&frame->uc, env); if (err) diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c index 5572baa7dc..fada0f1495 100644 --- a/linux-user/microblaze/signal.c +++ b/linux-user/microblaze/signal.c @@ -133,9 +133,7 @@ static abi_ulong get_sigframe(struct target_sigaction *ka, { abi_ulong sp = env->regs[1]; - if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } + sp = target_sigsp(sp, ka); return ((sp - frame_size) & -8UL); } diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c index adeb5a4241..ed9849c7f6 100644 --- a/linux-user/mips/signal.c +++ b/linux-user/mips/signal.c @@ -179,20 +179,12 @@ get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size) { unsigned long sp; - /* Default to using normal stack */ - sp = regs->active_tc.gpr[29]; - /* * FPU emulator may have its own trampoline active just * above the user stack, 16-bytes before the next lowest * 16 byte boundary. Try to avoid trashing it. */ - sp -= 32; - - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } + sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka); return (sp - frame_size) & ~7; } @@ -323,10 +315,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(0, &frame->rs_uc.tuc_flags); __put_user(0, &frame->rs_uc.tuc_link); - __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp); - __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size); - __put_user(sas_ss_flags(get_sp_from_cpustate(env)), - &frame->rs_uc.tuc_stack.ss_flags); + target_save_altstack(&frame->rs_uc.tuc_stack, env); setup_sigcontext(env, &frame->rs_uc.tuc_mcontext); diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c index 816eed90f1..9a0b36e5ad 100644 --- a/linux-user/nios2/signal.c +++ b/linux-user/nios2/signal.c @@ -42,18 +42,6 @@ struct target_rt_sigframe { struct target_ucontext uc; }; -static unsigned long sigsp(unsigned long sp, struct target_sigaction *ka) -{ - if (unlikely((ka->sa_flags & SA_ONSTACK)) && !sas_ss_flags(sp)) { -#ifdef CONFIG_STACK_GROWSUP - return target_sigaltstack_used.ss_sp; -#else - return target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; -#endif - } - return sp; -} - static int rt_setup_ucontext(struct target_ucontext *uc, CPUNios2State *env) { unsigned long *gregs = uc->tuc_mcontext.gregs; @@ -158,11 +146,8 @@ static void *get_sigframe(struct target_sigaction *ka, CPUNios2State *env, { unsigned long usp; - /* Default to using normal stack. */ - usp = env->regs[R_SP]; - /* This is the X/Open sanctioned signal stack switching. */ - usp = sigsp(usp, ka); + usp = target_sigsp(get_sp_from_cpustate(env), ka); /* Verify, is it 32 or 64 bit aligned */ return (void *)((usp - frame_size) & -8UL); @@ -185,9 +170,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /* Create the ucontext. */ __put_user(0, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_link); - __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(env->regs[R_SP]), &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); + target_save_altstack(&frame->uc.tuc_stack, env); err |= rt_setup_ucontext(&frame->uc, env); for (i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user((abi_ulong)set->sig[i], diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c index 0276808b59..ecf2897ccd 100644 --- a/linux-user/openrisc/signal.c +++ b/linux-user/openrisc/signal.c @@ -124,14 +124,11 @@ static inline abi_ulong get_sigframe(struct target_sigaction *ka, CPUOpenRISCState *regs, size_t frame_size) { - unsigned long sp = cpu_get_gpr(regs, 1); + unsigned long sp = get_sp_from_cpustate(regs); int onsigstack = on_sig_stack(sp); /* redzone */ - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } + sp = target_sigsp(sp, ka); sp = align_sigframe(sp - frame_size); @@ -175,12 +172,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /*err |= __clear_user(&frame->uc, offsetof(ucontext_t, uc_mcontext));*/ __put_user(0, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_link); - __put_user(target_sigaltstack_used.ss_sp, - &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(cpu_get_gpr(env, 1)), - &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, - &frame->uc.tuc_stack.ss_size); + target_save_altstack(&frame->uc.tuc_stack, env); setup_sigcontext(&frame->sc, env, set->sig[0]); /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/ diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index 15148d54a9..cacc9afb5a 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -217,13 +217,7 @@ static target_ulong get_sigframe(struct target_sigaction *ka, { target_ulong oldsp; - oldsp = env->gpr[1]; - - if ((ka->sa_flags & TARGET_SA_ONSTACK) && - (sas_ss_flags(oldsp) == 0)) { - oldsp = (target_sigaltstack_used.ss_sp - + target_sigaltstack_used.ss_size); - } + oldsp = target_sigsp(get_sp_from_cpustate(env), ka); return (oldsp - frame_size) & ~0xFUL; } @@ -515,12 +509,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(0, &rt_sf->uc.tuc_flags); __put_user(0, &rt_sf->uc.tuc_link); - __put_user((target_ulong)target_sigaltstack_used.ss_sp, - &rt_sf->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(env->gpr[1]), - &rt_sf->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, - &rt_sf->uc.tuc_stack.ss_size); + target_save_altstack(&rt_sf->uc.tuc_stack, env); #if !defined(TARGET_PPC64) __put_user(h2g (&rt_sf->uc.tuc_mcontext), &rt_sf->uc.tuc_regs); diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c index 718f3a5679..ef599e319a 100644 --- a/linux-user/riscv/signal.c +++ b/linux-user/riscv/signal.c @@ -54,24 +54,20 @@ struct target_rt_sigframe { static abi_ulong get_sigframe(struct target_sigaction *ka, CPURISCVState *regs, size_t framesize) { - abi_ulong sp = regs->gpr[xSP]; - int onsigstack = on_sig_stack(sp); - - /* redzone */ - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } - - sp -= framesize; - sp &= ~3UL; /* align sp on 4-byte boundary */ + abi_ulong sp = get_sp_from_cpustate(regs); /* If we are on the alternate signal stack and would overflow it, don't. Return an always-bogus address instead so we will die with SIGSEGV. */ - if (onsigstack && !likely(on_sig_stack(sp))) { + if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) { return -1L; } + /* This is the X/Open sanctioned signal stack switching. */ + sp = target_sigsp(sp, ka) - framesize; + + /* XXX: kernel aligns with 0xf ? */ + sp &= ~3UL; /* align sp on 4-byte boundary */ + return sp; } @@ -95,16 +91,10 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPURISCVState *env) static void setup_ucontext(struct target_ucontext *uc, CPURISCVState *env, target_sigset_t *set) { - abi_ulong ss_sp = (target_ulong)target_sigaltstack_used.ss_sp; - abi_ulong ss_flags = sas_ss_flags(env->gpr[xSP]); - abi_ulong ss_size = target_sigaltstack_used.ss_size; - __put_user(0, &(uc->uc_flags)); __put_user(0, &(uc->uc_link)); - __put_user(ss_sp, &(uc->uc_stack.ss_sp)); - __put_user(ss_flags, &(uc->uc_stack.ss_flags)); - __put_user(ss_size, &(uc->uc_stack.ss_size)); + target_save_altstack(&uc->uc_stack, env); int i; for (i = 0; i < TARGET_NSIG_WORDS; i++) { diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index a204a85e4a..e35cbe6870 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -86,14 +86,11 @@ get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size) abi_ulong sp; /* Default to using normal stack */ - sp = env->regs[15]; + sp = get_sp_from_cpustate(env); /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa_flags & TARGET_SA_ONSTACK) { - if (!sas_ss_flags(sp)) { - sp = target_sigaltstack_used.ss_sp + - target_sigaltstack_used.ss_size; - } + sp = target_sigsp(sp, ka); } /* This is the legacy signal stack switching. */ @@ -205,10 +202,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /* Create the ucontext. */ __put_user(0, &frame->uc.tuc_flags); __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link); - __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(get_sp_from_cpustate(env)), - &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); + target_save_altstack(&frame->uc.tuc_stack, env); save_sigregs(env, &frame->uc.tuc_mcontext); for (i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user((abi_ulong)set->sig[i], diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index 5ce182aff7..2a5378e16e 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -78,9 +78,7 @@ struct target_rt_sigframe static abi_ulong get_sigframe(struct target_sigaction *ka, unsigned long sp, size_t frame_size) { - if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } + sp = target_sigsp(sp, ka); return (sp - frame_size) & -8ul; } @@ -238,12 +236,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /* Create the ucontext. */ __put_user(0, &frame->uc.tuc_flags); __put_user(0, (unsigned long *)&frame->uc.tuc_link); - __put_user((unsigned long)target_sigaltstack_used.ss_sp, - &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(regs->gregs[15]), - &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, - &frame->uc.tuc_stack.ss_size); + target_save_altstack(&frame->uc.tuc_stack, regs); setup_sigcontext(&frame->uc.tuc_mcontext, regs, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h index fbb8d4365c..51030a9306 100644 --- a/linux-user/signal-common.h +++ b/linux-user/signal-common.h @@ -21,17 +21,10 @@ #define SIGNAL_COMMON_H extern struct target_sigaltstack target_sigaltstack_used; -static inline int on_sig_stack(unsigned long sp) -{ - return (sp - target_sigaltstack_used.ss_sp - < target_sigaltstack_used.ss_size); -} - -static inline int sas_ss_flags(unsigned long sp) -{ - return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE - : on_sig_stack(sp) ? SS_ONSTACK : 0); -} +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); +void target_save_altstack(target_stack_t *uss, CPUArchState *env); static inline void target_sigemptyset(target_sigset_t *set) { diff --git a/linux-user/signal.c b/linux-user/signal.c index a3022c2f04..01de433e3a 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -249,6 +249,38 @@ void set_sigmask(const sigset_t *set) } #endif +/* sigaltstack management */ + +int on_sig_stack(unsigned long sp) +{ + return (sp - target_sigaltstack_used.ss_sp + < target_sigaltstack_used.ss_size); +} + +int sas_ss_flags(unsigned long sp) +{ + return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE + : on_sig_stack(sp) ? SS_ONSTACK : 0); +} + +abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka) +{ + /* + * This is the X/Open sanctioned signal stack switching. + */ + if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) { + return target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } + return sp; +} + +void target_save_altstack(target_stack_t *uss, CPUArchState *env) +{ + __put_user(target_sigaltstack_used.ss_sp, &uss->ss_sp); + __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &uss->ss_flags); + __put_user(target_sigaltstack_used.ss_size, &uss->ss_size); +} + /* siginfo conversion */ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index c823e61cee..45e922f328 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -123,18 +123,28 @@ static inline abi_ulong get_sigframe(struct target_sigaction *sa, CPUSPARCState *env, unsigned long framesize) { - abi_ulong sp; + abi_ulong sp = get_sp_from_cpustate(env); - sp = env->regwptr[UREG_FP]; + /* + * If we are on the alternate signal stack and would overflow it, don't. + * Return an always-bogus address instead so we will die with SIGSEGV. + */ + if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) { + return -1; + } /* This is the X/Open sanctioned signal stack switching. */ - if (sa->sa_flags & TARGET_SA_ONSTACK) { - if (!on_sig_stack(sp) - && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } - } - return sp - framesize; + sp = target_sigsp(sp, sa) - framesize; + + /* Always align the stack frame. This handles two cases. First, + * sigaltstack need not be mindful of platform specific stack + * alignment. Second, if we took this signal because the stack + * is not aligned properly, we'd like to take the signal cleanly + * and report that. + */ + sp &= ~15UL; + + return sp; } static int diff --git a/linux-user/tilegx/signal.c b/linux-user/tilegx/signal.c index 8f54f54f95..d0ed3de569 100644 --- a/linux-user/tilegx/signal.c +++ b/linux-user/tilegx/signal.c @@ -86,17 +86,13 @@ static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc) static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env, size_t frame_size) { - unsigned long sp = env->regs[TILEGX_R_SP]; + unsigned long sp = get_sp_from_cpustate(env); if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) { return -1UL; } - if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } - - sp -= frame_size; + sp = target_sigsp(sp, ka) - frame_size; sp &= -16UL; return sp; } @@ -127,10 +123,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /* Create the ucontext. */ __put_user(0, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_link); - __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]), - &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); + target_save_altstack(&frame->uc.tuc_stack, env); setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo); if (ka->sa_flags & TARGET_SA_RESTORER) { diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c index 1e98910c1b..3e483efc61 100644 --- a/linux-user/xtensa/signal.c +++ b/linux-user/xtensa/signal.c @@ -55,12 +55,10 @@ static abi_ulong get_sigframe(struct target_sigaction *sa, CPUXtensaState *env, unsigned long framesize) { - abi_ulong sp = env->regs[1]; + abi_ulong sp; + + sp = target_sigsp(get_sp_from_cpustate(env), sa); - /* This is the X/Open sanctioned signal stack switching. */ - if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) { - sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; - } return (sp - framesize) & -16; } @@ -152,12 +150,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(0, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_link); - __put_user(target_sigaltstack_used.ss_sp, - &frame->uc.tuc_stack.ss_sp); - __put_user(sas_ss_flags(env->regs[1]), - &frame->uc.tuc_stack.ss_flags); - __put_user(target_sigaltstack_used.ss_size, - &frame->uc.tuc_stack.ss_size); + target_save_altstack(&frame->uc.tuc_stack, env); if (!setup_sigcontext(frame, env)) { unlock_user_struct(frame, frame_addr, 0); goto give_sigsegv; From 7f254c5cb80bc478794a4c3d7fe5d503b033be13 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 2 May 2018 23:57:30 +0200 Subject: [PATCH 6/6] linux-user: remove useless padding in flock64 structure Since commit 8efb2ed5ec ("linux-user: Correct signedness of target_flock l_start and l_len fields"), flock64 structure uses abi_llong for l_start and l_len in place of "unsigned long long" this should force them to be aligned accordingly to the target rules. So we can remove the padding field and the QEMU_PACKED attribute. I have compared the result of the following program before and after the change: cat -> flock64_dump <l_type p/d &((struct target_flock64 *)0)->l_whence p/d &((struct target_flock64 *)0)->l_start p/d &((struct target_flock64 *)0)->l_len p/d &((struct target_flock64 *)0)->l_pid quit EOF for file in build/all/*-linux-user/qemu-* ; do echo $file gdb -batch -nx -x flock64_dump $file 2> /dev/null done The sizeof() changes because we remove the QEMU_PACKED. The new size is 32 (except for i386 and m68k) and this is the real size of "struct flock64" on the target architecture. The following architectures differ: aarch64_be, aarch64, alpha, armeb, arm, cris, hppa, nios2, or1k, riscv32, riscv64, s390x. For a subset of these architectures, I have checked with the following program the new structure is the correct one: #include #define __USE_LARGEFILE64 #include int main(void) { printf("struct flock64 %d\n", sizeof(struct flock64)); printf("l_type %d\n", &((struct flock64 *)0)->l_type); printf("l_whence %d\n", &((struct flock64 *)0)->l_whence); printf("l_start %d\n", &((struct flock64 *)0)->l_start); printf("l_len %d\n", &((struct flock64 *)0)->l_len); printf("l_pid %d\n", &((struct flock64 *)0)->l_pid); } [I have checked aarch64, alpha, hppa, s390x] For ARM, the target_flock64 becomes the EABI definition, so we need to define the OABI one in place of the EABI one and use it when it is needed. I have also fixed the alignment value for sh4 (to align llong on 4 bytes) (see c2e3dee6e0 "linux-user: Define target alignment size") [We should check alignment properties for cris, nios2 and or1k] Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180502215730.28162-1-laurent@vivier.eu> --- include/exec/user/abitypes.h | 2 +- linux-user/arm/target_structs.h | 7 +++++++ linux-user/syscall.c | 14 +++++++------- linux-user/syscall_defs.h | 25 ++++--------------------- 4 files changed, 19 insertions(+), 29 deletions(-) diff --git a/include/exec/user/abitypes.h b/include/exec/user/abitypes.h index ba188608c2..743b8bb9ea 100644 --- a/include/exec/user/abitypes.h +++ b/include/exec/user/abitypes.h @@ -15,7 +15,7 @@ #define ABI_LLONG_ALIGNMENT 2 #endif -#if defined(TARGET_I386) && !defined(TARGET_X86_64) +#if (defined(TARGET_I386) && !defined(TARGET_X86_64)) || defined(TARGET_SH4) #define ABI_LLONG_ALIGNMENT 4 #endif diff --git a/linux-user/arm/target_structs.h b/linux-user/arm/target_structs.h index 0bf034cc25..9a3dbce03d 100644 --- a/linux-user/arm/target_structs.h +++ b/linux-user/arm/target_structs.h @@ -49,4 +49,11 @@ struct target_shmid_ds { abi_ulong __unused5; }; +struct target_oabi_flock64 { + abi_short l_type; + abi_short l_whence; + abi_llong l_start; + abi_llong l_len; + abi_int l_pid; +} QEMU_PACKED; #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 404be44ad5..e4825747f9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6600,10 +6600,10 @@ typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr); typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl); #if defined(TARGET_ARM) && TARGET_ABI_BITS == 32 -static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl, +static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl, abi_ulong target_flock_addr) { - struct target_eabi_flock64 *target_fl; + struct target_oabi_flock64 *target_fl; short l_type; if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) { @@ -6620,10 +6620,10 @@ static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl, return 0; } -static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr, +static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr, const struct flock64 *fl) { - struct target_eabi_flock64 *target_fl; + struct target_oabi_flock64 *target_fl; short l_type; if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) { @@ -11629,9 +11629,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, to_flock64_fn *copyto = copy_to_user_flock64; #ifdef TARGET_ARM - if (((CPUARMState *)cpu_env)->eabi) { - copyfrom = copy_from_user_eabi_flock64; - copyto = copy_to_user_eabi_flock64; + if (!((CPUARMState *)cpu_env)->eabi) { + copyfrom = copy_from_user_oabi_flock64; + copyto = copy_to_user_oabi_flock64; } #endif diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 23f5bccf0e..361bb83a29 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2649,29 +2649,12 @@ struct target_flock { }; struct target_flock64 { - short l_type; - short l_whence; -#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) \ - || defined(TARGET_SPARC) || defined(TARGET_HPPA) \ - || defined(TARGET_MICROBLAZE) || defined(TARGET_TILEGX) \ - || defined(TARGET_XTENSA) - int __pad; -#endif + abi_short l_type; + abi_short l_whence; abi_llong l_start; abi_llong l_len; - int l_pid; -} QEMU_PACKED; - -#ifdef TARGET_ARM -struct target_eabi_flock64 { - short l_type; - short l_whence; - int __pad; - abi_llong l_start; - abi_llong l_len; - int l_pid; -} QEMU_PACKED; -#endif + abi_int l_pid; +}; struct target_f_owner_ex { int type; /* Owner type of ID. */