cforkptrace

ptrace not recording forked process despite setting PTRACE_SETOPTIONS to PTRACE_O_TRACEFORK


I'm trying to follow the syscalls of a program using ptrace, but it does not work when the traced program has a fork() and just ignores it, supposedly you just need to set the line below and it should follow the process originating from fork() as well.

ptrace(PTRACE_SETOPTIONS, child, NULL, PTRACE_O_TRACEFORK); I'm posting my code below, for tracer.c:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <unistd.h>
#include <errno.h>
#include <sys/user.h>

int main(int argc, char* argv[]){
    if (argc < 2) {
        printf("Usage: %s <program> [args...]\n", argv[0]);
        return 1;
    }

    pid_t child;
    struct user_regs_struct regs;
    int status;
    int notPrinted = 1;

    child = fork();

    if (child == 0){
        if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0){
            perror("ptrace");
            return 1;
        }
        execvp(argv[1], &argv[1]);
    }
    else if (child > 0){
        wait(&status);

        ptrace(PTRACE_SETOPTIONS, child, NULL, PTRACE_SETOPTIONS | PTRACE_O_TRACEFORK | PTRACE_O_TRACESYSGOOD);
        while (WIFSTOPPED(status)){
            ptrace(PTRACE_GETREGS, child, NULL, &regs);

            if(notPrinted){
                if (regs.orig_rax != -1){
                    notPrinted = 0;
                    printf("FROM: %d, Syscall %ld: rdi=%ld, rsi=%ld, rdx=%ld, r10=%ld\n",
                        child, regs.orig_rax, regs.rbx, regs.rcx, regs.rdx, regs.r10);
                }
            }
            else{
                notPrinted = 1;
            }
            if (ptrace(PTRACE_SYSCALL, child, NULL, NULL) < 0){
                perror("ptrace");
                return 1;
            }
            wait(&status);
        }
    }
    else{
        perror("fork");
        return 1;
    }
    return 0;
}

As well as a simple program I've been using to test, random.c:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {

    if(fork() == 0){
        sleep(1);
    }
    srand(time(NULL));

    for (int i = 0; i < 30; i++) {
        printf("%d ", rand() & 0xf);
    }
    printf("\n");
    sleep(5);
    return 0;
}

Previously I had the following line with just set option to "PTRACE_O_TRACEFORK"; So i believe the issue is still a wrong configuration of PTRACE_SETOPTIONS; my goal is to have the program follow a program that uses fork() correctly, like strace -f option does

ptrace(PTRACE_SETOPTIONS, child, NULL, PTRACE_SETOPTIONS | PTRACE_O_TRACEFORK | PTRACE_O_TRACESYSGOOD);

EDIT:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char* argv[]){
    if (argc < 2){
        printf("Usage: %s <program> [args...]\n", argv[0]);
        return 1;
    }

    pid_t child;
    struct user_regs_struct regs;
    int status;

    child = fork();

    if (child == 0){
        if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) {
            perror("ptrace");
            return 1;
        }
        execvp(argv[1], &argv[1]);
    } else if (child > 0){
        child = wait(&status);
        ptrace(PTRACE_SETOPTIONS, child, NULL, PTRACE_SETOPTIONS | PTRACE_O_TRACEFORK | PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACECLONE);

        while (WIFSTOPPED(status)){
            ptrace(PTRACE_GETREGS, child, NULL, &regs);

            if (regs.orig_rax != -1){
                printf("FROM: %d, Syscall %ld: rdi=%ld, rsi=%ld, rdx=%ld, r10=%ld\n",
                        child, regs.orig_rax, regs.rbx, regs.rcx, regs.rdx, regs.r10);
            }
            if (ptrace(PTRACE_SYSCALL, child, NULL, NULL) < 0){
                perror("ptrace");
                return 1;
            }

            child = wait(&status);
        }
    } else{
        perror("fork");
        return 1;
    }

    return 0;
}

This is the new code with PTRACE_O_TRACECLONE option included, removed notPrinted just for code readability, and with updated child by doing

child = wait(&status);
ptrace(PTRACE_GETREGS, child, NULL, &regs);

to get updated child, and then to read the registers from the process; But I'm still only getting one process as child, any idea why so?


