a bit more debug printing
[platform/upstream/ltrace.git] / options.c
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@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@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 }