proc.c revision 69a03e6f8c15fb0272089e387a658acad887fb9c
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 void 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 51 if (trace_pid(pid) < 0) { 52 fprintf(stderr, "Cannot attach to pid %u: %s\n", pid, 53 strerror(errno)); 54 return; 55 } 56 57 filename = pid2name(pid); 58 59 if (!filename) { 60 fprintf(stderr, "Cannot trace pid %u: %s\n", pid, 61 strerror(errno)); 62 return; 63 } 64 65 proc = open_program(filename, pid, 1); 66 continue_process(pid); 67 proc->breakpoints_enabled = 1; 68} 69 70void 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 95static 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 102Process * 103pid2proc(pid_t pid) { 104 return each_process(NULL, &find_proc, (void *)(uintptr_t)pid); 105} 106 107 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} 125 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 143void 144add_process(Process * proc) 145{ 146 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; 170} 171 172static 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 189void 190remove_process(Process *proc) 191{ 192 Process *tmp, *tmp2; 193 194 debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid); 195 196 if (proc->leader == proc) 197 each_task(proc, &clear_leader, NULL); 198 199 if (list_of_processes == proc) { 200 tmp = list_of_processes; 201 list_of_processes = list_of_processes->next; 202 delete_events_for(tmp); 203 free(tmp); 204 return; 205 } 206 tmp = list_of_processes; 207 while (tmp->next) { 208 if (tmp->next == proc) { 209 tmp2 = tmp->next; 210 tmp->next = tmp->next->next; 211 delete_events_for(tmp2); 212 free(tmp2); 213 return; 214 } 215 tmp = tmp->next; 216 } 217} 218