diff options
Diffstat (limited to 'options.c')
-rw-r--r-- | options.c | 374 |
1 files changed, 192 insertions, 182 deletions
@@ -2,6 +2,10 @@ #include "config.h" #endif +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "0.3.32" +#endif + #include <string.h> #include <stdlib.h> #include <unistd.h> @@ -21,7 +25,7 @@ char *library[MAX_LIBRARY]; int library_num = 0; static char *progname; /* Program name (`ltrace') */ -FILE *output; +FILE * output; int opt_a = DEFAULT_ACOLUMN; /* default alignment column for results */ int opt_c = 0; /* Count time, calls, and report a summary on program exit */ int opt_d = 0; /* debug */ @@ -30,7 +34,7 @@ int opt_s = DEFAULT_STRLEN; /* default maximum # of bytes printed in strings */ int opt_S = 0; /* display syscalls */ int opt_L = 1; /* display library calls */ int opt_f = 0; /* trace child processes as they are created */ -char *opt_u = NULL; /* username to run command as */ +char * opt_u = NULL; /* username to run command as */ int opt_r = 0; /* print relative timestamp */ int opt_t = 0; /* print absolute timestamp */ #ifdef USE_DEMANGLE @@ -40,81 +44,91 @@ int opt_n = 0; /* indent trace output according to program flow */ int opt_T = 0; /* show the time spent inside each call */ /* List of pids given to option -p: */ -struct opt_p_t *opt_p = NULL; /* attach to process with a given pid */ +struct opt_p_t * opt_p = NULL; /* attach to process with a given pid */ /* List of function names given to option -e: */ -struct opt_e_t *opt_e = NULL; -int opt_e_enable = 1; +struct opt_e_t * opt_e = NULL; +int opt_e_enable=1; + +/* List of global function names given to -x: */ +struct opt_e_t * opt_x = NULL; + +/* Set a break on the routine named here in order to re-initialize breakpoints + after all the PLTs have been initialzed */ +char * PLTs_initialized_by_here = PLTs_INIT_BY_HERE; -static void usage(void) -{ +static void +usage(void) { #if !(HAVE_GETOPT || HAVE_GETOPT_LONG) fprintf(stdout, "Usage: %s [command [arg ...]]\n" - "Trace library calls of a given program.\n\n", progname); +"Trace library calls of a given program.\n\n", progname); #else fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n" - "Trace library calls of a given program.\n\n" +"Trace library calls of a given program.\n\n" + # if HAVE_GETOPT_LONG - " -a, --align=COLUMN align return values in a secific column.\n" +" -a, --align=COLUMN align return values in a secific column.\n" # else - " -a COLUMN align return values in a secific column.\n" +" -a COLUMN align return values in a secific column.\n" # endif - " -c count time and calls, and report a summary on exit.\n" +" -c count time and calls, and report a summary on exit.\n" # ifdef USE_DEMANGLE # if HAVE_GETOPT_LONG - " -C, --demangle decode low-level symbol names into user-level names.\n" +" -C, --demangle decode low-level symbol names into user-level names.\n" # else - " -C decode low-level symbol names into user-level names.\n" +" -C decode low-level symbol names into user-level names.\n" # endif # endif # if HAVE_GETOPT_LONG - " -d, --debug print debugging info.\n" +" -d, --debug print debugging info.\n" # else - " -d print debugging info.\n" +" -d print debugging info.\n" # endif - " -e expr modify which events to trace.\n" - " -f follow forks.\n" +" -e expr modify which events to trace.\n" +" -f follow forks.\n" # if HAVE_GETOPT_LONG - " -h, --help display this help and exit.\n" +" -h, --help display this help and exit.\n" # else - " -h display this help and exit.\n" +" -h display this help and exit.\n" # endif - " -i print instruction pointer at time of library call.\n" +" -i print instruction pointer at time of library call.\n" # if HAVE_GETOPT_LONG - " -l, --library=FILE print library calls from this library only.\n" +" -l, --library=FILE print library calls from this library only.\n" # else - " -l FILE print library calls from this library only.\n" +" -l FILE print library calls from this library only.\n" # endif - " -L do NOT display library calls.\n" +" -L do NOT display library calls.\n" # if HAVE_GETOPT_LONG - " -n, --indent=NR indent output by NR spaces for each call level nesting.\n" +" -n, --indent=NR indent output by NR spaces for each call level nesting.\n" # else - " -n NR indent output by NR spaces for each call level nesting.\n" +" -n NR indent output by NR spaces for each call level nesting.\n" # endif # if HAVE_GETOPT_LONG - " -o, --output=FILE write the trace output to that file.\n" +" -o, --output=FILE write the trace output to that file.\n" # else - " -o FILE write the trace output to that file.\n" +" -o FILE write the trace output to that file.\n" # endif - " -p PID attach to the process with the process ID pid.\n" - " -r print relative timestamps.\n" - " -s STRLEN specify the maximum string size to print.\n" - " -S display system calls.\n" - " -t, -tt, -ttt print absolute timestamps.\n" - " -T show the time spent inside each call.\n" - " -u USERNAME run command with the userid, groupid of username.\n" +" -p PID attach to the process with the process ID pid.\n" +" -r print relative timestamps.\n" +" -s STRLEN specify the maximum string size to print.\n" +" -S display system calls.\n" +" -t, -tt, -ttt print absolute timestamps.\n" +" -T show the time spent inside each call.\n" +" -u USERNAME run command with the userid, groupid of username.\n" # if HAVE_GETOPT_LONG - " -V, --version output version information and exit.\n" +" -V, --version output version information and exit.\n" # else - " -V output version information and exit.\n" +" -V output version information and exit.\n" # endif - "\nReport bugs to Juan Cespedes <cespedes@debian.org>\n", - progname); +" -x NAME treat the global NAME like a library subroutine.\n" +" -X NAME same as -x; and PLT's will be initialized by here.\n" +"\nReport bugs to Juan Cespedes <cespedes@debian.org>\n" + , progname); #endif } -static char *search_for_command(char *filename) -{ +static char * +search_for_command(char * filename) { static char pathname[PATH_MAX]; char *path; int m, n; @@ -145,193 +159,189 @@ static char *search_for_command(char *filename) return filename; } -char **process_options(int argc, char **argv) -{ +char ** +process_options(int argc, char **argv) { progname = argv[0]; output = stderr; #if HAVE_GETOPT || HAVE_GETOPT_LONG - while (1) { + while(1) { int c; #if HAVE_GETOPT_LONG int option_index = 0; static struct option long_options[] = { - {"align", 1, 0, 'a'}, - {"debug", 0, 0, 'd'}, + { "align", 1, 0, 'a'}, + { "debug", 0, 0, 'd'}, # ifdef USE_DEMANGLE - {"demangle", 0, 0, 'C'}, + { "demangle", 0, 0, 'C'}, #endif - {"indent", 1, 0, 'n'}, - {"help", 0, 0, 'h'}, - {"library", 1, 0, 'l'}, - {"output", 1, 0, 'o'}, - {"version", 0, 0, 'V'}, - {0, 0, 0, 0} + { "indent", 1, 0, 'n'}, + { "help", 0, 0, 'h'}, + { "library", 1, 0, 'l'}, + { "output", 1, 0, 'o'}, + { "version", 0, 0, 'V'}, + { 0, 0, 0, 0} }; c = getopt_long(argc, argv, "+cdfhiLrStTV" # ifdef USE_DEMANGLE - "C" + "C" # endif - "a:e:l:n:o:p:s:u:", long_options, - &option_index); + "a:e:l:n:o:p:s:u:x:X:", long_options, &option_index); #else c = getopt(argc, argv, "+cdfhiLrStTV" # ifdef USE_DEMANGLE - "C" + "C" # endif - "a:e:l:n:o:p:s:u:"); + "a:e:l:n:o:p:s:u:x:X:"); #endif - if (c == -1) { + if (c==-1) { break; } - switch (c) { - case 'a': - opt_a = atoi(optarg); - break; - case 'c': - opt_c++; - break; + switch(c) { + case 'a': opt_a = atoi(optarg); + break; + case 'c': opt_c++; + break; #ifdef USE_DEMANGLE - case 'C': - opt_C++; - break; + case 'C': opt_C++; + break; #endif - case 'd': - opt_d++; - break; - case 'e': - { - char *str_e = strdup(optarg); - if (!str_e) { - perror("ltrace: strdup"); - exit(1); - } - if (str_e[0] == '!') { - opt_e_enable = 0; - str_e++; - } - while (*str_e) { - struct opt_e_t *tmp; - char *str2 = strchr(str_e, ','); - if (str2) { - *str2 = '\0'; + case 'd': opt_d++; + break; + case 'e': + { + char * str_e = strdup(optarg); + if (!str_e) { + perror("ltrace: strdup"); + exit(1); + } + if (str_e[0]=='!') { + opt_e_enable=0; + str_e++; } - tmp = malloc(sizeof(struct opt_e_t)); + while(*str_e) { + struct opt_e_t * tmp; + char *str2 = strchr(str_e,','); + if (str2) { + *str2 = '\0'; + } + tmp = malloc(sizeof(struct opt_e_t)); + if (!tmp) { + perror("ltrace: malloc"); + exit(1); + } + tmp->name = str_e; + tmp->next = opt_e; + opt_e = tmp; + if (str2) { + str_e = str2+1; + } else { + break; + } + } + break; + } + case 'f': opt_f = 1; + break; + case 'h': usage(); + exit(0); + case 'i': opt_i++; + break; + case 'l': if (library_num == MAX_LIBRARY) { + fprintf(stderr, "Too many libraries. Maximum is %i.\n", MAX_LIBRARY); + exit(1); + } + library[library_num++] = optarg; + break; + case 'L': opt_L = 0; + break; + case 'n': opt_n = atoi(optarg); + break; + case 'o': output = fopen(optarg, "w"); + if (!output) { + fprintf(stderr, "Can't open %s for output: %s\n", optarg, strerror(errno)); + exit(1); + } + setvbuf(output, (char *)NULL, _IOLBF, 0); + fcntl(fileno(output), F_SETFD, FD_CLOEXEC); + break; + case 'p': + { + struct opt_p_t * tmp = malloc(sizeof(struct opt_p_t)); if (!tmp) { perror("ltrace: malloc"); exit(1); } - tmp->name = str_e; - tmp->next = opt_e; - opt_e = tmp; - if (str2) { - str_e = str2 + 1; - } else { + tmp->pid = atoi(optarg); + tmp->next = opt_p; + opt_p = tmp; + break; + } + case 'r': opt_r++; break; + case 's': opt_s = atoi(optarg); + break; + case 'S': opt_S = 1; + break; + case 't': opt_t++; + break; + case 'T': opt_T++; + break; + case 'u': opt_u = optarg; + break; + case 'V': printf("ltrace version " PACKAGE_VERSION ".\n" +"Copyright (C) 1997-2006 Juan Cespedes <cespedes@debian.org>.\n" +"This is free software; see the GNU General Public Licence\n" +"version 2 or later for copying conditions. There is NO warranty.\n"); + exit(0); + case 'X': PLTs_initialized_by_here = optarg; + /* Fall Thru */ + + case 'x': + { + struct opt_e_t * p = opt_x; + + /* First, check for duplicate. */ + while (p && strcmp(p->name, optarg)) { + p = p->next; } + if (p) { break; } + + /* If not duplicate, add to list. */ + p = malloc(sizeof(struct opt_e_t)); + if (!p) { + perror("ltrace: malloc"); + exit(1); + } + p->name = optarg; + p->next = opt_x; + opt_x = p; + break; } - break; - } - case 'f': - opt_f = 1; - break; - case 'h': - usage(); - exit(0); - case 'i': - opt_i++; - break; - case 'l': - if (library_num == MAX_LIBRARY) { - fprintf(stderr, - "Too many libraries. Maximum is %i.\n", - MAX_LIBRARY); - exit(1); - } - library[library_num++] = optarg; - break; - case 'L': - opt_L = 0; - break; - case 'n': - opt_n = atoi(optarg); - break; - case 'o': - output = fopen(optarg, "w"); - if (!output) { - fprintf(stderr, - "Can't open %s for output: %s\n", - optarg, strerror(errno)); - exit(1); - } - setvbuf(output, (char *)NULL, _IOLBF, 0); - fcntl(fileno(output), F_SETFD, FD_CLOEXEC); - break; - case 'p': - { - struct opt_p_t *tmp = - malloc(sizeof(struct opt_p_t)); - if (!tmp) { - perror("ltrace: malloc"); - exit(1); - } - tmp->pid = atoi(optarg); - tmp->next = opt_p; - opt_p = tmp; - break; - } - case 'r': - opt_r++; - break; - case 's': - opt_s = atoi(optarg); - break; - case 'S': - opt_S = 1; - break; - case 't': - opt_t++; - break; - case 'T': - opt_T++; - break; - case 'u': - opt_u = optarg; - break; - case 'V': - printf("ltrace version " PACKAGE_VERSION ".\n" - "Copyright (C) 1997-2006 Juan Cespedes <cespedes@debian.org>.\n" - "This is free software; see the GNU General Public Licence\n" - "version 2 or later for copying conditions. There is NO warranty.\n"); - exit(0); - default: + + default: #if HAVE_GETOPT_LONG - fprintf(stderr, - "Try `%s --help' for more information\n", - progname); + fprintf(stderr, "Try `%s --help' for more information\n", progname); #else - fprintf(stderr, "Try `%s -h' for more information\n", - progname); + fprintf(stderr, "Try `%s -h' for more information\n", progname); #endif - exit(1); + exit(1); } } - argc -= optind; - argv += optind; + argc -= optind; argv += optind; #endif - if (!opt_p && argc < 1) { + if (!opt_p && argc<1) { fprintf(stderr, "%s: too few arguments\n", progname); usage(); exit(1); } if (opt_r && opt_t) { - fprintf(stderr, "%s: Incompatible options -r and -t\n", - progname); + fprintf(stderr, "%s: Incompatible options -r and -t\n", progname); exit(1); } - if (argc > 0) { + if (argc>0) { command = search_for_command(argv[0]); } return &argv[0]; |