void ltrace_init(int argc, char **argv) { struct opt_p_t *opt_p_tmp; atexit(normal_exit); signal(SIGINT, signal_exit); /* Detach processes when interrupted */ signal(SIGTERM, signal_exit); /* ... or killed */ argv = process_options(argc, argv); init_global_config(); while (opt_F) { /* If filename begins with ~, expand it to the user's home */ /* directory. This does not correctly handle ~yoda, but that */ /* isn't as bad as it seems because the shell will normally */ /* be doing the expansion for us; only the hardcoded */ /* ~/.ltrace.conf should ever use this code. */ if (opt_F->filename[0] == '~') { char path[PATH_MAX]; char *home_dir = getenv("HOME"); if (home_dir) { strncpy(path, home_dir, PATH_MAX - 1); path[PATH_MAX - 1] = '\0'; strncat(path, opt_F->filename + 1, PATH_MAX - strlen(path) - 1); read_config_file(path); } } else { read_config_file(opt_F->filename); } struct opt_F_t *next = opt_F->next; if (opt_F->own_filename) free(opt_F->filename); free(opt_F); opt_F = next; } if (command) { /* Check that the binary ABI is supported before * calling execute_program. */ struct ltelf lte = {}; open_elf(<e, command); do_close_elf(<e); pid_t pid = execute_program(command, argv); struct Process *proc = open_program(command, pid); if (proc == NULL) { fprintf(stderr, "couldn't open program '%s': %s\n", command, strerror(errno)); exit(EXIT_FAILURE); } trace_set_options(proc); continue_process(pid); } opt_p_tmp = opt_p; while (opt_p_tmp) { open_pid(opt_p_tmp->pid); opt_p_tmp = opt_p_tmp->next; } }
void pvs_start(Char *title) { pvs_after_init=0; pvs_in_checker=0; open_program(translate("pvsscript %i &"), title, pvs_parse); pvs_get_templates(); }
void open_pid(pid_t pid) { Process *proc; char *filename; if (trace_pid(pid) < 0) { fprintf(stderr, "Cannot attach to pid %u: %s\n", pid, strerror(errno)); return; } filename = pid2name(pid); if (!filename) { fprintf(stderr, "Cannot trace pid %u: %s\n", pid, strerror(errno)); return; } proc = open_program(filename, pid); continue_process(pid); proc->breakpoints_enabled = 1; //modify for android attach_child_thread(proc); }
void ltrace_init(int argc, char **argv) { struct opt_p_t *opt_p_tmp; #ifdef HAVE_PYTHON Py_Initialize(); #endif atexit(normal_exit); signal(SIGINT, signal_exit); /* Detach processes when interrupted */ signal(SIGTERM, signal_exit); /* ... or killed */ argv = process_options(argc, argv); while (opt_F) { /* If filename begins with ~, expand it to the user's home */ /* directory. This does not correctly handle ~yoda, but that */ /* isn't as bad as it seems because the shell will normally */ /* be doing the expansion for us; only the hardcoded */ /* ~/.ltrace.conf should ever use this code. */ if (opt_F->filename[0] == '~') { char path[PATH_MAX]; char *home_dir = getenv("HOME"); if (home_dir) { strncpy(path, home_dir, PATH_MAX - 1); path[PATH_MAX - 1] = '\0'; strncat(path, opt_F->filename + 1, PATH_MAX - strlen(path) - 1); read_config_file(path); } } else { read_config_file(opt_F->filename); } opt_F = opt_F->next; } if (opt_e) { struct opt_e_t *tmp = opt_e; while (tmp) { debug(1, "Option -e: %s\n", tmp->name); tmp = tmp->next; } } if (command) { /* Check that the binary ABI is supported before * calling execute_program. */ struct ltelf lte = {}; open_elf(<e, command); open_program(command, execute_program(command, argv), 0); } opt_p_tmp = opt_p; while (opt_p_tmp) { open_pid(opt_p_tmp->pid); opt_p_tmp = opt_p_tmp->next; } }
void ltrace_init(int argc, char **argv) { setlocale(LC_ALL, ""); struct opt_p_t *opt_p_tmp; atexit(normal_exit); signal(SIGINT, signal_exit); /* Detach processes when interrupted */ signal(SIGTERM, signal_exit); /* ... or killed */ argv = process_options(argc, argv); init_global_config(); if (command) { /* Check that the binary ABI is supported before * calling execute_program. */ { struct ltelf lte; if (ltelf_init(<e, command) == 0) ltelf_destroy(<e); else exit(EXIT_FAILURE); } pid_t pid = execute_program(command, argv); struct process *proc = open_program(command, pid); if (proc == NULL) { fprintf(stderr, "couldn't open program '%s': %s\n", command, strerror(errno)); exit(EXIT_FAILURE); } trace_set_options(proc); continue_process(pid); } opt_p_tmp = opt_p; while (opt_p_tmp) { open_pid(opt_p_tmp->pid); opt_p_tmp = opt_p_tmp->next; } }
int process_clone(struct Process *retp, struct Process *proc, pid_t pid) { if (process_bare_init(retp, proc->filename, pid, 0) < 0) { fail1: fprintf(stderr, "failed to clone process %d->%d : %s\n", proc->pid, pid, strerror(errno)); return -1; } retp->tracesysgood = proc->tracesysgood; retp->e_machine = proc->e_machine; retp->e_class = proc->e_class; /* For non-leader processes, that's all we need to do. */ if (retp->leader != retp) return 0; /* Clone symbols first so that we can clone and relink * breakpoints. */ struct library *lib; struct library **nlibp = &retp->libraries; for (lib = proc->leader->libraries; lib != NULL; lib = lib->next) { *nlibp = malloc(sizeof(**nlibp)); if (*nlibp == NULL || library_clone(*nlibp, lib) < 0) { fail2: process_bare_destroy(retp, 0); /* Error when cloning. Unroll what was done. */ for (lib = retp->libraries; lib != NULL; ) { struct library *next = lib->next; library_destroy(lib); free(lib); lib = next; } goto fail1; } nlibp = &(*nlibp)->next; } /* Now clone breakpoints. Symbol relinking is done in * clone_single_bp. */ struct clone_single_bp_data data = { .old_proc = proc, .new_proc = retp, .error = 0, }; dict_apply_to_all(proc->leader->breakpoints, &clone_single_bp, &data); if (data.error < 0) goto fail2; /* And finally the call stack. */ /* XXX clearly the callstack handling should be moved to a * separate module and this whole business extracted to * callstack_clone, or callstack_element_clone. */ memcpy(retp->callstack, proc->callstack, sizeof(retp->callstack)); retp->callstack_depth = proc->callstack_depth; size_t i; for (i = 0; i < retp->callstack_depth; ++i) { struct callstack_element *elem = &retp->callstack[i]; struct fetch_context *ctx = elem->fetch_context; if (ctx != NULL) { struct fetch_context *nctx = fetch_arg_clone(retp, ctx); if (nctx == NULL) { size_t j; fail3: for (j = 0; j < i; ++j) { nctx = elem->fetch_context; fetch_arg_done(nctx); elem->fetch_context = NULL; } goto fail2; } elem->fetch_context = nctx; } struct value_dict *args = elem->arguments; if (args != NULL) { struct value_dict *nargs = malloc(sizeof(*nargs)); if (nargs == NULL || val_dict_clone(nargs, args) < 0) { size_t j; for (j = 0; j < i; ++j) { nargs = elem->arguments; val_dict_destroy(nargs); free(nargs); elem->arguments = NULL; } /* Pretend that this round went well, * so that fail3 frees I-th * fetch_context. */ ++i; goto fail3; } elem->arguments = nargs; } /* If it's not a syscall, we need to find the * corresponding library symbol in the cloned * library. */ if (!elem->is_syscall && elem->c_un.libfunc != NULL) { struct library_symbol *libfunc = elem->c_un.libfunc; int rc = proc_find_symbol(retp, libfunc, NULL, &elem->c_un.libfunc); assert(rc == 0); } } /* At this point, retp is fully initialized, except for OS and * arch parts, and we can call private_process_destroy. */ if (os_process_clone(retp, proc) < 0) { private_process_destroy(retp, 0); return -1; } if (arch_process_clone(retp, proc) < 0) { os_process_destroy(retp); private_process_destroy(retp, 0); return -1; } return 0; } static int open_one_pid(pid_t pid) { Process *proc; char *filename; debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid); /* Get the filename first. Should the trace_pid fail, we can * easily free it, untracing is more work. */ if ((filename = pid2name(pid)) == NULL || trace_pid(pid) < 0) { fail: free(filename); return -1; } proc = open_program(filename, pid); if (proc == NULL) goto fail; free(filename); trace_set_options(proc); return 0; }
/* * Open an ELF file and load it into memory. */ static Elf32_Addr load_elf_file(const char *filename, size_t pagesize, Elf32_Addr *out_base, Elf32_Addr *out_phdr, Elf32_Addr *out_phnum, const char **out_interp) { int fd = open_program(filename); if (fd < 0) { fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno)); exit(2); } uintptr_t pread_pos = 0; Elf32_Ehdr ehdr; my_pread(filename, "Failed to read ELF header from file! ", fd, &ehdr, sizeof(ehdr), 0, &pread_pos); if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || ehdr.e_version != EV_CURRENT || ehdr.e_ehsize != sizeof(ehdr) || ehdr.e_phentsize != sizeof(Elf32_Phdr)) { fprintf(stderr, "%s has no valid ELF header!\n", filename); exit(1); } switch (ehdr.e_machine) { #if defined(__i386__) case EM_386: #elif defined(__x86_64__) case EM_X86_64: #elif defined(__arm__) case EM_ARM: #elif defined(__mips__) case EM_MIPS: #else # error "Don't know the e_machine value for this architecture!" #endif break; default: fprintf(stderr, "%s: ELF file has wrong architecture (e_machine=%u)\n", filename, ehdr.e_machine); exit(1); } Elf32_Phdr phdr[MAX_PHNUM]; if (ehdr.e_phnum > sizeof(phdr) / sizeof(phdr[0]) || ehdr.e_phnum < 1) { fprintf(stderr, "%s: ELF file has unreasonable e_phnum=%u\n", filename, ehdr.e_phnum); exit(1); } bool anywhere; switch (ehdr.e_type) { case ET_EXEC: anywhere = false; break; case ET_DYN: anywhere = true; break; default: fprintf(stderr, "%s: ELF file has unexpected e_type=%u\n", filename, ehdr.e_type); exit(1); } my_pread(filename, "Failed to read program headers from ELF file! ", fd, phdr, sizeof(phdr[0]) * ehdr.e_phnum, ehdr.e_phoff, &pread_pos); size_t i = 0; while (i < ehdr.e_phnum && phdr[i].p_type != PT_LOAD) ++i; if (i == ehdr.e_phnum) { fprintf(stderr, "%s: ELF file has no PT_LOAD header!", filename); exit(1); } /* * ELF requires that PT_LOAD segments be in ascending order of p_vaddr. * Find the last one to calculate the whole address span of the image. */ const Elf32_Phdr *first_load = &phdr[i]; const Elf32_Phdr *last_load = &phdr[ehdr.e_phnum - 1]; while (last_load > first_load && last_load->p_type != PT_LOAD) --last_load; /* * For NaCl, the first load segment must always be the code segment. */ if (first_load->p_flags != (PF_R | PF_X)) { fprintf(stderr, "%s: First PT_LOAD has p_flags=%#x (expecting RX=%#x)\n", filename, first_load->p_flags, PF_R | PF_X); exit(1); } if (first_load->p_filesz != first_load->p_memsz) { fprintf(stderr, "%s: Code segment has p_filesz %u != p_memsz %u\n", filename, first_load->p_filesz, first_load->p_memsz); exit(1); } /* * Decide where to load the image and reserve the portions of the address * space where it will reside. */ Elf32_Addr load_bias = choose_load_bias(filename, pagesize, first_load, last_load, anywhere); DEBUG_PRINTF("XXX load_bias (%s) %#x\n", anywhere ? "anywhere" : "fixed", load_bias); /* * Map the code segment in. */ my_mmap(filename, "code segment", first_load - phdr, load_bias + round_down(first_load->p_vaddr, pagesize), first_load->p_memsz, prot_from_phdr(first_load), MAP_PRIVATE | MAP_FIXED, fd, round_down(first_load->p_offset, pagesize)); Elf32_Addr last_end = first_load->p_vaddr + load_bias + first_load->p_memsz; Elf32_Addr last_page_end = round_up(last_end, pagesize); /* * Map the remaining segments, and protect any holes between them. * The large hole after the code segment does not need to be * protected (and cannot be). It covers the whole large tail of the * dynamic text area, which cannot be touched by mprotect. */ const Elf32_Phdr *ph; for (ph = first_load + 1; ph <= last_load; ++ph) { if (ph->p_type == PT_LOAD) { Elf32_Addr start = round_down(ph->p_vaddr + load_bias, pagesize); if (start > last_page_end && ph > first_load + 1) { if (mprotect((void *) last_page_end, start - last_page_end, PROT_NONE) != 0) { fprintf(stderr, "%s: Failed to mprotect segment %u hole! (%s)\n", filename, ph - phdr, strerror(errno)); exit(1); } } last_end = ph->p_vaddr + load_bias + ph->p_memsz; last_page_end = round_up(last_end, pagesize); Elf32_Addr map_end = last_page_end; /* * Unlike POSIX mmap, NaCl's mmap does not reliably handle COW * faults in the remainder of the final partial page. So to get * the expected behavior for the unaligned boundary between data * and bss, it's necessary to allocate the final partial page of * data as anonymous memory rather than mapping it from the file. */ Elf32_Addr file_end = ph->p_vaddr + load_bias + ph->p_filesz; if (ph->p_memsz > ph->p_filesz) map_end = round_down(file_end, pagesize); if (map_end > start) { my_mmap(filename, "segment", ph - phdr, start, map_end - start, prot_from_phdr(ph), MAP_PRIVATE | MAP_FIXED, fd, round_down(ph->p_offset, pagesize)); } if (map_end < last_page_end) { /* * Handle the "bss" portion of a segment, where the memory size * exceeds the file size and we zero-fill the difference. We map * anonymous pages for all the pages containing bss space. Then, * if there is any partial-page tail of the file data, we read that * into the first such page. * * This scenario is invalid for an unwritable segment. */ if ((ph->p_flags & PF_W) == 0) { fprintf(stderr, "%s: Segment %u has p_memsz %u > p_filesz %u but no PF_W!\n", filename, ph - phdr, ph->p_memsz, ph->p_filesz); exit(1); } my_mmap(filename, "bss segment", ph - phdr, map_end, last_page_end - map_end, prot_from_phdr(ph), MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); if (file_end > map_end) { /* * There is a partial page of data to read in. */ my_pread(filename, "Failed to read final partial page of data! ", fd, (void *) map_end, file_end - map_end, round_down(ph->p_offset + ph->p_filesz, pagesize), &pread_pos); } } } } /* * We've finished with the file now. */ close(fd); /* * Find the PT_INTERP header, if there is one. */ const Elf32_Phdr *interp = NULL; if (out_interp != NULL) { for (i = 0; i < ehdr.e_phnum; ++i) { if (phdr[i].p_type == PT_INTERP) { interp = &phdr[i]; break; } } } /* * Find the PT_LOAD segments containing the PT_INTERP data and the phdrs. */ for (ph = first_load; ph <= last_load && (interp != NULL || out_phdr != NULL); ++ph) { if (interp != NULL && segment_contains(ph, interp->p_offset, interp->p_filesz)) { *out_interp = (const char *) (interp->p_vaddr + load_bias); interp = NULL; } if (out_phdr != NULL && segment_contains(ph, ehdr.e_phoff, ehdr.e_phnum * sizeof(phdr[0]))) { *out_phdr = ehdr.e_phoff - ph->p_offset + ph->p_vaddr + load_bias; out_phdr = NULL; } } if (interp != NULL) { fprintf(stderr, "%s: PT_INTERP not within any PT_LOAD segment\n", filename); exit(1); } if (out_phdr != NULL) { *out_phdr = 0; fprintf(stderr, "Warning: %s: ELF program headers not within any PT_LOAD segment\n", filename); } if (out_phnum != NULL) *out_phnum = ehdr.e_phnum; if (out_base != NULL) *out_base = load_bias; return ehdr.e_entry + load_bias; }