Home | History | Annotate | Download | only in ltrace
      1 /*
      2  * This file is part of ltrace.
      3  * Copyright (C) 2012, 2013, 2014 Petr Machata, Red Hat Inc.
      4  * Copyright (C) 2009,2010 Joe Damato
      5  * Copyright (C) 1998,1999,2002,2003,2004,2007,2008,2009 Juan Cespedes
      6  * Copyright (C) 2006 Ian Wienand
      7  * Copyright (C) 2006 Steve Fink
      8  * Copyright (C) 2006 Paul Gilliam, IBM Corporation
      9  *
     10  * This program is free software; you can redistribute it and/or
     11  * modify it under the terms of the GNU General Public License as
     12  * published by the Free Software Foundation; either version 2 of the
     13  * License, or (at your option) any later version.
     14  *
     15  * This program is distributed in the hope that it will be useful, but
     16  * WITHOUT ANY WARRANTY; without even the implied warranty of
     17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18  * General Public License for more details.
     19  *
     20  * You should have received a copy of the GNU General Public License
     21  * along with this program; if not, write to the Free Software
     22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
     23  * 02110-1301 USA
     24  */
     25 
     26 #include "config.h"
     27 
     28 #include <sys/ioctl.h>
     29 #include <sys/stat.h>
     30 #include <sys/types.h>
     31 #include <assert.h>
     32 #include <errno.h>
     33 #include <fcntl.h>
     34 #include <getopt.h>
     35 #include <limits.h>
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <string.h>
     39 #include <unistd.h>
     40 
     41 #include "common.h"
     42 #include "filter.h"
     43 #include "glob.h"
     44 #include "demangle.h"
     45 
     46 struct options_t options = {
     47 	.align    = DEFAULT_ALIGN,    /* alignment column for results */
     48 	.user     = NULL,             /* username to run command as */
     49 	.syscalls = 0,                /* display syscalls */
     50 #ifdef USE_DEMANGLE
     51 	.demangle = 0,                /* Demangle low-level symbol names */
     52 #endif
     53 	.indent = 0,                  /* indent output according to program flow */
     54 	.output = NULL,               /* output to a specific file */
     55 	.summary = 0,                 /* Report a summary on program exit */
     56 	.debug = 0,                   /* debug */
     57 	.arraylen = DEFAULT_ARRAYLEN, /* maximum # array elements to print */
     58 	.strlen = DEFAULT_STRLEN,     /* maximum # of bytes printed in strings */
     59 	.follow = 0,                  /* trace child processes */
     60 };
     61 
     62 static char *progname;		/* Program name (`ltrace') */
     63 int opt_i = 0;			/* instruction pointer */
     64 int opt_r = 0;			/* print relative timestamp */
     65 int opt_t = 0;			/* print absolute timestamp */
     66 int opt_T = 0;			/* show the time spent inside each call */
     67 
     68 /* List of pids given to option -p: */
     69 struct opt_p_t *opt_p = NULL;	/* attach to process with a given pid */
     70 
     71 /* Vector of struct opt_F_t.  */
     72 struct vect opt_F;
     73 
     74 static void
     75 err_usage(void) {
     76 	fprintf(stderr, "Try `%s --help' for more information.\n", progname);
     77 	exit(1);
     78 }
     79 
     80 static void
     81 usage(void) {
     82 	fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n"
     83 		"Trace library calls of a given program.\n\n"
     84 		"  -a, --align=COLUMN  align return values in a secific column.\n"
     85 		"  -A MAXELTS          maximum number of array elements to print.\n"
     86 		"  -b, --no-signals    don't print signals.\n"
     87 		"  -c                  count time and calls, and report a summary on exit.\n"
     88 # ifdef USE_DEMANGLE
     89 		"  -C, --demangle      decode low-level symbol names into user-level names.\n"
     90 # endif
     91 		"  -D, --debug=MASK    enable debugging (see -Dh or --debug=help).\n"
     92 		"  -Dh, --debug=help   show help on debugging.\n"
     93 		"  -e FILTER           modify which library calls to trace.\n"
     94 		"  -f                  trace children (fork() and clone()).\n"
     95 		"  -F, --config=FILE   load alternate configuration file (may be repeated).\n"
     96 		"  -h, --help          display this help and exit.\n"
     97 		"  -i                  print instruction pointer at time of library call.\n"
     98 		"  -l, --library=LIBRARY_PATTERN only trace symbols implemented by this library.\n"
     99 		"  -L                  do NOT display library calls.\n"
    100 		"  -n, --indent=NR     indent output by NR spaces for each call level nesting.\n"
    101 		"  -o, --output=FILENAME write the trace output to file with given name.\n"
    102 		"  -p PID              attach to the process with the process ID pid.\n"
    103 		"  -r                  print relative timestamps.\n"
    104 		"  -s STRSIZE          specify the maximum string size to print.\n"
    105 		"  -S                  trace system calls as well as library calls.\n"
    106 		"  -t, -tt, -ttt       print absolute timestamps.\n"
    107 		"  -T                  show the time spent inside each call.\n"
    108 		"  -u USERNAME         run command with the userid, groupid of username.\n"
    109 		"  -V, --version       output version information and exit.\n"
    110 #if defined(HAVE_UNWINDER)
    111 		"  -w, --where=NR      print backtrace showing NR stack frames at most.\n"
    112 #endif /* defined(HAVE_UNWINDER) */
    113 		"  -x FILTER           modify which static functions to trace.\n"
    114 		"\nReport bugs to ltrace-devel (at) lists.alioth.debian.org\n",
    115 		progname);
    116 }
    117 
    118 static void
    119 usage_debug(void) {
    120 	fprintf(stdout, "%s debugging option, --debug=<octal> or -D<octal>:\n", progname);
    121 	fprintf(stdout,
    122 			"\n"
    123 			" number  ref. in source   description\n"
    124 			"      1   general           Generally helpful progress information\n"
    125 			"     10   event             Shows every event received by a traced process\n"
    126 			"     20   process           Shows actions carried upon a traced processes\n"
    127 			"     40   function          Shows every entry to internal functions\n"
    128 			"\n"
    129 			"Debugging options are mixed using bitwise-or.\n"
    130 			"Note that the meanings and values are subject to change.\n"
    131 			"Also note that these values are used inconsistently in ltrace, and the\n"
    132 			"only debuglevel that you can rely on is -D77 that will show everything.\n"
    133 		   );
    134 }
    135 
    136 static char *
    137 search_for_command(char *filename) {
    138 	static char pathname[PATH_MAX];
    139 	char *path;
    140 	int m, n;
    141 
    142 	if (strchr(filename, '/')) {
    143 		return filename;
    144 	}
    145 	for (path = getenv("PATH"); path && *path; path += m) {
    146 		if (strchr(path, ':')) {
    147 			n = strchr(path, ':') - path;
    148 			m = n + 1;
    149 		} else {
    150 			m = n = strlen(path);
    151 		}
    152 		if (n + strlen(filename) + 1 >= PATH_MAX) {
    153 			fprintf(stderr, "Error: filename too long.\n");
    154 			exit(1);
    155 		}
    156 		strncpy(pathname, path, n);
    157 		if (n && pathname[n - 1] != '/') {
    158 			pathname[n++] = '/';
    159 		}
    160 		strcpy(pathname + n, filename);
    161 		if (!access(pathname, X_OK)) {
    162 			return pathname;
    163 		}
    164 	}
    165 	return filename;
    166 }
    167 
    168 static void
    169 guess_cols(void) {
    170 	struct winsize ws;
    171 	char *c;
    172 
    173 	options.align = DEFAULT_ALIGN;
    174 	c = getenv("COLUMNS");
    175 	if (c && *c) {
    176 		char *endptr;
    177 		int cols;
    178 		cols = strtol(c, &endptr, 0);
    179 		if (cols > 0 && !*endptr) {
    180 			options.align = cols * 5 / 8;
    181 		}
    182 	} else if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) {
    183 		options.align = ws.ws_col * 5 / 8;
    184 	} else if (ioctl(2, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) {
    185 		options.align = ws.ws_col * 5 / 8;
    186 	}
    187 }
    188 
    189 static int
    190 compile_libname(const char *expr, const char *a_lib, int lib_re_p,
    191 		struct filter_lib_matcher *matcher)
    192 {
    193 	if (strcmp(a_lib, "MAIN") == 0) {
    194 		filter_lib_matcher_main_init(matcher);
    195 	} else {
    196 		/* Add ^ and $ to the library expression as well.  */
    197 		char lib[strlen(a_lib) + 3];
    198 		sprintf(lib, "^%s$", a_lib);
    199 
    200 		enum filter_lib_matcher_type type
    201 			= lib[0] == '/' ? FLM_PATHNAME : FLM_SONAME;
    202 
    203 		regex_t lib_re;
    204 		int status = (lib_re_p ? regcomp : globcomp)(&lib_re, lib, 0);
    205 		if (status != 0) {
    206 			char buf[100];
    207 			regerror(status, &lib_re, buf, sizeof buf);
    208 			fprintf(stderr, "Couldn't compile '%s': %s.\n",
    209 				expr, buf);
    210 			return -1;
    211 		}
    212 		filter_lib_matcher_name_init(matcher, type, lib_re);
    213 	}
    214 	return 0;
    215 }
    216 
    217 static int
    218 add_filter_rule(struct filter *filt, const char *expr,
    219 		enum filter_rule_type type,
    220 		const char *a_sym, int sym_re_p,
    221 		const char *a_lib, int lib_re_p)
    222 {
    223 	struct filter_rule *rule = malloc(sizeof(*rule));
    224 	struct filter_lib_matcher *matcher = malloc(sizeof(*matcher));
    225 
    226 	if (rule == NULL || matcher == NULL) {
    227 	fail:
    228 		free(rule);
    229 		free(matcher);
    230 		return -1;
    231 	}
    232 
    233 	regex_t symbol_re;
    234 	{
    235 		/* Add ^ to the start of expression and $ to the end, so that
    236 		 * we match the whole symbol name.  Let the user write the "*"
    237 		 * explicitly if they wish.  */
    238 		char sym[strlen(a_sym) + 3];
    239 		sprintf(sym, "^%s$", a_sym);
    240 		int status = (sym_re_p ? regcomp : globcomp)
    241 			(&symbol_re, sym, 0);
    242 		if (status != 0) {
    243 			char buf[100];
    244 			regerror(status, &symbol_re, buf, sizeof buf);
    245 			fprintf(stderr, "Couldn't compile '%s': %s.\n",
    246 				expr, buf);
    247 			goto fail;
    248 		}
    249 	}
    250 
    251 	if (compile_libname(expr, a_lib, lib_re_p, matcher) < 0) {
    252 		regfree(&symbol_re);
    253 		goto fail;
    254 	}
    255 
    256 	filter_rule_init(rule, type, matcher, symbol_re);
    257 	filter_add_rule(filt, rule);
    258 	return 0;
    259 }
    260 
    261 static int
    262 grok_libname_pattern(char **libnamep, char **libendp)
    263 {
    264 	char *libname = *libnamep;
    265 	char *libend = *libendp;
    266 
    267 	if (libend[0] != '/')
    268 		return 0;
    269 
    270 	*libend-- = 0;
    271 	if (libname != libend && libname[0] == '/')
    272 		++libname;
    273 	else
    274 		fprintf(stderr, "Unmatched '/' in library name.\n");
    275 
    276 	*libendp = libend;
    277 	*libnamep = libname;
    278 	return 1;
    279 }
    280 
    281 static int
    282 parse_filter(struct filter *filt, char *expr, int operators)
    283 {
    284 	/* Filter is a chain of sym@lib rules separated by '-' or '+'.
    285 	 * If the filter expression starts with '-', the missing
    286 	 * initial rule is implicitly *@*.  */
    287 
    288 	enum filter_rule_type type = FR_ADD;
    289 
    290 	while (*expr != 0) {
    291 		size_t s = strcspn(expr, &"-+@"[operators ? 0 : 2]);
    292 		char *symname = expr;
    293 		char *libname;
    294 		char *next = expr + s + 1;
    295 		enum filter_rule_type this_type = type;
    296 
    297 		if (expr[s] == 0) {
    298 			libname = "*";
    299 			expr = next - 1;
    300 
    301 		} else if (expr[s] == '-' || expr[s] == '+') {
    302 			type = expr[s] == '-' ? FR_SUBTRACT : FR_ADD;
    303 			expr[s] = 0;
    304 			libname = "*";
    305 			expr = next;
    306 
    307 		} else {
    308 			assert(expr[s] == '@');
    309 			expr[s] = 0;
    310 			s = strcspn(next, &"-+"[operators ? 0 : 2]);
    311 			if (s == 0) {
    312 				libname = "*";
    313 				expr = next;
    314 			} else if (next[s] == 0) {
    315 				expr = next + s;
    316 				libname = next;
    317 			} else {
    318 				assert(next[s] == '-' || next[s] == '+');
    319 				type = next[s] == '-' ? FR_SUBTRACT : FR_ADD;
    320 				next[s] = 0;
    321 				expr = next + s + 1;
    322 				libname = next;
    323 			}
    324 		}
    325 
    326 		assert(*libname != 0);
    327 		char *symend = symname + strlen(symname) - 1;
    328 		char *libend = libname + strlen(libname) - 1;
    329 		int sym_is_re = 0;
    330 		int lib_is_re = 0;
    331 
    332 		/*
    333 		 * /xxx/@... and ...@/xxx/ means that xxx are regular
    334 		 * expressions.  They are globs otherwise.
    335 		 *
    336 		 * /xxx@yyy/ is the same as /xxx/@/yyy/
    337 		 *
    338 		 * @/xxx matches library path name
    339 		 * @.xxx matches library relative path name
    340 		 */
    341 		if (symname[0] == '/') {
    342 			if (symname != symend && symend[0] == '/') {
    343 				++symname;
    344 				*symend-- = 0;
    345 				sym_is_re = 1;
    346 
    347 			} else {
    348 				sym_is_re = 1;
    349 				lib_is_re = 1;
    350 				++symname;
    351 
    352 				/* /XXX@YYY/ is the same as
    353 				 * /XXX/@/YYY/.  */
    354 				if (libend[0] != '/')
    355 					fprintf(stderr, "Unmatched '/'"
    356 						" in symbol name.\n");
    357 				else
    358 					*libend-- = 0;
    359 			}
    360 		}
    361 
    362 		/* If libname ends in '/', then we expect '/' in the
    363 		 * beginning too.  Otherwise the initial '/' is part
    364 		 * of absolute file name.  */
    365 		if (!lib_is_re)
    366 			lib_is_re = grok_libname_pattern(&libname, &libend);
    367 
    368 		if (*symname == 0) /* /@AA/ */
    369 			symname = "*";
    370 		if (*libname == 0) /* /aa@/ */
    371 			libname = "*";
    372 
    373 		add_filter_rule(filt, expr, this_type,
    374 				symname, sym_is_re,
    375 				libname, lib_is_re);
    376 	}
    377 
    378 	return 0;
    379 }
    380 
    381 static struct filter *
    382 recursive_parse_chain(const char *orig, char *expr, int operators)
    383 {
    384 	struct filter *filt = malloc(sizeof(*filt));
    385 	if (filt == NULL) {
    386 		fprintf(stderr, "(Part of) filter will be ignored: '%s': %s.\n",
    387 			expr, strerror(errno));
    388 		return NULL;
    389 	}
    390 
    391 	filter_init(filt);
    392 	if (parse_filter(filt, expr, operators) < 0) {
    393 		fprintf(stderr, "Filter '%s' will be ignored.\n", orig);
    394 		free(filt);
    395 		filt = NULL;
    396 	}
    397 
    398 	return filt;
    399 }
    400 
    401 static struct filter **
    402 slist_chase_end(struct filter **begin)
    403 {
    404 	for (; *begin != NULL; begin = &(*begin)->next)
    405 		;
    406 	return begin;
    407 }
    408 
    409 static void
    410 parse_filter_chain(const char *expr, struct filter **retp)
    411 {
    412 	char *str = strdup(expr);
    413 	if (str == NULL) {
    414 		fprintf(stderr, "Filter '%s' will be ignored: %s.\n",
    415 			expr, strerror(errno));
    416 		return;
    417 	}
    418 	/* Support initial '!' for backward compatibility.  */
    419 	if (str[0] == '!')
    420 		str[0] = '-';
    421 
    422 	*slist_chase_end(retp) = recursive_parse_chain(expr, str, 1);
    423 	free(str);
    424 }
    425 
    426 static int
    427 parse_int(const char *optarg, char opt, int min, int max)
    428 {
    429 	char *endptr;
    430 	long int l = strtol(optarg, &endptr, 0);
    431 	if (l < min || (max != 0 && l > max)
    432 	    || *optarg == 0 || *endptr != 0) {
    433 		const char *fmt = max != 0
    434 			? "Invalid argument to -%c: '%s'.  Use integer %d..%d.\n"
    435 			: "Invalid argument to -%c: '%s'.  Use integer >=%d.\n";
    436 		fprintf(stderr, fmt, opt, optarg, min, max);
    437 		exit(1);
    438 	}
    439 	return (int)l;
    440 }
    441 
    442 int
    443 parse_colon_separated_list(const char *paths, struct vect *vec)
    444 {
    445 	/* PATHS contains a colon-separated list of directories and
    446 	 * files to load.  It's modeled after shell PATH variable,
    447 	 * which doesn't allow escapes.  PYTHONPATH in CPython behaves
    448 	 * the same way.  So let's follow suit, it makes things easier
    449 	 * to us.  */
    450 
    451 	char *clone = strdup(paths);
    452 	if (clone == NULL) {
    453 		fprintf(stderr, "Couldn't parse argument %s: %s.\n",
    454 			paths, strerror(errno));
    455 		return -1;
    456 	}
    457 
    458 	/* It's undesirable to use strtok, because we want the string
    459 	 * "a::b" to have three elements.  */
    460 	char *tok = clone - 1;
    461 	char *end = clone + strlen(clone);
    462 	while (tok < end) {
    463 		++tok;
    464 		size_t len = strcspn(tok, ":");
    465 		tok[len] = 0;
    466 
    467 		struct opt_F_t arg = {
    468 			.pathname = tok,
    469 			.own_pathname = tok == clone,
    470 		};
    471 		if (VECT_PUSHBACK(vec, &arg) < 0)
    472 			/* Presumably this is not a deal-breaker.  */
    473 			fprintf(stderr, "Couldn't store component of %s: %s.\n",
    474 				paths, strerror(errno));
    475 
    476 		tok += len;
    477 	}
    478 
    479 	return 0;
    480 }
    481 
    482 void
    483 opt_F_destroy(struct opt_F_t *entry)
    484 {
    485 	if (entry == NULL)
    486 		return;
    487 	if (entry->own_pathname)
    488 		free(entry->pathname);
    489 }
    490 
    491 enum opt_F_kind
    492 opt_F_get_kind(struct opt_F_t *entry)
    493 {
    494 	if (entry->kind == OPT_F_UNKNOWN) {
    495 		struct stat st;
    496 		if (lstat(entry->pathname, &st) < 0) {
    497 			fprintf(stderr, "Couldn't stat %s: %s\n",
    498 				entry->pathname, strerror(errno));
    499 			entry->kind = OPT_F_BROKEN;
    500 		} else if (S_ISDIR(st.st_mode)) {
    501 			entry->kind = OPT_F_DIR;
    502 		} else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
    503 			entry->kind = OPT_F_FILE;
    504 		} else {
    505 			fprintf(stderr, "%s is neither a regular file, "
    506 				"nor a directory.\n", entry->pathname);
    507 			entry->kind = OPT_F_BROKEN;
    508 		}
    509 	}
    510 	assert(entry->kind != OPT_F_UNKNOWN);
    511 	return entry->kind;
    512 }
    513 
    514 char **
    515 process_options(int argc, char **argv)
    516 {
    517 	VECT_INIT(&opt_F, struct opt_F_t);
    518 
    519 	progname = argv[0];
    520 	options.output = stderr;
    521 	options.no_signals = 0;
    522 #if defined(HAVE_UNWINDER)
    523 	options.bt_depth = -1;
    524 #endif /* defined(HAVE_UNWINDER) */
    525 
    526 	guess_cols();
    527 
    528 	int libcalls = 1;
    529 
    530 	while (1) {
    531 		int c;
    532 		char *p;
    533 #ifdef HAVE_GETOPT_LONG
    534 		int option_index = 0;
    535 		static struct option long_options[] = {
    536 			{"align", 1, 0, 'a'},
    537 			{"config", 1, 0, 'F'},
    538 			{"debug", 1, 0, 'D'},
    539 # ifdef USE_DEMANGLE
    540 			{"demangle", 0, 0, 'C'},
    541 # endif
    542 			{"indent", 1, 0, 'n'},
    543 			{"help", 0, 0, 'h'},
    544 			{"library", 1, 0, 'l'},
    545 			{"output", 1, 0, 'o'},
    546 			{"version", 0, 0, 'V'},
    547 			{"no-signals", 0, 0, 'b'},
    548 # if defined(HAVE_UNWINDER)
    549 			{"where", 1, 0, 'w'},
    550 # endif /* defined(HAVE_UNWINDER) */
    551 			{0, 0, 0, 0}
    552 		};
    553 #endif
    554 
    555 		const char *opts = "+"
    556 #ifdef USE_DEMANGLE
    557 			"C"
    558 #endif
    559 #if defined(HAVE_UNWINDER)
    560 			"w:"
    561 #endif
    562 			"cfhiLrStTVba:A:D:e:F:l:n:o:p:s:u:x:";
    563 
    564 #ifdef HAVE_GETOPT_LONG
    565 		c = getopt_long(argc, argv, opts, long_options, &option_index);
    566 #else
    567 		c = getopt(argc, argv, opts);
    568 #endif
    569 		if (c == -1) {
    570 			break;
    571 		}
    572 		switch (c) {
    573 		case 'a':
    574 			options.align = parse_int(optarg, 'a', 0, 0);
    575 			break;
    576 		case 'A':
    577 			options.arraylen = parse_int(optarg, 'A', 0, 0);
    578 			break;
    579 		case 'b':
    580 			options.no_signals = 1;
    581 			break;
    582 		case 'c':
    583 			options.summary++;
    584 			break;
    585 #ifdef USE_DEMANGLE
    586 		case 'C':
    587 			options.demangle++;
    588 			break;
    589 #endif
    590 		case 'D':
    591 			if (optarg[0]=='h') {
    592 				usage_debug();
    593 				exit(0);
    594 			}
    595 			options.debug = strtoul(optarg,&p,8);
    596 			if (*p) {
    597 				fprintf(stderr, "%s: --debug requires an octal argument\n", progname);
    598 				err_usage();
    599 			}
    600 			break;
    601 
    602 		case 'e':
    603 			parse_filter_chain(optarg, &options.plt_filter);
    604 			break;
    605 
    606 		case 'f':
    607 			options.follow = 1;
    608 			break;
    609 		case 'F':
    610 			parse_colon_separated_list(optarg, &opt_F);
    611 			break;
    612 		case 'h':
    613 			usage();
    614 			exit(0);
    615 		case 'i':
    616 			opt_i++;
    617 			break;
    618 
    619 		case 'l': {
    620 			size_t patlen = strlen(optarg);
    621 			char buf[patlen + 2];
    622 			sprintf(buf, "@%s", optarg);
    623 			*slist_chase_end(&options.export_filter)
    624 				= recursive_parse_chain(buf, buf, 0);
    625 			break;
    626 		}
    627 
    628 		case 'L':
    629 			libcalls = 0;
    630 			break;
    631 		case 'n':
    632 			options.indent = parse_int(optarg, 'n', 0, 20);
    633 			break;
    634 		case 'o':
    635 			options.output = fopen(optarg, "w");
    636 			if (!options.output) {
    637 				fprintf(stderr,
    638 					"can't open %s for writing: %s\n",
    639 					optarg, strerror(errno));
    640 				exit(1);
    641 			}
    642 			setvbuf(options.output, (char *)NULL, _IOLBF, 0);
    643 			fcntl(fileno(options.output), F_SETFD, FD_CLOEXEC);
    644 			break;
    645 		case 'p':
    646 			{
    647 				struct opt_p_t *tmp = malloc(sizeof(struct opt_p_t));
    648 				if (!tmp) {
    649 					perror("ltrace: malloc");
    650 					exit(1);
    651 				}
    652 				tmp->pid = parse_int(optarg, 'p', 1, 0);
    653 				tmp->next = opt_p;
    654 				opt_p = tmp;
    655 				break;
    656 			}
    657 		case 'r':
    658 			opt_r++;
    659 			break;
    660 		case 's':
    661 			options.strlen = parse_int(optarg, 's', 0, 0);
    662 			break;
    663 		case 'S':
    664 			options.syscalls = 1;
    665 			break;
    666 		case 't':
    667 			opt_t++;
    668 			break;
    669 		case 'T':
    670 			opt_T++;
    671 			break;
    672 		case 'u':
    673 			options.user = optarg;
    674 			break;
    675 		case 'V':
    676 			printf("ltrace " PACKAGE_VERSION "\n"
    677 			       "Copyright (C) 2010-2013 Petr Machata, Red Hat Inc.\n"
    678 			       "Copyright (C) 1997-2009 Juan Cespedes <cespedes (at) debian.org>.\n"
    679 			       "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
    680 			       "This is free software: you are free to change and redistribute it.\n"
    681 			       "There is NO WARRANTY, to the extent permitted by law.\n");
    682 			exit(0);
    683 			break;
    684 #if defined(HAVE_UNWINDER)
    685 		case 'w':
    686 			options.bt_depth = parse_int(optarg, 'w', 1, 0);
    687 			break;
    688 #endif /* defined(HAVE_UNWINDER) */
    689 
    690 		case 'x':
    691 			parse_filter_chain(optarg, &options.static_filter);
    692 			break;
    693 
    694 		default:
    695 			err_usage();
    696 		}
    697 	}
    698 	argc -= optind;
    699 	argv += optind;
    700 
    701 	/* If neither -e, nor -l, nor -L are used, set default -e.
    702 	 * Use @MAIN for now, as that's what ltrace used to have in
    703 	 * the past.  XXX Maybe we should make this "*" instead.  */
    704 	if (libcalls
    705 	    && options.plt_filter == NULL
    706 	    && options.export_filter == NULL) {
    707 		parse_filter_chain("@MAIN", &options.plt_filter);
    708 		options.hide_caller = 1;
    709 	}
    710 	if (!libcalls && options.plt_filter != NULL) {
    711 		fprintf(stderr,
    712 			"%s: Option -L can't be used with -e or -l.\n",
    713 			progname);
    714 		err_usage();
    715 	}
    716 
    717 	if (!opt_p && argc < 1) {
    718 		fprintf(stderr, "%s: too few arguments\n", progname);
    719 		err_usage();
    720 	}
    721 	if (opt_r && opt_t) {
    722 		fprintf(stderr,
    723 			"%s: Options -r and -t can't be used together\n",
    724 			progname);
    725 		err_usage();
    726 	}
    727 	if (argc > 0) {
    728 		command = search_for_command(argv[0]);
    729 	}
    730 	return &argv[0];
    731 }
    732