1d8e69ca616dfbb4acb0a2996bfe20e2664efb8f
[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 abort();
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 abort();
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 abort();
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 abort();
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 abort();
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 abort();
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 abort();
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 abort();
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 abort();
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 abort();
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 abort();
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;
406
407 if (opt_no_syscall)
408 return 0;
409 memset(&domain, 0, sizeof(domain));
410 ev = lttng_event_create();
411 if (!ev)
412 abort();
413 domain.type = LTTNG_DOMAIN_KERNEL;
414 domain.buf_type = LTTNG_BUFFER_GLOBAL;
415
416 handle = lttng_create_handle(ctx->session_name, &domain);
417 if (!handle)
418 abort();
419 ev->type = LTTNG_EVENT_SYSCALL;
420 strcpy(ev->name, "*");
421 ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
422 ret = lttng_enable_event_with_exclusions(handle,
423 ev, NULL, NULL, 0, NULL);
424 if (ret)
425 abort();
426 lttng_destroy_handle(handle);
427 return 0;
428 }
429
430 static
431 int add_contexts(struct lttng_trace_ctx *ctx, enum lttng_domain_type domain_type)
432 {
433 struct lttng_domain domain;
434 struct lttng_event_context event_ctx;
435 struct lttng_handle *handle;
436
437 if (opt_no_context)
438 return 0;
439 memset(&domain, 0, sizeof(domain));
440 switch (domain_type) {
441 case LTTNG_DOMAIN_KERNEL:
442 domain.buf_type = LTTNG_BUFFER_GLOBAL;
443 break;
444 case LTTNG_DOMAIN_UST:
445 domain.buf_type = LTTNG_BUFFER_PER_UID;
446 break;
447 default:
448 return -1;
449 }
450 domain.type = domain_type;
451
452 handle = lttng_create_handle(ctx->session_name, &domain);
453 if (!handle)
454 abort();
455
456 memset(&event_ctx, 0, sizeof(event_ctx));
457 event_ctx.ctx = LTTNG_EVENT_CONTEXT_PROCNAME;
458 if (lttng_add_context(handle, &event_ctx, NULL, NULL) < 0)
459 abort();
460
461 memset(&event_ctx, 0, sizeof(event_ctx));
462 event_ctx.ctx = LTTNG_EVENT_CONTEXT_VPID;
463 if (lttng_add_context(handle, &event_ctx, NULL, NULL) < 0)
464 abort();
465
466 memset(&event_ctx, 0, sizeof(event_ctx));
467 event_ctx.ctx = LTTNG_EVENT_CONTEXT_VTID;
468 if (lttng_add_context(handle, &event_ctx, NULL, NULL) < 0)
469 abort();
470
471 lttng_destroy_handle(handle);
472 return 0;
473 }
474
475 static
476 int create_channels(struct lttng_trace_ctx *ctx, enum lttng_domain_type domain_type)
477 {
478 struct lttng_domain domain;
479 struct lttng_channel *channel;
480 struct lttng_handle *handle;
481
482 memset(&domain, 0, sizeof(domain));
483 switch (domain_type) {
484 case LTTNG_DOMAIN_KERNEL:
485 domain.buf_type = LTTNG_BUFFER_GLOBAL;
486 break;
487 case LTTNG_DOMAIN_UST:
488 domain.buf_type = LTTNG_BUFFER_PER_UID;
489 break;
490 default:
491 return -1;
492 }
493 domain.type = domain_type;
494 channel = lttng_channel_create(&domain);
495 channel->enabled = 1;
496
497 handle = lttng_create_handle(ctx->session_name, &domain);
498 if (!handle)
499 abort();
500 if (lttng_enable_channel(handle, channel) < 0)
501 abort();
502 lttng_destroy_handle(handle);
503
504 lttng_channel_destroy(channel);
505 return 0;
506 }
507
508 static
509 struct lttng_handle *create_kernel_handle(struct lttng_trace_ctx *ctx)
510 {
511 struct lttng_domain domain;
512
513 memset(&domain, 0, sizeof(domain));
514 domain.type = LTTNG_DOMAIN_KERNEL;
515 domain.buf_type = LTTNG_BUFFER_GLOBAL;
516 return lttng_create_handle(ctx->session_name, &domain);
517 }
518
519 static
520 struct lttng_handle *create_ust_handle(struct lttng_trace_ctx *ctx)
521 {
522 struct lttng_domain domain;
523
524 memset(&domain, 0, sizeof(domain));
525 domain.type = LTTNG_DOMAIN_UST;
526 domain.buf_type = LTTNG_BUFFER_PER_UID;
527 return lttng_create_handle(ctx->session_name, &domain);
528 }
529
530 static
531 void sighandler(int signo, siginfo_t *siginfo __unused, void *context __unused)
532 {
533 int ret;
534
535 DBG("sighandler receives signal %d, forwarding to child %d",
536 signo, sigfwd_pid);
537 ret = kill(sigfwd_pid, signo);
538 if (ret) {
539 PERROR("kill");
540 abort();
541 }
542 }
543
544 static
545 int lttng_trace_ctx_init(struct lttng_trace_ctx *ctx, const char *cmd_name)
546 {
547 char datetime[16];
548 struct tm *timeinfo;
549
550 ctx->creation_time = time(NULL);
551 if (ctx->creation_time == (time_t) -1)
552 abort();
553 timeinfo = localtime(&ctx->creation_time);
554 if (!timeinfo)
555 abort();
556 strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
557
558 if (opt_session) {
559 if (strlen(session_name) > LTTNG_NAME_MAX - 1) {
560 abort();
561 }
562 strcpy(ctx->session_name, session_name);
563 } else {
564 memset(ctx, 0, sizeof(*ctx));
565 strncpy(ctx->session_name, cmd_name, LTTNG_NAME_MAX - 1);
566 ctx->session_name[LTTNG_NAME_MAX - 1] = '\0';
567 strcat(ctx->session_name, "-");
568 strcat(ctx->session_name, datetime);
569 }
570
571 if (opt_output) {
572 if (strlen(output_path) > PATH_MAX - 1) {
573 abort();
574 }
575 strcpy(ctx->path, output_path);
576 } else {
577 strcpy(ctx->path, "/tmp/lttng-trace/");
578 strcat(ctx->path, ctx->session_name);
579 }
580 return 0;
581 }
582
583 static
584 int lttng_trace_untrack_all(struct lttng_handle **handle,
585 size_t nr_handles)
586 {
587 size_t i;
588 int ret;
589
590 for (i = 0; i < nr_handles; i++) {
591 ret = lttng_untrack_pid(handle[i], -1);
592 if (ret && ret != -LTTNG_ERR_INVALID) {
593 ERR("Error %d untracking pid %d", ret, -1);
594 abort();
595 }
596 }
597 return 0;
598 }
599
600 /* Return value:
601 * >= 0: number of arguments to skip before command.
602 * < 0: error.
603 */
604 static
605 int parse_args(int argc, char **argv)
606 {
607 int i;
608
609 for (i = 1; i < argc; i++) {
610 const char *str = argv[i];
611
612 if (!strcmp(str, "--")) {
613 i++; /* Next is command position. */
614 goto end;
615 }
616 if (str[0] != '-') {
617 goto end; /* Cursor at command position. */
618 }
619 if (!strcmp(str, "--help")) {
620 opt_help = true;
621 }
622 if (!strcmp(str, "--no-context")) {
623 opt_no_context = true;
624 }
625 if (!strcmp(str, "--no-pause")) {
626 opt_no_pause = true;
627 }
628 if (!strcmp(str, "--no-syscall")) {
629 opt_no_syscall = true;
630 }
631 if (!strcmp(str, "--output")) {
632 opt_output = true;
633 if (i == argc - 1) {
634 ERR("Expected path argument after --output");
635 return -1;
636 }
637 output_path = argv[++i];
638 }
639 if (!strcmp(str, "--session")) {
640 opt_session = true;
641 if (i == argc - 1) {
642 ERR("Expected path argument after --session");
643 return -1;
644 }
645 session_name = argv[++i];
646 }
647 if (!strcmp(str, "--view")) {
648 opt_view = true;
649 }
650 }
651 end:
652 if (i == argc && !opt_help) {
653 ERR("Expected COMMAND argument after options. See `%s --help` for details.", argv[0]);
654 return -1;
655 }
656 return i;
657 }
658
659 static
660 int show_help(int argc __unused, char **argv)
661 {
662 printf("Usage of %s:\n", argv[0]);
663 printf("\n");
664 printf(" %s [OPTION] [--] COMMAND [COMMAND OPTIONS]\n", argv[0]);
665 printf("\n");
666 printf("Runs COMMAND while tracing the system calls of the children\n");
667 printf("process hierarchy. See standard error output while executing\n");
668 printf("this command for more information.\n");
669 printf("\n");
670 printf("Supported options:\n");
671 printf(" --help: This help screen.\n");
672 printf(" --no-context: Do not trace default contexts (vpid, vtid, procname).\n");
673 printf(" --no-pause: Do not wait for user input before running COMMAND.\n");
674 printf(" --no-syscall: Do not trace system calls.\n");
675 printf(" --output PATH: Write trace into output PATH. (default: /tmp/lttng-ptrace/$SESSION_NAME)\n");
676 printf(" --session NAME: Tracing session name. (default: lttng-ptrace-$PID-$DATETIME)\n");
677 printf(" --view: View trace after end of COMMAND execution.\n");
678 printf("\n");
679 return 0;
680 }
681
682 int main(int argc, char **argv)
683 {
684 int retval = 0, ret;
685 pid_t pid;
686 struct lttng_handle *handle[NR_HANDLES];
687 struct sigaction act;
688 struct lttng_trace_ctx ptrace_ctx;
689 int skip_args = 0;
690
691 skip_args = parse_args(argc, argv);
692 if (skip_args < 0) {
693 return EXIT_FAILURE;
694 }
695 if (opt_help) {
696 show_help(argc, argv);
697 return EXIT_SUCCESS;
698 }
699
700 if (lttng_trace_ctx_init(&ptrace_ctx, argv[skip_args]))
701 abort();
702
703 act.sa_sigaction = sighandler;
704 act.sa_flags = SA_SIGINFO | SA_RESTART;
705 sigemptyset(&act.sa_mask);
706 ret = sigaction(SIGTERM, &act, NULL);
707 if (ret)
708 abort();
709 ret = sigaction(SIGINT, &act, NULL);
710 if (ret)
711 abort();
712
713 if (create_session(&ptrace_ctx) < 0) {
714 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);
715 retval = -1;
716 goto end;
717 }
718 handle[0] = create_kernel_handle(&ptrace_ctx);
719 if (!handle[0]) {
720 retval = -1;
721 goto end_kernel_handle;
722 }
723 handle[1] = create_ust_handle(&ptrace_ctx);
724 if (!handle[1]) {
725 retval = -1;
726 goto end_ust_handle;
727 }
728 if (create_channels(&ptrace_ctx, LTTNG_DOMAIN_KERNEL) < 0) {
729 retval = -1;
730 goto end_wait_on_children;
731 }
732 if (create_channels(&ptrace_ctx, LTTNG_DOMAIN_UST) < 0) {
733 retval = -1;
734 goto end_wait_on_children;
735 }
736 if (enable_syscalls(&ptrace_ctx) < 0) {
737 retval = -1;
738 goto end_wait_on_children;
739 }
740 if (add_contexts(&ptrace_ctx, LTTNG_DOMAIN_KERNEL) < 0) {
741 retval = -1;
742 goto end_wait_on_children;
743 }
744 if (add_contexts(&ptrace_ctx, LTTNG_DOMAIN_UST) < 0) {
745 retval = -1;
746 goto end_wait_on_children;
747 }
748 if (lttng_trace_untrack_all(handle, NR_HANDLES) < 0) {
749 retval = -1;
750 goto end_wait_on_children;
751 }
752 fprintf(stderr, "%sTracing session `%s` created. It can be customized using the `lttng` command.\n", MESSAGE_PREFIX, ptrace_ctx.session_name);
753 if (!opt_no_pause) {
754 fprintf(stderr, "Press <ENTER> key when ready to run the child process.\n");
755 getchar();
756 }
757
758 if (start_session(&ptrace_ctx) < 0) {
759 retval = -1;
760 goto end_wait_on_children;
761 }
762
763 //TODO: signal off before we can forward it.
764 pid = run_child(argc - skip_args, argv + skip_args);
765 if (pid <= 0) {
766 retval = -1;
767 goto end;
768 }
769
770 sigfwd_pid = pid;
771 //TODO signals on
772
773 ret = wait_on_children(pid, handle, NR_HANDLES);
774 if (ret) {
775 retval = -1;
776 goto end_wait_on_children;
777 }
778
779
780 end_wait_on_children:
781 lttng_destroy_handle(handle[1]);
782 end_ust_handle:
783 lttng_destroy_handle(handle[0]);
784 end_kernel_handle:
785 if (destroy_session(&ptrace_ctx))
786 abort();
787 end:
788 if (retval) {
789 return EXIT_FAILURE;
790 } else {
791 fprintf(stderr, "%sSub-process hierarchy traced successfully. View trace with `babeltrace2 %s`.\n", MESSAGE_PREFIX,
792 ptrace_ctx.path);
793 if (opt_view) {
794 return execlp("babeltrace2", "babeltrace2", ptrace_ctx.path, NULL);
795 }
796 return EXIT_SUCCESS;
797 }
798 return 0;
799 }
This page took 0.043902 seconds and 3 git commands to generate.