Error handling
[lttng-trace.git] / src / lttng-trace.c
CommitLineData
27caca78
MD
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
bd213c0b 39#define MESSAGE_PREFIX "[lttng-trace] "
27caca78
MD
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")
4f25f88c 47#define ERR(fmt, args...) fprintf(stderr, fmt "\n", ## args)
27caca78
MD
48
49#ifdef DEBUG
4f25f88c 50#define DBG(fmt, args...) printf(fmt "\n", ## args)
27caca78
MD
51#else
52#define DBG(fmt, args...)
53#endif
54
55#define __unused __attribute__((unused))
56
57static pid_t sigfwd_pid;
58
59static 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
67static const char *output_path;
68static const char *session_name;
69
70struct lttng_trace_ctx {
71 char session_name[LTTNG_NAME_MAX];
72 char path[PATH_MAX];
73 time_t creation_time;
74};
75
76static
77long 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
96static
97int 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");
25c1285e 125 return -1;
27caca78
MD
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");
25c1285e 143 return -1;
27caca78
MD
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");
25c1285e 166 return -1;
27caca78
MD
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");
25c1285e 181 return -1;
27caca78
MD
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");
25c1285e 196 return -1;
27caca78
MD
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");
25c1285e 211 return -1;
27caca78
MD
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");
25c1285e 263 return -1;
27caca78
MD
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");
25c1285e 271 return -1;
27caca78
MD
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");
25c1285e 282 return -1;
27caca78
MD
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");
25c1285e 299 return -1;
27caca78
MD
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");
25c1285e 310 return -1;
27caca78
MD
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
338static
339int 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
381static
382int create_session(struct lttng_trace_ctx *ctx)
383{
384 return lttng_create_session(ctx->session_name, ctx->path);
385}
386
387static
388int destroy_session(struct lttng_trace_ctx *ctx)
389{
390 return lttng_destroy_session(ctx->session_name);
391}
392
393static
394int start_session(struct lttng_trace_ctx *ctx)
395{
396 return lttng_start_tracing(ctx->session_name);
397}
398
399static
400int enable_syscalls(struct lttng_trace_ctx *ctx)
401{
402 struct lttng_domain domain;
403 struct lttng_event *ev;
404 struct lttng_handle *handle;
25c1285e 405 int ret = 0;
27caca78
MD
406
407 if (opt_no_syscall)
408 return 0;
409 memset(&domain, 0, sizeof(domain));
410 ev = lttng_event_create();
25c1285e
MD
411 if (!ev) {
412 ERR("Error creating event");
413 goto end;
414 }
27caca78
MD
415 domain.type = LTTNG_DOMAIN_KERNEL;
416 domain.buf_type = LTTNG_BUFFER_GLOBAL;
417
418 handle = lttng_create_handle(ctx->session_name, &domain);
25c1285e
MD
419 if (!handle) {
420 ERR("Error creating handle");
421 ret = -1;
422 goto error_handle;
423 }
27caca78
MD
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);
25c1285e
MD
429 if (ret) {
430 ERR("Error enabling syscall events");
431 ret = -1;
432 }
27caca78 433 lttng_destroy_handle(handle);
25c1285e
MD
434error_handle:
435 lttng_event_destroy(ev);
436end:
437 return ret;
27caca78
MD
438}
439
440static
441int 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;
25c1285e
MD
446 const char *domain_str;
447 int ret = 0;
27caca78
MD
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;
25c1285e 455 domain_str = "kernel";
27caca78
MD
456 break;
457 case LTTNG_DOMAIN_UST:
458 domain.buf_type = LTTNG_BUFFER_PER_UID;
25c1285e 459 domain_str = "ust";
27caca78
MD
460 break;
461 default:
462 return -1;
463 }
464 domain.type = domain_type;
465
466 handle = lttng_create_handle(ctx->session_name, &domain);
25c1285e
MD
467 if (!handle) {
468 ERR("Error creating handle");
469 ret = -1;
470 goto end;
471 }
27caca78
MD
472 memset(&event_ctx, 0, sizeof(event_ctx));
473 event_ctx.ctx = LTTNG_EVENT_CONTEXT_PROCNAME;
25c1285e
MD
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 }
27caca78
MD
479 memset(&event_ctx, 0, sizeof(event_ctx));
480 event_ctx.ctx = LTTNG_EVENT_CONTEXT_VPID;
25c1285e
MD
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 }
27caca78
MD
486 memset(&event_ctx, 0, sizeof(event_ctx));
487 event_ctx.ctx = LTTNG_EVENT_CONTEXT_VTID;
25c1285e
MD
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 }
27caca78 493
25c1285e 494error_context:
27caca78 495 lttng_destroy_handle(handle);
25c1285e
MD
496end:
497 return ret;
27caca78
MD
498}
499
500static
501int 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;
25c1285e
MD
506 const char *domain_str;
507 int ret = 0;
27caca78
MD
508
509 memset(&domain, 0, sizeof(domain));
510 switch (domain_type) {
511 case LTTNG_DOMAIN_KERNEL:
512 domain.buf_type = LTTNG_BUFFER_GLOBAL;
25c1285e 513 domain_str = "kernel";
27caca78
MD
514 break;
515 case LTTNG_DOMAIN_UST:
516 domain.buf_type = LTTNG_BUFFER_PER_UID;
25c1285e 517 domain_str = "ust";
27caca78
MD
518 break;
519 default:
520 return -1;
521 }
522 domain.type = domain_type;
523 channel = lttng_channel_create(&domain);
25c1285e
MD
524 if (!channel) {
525 ERR("Error creating channel for domain `%s`", domain_str);
526 ret = -1;
527 goto end;
528 }
27caca78
MD
529 channel->enabled = 1;
530
531 handle = lttng_create_handle(ctx->session_name, &domain);
25c1285e
MD
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 }
27caca78 541 lttng_destroy_handle(handle);
25c1285e 542error_handle:
27caca78 543 lttng_channel_destroy(channel);
25c1285e
MD
544end:
545 return ret;
27caca78
MD
546}
547
548static
549struct 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
559static
560struct 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
570static
571void 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
584static
bd213c0b 585int lttng_trace_ctx_init(struct lttng_trace_ctx *ctx, const char *cmd_name)
27caca78 586{
27caca78
MD
587 char datetime[16];
588 struct tm *timeinfo;
589
590 ctx->creation_time = time(NULL);
25c1285e
MD
591 if (ctx->creation_time == (time_t) -1) {
592 PERROR("time");
593 return -1;
594 }
27caca78 595 timeinfo = localtime(&ctx->creation_time);
25c1285e
MD
596 if (!timeinfo) {
597 PERROR("localtime");
598 return -1;
599 }
27caca78
MD
600 strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
601
602 if (opt_session) {
603 if (strlen(session_name) > LTTNG_NAME_MAX - 1) {
25c1285e
MD
604 ERR("Session name is too long");
605 return -1;
27caca78
MD
606 }
607 strcpy(ctx->session_name, session_name);
608 } else {
609 memset(ctx, 0, sizeof(*ctx));
bd213c0b
MD
610 strncpy(ctx->session_name, cmd_name, LTTNG_NAME_MAX - 1);
611 ctx->session_name[LTTNG_NAME_MAX - 1] = '\0';
27caca78
MD
612 strcat(ctx->session_name, "-");
613 strcat(ctx->session_name, datetime);
614 }
615
616 if (opt_output) {
617 if (strlen(output_path) > PATH_MAX - 1) {
25c1285e
MD
618 ERR("output path is too long");
619 return -1;
27caca78
MD
620 }
621 strcpy(ctx->path, output_path);
622 } else {
bd213c0b 623 strcpy(ctx->path, "/tmp/lttng-trace/");
27caca78
MD
624 strcat(ctx->path, ctx->session_name);
625 }
626 return 0;
627}
628
629static
630int lttng_trace_untrack_all(struct lttng_handle **handle,
631 size_t nr_handles)
632{
633 size_t i;
634 int ret;
635
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);
27caca78
MD
640 }
641 }
642 return 0;
643}
644
645/* Return value:
646 * >= 0: number of arguments to skip before command.
647 * < 0: error.
648 */
649static
650int parse_args(int argc, char **argv)
651{
652 int i;
653
654 for (i = 1; i < argc; i++) {
655 const char *str = argv[i];
656
657 if (!strcmp(str, "--")) {
658 i++; /* Next is command position. */
659 goto end;
660 }
661 if (str[0] != '-') {
662 goto end; /* Cursor at command position. */
663 }
664 if (!strcmp(str, "--help")) {
665 opt_help = true;
666 }
667 if (!strcmp(str, "--no-context")) {
668 opt_no_context = true;
669 }
670 if (!strcmp(str, "--no-pause")) {
671 opt_no_pause = true;
672 }
673 if (!strcmp(str, "--no-syscall")) {
674 opt_no_syscall = true;
675 }
676 if (!strcmp(str, "--output")) {
677 opt_output = true;
678 if (i == argc - 1) {
679 ERR("Expected path argument after --output");
680 return -1;
681 }
682 output_path = argv[++i];
683 }
684 if (!strcmp(str, "--session")) {
685 opt_session = true;
686 if (i == argc - 1) {
687 ERR("Expected path argument after --session");
688 return -1;
689 }
690 session_name = argv[++i];
691 }
692 if (!strcmp(str, "--view")) {
693 opt_view = true;
694 }
695 }
696end:
697 if (i == argc && !opt_help) {
698 ERR("Expected COMMAND argument after options. See `%s --help` for details.", argv[0]);
699 return -1;
700 }
701 return i;
702}
703
704static
705int show_help(int argc __unused, char **argv)
706{
707 printf("Usage of %s:\n", argv[0]);
708 printf("\n");
709 printf(" %s [OPTION] [--] COMMAND [COMMAND OPTIONS]\n", argv[0]);
710 printf("\n");
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");
714 printf("\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");
723 printf("\n");
724 return 0;
725}
726
727int main(int argc, char **argv)
728{
729 int retval = 0, ret;
730 pid_t pid;
731 struct lttng_handle *handle[NR_HANDLES];
732 struct sigaction act;
733 struct lttng_trace_ctx ptrace_ctx;
734 int skip_args = 0;
735
736 skip_args = parse_args(argc, argv);
737 if (skip_args < 0) {
738 return EXIT_FAILURE;
739 }
740 if (opt_help) {
741 show_help(argc, argv);
742 return EXIT_SUCCESS;
743 }
744
25c1285e
MD
745 if (lttng_trace_ctx_init(&ptrace_ctx, argv[skip_args])) {
746 ERR("Error initializing trace context");
747 retval = -1;
748 goto end;
749 }
27caca78
MD
750
751 act.sa_sigaction = sighandler;
752 act.sa_flags = SA_SIGINFO | SA_RESTART;
753 sigemptyset(&act.sa_mask);
754 ret = sigaction(SIGTERM, &act, NULL);
25c1285e
MD
755 if (ret) {
756 PERROR("sigaction");
757 retval = -1;
758 goto end;
759 }
27caca78 760 ret = sigaction(SIGINT, &act, NULL);
25c1285e
MD
761 if (ret) {
762 PERROR("sigaction");
763 retval = -1;
764 goto end;
765 }
27caca78
MD
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);
768 retval = -1;
769 goto end;
770 }
771 handle[0] = create_kernel_handle(&ptrace_ctx);
772 if (!handle[0]) {
773 retval = -1;
774 goto end_kernel_handle;
775 }
776 handle[1] = create_ust_handle(&ptrace_ctx);
777 if (!handle[1]) {
778 retval = -1;
779 goto end_ust_handle;
780 }
781 if (create_channels(&ptrace_ctx, LTTNG_DOMAIN_KERNEL) < 0) {
782 retval = -1;
783 goto end_wait_on_children;
784 }
785 if (create_channels(&ptrace_ctx, LTTNG_DOMAIN_UST) < 0) {
786 retval = -1;
787 goto end_wait_on_children;
788 }
789 if (enable_syscalls(&ptrace_ctx) < 0) {
790 retval = -1;
791 goto end_wait_on_children;
792 }
793 if (add_contexts(&ptrace_ctx, LTTNG_DOMAIN_KERNEL) < 0) {
794 retval = -1;
795 goto end_wait_on_children;
796 }
797 if (add_contexts(&ptrace_ctx, LTTNG_DOMAIN_UST) < 0) {
798 retval = -1;
799 goto end_wait_on_children;
800 }
801 if (lttng_trace_untrack_all(handle, NR_HANDLES) < 0) {
802 retval = -1;
803 goto end_wait_on_children;
804 }
805 fprintf(stderr, "%sTracing session `%s` created. It can be customized using the `lttng` command.\n", MESSAGE_PREFIX, ptrace_ctx.session_name);
806 if (!opt_no_pause) {
c65c49ac 807 fprintf(stderr, "%sPress <ENTER> key when ready to run the child process.\n", MESSAGE_PREFIX);
27caca78
MD
808 getchar();
809 }
810
811 if (start_session(&ptrace_ctx) < 0) {
812 retval = -1;
813 goto end_wait_on_children;
814 }
815
816 //TODO: signal off before we can forward it.
817 pid = run_child(argc - skip_args, argv + skip_args);
818 if (pid <= 0) {
819 retval = -1;
820 goto end;
821 }
822
823 sigfwd_pid = pid;
824 //TODO signals on
825
826 ret = wait_on_children(pid, handle, NR_HANDLES);
827 if (ret) {
828 retval = -1;
829 goto end_wait_on_children;
830 }
831
832
833end_wait_on_children:
834 lttng_destroy_handle(handle[1]);
835end_ust_handle:
836 lttng_destroy_handle(handle[0]);
837end_kernel_handle:
25c1285e
MD
838 if (destroy_session(&ptrace_ctx)) {
839 ERR("Error destroying session");
840 retval = -1;
841 }
27caca78
MD
842end:
843 if (retval) {
844 return EXIT_FAILURE;
845 } else {
846 fprintf(stderr, "%sSub-process hierarchy traced successfully. View trace with `babeltrace2 %s`.\n", MESSAGE_PREFIX,
847 ptrace_ctx.path);
848 if (opt_view) {
849 return execlp("babeltrace2", "babeltrace2", ptrace_ctx.path, NULL);
850 }
851 return EXIT_SUCCESS;
852 }
853 return 0;
854}
This page took 0.05492 seconds and 4 git commands to generate.