blob: f896bac68fd0a8539b6d20e7946f3d1d42fc5546 [file] [log] [blame]
Joe Damatoab3b72c2010-10-31 00:21:53 -07001#include "config.h"
2
3#if defined(HAVE_LIBUNWIND)
4#include <libunwind.h>
5#include <libunwind-ptrace.h>
6#endif /* defined(HAVE_LIBUNWIND) */
7
Juan Cespedes273ea6d1998-03-14 23:02:40 +01008#include <sys/types.h>
9#include <string.h>
10#include <stdio.h>
11#include <errno.h>
12#include <stdlib.h>
Petr Machata1b17dbf2011-07-08 19:22:52 +020013#include <assert.h>
Juan Cespedes273ea6d1998-03-14 23:02:40 +010014
Juan Cespedesf7281232009-06-25 16:11:21 +020015#include "common.h"
Juan Cespedes273ea6d1998-03-14 23:02:40 +010016
Juan Cespedesa8909f72009-04-28 20:02:41 +020017Process *
Petr Machatac7585b62011-07-08 22:58:12 +020018open_program(char *filename, pid_t pid, int enable) {
Juan Cespedesa8909f72009-04-28 20:02:41 +020019 Process *proc;
Petr Machata1b17dbf2011-07-08 19:22:52 +020020 assert(pid != 0);
Juan Cespedesa8909f72009-04-28 20:02:41 +020021 proc = calloc(sizeof(Process), 1);
Juan Cespedes273ea6d1998-03-14 23:02:40 +010022 if (!proc) {
23 perror("malloc");
24 exit(1);
25 }
Juan Cespedese0660df2009-05-21 18:14:39 +020026 proc->filename = strdup(filename);
Juan Cespedes273ea6d1998-03-14 23:02:40 +010027 proc->breakpoints_enabled = -1;
Petr Machata1b17dbf2011-07-08 19:22:52 +020028 proc->pid = pid;
Joe Damatoab3b72c2010-10-31 00:21:53 -070029#if defined(HAVE_LIBUNWIND)
Petr Machata1b17dbf2011-07-08 19:22:52 +020030 proc->unwind_priv = _UPT_create(pid);
31 proc->unwind_as = unw_create_addr_space(&_UPT_accessors, 0);
Joe Damatoab3b72c2010-10-31 00:21:53 -070032#endif /* defined(HAVE_LIBUNWIND) */
Joe Damatoab3b72c2010-10-31 00:21:53 -070033
Petr Machatacebb8842011-07-09 11:14:11 +020034 add_process(proc);
Petr Machata9a5420c2011-07-09 11:21:23 +020035 assert(proc->leader != NULL);
Juan Cespedes273ea6d1998-03-14 23:02:40 +010036
Petr Machata9a5420c2011-07-09 11:21:23 +020037 if (proc->leader == proc)
38 breakpoints_init(proc, enable);
Joe Damatoab3b72c2010-10-31 00:21:53 -070039
Juan Cespedes273ea6d1998-03-14 23:02:40 +010040 return proc;
41}
42
Petr Machata9a5420c2011-07-09 11:21:23 +020043static void
44open_one_pid(pid_t pid)
45{
Juan Cespedesa8909f72009-04-28 20:02:41 +020046 Process *proc;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010047 char *filename;
Petr Machata9a5420c2011-07-09 11:21:23 +020048 debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid);
49
Juan Cespedes273ea6d1998-03-14 23:02:40 +010050
Ian Wienand2d45b1a2006-02-20 22:48:07 +010051 if (trace_pid(pid) < 0) {
52 fprintf(stderr, "Cannot attach to pid %u: %s\n", pid,
53 strerror(errno));
Juan Cespedes35d70631998-03-15 14:05:40 +010054 return;
55 }
56
Juan Cespedes273ea6d1998-03-14 23:02:40 +010057 filename = pid2name(pid);
58
59 if (!filename) {
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020060 fprintf(stderr, "Cannot trace pid %u: %s\n", pid,
Ian Wienand2d45b1a2006-02-20 22:48:07 +010061 strerror(errno));
Juan Cespedes273ea6d1998-03-14 23:02:40 +010062 return;
63 }
Juan Cespedes273ea6d1998-03-14 23:02:40 +010064
Petr Machatac7585b62011-07-08 22:58:12 +020065 proc = open_program(filename, pid, 1);
Petr Machata602330f2011-07-09 11:15:34 +020066 trace_set_options(proc, pid);
Juan Cespedesaee09312007-08-31 18:49:48 +020067 continue_process(pid);
Ian Wienand9a2ad352006-02-20 22:44:45 +010068 proc->breakpoints_enabled = 1;
Juan Cespedes273ea6d1998-03-14 23:02:40 +010069}
Juan Cespedese74c80d2009-02-11 11:32:31 +010070
Petr Machata9a5420c2011-07-09 11:21:23 +020071void
72open_pid(pid_t pid)
73{
74 debug(DEBUG_PROCESS, "open_pid(pid=%d)", pid);
75 pid_t *tasks;
76 size_t ntasks;
77 int should_free = 1;
78 if (process_tasks(pid, &tasks, &ntasks) < 0) {
79 fprintf(stderr, "Cannot obtain tasks of pid %u: %s\n", pid,
80 strerror(errno));
81
82 // Attach at least this one.
83 tasks = &pid;
84 ntasks = 1;
85 should_free = 0;
86 }
87
88 size_t i;
89 for (i = 0; i < ntasks; ++i)
90 open_one_pid(tasks[i]);
91
92 if (should_free)
93 free(tasks);
94}
95
Petr Machatacebb8842011-07-09 11:14:11 +020096static enum pcb_status
97find_proc(Process * proc, void * data)
98{
99 pid_t pid = (pid_t)(uintptr_t)data;
100 return proc->pid == pid ? pcb_stop : pcb_cont;
101}
102
Juan Cespedesa8909f72009-04-28 20:02:41 +0200103Process *
Juan Cespedese74c80d2009-02-11 11:32:31 +0100104pid2proc(pid_t pid) {
Petr Machatacebb8842011-07-09 11:14:11 +0200105 return each_process(NULL, &find_proc, (void *)(uintptr_t)pid);
106}
Juan Cespedese74c80d2009-02-11 11:32:31 +0100107
Petr Machatacebb8842011-07-09 11:14:11 +0200108
109static Process * list_of_processes = NULL;
110
111Process *
112each_process(Process * proc,
113 enum pcb_status (* cb)(Process * proc, void * data),
114 void * data)
115{
116 Process * it = proc ?: list_of_processes;
117 for (; it != NULL; ) {
118 /* Callback might call remove_process. */
119 Process * next = it->next;
120 if ((*cb) (it, data) == pcb_stop)
121 return it;
122 it = next;
123 }
124 return NULL;
125}
Petr Machata9a5420c2011-07-09 11:21:23 +0200126
127Process *
128each_task(Process * it, enum pcb_status (* cb)(Process * proc, void * data),
129 void * data)
130{
131 if (it != NULL) {
132 Process * leader = it->leader;
133 for (; it != NULL && it->leader == leader; ) {
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 }
141 return NULL;
142}
143
Petr Machatacebb8842011-07-09 11:14:11 +0200144void
145add_process(Process * proc)
146{
Petr Machata9a5420c2011-07-09 11:21:23 +0200147 Process ** leaderp = &list_of_processes;
148 if (proc->pid) {
149 pid_t tgid = process_leader(proc->pid);
150 if (tgid == proc->pid)
151 proc->leader = proc;
152 else {
153 Process * leader = pid2proc(tgid);
154 proc->leader = leader;
155 if (leader != NULL)
156 // NULL: sub-task added before leader?
157 leaderp = &leader->next;
158 }
159 }
160 proc->next = *leaderp;
161 *leaderp = proc;
162}
163
164static enum pcb_status
165clear_leader(Process * proc, void * data)
166{
167 debug(DEBUG_FUNCTION, "detach_task %d from leader %d",
168 proc->pid, proc->leader->pid);
169 proc->leader = NULL;
170 return pcb_cont;
Petr Machatacebb8842011-07-09 11:14:11 +0200171}
172
Petr Machata69a03e62011-07-09 11:29:12 +0200173static enum ecb_status
174event_for_proc(Event * event, void * data)
175{
176 if (event->proc == data)
177 return ecb_deque;
178 else
179 return ecb_cont;
180}
181
182static void
183delete_events_for(Process * proc)
184{
185 Event * event;
186 while ((event = each_qd_event(&event_for_proc, proc)) != NULL)
187 free(event);
188}
189
Petr Machatacebb8842011-07-09 11:14:11 +0200190void
191remove_process(Process *proc)
192{
193 Process *tmp, *tmp2;
194
195 debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
196
Petr Machata9a5420c2011-07-09 11:21:23 +0200197 if (proc->leader == proc)
198 each_task(proc, &clear_leader, NULL);
199
Petr Machatacebb8842011-07-09 11:14:11 +0200200 if (list_of_processes == proc) {
201 tmp = list_of_processes;
202 list_of_processes = list_of_processes->next;
Petr Machata69a03e62011-07-09 11:29:12 +0200203 delete_events_for(tmp);
Petr Machatacebb8842011-07-09 11:14:11 +0200204 free(tmp);
205 return;
206 }
Juan Cespedese74c80d2009-02-11 11:32:31 +0100207 tmp = list_of_processes;
Petr Machatacebb8842011-07-09 11:14:11 +0200208 while (tmp->next) {
209 if (tmp->next == proc) {
210 tmp2 = tmp->next;
211 tmp->next = tmp->next->next;
Petr Machata69a03e62011-07-09 11:29:12 +0200212 delete_events_for(tmp2);
Petr Machatacebb8842011-07-09 11:14:11 +0200213 free(tmp2);
214 return;
Juan Cespedese74c80d2009-02-11 11:32:31 +0100215 }
216 tmp = tmp->next;
217 }
Juan Cespedese74c80d2009-02-11 11:32:31 +0100218}
Petr Machata4007d742011-07-09 11:29:42 +0200219
220void
221install_event_handler(Process * proc, Event_Handler * handler)
222{
223 assert(proc->event_handler == NULL);
224 proc->event_handler = handler;
225}
226
227void
228destroy_event_handler(Process * proc)
229{
230 Event_Handler * handler = proc->event_handler;
231 assert(handler != NULL);
232 handler->destroy(handler);
233 free(handler);
234 proc->event_handler = NULL;
235}