int run()

in cli/bpfcov.c [1050:1185]


int run(struct root_args *args)
{
    log_info(args, "executing program '%s'\n", args->program[0]);

    pid_t pid = fork();
    switch (pid)
    {
    case -1: /* Error */
        log_fata(args, "%s\n", strerror(errno));
    case 0: /* Child */
        if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0)
        {
            log_fata(args, "%s\n", strerror(errno));
        }
        execvp(args->program[0], args->program);
        log_fata(args, "%s\n", strerror(errno));
    }

    /* Parent */
    waitpid(pid, 0, 0); // sync with PTRACE_TRACEME
    ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL);

    int is_map = 0;
    for (;;)
    {
        /* Enter next system call */
        if (ptrace(PTRACE_SYSCALL, pid, 0, 0) == -1)
        {
            log_fata(args, "%s\n", strerror(errno));
        }

        /* Waiting for PID to die */
        if (waitpid(pid, 0, 0) == -1)
        {
            log_fata(args, "%s\n", strerror(errno));
        }

        /* Gather system call arguments */
        struct user_regs_struct regs;
        if (ptrace(PTRACE_GETREGS, pid, 0, &regs) == -1)
        {
            log_fata(args, "%s\n", strerror(errno));
        }

        /* Mark bpf(BPF_MAP_CREATE, ...) */
        const unsigned int sysc = regs.orig_rax;
        const unsigned int comm = regs.rdi;
        is_map = (sysc == SYS_bpf && comm == BPF_MAP_CREATE);

        /* Print a representation of the system call */
        log_debu(args,
                 "%d(%d, %ld, %ld, %ld, %ld, %ld)",
                 sysc,
                 comm, (long)regs.rsi, (long)regs.rdx, (long)regs.r10, (long)regs.r8, (long)regs.r9);

        /* Run system call and stop on exit */
        if (ptrace(PTRACE_SYSCALL, pid, 0, 0) == -1)
        {
            log_fata(args, "%s\n", strerror(errno));
        }

        /* Waiting for PID to die */
        if (waitpid(pid, 0, 0) == -1)
        {
            log_fata(args, "%s\n", strerror(errno));
        }

        /* Get system call result */
        if (ptrace(PTRACE_GETREGS, pid, 0, &regs) == -1)
        {
            if (DEBUG) {
                print_log(3, NULL, args, "%s\n", " = ?");
            }
            if (errno == ESRCH)
            {
                exit(regs.rdi); // _exit(2) or similar
            }
            log_fata(args, "%s\n", strerror(errno));
        }

        /* Print system call result */
        long result = regs.rax;
        if (DEBUG) {
            print_log(3, NULL, args, " = %ld\n", result);
        }

        /* Pin the bpfcov maps */
        if (is_map && result)
        {
            int pidfd = syscall(SYS_pidfd_open, pid, 0);
            if (pidfd < 0)
            {
                continue;
            }
            int curfd = syscall(SYS_pidfd_getfd, pidfd, result, 0);
            if (curfd < 0)
            {
                continue;
            }
            close(pidfd);

            struct bpf_map_info map_info = {};
            int err;
            err = get_map_info(curfd, &map_info);
            if (!err && strlen(map_info.name) > 0)
            {
                log_info(args, "got info about map '%s'\n", map_info.name);

                char map_name[BPF_OBJ_NAME_LEN];
                strcpy(map_name, map_info.name);

                const char *sep = ".";
                strtok(map_info.name, sep);
                char *suffix = strtok(NULL, sep);

                char *pin_path = "";
                if (get_pin_path(args, suffix, &pin_path))
                {
                    err = bpf_obj_pin(curfd, pin_path);
                    if (err)
                    {
                        if (errno == EEXIST)
                        {
                            log_warn(args, "pin '%s' already exists for map '%s'\n", pin_path, map_name);
                            continue;
                        }
                        log_fata(args, "%s\n", "could not pin map");
                    }
                    log_warn(args, "pin map '%s' to '%s'\n", map_name, pin_path);
                }
            }
        }
    }

    return 0;
}