16 #define SYSCONFDIR "/etc"
19 #define SYSTEM_CONFIG_FILE SYSCONFDIR "/ltrace.conf"
20 #define USER_CONFIG_FILE "~/.ltrace.conf"
22 struct options_t options = {
23 .align = DEFAULT_ALIGN, /* alignment column for results */
24 .user = NULL, /* username to run command as */
25 .syscalls = 0, /* display syscalls */
26 .libcalls = 1, /* display library calls */
28 .demangle = 0, /* Demangle low-level symbol names */
30 .indent = 0, /* indent output according to program flow */
31 .output = NULL, /* output to a specific file */
32 .summary = 0, /* Report a summary on program exit */
33 .debug = 0, /* debug */
34 .arraylen = DEFAULT_ARRAYLEN, /* maximum # array elements to print */
35 .strlen = DEFAULT_STRLEN, /* maximum # of bytes printed in strings */
36 .follow = 0, /* trace child processes */
39 char *library[MAX_LIBRARIES];
41 static char *progname; /* Program name (`ltrace') */
42 int opt_i = 0; /* instruction pointer */
43 int opt_r = 0; /* print relative timestamp */
44 int opt_t = 0; /* print absolute timestamp */
45 int opt_T = 0; /* show the time spent inside each call */
47 /* List of pids given to option -p: */
48 struct opt_p_t *opt_p = NULL; /* attach to process with a given pid */
50 /* List of function names given to option -e: */
51 struct opt_e_t *opt_e = NULL;
54 /* List of global function names given to -x: */
55 struct opt_x_t *opt_x = NULL;
57 /* List of filenames give to option -F: */
58 struct opt_F_t *opt_F = NULL; /* alternate configuration file(s) */
60 #ifdef PLT_REINITALISATION_BP
61 /* Set a break on the routine named here in order to re-initialize breakpoints
62 after all the PLTs have been initialzed */
63 char *PLTs_initialized_by_here = PLT_REINITALISATION_BP;
68 fprintf(stderr, "Try `%s --help' for more information\n", progname);
74 fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n"
75 "Trace library calls of a given program.\n\n"
76 " -a, --align=COLUMN align return values in a secific column.\n"
77 " -A ARRAYLEN maximum number of array elements to print.\n"
78 " -c count time and calls, and report a summary on exit.\n"
80 " -C, --demangle decode low-level symbol names into user-level names.\n"
82 " -D, --debug=LEVEL enable debugging (see -Dh or --debug=help).\n"
83 " -Dh, --debug=help show help on debugging.\n"
84 " -e expr modify which events to trace.\n"
85 " -f trace children (fork() and clone()).\n"
86 " -F, --config=FILE load alternate configuration file (may be repeated).\n"
87 " -h, --help display this help and exit.\n"
88 " -i print instruction pointer at time of library call.\n"
89 " -l, --library=FILE print library calls from this library only.\n"
90 " -L do NOT display library calls.\n"
91 " -n, --indent=NR indent output by NR spaces for each call level nesting.\n"
92 " -o, --output=FILE write the trace output to that file.\n"
93 " -p PID attach to the process with the process ID pid.\n"
94 " -r print relative timestamps.\n"
95 " -s STRLEN specify the maximum string size to print.\n"
96 " -S display system calls.\n"
97 " -t, -tt, -ttt print absolute timestamps.\n"
98 " -T show the time spent inside each call.\n"
99 " -u USERNAME run command with the userid, groupid of username.\n"
100 " -V, --version output version information and exit.\n"
101 " -x NAME treat the global NAME like a library subroutine.\n"
102 #ifdef PLT_REINITALISATION_BP
103 " -X NAME same as -x; and PLT's will be initialized by here.\n"
105 "\nReport bugs to ltrace-devel@lists.alioth.debian.org\n",
111 fprintf(stdout, "%s debugging option, --debug=<octal> or -D<octal>:\n", progname);
114 " number ref. in source description\n"
115 " 1 general Generally helpful progress information\n"
116 " 10 event Shows every event received by a traced process\n"
117 " 20 process Shows actions carried upon a traced processes\n"
118 " 40 function Shows every entry to internal functions\n"
120 "Debugging options are mixed using bitwise-or.\n"
121 "Note that the meanings and values are subject to change.\n"
126 search_for_command(char *filename) {
127 static char pathname[PATH_MAX];
131 if (strchr(filename, '/')) {
134 for (path = getenv("PATH"); path && *path; path += m) {
135 if (strchr(path, ':')) {
136 n = strchr(path, ':') - path;
139 m = n = strlen(path);
141 if (n + strlen(filename) + 1 >= PATH_MAX) {
142 fprintf(stderr, "Error: filename too long\n");
145 strncpy(pathname, path, n);
146 if (n && pathname[n - 1] != '/') {
149 strcpy(pathname + n, filename);
150 if (!access(pathname, X_OK)) {
162 options.align = DEFAULT_ALIGN;
163 c = getenv("COLUMNS");
167 cols = strtol(c, &endptr, 0);
168 if (cols > 0 && !*endptr) {
169 options.align = cols * 5 / 8;
171 } else if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) {
172 options.align = ws.ws_col * 5 / 8;
173 } else if (ioctl(2, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) {
174 options.align = ws.ws_col * 5 / 8;
179 process_options(int argc, char **argv) {
181 options.output = stderr;
188 int option_index = 0;
189 static struct option long_options[] = {
190 {"align", 1, 0, 'a'},
191 {"config", 1, 0, 'F'},
192 {"debug", 1, 0, 'D'},
194 {"demangle", 0, 0, 'C'},
196 {"indent", 1, 0, 'n'},
198 {"library", 1, 0, 'l'},
199 {"output", 1, 0, 'o'},
200 {"version", 0, 0, 'V'},
203 c = getopt_long(argc, argv, "+cfhiLrStTV"
207 "a:A:D:e:F:l:n:o:p:s:u:x:X:", long_options,
214 options.align = atoi(optarg);
217 options.arraylen = atoi(optarg);
228 if (optarg[0]=='h') {
232 options.debug = strtoul(optarg,&p,8);
234 fprintf(stderr, "%s: --debug requires an octal argument\n", progname);
240 char *str_e = strdup(optarg);
242 perror("ltrace: strdup");
245 if (str_e[0] == '!') {
251 char *str2 = strchr(str_e, ',');
255 tmp = malloc(sizeof(struct opt_e_t));
257 perror("ltrace: malloc");
276 struct opt_F_t *tmp = malloc(sizeof(struct opt_F_t));
278 perror("ltrace: malloc");
281 tmp->filename = strdup(optarg);
293 if (library_num == MAX_LIBRARIES) {
295 "Too many libraries. Maximum is %i.\n",
299 library[library_num++] = optarg;
302 options.libcalls = 0;
305 options.indent = atoi(optarg);
308 options.output = fopen(optarg, "w");
309 if (!options.output) {
311 "Can't open %s for output: %s\n",
312 optarg, strerror(errno));
315 setvbuf(options.output, (char *)NULL, _IOLBF, 0);
316 fcntl(fileno(options.output), F_SETFD, FD_CLOEXEC);
320 struct opt_p_t *tmp = malloc(sizeof(struct opt_p_t));
322 perror("ltrace: malloc");
325 tmp->pid = atoi(optarg);
334 options.strlen = atoi(optarg);
337 options.syscalls = 1;
346 options.user = optarg;
349 printf("ltrace version " PACKAGE_VERSION ".\n"
350 "Copyright (C) 1997-2009 Juan Cespedes <cespedes@debian.org>.\n"
351 "This is free software; see the GNU General Public Licence\n"
352 "version 2 or later for copying conditions. There is NO warranty.\n");
355 #ifdef PLT_REINITALISATION_BP
356 PLTs_initialized_by_here = optarg;
358 fprintf(stderr, "WARNING: \"-X\" not used for this "
359 "architecture: assuming you meant \"-x\"\n");
365 struct opt_x_t *p = opt_x;
367 /* First, check for duplicate. */
368 while (p && strcmp(p->name, optarg)) {
375 /* If not duplicate, add to list. */
376 p = malloc(sizeof(struct opt_x_t));
378 perror("ltrace: malloc");
396 opt_F = malloc(sizeof(struct opt_F_t));
397 opt_F->next = malloc(sizeof(struct opt_F_t));
398 opt_F->next->next = NULL;
399 opt_F->filename = USER_CONFIG_FILE;
400 opt_F->next->filename = SYSTEM_CONFIG_FILE;
402 /* Reverse the config file list since it was built by
403 * prepending, and it would make more sense to process the
404 * files in the order they were given. Probably it would make
405 * more sense to keep a tail pointer instead? */
407 struct opt_F_t *egg = NULL;
408 struct opt_F_t *chicken;
410 chicken = opt_F->next;
418 if (!opt_p && argc < 1) {
419 fprintf(stderr, "%s: too few arguments\n", progname);
422 if (opt_r && opt_t) {
423 fprintf(stderr, "%s: Incompatible options -r and -t\n",
428 command = search_for_command(argv[0]);