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