ATF_TC_BODY(signal_forward, tc) { struct proc_handle *phdl; int state, status; phdl = start_prog(tc, true); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); /* The process should have been interrupted by a signal. */ state = proc_wstatus(phdl); ATF_REQUIRE_EQ_MSG(state, PS_STOP, "process has unexpected state %d", state); /* Continue execution and allow the signal to be delivered. */ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); /* * Make sure the process exited with status 0. If it didn't receive the * SIGUSR1 that it sent to itself, it'll exit with a non-zero exit * status, causing the test to fail. */ state = proc_wstatus(phdl); ATF_REQUIRE_EQ_MSG(state, PS_UNDEAD, "process has unexpected state %d", state); status = proc_getwstat(phdl); ATF_REQUIRE(status >= 0); ATF_REQUIRE(WIFEXITED(status)); ATF_REQUIRE_EQ(WEXITSTATUS(status), 0); proc_free(phdl); }
ATF_TC_BODY(symbol_lookup, tc) { GElf_Sym main_sym, r_debug_state_sym; struct proc_handle *phdl; u_long saved; int error; phdl = start_prog(tc, false); error = proc_name2sym(phdl, target_prog_file, "main", &main_sym, NULL); ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main'"); error = proc_name2sym(phdl, ldelf_object, "r_debug_state", &r_debug_state_sym, NULL); ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'r_debug_state'"); set_bkpt(phdl, r_debug_state_sym.st_value, &saved); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); verify_bkpt(phdl, &r_debug_state_sym, "r_debug_state", ldelf_object); remove_bkpt(phdl, r_debug_state_sym.st_value, saved); set_bkpt(phdl, main_sym.st_value, &saved); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); verify_bkpt(phdl, &main_sym, "main", target_prog_file); remove_bkpt(phdl, main_sym.st_value, saved); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); proc_free(phdl); }
ATF_TC_BODY(symbol_lookup, tc) { GElf_Sym main_sym, r_debug_state_sym; struct proc_handle *phdl; proc_breakpoint_t saved; int error; phdl = start_prog(tc, false); error = proc_name2sym(phdl, target_prog_file, "main", &main_sym, NULL); ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main'"); error = proc_name2sym(phdl, ldelf_object, r_debug_state, &r_debug_state_sym, NULL); ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up '%s'", r_debug_state); set_bkpt(phdl, (uintptr_t)r_debug_state_sym.st_value, &saved); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); verify_bkpt(phdl, &r_debug_state_sym, r_debug_state, ldelf_object); remove_bkpt(phdl, (uintptr_t)r_debug_state_sym.st_value, &saved); set_bkpt(phdl, (uintptr_t)main_sym.st_value, &saved); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); verify_bkpt(phdl, &main_sym, "main", target_prog_file); remove_bkpt(phdl, (uintptr_t)main_sym.st_value, &saved); ATF_CHECK_EQ_MSG(proc_detach(phdl, PRELEASE_HANG), 0, "failed to detach"); proc_free(phdl); }
ATF_TC_BODY(symbol_lookup_fail, tc) { char symname[32]; GElf_Sym sym; struct proc_handle *phdl; prmap_t *map; int error; phdl = start_prog(tc, false); /* Initialize the rtld_db handle. */ (void)proc_rdagent(phdl); map = proc_name2map(phdl, target_prog_file); ATF_REQUIRE_MSG(map != NULL, "failed to look up map for '%s'", target_prog_file); /* * We shouldn't be able to find symbols at the beginning of a mapped * file. */ error = proc_addr2sym(phdl, map->pr_vaddr, symname, sizeof(symname), &sym); ATF_REQUIRE_MSG(error != 0, "unexpectedly found a symbol"); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); proc_free(phdl); }
ATF_TC_BODY(map_alias_name2sym, tc) { GElf_Sym sym1, sym2; prsyminfo_t si1, si2; struct proc_handle *phdl; int error; phdl = start_prog(tc, false); /* Initialize the rtld_db handle. */ (void)proc_rdagent(phdl); /* * Make sure that "target_prog:main" and "a.out:main" return the same * symbol. */ error = proc_name2sym(phdl, target_prog_file, "main", &sym1, &si1); ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s", target_prog_file); error = proc_name2sym(phdl, aout_object, "main", &sym2, &si2); ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s", aout_object); ATF_CHECK_EQ(memcmp(&sym1, &sym2, sizeof(sym1)), 0); ATF_CHECK_EQ(si1.prs_id, si2.prs_id); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); proc_free(phdl); }
int t1_bkpt_d() { struct proc_handle *phdl; char *targv[] = { "t1-bkpt-t", NULL}; unsigned long saved; proc_create("./t1-bkpt", targv, NULL, NULL, &phdl); assert(proc_bkptset(phdl, (uintptr_t)t1_bkpt_t, &saved) == 0); proc_continue(phdl); assert(proc_wstatus(phdl) == PS_STOP); proc_bkptexec(phdl, saved); proc_continue(phdl); proc_wstatus(phdl); proc_free(phdl); }
int proc_bkptdel(struct proc_handle *phdl, uintptr_t address, unsigned long saved) { struct ptrace_io_desc piod; uintptr_t caddr; int ret = 0, stopped; instr_t instr; if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || phdl->status == PS_IDLE) { errno = ENOENT; return (-1); } DPRINTFX("removing breakpoint at 0x%lx", address); stopped = 0; if (phdl->status != PS_STOP) { if (proc_stop(phdl) != 0) return (-1); stopped = 1; } /* * Overwrite the breakpoint instruction that we setup previously. */ caddr = address; instr = saved; piod.piod_op = PIOD_WRITE_I; piod.piod_offs = (void *)caddr; piod.piod_addr = &instr; piod.piod_len = BREAKPOINT_INSTR_SZ; if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { DPRINTF("ERROR: couldn't write instruction at address 0x%" PRIuPTR, address); ret = -1; } if (stopped) /* Restart the process if we had to stop it. */ proc_continue(phdl); return (ret); }
ATF_TC_BODY(map_prefix_name2map, tc) { struct proc_handle *phdl; prmap_t *map1, *map2; phdl = start_prog(tc, false); /* Initialize the rtld_db handle. */ (void)proc_rdagent(phdl); /* Make sure that "ld-elf" and "ld-elf.so" return the same map. */ map1 = proc_name2map(phdl, "ld-elf"); ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for 'ld-elf'"); map2 = proc_name2map(phdl, "ld-elf.so"); ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for 'ld-elf.so'"); ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); proc_free(phdl); }
ATF_TC_BODY(map_alias_name2map, tc) { struct proc_handle *phdl; prmap_t *map1, *map2; phdl = start_prog(tc, false); /* Initialize the rtld_db handle. */ (void)proc_rdagent(phdl); /* Ensure that "target_prog" and "a.out" return the same map. */ map1 = proc_name2map(phdl, target_prog_file); ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for '%s'", target_prog_file); map2 = proc_name2map(phdl, aout_object); ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for '%s'", aout_object); ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0); ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution"); proc_free(phdl); }
int init_loop(tracee_t* tracee, addr_t* will_start) { int signal, ret, brk_set = 0; list_t* cur; brkp_t* brkp; /* ** Address where the tracing will start. */ *will_start = 0; /* ** Init binaries. */ tracee->binh = bin_create_handler(tracee->proc->path); if (tracee->binh == NULL) errexit("ftrace: bin_create_handler, %s", ftrace_strerror(errno)); bin_refresh_depends_list(proc_get_depends_list(tracee->proc), tracee->binh); /* ** Inject breakpoints. */ brkps_inject(tracee); /* ** Waiting for breakpoint ? */ for (cur = tracee->brkps; cur; cur = cur->next) { if (((brkp_t*) cur->value)->set) { brk_set = 1; break; } if (cur == tracee->brkps->prev) break; } /* ** No breakpoint setted, trace ! */ if (!brk_set && !tracee->brkps_toset) { /* ** Remove FTrace breakpoints */ for (cur = tracee->fbrkps; cur; cur = cur->next) { if (((brkp_t*) cur->value)->set) { if (proc_unset_breakpoint(tracee->proc, (brkp_t*) cur->value) == -1) errexit("ftrace: proc_unset_breakpoint, %s", ftrace_strerror(errno)); } if (cur == tracee->fbrkps->prev) break; } return (TRACEE_OK); } /* ** Else wait for breakpoint hit. */ tracee->status = RUN; if (proc_continue(tracee->proc, 0) == -1) errexit("ftrace: proc_continue, %s", ftrace_strerror(errno)); while (1) { ret = proc_wait_debug_event(tracee->proc, &signal); if (ret == -1) errexit("ftrace: proc_wait_debug_event, %s", ftrace_strerror(errno)); switch (ret) { case DEBUG_EVENT: if (tracer_quit) return (0); /* ** if ftrace breakpoint: */ brkp = proc_seek_brkps(tracee->proc, tracee->fbrkps); if (brkp && brkp->set) { /* ** Lookup if any shared objects has been load. ** If there is a new so, try de resolve unsolved user breakpoint. */ if (bin_refresh_depends_list(proc_get_depends_list(tracee->proc), tracee->binh)) brkps_try_resolved(tracee); /* ** Unset ftrace one shot breakpoint */ if (proc_unset_breakpoint(tracee->proc, brkp) == -1) errexit("ftrace: proc_unset_breakpoint, %s", ftrace_strerror(errno)); /* ** Step back after restore and continue to seek user breakpoint. */ if (proc_step_addr(tracee->proc, brkp->addr, 0) == -1) errexit("ftrace: proc_step_addr, %s", ftrace_strerror(errno)); break; } /* ** if user breakpoint: */ brkp = proc_seek_brkps(tracee->proc, tracee->brkps); if (brkp && brkp->set) { /* ** Breakpoint hit! ** Remove every breakpoints and start tracing ! */ /* ** Remove user breakpoints. */ for (cur = tracee->brkps; cur; cur = cur->next) { if (((brkp_t*) cur->value)->set) { if (proc_unset_breakpoint(tracee->proc, (brkp_t*) cur->value) == -1) errexit("ftrace: proc_unset_breakpoint, %s", ftrace_strerror(errno)); } if (cur == tracee->brkps->prev) break; } /* ** Remove ftrace breakpoints. */ for (cur = tracee->fbrkps; cur; cur = cur->next) { if (((brkp_t*) cur->value)->set) { if (proc_unset_breakpoint(tracee->proc, (brkp_t*) cur->value) == -1) errexit("ftrace: proc_unset_breakpoint, %s", ftrace_strerror(errno)); } if (cur == tracee->fbrkps->prev) break; } /* ** Step back after restore. */ if (proc_step_addr(tracee->proc, brkp->addr, 0) == -1) errexit("ftrace: proc_step_addr, %s", ftrace_strerror(errno)); *will_start = brkp->addr; return (TRACEE_OK); } if (proc_continue(tracee->proc, 0) == -1) errexit("ftrace: proc_continue, %s", ftrace_strerror(errno)); break; case SIGNAL_EVENT: pwarn("Program received signal %d, %s\n", signal, sys_siglist[signal]); if (proc_continue(tracee->proc, signal) == -1) errexit("ftrace: proc_continue, %s", ftrace_strerror(errno)); break; case EXIT_EVENT: pverbose(1, "\nProgram exited normally.\n"); return (TRACEE_EXIT); break; case EXIT_SIGNALED_EVENT: pverbose(1, "Program exited with signal %d, %s\n", signal, sys_siglist[signal]); return (TRACEE_EXIT); break; default: errexit("ftrace: proc_wait_debug_event, Unknow Error !"); } } return (-1); }
int proc_bkptset(struct proc_handle *phdl, uintptr_t address, unsigned long *saved) { struct ptrace_io_desc piod; uintptr_t caddr; int ret = 0, stopped; instr_t instr; *saved = 0; if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || phdl->status == PS_IDLE) { errno = ENOENT; return (-1); } DPRINTFX("adding breakpoint at 0x%lx", address); stopped = 0; if (phdl->status != PS_STOP) { if (proc_stop(phdl) != 0) return (-1); stopped = 1; } /* * Read the original instruction. */ caddr = address; instr = 0; piod.piod_op = PIOD_READ_I; piod.piod_offs = (void *)caddr; piod.piod_addr = &instr; piod.piod_len = BREAKPOINT_INSTR_SZ; if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { DPRINTF("ERROR: couldn't read instruction at address 0x%" PRIuPTR, address); ret = -1; goto done; } *saved = instr; /* * Write a breakpoint instruction to that address. */ caddr = address; instr = BREAKPOINT_INSTR; piod.piod_op = PIOD_WRITE_I; piod.piod_offs = (void *)caddr; piod.piod_addr = &instr; piod.piod_len = BREAKPOINT_INSTR_SZ; if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) { DPRINTF("ERROR: couldn't write instruction at address 0x%" PRIuPTR, address); ret = -1; goto done; } done: if (stopped) /* Restart the process if we had to stop it. */ proc_continue(phdl); return (ret); }