blob: 8020c6e4a02b5190b500070fe660584b42b9bc20 [file] [log] [blame]
Juan Cespedesf7281232009-06-25 16:11:21 +02001#include "config.h"
Juan Cespedesf7281232009-06-25 16:11:21 +02002
Petr Machata3ed2a422012-04-06 17:18:55 +02003#include <sys/param.h>
4#include <sys/wait.h>
5#include <errno.h>
6#include <error.h>
7#include <signal.h>
Juan Cespedesf7281232009-06-25 16:11:21 +02008#include <stdio.h>
9#include <stdlib.h>
Juan Cespedesf7281232009-06-25 16:11:21 +020010#include <string.h>
Petr Machata3ed2a422012-04-06 17:18:55 +020011#include <unistd.h>
Juan Cespedesf7281232009-06-25 16:11:21 +020012
13#include "common.h"
Petr Machata366c2f42012-02-09 19:34:36 +010014#include "proc.h"
Juan Cespedesf7281232009-06-25 16:11:21 +020015
16char *command = NULL;
Juan Cespedesf7281232009-06-25 16:11:21 +020017
18int exiting = 0; /* =1 if a SIGINT or SIGTERM has been received */
19
Petr Machata2b46cfc2012-02-18 11:17:29 +010020static enum callback_status
21stop_non_p_processes(Process *proc, void *data)
Petr Machatacebb8842011-07-09 11:14:11 +020022{
23 int stop = 1;
24
25 struct opt_p_t *it;
26 for (it = opt_p; it != NULL; it = it->next) {
27 Process * p_proc = pid2proc(it->pid);
28 if (p_proc == NULL) {
29 printf("stop_non_p_processes: %d terminated?\n", it->pid);
30 continue;
31 }
Petr Machata9a5420c2011-07-09 11:21:23 +020032 if (p_proc == proc || p_proc->leader == proc->leader) {
Petr Machatacebb8842011-07-09 11:14:11 +020033 stop = 0;
34 break;
35 }
36 }
37
38 if (stop) {
39 debug(2, "Sending SIGSTOP to process %u", proc->pid);
40 kill(proc->pid, SIGSTOP);
41 }
42
Petr Machata2b46cfc2012-02-18 11:17:29 +010043 return CBS_CONT;
Petr Machatacebb8842011-07-09 11:14:11 +020044}
45
Juan Cespedesf7281232009-06-25 16:11:21 +020046static void
47signal_alarm(int sig) {
Juan Cespedesf7281232009-06-25 16:11:21 +020048 signal(SIGALRM, SIG_DFL);
Petr Machatacebb8842011-07-09 11:14:11 +020049 each_process(NULL, &stop_non_p_processes, NULL);
Juan Cespedesf7281232009-06-25 16:11:21 +020050}
51
52static void
Petr Machataffe4cd22012-04-11 18:01:44 +020053signal_exit(int sig)
54{
Juan Cespedesf7281232009-06-25 16:11:21 +020055 debug(1, "Received interrupt signal; exiting...");
Petr Machataffe4cd22012-04-11 18:01:44 +020056 if (exiting != 0)
57 return;
58
59 exiting = 1 + !!os_ltrace_exiting_sighandler();
60
Juan Cespedesf7281232009-06-25 16:11:21 +020061 signal(SIGINT, SIG_IGN);
62 signal(SIGTERM, SIG_IGN);
63 signal(SIGALRM, signal_alarm);
Petr Machata602330f2011-07-09 11:15:34 +020064 //alarm(1);
Juan Cespedesf7281232009-06-25 16:11:21 +020065}
66
67static void
68normal_exit(void) {
69 output_line(0, 0);
70 if (options.summary) {
71 show_summary();
72 }
73 if (options.output) {
74 fclose(options.output);
75 options.output = NULL;
76 }
77}
78
79void
80ltrace_init(int argc, char **argv) {
81 struct opt_p_t *opt_p_tmp;
82
83 atexit(normal_exit);
84 signal(SIGINT, signal_exit); /* Detach processes when interrupted */
85 signal(SIGTERM, signal_exit); /* ... or killed */
86
87 argv = process_options(argc, argv);
88 while (opt_F) {
89 /* If filename begins with ~, expand it to the user's home */
90 /* directory. This does not correctly handle ~yoda, but that */
91 /* isn't as bad as it seems because the shell will normally */
92 /* be doing the expansion for us; only the hardcoded */
93 /* ~/.ltrace.conf should ever use this code. */
94 if (opt_F->filename[0] == '~') {
95 char path[PATH_MAX];
96 char *home_dir = getenv("HOME");
97 if (home_dir) {
98 strncpy(path, home_dir, PATH_MAX - 1);
99 path[PATH_MAX - 1] = '\0';
100 strncat(path, opt_F->filename + 1,
101 PATH_MAX - strlen(path) - 1);
102 read_config_file(path);
103 }
104 } else {
105 read_config_file(opt_F->filename);
106 }
107 opt_F = opt_F->next;
108 }
Juan Cespedesf7281232009-06-25 16:11:21 +0200109 if (command) {
Petr Machata02bd9ec2011-09-21 17:38:59 +0200110 /* Check that the binary ABI is supported before
111 * calling execute_program. */
112 struct ltelf lte = {};
113 open_elf(&lte, command);
114
Petr Machatac805c622012-03-02 00:10:37 +0100115 pid_t pid = execute_program(command, argv);
Petr Machata75934ad2012-04-14 02:28:03 +0200116 struct Process *proc = open_program(command, pid);
Petr Machata3ed2a422012-04-06 17:18:55 +0200117 if (proc == NULL)
118 error(EXIT_FAILURE, errno,
119 "couldn't open program '%s'", command);
Petr Machata79a47ba2012-04-06 19:54:55 +0200120
121 trace_set_options(proc);
Petr Machatac805c622012-03-02 00:10:37 +0100122 continue_process(pid);
Juan Cespedesf7281232009-06-25 16:11:21 +0200123 }
124 opt_p_tmp = opt_p;
125 while (opt_p_tmp) {
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200126 open_pid(opt_p_tmp->pid);
Juan Cespedesf7281232009-06-25 16:11:21 +0200127 opt_p_tmp = opt_p_tmp->next;
128 }
129}
130
Juan Cespedes61da3372009-07-03 11:55:44 +0200131static int num_ltrace_callbacks[EVENT_MAX];
132static callback_func * ltrace_callbacks[EVENT_MAX];
Juan Cespedes40dc6352009-06-25 19:54:10 +0200133
134void
Juan Cespedes61da3372009-07-03 11:55:44 +0200135ltrace_add_callback(callback_func func, Event_type type) {
136 ltrace_callbacks[type] = realloc(ltrace_callbacks[type], (num_ltrace_callbacks[type]+1)*sizeof(callback_func));
137 ltrace_callbacks[type][num_ltrace_callbacks[type]++] = func;
138}
Juan Cespedes40dc6352009-06-25 19:54:10 +0200139
Juan Cespedes61da3372009-07-03 11:55:44 +0200140static void
141dispatch_callbacks(Event * ev) {
142 int i;
143 /* Ignoring case 1: signal into a dying tracer */
144 if (ev->type==EVENT_SIGNAL &&
145 exiting && ev->e_un.signum == SIGSTOP) {
146 return;
147 }
148 /* Ignoring case 2: process being born before a clone event */
149 if (ev->proc && ev->proc->state == STATE_IGNORED) {
150 return;
151 }
152 for (i=0; i<num_ltrace_callbacks[ev->type]; i++) {
153 ltrace_callbacks[ev->type][i](ev);
Juan Cespedes40dc6352009-06-25 19:54:10 +0200154 }
155}
156
Juan Cespedesf7281232009-06-25 16:11:21 +0200157void
158ltrace_main(void) {
Juan Cespedes40dc6352009-06-25 19:54:10 +0200159 Event * ev;
Juan Cespedesf7281232009-06-25 16:11:21 +0200160 while (1) {
Juan Cespedes40dc6352009-06-25 19:54:10 +0200161 ev = next_event();
Juan Cespedes61da3372009-07-03 11:55:44 +0200162 dispatch_callbacks(ev);
Juan Cespedes03192f82009-07-03 10:16:22 +0200163 handle_event(ev);
Juan Cespedesf7281232009-06-25 16:11:21 +0200164 }
165}