proc.c revision 9294d82f67e20f5f2b61f317ad04f5cb717c7d27
1#define _GNU_SOURCE /* For getline. */ 2#include "config.h" 3#include "common.h" 4 5#include <sys/types.h> 6#include <sys/stat.h> 7#include <fcntl.h> 8#include <inttypes.h> 9#include <link.h> 10#include <stdio.h> 11#include <string.h> 12#include <signal.h> 13#include <unistd.h> 14#include <dirent.h> 15#include <ctype.h> 16#include <errno.h> 17#include <sys/syscall.h> 18#include <error.h> 19 20#include "breakpoint.h" 21 22/* /proc/pid doesn't exist just after the fork, and sometimes `ltrace' 23 * couldn't open it to find the executable. So it may be necessary to 24 * have a bit delay 25 */ 26 27#define MAX_DELAY 100000 /* 100000 microseconds = 0.1 seconds */ 28 29#define PROC_PID_FILE(VAR, FORMAT, PID) \ 30 char VAR[strlen(FORMAT) + 6]; \ 31 sprintf(VAR, FORMAT, PID) 32 33/* 34 * Returns a (malloc'd) file name corresponding to a running pid 35 */ 36char * 37pid2name(pid_t pid) { 38 if (!kill(pid, 0)) { 39 int delay = 0; 40 41 PROC_PID_FILE(proc_exe, "/proc/%d/exe", pid); 42 43 while (delay < MAX_DELAY) { 44 if (!access(proc_exe, F_OK)) { 45 return strdup(proc_exe); 46 } 47 delay += 1000; /* 1 milisecond */ 48 } 49 } 50 return NULL; 51} 52 53static FILE * 54open_status_file(pid_t pid) 55{ 56 PROC_PID_FILE(fn, "/proc/%d/status", pid); 57 /* Don't complain if we fail. This would typically happen 58 when the process is about to terminate, and these files are 59 not available anymore. This function is called from the 60 event loop, and we don't want to clutter the output just 61 because the process terminates. */ 62 return fopen(fn, "r"); 63} 64 65static char * 66find_line_starting(FILE * file, const char * prefix, size_t len) 67{ 68 char * line = NULL; 69 size_t line_len = 0; 70 while (!feof(file)) { 71 if (getline(&line, &line_len, file) < 0) 72 return NULL; 73 if (strncmp(line, prefix, len) == 0) 74 return line; 75 } 76 return NULL; 77} 78 79static void 80each_line_starting(FILE * file, const char *prefix, 81 enum pcb_status (*cb)(const char * line, const char * prefix, 82 void * data), 83 void * data) 84{ 85 size_t len = strlen(prefix); 86 char * line; 87 while ((line = find_line_starting(file, prefix, len)) != NULL) { 88 enum pcb_status st = (*cb)(line, prefix, data); 89 free (line); 90 if (st == pcb_stop) 91 return; 92 } 93} 94 95static enum pcb_status 96process_leader_cb(const char * line, const char * prefix, void * data) 97{ 98 pid_t * pidp = data; 99 *pidp = atoi(line + strlen(prefix)); 100 return pcb_stop; 101} 102 103pid_t 104process_leader(pid_t pid) 105{ 106 pid_t tgid = 0; 107 FILE * file = open_status_file(pid); 108 if (file != NULL) { 109 each_line_starting(file, "Tgid:\t", &process_leader_cb, &tgid); 110 fclose(file); 111 } 112 113 return tgid; 114} 115 116static enum pcb_status 117process_stopped_cb(const char * line, const char * prefix, void * data) 118{ 119 char c = line[strlen(prefix)]; 120 // t:tracing stop, T:job control stop 121 *(int *)data = (c == 't' || c == 'T'); 122 return pcb_stop; 123} 124 125int 126process_stopped(pid_t pid) 127{ 128 int is_stopped = -1; 129 FILE * file = open_status_file(pid); 130 if (file != NULL) { 131 each_line_starting(file, "State:\t", &process_stopped_cb, 132 &is_stopped); 133 fclose(file); 134 } 135 return is_stopped; 136} 137 138static enum pcb_status 139process_status_cb(const char * line, const char * prefix, void * data) 140{ 141 const char * status = line + strlen(prefix); 142 const char c = *status; 143 144#define RETURN(C) do { \ 145 *(enum process_status *)data = C; \ 146 return pcb_stop; \ 147 } while (0) 148 149 switch (c) { 150 case 'Z': RETURN(ps_zombie); 151 case 't': RETURN(ps_tracing_stop); 152 case 'T': 153 /* This can be either "T (stopped)" or, for older 154 * kernels, "T (tracing stop)". */ 155 if (!strcmp(status, "T (stopped)\n")) 156 RETURN(ps_stop); 157 else if (!strcmp(status, "T (tracing stop)\n")) 158 RETURN(ps_tracing_stop); 159 else { 160 fprintf(stderr, "Unknown process status: %s", 161 status); 162 RETURN(ps_stop); /* Some sort of stop 163 * anyway. */ 164 } 165 case 'D': 166 case 'S': RETURN(ps_sleeping); 167 } 168 169 RETURN(ps_other); 170#undef RETURN 171} 172 173enum process_status 174process_status(pid_t pid) 175{ 176 enum process_status ret = ps_invalid; 177 FILE * file = open_status_file(pid); 178 if (file != NULL) { 179 each_line_starting(file, "State:\t", &process_status_cb, &ret); 180 fclose(file); 181 if (ret == ps_invalid) 182 error(0, errno, "process_status %d", pid); 183 } else 184 /* If the file is not present, the process presumably 185 * exited already. */ 186 ret = ps_zombie; 187 188 return ret; 189} 190 191static int 192all_digits(const char *str) 193{ 194 while (isdigit(*str)) 195 str++; 196 return !*str; 197} 198 199int 200process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n) 201{ 202 PROC_PID_FILE(fn, "/proc/%d/task", pid); 203 DIR * d = opendir(fn); 204 if (d == NULL) 205 return -1; 206 207 pid_t *tasks = NULL; 208 size_t n = 0; 209 size_t alloc = 0; 210 211 while (1) { 212 struct dirent entry; 213 struct dirent *result; 214 if (readdir_r(d, &entry, &result) != 0) { 215 free(tasks); 216 return -1; 217 } 218 if (result == NULL) 219 break; 220 if (result->d_type == DT_DIR && all_digits(result->d_name)) { 221 pid_t npid = atoi(result->d_name); 222 if (n >= alloc) { 223 alloc = alloc > 0 ? (2 * alloc) : 8; 224 pid_t *ntasks = realloc(tasks, 225 sizeof(*tasks) * alloc); 226 if (ntasks == NULL) { 227 free(tasks); 228 return -1; 229 } 230 tasks = ntasks; 231 } 232 if (n >= alloc) 233 abort(); 234 tasks[n++] = npid; 235 } 236 } 237 238 closedir(d); 239 240 *ret_tasks = tasks; 241 *ret_n = n; 242 return 0; 243} 244 245static int 246find_dynamic_entry_addr(Process *proc, void *pvAddr, int d_tag, void **addr) { 247 int i = 0, done = 0; 248 ElfW(Dyn) entry; 249 250 debug(DEBUG_FUNCTION, "find_dynamic_entry()"); 251 252 if (addr == NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) { 253 return -1; 254 } 255 256 while ((!done) && (i < ELF_MAX_SEGMENTS) && 257 (sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) && 258 (entry.d_tag != DT_NULL)) { 259 if (entry.d_tag == d_tag) { 260 done = 1; 261 *addr = (void *)entry.d_un.d_val; 262 } 263 pvAddr += sizeof(entry); 264 i++; 265 } 266 267 if (done) { 268 debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag); 269 return 0; 270 } 271 else { 272 debug(2, "Couldn't address for dtag!\n"); 273 return -1; 274 } 275} 276 277struct cb_data { 278 const char *lib_name; 279 struct ltelf *lte; 280 ElfW(Addr) addr; 281 Process *proc; 282}; 283 284static void 285crawl_linkmap(Process *proc, struct r_debug *dbg, void (*callback)(void *), struct cb_data *data) { 286 struct link_map rlm; 287 char lib_name[BUFSIZ]; 288 struct link_map *lm = NULL; 289 290 debug (DEBUG_FUNCTION, "crawl_linkmap()"); 291 292 if (!dbg || !dbg->r_map) { 293 debug(2, "Debug structure or it's linkmap are NULL!"); 294 return; 295 } 296 297 lm = dbg->r_map; 298 299 while (lm) { 300 if (umovebytes(proc, lm, &rlm, sizeof(rlm)) != sizeof(rlm)) { 301 debug(2, "Unable to read link map\n"); 302 return; 303 } 304 305 lm = rlm.l_next; 306 if (rlm.l_name == NULL) { 307 debug(2, "Invalid library name referenced in dynamic linker map\n"); 308 return; 309 } 310 311 umovebytes(proc, rlm.l_name, lib_name, sizeof(lib_name)); 312 313 if (lib_name[0] == '\0') { 314 debug(2, "Library name is an empty string"); 315 continue; 316 } 317 318 if (callback) { 319 debug(2, "Dispatching callback for: %s, " 320 "Loaded at 0x%" PRI_ELF_ADDR "\n", 321 lib_name, rlm.l_addr); 322 data->addr = rlm.l_addr; 323 data->lib_name = lib_name; 324 callback(data); 325 } 326 } 327 return; 328} 329 330static struct r_debug * 331load_debug_struct(Process *proc) { 332 struct r_debug *rdbg = NULL; 333 334 debug(DEBUG_FUNCTION, "load_debug_struct"); 335 336 rdbg = malloc(sizeof(*rdbg)); 337 if (!rdbg) { 338 return NULL; 339 } 340 341 if (umovebytes(proc, proc->debug, rdbg, sizeof(*rdbg)) != sizeof(*rdbg)) { 342 debug(2, "This process does not have a debug structure!\n"); 343 free(rdbg); 344 return NULL; 345 } 346 347 return rdbg; 348} 349 350static void 351linkmap_add_cb(void *data) { //const char *lib_name, ElfW(Addr) addr) { 352 size_t i = 0; 353 struct cb_data *lm_add = data; 354 struct ltelf lte; 355 struct opt_x_t *xptr; 356 357 debug(DEBUG_FUNCTION, "linkmap_add_cb"); 358 359 /* 360 XXX 361 iterate through library[i]'s to see if this lib is in the list. 362 if not, add it 363 */ 364 for(;i < library_num;i++) { 365 if (strcmp(library[i], lm_add->lib_name) == 0) { 366 /* found it, so its not new */ 367 return; 368 } 369 } 370 371 /* new library linked! */ 372 debug(2, "New libdl loaded library found: %s\n", lm_add->lib_name); 373 374 if (library_num < MAX_LIBRARIES) { 375 library[library_num++] = strdup(lm_add->lib_name); 376 memset(<e, 0, sizeof(struct ltelf)); 377 lte.base_addr = lm_add->addr; 378 do_init_elf(<e, library[library_num-1]); 379 /* add bps */ 380 for (xptr = opt_x; xptr; xptr = xptr->next) { 381 if (xptr->found) 382 continue; 383 384 GElf_Sym sym; 385 GElf_Addr addr; 386 387 if (in_load_libraries(xptr->name, <e, 1, &sym)) { 388 debug(2, "found symbol %s @ %#" PRIx64 389 ", adding it.", 390 xptr->name, sym.st_value); 391 addr = sym.st_value; 392 add_library_symbol(addr, xptr->name, &library_symbols, LS_TOPLT_NONE, 0); 393 xptr->found = 1; 394 insert_breakpoint(lm_add->proc, 395 sym2addr(lm_add->proc, 396 library_symbols), 397 library_symbols, 1); 398 } 399 } 400 do_close_elf(<e); 401 } 402} 403 404void 405arch_check_dbg(Process *proc) { 406 struct r_debug *dbg = NULL; 407 struct cb_data data; 408 409 debug(DEBUG_FUNCTION, "arch_check_dbg"); 410 411 if (!(dbg = load_debug_struct(proc))) { 412 debug(2, "Unable to load debug structure!"); 413 return; 414 } 415 416 if (dbg->r_state == RT_CONSISTENT) { 417 debug(2, "Linkmap is now consistent"); 418 if (proc->debug_state == RT_ADD) { 419 debug(2, "Adding DSO to linkmap"); 420 data.proc = proc; 421 crawl_linkmap(proc, dbg, linkmap_add_cb, &data); 422 } else if (proc->debug_state == RT_DELETE) { 423 debug(2, "Removing DSO from linkmap"); 424 } else { 425 debug(2, "Unexpected debug state!"); 426 } 427 } 428 429 proc->debug_state = dbg->r_state; 430 431 return; 432} 433 434static void 435hook_libdl_cb(void *data) { 436 struct cb_data *hook_data = data; 437 const char *lib_name = NULL; 438 ElfW(Addr) addr; 439 struct ltelf *lte = NULL; 440 441 debug(DEBUG_FUNCTION, "add_library_cb"); 442 443 if (!data) { 444 debug(2, "No callback data"); 445 return; 446 } 447 448 lib_name = hook_data->lib_name; 449 addr = hook_data->addr; 450 lte = hook_data->lte; 451 452 if (library_num < MAX_LIBRARIES) { 453 lte[library_num].base_addr = addr; 454 library[library_num++] = strdup(lib_name); 455 } 456 else { 457 fprintf (stderr, "MAX LIBS REACHED\n"); 458 exit(EXIT_FAILURE); 459 } 460} 461 462int 463linkmap_init(Process *proc, struct ltelf *lte) { 464 void *dbg_addr = NULL, *dyn_addr = GELF_ADDR_CAST(lte->dyn_addr); 465 struct r_debug *rdbg = NULL; 466 struct cb_data data; 467 468 debug(DEBUG_FUNCTION, "linkmap_init()"); 469 470 if (find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, &dbg_addr) == -1) { 471 debug(2, "Couldn't find debug structure!"); 472 return -1; 473 } 474 475 proc->debug = dbg_addr; 476 477 if (!(rdbg = load_debug_struct(proc))) { 478 debug(2, "No debug structure or no memory to allocate one!"); 479 return -1; 480 } 481 482 data.lte = lte; 483 484 add_library_symbol(rdbg->r_brk, "", &library_symbols, LS_TOPLT_NONE, 0); 485 insert_breakpoint(proc, sym2addr(proc, library_symbols), 486 library_symbols, 1); 487 488 crawl_linkmap(proc, rdbg, hook_libdl_cb, &data); 489 490 free(rdbg); 491 return 0; 492} 493 494int 495task_kill (pid_t pid, int sig) 496{ 497 // Taken from GDB 498 int ret; 499 500 errno = 0; 501 ret = syscall (__NR_tkill, pid, sig); 502 return ret; 503} 504