diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2013-07-16 12:06:25 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2013-07-16 12:06:25 +0200 |
commit | b51f364c4241aa247a7a22f92c06f1f1a4ab99b4 (patch) | |
tree | 31d0d194e5659cb0cfaaddcd2ca05c5a09a4f89f | |
parent | 9afc2ee682d2f9fd3ad938756c841d7f0eed5f21 (diff) | |
download | strace-b51f364c4241aa247a7a22f92c06f1f1a4ab99b4.tar.gz strace-b51f364c4241aa247a7a22f92c06f1f1a4ab99b4.tar.bz2 strace-b51f364c4241aa247a7a22f92c06f1f1a4ab99b4.tar.xz |
Improve sigreturn decoding on x86 to show RT signal bits too.
This includes decoding of 32-bit sigreturn by 64-bit strace,
which previously wasn't done.
Added a test for it.
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rw-r--r-- | defs.h | 4 | ||||
-rw-r--r-- | signal.c | 121 | ||||
-rw-r--r-- | syscall.c | 4 | ||||
-rw-r--r-- | test/.gitignore | 1 | ||||
-rw-r--r-- | test/Makefile | 2 | ||||
-rw-r--r-- | test/sigreturn.c | 30 |
6 files changed, 108 insertions, 54 deletions
@@ -378,8 +378,8 @@ struct arm_pt_regs { # define PERSONALITY0_WORDSIZE (int)(sizeof(long)) #endif -#if defined(I386) -extern struct user_regs_struct i386_regs; +#if defined(I386) || defined(X86_64) +extern uint32_t *const i386_esp_ptr; #elif defined(IA64) extern bool ia64_ia32mode; #elif defined(SPARC) || defined(SPARC64) @@ -70,35 +70,8 @@ typedef struct { # include <asm/sigcontext.h> # endif #else /* !HAVE_ASM_SIGCONTEXT_H */ -# if defined I386 && !defined HAVE_STRUCT_SIGCONTEXT_STRUCT -struct sigcontext_struct { - unsigned short gs, __gsh; - unsigned short fs, __fsh; - unsigned short es, __esh; - unsigned short ds, __dsh; - unsigned long edi; - unsigned long esi; - unsigned long ebp; - unsigned long esp; - unsigned long ebx; - unsigned long edx; - unsigned long ecx; - unsigned long eax; - unsigned long trapno; - unsigned long err; - unsigned long eip; - unsigned short cs, __csh; - unsigned long eflags; - unsigned long esp_at_signal; - unsigned short ss, __ssh; - unsigned long i387; - unsigned long oldmask; - unsigned long cr2; -}; -# else /* !I386 */ -# if defined M68K && !defined HAVE_STRUCT_SIGCONTEXT -struct sigcontext -{ +# if defined M68K && !defined HAVE_STRUCT_SIGCONTEXT +struct sigcontext { unsigned long sc_mask; unsigned long sc_usp; unsigned long sc_d0; @@ -109,9 +82,53 @@ struct sigcontext unsigned long sc_pc; unsigned short sc_formatvec; }; -# endif /* M68K */ -# endif /* !I386 */ +# endif /* M68K */ #endif /* !HAVE_ASM_SIGCONTEXT_H */ +#if defined(I386) || defined(X86_64) +struct i386_sigcontext_struct { + uint16_t gs, __gsh; + uint16_t fs, __fsh; + uint16_t es, __esh; + uint16_t ds, __dsh; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t trapno; + uint32_t err; + uint32_t eip; + uint16_t cs, __csh; + uint32_t eflags; + uint32_t esp_at_signal; + uint16_t ss, __ssh; + uint32_t i387; + uint32_t oldmask; + uint32_t cr2; +}; +struct i386_fpstate { + uint32_t cw; + uint32_t sw; + uint32_t tag; + uint32_t ipoff; + uint32_t cssel; + uint32_t dataoff; + uint32_t datasel; + uint8_t st[8][10]; /* 8*10 bytes: FP regs */ + uint16_t status; + uint16_t magic; + uint32_t fxsr_env[6]; + uint32_t mxcsr; + uint32_t reserved; + uint8_t stx[8][16]; /* 8*16 bytes: FP regs, each padded to 16 bytes */ + uint8_t xmm[8][16]; /* 8 XMM regs */ + uint32_t padding1[44]; + uint32_t padding2[12]; /* union with struct _fpx_sw_bytes */ +}; +#endif #ifndef NSIG # warning: NSIG is not defined, using 32 @@ -288,10 +305,13 @@ sprintsigmask(const char *str, sigset_t *mask, int rt) char sep; char *s; + /* Note: nsignals = ARRAY_SIZE(signalent[]), + * and that array may not have SIGRTnn. + */ maxsigs = nsignals; #ifdef __SIGRTMAX if (rt) - maxsigs = __SIGRTMAX; /* instead */ + maxsigs = __SIGRTMAX + 1; /* instead */ #endif s = stpcpy(outstr, str); nsigs = 0; @@ -308,23 +328,17 @@ sprintsigmask(const char *str, sigset_t *mask, int rt) sep = '['; for (i = 1; i < maxsigs; i++) { if (sigismember(mask, i) == show_members) { - /* real-time signals on solaris don't have - * signalent entries - */ - char tsig[40]; *s++ = sep; if (i < nsignals) { s = stpcpy(s, signalent[i] + 3); } #ifdef SIGRTMIN else if (i >= __SIGRTMIN && i <= __SIGRTMAX) { - sprintf(tsig, "RT_%u", i - __SIGRTMIN); - s = stpcpy(s, tsig); + s += sprintf(s, "RT_%u", i - __SIGRTMIN); } #endif /* SIGRTMIN */ else { - sprintf(tsig, "%u", i); - s = stpcpy(s, tsig); + s += sprintf(s, "%u", i); } sep = ' '; } @@ -832,19 +846,28 @@ sys_sigreturn(struct tcb *tcp) return 0; tprints(sprintsigmask(") (mask ", (sigset_t *)&sc.oldmask[0], 0)); } -#elif defined(I386) +#elif defined(I386) || defined(X86_64) +# if defined(X86_64) + if (current_personality == 0) /* 64-bit */ + return 0; +# endif if (entering(tcp)) { - struct sigcontext_struct sc; - /* Note: on i386, sc is followed on stack by struct fpstate + struct { + struct i386_sigcontext_struct sc; + struct i386_fpstate fp; + uint32_t extramask[1]; + } signal_stack; + /* On i386, sc is followed on stack by struct fpstate * and after it an additional u32 extramask[1] which holds - * upper half of the mask. We can fetch it there - * if/when we'd want to display the full mask... + * upper half of the mask. */ sigset_t sigm; - if (umove(tcp, i386_regs.esp, &sc) < 0) + if (umove(tcp, *i386_esp_ptr, &signal_stack) < 0) return 0; - long_to_sigset(sc.oldmask, &sigm); - tprints(sprintsigmask(") (mask ", &sigm, 0)); + sigemptyset(&sigm); + ((uint32_t*)&sigm)[0] = signal_stack.sc.oldmask; + ((uint32_t*)&sigm)[1] = signal_stack.extramask[0]; + tprints(sprintsigmask(") (mask ", &sigm, /*RT sigs too?:*/ 1)); } #elif defined(IA64) if (entering(tcp)) { @@ -993,8 +1016,6 @@ sys_sigreturn(struct tcb *tcp) long_to_sigset(sc.oldmask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } -#elif defined(X86_64) - /* no need to remind */ #elif defined(XTENSA) /* Xtensa only has rt_sys_sigreturn */ #else @@ -682,7 +682,8 @@ getrval2(struct tcb *tcp) #endif #if defined(I386) -struct user_regs_struct i386_regs; +static struct user_regs_struct i386_regs; +uint32_t *const i386_esp_ptr = &i386_regs.esp; # define ARCH_REGS_FOR_GETREGSET i386_regs #elif defined(X86_64) || defined(X32) /* @@ -716,6 +717,7 @@ static union { } x86_regs_union; # define x86_64_regs x86_regs_union.x86_64_r # define i386_regs x86_regs_union.i386_r +uint32_t *const i386_esp_ptr = &i386_regs.esp; static struct iovec x86_io = { .iov_base = &x86_regs_union }; diff --git a/test/.gitignore b/test/.gitignore index ce242fd..7eb39cf 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -10,3 +10,4 @@ wait_must_be_interruptible threaded_execve mtd ubi +sigreturn diff --git a/test/Makefile b/test/Makefile index 97ae746..92142b1 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,7 +3,7 @@ CFLAGS += -Wall PROGS = \ vfork fork sig skodic clone leaderkill childthread \ sigkill_rain wait_must_be_interruptible threaded_execve \ - mtd ubi + mtd ubi sigreturn all: $(PROGS) diff --git a/test/sigreturn.c b/test/sigreturn.c new file mode 100644 index 0000000..246a3ce --- /dev/null +++ b/test/sigreturn.c @@ -0,0 +1,30 @@ +/* + * Check that strace output contains RT_1 RT_3 RT_31 RT_32 here: + * rt_sigprocmask(SIG_BLOCK, [CHLD RT_1 RT_3 RT_31 RT_32], NULL, 8) = 0 + * and here: + * sigreturn() (mask [CHLD RT_1 RT_3 RT_31 RT_32]) = 0 + * + * On x86, both 32-bit and 64-bit strace needs to be checked. + */ +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> + +void null_handler(int sig) +{ +} + +int main(int argc, char *argv[]) +{ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigaddset(&set, 33); + sigaddset(&set, 35); + sigaddset(&set, 63); + sigaddset(&set, 64); + sigprocmask(SIG_BLOCK, &set, NULL); + signal(SIGWINCH, null_handler); + raise(SIGWINCH); + return 0; +} |