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