diff options
author | Helge Deller <deller@gmx.de> | 2023-01-29 22:08:51 +0100 |
---|---|---|
committer | Dmitry V. Levin <ldv@strace.io> | 2023-01-29 21:08:51 +0000 |
commit | 8e8434397487f533a6e263b1e3f24d1c4289eb09 (patch) | |
tree | 5d9c6678506caf729d658450466cc443c946bdd0 | |
parent | ad8aff80d9562207d07ed8bfb5af4ac32393d035 (diff) | |
download | strace-8e8434397487f533a6e263b1e3f24d1c4289eb09.tar.gz |
hppa: Fix display of mask for rt_sigreturn syscall
Fix FUNC_GET_RT_SIGFRAME_ADDR to return correct address to the
sigframe so that the mask can be shown for the rt_sigreturn syscall.
This patch cleans up and simplifies the address calculation when
running on Linux kernels < 5.18, where the signal trampoline code
was stored in the executable stack.
With kernel 5.18 we added a VDSO with the trampoline code, could drop
the neccessarity of an executable stack and provided the offset to the
ucontext of the rt_sigframe struct for gdb and to simplify the
calculation sigframe address.
With this patch the rt_sigreturn.gen.test passes for 5.16 and 6.1
kernels on hppa.
Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r-- | src/linux/hppa/arch_rt_sigframe.c | 37 | ||||
-rw-r--r-- | src/linux/hppa/rt_sigframe.h | 8 |
2 files changed, 37 insertions, 8 deletions
diff --git a/src/linux/hppa/arch_rt_sigframe.c b/src/linux/hppa/arch_rt_sigframe.c index 99249a3e5..879a7d3f6 100644 --- a/src/linux/hppa/arch_rt_sigframe.c +++ b/src/linux/hppa/arch_rt_sigframe.c @@ -7,15 +7,38 @@ #include "rt_sigframe.h" -#define SIGFRAME (sizeof(long) * 16) -#define FUNCTIONCALLFRAME (sizeof(long) * 12) -#define RT_SIGFRAME_SIZE \ - (((sizeof(struct_rt_sigframe) + FUNCTIONCALLFRAME)) & -SIGFRAME) +/* see further comments in GDB: gdb/hppa-linux-tdep.c */ + +#define SIGFRAME 64 FUNC_GET_RT_SIGFRAME_ADDR { - unsigned long addr; + unsigned long sp, ip; + + if (!get_instruction_pointer(tcp, &ip) || + !get_stack_pointer(tcp, &sp)) + return 0; + + sp &= -1UL; + /* check if ip is part of stack, running in tramp[] of rt_sigframe */ + if ((sp - ip) < 1024) { + /* on executable stack: We execute in tramp[], so align down. */ + return (ip & -SIGFRAME) + /* compensate for size difference old and new frame */ + + sizeof(struct_rt_sigframe_old) + - sizeof(struct_rt_sigframe); + } else { + /* running in VDSO on kernel >= 5.18 */ + static kernel_ulong_t context_offset; + + /* read sigframe offset from kernel VDSO header */ + if (!context_offset) + context_offset = ptrace(PTRACE_PEEKTEXT, (pid_t) tcp->pid, + (void *)(ip & -SIGFRAME), 0); + if (context_offset == (kernel_ulong_t) -1) + return 0; - return get_stack_pointer(tcp, &addr) - ? (addr & ~1UL) - RT_SIGFRAME_SIZE : 0; + /* context_offset is a negative value */ + return sp + context_offset - offsetof(struct_rt_sigframe, uc.uc_mcontext); + } } diff --git a/src/linux/hppa/rt_sigframe.h b/src/linux/hppa/rt_sigframe.h index 17bff7cd6..3b8348b04 100644 --- a/src/linux/hppa/rt_sigframe.h +++ b/src/linux/hppa/rt_sigframe.h @@ -14,6 +14,12 @@ typedef struct { unsigned int tramp[9]; siginfo_t info; ucontext_t uc; -} struct_rt_sigframe; +} struct_rt_sigframe_old; /* when executed on stack */ + +typedef struct { + unsigned int tramp[2]; /* holds original return address */ + siginfo_t info; + ucontext_t uc; +} struct_rt_sigframe; /* when VDSO is used */ #endif /* !STRACE_RT_SIGFRAME_H */ |