blob: 22959015fccafb3362c460c61345f82a7d355f8d [file] [log] [blame]
Juan Cespedesf7281232009-06-25 16:11:21 +02001#include "config.h"
Juan Cespedesf7281232009-06-25 16:11:21 +02002
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <string.h>
7#include <errno.h>
8#include <sys/param.h>
9#include <signal.h>
10#include <sys/wait.h>
11
12#include "common.h"
Petr Machata366c2f42012-02-09 19:34:36 +010013#include "proc.h"
Juan Cespedesf7281232009-06-25 16:11:21 +020014
15char *command = NULL;
Juan Cespedesf7281232009-06-25 16:11:21 +020016
17int exiting = 0; /* =1 if a SIGINT or SIGTERM has been received */
18
Petr Machata2b46cfc2012-02-18 11:17:29 +010019static enum callback_status
20stop_non_p_processes(Process *proc, void *data)
Petr Machatacebb8842011-07-09 11:14:11 +020021{
22 int stop = 1;
23
24 struct opt_p_t *it;
25 for (it = opt_p; it != NULL; it = it->next) {
26 Process * p_proc = pid2proc(it->pid);
27 if (p_proc == NULL) {
28 printf("stop_non_p_processes: %d terminated?\n", it->pid);
29 continue;
30 }
Petr Machata9a5420c2011-07-09 11:21:23 +020031 if (p_proc == proc || p_proc->leader == proc->leader) {
Petr Machatacebb8842011-07-09 11:14:11 +020032 stop = 0;
33 break;
34 }
35 }
36
37 if (stop) {
38 debug(2, "Sending SIGSTOP to process %u", proc->pid);
39 kill(proc->pid, SIGSTOP);
40 }
41
Petr Machata2b46cfc2012-02-18 11:17:29 +010042 return CBS_CONT;
Petr Machatacebb8842011-07-09 11:14:11 +020043}
44
Juan Cespedesf7281232009-06-25 16:11:21 +020045static void
46signal_alarm(int sig) {
Juan Cespedesf7281232009-06-25 16:11:21 +020047 signal(SIGALRM, SIG_DFL);
Petr Machatacebb8842011-07-09 11:14:11 +020048 each_process(NULL, &stop_non_p_processes, NULL);
Juan Cespedesf7281232009-06-25 16:11:21 +020049}
50
51static void
Petr Machataffe4cd22012-04-11 18:01:44 +020052signal_exit(int sig)
53{
Juan Cespedesf7281232009-06-25 16:11:21 +020054 debug(1, "Received interrupt signal; exiting...");
Petr Machataffe4cd22012-04-11 18:01:44 +020055 if (exiting != 0)
56 return;
57
58 exiting = 1 + !!os_ltrace_exiting_sighandler();
59
Juan Cespedesf7281232009-06-25 16:11:21 +020060 signal(SIGINT, SIG_IGN);
61 signal(SIGTERM, SIG_IGN);
62 signal(SIGALRM, signal_alarm);
Petr Machata602330f2011-07-09 11:15:34 +020063 //alarm(1);
Juan Cespedesf7281232009-06-25 16:11:21 +020064}
65
66static void
67normal_exit(void) {
68 output_line(0, 0);
69 if (options.summary) {
70 show_summary();
71 }
72 if (options.output) {
73 fclose(options.output);
74 options.output = NULL;
75 }
76}
77
78void
79ltrace_init(int argc, char **argv) {
80 struct opt_p_t *opt_p_tmp;
81
82 atexit(normal_exit);
83 signal(SIGINT, signal_exit); /* Detach processes when interrupted */
84 signal(SIGTERM, signal_exit); /* ... or killed */
85
86 argv = process_options(argc, argv);
87 while (opt_F) {
88 /* If filename begins with ~, expand it to the user's home */
89 /* directory. This does not correctly handle ~yoda, but that */
90 /* isn't as bad as it seems because the shell will normally */
91 /* be doing the expansion for us; only the hardcoded */
92 /* ~/.ltrace.conf should ever use this code. */
93 if (opt_F->filename[0] == '~') {
94 char path[PATH_MAX];
95 char *home_dir = getenv("HOME");
96 if (home_dir) {
97 strncpy(path, home_dir, PATH_MAX - 1);
98 path[PATH_MAX - 1] = '\0';
99 strncat(path, opt_F->filename + 1,
100 PATH_MAX - strlen(path) - 1);
101 read_config_file(path);
102 }
103 } else {
104 read_config_file(opt_F->filename);
105 }
106 opt_F = opt_F->next;
107 }
108 if (opt_e) {
109 struct opt_e_t *tmp = opt_e;
110 while (tmp) {
111 debug(1, "Option -e: %s\n", tmp->name);
112 tmp = tmp->next;
113 }
114 }
115 if (command) {
Petr Machata02bd9ec2011-09-21 17:38:59 +0200116 /* Check that the binary ABI is supported before
117 * calling execute_program. */
118 struct ltelf lte = {};
119 open_elf(&lte, command);
120
Petr Machatac7585b62011-07-08 22:58:12 +0200121 open_program(command, execute_program(command, argv), 0);
Juan Cespedesf7281232009-06-25 16:11:21 +0200122 }
123 opt_p_tmp = opt_p;
124 while (opt_p_tmp) {
Juan Cespedes8d1b92b2009-07-03 10:39:34 +0200125 open_pid(opt_p_tmp->pid);
Juan Cespedesf7281232009-06-25 16:11:21 +0200126 opt_p_tmp = opt_p_tmp->next;
127 }
128}
129
Juan Cespedes61da3372009-07-03 11:55:44 +0200130static int num_ltrace_callbacks[EVENT_MAX];
131static callback_func * ltrace_callbacks[EVENT_MAX];
Juan Cespedes40dc6352009-06-25 19:54:10 +0200132
133void
Juan Cespedes61da3372009-07-03 11:55:44 +0200134ltrace_add_callback(callback_func func, Event_type type) {
135 ltrace_callbacks[type] = realloc(ltrace_callbacks[type], (num_ltrace_callbacks[type]+1)*sizeof(callback_func));
136 ltrace_callbacks[type][num_ltrace_callbacks[type]++] = func;
137}
Juan Cespedes40dc6352009-06-25 19:54:10 +0200138
Juan Cespedes61da3372009-07-03 11:55:44 +0200139static void
140dispatch_callbacks(Event * ev) {
141 int i;
142 /* Ignoring case 1: signal into a dying tracer */
143 if (ev->type==EVENT_SIGNAL &&
144 exiting && ev->e_un.signum == SIGSTOP) {
145 return;
146 }
147 /* Ignoring case 2: process being born before a clone event */
148 if (ev->proc && ev->proc->state == STATE_IGNORED) {
149 return;
150 }
151 for (i=0; i<num_ltrace_callbacks[ev->type]; i++) {
152 ltrace_callbacks[ev->type][i](ev);
Juan Cespedes40dc6352009-06-25 19:54:10 +0200153 }
154}
155
Juan Cespedesf7281232009-06-25 16:11:21 +0200156void
157ltrace_main(void) {
Juan Cespedes40dc6352009-06-25 19:54:10 +0200158 Event * ev;
Juan Cespedesf7281232009-06-25 16:11:21 +0200159 while (1) {
Juan Cespedes40dc6352009-06-25 19:54:10 +0200160 ev = next_event();
Juan Cespedes61da3372009-07-03 11:55:44 +0200161 dispatch_callbacks(ev);
Juan Cespedes03192f82009-07-03 10:16:22 +0200162 handle_event(ev);
Juan Cespedesf7281232009-06-25 16:11:21 +0200163 }
164}