2 * Copyright (c) 2015-2021 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
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.
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.
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.
24 #include <sys/types.h>
27 #include <sys/ptrace.h>
29 #include <sys/signal.h>
34 #include <lttng/lttng.h>
35 #include <lttng/handle.h>
36 #include <lttng/session.h>
37 #include <lttng/tracker.h>
39 #define MESSAGE_PREFIX "[lttng-trace] "
42 #ifndef PTRACE_EVENT_STOP
43 #define PTRACE_EVENT_STOP 128
46 #define PERROR(msg) perror(msg "\n")
47 #define ERR(fmt, args...) fprintf(stderr, fmt "\n", ## args)
50 #define DBG(fmt, args...) printf(fmt "\n", ## args)
52 #define DBG(fmt, args...)
55 #define __unused __attribute__((unused))
57 static pid_t sigfwd_pid
;
59 static bool opt_help
= false,
60 opt_no_context
= false,
62 opt_no_syscall
= false,
67 static const char *output_path
;
68 static const char *session_name
;
70 struct lttng_trace_ctx
{
71 char session_name
[LTTNG_NAME_MAX
];
77 long ptrace_setup(pid_t pid
)
82 flags
= PTRACE_O_TRACECLONE
| PTRACE_O_TRACEEXIT
83 | PTRACE_O_TRACEFORK
| PTRACE_O_TRACEVFORK
85 //ptrace_ret = ptrace(PTRACE_SETOPTIONS, pid,
86 ptrace_ret
= ptrace(PTRACE_SEIZE
, pid
,
87 NULL
, (void *) flags
);
89 //PERROR("ptrace setoptions");
90 PERROR("ptrace seize");
97 int wait_on_children(pid_t top_pid
, struct lttng_handle
**handle
,
106 DBG("Setup ptrace options on top child pid %d", pid
);
107 ret
= ptrace_setup(pid
);
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
);
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
);
131 pid
= waitpid(-1, &status
, __WALL
);
132 DBG("Activity on child pid %d", pid
);
134 if (errno
== ECHILD
) {
135 /* No more children to possibly wait for. */
141 } else if (pid
== 0) {
142 ERR("Unexpected PID 0");
145 if (WIFSTOPPED(status
)) {
146 int shiftstatus
, restartsig
;
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
);
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
);
160 } else if (shiftstatus
== (SIGTRAP
| (PTRACE_EVENT_FORK
<< 8))) {
163 ptrace_ret
= ptrace(PTRACE_GETEVENTMSG
, pid
, 0, &newpid
);
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
);
175 } else if (shiftstatus
== (SIGTRAP
| (PTRACE_EVENT_VFORK
<< 8))) {
178 ptrace_ret
= ptrace(PTRACE_GETEVENTMSG
, pid
, 0, &newpid
);
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
);
190 } else if (shiftstatus
== (SIGTRAP
| PTRACE_EVENT_CLONE
<< 8)) {
193 ptrace_ret
= ptrace(PTRACE_GETEVENTMSG
, pid
, 0, &newpid
);
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
);
205 } else if (shiftstatus
== (SIGTRAP
| PTRACE_EVENT_EXEC
<< 8)) {
208 ptrace_ret
= ptrace(PTRACE_GETEVENTMSG
, pid
, 0, &oldpid
);
213 DBG("Child pid (old: %ld, new: %d) is issuing exec",
216 * Needed for exec issued from
217 * multithreaded process.
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
);
224 ret
= lttng_track_pid(handle
[i
], pid
);
225 if (ret
&& ret
!= -LTTNG_ERR_INVALID
) {
226 ERR("Error %d tracking pid %d", ret
, pid
);
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
);
242 DBG("Ignoring signal %d (status %d) from pid %d (eventcode = %u)",
243 WSTOPSIG(status
), status
, pid
,
244 (shiftstatus
& ~WSTOPSIG(status
)) >> 8);
247 restartsig
= WSTOPSIG(status
);
248 switch (restartsig
) {
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
);
265 } else if (status
>> 16 == PTRACE_EVENT_STOP
) {
267 //ptrace_ret = ptrace(PTRACE_LISTEN, pid, 0, 0);
268 ptrace_ret
= ptrace(PTRACE_CONT
, pid
, 0, 0);
270 PERROR("ptrace cont");
274 DBG("job control stop ret %ld errno %d", ptrace_ret
, errno
);
276 * It's not a group-stop, so restart process,
277 * skipping the signal.
279 ptrace_ret
= ptrace(PTRACE_CONT
, pid
, 0, 0);
281 PERROR("ptrace cont");
289 //unsigned long data;
291 //if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data) == 0) {
293 * Restart process skipping the signal when
294 * receiving a message.
296 ptrace_ret
= ptrace(PTRACE_CONT
, pid
, 0, 0);
306 /* Restart with original signal. */
307 ptrace_ret
= ptrace(PTRACE_CONT
, pid
, 0, restartsig
);
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
);
322 } else if (WIFSIGNALED(status
)) {
323 DBG("Child pid %d terminated by signal %d", pid
,
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
);
332 DBG("Unhandled status %d from child %d", status
, pid
);
339 int run_child(int argc
, char **argv
)
345 ERR("Please provide executable name as first argument.");
352 DBG("Child process created (pid: %d)", pid
);
353 } else if (pid
== 0) {
358 ptraceret
= ptrace(PTRACE_TRACEME
, 0, NULL
, NULL
);
364 ret
= raise(SIGSTOP
);
369 ret
= execvp(argv
[0], &argv
[0]);
382 int create_session(struct lttng_trace_ctx
*ctx
)
384 return lttng_create_session(ctx
->session_name
, ctx
->path
);
388 int destroy_session(struct lttng_trace_ctx
*ctx
)
390 return lttng_destroy_session(ctx
->session_name
);
394 int start_session(struct lttng_trace_ctx
*ctx
)
396 return lttng_start_tracing(ctx
->session_name
);
400 int enable_syscalls(struct lttng_trace_ctx
*ctx
)
402 struct lttng_domain domain
;
403 struct lttng_event
*ev
;
404 struct lttng_handle
*handle
;
409 memset(&domain
, 0, sizeof(domain
));
410 ev
= lttng_event_create();
412 ERR("Error creating event");
415 domain
.type
= LTTNG_DOMAIN_KERNEL
;
416 domain
.buf_type
= LTTNG_BUFFER_GLOBAL
;
418 handle
= lttng_create_handle(ctx
->session_name
, &domain
);
420 ERR("Error creating handle");
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
);
430 ERR("Error enabling syscall events");
433 lttng_destroy_handle(handle
);
435 lttng_event_destroy(ev
);
441 int add_contexts(struct lttng_trace_ctx
*ctx
, enum lttng_domain_type domain_type
)
443 struct lttng_domain domain
;
444 struct lttng_event_context event_ctx
;
445 struct lttng_handle
*handle
;
446 const char *domain_str
;
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";
457 case LTTNG_DOMAIN_UST
:
458 domain
.buf_type
= LTTNG_BUFFER_PER_UID
;
464 domain
.type
= domain_type
;
466 handle
= lttng_create_handle(ctx
->session_name
, &domain
);
468 ERR("Error creating handle");
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
);
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
);
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
);
495 lttng_destroy_handle(handle
);
501 int create_channels(struct lttng_trace_ctx
*ctx
, enum lttng_domain_type domain_type
)
503 struct lttng_domain domain
;
504 struct lttng_channel
*channel
;
505 struct lttng_handle
*handle
;
506 const char *domain_str
;
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";
515 case LTTNG_DOMAIN_UST
:
516 domain
.buf_type
= LTTNG_BUFFER_PER_UID
;
522 domain
.type
= domain_type
;
523 channel
= lttng_channel_create(&domain
);
525 ERR("Error creating channel for domain `%s`", domain_str
);
529 channel
->enabled
= 1;
531 handle
= lttng_create_handle(ctx
->session_name
, &domain
);
533 ERR("Error creating handle");
537 if (lttng_enable_channel(handle
, channel
) < 0) {
538 ERR("Error enabling channel for domain `%s`", domain_str
);
541 lttng_destroy_handle(handle
);
543 lttng_channel_destroy(channel
);
549 struct lttng_handle
*create_kernel_handle(struct lttng_trace_ctx
*ctx
)
551 struct lttng_domain domain
;
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
);
560 struct lttng_handle
*create_ust_handle(struct lttng_trace_ctx
*ctx
)
562 struct lttng_domain domain
;
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
);
571 void sighandler(int signo
, siginfo_t
*siginfo __unused
, void *context __unused
)
575 DBG("sighandler receives signal %d, forwarding to child %d",
577 ret
= kill(sigfwd_pid
, signo
);
585 int lttng_trace_ctx_init(struct lttng_trace_ctx
*ctx
, const char *cmd_name
)
590 ctx
->creation_time
= time(NULL
);
591 if (ctx
->creation_time
== (time_t) -1) {
595 timeinfo
= localtime(&ctx
->creation_time
);
600 strftime(datetime
, sizeof(datetime
), "%Y%m%d-%H%M%S", timeinfo
);
603 if (strlen(session_name
) > LTTNG_NAME_MAX
- 1) {
604 ERR("Session name is too long");
607 strcpy(ctx
->session_name
, session_name
);
609 memset(ctx
, 0, sizeof(*ctx
));
610 strncpy(ctx
->session_name
, cmd_name
, LTTNG_NAME_MAX
- 1);
611 ctx
->session_name
[LTTNG_NAME_MAX
- 1] = '\0';
612 strcat(ctx
->session_name
, "-");
613 strcat(ctx
->session_name
, datetime
);
617 if (strlen(output_path
) > PATH_MAX
- 1) {
618 ERR("output path is too long");
621 strcpy(ctx
->path
, output_path
);
623 strcpy(ctx
->path
, "/tmp/lttng-trace/");
624 strcat(ctx
->path
, ctx
->session_name
);
630 int lttng_trace_untrack_all(struct lttng_handle
**handle
,
636 for (i
= 0; i
< nr_handles
; i
++) {
637 ret
= lttng_untrack_pid(handle
[i
], -1);
638 if (ret
&& ret
!= -LTTNG_ERR_INVALID
) {
639 ERR("Error %d untracking pid %d", ret
, -1);
646 * >= 0: number of arguments to skip before command.
650 int parse_args(int argc
, char **argv
)
654 for (i
= 1; i
< argc
; i
++) {
655 const char *str
= argv
[i
];
657 if (!strcmp(str
, "--")) {
658 i
++; /* Next is command position. */
662 goto end
; /* Cursor at command position. */
664 if (!strcmp(str
, "--help")) {
667 if (!strcmp(str
, "--no-context")) {
668 opt_no_context
= true;
670 if (!strcmp(str
, "--no-pause")) {
673 if (!strcmp(str
, "--no-syscall")) {
674 opt_no_syscall
= true;
676 if (!strcmp(str
, "--output")) {
679 ERR("Expected path argument after --output");
682 output_path
= argv
[++i
];
684 if (!strcmp(str
, "--session")) {
687 ERR("Expected path argument after --session");
690 session_name
= argv
[++i
];
692 if (!strcmp(str
, "--view")) {
697 if (i
== argc
&& !opt_help
) {
698 ERR("Expected COMMAND argument after options. See `%s --help` for details.", argv
[0]);
705 int show_help(int argc __unused
, char **argv
)
707 printf("Usage of %s:\n", argv
[0]);
709 printf(" %s [OPTION] [--] COMMAND [COMMAND OPTIONS]\n", argv
[0]);
711 printf("Runs COMMAND while tracing the system calls of the children\n");
712 printf("process hierarchy. See standard error output while executing\n");
713 printf("this command for more information.\n");
715 printf("Supported options:\n");
716 printf(" --help: This help screen.\n");
717 printf(" --no-context: Do not trace default contexts (vpid, vtid, procname).\n");
718 printf(" --no-pause: Do not wait for user input before running COMMAND.\n");
719 printf(" --no-syscall: Do not trace system calls.\n");
720 printf(" --output PATH: Write trace into output PATH. (default: /tmp/lttng-ptrace/$SESSION_NAME)\n");
721 printf(" --session NAME: Tracing session name. (default: lttng-ptrace-$PID-$DATETIME)\n");
722 printf(" --view: View trace after end of COMMAND execution.\n");
727 int main(int argc
, char **argv
)
731 struct lttng_handle
*handle
[NR_HANDLES
];
732 struct sigaction act
;
733 struct lttng_trace_ctx ptrace_ctx
;
736 skip_args
= parse_args(argc
, argv
);
741 show_help(argc
, argv
);
745 if (lttng_trace_ctx_init(&ptrace_ctx
, argv
[skip_args
])) {
746 ERR("Error initializing trace context");
751 act
.sa_sigaction
= sighandler
;
752 act
.sa_flags
= SA_SIGINFO
| SA_RESTART
;
753 sigemptyset(&act
.sa_mask
);
754 ret
= sigaction(SIGTERM
, &act
, NULL
);
760 ret
= sigaction(SIGINT
, &act
, NULL
);
766 if (create_session(&ptrace_ctx
) < 0) {
767 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
);
771 handle
[0] = create_kernel_handle(&ptrace_ctx
);
774 goto end_kernel_handle
;
776 handle
[1] = create_ust_handle(&ptrace_ctx
);
781 if (create_channels(&ptrace_ctx
, LTTNG_DOMAIN_KERNEL
) < 0) {
783 goto end_wait_on_children
;
785 if (create_channels(&ptrace_ctx
, LTTNG_DOMAIN_UST
) < 0) {
787 goto end_wait_on_children
;
789 if (enable_syscalls(&ptrace_ctx
) < 0) {
791 goto end_wait_on_children
;
793 if (add_contexts(&ptrace_ctx
, LTTNG_DOMAIN_KERNEL
) < 0) {
795 goto end_wait_on_children
;
797 if (add_contexts(&ptrace_ctx
, LTTNG_DOMAIN_UST
) < 0) {
799 goto end_wait_on_children
;
801 if (lttng_trace_untrack_all(handle
, NR_HANDLES
) < 0) {
803 goto end_wait_on_children
;
805 fprintf(stderr
, "%sTracing session `%s` created. It can be customized using the `lttng` command.\n", MESSAGE_PREFIX
, ptrace_ctx
.session_name
);
807 fprintf(stderr
, "%sPress <ENTER> key when ready to run the child process.\n", MESSAGE_PREFIX
);
811 if (start_session(&ptrace_ctx
) < 0) {
813 goto end_wait_on_children
;
816 //TODO: signal off before we can forward it.
817 pid
= run_child(argc
- skip_args
, argv
+ skip_args
);
826 ret
= wait_on_children(pid
, handle
, NR_HANDLES
);
829 goto end_wait_on_children
;
833 end_wait_on_children
:
834 lttng_destroy_handle(handle
[1]);
836 lttng_destroy_handle(handle
[0]);
838 if (destroy_session(&ptrace_ctx
)) {
839 ERR("Error destroying session");
846 fprintf(stderr
, "%sSub-process hierarchy traced successfully. View trace with `babeltrace2 %s`.\n", MESSAGE_PREFIX
,
849 return execlp("babeltrace2", "babeltrace2", ptrace_ctx
.path
, NULL
);