proc.c revision 17476b7bfac0e1cb68f9a1dbdb65dab2ac2160c6
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 ElfW(Dyn) entry; 253 254 debug(DEBUG_FUNCTION, "find_dynamic_entry()"); 255 256 if (addr == NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) { 257 return -1; 258 } 259 260 while ((sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) && 261 (entry.d_tag != DT_NULL)) { 262 fprintf(stderr, " entry %ld %#lx\n", entry.d_tag, entry.d_un.d_val); 263 if (entry.d_tag == d_tag) { 264 fprintf(stderr, " hit\n"); 265 *addr = (void *)entry.d_un.d_val; 266 debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag); 267 return 0; 268 } 269 pvAddr += sizeof(entry); 270 } 271 272 debug(2, "Couldn't address for dtag!\n"); 273 return -1; 274} 275 276enum callback_status 277find_library_addr(struct Process *proc, struct library *lib, void *data) 278{ 279 target_address_t addr = (target_address_t)*(GElf_Addr *)data; 280 return lib->base == addr ? CBS_STOP : CBS_CONT; 281} 282 283static void 284crawl_linkmap(Process *proc, struct r_debug *dbg) 285{ 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 debug(2, "Dispatching callback for: %s, " 314 "Loaded at 0x%" PRI_ELF_ADDR "\n", 315 lib_name, rlm.l_addr); 316 fprintf(stderr, "DSO addr=%#lx, name='%s'\n", rlm.l_addr, lib_name); 317 318 /* Do we have that library already? */ 319 struct library *lib 320 = proc_each_library(proc, NULL, find_library_addr, 321 &rlm.l_addr); 322 if (lib != NULL) 323 continue; 324 325 if (*lib_name == '\0') { 326 /* VDSO. No associated file, XXX but we might 327 * load it from the address space of the 328 * process. */ 329 continue; 330 } 331 332 lib = ltelf_read_library(proc, lib_name, rlm.l_addr); 333 if (lib == NULL) { 334 error(0, errno, "Couldn't load ELF object %s\n", 335 lib_name); 336 continue; 337 } 338 339 proc_add_library(proc, lib); 340 } 341 return; 342} 343 344static struct r_debug * 345load_debug_struct(Process *proc) { 346 struct r_debug *rdbg = NULL; 347 348 debug(DEBUG_FUNCTION, "load_debug_struct"); 349 350 rdbg = malloc(sizeof(*rdbg)); 351 if (!rdbg) { 352 return NULL; 353 } 354 355 if (umovebytes(proc, proc->debug, rdbg, sizeof(*rdbg)) != sizeof(*rdbg)) { 356 debug(2, "This process does not have a debug structure!\n"); 357 free(rdbg); 358 return NULL; 359 } 360 361 return rdbg; 362} 363 364static void 365rdebug_callback_hit(struct breakpoint *bp, struct Process *proc) 366{ 367 fprintf(stderr, "======= HIT\n"); 368 struct r_debug *dbg = NULL; 369 //struct cb_data data; 370 371 debug(DEBUG_FUNCTION, "arch_check_dbg"); 372 373 if (!(dbg = load_debug_struct(proc))) { 374 debug(2, "Unable to load debug structure!"); 375 return; 376 } 377 378 if (dbg->r_state == RT_CONSISTENT) { 379 debug(2, "Linkmap is now consistent"); 380 if (proc->debug_state == RT_ADD) { 381 debug(2, "Adding DSO to linkmap"); 382 //data.proc = proc; 383 crawl_linkmap(proc, dbg); 384 //&data); 385 } else if (proc->debug_state == RT_DELETE) { 386 debug(2, "Removing DSO from linkmap"); 387 } else { 388 debug(2, "Unexpected debug state!"); 389 } 390 } 391 392 proc->debug_state = dbg->r_state; 393 return; 394} 395 396void *dyn_addr; 397int 398linkmap_init(struct Process *proc) 399{ 400 return 0; 401 void *dbg_addr = NULL; 402 struct r_debug *rdbg = NULL; 403 //struct cb_data data; 404 405 debug(DEBUG_FUNCTION, "linkmap_init()"); 406 fprintf(stderr, "linkmap_init dyn_addr=%p\n", dyn_addr); 407 408 if (find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, &dbg_addr) == -1) { 409 debug(2, "Couldn't find debug structure!"); 410 return -1; 411 } 412 413 proc->debug = dbg_addr; 414 415 if (!(rdbg = load_debug_struct(proc))) { 416 debug(2, "No debug structure or no memory to allocate one!"); 417 return -1; 418 } 419 420 //data.lte = lte; 421 422 void *addr; 423 { 424 struct library_symbol libsym; 425 library_symbol_init(&libsym, (target_address_t)rdbg->r_brk, 426 NULL, 0, LS_TOPLT_NONE); 427 addr = sym2addr(proc, &libsym); 428 library_symbol_destroy(&libsym); 429 } 430 struct breakpoint *rdebug_bp = insert_breakpoint(proc, addr, NULL); 431 static struct bp_callbacks rdebug_callbacks = { 432 .on_hit = rdebug_callback_hit, 433 }; 434 rdebug_bp->cbs = &rdebug_callbacks; 435 436 crawl_linkmap(proc, rdbg); 437 438 free(rdbg); 439 return 0; 440} 441 442int 443task_kill (pid_t pid, int sig) 444{ 445 // Taken from GDB 446 int ret; 447 448 errno = 0; 449 ret = syscall (__NR_tkill, pid, sig); 450 return ret; 451} 452