Replace leading dot by underscore for session name
[lttng-trace.git] / src / lttng-trace.c
1 /*
2 * Copyright (c) 2015-2021 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
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 along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _LGPL_SOURCE
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <sys/ptrace.h>
28 #include <sys/wait.h>
29 #include <sys/signal.h>
30 #include <stdbool.h>
31 #include <errno.h>
32 #include <time.h>
33
34 #include <lttng/lttng.h>
35 #include <lttng/handle.h>
36 #include <lttng/session.h>
37 #include <lttng/tracker.h>
38
39 #define MESSAGE_PREFIX "[lttng-trace] "
40 #define NR_HANDLES 2
41
42 #ifndef PTRACE_EVENT_STOP
43 #define PTRACE_EVENT_STOP 128
44 #endif
45
46 #define PERROR(msg) perror(msg "\n")
47 #define ERR(fmt, args...) fprintf(stderr, fmt "\n", ## args)
48
49 #ifdef DEBUG
50 #define DBG(fmt, args...) printf(fmt "\n", ## args)
51 #else
52 #define DBG(fmt, args...)
53 #endif
54
55 #define __unused __attribute__((unused))
56
57 static pid_t sigfwd_pid;
58
59 static bool opt_help = false,
60 opt_no_context = false,
61 opt_no_pause = false,
62 opt_no_syscall = false,
63 opt_session = false,
64 opt_view = false,
65 opt_output = false;
66
67 static const char *output_path;
68 static const char *session_name;
69
70 struct lttng_trace_ctx {
71 char session_name[LTTNG_NAME_MAX];
72 char path[PATH_MAX];
73 time_t creation_time;
74 };
75
76 static
77 long ptrace_setup(pid_t pid)
78 {
79 long ptrace_ret;
80 unsigned long flags;
81
82 flags = PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXIT
83 | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
84 | PTRACE_O_TRACEEXEC;
85 //ptrace_ret = ptrace(PTRACE_SETOPTIONS, pid,
86 ptrace_ret = ptrace(PTRACE_SEIZE, pid,
87 NULL, (void *) flags);
88 if (ptrace_ret) {
89 //PERROR("ptrace setoptions");
90 PERROR("ptrace seize");
91 return -1;
92 }
93 return 0;
94 }
95
96 static
97 int wait_on_children(pid_t top_pid, struct lttng_handle **handle,
98 size_t nr_handles)
99 {
100 pid_t pid;
101 long ptrace_ret;
102 int ret;
103 size_t i;
104
105 pid = top_pid;
106 DBG("Setup ptrace options on top child pid %d", pid);
107 ret = ptrace_setup(pid);
108 if (ret) {
109 return ret;
110 }
111 for (i = 0; i < nr_handles; i++) {
112 ret = lttng_track_pid(handle[i], pid);
113 if (ret && ret != -LTTNG_ERR_INVALID) {
114 ERR("Error %d tracking pid %d", ret, pid);
115 }
116 }
117 top_pid = -1;
118 /* Restart initial raise(SIGSTOP) */
119 //ptrace_ret = ptrace(PTRACE_CONT, pid, 0, restartsig);
120 //TODO wait for child to have stopped....
121 ret = kill(pid, SIGCONT);
122 if (ret) {
123 //if (ptrace_ret) {
124 PERROR("kill");
125 return -1;
126 }
127
128 for (;;) {
129 int status;
130
131 pid = waitpid(-1, &status, __WALL);
132 DBG("Activity on child pid %d", pid);
133 if (pid < 0) {
134 if (errno == ECHILD) {
135 /* No more children to possibly wait for. */
136 return 0;
137 } else {
138 PERROR("waitpid");
139 return -1;
140 }
141 } else if (pid == 0) {
142 ERR("Unexpected PID 0");
143 return -1;
144 } else {
145 if (WIFSTOPPED(status)) {
146 int shiftstatus, restartsig;
147
148 DBG("Child pid %d is stopped", pid);
149 shiftstatus = status >> 8;
150 if (shiftstatus == (SIGTRAP | (PTRACE_EVENT_EXIT << 8))) {
151 DBG("Child pid %d is exiting", pid);
152 #if 0
153 for (i = 0; i < nr_handles; i++) {
154 ret = lttng_untrack_pid(handle[i], pid);
155 if (ret && ret != -LTTNG_ERR_INVALID) {
156 ERR("Error %d untracking pid %d", ret, pid);
157 }
158 }
159 #endif
160 } else if (shiftstatus == (SIGTRAP | (PTRACE_EVENT_FORK << 8))) {
161 long newpid;
162
163 ptrace_ret = ptrace(PTRACE_GETEVENTMSG, pid, 0, &newpid);
164 if (ptrace_ret) {
165 PERROR("ptrace");
166 return -1;
167 }
168 DBG("Child pid %d is forking, child pid %ld", pid, newpid);
169 for (i = 0; i < nr_handles; i++) {
170 ret = lttng_track_pid(handle[i], newpid);
171 if (ret && ret != -LTTNG_ERR_INVALID) {
172 ERR("Error %d tracking pid %ld", ret, newpid);
173 }
174 }
175 } else if (shiftstatus == (SIGTRAP | (PTRACE_EVENT_VFORK << 8))) {
176 long newpid;
177
178 ptrace_ret = ptrace(PTRACE_GETEVENTMSG, pid, 0, &newpid);
179 if (ptrace_ret) {
180 PERROR("ptrace");
181 return -1;
182 }
183 DBG("Child pid %d issuing vfork, child pid %ld", pid, newpid);
184 for (i = 0; i < nr_handles; i++) {
185 ret = lttng_track_pid(handle[i], newpid);
186 if (ret && ret != -LTTNG_ERR_INVALID) {
187 ERR("Error %d tracking pid %ld", ret, newpid);
188 }
189 }
190 } else if (shiftstatus == (SIGTRAP | PTRACE_EVENT_CLONE << 8)) {
191 long newpid;
192
193 ptrace_ret = ptrace(PTRACE_GETEVENTMSG, pid, 0, &newpid);
194 if (ptrace_ret) {
195 PERROR("ptrace");
196 return -1;
197 }
198 DBG("Child pid %d issuing clone, child pid %ld", pid, newpid);
199 for (i = 0; i < nr_handles; i++) {
200 ret = lttng_track_pid(handle[i], newpid);
201 if (ret && ret != -LTTNG_ERR_INVALID) {
202 ERR("Error %d tracking pid %ld", ret, newpid);
203 }
204 }
205 } else if (shiftstatus == (SIGTRAP | PTRACE_EVENT_EXEC << 8)) {
206 long oldpid;
207
208 ptrace_ret = ptrace(PTRACE_GETEVENTMSG, pid, 0, &oldpid);
209 if (ptrace_ret) {
210 PERROR("ptrace");
211 return -1;
212 }
213 DBG("Child pid (old: %ld, new: %d) is issuing exec",
214 oldpid, pid);
215 /*
216 * Needed for exec issued from
217 * multithreaded process.
218 */
219 for (i = 0; i < nr_handles; i++) {
220 ret = lttng_untrack_pid(handle[i], oldpid);
221 if (ret && ret != -LTTNG_ERR_INVALID) {
222 ERR("Error %d untracking pid %ld", ret, oldpid);
223 }
224 ret = lttng_track_pid(handle[i], pid);
225 if (ret && ret != -LTTNG_ERR_INVALID) {
226 ERR("Error %d tracking pid %d", ret, pid);
227 }
228 }
229 } else if (shiftstatus == SIGTRAP) {
230 DBG("Received SIGTRAP from pid %d without event of interest", pid);
231 } else if (shiftstatus == SIGSTOP) {
232 DBG("Received SIGSTOP from pid %d without event of interest", pid);
233 } else if (shiftstatus == SIGSEGV) {
234 DBG("Received SIGSEGV from pid %d without event of interest", pid);
235 } else if (shiftstatus == SIGTTIN) {
236 DBG("Received SIGTTIN from pid %d without event of interest", pid);
237 } else if (shiftstatus == SIGTTOU) {
238 DBG("Received SIGTTOU from pid %d without event of interest", pid);
239 } else if (shiftstatus == SIGTSTP) {
240 DBG("Received SIGTSTP from pid %d without event of interest", pid);
241 } else {
242 DBG("Ignoring signal %d (status %d) from pid %d (eventcode = %u)",
243 WSTOPSIG(status), status, pid,
244 (shiftstatus & ~WSTOPSIG(status)) >> 8);
245 }
246
247 restartsig = WSTOPSIG(status);
248 switch (restartsig) {
249 case SIGTSTP:
250 case SIGTTIN:
251 case SIGTTOU:
252 case SIGSTOP:
253 {
254 //siginfo_t siginfo;
255
256 errno = 0;
257 //ptrace_ret = ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo);
258 //if (ptrace_ret < 0 && errno == EINVAL) {
259 if (restartsig == SIGTTIN) {
260 ret = kill(pid, SIGTTIN);
261 if (ret) {
262 PERROR("kill");
263 return -1;
264 }
265 } else if (status >> 16 == PTRACE_EVENT_STOP) {
266 DBG("ptrace stop");
267 //ptrace_ret = ptrace(PTRACE_LISTEN, pid, 0, 0);
268 ptrace_ret = ptrace(PTRACE_CONT, pid, 0, 0);
269 if (ptrace_ret) {
270 PERROR("ptrace cont");
271 return -1;
272 }
273 } else {
274 DBG("job control stop ret %ld errno %d", ptrace_ret, errno);
275 /*
276 * It's not a group-stop, so restart process,
277 * skipping the signal.
278 */
279 ptrace_ret = ptrace(PTRACE_CONT, pid, 0, 0);
280 if (ptrace_ret) {
281 PERROR("ptrace cont");
282 return -1;
283 }
284 }
285 break;
286 }
287 case SIGTRAP:
288 {
289 //unsigned long data;
290
291 //if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data) == 0) {
292 /*
293 * Restart process skipping the signal when
294 * receiving a message.
295 */
296 ptrace_ret = ptrace(PTRACE_CONT, pid, 0, 0);
297 if (ptrace_ret) {
298 PERROR("ptrace");
299 return -1;
300 }
301 break;
302 //}
303 }
304 /* Fall-through */
305 default:
306 /* Restart with original signal. */
307 ptrace_ret = ptrace(PTRACE_CONT, pid, 0, restartsig);
308 if (ptrace_ret) {
309 PERROR("ptrace");
310 return -1;
311 }
312 }
313 } else if (WIFEXITED(status)) {
314 DBG("Child pid %d exited normally with status %d",
315 pid, WEXITSTATUS(status));
316 for (i = 0; i < nr_handles; i++) {
317 ret = lttng_untrack_pid(handle[i], pid);
318 if (ret && ret != -LTTNG_ERR_INVALID) {
319 ERR("Error %d tracking pid %d", ret, pid);
320 }
321 }
322 } else if (WIFSIGNALED(status)) {
323 DBG("Child pid %d terminated by signal %d", pid,
324 WTERMSIG(status));
325 for (i = 0; i < nr_handles; i++) {
326 ret = lttng_untrack_pid(handle[i], pid);
327 if (ret && ret != -LTTNG_ERR_INVALID) {
328 ERR("Error %d tracking pid %d", ret, pid);
329 }
330 }
331 } else {
332 DBG("Unhandled status %d from child %d", status, pid);
333 }
334 }
335 }
336 }
337
338 static
339 int run_child(int argc, char **argv)
340 {
341 pid_t pid;
342 int ret;
343
344 if (argc < 1) {
345 ERR("Please provide executable name as first argument.");
346 return -1;
347 }
348
349 pid = fork();
350 if (pid > 0) {
351 /* In parent */
352 DBG("Child process created (pid: %d)", pid);
353 } else if (pid == 0) {
354 /* In child */
355 #if 0
356 long ptraceret;
357
358 ptraceret = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
359 if (ptraceret) {
360 PERROR("ptrace");
361 exit(EXIT_FAILURE);
362 }
363 #endif
364 ret = raise(SIGSTOP);
365 if (ret) {
366 PERROR("raise");
367 exit(EXIT_FAILURE);
368 }
369 ret = execvp(argv[0], &argv[0]);
370 if (ret) {
371 PERROR("execvp");
372 exit(EXIT_FAILURE);
373 }
374 } else {
375 PERROR("fork");
376 return -1;
377 }
378 return pid;
379 }
380
381 static
382 int create_session(struct lttng_trace_ctx *ctx)
383 {
384 return lttng_create_session(ctx->session_name, ctx->path);
385 }
386
387 static
388 int destroy_session(struct lttng_trace_ctx *ctx)
389 {
390 return lttng_destroy_session(ctx->session_name);
391 }
392
393 static
394 int start_session(struct lttng_trace_ctx *ctx)
395 {
396 return lttng_start_tracing(ctx->session_name);
397 }
398
399 static
400 int enable_syscalls(struct lttng_trace_ctx *ctx)
401 {
402 struct lttng_domain domain;
403 struct lttng_event *ev;
404 struct lttng_handle *handle;
405 int ret = 0;
406
407 if (opt_no_syscall)
408 return 0;
409 memset(&domain, 0, sizeof(domain));
410 ev = lttng_event_create();
411 if (!ev) {
412 ERR("Error creating event");
413 goto end;
414 }
415 domain.type = LTTNG_DOMAIN_KERNEL;
416 domain.buf_type = LTTNG_BUFFER_GLOBAL;
417
418 handle = lttng_create_handle(ctx->session_name, &domain);
419 if (!handle) {
420 ERR("Error creating handle");
421 ret = -1;
422 goto error_handle;
423 }
424 ev->type = LTTNG_EVENT_SYSCALL;
425 strcpy(ev->name, "*");
426 ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
427 ret = lttng_enable_event_with_exclusions(handle,
428 ev, NULL, NULL, 0, NULL);
429 if (ret) {
430 ERR("Error enabling syscall events");
431 ret = -1;
432 }
433 lttng_destroy_handle(handle);
434 error_handle:
435 lttng_event_destroy(ev);
436 end:
437 return ret;
438 }
439
440 static
441 int add_contexts(struct lttng_trace_ctx *ctx, enum lttng_domain_type domain_type)
442 {
443 struct lttng_domain domain;
444 struct lttng_event_context event_ctx;
445 struct lttng_handle *handle;
446 const char *domain_str;
447 int ret = 0;
448
449 if (opt_no_context)
450 return 0;
451 memset(&domain, 0, sizeof(domain));
452 switch (domain_type) {
453 case LTTNG_DOMAIN_KERNEL:
454 domain.buf_type = LTTNG_BUFFER_GLOBAL;
455 domain_str = "kernel";
456 break;
457 case LTTNG_DOMAIN_UST:
458 domain.buf_type = LTTNG_BUFFER_PER_UID;
459 domain_str = "ust";
460 break;
461 default:
462 return -1;
463 }
464 domain.type = domain_type;
465
466 handle = lttng_create_handle(ctx->session_name, &domain);
467 if (!handle) {
468 ERR("Error creating handle");
469 ret = -1;
470 goto end;
471 }
472 memset(&event_ctx, 0, sizeof(event_ctx));
473 event_ctx.ctx = LTTNG_EVENT_CONTEXT_PROCNAME;
474 if (lttng_add_context(handle, &event_ctx, NULL, NULL) < 0) {
475 ERR("Error adding `procname` context to domain `%s`", domain_str);
476 ret = -1;
477 goto error_context;
478 }
479 memset(&event_ctx, 0, sizeof(event_ctx));
480 event_ctx.ctx = LTTNG_EVENT_CONTEXT_VPID;
481 if (lttng_add_context(handle, &event_ctx, NULL, NULL) < 0) {
482 ERR("Error adding `vpid` context to domain `%s`", domain_str);
483 ret = -1;
484 goto error_context;
485 }
486 memset(&event_ctx, 0, sizeof(event_ctx));
487 event_ctx.ctx = LTTNG_EVENT_CONTEXT_VTID;
488 if (lttng_add_context(handle, &event_ctx, NULL, NULL) < 0) {
489 ERR("Error adding `vtid` context to domain `%s`", domain_str);
490 ret = -1;
491 goto error_context;
492 }
493
494 error_context:
495 lttng_destroy_handle(handle);
496 end:
497 return ret;
498 }
499
500 static
501 int create_channels(struct lttng_trace_ctx *ctx, enum lttng_domain_type domain_type)
502 {
503 struct lttng_domain domain;
504 struct lttng_channel *channel;
505 struct lttng_handle *handle;
506 const char *domain_str;
507 int ret = 0;
508
509 memset(&domain, 0, sizeof(domain));
510 switch (domain_type) {
511 case LTTNG_DOMAIN_KERNEL:
512 domain.buf_type = LTTNG_BUFFER_GLOBAL;
513 domain_str = "kernel";
514 break;
515 case LTTNG_DOMAIN_UST:
516 domain.buf_type = LTTNG_BUFFER_PER_UID;
517 domain_str = "ust";
518 break;
519 default:
520 return -1;
521 }
522 domain.type = domain_type;
523 channel = lttng_channel_create(&domain);
524 if (!channel) {
525 ERR("Error creating channel for domain `%s`", domain_str);
526 ret = -1;
527 goto end;
528 }
529 channel->enabled = 1;
530
531 handle = lttng_create_handle(ctx->session_name, &domain);
532 if (!handle) {
533 ERR("Error creating handle");
534 ret = -1;
535 goto error_handle;
536 }
537 if (lttng_enable_channel(handle, channel) < 0) {
538 ERR("Error enabling channel for domain `%s`", domain_str);
539 ret = -1;
540 }
541 lttng_destroy_handle(handle);
542 error_handle:
543 lttng_channel_destroy(channel);
544 end:
545 return ret;
546 }
547
548 static
549 struct lttng_handle *create_kernel_handle(struct lttng_trace_ctx *ctx)
550 {
551 struct lttng_domain domain;
552
553 memset(&domain, 0, sizeof(domain));
554 domain.type = LTTNG_DOMAIN_KERNEL;
555 domain.buf_type = LTTNG_BUFFER_GLOBAL;
556 return lttng_create_handle(ctx->session_name, &domain);
557 }
558
559 static
560 struct lttng_handle *create_ust_handle(struct lttng_trace_ctx *ctx)
561 {
562 struct lttng_domain domain;
563
564 memset(&domain, 0, sizeof(domain));
565 domain.type = LTTNG_DOMAIN_UST;
566 domain.buf_type = LTTNG_BUFFER_PER_UID;
567 return lttng_create_handle(ctx->session_name, &domain);
568 }
569
570 static
571 void sighandler(int signo, siginfo_t *siginfo __unused, void *context __unused)
572 {
573 int ret;
574
575 DBG("sighandler receives signal %d, forwarding to child %d",
576 signo, sigfwd_pid);
577 ret = kill(sigfwd_pid, signo);
578 if (ret) {
579 PERROR("kill");
580 abort();
581 }
582 }
583
584 /*
585 * Replace forbidden session name characters by '_'.
586 */
587 static
588 void replace_session_chars(char *session_name)
589 {
590 size_t len, i;
591
592 len = strlen(session_name);
593 for (i = 0; i < len; i++) {
594 char *p = &session_name[i];
595 switch (*p) {
596 case '/':
597 *p = '_';
598 break;
599 case '.':
600 /* Leading dot is replaced by '_'. */
601 if (i == 0)
602 *p = '_';
603 break;
604 default:
605 break;
606 }
607 }
608 }
609
610 static
611 int lttng_trace_ctx_init(struct lttng_trace_ctx *ctx, const char *cmd_name)
612 {
613 char datetime[16];
614 struct tm *timeinfo;
615
616 ctx->creation_time = time(NULL);
617 if (ctx->creation_time == (time_t) -1) {
618 PERROR("time");
619 return -1;
620 }
621 timeinfo = localtime(&ctx->creation_time);
622 if (!timeinfo) {
623 PERROR("localtime");
624 return -1;
625 }
626 strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
627
628 if (opt_session) {
629 if (strlen(session_name) > LTTNG_NAME_MAX - 1) {
630 ERR("Session name is too long");
631 return -1;
632 }
633 strcpy(ctx->session_name, session_name);
634 } else {
635 memset(ctx, 0, sizeof(*ctx));
636 strncpy(ctx->session_name, cmd_name, LTTNG_NAME_MAX - 1);
637 ctx->session_name[LTTNG_NAME_MAX - 1] = '\0';
638 strcat(ctx->session_name, "-");
639 strcat(ctx->session_name, datetime);
640 }
641 replace_session_chars(ctx->session_name);
642
643 if (opt_output) {
644 if (strlen(output_path) > PATH_MAX - 1) {
645 ERR("output path is too long");
646 return -1;
647 }
648 strcpy(ctx->path, output_path);
649 } else {
650 strcpy(ctx->path, "/tmp/lttng-trace/");
651 strcat(ctx->path, ctx->session_name);
652 }
653 return 0;
654 }
655
656 static
657 int lttng_trace_untrack_all(struct lttng_handle **handle,
658 size_t nr_handles)
659 {
660 size_t i;
661 int ret;
662
663 for (i = 0; i < nr_handles; i++) {
664 ret = lttng_untrack_pid(handle[i], -1);
665 if (ret && ret != -LTTNG_ERR_INVALID) {
666 ERR("Error %d untracking pid %d", ret, -1);
667 }
668 }
669 return 0;
670 }
671
672 /* Return value:
673 * >= 0: number of arguments to skip before command.
674 * < 0: error.
675 */
676 static
677 int parse_args(int argc, char **argv)
678 {
679 int i;
680
681 for (i = 1; i < argc; i++) {
682 const char *str = argv[i];
683
684 if (!strcmp(str, "--")) {
685 i++; /* Next is command position. */
686 goto end;
687 }
688 if (str[0] != '-') {
689 goto end; /* Cursor at command position. */
690 }
691 if (!strcmp(str, "--help")) {
692 opt_help = true;
693 }
694 if (!strcmp(str, "--no-context")) {
695 opt_no_context = true;
696 }
697 if (!strcmp(str, "--no-pause")) {
698 opt_no_pause = true;
699 }
700 if (!strcmp(str, "--no-syscall")) {
701 opt_no_syscall = true;
702 }
703 if (!strcmp(str, "--output")) {
704 opt_output = true;
705 if (i == argc - 1) {
706 ERR("Expected path argument after --output");
707 return -1;
708 }
709 output_path = argv[++i];
710 }
711 if (!strcmp(str, "--session")) {
712 opt_session = true;
713 if (i == argc - 1) {
714 ERR("Expected path argument after --session");
715 return -1;
716 }
717 session_name = argv[++i];
718 }
719 if (!strcmp(str, "--view")) {
720 opt_view = true;
721 }
722 }
723 end:
724 if (i == argc && !opt_help) {
725 ERR("Expected COMMAND argument after options. See `%s --help` for details.", argv[0]);
726 return -1;
727 }
728 return i;
729 }
730
731 static
732 int show_help(int argc __unused, char **argv)
733 {
734 printf("Usage of %s:\n", argv[0]);
735 printf("\n");
736 printf(" %s [OPTION] [--] COMMAND [COMMAND OPTIONS]\n", argv[0]);
737 printf("\n");
738 printf("Runs COMMAND while tracing the system calls of the children\n");
739 printf("process hierarchy. See standard error output while executing\n");
740 printf("this command for more information.\n");
741 printf("\n");
742 printf("Supported options:\n");
743 printf(" --help: This help screen.\n");
744 printf(" --no-context: Do not trace default contexts (vpid, vtid, procname).\n");
745 printf(" --no-pause: Do not wait for user input before running COMMAND.\n");
746 printf(" --no-syscall: Do not trace system calls.\n");
747 printf(" --output PATH: Write trace into output PATH. (default: /tmp/lttng-ptrace/$SESSION_NAME)\n");
748 printf(" --session NAME: Tracing session name. (default: lttng-ptrace-$PID-$DATETIME)\n");
749 printf(" --view: View trace after end of COMMAND execution.\n");
750 printf("\n");
751 return 0;
752 }
753
754 int main(int argc, char **argv)
755 {
756 int retval = 0, ret;
757 pid_t pid;
758 struct lttng_handle *handle[NR_HANDLES];
759 struct sigaction act;
760 struct lttng_trace_ctx ptrace_ctx;
761 int skip_args = 0;
762
763 skip_args = parse_args(argc, argv);
764 if (skip_args < 0) {
765 return EXIT_FAILURE;
766 }
767 if (opt_help) {
768 show_help(argc, argv);
769 return EXIT_SUCCESS;
770 }
771
772 if (lttng_trace_ctx_init(&ptrace_ctx, argv[skip_args])) {
773 ERR("Error initializing trace context");
774 retval = -1;
775 goto end;
776 }
777
778 act.sa_sigaction = sighandler;
779 act.sa_flags = SA_SIGINFO | SA_RESTART;
780 sigemptyset(&act.sa_mask);
781 ret = sigaction(SIGTERM, &act, NULL);
782 if (ret) {
783 PERROR("sigaction");
784 retval = -1;
785 goto end;
786 }
787 ret = sigaction(SIGINT, &act, NULL);
788 if (ret) {
789 PERROR("sigaction");
790 retval = -1;
791 goto end;
792 }
793 if (create_session(&ptrace_ctx) < 0) {
794 fprintf(stderr, "%sError: Unable to create tracing session. Please ensure that lttng-sessiond is running as root and that your user belongs to the `tracing` group.\n", MESSAGE_PREFIX);
795 retval = -1;
796 goto end;
797 }
798 handle[0] = create_kernel_handle(&ptrace_ctx);
799 if (!handle[0]) {
800 retval = -1;
801 goto end_kernel_handle;
802 }
803 handle[1] = create_ust_handle(&ptrace_ctx);
804 if (!handle[1]) {
805 retval = -1;
806 goto end_ust_handle;
807 }
808 if (create_channels(&ptrace_ctx, LTTNG_DOMAIN_KERNEL) < 0) {
809 retval = -1;
810 goto end_wait_on_children;
811 }
812 if (create_channels(&ptrace_ctx, LTTNG_DOMAIN_UST) < 0) {
813 retval = -1;
814 goto end_wait_on_children;
815 }
816 if (enable_syscalls(&ptrace_ctx) < 0) {
817 retval = -1;
818 goto end_wait_on_children;
819 }
820 if (add_contexts(&ptrace_ctx, LTTNG_DOMAIN_KERNEL) < 0) {
821 retval = -1;
822 goto end_wait_on_children;
823 }
824 if (add_contexts(&ptrace_ctx, LTTNG_DOMAIN_UST) < 0) {
825 retval = -1;
826 goto end_wait_on_children;
827 }
828 if (lttng_trace_untrack_all(handle, NR_HANDLES) < 0) {
829 retval = -1;
830 goto end_wait_on_children;
831 }
832 fprintf(stderr, "%sTracing session `%s` created. It can be customized using the `lttng` command.\n", MESSAGE_PREFIX, ptrace_ctx.session_name);
833 if (!opt_no_pause) {
834 fprintf(stderr, "%sPress <ENTER> key when ready to run the child process.\n", MESSAGE_PREFIX);
835 getchar();
836 }
837
838 if (start_session(&ptrace_ctx) < 0) {
839 retval = -1;
840 goto end_wait_on_children;
841 }
842
843 //TODO: signal off before we can forward it.
844 pid = run_child(argc - skip_args, argv + skip_args);
845 if (pid <= 0) {
846 retval = -1;
847 goto end;
848 }
849
850 sigfwd_pid = pid;
851 //TODO signals on
852
853 ret = wait_on_children(pid, handle, NR_HANDLES);
854 if (ret) {
855 retval = -1;
856 goto end_wait_on_children;
857 }
858
859
860 end_wait_on_children:
861 lttng_destroy_handle(handle[1]);
862 end_ust_handle:
863 lttng_destroy_handle(handle[0]);
864 end_kernel_handle:
865 if (destroy_session(&ptrace_ctx)) {
866 ERR("Error destroying session");
867 retval = -1;
868 }
869 end:
870 if (retval) {
871 return EXIT_FAILURE;
872 } else {
873 fprintf(stderr, "%sSub-process hierarchy traced successfully. View trace with `babeltrace2 %s`.\n", MESSAGE_PREFIX,
874 ptrace_ctx.path);
875 if (opt_view) {
876 return execlp("babeltrace2", "babeltrace2", ptrace_ctx.path, NULL);
877 }
878 return EXIT_SUCCESS;
879 }
880 return 0;
881 }
This page took 0.045726 seconds and 4 git commands to generate.