3797008022e2463a497149a33d8f765eefdbe7ed
[staptrace.git] / src / staptrace.c
1 /* Copyright (C) 2010 Free Software Foundation, Inc.
2
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 3 of the License, or
6    (at your option) any later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
15
16 #include <error.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <libintl.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <signal.h>
24 #include <stdarg.h>
25 #include <fcntl.h>
26 #include <poll.h>
27 #include <assert.h>
28
29 #ifndef STAP_SCRIPT_FILENAME
30 #error "STAP_SCRIPT_FILENAME is required"
31 #endif
32
33 #define STRINGIFY1(lit) #lit
34 #define STRINGIFY(lit) STRINGIFY1 (lit)
35 #define _(x) gettext (x)
36
37 static int opt_d, opt_f, opt_q, opt_p;
38 /* Verified we should run the -ff postprocessor.  */
39 static int opt_ff;
40 static char *opt_o;
41 static size_t opt_o_len;
42
43 /* Script filename.  */
44 static char *opt_Z = STRINGIFY (STAP_SCRIPT_FILENAME);
45
46 static void *
47 xmalloc (size_t size)
48 {
49   void *retval = malloc (size);
50
51   if (retval == NULL)
52     error (EXIT_FAILURE, errno, _("memory allocation of %zu bytes"), size);
53
54   return retval;
55 }
56
57 /* warning: EOF is also an error.  */
58 static size_t
59 xread (int fd, void *buf, size_t count)
60 {
61   ssize_t retval = read (fd, buf, count);
62
63   if (retval <= 0)
64     error (EXIT_FAILURE, errno, _("Error reading data"));
65
66   return retval;
67 }
68
69 /* warning: No events are also an error.  */
70 static void
71 xpoll (struct pollfd *fds, nfds_t nfds, int timeout)
72 {
73   if (poll (fds, nfds, timeout) != 1)
74     error (EXIT_FAILURE, errno, _("poll returned error"));
75 }
76
77 static pid_t
78 xfork (void)
79 {
80   pid_t retval = fork ();
81
82   if (retval == -1)
83     error (EXIT_FAILURE, errno, _("Error calling fork"));
84
85   return retval;
86 }
87
88 static void
89 xsnprintf (char *str, size_t size, const char *format, ...)
90 {
91   int i;
92   va_list ap;
93
94   va_start (ap, format);
95   i = vsnprintf (str, size, format, ap);
96   va_end (ap);
97   if (i <= 0 || strlen (str) >= size - 1)
98     error (EXIT_FAILURE, errno, _("Error calling sprintf"));
99 }
100
101 static void
102 xfflush (FILE *stream)
103 {
104   if (fflush (stream) != 0)
105     error (EXIT_FAILURE, errno, _("Error calling fflush"));
106 }
107
108 static void
109 xdup2 (int oldfd, int newfd)
110 {
111   if (dup2 (oldfd, newfd) != newfd)
112     error (EXIT_FAILURE, errno, _("Error calling dup2 (%d, %d)"), oldfd,
113            newfd);
114 }
115
116 static void
117 xclose (int fd)
118 {
119   if (close (fd) != 0)
120     error (EXIT_FAILURE, errno, _("Error calling close (%d)"), fd);
121 }
122
123 static void
124 xpipe (int pipefd[2])
125 {
126   if (pipe (pipefd) != 0)
127     error (EXIT_FAILURE, errno, _("Error creating internal pipe"));
128 }
129
130 static void
131 xraise (int sig)
132 {
133   if (raise (sig) != 0)
134     error (EXIT_FAILURE, errno, _("Error calling raise (%d)"), sig);
135 }
136
137 static void
138 xfcntl_setfl (int fd, int cmdarg)
139 {
140   if (fcntl (fd, F_SETFL, cmdarg) != 0)
141     error (EXIT_FAILURE, errno,
142            _("Error calling fcntl (%d, F_SETFL, 0%o)"), fd, cmdarg);
143 }
144
145 static void
146 xwrite (int fd, const void *buf, size_t count)
147 {
148   if (!count)
149     return;
150
151   if ((ssize_t) count < 0 || write (fd, buf, count) != (ssize_t) count)
152     error (EXIT_FAILURE, errno,
153            _("Error calling write (%d, ..., %zu)"), fd, count);
154 }
155
156 static int
157 xopen (const char *pathname, int flags, mode_t mode)
158 {
159   int retval = open (pathname, flags, mode);
160
161   if (retval == -1)
162     error (EXIT_FAILURE, errno,
163            _("Error %s file \"%s\" (flags 0x%x, mode 0%o)"),
164            flags & O_APPEND ? _("appending")
165                             : (flags & O_CREAT ? _("creating")
166                                                : _("opening")),
167            pathname, flags, mode);
168
169   return retval;
170 }
171
172 static void
173 usage (int status)
174 {
175   printf ("\
176 usage: staptrace [-dfq] [-o file] [-p pid] [command [arg ...]]\n\
177                  [-Z <stap script>]\n\
178 \n\
179 Default -Z is: %s\n\
180 ",
181           opt_Z);
182   exit (status);
183 }
184
185 static void
186 dump_args (char **args)
187 {
188   char **argp;
189
190   for (argp = args; *argp; argp++)
191     {
192       if (argp > args)
193         fputc (' ', stderr);
194       fputs (*argp, stderr);
195     }
196   fputc ('\n', stderr);
197 }
198
199 static void
200 ff_filter (int fd_read)
201 {
202   char buf[getpagesize ()];
203   size_t buf_len = 0;
204   /* Does the buf start on a line boundary?  */
205   int buf_nl = 1;
206   /* Initial fd if no `\n[' is seen at the start.  */
207   int fd_write = STDOUT_FILENO;
208
209   xfcntl_setfl (fd_read, O_NONBLOCK);
210
211   for (;;)
212     {
213       struct pollfd pollfd;
214
215       pollfd.fd = fd_read;
216       pollfd.events = POLLIN;
217
218       xpoll (&pollfd, 1, -1);
219
220       if (pollfd.revents & ~(POLLIN | POLLHUP) || pollfd.revents == 0)
221         error (EXIT_FAILURE, errno, _("poll returned error revents 0x%x"),
222                pollfd.revents);
223
224       if (pollfd.revents & POLLIN)
225         {
226           ssize_t want, got;
227           char *s;
228           char *start;
229           int start_nl;
230
231           want = sizeof (buf) - buf_len - 1;
232           assert (want > 0);
233           got = xread (fd_read, &buf[buf_len], want);
234           if (memchr (&buf[buf_len], 0, got) != NULL)
235             error (EXIT_FAILURE, 0,
236                    _("Unexpected \\0 in the internal -ff stream"));
237           buf_len += got;
238           buf[buf_len] = 0;
239           if (opt_d >= 2)
240             fprintf (stderr, "buf_len %zu + %zd = %zu, read: {%s}\n",
241                      buf_len - got, got, buf_len, &buf[buf_len - got]);
242           start = buf;
243           start_nl = buf_nl;
244
245           /* Keep the last character for `c' or `n' line continuations.  */
246           while (start + 1 < &buf[buf_len])
247             {
248               unsigned long ul;
249               char *end;
250               static char fname[FILENAME_MAX];
251
252               if (!start_nl)
253                 {
254                   ssize_t len;
255
256                   s = strchr (start, '\n');
257                   if (!s)
258                     {
259                       len = strlen (start);
260                       assert (len > 0);
261                       if (start[len - 1] == 'c' || start[len - 1] == 'n')
262                         len--;
263                       xwrite (fd_write, start, len);
264                       start += len;
265                       continue;
266                     }
267                   len = s - start - 1;
268                   assert (len >= 0);
269                   if (start[len] == 'n')
270                     start[len++] = '\n';
271                   xwrite (fd_write, start, len);
272                   start = s + 1;
273                   start_nl = 1;
274                   continue;
275                 }
276
277               if (*start != '[')
278                 error (EXIT_FAILURE, 0,
279                        _("'[' expected in the internal -ff stream"));
280               if (start[1] == 0)
281                 {
282                   /* We need more data.  */
283                   break;
284                 }
285               ul = strtoul (&start[1], &end, 10);
286               assert (end != NULL);
287               if (*end == 0)
288                 {
289                   /* We need more data.  */
290                   break;
291                 }
292               if (end > start + 64 || *end != ']' || end == &start[1])
293                 error (EXIT_FAILURE, 0,
294                        _("Invalid TID in the internal -ff stream: %s"), start);
295               start = end + 1;
296               start_nl = 0;
297
298               xsnprintf (fname, sizeof (fname), "%s.%lu", opt_o, ul);
299               if (fd_write != STDOUT_FILENO)
300                 xclose (fd_write);
301               fd_write = xopen (fname, O_WRONLY | O_APPEND | O_CREAT, 0644);
302
303               continue;
304             }
305
306           want = &buf[buf_len] - start;
307           memmove (buf, start, want);
308           buf_len = want;
309           buf_nl = start_nl;
310           continue;
311         }
312       if (pollfd.revents & POLLHUP)
313         break;
314       assert (0);
315     }
316   if (fd_write != STDOUT_FILENO)
317     xclose (fd_write);
318 }
319
320 int
321 main (int argc, char **argv)
322 {
323   char **args, **argp;
324
325   args = xmalloc (sizeof (*args) * argc * 2 + 32);
326   argp = args;
327   *argp++ = "stap";
328
329   for (;;)
330     {
331       int i;
332
333       i = getopt (argc, argv, "+dfqo:p:hZ:");
334       if (i == EOF)
335         break;
336       switch (i)
337         {
338         case 'd':
339           opt_d++;
340           break;
341         case 'f':
342           opt_f++;
343           break;
344         case 'q':
345           *argp++ = "-G";
346           *argp++ = "opt_q=1";
347           opt_q = 1;
348           break;
349         case 'o':
350           opt_o = optarg;
351           opt_o_len = strlen (opt_o);
352           break;
353         case 'p':
354           *argp++ = "-x";
355           *argp++ = optarg;
356           opt_p = 1;
357           break;
358         case 'Z':
359           opt_Z = optarg;
360           break;
361         case 'h':
362           usage (EXIT_SUCCESS);
363         default:
364           usage (EXIT_FAILURE);
365         }
366     }
367
368   if ((optind == argc) == !opt_p)
369     usage (EXIT_FAILURE);
370
371   if (optind < argc)
372     {
373       pid_t child;
374       static char kill_s[256];
375       static char option_s[256];
376
377       child = xfork ();
378       if (!child)
379         {
380           xraise (SIGSTOP);
381
382           execvp (argv[optind], &argv[optind]);
383           error (EXIT_FAILURE, errno, _("Error executing child command"));
384         }
385
386       /* FIXME: Call `kill -CONT' from the systamtap script.  How?  */
387       xsnprintf (kill_s, sizeof (kill_s),
388                  "kill -CONT %lu; "
389                  "while [ -e /proc/%lu/root ]; do sleep 0.1; done",
390                  (unsigned long) child, (unsigned long) child);
391       *argp++ = "-c";
392       *argp++ = kill_s;
393       xsnprintf (option_s, sizeof (option_s), "opt_child=%lu",
394                  (unsigned long) child);
395       *argp++ = "-G";
396       *argp++ = option_s;
397     }
398
399   xfflush (stdout);
400   xdup2 (STDERR_FILENO, STDOUT_FILENO);
401
402   switch (opt_f)
403     {
404     case 1:
405       *argp++ = "-G";
406       *argp++ = "opt_f=1";
407       /* FALLTHRU */
408     case 0:
409       if (opt_o)
410         {
411           *argp++ = "-o";
412           *argp++ = opt_o;
413         }
414       break;
415     default:
416       *argp++ = "-G";
417       *argp++ = "opt_f=1";
418       if (opt_o)
419         {
420           *argp++ = "-G";
421           *argp++ = "opt_ff=1";
422           opt_ff = 1;
423         }
424       else
425         {
426           /* -ff is the same like -f when no -o is specified.  */
427         }
428       break;
429     }
430
431   *argp++ = opt_Z;
432   *argp = NULL;
433
434   if (opt_d)
435     dump_args (args);
436
437   if (opt_ff)
438     {
439       int pipefd[2];
440
441       xpipe (pipefd);
442
443       if (xfork ())
444         {
445           xclose (pipefd[1]);
446           ff_filter (pipefd[0]);
447           exit (EXIT_SUCCESS);
448         }
449
450       xclose (pipefd[0]);
451       xdup2 (pipefd[1], STDOUT_FILENO);
452       xclose (pipefd[1]);
453     }
454
455   execvp ("stap", args);
456
457   if (!opt_d)
458     dump_args (args);
459   error (EXIT_FAILURE, errno, _("Error executing stap"));
460 }