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>
This commit is contained in:
parent
9afc2ee682
commit
b51f364c42
4
defs.h
4
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)
|
||||
|
121
signal.c
121
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
|
||||
|
@ -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
|
||||
};
|
||||
|
1
test/.gitignore
vendored
1
test/.gitignore
vendored
@ -10,3 +10,4 @@ wait_must_be_interruptible
|
||||
threaded_execve
|
||||
mtd
|
||||
ubi
|
||||
sigreturn
|
||||
|
@ -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)
|
||||
|
||||
|
30
test/sigreturn.c
Normal file
30
test/sigreturn.c
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user