Solution

  • A few issues ...

    1. You need to [also] add PTRACE_O_TRACECLONE when you set options. You're doing fork but that's the libc function. (e.g. Under linux) it uses the clone syscall).

    2. You have to do ptrace(PTRACE_CONT, pid, 0, 0); to resume the child after the tracer processes the stop.

    3. If you're going to trace an app that calls fork and you want to also trace any children it created, you have to use the correct pid. You never change the value of child, so you never get the pid of any grandchildren.

    4. You have to do: child = wait(&status); When you're tracing multiple children, you have to know which pid caused the return from wait.


    For some additional info, you could look at some of my ptrace answers:

    1. Ptrace options not working in parent process

    UPDATE:

    I have edited the code if you could please check again. I have added PTRACE_O_TRACECLONE, I did not add ptrace(PTRACE_CONT, pid, 0, 0); because I believe ptrace(PTRACE_SYSCALL, child, NULL, NULL) already does that and PTRACE_CONT is not required, and changed to record child_pid, but im not getting the grandchild, any ideas on what else I can do? – frazz

    Yes, PTRACE_SYSCALL is sufficient.

    I reworked your latest source. In the process, I discovered the bug.

    Your PTRACE_SETOPTIONS call is incorrect. You are doing:

    ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_SETOPTIONS |
        PTRACE_O_TRACEFORK | PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACECLONE);
    

    You are ORing in PTRACE_SETOPTIONS into the last argument. This argument should only have PTRACE_O_* options in it.

    This [somehow] breaks things. The correct way is:

    ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEFORK |
        PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACECLONE);
    

    I added some extra code to have a per-process control struct to keep track of the state of each process being traced. While not strictly necessary for your example, it is a common thing to do.

    I also added a log file for tracing.

    And, I refactored your random a bit to be slightly more trace friendly (not necessary but helped spot the issue).

    Here is the tracer:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ptrace.h>
    #include <sys/wait.h>
    #include <sys/reg.h>
    #include <sys/user.h>
    #include <unistd.h>
    #include <errno.h>
    #include <syscall.h>
    
    FILE *xflog;
    int opt_bug;                                // 1=show bug
    int opt_v;                                  // 1=verbose dump mode
    char *opt_L;                                // logfile name
    char *pgmname;
    
    #define logf(_fmt...) \
        fprintf(xflog,_fmt)
    
    #if 0
    #define DREG(_reg) \
        logf(" " #_reg "=%16.16llX/%llu\n",regs._reg,regs._reg)
    #else
    #define DREG(_reg) \
        logf(" " #_reg "=%16.16llX\n",regs._reg)
    #endif
    
    struct pidctl {
        struct pidctl *ctl_next;                // linked list
        pid_t ctl_pid;                          // process id
        int ctl_xid;                            // incremental id (e.g. 1, 2, 3)
        unsigned int ctl_seqno;                 // event sequence number
        int ctl_status;                         // status from last wait call
        int ctl_signo;                          // signal number from last call
        int ctl_mode;                           // mode (0=enter, 1=exit) syscall
    };
    
    struct pidctl *pidlist;                     // list of active processes
    int pidcount;                               // number of entries in pidlist
    int pidxid;                                 // incremental id
    
    #if 1
    #define WAITFOR(_status)        wait(_status)
    #else
    #define WAITFOR(_status)        waitpid(-1,_status,0)
    #endif
    
    const char *sysname(int sysno);
    
    // pidfind -- find control for given pid
    struct pidctl *
    pidfind(pid_t pid,int status)
    {
        struct pidctl *prev = NULL;
        struct pidctl *cur = pidlist;
    
        // find existing entry
        for (;  cur != NULL;  cur = cur->ctl_next) {
            if (cur->ctl_pid == pid)
                break;
            prev = cur;
        }
    
        do {
            // already exists
            if (cur != NULL)
                break;
    
            // create new entry
            cur = calloc(1,sizeof(*cur));
            cur->ctl_pid = pid;
            cur->ctl_xid = pidxid++;
            logf("pidfind: NEWPID ctl_xid=%d ctl_pid=%8.8X/%d\n",
                cur->ctl_xid,cur->ctl_pid,cur->ctl_pid);
    
            // start in "AFT" mode
            cur->ctl_mode = 1;
    
            if (prev != NULL)
                prev->ctl_next = cur;
            else
                pidlist = cur;
    
            ++pidcount;
        } while (0);
    
        cur->ctl_status = status;
    
        if (WIFSTOPPED(status))
            cur->ctl_signo = WSTOPSIG(status);
        else
            cur->ctl_signo = 0;
    
        return cur;
    }
    
    void
    pidsetup(pid_t pid)
    {
    
    // NOTE/BUG: PTRACE_SETOPTIONS must _not_ be or'ed in with PTRACE_O_*
        if (opt_bug)
            ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_SETOPTIONS |
                PTRACE_O_TRACEFORK | PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACECLONE);
        else
            ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEFORK |
                PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACECLONE);
    }
    
    int
    main(int argc, char **argv)
    {
    
        pgmname = *argv;
        --argc;
        ++argv;
    
        for (;  argc > 0;  --argc, ++argv) {
            char *cp = *argv;
            if (*cp != '-')
                break;
    
            cp += 2;
            switch (cp[-1]) {
            case 'b':
                opt_bug = ! opt_bug;
                break;
            case 'v':
                opt_v = ! opt_v;
                break;
            case 'L':
                opt_L = (*cp != 0) ? cp : NULL;
                break;
            }
        }
    
        if (argc < 1) {
            printf("Usage: %s <program> [args...]\n", pgmname);
            return 1;
        }
    
        pid_t child;
        struct user_regs_struct regs;
        int status;
    
        if (opt_L == NULL)
            opt_L = "LOG";
        xflog = fopen(opt_L,"w");
        setlinebuf(xflog);
    
        child = fork();
        if (child < 0) {
            perror("fork");
            return 1;
        }
    
        if (child == 0) {
            if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) {
                perror("ptrace");
                return 1;
            }
            execvp(argv[0], &argv[0]);
            perror("execvp");
            exit(9);
        }
    
        struct pidctl *ctl;
    
        child = WAITFOR(&status);
    
    #if 1
        ctl = pidfind(child,status);
    #endif
    
        pidsetup(child);
    
        unsigned int seqno = 0;
        int sysno;
        int exit_count = 0;
    
        while (pidcount > 0) {
            logf("\n");
            ctl = pidfind(child,status);
    
            if (WIFEXITED(status)) {
                logf("EXIT: %d status=%8.8X\n",ctl->ctl_xid,status);
                --pidcount;
                if (pidcount <= 0)
                    break;
                continue;
            }
    
            ptrace(PTRACE_GETREGS, child, NULL, &regs);
    
            sysno = regs.orig_rax;
    
            do {
    #if 0
                if (sysno == -1)
                    break;
    #endif
    
    #if 0
                logf("FROM: %d, Syscall %ld: rdi=%ld, rsi=%ld, rdx=%ld, r10=%ld\n",
                    child, regs.orig_rax, regs.rbx, regs.rcx, regs.rdx, regs.r10);
    #else
                logf("%u: %d %s %d/%s\n",
                    seqno,ctl->ctl_xid,
                    ctl->ctl_mode ? "AFT" : "BEF",
                    sysno,sysname(sysno));
                if (opt_v) {
                    DREG(rdi);
                    DREG(rsi);
                    DREG(rdx);
                    DREG(rcx);
                    DREG(r10);
                }
                DREG(rax);
    #endif
            } while (0);
    
            // wait for exit from all ones we're tracing
            if (sysno == __NR_exit_group) {
                if (++exit_count == pidcount)
                    break;
            }
    
            if (ptrace(PTRACE_SYSCALL, child, NULL, NULL) < 0) {
                perror("ptrace");
                return 1;
            }
    
            ctl->ctl_seqno = seqno++;
            ctl->ctl_mode = ! ctl->ctl_mode;
    
            child = WAITFOR(&status);
        }
    
        fclose(xflog);
    
        return 0;
    }
    
    #define NRALL(_cmd) \
        _cmd(read) \
        _cmd(write) \
        _cmd(open) \
        _cmd(close) \
        _cmd(stat) \
        _cmd(fstat) \
        _cmd(lstat) \
        _cmd(poll) \
        _cmd(lseek) \
        _cmd(mmap) \
        _cmd(mprotect) \
        _cmd(munmap) \
        _cmd(brk) \
        _cmd(rt_sigaction) \
        _cmd(rt_sigprocmask) \
        _cmd(rt_sigreturn) \
        _cmd(ioctl) \
        _cmd(pread64) \
        _cmd(pwrite64) \
        _cmd(readv) \
        _cmd(writev) \
        _cmd(access) \
        _cmd(pipe) \
        _cmd(select) \
        _cmd(sched_yield) \
        _cmd(mremap) \
        _cmd(msync) \
        _cmd(mincore) \
        _cmd(madvise) \
        _cmd(shmget) \
        _cmd(shmat) \
        _cmd(shmctl) \
        _cmd(dup) \
        _cmd(dup2) \
        _cmd(pause) \
        _cmd(nanosleep) \
        _cmd(getitimer) \
        _cmd(alarm) \
        _cmd(setitimer) \
        _cmd(getpid) \
        _cmd(sendfile) \
        _cmd(socket) \
        _cmd(connect) \
        _cmd(accept) \
        _cmd(sendto) \
        _cmd(recvfrom) \
        _cmd(sendmsg) \
        _cmd(recvmsg) \
        _cmd(shutdown) \
        _cmd(bind) \
        _cmd(listen) \
        _cmd(getsockname) \
        _cmd(getpeername) \
        _cmd(socketpair) \
        _cmd(setsockopt) \
        _cmd(getsockopt) \
        _cmd(clone) \
        _cmd(fork) \
        _cmd(vfork) \
        _cmd(execve) \
        _cmd(exit) \
        _cmd(wait4) \
        _cmd(kill) \
        _cmd(uname) \
        _cmd(semget) \
        _cmd(semop) \
        _cmd(semctl) \
        _cmd(shmdt) \
        _cmd(msgget) \
        _cmd(msgsnd) \
        _cmd(msgrcv) \
        _cmd(msgctl) \
        _cmd(fcntl) \
        _cmd(flock) \
        _cmd(fsync) \
        _cmd(fdatasync) \
        _cmd(truncate) \
        _cmd(ftruncate) \
        _cmd(getdents) \
        _cmd(getcwd) \
        _cmd(chdir) \
        _cmd(fchdir) \
        _cmd(rename) \
        _cmd(mkdir) \
        _cmd(rmdir) \
        _cmd(creat) \
        _cmd(link) \
        _cmd(unlink) \
        _cmd(symlink) \
        _cmd(readlink) \
        _cmd(chmod) \
        _cmd(fchmod) \
        _cmd(chown) \
        _cmd(fchown) \
        _cmd(lchown) \
        _cmd(umask) \
        _cmd(gettimeofday) \
        _cmd(getrlimit) \
        _cmd(getrusage) \
        _cmd(sysinfo) \
        _cmd(times) \
        _cmd(ptrace) \
        _cmd(getuid) \
        _cmd(syslog) \
        _cmd(getgid) \
        _cmd(setuid) \
        _cmd(setgid) \
        _cmd(geteuid) \
        _cmd(getegid) \
        _cmd(setpgid) \
        _cmd(getppid) \
        _cmd(getpgrp) \
        _cmd(setsid) \
        _cmd(setreuid) \
        _cmd(setregid) \
        _cmd(getgroups) \
        _cmd(setgroups) \
        _cmd(setresuid) \
        _cmd(getresuid) \
        _cmd(setresgid) \
        _cmd(getresgid) \
        _cmd(getpgid) \
        _cmd(setfsuid) \
        _cmd(setfsgid) \
        _cmd(getsid) \
        _cmd(capget) \
        _cmd(capset) \
        _cmd(rt_sigpending) \
        _cmd(rt_sigtimedwait) \
        _cmd(rt_sigqueueinfo) \
        _cmd(rt_sigsuspend) \
        _cmd(sigaltstack) \
        _cmd(utime) \
        _cmd(mknod) \
        _cmd(uselib) \
        _cmd(personality) \
        _cmd(ustat) \
        _cmd(statfs) \
        _cmd(fstatfs) \
        _cmd(sysfs) \
        _cmd(getpriority) \
        _cmd(setpriority) \
        _cmd(sched_setparam) \
        _cmd(sched_getparam) \
        _cmd(sched_setscheduler) \
        _cmd(sched_getscheduler) \
        _cmd(sched_get_priority_max) \
        _cmd(sched_get_priority_min) \
        _cmd(sched_rr_get_interval) \
        _cmd(mlock) \
        _cmd(munlock) \
        _cmd(mlockall) \
        _cmd(munlockall) \
        _cmd(vhangup) \
        _cmd(modify_ldt) \
        _cmd(pivot_root) \
        _cmd(_sysctl) \
        _cmd(prctl) \
        _cmd(arch_prctl) \
        _cmd(adjtimex) \
        _cmd(setrlimit) \
        _cmd(chroot) \
        _cmd(sync) \
        _cmd(acct) \
        _cmd(settimeofday) \
        _cmd(mount) \
        _cmd(umount2) \
        _cmd(swapon) \
        _cmd(swapoff) \
        _cmd(reboot) \
        _cmd(sethostname) \
        _cmd(setdomainname) \
        _cmd(iopl) \
        _cmd(ioperm) \
        _cmd(create_module) \
        _cmd(init_module) \
        _cmd(delete_module) \
        _cmd(get_kernel_syms) \
        _cmd(query_module) \
        _cmd(quotactl) \
        _cmd(nfsservctl) \
        _cmd(getpmsg) \
        _cmd(putpmsg) \
        _cmd(afs_syscall) \
        _cmd(tuxcall) \
        _cmd(security) \
        _cmd(gettid) \
        _cmd(readahead) \
        _cmd(setxattr) \
        _cmd(lsetxattr) \
        _cmd(fsetxattr) \
        _cmd(getxattr) \
        _cmd(lgetxattr) \
        _cmd(fgetxattr) \
        _cmd(listxattr) \
        _cmd(llistxattr) \
        _cmd(flistxattr) \
        _cmd(removexattr) \
        _cmd(lremovexattr) \
        _cmd(fremovexattr) \
        _cmd(tkill) \
        _cmd(time) \
        _cmd(futex) \
        _cmd(sched_setaffinity) \
        _cmd(sched_getaffinity) \
        _cmd(set_thread_area) \
        _cmd(io_setup) \
        _cmd(io_destroy) \
        _cmd(io_getevents) \
        _cmd(io_submit) \
        _cmd(io_cancel) \
        _cmd(get_thread_area) \
        _cmd(lookup_dcookie) \
        _cmd(epoll_create) \
        _cmd(epoll_ctl_old) \
        _cmd(epoll_wait_old) \
        _cmd(remap_file_pages) \
        _cmd(getdents64) \
        _cmd(set_tid_address) \
        _cmd(restart_syscall) \
        _cmd(semtimedop) \
        _cmd(fadvise64) \
        _cmd(timer_create) \
        _cmd(timer_settime) \
        _cmd(timer_gettime) \
        _cmd(timer_getoverrun) \
        _cmd(timer_delete) \
        _cmd(clock_settime) \
        _cmd(clock_gettime) \
        _cmd(clock_getres) \
        _cmd(clock_nanosleep) \
        _cmd(exit_group) \
        _cmd(epoll_wait) \
        _cmd(epoll_ctl) \
        _cmd(tgkill) \
        _cmd(utimes) \
        _cmd(vserver) \
        _cmd(mbind) \
        _cmd(set_mempolicy) \
        _cmd(get_mempolicy) \
        _cmd(mq_open) \
        _cmd(mq_unlink) \
        _cmd(mq_timedsend) \
        _cmd(mq_timedreceive) \
        _cmd(mq_notify) \
        _cmd(mq_getsetattr) \
        _cmd(kexec_load) \
        _cmd(waitid) \
        _cmd(add_key) \
        _cmd(request_key) \
        _cmd(keyctl) \
        _cmd(ioprio_set) \
        _cmd(ioprio_get) \
        _cmd(inotify_init) \
        _cmd(inotify_add_watch) \
        _cmd(inotify_rm_watch) \
        _cmd(migrate_pages) \
        _cmd(openat) \
        _cmd(mkdirat) \
        _cmd(mknodat) \
        _cmd(fchownat) \
        _cmd(futimesat) \
        _cmd(newfstatat) \
        _cmd(unlinkat) \
        _cmd(renameat) \
        _cmd(linkat) \
        _cmd(symlinkat) \
        _cmd(readlinkat) \
        _cmd(fchmodat) \
        _cmd(faccessat) \
        _cmd(pselect6) \
        _cmd(ppoll) \
        _cmd(unshare) \
        _cmd(set_robust_list) \
        _cmd(get_robust_list) \
        _cmd(splice) \
        _cmd(tee) \
        _cmd(sync_file_range) \
        _cmd(vmsplice) \
        _cmd(move_pages) \
        _cmd(utimensat) \
        _cmd(epoll_pwait) \
        _cmd(signalfd) \
        _cmd(timerfd_create) \
        _cmd(eventfd) \
        _cmd(fallocate) \
        _cmd(timerfd_settime) \
        _cmd(timerfd_gettime) \
        _cmd(accept4) \
        _cmd(signalfd4) \
        _cmd(eventfd2) \
        _cmd(epoll_create1) \
        _cmd(dup3) \
        _cmd(pipe2) \
        _cmd(inotify_init1) \
        _cmd(preadv) \
        _cmd(pwritev) \
        _cmd(rt_tgsigqueueinfo) \
        _cmd(perf_event_open) \
        _cmd(recvmmsg) \
        _cmd(fanotify_init) \
        _cmd(fanotify_mark) \
        _cmd(prlimit64) \
        _cmd(name_to_handle_at) \
        _cmd(open_by_handle_at) \
        _cmd(clock_adjtime) \
        _cmd(syncfs) \
        _cmd(sendmmsg) \
        _cmd(setns) \
        _cmd(getcpu) \
        _cmd(process_vm_readv) \
        _cmd(process_vm_writev) \
        _cmd(kcmp) \
        _cmd(finit_module) \
        _cmd(sched_setattr) \
        _cmd(sched_getattr) \
        _cmd(renameat2) \
        _cmd(seccomp) \
        _cmd(getrandom) \
        _cmd(memfd_create) \
        _cmd(kexec_file_load) \
        _cmd(bpf) \
        _cmd(execveat) \
        _cmd(userfaultfd) \
        _cmd(membarrier) \
        _cmd(mlock2) \
        _cmd(copy_file_range) \
        _cmd(preadv2) \
        _cmd(pwritev2) \
        _cmd(pkey_mprotect) \
        _cmd(pkey_alloc) \
        _cmd(pkey_free) \
        _cmd(statx) \
        _cmd(io_pgetevents) \
        _cmd(rseq) \
        _cmd(pidfd_send_signal) \
        _cmd(io_uring_setup) \
        _cmd(io_uring_enter) \
        _cmd(io_uring_register) \
        _cmd(open_tree) \
        _cmd(move_mount) \
        _cmd(fsopen) \
        _cmd(fsconfig) \
        _cmd(fsmount) \
        _cmd(fspick) \
        _cmd(pidfd_open) \
        _cmd(clone3)
    
    #define NRSTR(_sym) \
        [__NR_##_sym] = #_sym,
    const char *NR_name[] = {
        NRALL(NRSTR)
    };
    
    const char *
    sysname(int sysno)
    {
    
        return NR_name[sysno];
    }
    

    Here is the test program:

    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <sys/wait.h>
    
    int opt_w;                              // 1=wait for child
    
    int
    main(int argc,char **argv)
    {
    
        --argc;
        ++argv;
    
        for (;  argc > 0;  --argc, ++argv) {
            char *cp = *argv;
            if (*cp != '-')
                break;
    
            cp += 2;
            switch (cp[-1]) {
            case 'w':
                opt_w = ! opt_w;
                break;
            }
        }
    
        int xid = 0;
    
        pid_t child = fork();
    
        if (child == 0) {
            sleep(1);
            ++xid;
        }
        srand(time(NULL));
    
        pid_t pid = getpid();
    
        setlinebuf(stdout);
        printf("%d: pid=%d\n",xid,pid);
    
        for (int i = 0; i < 5; i++) {
            printf("%d: %d\n", xid, rand() & 0xf);
        }
    
        sleep(5);
    
        if (opt_w && (child != 0))
            wait(NULL);
    
        return 0;
    }
    

    Here is the LOG file for the "buggy" case (e.g. -b). Notice that there is only one process traced and that there are no clone syscalls.

    pidfind: NEWPID ctl_xid=0 ctl_pid=00150066/1376358
    
    0: 0 AFT 59/execve
     rax=0000000000000000
    
    1: 0 BEF 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    2: 0 AFT 12/brk
     rax=000000000159F000
    
    3: 0 BEF 158/arch_prctl
     rax=FFFFFFFFFFFFFFDA
    
    4: 0 AFT 158/arch_prctl
     rax=FFFFFFFFFFFFFFEA
    
    5: 0 BEF 21/access
     rax=FFFFFFFFFFFFFFDA
    
    6: 0 AFT 21/access
     rax=FFFFFFFFFFFFFFFE
    
    7: 0 BEF 257/openat
     rax=FFFFFFFFFFFFFFDA
    
    8: 0 AFT 257/openat
     rax=0000000000000004
    
    9: 0 BEF 5/fstat
     rax=FFFFFFFFFFFFFFDA
    
    10: 0 AFT 5/fstat
     rax=0000000000000000
    
    11: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    12: 0 AFT 9/mmap
     rax=00007FC42DFE8000
    
    13: 0 BEF 3/close
     rax=FFFFFFFFFFFFFFDA
    
    14: 0 AFT 3/close
     rax=0000000000000000
    
    15: 0 BEF 257/openat
     rax=FFFFFFFFFFFFFFDA
    
    16: 0 AFT 257/openat
     rax=0000000000000004
    
    17: 0 BEF 0/read
     rax=FFFFFFFFFFFFFFDA
    
    18: 0 AFT 0/read
     rax=0000000000000340
    
    19: 0 BEF 8/lseek
     rax=FFFFFFFFFFFFFFDA
    
    20: 0 AFT 8/lseek
     rax=0000000000000318
    
    21: 0 BEF 0/read
     rax=FFFFFFFFFFFFFFDA
    
    22: 0 AFT 0/read
     rax=0000000000000044
    
    23: 0 BEF 5/fstat
     rax=FFFFFFFFFFFFFFDA
    
    24: 0 AFT 5/fstat
     rax=0000000000000000
    
    25: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    26: 0 AFT 9/mmap
     rax=00007FC42DFE6000
    
    27: 0 BEF 8/lseek
     rax=FFFFFFFFFFFFFFDA
    
    28: 0 AFT 8/lseek
     rax=0000000000000318
    
    29: 0 BEF 0/read
     rax=FFFFFFFFFFFFFFDA
    
    30: 0 AFT 0/read
     rax=0000000000000044
    
    31: 0 BEF 8/lseek
     rax=FFFFFFFFFFFFFFDA
    
    32: 0 AFT 8/lseek
     rax=0000000000000360
    
    33: 0 BEF 0/read
     rax=FFFFFFFFFFFFFFDA
    
    34: 0 AFT 0/read
     rax=0000000000000020
    
    35: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    36: 0 AFT 9/mmap
     rax=00007FC42DE20000
    
    37: 0 BEF 10/mprotect
     rax=FFFFFFFFFFFFFFDA
    
    38: 0 AFT 10/mprotect
     rax=0000000000000000
    
    39: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    40: 0 AFT 9/mmap
     rax=00007FC42DE42000
    
    41: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    42: 0 AFT 9/mmap
     rax=00007FC42DF8F000
    
    43: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    44: 0 AFT 9/mmap
     rax=00007FC42DFDC000
    
    45: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    46: 0 AFT 9/mmap
     rax=00007FC42DFE2000
    
    47: 0 BEF 3/close
     rax=FFFFFFFFFFFFFFDA
    
    48: 0 AFT 3/close
     rax=0000000000000000
    
    49: 0 BEF 158/arch_prctl
     rax=FFFFFFFFFFFFFFDA
    
    50: 0 AFT 158/arch_prctl
     rax=0000000000000000
    
    51: 0 BEF 10/mprotect
     rax=FFFFFFFFFFFFFFDA
    
    52: 0 AFT 10/mprotect
     rax=0000000000000000
    
    53: 0 BEF 10/mprotect
     rax=FFFFFFFFFFFFFFDA
    
    54: 0 AFT 10/mprotect
     rax=0000000000000000
    
    55: 0 BEF 10/mprotect
     rax=FFFFFFFFFFFFFFDA
    
    56: 0 AFT 10/mprotect
     rax=0000000000000000
    
    57: 0 BEF 11/munmap
     rax=FFFFFFFFFFFFFFDA
    
    58: 0 AFT 11/munmap
     rax=0000000000000000
    
    59: 0 BEF 56/clone
     rax=FFFFFFFFFFFFFFDA
    
    60: 0 AFT 56/clone
     rax=0000000000150067
    
    61: 0 BEF 39/getpid
     rax=FFFFFFFFFFFFFFDA
    
    62: 0 AFT 39/getpid
     rax=0000000000150066
    
    63: 0 BEF 5/fstat
     rax=FFFFFFFFFFFFFFDA
    
    64: 0 AFT 5/fstat
     rax=0000000000000000
    
    65: 0 BEF 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    66: 0 AFT 12/brk
     rax=000000000159F000
    
    67: 0 BEF 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    68: 0 AFT 12/brk
     rax=00000000015C0000
    
    69: 0 BEF 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    70: 0 AFT 12/brk
     rax=00000000015C0000
    
    71: 0 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    72: 0 AFT 1/write
     rax=000000000000000F
    
    73: 0 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    74: 0 AFT 1/write
     rax=0000000000000005
    
    75: 0 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    76: 0 AFT 1/write
     rax=0000000000000006
    
    77: 0 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    78: 0 AFT 1/write
     rax=0000000000000005
    
    79: 0 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    80: 0 AFT 1/write
     rax=0000000000000005
    
    81: 0 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    82: 0 AFT 1/write
     rax=0000000000000005
    
    83: 0 BEF 35/nanosleep
     rax=FFFFFFFFFFFFFFDA
    
    84: 0 AFT 35/nanosleep
     rax=0000000000000000
    
    85: 0 BEF 231/exit_group
     rax=FFFFFFFFFFFFFFDA
    

    Here is the LOG for the "fixed" case:

    pidfind: NEWPID ctl_xid=0 ctl_pid=0015006B/1376363
    
    0: 0 AFT 59/execve
     rax=0000000000000000
    
    1: 0 BEF 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    2: 0 AFT 12/brk
     rax=0000000000F4D000
    
    3: 0 BEF 158/arch_prctl
     rax=FFFFFFFFFFFFFFDA
    
    4: 0 AFT 158/arch_prctl
     rax=FFFFFFFFFFFFFFEA
    
    5: 0 BEF 21/access
     rax=FFFFFFFFFFFFFFDA
    
    6: 0 AFT 21/access
     rax=FFFFFFFFFFFFFFFE
    
    7: 0 BEF 257/openat
     rax=FFFFFFFFFFFFFFDA
    
    8: 0 AFT 257/openat
     rax=0000000000000004
    
    9: 0 BEF 5/fstat
     rax=FFFFFFFFFFFFFFDA
    
    10: 0 AFT 5/fstat
     rax=0000000000000000
    
    11: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    12: 0 AFT 9/mmap
     rax=00007FEE5BF30000
    
    13: 0 BEF 3/close
     rax=FFFFFFFFFFFFFFDA
    
    14: 0 AFT 3/close
     rax=0000000000000000
    
    15: 0 BEF 257/openat
     rax=FFFFFFFFFFFFFFDA
    
    16: 0 AFT 257/openat
     rax=0000000000000004
    
    17: 0 BEF 0/read
     rax=FFFFFFFFFFFFFFDA
    
    18: 0 AFT 0/read
     rax=0000000000000340
    
    19: 0 BEF 8/lseek
     rax=FFFFFFFFFFFFFFDA
    
    20: 0 AFT 8/lseek
     rax=0000000000000318
    
    21: 0 BEF 0/read
     rax=FFFFFFFFFFFFFFDA
    
    22: 0 AFT 0/read
     rax=0000000000000044
    
    23: 0 BEF 5/fstat
     rax=FFFFFFFFFFFFFFDA
    
    24: 0 AFT 5/fstat
     rax=0000000000000000
    
    25: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    26: 0 AFT 9/mmap
     rax=00007FEE5BF2E000
    
    27: 0 BEF 8/lseek
     rax=FFFFFFFFFFFFFFDA
    
    28: 0 AFT 8/lseek
     rax=0000000000000318
    
    29: 0 BEF 0/read
     rax=FFFFFFFFFFFFFFDA
    
    30: 0 AFT 0/read
     rax=0000000000000044
    
    31: 0 BEF 8/lseek
     rax=FFFFFFFFFFFFFFDA
    
    32: 0 AFT 8/lseek
     rax=0000000000000360
    
    33: 0 BEF 0/read
     rax=FFFFFFFFFFFFFFDA
    
    34: 0 AFT 0/read
     rax=0000000000000020
    
    35: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    36: 0 AFT 9/mmap
     rax=00007FEE5BD68000
    
    37: 0 BEF 10/mprotect
     rax=FFFFFFFFFFFFFFDA
    
    38: 0 AFT 10/mprotect
     rax=0000000000000000
    
    39: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    40: 0 AFT 9/mmap
     rax=00007FEE5BD8A000
    
    41: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    42: 0 AFT 9/mmap
     rax=00007FEE5BED7000
    
    43: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    44: 0 AFT 9/mmap
     rax=00007FEE5BF24000
    
    45: 0 BEF 9/mmap
     rax=FFFFFFFFFFFFFFDA
    
    46: 0 AFT 9/mmap
     rax=00007FEE5BF2A000
    
    47: 0 BEF 3/close
     rax=FFFFFFFFFFFFFFDA
    
    48: 0 AFT 3/close
     rax=0000000000000000
    
    49: 0 BEF 158/arch_prctl
     rax=FFFFFFFFFFFFFFDA
    
    50: 0 AFT 158/arch_prctl
     rax=0000000000000000
    
    51: 0 BEF 10/mprotect
     rax=FFFFFFFFFFFFFFDA
    
    52: 0 AFT 10/mprotect
     rax=0000000000000000
    
    53: 0 BEF 10/mprotect
     rax=FFFFFFFFFFFFFFDA
    
    54: 0 AFT 10/mprotect
     rax=0000000000000000
    
    55: 0 BEF 10/mprotect
     rax=FFFFFFFFFFFFFFDA
    
    56: 0 AFT 10/mprotect
     rax=0000000000000000
    
    57: 0 BEF 11/munmap
     rax=FFFFFFFFFFFFFFDA
    
    58: 0 AFT 11/munmap
     rax=0000000000000000
    
    59: 0 BEF 56/clone
     rax=FFFFFFFFFFFFFFDA
    
    60: 0 AFT 56/clone
     rax=FFFFFFFFFFFFFFDA
    
    pidfind: NEWPID ctl_xid=1 ctl_pid=0015006C/1376364
    61: 1 AFT 56/clone
     rax=0000000000000000
    
    62: 0 BEF 56/clone
     rax=000000000015006C
    
    63: 0 AFT 39/getpid
     rax=FFFFFFFFFFFFFFDA
    
    64: 1 BEF 35/nanosleep
     rax=FFFFFFFFFFFFFFDA
    
    65: 0 BEF 39/getpid
     rax=000000000015006B
    
    66: 0 AFT 5/fstat
     rax=FFFFFFFFFFFFFFDA
    
    67: 0 BEF 5/fstat
     rax=0000000000000000
    
    68: 0 AFT 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    69: 0 BEF 12/brk
     rax=0000000000F4D000
    
    70: 0 AFT 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    71: 0 BEF 12/brk
     rax=0000000000F6E000
    
    72: 0 AFT 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    73: 0 BEF 12/brk
     rax=0000000000F6E000
    
    74: 0 AFT 1/write
     rax=FFFFFFFFFFFFFFDA
    
    75: 0 BEF 1/write
     rax=000000000000000F
    
    76: 0 AFT 1/write
     rax=FFFFFFFFFFFFFFDA
    
    77: 0 BEF 1/write
     rax=0000000000000005
    
    78: 0 AFT 1/write
     rax=FFFFFFFFFFFFFFDA
    
    79: 0 BEF 1/write
     rax=0000000000000006
    
    80: 0 AFT 1/write
     rax=FFFFFFFFFFFFFFDA
    
    81: 0 BEF 1/write
     rax=0000000000000005
    
    82: 0 AFT 1/write
     rax=FFFFFFFFFFFFFFDA
    
    83: 0 BEF 1/write
     rax=0000000000000006
    
    84: 0 AFT 1/write
     rax=FFFFFFFFFFFFFFDA
    
    85: 0 BEF 1/write
     rax=0000000000000005
    
    86: 0 AFT 35/nanosleep
     rax=FFFFFFFFFFFFFFDA
    
    87: 1 AFT 35/nanosleep
     rax=0000000000000000
    
    88: 1 BEF 39/getpid
     rax=FFFFFFFFFFFFFFDA
    
    89: 1 AFT 39/getpid
     rax=000000000015006C
    
    90: 1 BEF 5/fstat
     rax=FFFFFFFFFFFFFFDA
    
    91: 1 AFT 5/fstat
     rax=0000000000000000
    
    92: 1 BEF 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    93: 1 AFT 12/brk
     rax=0000000000F4D000
    
    94: 1 BEF 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    95: 1 AFT 12/brk
     rax=0000000000F6E000
    
    96: 1 BEF 12/brk
     rax=FFFFFFFFFFFFFFDA
    
    97: 1 AFT 12/brk
     rax=0000000000F6E000
    
    98: 1 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    99: 1 AFT 1/write
     rax=000000000000000F
    
    100: 1 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    101: 1 AFT 1/write
     rax=0000000000000005
    
    102: 1 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    103: 1 AFT 1/write
     rax=0000000000000005
    
    104: 1 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    105: 1 AFT 1/write
     rax=0000000000000006
    
    106: 1 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    107: 1 AFT 1/write
     rax=0000000000000005
    
    108: 1 BEF 1/write
     rax=FFFFFFFFFFFFFFDA
    
    109: 1 AFT 1/write
     rax=0000000000000006
    
    110: 1 BEF 35/nanosleep
     rax=FFFFFFFFFFFFFFDA
    
    111: 0 BEF 35/nanosleep
     rax=0000000000000000
    
    112: 0 AFT 61/wait4
     rax=FFFFFFFFFFFFFFDA
    
    113: 1 AFT 35/nanosleep
     rax=0000000000000000
    
    114: 1 BEF 231/exit_group
     rax=FFFFFFFFFFFFFFDA
    
    EXIT: 1 status=00000000
    
    EXIT: 1 status=00000000