From: Denys Vlasenko Date: Fri, 16 Mar 2012 14:11:34 +0000 (+0100) Subject: Make alloc_tcb and droptcb static. No code changes. X-Git-Tag: v4.7~79 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=800ec8ffde1296b3f2cfdd838fb08f2ff2bbe946;p=strace Make alloc_tcb and droptcb static. No code changes. The change is trivial. Diff is large because it is confused by function definitions being moved around. * defs.h: Remove declarations of alloc_tcb and droptcb. * strace.c: Make alloc_tcb and droptcb static. Shuffle functions around to make compiler happy. Signed-off-by: Denys Vlasenko --- diff --git a/defs.h b/defs.h index 2c8814b8..3f60d161 100644 --- a/defs.h +++ b/defs.h @@ -460,10 +460,6 @@ void die_out_of_memory(void) __attribute__ ((noreturn)); extern void set_personality(int personality); extern const char *xlookup(const struct xlat *, int); -extern struct tcb *alloc_tcb(int, int); -extern void droptcb(struct tcb *); - -#define alloctcb(pid) alloc_tcb((pid), 1) extern void set_sortby(const char *); extern void set_overhead(int); diff --git a/strace.c b/strace.c index 6e22e8b0..7446b746 100644 --- a/strace.c +++ b/strace.c @@ -366,6 +366,88 @@ static void kill_save_errno(pid_t pid, int sig) errno = saved_errno; } +/* + * When strace is setuid executable, we have to swap uids + * before and after filesystem and process management operations. + */ +static void +swap_uid(void) +{ + int euid = geteuid(), uid = getuid(); + + if (euid != uid && setreuid(euid, uid) < 0) { + perror_msg_and_die("setreuid"); + } +} + +#if _LFS64_LARGEFILE +# define fopen_for_output fopen64 +#else +# define fopen_for_output fopen +#endif + +static FILE * +strace_fopen(const char *path) +{ + FILE *fp; + + swap_uid(); + fp = fopen_for_output(path, "w"); + if (!fp) + perror_msg_and_die("Can't fopen '%s'", path); + swap_uid(); + set_cloexec_flag(fileno(fp)); + return fp; +} + +static int popen_pid = 0; + +#ifndef _PATH_BSHELL +# define _PATH_BSHELL "/bin/sh" +#endif + +/* + * We cannot use standard popen(3) here because we have to distinguish + * popen child process from other processes we trace, and standard popen(3) + * does not export its child's pid. + */ +static FILE * +strace_popen(const char *command) +{ + FILE *fp; + int fds[2]; + + swap_uid(); + if (pipe(fds) < 0) + perror_msg_and_die("pipe"); + + set_cloexec_flag(fds[1]); /* never fails */ + + popen_pid = vfork(); + if (popen_pid == -1) + perror_msg_and_die("vfork"); + + if (popen_pid == 0) { + /* child */ + close(fds[1]); + if (fds[0] != 0) { + if (dup2(fds[0], 0)) + perror_msg_and_die("dup2"); + close(fds[0]); + } + execl(_PATH_BSHELL, "sh", "-c", command, NULL); + perror_msg_and_die("Can't execute '%s'", _PATH_BSHELL); + } + + /* parent */ + close(fds[0]); + swap_uid(); + fp = fdopen(fds[1], "w"); + if (!fp) + die_out_of_memory(); + return fp; +} + void tprintf(const char *fmt, ...) { @@ -491,96 +573,200 @@ tabto(void) tprints(acolumn_spaces + curcol); } -/* - * When strace is setuid executable, we have to swap uids - * before and after filesystem and process management operations. - */ static void -swap_uid(void) +newoutf(struct tcb *tcp) { - int euid = geteuid(), uid = getuid(); - - if (euid != uid && setreuid(euid, uid) < 0) { - perror_msg_and_die("setreuid"); + if (outfname && followfork >= 2) { + char name[520 + sizeof(int) * 3]; + sprintf(name, "%.512s.%u", outfname, tcp->pid); + tcp->outf = strace_fopen(name); } } -#if _LFS64_LARGEFILE -# define fopen_for_output fopen64 -#else -# define fopen_for_output fopen -#endif +static void +expand_tcbtab(void) +{ + /* Allocate some more TCBs and expand the table. + We don't want to relocate the TCBs because our + callers have pointers and it would be a pain. + So tcbtab is a table of pointers. Since we never + free the TCBs, we allocate a single chunk of many. */ + int i = tcbtabsize; + struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0])); + struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0])); + if (!newtab || !newtcbs) + die_out_of_memory(); + tcbtabsize *= 2; + tcbtab = newtab; + while (i < tcbtabsize) + tcbtab[i++] = newtcbs++; +} -static FILE * -strace_fopen(const char *path) +static struct tcb * +alloc_tcb(int pid, int command_options_parsed) { - FILE *fp; + int i; + struct tcb *tcp; - swap_uid(); - fp = fopen_for_output(path, "w"); - if (!fp) - perror_msg_and_die("Can't fopen '%s'", path); - swap_uid(); - set_cloexec_flag(fileno(fp)); - return fp; + if (nprocs == tcbtabsize) + expand_tcbtab(); + + for (i = 0; i < tcbtabsize; i++) { + tcp = tcbtab[i]; + if ((tcp->flags & TCB_INUSE) == 0) { + memset(tcp, 0, sizeof(*tcp)); + tcp->pid = pid; + tcp->flags = TCB_INUSE; + tcp->outf = outf; /* Initialise to current out file */ +#if SUPPORTED_PERSONALITIES > 1 + tcp->currpers = current_personality; +#endif + nprocs++; + if (debug_flag) + fprintf(stderr, "new tcb for pid %d, active tcbs:%d\n", tcp->pid, nprocs); + if (command_options_parsed) + newoutf(tcp); + return tcp; + } + } + error_msg_and_die("bug in alloc_tcb"); } +#define alloctcb(pid) alloc_tcb((pid), 1) -static int popen_pid = 0; +static void +droptcb(struct tcb *tcp) +{ + if (tcp->pid == 0) + return; -#ifndef _PATH_BSHELL -# define _PATH_BSHELL "/bin/sh" -#endif + nprocs--; + if (debug_flag) + fprintf(stderr, "dropped tcb for pid %d, %d remain\n", tcp->pid, nprocs); -/* - * We cannot use standard popen(3) here because we have to distinguish - * popen child process from other processes we trace, and standard popen(3) - * does not export its child's pid. + if (tcp->outf) { + if (outfname && followfork >= 2) { + if (tcp->curcol != 0) + fprintf(tcp->outf, " \n"); + fclose(tcp->outf); + if (outf == tcp->outf) + outf = NULL; + } else { + if (printing_tcp == tcp && tcp->curcol != 0) + fprintf(tcp->outf, " \n"); + fflush(tcp->outf); + } + } + + if (printing_tcp == tcp) + printing_tcp = NULL; + + memset(tcp, 0, sizeof(*tcp)); +} + +/* detach traced process; continue with sig + * Never call DETACH twice on the same process as both unattached and + * attached-unstopped processes give the same ESRCH. For unattached process we + * would SIGSTOP it and wait for its SIGSTOP notification forever. */ -static FILE * -strace_popen(const char *command) +static int +detach(struct tcb *tcp) { - FILE *fp; - int fds[2]; + int error; + int status, sigstop_expected; - swap_uid(); - if (pipe(fds) < 0) - perror_msg_and_die("pipe"); + if (tcp->flags & TCB_BPTSET) + clearbpt(tcp); - set_cloexec_flag(fds[1]); /* never fails */ + /* + * Linux wrongly insists the child be stopped + * before detaching. Arghh. We go through hoops + * to make a clean break of things. + */ +#if defined(SPARC) +#undef PTRACE_DETACH +#define PTRACE_DETACH PTRACE_SUNDETACH +#endif - popen_pid = vfork(); - if (popen_pid == -1) - perror_msg_and_die("vfork"); + error = 0; + sigstop_expected = 0; + if (tcp->flags & TCB_ATTACHED) { + /* + * We attached but possibly didn't see the expected SIGSTOP. + * We must catch exactly one as otherwise the detached process + * would be left stopped (process state T). + */ + sigstop_expected = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP); + error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, 0); + if (error == 0) { + /* On a clear day, you can see forever. */ + } + else if (errno != ESRCH) { + /* Shouldn't happen. */ + perror("detach: ptrace(PTRACE_DETACH, ...)"); + } + else if (my_tkill(tcp->pid, 0) < 0) { + if (errno != ESRCH) + perror("detach: checking sanity"); + } + else if (!sigstop_expected && my_tkill(tcp->pid, SIGSTOP) < 0) { + if (errno != ESRCH) + perror("detach: stopping child"); + } + else + sigstop_expected = 1; + } - if (popen_pid == 0) { - /* child */ - close(fds[1]); - if (fds[0] != 0) { - if (dup2(fds[0], 0)) - perror_msg_and_die("dup2"); - close(fds[0]); + if (sigstop_expected) { + for (;;) { +#ifdef __WALL + if (waitpid(tcp->pid, &status, __WALL) < 0) { + if (errno == ECHILD) /* Already gone. */ + break; + if (errno != EINVAL) { + perror("detach: waiting"); + break; + } +#endif /* __WALL */ + /* No __WALL here. */ + if (waitpid(tcp->pid, &status, 0) < 0) { + if (errno != ECHILD) { + perror("detach: waiting"); + break; + } +#ifdef __WCLONE + /* If no processes, try clones. */ + if (waitpid(tcp->pid, &status, __WCLONE) < 0) { + if (errno != ECHILD) + perror("detach: waiting"); + break; + } +#endif /* __WCLONE */ + } +#ifdef __WALL + } +#endif + if (!WIFSTOPPED(status)) { + /* Au revoir, mon ami. */ + break; + } + if (WSTOPSIG(status) == SIGSTOP) { + ptrace_restart(PTRACE_DETACH, tcp, 0); + break; + } + error = ptrace_restart(PTRACE_CONT, tcp, + WSTOPSIG(status) == syscall_trap_sig ? 0 + : WSTOPSIG(status)); + if (error < 0) + break; } - execl(_PATH_BSHELL, "sh", "-c", command, NULL); - perror_msg_and_die("Can't execute '%s'", _PATH_BSHELL); } - /* parent */ - close(fds[0]); - swap_uid(); - fp = fdopen(fds[1], "w"); - if (!fp) - die_out_of_memory(); - return fp; -} + if (!qflag && (tcp->flags & TCB_ATTACHED)) + fprintf(stderr, "Process %u detached\n", tcp->pid); -static void -newoutf(struct tcb *tcp) -{ - if (outfname && followfork >= 2) { - char name[520 + sizeof(int) * 3]; - sprintf(name, "%.512s.%u", outfname, tcp->pid); - tcp->outf = strace_fopen(name); - } + droptcb(tcp); + + return error; } static void @@ -1507,55 +1693,6 @@ init(int argc, char *argv[]) print_pid_pfx = (outfname && followfork < 2 && (followfork == 1 || nprocs > 1)); } -static void -expand_tcbtab(void) -{ - /* Allocate some more TCBs and expand the table. - We don't want to relocate the TCBs because our - callers have pointers and it would be a pain. - So tcbtab is a table of pointers. Since we never - free the TCBs, we allocate a single chunk of many. */ - int i = tcbtabsize; - struct tcb *newtcbs = calloc(tcbtabsize, sizeof(newtcbs[0])); - struct tcb **newtab = realloc(tcbtab, tcbtabsize * 2 * sizeof(tcbtab[0])); - if (!newtab || !newtcbs) - die_out_of_memory(); - tcbtabsize *= 2; - tcbtab = newtab; - while (i < tcbtabsize) - tcbtab[i++] = newtcbs++; -} - -struct tcb * -alloc_tcb(int pid, int command_options_parsed) -{ - int i; - struct tcb *tcp; - - if (nprocs == tcbtabsize) - expand_tcbtab(); - - for (i = 0; i < tcbtabsize; i++) { - tcp = tcbtab[i]; - if ((tcp->flags & TCB_INUSE) == 0) { - memset(tcp, 0, sizeof(*tcp)); - tcp->pid = pid; - tcp->flags = TCB_INUSE; - tcp->outf = outf; /* Initialise to current out file */ -#if SUPPORTED_PERSONALITIES > 1 - tcp->currpers = current_personality; -#endif - nprocs++; - if (debug_flag) - fprintf(stderr, "new tcb for pid %d, active tcbs:%d\n", tcp->pid, nprocs); - if (command_options_parsed) - newoutf(tcp); - return tcp; - } - } - error_msg_and_die("bug in alloc_tcb"); -} - static struct tcb * pid2tcb(int pid) { @@ -1573,142 +1710,6 @@ pid2tcb(int pid) return NULL; } -void -droptcb(struct tcb *tcp) -{ - if (tcp->pid == 0) - return; - - nprocs--; - if (debug_flag) - fprintf(stderr, "dropped tcb for pid %d, %d remain\n", tcp->pid, nprocs); - - if (tcp->outf) { - if (outfname && followfork >= 2) { - if (tcp->curcol != 0) - fprintf(tcp->outf, " \n"); - fclose(tcp->outf); - if (outf == tcp->outf) - outf = NULL; - } else { - if (printing_tcp == tcp && tcp->curcol != 0) - fprintf(tcp->outf, " \n"); - fflush(tcp->outf); - } - } - - if (printing_tcp == tcp) - printing_tcp = NULL; - - memset(tcp, 0, sizeof(*tcp)); -} - -/* detach traced process; continue with sig - * Never call DETACH twice on the same process as both unattached and - * attached-unstopped processes give the same ESRCH. For unattached process we - * would SIGSTOP it and wait for its SIGSTOP notification forever. - */ -static int -detach(struct tcb *tcp) -{ - int error; - int status, sigstop_expected; - - if (tcp->flags & TCB_BPTSET) - clearbpt(tcp); - - /* - * Linux wrongly insists the child be stopped - * before detaching. Arghh. We go through hoops - * to make a clean break of things. - */ -#if defined(SPARC) -#undef PTRACE_DETACH -#define PTRACE_DETACH PTRACE_SUNDETACH -#endif - - error = 0; - sigstop_expected = 0; - if (tcp->flags & TCB_ATTACHED) { - /* - * We attached but possibly didn't see the expected SIGSTOP. - * We must catch exactly one as otherwise the detached process - * would be left stopped (process state T). - */ - sigstop_expected = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP); - error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, 0); - if (error == 0) { - /* On a clear day, you can see forever. */ - } - else if (errno != ESRCH) { - /* Shouldn't happen. */ - perror("detach: ptrace(PTRACE_DETACH, ...)"); - } - else if (my_tkill(tcp->pid, 0) < 0) { - if (errno != ESRCH) - perror("detach: checking sanity"); - } - else if (!sigstop_expected && my_tkill(tcp->pid, SIGSTOP) < 0) { - if (errno != ESRCH) - perror("detach: stopping child"); - } - else - sigstop_expected = 1; - } - - if (sigstop_expected) { - for (;;) { -#ifdef __WALL - if (waitpid(tcp->pid, &status, __WALL) < 0) { - if (errno == ECHILD) /* Already gone. */ - break; - if (errno != EINVAL) { - perror("detach: waiting"); - break; - } -#endif /* __WALL */ - /* No __WALL here. */ - if (waitpid(tcp->pid, &status, 0) < 0) { - if (errno != ECHILD) { - perror("detach: waiting"); - break; - } -#ifdef __WCLONE - /* If no processes, try clones. */ - if (waitpid(tcp->pid, &status, __WCLONE) < 0) { - if (errno != ECHILD) - perror("detach: waiting"); - break; - } -#endif /* __WCLONE */ - } -#ifdef __WALL - } -#endif - if (!WIFSTOPPED(status)) { - /* Au revoir, mon ami. */ - break; - } - if (WSTOPSIG(status) == SIGSTOP) { - ptrace_restart(PTRACE_DETACH, tcp, 0); - break; - } - error = ptrace_restart(PTRACE_CONT, tcp, - WSTOPSIG(status) == syscall_trap_sig ? 0 - : WSTOPSIG(status)); - if (error < 0) - break; - } - } - - if (!qflag && (tcp->flags & TCB_ATTACHED)) - fprintf(stderr, "Process %u detached\n", tcp->pid); - - droptcb(tcp); - - return error; -} - static void cleanup(void) {