proc.c revision 75dcf7d73b6c19f7aeb932e4cb5e251b316a6c69
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 trace_set_options(proc, pid); 67 continue_process(pid); 68 proc->breakpoints_enabled = 1; 69} 70 71void 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 96static 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 103Process * 104pid2proc(pid_t pid) { 105 return each_process(NULL, &find_proc, (void *)(uintptr_t)pid); 106} 107 108 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} 126 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 144void 145add_process(Process * proc) 146{ 147 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; 171} 172 173static 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 190void 191remove_process(Process *proc) 192{ 193 Process *tmp, *tmp2; 194 195 debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid); 196 197 if (proc->leader == proc) 198 each_task(proc, &clear_leader, NULL); 199 200 if (list_of_processes == proc) { 201 tmp = list_of_processes; 202 list_of_processes = list_of_processes->next; 203 delete_events_for(tmp); 204 free(tmp); 205 return; 206 } 207 tmp = list_of_processes; 208 while (tmp->next) { 209 if (tmp->next == proc) { 210 tmp2 = tmp->next; 211 tmp->next = tmp->next->next; 212 delete_events_for(tmp2); 213 free(tmp2); 214 return; 215 } 216 tmp = tmp->next; 217 } 218} 219 220void 221install_event_handler(Process * proc, Event_Handler * handler) 222{ 223 debug(DEBUG_FUNCTION, "install_event_handler(pid=%d, %p)", proc->pid, handler); 224 assert(proc->event_handler == NULL); 225 proc->event_handler = handler; 226} 227 228void 229destroy_event_handler(Process * proc) 230{ 231 Event_Handler * handler = proc->event_handler; 232 debug(DEBUG_FUNCTION, "destroy_event_handler(pid=%d, %p)", proc->pid, handler); 233 assert(handler != NULL); 234 handler->destroy(handler); 235 free(handler); 236 proc->event_handler = NULL; 237} 238