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
46struct 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
62static char *progname;		/* Program name (`ltrace') */
63int opt_i = 0;			/* instruction pointer */
64int opt_r = 0;			/* print relative timestamp */
65int opt_t = 0;			/* print absolute timestamp */
66int opt_T = 0;			/* show the time spent inside each call */
67
68/* List of pids given to option -p: */
69struct opt_p_t *opt_p = NULL;	/* attach to process with a given pid */
70
71/* Vector of struct opt_F_t.  */
72struct vect opt_F;
73
74static void
75err_usage(void) {
76	fprintf(stderr, "Try `%s --help' for more information.\n", progname);
77	exit(1);
78}
79
80static void
81usage(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
118static void
119usage_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
136static char *
137search_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
168static void
169guess_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
189static int
190compile_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
217static int
218add_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
261static int
262grok_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
281static int
282parse_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
381static struct filter *
382recursive_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
401static struct filter **
402slist_chase_end(struct filter **begin)
403{
404	for (; *begin != NULL; begin = &(*begin)->next)
405		;
406	return begin;
407}
408
409static void
410parse_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
426static int
427parse_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
442int
443parse_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
482void
483opt_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
491enum opt_F_kind
492opt_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
514char **
515process_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}
732