strace/sigreturn.c
Denys Vlasenko 7d27c63806 Trivial optimization in sys_sigreturn()
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
2015-03-21 20:11:53 +01:00

239 lines
6.2 KiB
C

#include "defs.h"
#include "regs.h"
#include "ptrace.h"
#if defined HAVE_ASM_SIGCONTEXT_H && !defined HAVE_STRUCT_SIGCONTEXT
# include <asm/sigcontext.h>
#endif
#ifndef NSIG
# warning NSIG is not defined, using 32
# define NSIG 32
#elif NSIG < 32
# error NSIG < 32
#endif
int
sys_sigreturn(struct tcb *tcp)
{
#if defined AARCH64 || defined ARM
if (entering(tcp)) {
# define SIZEOF_STRUCT_SIGINFO 128
# define SIZEOF_STRUCT_SIGCONTEXT (21 * 4)
# define OFFSETOF_STRUCT_UCONTEXT_UC_SIGMASK (5 * 4 + SIZEOF_STRUCT_SIGCONTEXT)
const long addr =
# ifdef AARCH64
current_personality == 1 ?
(*aarch64_sp_ptr + SIZEOF_STRUCT_SIGINFO +
offsetof(struct ucontext, uc_sigmask)) :
# endif
(*arm_sp_ptr +
OFFSETOF_STRUCT_UCONTEXT_UC_SIGMASK);
tprints("{mask=");
print_sigset_addr_len(tcp, addr, NSIG / 8);
tprints("}");
}
#elif defined(S390) || defined(S390X)
if (entering(tcp)) {
long mask[NSIG / 8 / sizeof(long)];
const long addr = *s390_frame_ptr + __SIGNAL_FRAMESIZE;
if (umove(tcp, addr, &mask) < 0) {
tprintf("{mask=%#lx}", addr);
} else {
# ifdef S390
long v = mask[0];
mask[0] = mask[1];
mask[1] = v;
# endif
tprintsigmask_addr("{mask=", mask);
tprints("}");
}
}
#elif defined I386 || defined X86_64 || defined X32
if (entering(tcp)) {
# ifndef I386
if (current_personality != 1) {
const unsigned long addr =
(unsigned long) *x86_64_rsp_ptr +
offsetof(struct ucontext, uc_sigmask);
tprints("{mask=");
print_sigset_addr_len(tcp, addr, NSIG / 8);
tprints("}");
return 0;
}
# endif
/*
* On i386, sigcontext is followed on stack by struct fpstate
* and after it an additional u32 extramask which holds
* upper half of the mask.
*/
struct {
uint32_t struct_sigcontext_padding1[20];
uint32_t oldmask;
uint32_t struct_sigcontext_padding2;
uint32_t struct_fpstate_padding[156];
uint32_t extramask;
} frame;
if (umove(tcp, *i386_esp_ptr, &frame) < 0) {
tprintf("{mask=%#lx}", (unsigned long) *i386_esp_ptr);
} else {
uint32_t mask[2] = { frame.oldmask, frame.extramask };
tprintsigmask_addr("{mask=", mask);
tprints("}");
}
}
#elif defined(IA64)
if (entering(tcp)) {
/* offsetof(struct sigframe, sc) */
# define OFFSETOF_STRUCT_SIGFRAME_SC 0xA0
const long addr = *ia64_frame_ptr + 16 +
OFFSETOF_STRUCT_SIGFRAME_SC +
offsetof(struct sigcontext, sc_mask);
tprints("{mask=");
print_sigset_addr_len(tcp, addr, NSIG / 8);
tprints("}");
}
#elif defined(POWERPC)
if (entering(tcp)) {
long esp = ppc_regs.gpr[1];
struct sigcontext sc;
/* Skip dummy stack frame. */
#ifdef POWERPC64
if (current_personality == 0)
esp += 128;
else
#endif
esp += 64;
if (umove(tcp, esp, &sc) < 0) {
tprintf("{mask=%#lx}", esp);
} else {
unsigned long mask[NSIG / 8 / sizeof(long)];
#ifdef POWERPC64
mask[0] = sc.oldmask | (sc._unused[3] << 32);
#else
mask[0] = sc.oldmask;
mask[1] = sc._unused[3];
#endif
tprintsigmask_addr("{mask=", mask);
tprints("}");
}
}
#elif defined(M68K)
if (entering(tcp)) {
long addr;
if (upeek(tcp->pid, 4*PT_USP, &addr) < 0)
return 0;
/* Fetch pointer to struct sigcontext. */
if (umove(tcp, addr + 2 * sizeof(int), &addr) < 0)
return 0;
unsigned long mask[NSIG / 8 / sizeof(long)];
/* Fetch first word of signal mask. */
if (umove(tcp, addr, &mask[0]) < 0)
return 0;
/* Fetch remaining words of signal mask, located
immediately before. */
addr -= sizeof(mask) - sizeof(long);
if (umoven(tcp, addr, sizeof(mask) - sizeof(long), &mask[1]) < 0)
return 0;
tprintsigmask_addr("{mask=", mask);
tprints("}");
}
#elif defined(ALPHA)
if (entering(tcp)) {
long addr;
if (upeek(tcp->pid, REG_FP, &addr) < 0)
return 0;
addr += offsetof(struct sigcontext, sc_mask);
tprints("{mask=");
print_sigset_addr_len(tcp, addr, NSIG / 8);
tprints("}");
}
#elif defined(SPARC) || defined(SPARC64)
if (entering(tcp)) {
long fp = sparc_regs.u_regs[U_REG_FP] + sizeof(struct sparc_stackf);
struct {
struct pt_regs si_regs;
int si_mask;
void *fpu_save;
long insns[2] __attribute__ ((aligned (8)));
unsigned int extramask[NSIG / 8 / sizeof(int) - 1];
} frame;
if (umove(tcp, fp, &frame) < 0) {
tprintf("{mask=%#lx}", fp);
} else {
unsigned int mask[NSIG / 8 / sizeof(int)];
mask[0] = frame.si_mask;
memcpy(mask + 1, frame.extramask, sizeof(frame.extramask));
tprintsigmask_addr("{mask=", mask);
tprints("}");
}
}
#elif defined MIPS
if (entering(tcp)) {
# if defined LINUX_MIPSO32
/*
* offsetof(struct sigframe, sf_mask) ==
* sizeof(sf_ass) + sizeof(sf_pad) + sizeof(struct sigcontext)
*/
const long addr = mips_REG_SP + 6 * 4 +
sizeof(struct sigcontext);
# else
/*
* This decodes rt_sigreturn.
* The 64-bit ABIs do not have sigreturn.
*
* offsetof(struct rt_sigframe, rs_uc) ==
* sizeof(sf_ass) + sizeof(sf_pad) + sizeof(struct siginfo)
*/
const long addr = mips_REG_SP + 6 * 4 + 128 +
offsetof(struct ucontext, uc_sigmask);
# endif
tprints("{mask=");
print_sigset_addr_len(tcp, addr, NSIG / 8);
tprints("}");
}
#elif defined(CRISV10) || defined(CRISV32)
if (entering(tcp)) {
long regs[PT_MAX+1];
if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long)regs) < 0) {
perror_msg("sigreturn: PTRACE_GETREGS");
return 0;
}
const long addr = regs[PT_USP] +
offsetof(struct sigcontext, oldmask);
tprints("{mask=");
print_sigset_addr_len(tcp, addr, NSIG / 8);
tprints("}");
}
#elif defined(TILE)
if (entering(tcp)) {
/* offset of ucontext in the kernel's sigframe structure */
# define SIGFRAME_UC_OFFSET C_ABI_SAVE_AREA_SIZE + sizeof(siginfo_t)
const long addr = tile_regs.sp + SIGFRAME_UC_OFFSET +
offsetof(struct ucontext, uc_sigmask);
tprints("{mask=");
print_sigset_addr_len(tcp, addr, NSIG / 8);
tprints("}");
}
#elif defined(MICROBLAZE)
/* TODO: Verify that this is correct... */
if (entering(tcp)) {
long addr;
/* Read r1, the stack pointer. */
if (upeek(tcp->pid, 1 * 4, &addr) < 0)
return 0;
addr += offsetof(struct sigcontext, oldmask);
tprints("{mask=");
print_sigset_addr_len(tcp, addr, NSIG / 8);
tprints("}");
}
#else
# warning sigreturn/rt_sigreturn signal mask decoding is not implemented for this architecture
#endif
return 0;
}