Purpose of TCB_SIGTRAPPED?

Denys Vlasenko dvlasenk at redhat.com
Wed Dec 17 18:13:24 UTC 2008


Hi,

Testing my SIGTRAP-handling patch further, I looked into
this peculiar thing where strace does something
(not really clear what) when process tries to mask or SIG_IGN
SIGTRAP. (Noticed and quick-fixed a typo where we weren't
printing SIG_IGN correctly, in cvs now).


To see this, grep for TCB_SIGTRAPPED. For example:

int
sys_signal(tcp)
struct tcb *tcp;
{
        if (entering(tcp)) {
                printsignal(tcp->u_arg[0]);
                tprintf(", ");
                switch (tcp->u_arg[1]) {
                case (long) SIG_ERR:
                        tprintf("SIG_ERR");
                        break;
                case (long) SIG_DFL:
                        tprintf("SIG_DFL");
                        break;
                case (long) SIG_IGN:
#ifndef USE_PROCFS
                        if (tcp->u_arg[0] == SIGTRAP) {
fprintf(stderr, "HERE\n");
//                              tcp->flags |= TCB_SIGTRAPPED;
//                              kill(tcp->pid, SIGSTOP);
                        }
#endif /* !USE_PROCFS */
                        tprintf("SIG_IGN");
                        break;
                default:
#ifndef USE_PROCFS
                        if (tcp->u_arg[0] == SIGTRAP) {
fprintf(stderr, "HERE 1\n");
//                              tcp->flags |= TCB_SIGTRAPPED;
//                              kill(tcp->pid, SIGSTOP);
                        }
#endif /* !USE_PROCFS */
                        tprintf("%#lx", tcp->u_arg[1]);
                }


I verified that these code paths are reached when my test program
sets SIGTRAP to something which is not SIG_DFL, and that we pass
thru corresponding handling when we see this SIGSTOP:


                        if (WSTOPSIG(status) == SIGSTOP &&
                                        (tcp->flags & TCB_SIGTRAPPED)) {
fprintf(stderr, "HERE 2\n");
                                /*
                                 * Trapped attempt to block SIGTRAP
                                 * Hope we are back in control now.
                                 */
                                tcp->flags &= ~(TCB_INSYSCALL | TCB_SIGTRAPPED);
                                if (ptrace(PTRACE_SYSCALL,
                                                pid, (char *) 1, 0) < 0) {
                                        perror("trace: ptrace(PTRACE_SYSCALL, ...)");
                                        cleanup();
                                        return -1;
                                }
                                continue;
                        }


However, when I commented out setting of TCB_SIGTRAPPED and kill()
as shown above, strace still works.
(At least my patched one, at least on F9 kernel).

Does anybody know/remember why this TCB_SIGTRAPPED trick is even needed?
I want to document it in comments.

The strange thing, this handling is present in sys_signal and sys_sigaction
(that is, on "older" routines) but not in sys_rt_sigaction!

So, sys_rt_sigaction (which is what used by any modern libc)
will not make strace to handle blocking of SIGTRAP
specially, and we all know it seems to work just fine, no breakage.

?!


My test program:

#define _GNU_SOURCE
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
void trap() {
        write(2, "TRAP\n", 5);
}
int main() {
	// just using signal() would use sys_rt_sigaction!
        syscall(SYS_signal, (long) SIGTRAP, (long) &trap); // or SIG_IGN
        printf("%d\n", getpid()); fflush(NULL);
        sleep(9);
        write(2, "EXIT\n", 5);
        return 0;
}

I had to build it with 32-bit compiler (i486-linux-uclibc-gcc) since
x86_64 arch does not have SYS_signal, and sys_rt_sigaction would not
excercise these code paths in strace.

--
vda






More information about the Strace-devel mailing list