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