blob: fae6595c6772f0e7b99b5c8906fac37f0d8111ba [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);
Juan Cespedesaee09312007-08-31 18:49:48 +020066 continue_process(pid);
Ian Wienand9a2ad352006-02-20 22:44:45 +010067 proc->breakpoints_enabled = 1;
Juan Cespedes273ea6d1998-03-14 23:02:40 +010068}
Juan Cespedese74c80d2009-02-11 11:32:31 +010069
Petr Machata9a5420c2011-07-09 11:21:23 +020070void
71open_pid(pid_t pid)
72{
73 debug(DEBUG_PROCESS, "open_pid(pid=%d)", pid);
74 pid_t *tasks;
75 size_t ntasks;
76 int should_free = 1;
77 if (process_tasks(pid, &tasks, &ntasks) < 0) {
78 fprintf(stderr, "Cannot obtain tasks of pid %u: %s\n", pid,
79 strerror(errno));
80
81 // Attach at least this one.
82 tasks = &pid;
83 ntasks = 1;
84 should_free = 0;
85 }
86
87 size_t i;
88 for (i = 0; i < ntasks; ++i)
89 open_one_pid(tasks[i]);
90
91 if (should_free)
92 free(tasks);
93}
94
Petr Machatacebb8842011-07-09 11:14:11 +020095static enum pcb_status
96find_proc(Process * proc, void * data)
97{
98 pid_t pid = (pid_t)(uintptr_t)data;
99 return proc->pid == pid ? pcb_stop : pcb_cont;
100}
101
Juan Cespedesa8909f72009-04-28 20:02:41 +0200102Process *
Juan Cespedese74c80d2009-02-11 11:32:31 +0100103pid2proc(pid_t pid) {
Petr Machatacebb8842011-07-09 11:14:11 +0200104 return each_process(NULL, &find_proc, (void *)(uintptr_t)pid);
105}
Juan Cespedese74c80d2009-02-11 11:32:31 +0100106
Petr Machatacebb8842011-07-09 11:14:11 +0200107
108static Process * list_of_processes = NULL;
109
110Process *
111each_process(Process * proc,
112 enum pcb_status (* cb)(Process * proc, void * data),
113 void * data)
114{
115 Process * it = proc ?: list_of_processes;
116 for (; it != NULL; ) {
117 /* Callback might call remove_process. */
118 Process * next = it->next;
119 if ((*cb) (it, data) == pcb_stop)
120 return it;
121 it = next;
122 }
123 return NULL;
124}
Petr Machata9a5420c2011-07-09 11:21:23 +0200125
126Process *
127each_task(Process * it, enum pcb_status (* cb)(Process * proc, void * data),
128 void * data)
129{
130 if (it != NULL) {
131 Process * leader = it->leader;
132 for (; it != NULL && it->leader == leader; ) {
133 /* Callback might call remove_process. */
134 Process * next = it->next;
135 if ((*cb) (it, data) == pcb_stop)
136 return it;
137 it = next;
138 }
139 }
140 return NULL;
141}
142
Petr Machatacebb8842011-07-09 11:14:11 +0200143void
144add_process(Process * proc)
145{
Petr Machata9a5420c2011-07-09 11:21:23 +0200146 Process ** leaderp = &list_of_processes;
147 if (proc->pid) {
148 pid_t tgid = process_leader(proc->pid);
149 if (tgid == proc->pid)
150 proc->leader = proc;
151 else {
152 Process * leader = pid2proc(tgid);
153 proc->leader = leader;
154 if (leader != NULL)
155 // NULL: sub-task added before leader?
156 leaderp = &leader->next;
157 }
158 }
159 proc->next = *leaderp;
160 *leaderp = proc;
161}
162
163static enum pcb_status
164clear_leader(Process * proc, void * data)
165{
166 debug(DEBUG_FUNCTION, "detach_task %d from leader %d",
167 proc->pid, proc->leader->pid);
168 proc->leader = NULL;
169 return pcb_cont;
Petr Machatacebb8842011-07-09 11:14:11 +0200170}
171
Petr Machata69a03e62011-07-09 11:29:12 +0200172static enum ecb_status
173event_for_proc(Event * event, void * data)
174{
175 if (event->proc == data)
176 return ecb_deque;
177 else
178 return ecb_cont;
179}
180
181static void
182delete_events_for(Process * proc)
183{
184 Event * event;
185 while ((event = each_qd_event(&event_for_proc, proc)) != NULL)
186 free(event);
187}
188
Petr Machatacebb8842011-07-09 11:14:11 +0200189void
190remove_process(Process *proc)
191{
192 Process *tmp, *tmp2;
193
194 debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
195
Petr Machata9a5420c2011-07-09 11:21:23 +0200196 if (proc->leader == proc)
197 each_task(proc, &clear_leader, NULL);
198
Petr Machatacebb8842011-07-09 11:14:11 +0200199 if (list_of_processes == proc) {
200 tmp = list_of_processes;
201 list_of_processes = list_of_processes->next;
Petr Machata69a03e62011-07-09 11:29:12 +0200202 delete_events_for(tmp);
Petr Machatacebb8842011-07-09 11:14:11 +0200203 free(tmp);
204 return;
205 }
Juan Cespedese74c80d2009-02-11 11:32:31 +0100206 tmp = list_of_processes;
Petr Machatacebb8842011-07-09 11:14:11 +0200207 while (tmp->next) {
208 if (tmp->next == proc) {
209 tmp2 = tmp->next;
210 tmp->next = tmp->next->next;
Petr Machata69a03e62011-07-09 11:29:12 +0200211 delete_events_for(tmp2);
Petr Machatacebb8842011-07-09 11:14:11 +0200212 free(tmp2);
213 return;
Juan Cespedese74c80d2009-02-11 11:32:31 +0100214 }
215 tmp = tmp->next;
216 }
Juan Cespedese74c80d2009-02-11 11:32:31 +0100217}