]> granicus.if.org Git - strace/commitdiff
Improve sigreturn decoding on x86 to show RT signal bits too.
authorDenys Vlasenko <dvlasenk@redhat.com>
Tue, 16 Jul 2013 10:06:25 +0000 (12:06 +0200)
committerDenys Vlasenko <dvlasenk@redhat.com>
Tue, 16 Jul 2013 10:06:25 +0000 (12:06 +0200)
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>
defs.h
signal.c
syscall.c
test/.gitignore
test/Makefile
test/sigreturn.c [new file with mode: 0644]

diff --git a/defs.h b/defs.h
index 6e0bd8885f1be558263fb8f1e195d85fd5db69c2..09488a2216e34bb07b45954e41d0a67bfed775c4 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -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)
index 06cb67548e84ddf2dc2e78aa58db65bd1ca695ca..e433306f9fd7b1ba4c2c68045ddecb2c7a17fb9a 100644 (file)
--- a/signal.c
+++ b/signal.c
@@ -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
index 2715cea8b8f8849835a3fe9d48edc131cbd137ae..a27fee9b32e0726bf69ee1225db5a24a82a56df9 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -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
 };
index ce242fd3146a93b4eea444806555491ba645a2ac..7eb39cf492d4327bf43e310a1183c1423d0053dd 100644 (file)
@@ -10,3 +10,4 @@ wait_must_be_interruptible
 threaded_execve
 mtd
 ubi
+sigreturn
index 97ae746ef56e700ea286544c9378796c68dd5f7d..92142b180ee3762b74f1a70ea44ccd9dcc339f4c 100644 (file)
@@ -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 (file)
index 0000000..246a3ce
--- /dev/null
@@ -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;
+}