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