proc.c revision 3c516d5ced53508d8df7d82914a3190a3235b62d
1#include "config.h"
2
3#if defined(HAVE_LIBUNWIND)
4#include <libunwind.h>
5#include <libunwind-ptrace.h>
6#endif /* defined(HAVE_LIBUNWIND) */
7
8#include <sys/types.h>
9#include <string.h>
10#include <stdio.h>
11#include <errno.h>
12#include <stdlib.h>
13#include <assert.h>
14
15#include "common.h"
16
17Process *
18open_program(char *filename, pid_t pid, int enable) {
19	Process *proc;
20	assert(pid != 0);
21	proc = calloc(sizeof(Process), 1);
22	if (!proc) {
23		perror("malloc");
24		exit(1);
25	}
26	proc->filename = strdup(filename);
27	proc->breakpoints_enabled = -1;
28	proc->pid = pid;
29#if defined(HAVE_LIBUNWIND)
30	proc->unwind_priv = _UPT_create(pid);
31	proc->unwind_as = unw_create_addr_space(&_UPT_accessors, 0);
32#endif /* defined(HAVE_LIBUNWIND) */
33
34	add_process(proc);
35	assert(proc->leader != NULL);
36
37	if (proc->leader == proc)
38		breakpoints_init(proc, enable);
39
40	return proc;
41}
42
43static int
44open_one_pid(pid_t pid)
45{
46	Process *proc;
47	char *filename;
48	debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid);
49
50	if (trace_pid(pid) < 0)
51		return 0;
52
53	filename = pid2name(pid);
54	if (filename == NULL)
55		return 0;
56
57	proc = open_program(filename, pid, 1);
58	trace_set_options(proc, pid);
59	continue_process(pid);
60	proc->breakpoints_enabled = 1;
61
62	return 1;
63}
64
65void
66open_pid(pid_t pid)
67{
68	debug(DEBUG_PROCESS, "open_pid(pid=%d)", pid);
69	/* If we are already tracing this guy, we should be seeing all
70	 * his children via normal tracing route.  */
71	if (pid2proc(pid) != NULL)
72		return;
73
74	/* First, see if we can attach the requested PID itself.  */
75	if (!open_one_pid(pid)) {
76		fprintf(stderr, "Cannot attach to pid %u: %s\n",
77			pid, strerror(errno));
78		return;
79	}
80
81	/* Now attach to all tasks that belong to that PID.  There's a
82	 * race between process_tasks and open_one_pid.  So when we
83	 * fail in open_one_pid below, we just do another round.
84	 * Chances are that by then that PID will have gone away, and
85	 * that's why we have seen the failure.  The processes that we
86	 * manage to open_one_pid are stopped, so we should eventually
87	 * reach a point where process_tasks doesn't give any new
88	 * processes (because there's nobody left to produce
89	 * them).  */
90	int have_all;
91	do {
92		pid_t *tasks;
93		size_t ntasks;
94		size_t i;
95		if (process_tasks(pid, &tasks, &ntasks) < 0) {
96			fprintf(stderr, "Cannot obtain tasks of pid %u: %s\n",
97				pid, strerror(errno));
98			return;
99		}
100
101		have_all = 1;
102		for (i = 0; i < ntasks; ++i)
103			if (pid2proc(tasks[i]) == NULL
104			    && !open_one_pid(tasks[i]))
105				have_all = 0;
106
107		free(tasks);
108
109	} while (have_all == 0);
110}
111
112static enum pcb_status
113find_proc(Process * proc, void * data)
114{
115	pid_t pid = (pid_t)(uintptr_t)data;
116	return proc->pid == pid ? pcb_stop : pcb_cont;
117}
118
119Process *
120pid2proc(pid_t pid) {
121	return each_process(NULL, &find_proc, (void *)(uintptr_t)pid);
122}
123
124
125static Process * list_of_processes = NULL;
126
127Process *
128each_process(Process * proc,
129	     enum pcb_status (* cb)(Process * proc, void * data),
130	     void * data)
131{
132	Process * it = proc ?: list_of_processes;
133	for (; it != NULL; ) {
134		/* Callback might call remove_process.  */
135		Process * next = it->next;
136		if ((*cb) (it, data) == pcb_stop)
137			return it;
138		it = next;
139	}
140	return NULL;
141}
142
143Process *
144each_task(Process * it, enum pcb_status (* cb)(Process * proc, void * data),
145	  void * data)
146{
147	if (it != NULL) {
148		Process * leader = it->leader;
149		for (; it != NULL && it->leader == leader; ) {
150			/* Callback might call remove_process.  */
151			Process * next = it->next;
152			if ((*cb) (it, data) == pcb_stop)
153				return it;
154			it = next;
155		}
156	}
157	return NULL;
158}
159
160void
161add_process(Process * proc)
162{
163	Process ** leaderp = &list_of_processes;
164	if (proc->pid) {
165		pid_t tgid = process_leader(proc->pid);
166		if (tgid == proc->pid)
167			proc->leader = proc;
168		else {
169			Process * leader = pid2proc(tgid);
170			proc->leader = leader;
171			if (leader != NULL)
172				// NULL: sub-task added before leader?
173				leaderp = &leader->next;
174		}
175	}
176	proc->next = *leaderp;
177	*leaderp = proc;
178}
179
180static enum pcb_status
181clear_leader(Process * proc, void * data)
182{
183	debug(DEBUG_FUNCTION, "detach_task %d from leader %d",
184	      proc->pid, proc->leader->pid);
185	proc->leader = NULL;
186	return pcb_cont;
187}
188
189static enum ecb_status
190event_for_proc(Event * event, void * data)
191{
192	if (event->proc == data)
193		return ecb_deque;
194	else
195		return ecb_cont;
196}
197
198static void
199delete_events_for(Process * proc)
200{
201	Event * event;
202	while ((event = each_qd_event(&event_for_proc, proc)) != NULL)
203		free(event);
204}
205
206void
207remove_process(Process *proc)
208{
209	Process *tmp, *tmp2;
210
211	debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
212
213	if (proc->leader == proc)
214		each_task(proc, &clear_leader, NULL);
215
216	if (list_of_processes == proc) {
217		tmp = list_of_processes;
218		list_of_processes = list_of_processes->next;
219		delete_events_for(tmp);
220		free(tmp);
221		return;
222	}
223	tmp = list_of_processes;
224	while (tmp->next) {
225		if (tmp->next == proc) {
226			tmp2 = tmp->next;
227			tmp->next = tmp->next->next;
228			delete_events_for(tmp2);
229			free(tmp2);
230			return;
231		}
232		tmp = tmp->next;
233	}
234}
235
236void
237install_event_handler(Process * proc, Event_Handler * handler)
238{
239	debug(DEBUG_FUNCTION, "install_event_handler(pid=%d, %p)", proc->pid, handler);
240	assert(proc->event_handler == NULL);
241	proc->event_handler = handler;
242}
243
244void
245destroy_event_handler(Process * proc)
246{
247	Event_Handler * handler = proc->event_handler;
248	debug(DEBUG_FUNCTION, "destroy_event_handler(pid=%d, %p)", proc->pid, handler);
249	assert(handler != NULL);
250	handler->destroy(handler);
251	free(handler);
252	proc->event_handler = NULL;
253}
254