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