bool handle_wait(pid_t pid, int status, int count, int *continued, int *terminated) { unsigned int alarm_remaining_sec = waitproc_flags_test(WAITPROC_FLAG_ALARMSET) ? alarm(0) : 0; if (pid != -1) { struct flagged_int *p = get_flagged_int(&waitproc_options.pids, pid); assert(p); if (WIFSTOPPED(status)) { long r = WSTOPSIG(status); assert(p->valid); switch (r) { case SIGSTOP: if (p->state == STATE_ATTACHED) { p->state = STATE_CONTINUED; r = 0; assert(*continued < count); if (++(*continued) == count) set_alarm(); } else { r = SIGCONT; } break; case SIGTSTP: r = SIGCONT; break; default: // forward the signal break; } if (r >= 0) { assert(p->state >= STATE_ATTACHED); r = ptrace(PTRACE_CONT, pid, 0, r); assert(r == 0); } } else if (WIFEXITED(status) || WIFSIGNALED(status)) { assert(p->valid && p->state < STATE_TERMINATED); p->state = STATE_TERMINATED; p->valid = false; print_terminated_process(pid); if (++(*terminated) == count) return false; } } else switch (errno) { case EINTR: if (waitproc_options.last_signal == SIGALRM) { waitproc_options.last_signal = SIGINVALID; if (DEBUG || !alarm_remaining_sec) return false; } else { fputs("Interrupted by unexpected signal\n", stderr); UNEXPECTED_STATE(); } break; case ECHILD: *terminated = count; return false; default: UNEXPECTED_STATE(); break; } assert(*terminated < count); if (alarm_remaining_sec) alarm(alarm_remaining_sec); return true; }
void trace(pid_t child, std::vector<std::string>& files, std::mutex & mutex) { waitpid(-1, NULL, __WALL); ptrace(PTRACE_ATTACH, child, 0, 0); ptrace(PTRACE_SETOPTIONS, child, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXIT | PTRACE_O_EXITKILL); pid_t pid = child; while (true) { int status; ptrace(PTRACE_SYSCALL, pid, 0, 0); pid = waitpid(-1, &status, __WALL); if(WIFEXITED(status)) { break; } else if (WIFSTOPPED(status)) { struct user_regs_struct regs; ptrace(PTRACE_GETREGS, pid, 0, ®s); struct regs { #ifdef __x86_64__ unsigned long #endif long err, syscall, arg0; } regs_ = { #ifdef __x86_64__ regs.rax, regs.orig_rax, regs.rdi #else regs.eax, regs.orig_eax, regs.ebx #endif }; if (regs_.err == (unsigned long)-ENOSYS) { //syscall_enter stop if (regs_.syscall == __NR_open) { std::string file_name; long word = ptrace(PTRACE_PEEKDATA, pid, regs_.arg0, NULL); char * tmp = (char *)&word; while (*tmp != '\0') { file_name.push_back(*tmp); ++tmp; if (tmp == (char *)(&word + 1)) { regs_.arg0 += sizeof(word); word = ptrace(PTRACE_PEEKDATA, pid, regs_.arg0, NULL); tmp = (char *)&word; } } { std::lock_guard<std::mutex> l(mutex); files.push_back(file_name); } } } else { //syscall_exit stop } } } }
int restore_fpx_registers(int pid, unsigned long *fp_regs) { if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) return -errno; return 0; }
// fill in ptrace_lwpinfo for lid static bool process_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) { errno = 0; ptrace(PT_LWPINFO, lwp_id, linfo, sizeof(struct ptrace_lwpinfo)); return (errno == 0)? true: false; }
/** * Detaches the child process from monitoring. This method must only be * invoked, if the thread exits. We do not check errors here, since the * thread could have already exited. */ void sys_ptrace_detach(pid_t pid) { ptrace(PTRACE_DETACH, pid, 0, 0); }
static void trace_me () { #if __APPLE__ signal (SIGTRAP, SIG_IGN); //NEED BY STEP #endif #if __APPLE__ || __BSD__ /* we can probably remove this #if..as long as PT_TRACE_ME is redefined for OSX in r_debug.h */ signal (SIGABRT, inferior_abort_handler); if (ptrace (PT_TRACE_ME, 0, 0, 0) != 0) { #else if (ptrace (PTRACE_TRACEME, 0, NULL, NULL) != 0) { #endif r_sys_perror ("ptrace-traceme"); exit (MAGIC_EXIT); } } // __UNIX__ (not windows) static int fork_and_ptraceme(RIO *io, int bits, const char *cmd) { bool runprofile = io->runprofile && *(io->runprofile); char **argv; #if __APPLE__ && !__POWERPC__ if (!runprofile) { #define _POSIX_SPAWN_DISABLE_ASLR 0x0100 posix_spawn_file_actions_t fileActions; ut32 ps_flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; sigset_t no_signals; sigset_t all_signals; sigemptyset (&no_signals); sigfillset (&all_signals); posix_spawnattr_t attr = {0}; size_t copied = 1; cpu_type_t cpu; pid_t p = -1; int ret, useASLR = io->aslr; char *_cmd = io->args ? r_str_concatf (strdup (cmd), " %s", io->args) : strdup (cmd); argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return -1; } if (!*argv) { r_str_argv_free (argv); free (_cmd); eprintf ("Invalid execvp\n"); return -1; } posix_spawnattr_init (&attr); if (useASLR != -1) { if (!useASLR) ps_flags |= _POSIX_SPAWN_DISABLE_ASLR; } posix_spawn_file_actions_init (&fileActions); posix_spawn_file_actions_addinherit_np (&fileActions, STDIN_FILENO); posix_spawn_file_actions_addinherit_np (&fileActions, STDOUT_FILENO); posix_spawn_file_actions_addinherit_np (&fileActions, STDERR_FILENO); ps_flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; ps_flags |= POSIX_SPAWN_START_SUSPENDED; posix_spawnattr_setsigmask(&attr, &no_signals); posix_spawnattr_setsigdefault(&attr, &all_signals); (void)posix_spawnattr_setflags (&attr, ps_flags); #if __i386__ || __x86_64__ cpu = CPU_TYPE_I386; if (bits == 64) cpu |= CPU_ARCH_ABI64; #else cpu = CPU_TYPE_ANY; #endif posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &copied); { char *dst = r_file_readlink (argv[0]); if (dst) { argv[0] = dst; } } ret = posix_spawnp (&p, argv[0], &fileActions, &attr, argv, NULL); switch (ret) { case 0: // eprintf ("Success\n"); break; case 22: eprintf ("posix_spawnp: Invalid argument\n"); break; case 86: eprintf ("Unsupported architecture\n"); break; default: eprintf ("posix_spawnp: unknown error %d\n", ret); perror ("posix_spawnp"); break; } posix_spawn_file_actions_destroy (&fileActions); r_str_argv_free (argv); free (_cmd); return p; } #endif int ret, status, child_pid; child_pid = r_sys_fork (); switch (child_pid) { case -1: perror ("fork_and_ptraceme"); break; case 0: if (runprofile) { char *expr = NULL; int i; RRunProfile *rp = r_run_new (NULL); argv = r_str_argv (cmd, NULL); for (i = 0; argv[i]; i++) { rp->_args[i] = argv[i]; } rp->_args[i] = NULL; rp->_program = argv[0]; rp->_dodebug = true; if (io->runprofile && *io->runprofile) { if (!r_run_parsefile (rp, io->runprofile)) { eprintf ("Can't find profile '%s'\n", io->runprofile); exit (MAGIC_EXIT); } } if (bits == 64) r_run_parseline (rp, expr=strdup ("bits=64")); else if (bits == 32) r_run_parseline (rp, expr=strdup ("bits=32")); free (expr); if (r_run_config_env (rp)) { eprintf ("Can't config the environment.\n"); exit (1); } trace_me (); r_run_start (rp); r_run_free (rp); r_str_argv_free (argv); exit (1); } else { char *_cmd = io->args ? r_str_concatf (strdup (cmd), " %s", io->args) : strdup (cmd); trace_me (); argv = r_str_argv (_cmd, NULL); if (!argv) { free (_cmd); return -1; } if (argv && *argv) { int i; for (i = 3; i < 1024; i++) (void)close (i); execvp (argv[0], argv); } else { eprintf ("Invalid execvp\n"); } r_str_argv_free (argv); free (_cmd); } perror ("fork_and_attach: execv"); //printf(stderr, "[%d] %s execv failed.\n", getpid(), ps.filename); exit (MAGIC_EXIT); /* error */ return 0; // invalid pid // if exit is overriden.. :) default: /* XXX: clean this dirty code */ do { ret = wait (&status); if (ret == -1) return -1; if (ret != child_pid) { eprintf ("Wait event received by " "different pid %d\n", ret); } } while (ret != child_pid); if (WIFSTOPPED (status)) { eprintf ("Process with PID %d started...\n", (int)child_pid); } if (WEXITSTATUS (status) == MAGIC_EXIT) { child_pid = -1; } // XXX kill (pid, SIGSTOP); break; } return child_pid; }
long amd64_linux32_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) { struct reg regs; struct linux_syscall *fsc; struct syscall *sc; lwpid_t tid; long retval; int errorp, i; if (trussinfo->curthread->fsc == NULL) return (-1); tid = trussinfo->curthread->tid; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return (-1); } retval = regs.r_rax; errorp = !!(regs.r_rflags & PSL_C); /* * This code, while simpler than the initial versions I used, could * stand some significant cleaning. */ fsc = trussinfo->curthread->fsc; sc = fsc->sc; if (!sc) { for (i = 0; i < fsc->nargs; i++) asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); } else { /* * Here, we only look for arguments that have OUT masked in -- * otherwise, they were handled in the syscall_entry function. */ for (i = 0; i < sc->nargs; i++) { char *temp; if (sc->args[i].type & OUT) { /* * If an error occurred, then don't bother * getting the data; it may not be valid. */ if (errorp) { asprintf(&temp, "0x%lx", fsc->args[sc->args[i].offset]); } else { temp = print_arg(&sc->args[i], fsc->args, retval, trussinfo); } fsc->s_args[i] = temp; } } } /* * It would probably be a good idea to merge the error handling, * but that complicates things considerably. */ if (errorp) { for (i = 0; (size_t)i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) { if (retval == bsd_to_linux_errno[i]) break; } } if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 || strcmp(fsc->name, "exit") == 0)) trussinfo->curthread->in_syscall = 1; print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, errorp ? i : retval, fsc->sc); free_fsc(fsc); return (retval); }
void powerpc64_syscall_entry(struct trussinfo *trussinfo, int nargs) { char buf[32]; struct reg regs; void *args; int syscall_num; int i; unsigned int regargs; struct syscall *sc; cpid = trussinfo->curthread->tid; clear_fsc(); if (ptrace(PT_GETREGS, cpid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } /* * FreeBSD has two special kinds of system call redirctions -- * SYS_syscall, and SYS___syscall. The former is the old syscall() * routine, basically; the latter is for quad-aligned arguments. */ regargs = NARGREG; syscall_num = regs.fixreg[0]; args = ®s.fixreg[3]; if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) { args = ®s.fixreg[4]; regargs -= 1; syscall_num = regs.fixreg[3]; } fsc.number = syscall_num; fsc.name = (syscall_num < 0 || syscall_num >= nsyscalls) ? NULL : syscallnames[syscall_num]; if (!fsc.name) { fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num); } if (fsc.name && (trussinfo->flags & FOLLOWFORKS) && ((!strcmp(fsc.name, "fork") || !strcmp(fsc.name, "rfork") || !strcmp(fsc.name, "vfork")))) { trussinfo->curthread->in_fork = 1; } if (nargs == 0) return; fsc.args = malloc((1+nargs) * sizeof(unsigned long)); if (nargs > regargs) { struct ptrace_io_desc iorequest; memmove(&fsc.args[0], args, regargs * sizeof(fsc.args[0])); iorequest.piod_op = PIOD_READ_D; iorequest.piod_offs = (void *)(regs.fixreg[1] + 48); iorequest.piod_addr = &fsc.args[regargs]; iorequest.piod_len = (nargs - regargs) * sizeof(fsc.args[0]); ptrace(PT_IO, cpid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) return; } else { memmove(&fsc.args[0], args, nargs * sizeof(fsc.args[0])); } sc = get_syscall(fsc.name); if (sc) { fsc.nargs = sc->nargs; } else { #if DEBUG fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", fsc.name, nargs); #endif fsc.nargs = nargs; } fsc.s_args = calloc(1, (1+fsc.nargs) * sizeof(char*)); fsc.sc = sc; /* * At this point, we set up the system call arguments. * We ignore any OUT ones, however -- those are arguments that * are set by the system call, and so are probably meaningless * now. This doesn't currently support arguments that are * passed in *and* out, however. */ if (fsc.name) { #if DEBUG fprintf(stderr, "syscall %s(", fsc.name); #endif for (i = 0; i < fsc.nargs; i++) { #if DEBUG fprintf(stderr, "0x%x%s", sc ? fsc.args[sc->args[i].offset] : fsc.args[i], i < (fsc.nargs - 1) ? "," : ""); #endif if (sc && !(sc->args[i].type & OUT)) { fsc.s_args[i] = print_arg(&sc->args[i], fsc.args, 0, trussinfo); } } #if DEBUG fprintf(stderr, ")\n"); #endif } #if DEBUG fprintf(trussinfo->outfile, "\n"); #endif if (fsc.name && (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) { /* XXX * This could be done in a more general * manner but it still wouldn't be very pretty. */ if (!strcmp(fsc.name, "execve")) { if ((trussinfo->flags & EXECVEARGS) == 0) if (fsc.s_args[1]) { free(fsc.s_args[1]); fsc.s_args[1] = NULL; } if ((trussinfo->flags & EXECVEENVS) == 0) if (fsc.s_args[2]) { free(fsc.s_args[2]); fsc.s_args[2] = NULL; } } } return; }
long powerpc64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) { struct reg regs; long retval; int i; int errorp; struct syscall *sc; if (fsc.name == NULL) return (-1); cpid = trussinfo->curthread->tid; if (ptrace(PT_GETREGS, cpid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "\n"); return (-1); } retval = regs.fixreg[3]; errorp = !!(regs.cr & 0x10000000); /* * This code, while simpler than the initial versions I used, could * stand some significant cleaning. */ sc = fsc.sc; if (!sc) { for (i = 0; i < fsc.nargs; i++) asprintf(&fsc.s_args[i], "0x%lx", fsc.args[i]); } else { /* * Here, we only look for arguments that have OUT masked in -- * otherwise, they were handled in the syscall_entry function. */ for (i = 0; i < sc->nargs; i++) { char *temp; if (sc->args[i].type & OUT) { /* * If an error occurred, than don't bothe getting the data; * it may not be valid. */ if (errorp) asprintf(&temp, "0x%lx", fsc.args[sc->args[i].offset]); else temp = print_arg(&sc->args[i], fsc.args, retval, trussinfo); fsc.s_args[i] = temp; } } } if (fsc.name != NULL && (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) { trussinfo->curthread->in_syscall = 1; } /* * It would probably be a good idea to merge the error handling, * but that complicates things considerably. */ print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval, fsc.sc); clear_fsc(); return (retval); }
void pt_debugger_x64::poke_reg(int reg, long data) { ptrace(PTRACE_POKEUSER, process->getpid(), 8 * reg, data); }
void PTraceContinue(pid_t pid) { // Child process stopped after signalling us, let it proceed ptrace(PT_CONTINUE, pid, (caddr_t) 1, 0); }
long pt_debugger_x64::peek_reg(int reg) { return ptrace(PTRACE_PEEKUSER, process->getpid(), 8 * reg, NULL); }
void arm_syscall_entry(struct trussinfo *trussinfo, int nargs) { struct ptrace_io_desc iorequest; struct reg regs; struct freebsd_syscall *fsc; struct syscall *sc; lwpid_t tid; int i, syscall_num; register_t *ap; tid = trussinfo->curthread->tid; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } ap = ®s.r[0]; /* * FreeBSD has two special kinds of system call redirctions -- * SYS_syscall, and SYS___syscall. The former is the old syscall() * routine, basically; the latter is for quad-aligned arguments. */ #ifdef __ARM_EABI__ syscall_num = regs.r[7]; #else if ((syscall_num = ptrace(PT_READ_I, tid, (caddr_t)(regs.r[_REG_PC] - INSN_SIZE), 0)) == -1) { fprintf(trussinfo->outfile, "-- CANNOT READ PC --\n"); return; } syscall_num = syscall_num & 0x000fffff; #endif switch (syscall_num) { case SYS_syscall: syscall_num = *ap++; nargs--; break; case SYS___syscall: syscall_num = ap[_QUAD_LOWWORD]; ap += 2; nargs -= 2; break; } fsc = alloc_fsc(); if (fsc == NULL) return; fsc->number = syscall_num; fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? NULL : syscallnames[syscall_num]; if (!fsc->name) { fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num); } if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && (strcmp(fsc->name, "fork") == 0 || strcmp(fsc->name, "rfork") == 0 || strcmp(fsc->name, "vfork") == 0)) trussinfo->curthread->in_fork = 1; if (nargs == 0) return; fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); switch (nargs) { default: /* * The OS doesn't seem to allow more than 10 words of * parameters (yay!). So we shouldn't be here. */ warn("More than 10 words (%d) of arguments!\n", nargs); break; case 10: case 9: case 8: case 7: case 6: case 5: /* * If there are 7-10 words of arguments, they are placed * on the stack, as is normal for other processors. * The fall-through for all of these is deliberate!!! */ // XXX BAD constant used here iorequest.piod_op = PIOD_READ_D; iorequest.piod_offs = (void *)(regs.r[_REG_SP] + 4 * sizeof(uint32_t)); iorequest.piod_addr = &fsc->args[4]; iorequest.piod_len = (nargs - 4) * sizeof(fsc->args[0]); ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) return; case 4: fsc->args[3] = ap[3]; case 3: fsc->args[2] = ap[2]; case 2: fsc->args[1] = ap[1]; case 1: fsc->args[0] = ap[0]; case 0: break; } sc = NULL; if (fsc->name) sc = get_syscall(fsc->name); if (sc) fsc->nargs = sc->nargs; else { #if DEBUG fprintf(trussinfo->outfile, "unknown syscall %s -- setting " "args to %d\n", fsc->name, nargs); #endif fsc->nargs = nargs; } fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); fsc->sc = sc; /* * At this point, we set up the system call arguments. * We ignore any OUT ones, however -- those are arguments that * are set by the system call, and so are probably meaningless * now. This doesn't currently support arguments that are * passed in *and* out, however. */ if (fsc->name) { #if DEBUG fprintf(stderr, "syscall %s(", fsc->name); #endif for (i = 0; i < fsc->nargs; i++) { #if DEBUG fprintf(stderr, "0x%x%s", sc ? fsc->args[sc->args[i].offset] : fsc->args[i], i < (fsc->nargs - 1) ? "," : ""); #endif if (sc && !(sc->args[i].type & OUT)) { fsc->s_args[i] = print_arg(&sc->args[i], fsc->args, 0, trussinfo); } } #if DEBUG fprintf(stderr, ")\n"); #endif } #if DEBUG fprintf(trussinfo->outfile, "\n"); #endif if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || strcmp(fsc->name, "exit") == 0)) { /* * XXX * This could be done in a more general * manner but it still wouldn't be very pretty. */ if (strcmp(fsc->name, "execve") == 0) { if ((trussinfo->flags & EXECVEARGS) == 0) { if (fsc->s_args[1]) { free(fsc->s_args[1]); fsc->s_args[1] = NULL; } } if ((trussinfo->flags & EXECVEENVS) == 0) { if (fsc->s_args[2]) { free(fsc->s_args[2]); fsc->s_args[2] = NULL; } } } } trussinfo->curthread->fsc = fsc; }
/* this could use elf_interpreter() from elfread.c */ int proc_iterate_over_mappings (int (*func) (int, CORE_ADDR)) { vaddr_t curseg, memptr; pt_vseg_t pv; int rv, cmperr; sec_ptr interp_sec; char *interp_content; int interp_fd, funcstat; unsigned int size; char buf1[NBPG], buf2[NBPG]; /* * The following is really vile. We can get the name of the * shared library from the exec_bfd, and we can get a list of * each virtual memory segment, but there is no simple way to * find the mapped segment from the shared library (ala * procfs's PIOCOPENMEM). As a pretty nasty kludge, we * compare the virtual memory segment to the contents of the * .interp file. If they match, we assume that we've got the * right one. */ /* * TODO: for attach, use XPT_OPENT to get the executable, in * case we're attached without knowning the executable's * filename. */ #ifdef VERBOSE_DEBUG printf ("proc_iter\n"); #endif interp_sec = bfd_get_section_by_name (exec_bfd, ".interp"); if (!interp_sec) { return 0; } size = bfd_section_size (exec_bfd, interp_sec); interp_content = alloca (size); if (0 == bfd_get_section_contents (exec_bfd, interp_sec, interp_content, (file_ptr) 0, size)) { return 0; } #ifdef VERBOSE_DEBUG printf ("proc_iter: \"%s\"\n", interp_content); #endif interp_fd = open (interp_content, O_RDONLY, 0); if (-1 == interp_fd) { return 0; } curseg = 0; while (1) { rv = ptrace (PT_NEXT_VSEG, PIDGET (inferior_ptid), &pv, curseg); #ifdef VERBOSE_DEBUG printf ("PT_NEXT_VSEG: rv %d errno %d\n", rv, errno); #endif if (-1 == rv) break; if (0 == rv) break; #ifdef VERBOSE_DEBUG printf ("pv.pv_start 0x%x pv_size 0x%x pv_prot 0x%x\n", pv.pv_start, pv.pv_size, pv.pv_prot); #endif curseg = pv.pv_start + pv.pv_size; rv = lseek (interp_fd, 0, SEEK_SET); if (-1 == rv) { perror ("lseek"); close (interp_fd); return 0; } for (memptr = pv.pv_start; memptr < pv.pv_start + pv.pv_size; memptr += NBPG) { #ifdef VERBOSE_DEBUG printf ("memptr 0x%x\n", memptr); #endif rv = read (interp_fd, buf1, NBPG); if (-1 == rv) { perror ("read"); close (interp_fd); return 0; } rv = ptrace (PT_RDATA_PAGE, PIDGET (inferior_ptid), buf2, memptr); if (-1 == rv) { perror ("ptrace"); close (interp_fd); return 0; } cmperr = memcmp (buf1, buf2, NBPG); if (cmperr) break; } if (0 == cmperr) { /* this is it */ funcstat = (*func) (interp_fd, pv.pv_start); break; } } close (interp_fd); return 0; }
void set_return_addr(Process *proc, void *addr) { ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr); }
unsigned ReqProg_load( void ) { char **args; char *parms; char *parm_start; int i; char exe_name[PATH_MAX]; char *name; pid_t save_pgrp; prog_load_req *acc; prog_load_ret *ret; unsigned len; int status; acc = GetInPtr( 0 ); ret = GetOutPtr( 0 ); last_sig = -1; have_rdebug = FALSE; dbg_dyn = NULL; at_end = FALSE; parms = (char *)GetInPtr( sizeof( *acc ) ); parm_start = parms; len = GetTotalSize() - sizeof( *acc ); if( acc->true_argv ) { i = 1; for( ;; ) { if( len == 0 ) break; if( *parms == '\0' ) { i++; } ++parms; --len; } args = alloca( i * sizeof( *args ) ); parms = parm_start; len = GetTotalSize() - sizeof( *acc ); i = 1; for( ;; ) { if( len == 0 ) break; if( *parms == '\0' ) { args[i++] = parms + 1; } ++parms; --len; } args[i - 1] = NULL; } else { while( *parms != '\0' ) { ++parms; --len; } ++parms; --len; i = SplitParms( parms, NULL, len ); args = alloca( (i + 2) * sizeof( *args ) ); args[SplitParms( parms, &args[1], len ) + 1] = NULL; } args[0] = parm_start; attached = TRUE; pid = RunningProc( args[0], &name ); if( pid == 0 || ptrace( PTRACE_ATTACH, pid, NULL, NULL ) == -1 ) { attached = FALSE; args[0] = name; if( FindFilePath( TRUE, args[0], exe_name ) == 0 ) { exe_name[0] = '\0'; } save_pgrp = getpgrp(); setpgid( 0, OrigPGrp ); pid = fork(); if( pid == -1 ) return( 0 ); if( pid == 0 ) { if( ptrace( PTRACE_TRACEME, 0, NULL, NULL ) < 0 ) { exit( 1 ); } execve( exe_name, (const char **)args, (const char **)dbg_environ ); exit( 1 ); /* failsafe */ } setpgid( 0, save_pgrp ); } else if( pid ) { GetExeNameFromPid( pid, exe_name, PATH_MAX ); } ret->flags = 0; ret->mod_handle = 0; if( (pid != -1) && (pid != 0) ) { int status; ret->task_id = pid; ret->flags |= LD_FLAG_IS_PROT | LD_FLAG_IS_32; /* wait until it hits _start (upon execve) or gives us a SIGSTOP (if attached) */ if( waitpid( pid, &status, 0 ) < 0 ) goto fail; if( !WIFSTOPPED( status ) ) goto fail; if( attached ) { ret->flags |= LD_FLAG_IS_STARTED; if( WSTOPSIG( status ) != SIGSTOP ) goto fail; } else { if( WSTOPSIG( status ) != SIGTRAP ) goto fail; } #if defined( MD_x86 ) if( !GetFlatSegs( &flatCS, &flatDS ) ) goto fail; #endif dbg_dyn = GetDebuggeeDynSection( exe_name ); AddProcess(); errno = 0; } ret->err = errno; if( ret->err != 0 ) { pid = 0; } CONV_LE_32( ret->err ); CONV_LE_32( ret->task_id ); CONV_LE_32( ret->mod_handle ); return( sizeof( *ret ) ); fail: if( pid != 0 && pid != -1 ) { if( attached ) { ptrace( PTRACE_DETACH, pid, NULL, NULL ); attached = FALSE; } else { ptrace( PTRACE_KILL, pid, NULL, NULL ); waitpid( pid, &status, 0 ); } } pid = 0; CONV_LE_32( ret->err ); CONV_LE_32( ret->task_id ); CONV_LE_32( ret->mod_handle ); return( 0 ); }
bool run_test(int cpu) { int status; pid_t pid = fork(); pid_t wpid; if (pid < 0) { ksft_print_msg("fork() failed: %s\n", strerror(errno)); return false; } if (pid == 0) child(cpu); wpid = waitpid(pid, &status, __WALL); if (wpid != pid) { ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); return false; } if (!WIFSTOPPED(status)) { ksft_print_msg("child did not stop: %s\n", strerror(errno)); return false; } if (WSTOPSIG(status) != SIGSTOP) { ksft_print_msg("child did not stop with SIGSTOP: %s\n", strerror(errno)); return false; } if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) { if (errno == EIO) { ksft_exit_skip( "ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n", strerror(errno)); } ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n", strerror(errno)); return false; } wpid = waitpid(pid, &status, __WALL); if (wpid != pid) { ksft_print_msg("waitpid() failed: $s\n", strerror(errno)); return false; } if (WIFEXITED(status)) { ksft_print_msg("child did not single-step: %s\n", strerror(errno)); return false; } if (!WIFSTOPPED(status)) { ksft_print_msg("child did not stop: %s\n", strerror(errno)); return false; } if (WSTOPSIG(status) != SIGTRAP) { ksft_print_msg("child did not stop with SIGTRAP: %s\n", strerror(errno)); return false; } if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n", strerror(errno)); return false; } wpid = waitpid(pid, &status, __WALL); if (wpid != pid) { ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); return false; } if (!WIFEXITED(status)) { ksft_print_msg("child did not exit after PTRACE_CONT: %s\n", strerror(errno)); return false; } return true; }
static unsigned ProgRun( int step ) { static int ptrace_sig = 0; static int ld_state = 0; user_regs_struct regs; int status; prog_go_ret *ret; void (*old)(int); int debug_continue; if( pid == 0 ) return( 0 ); ret = GetOutPtr( 0 ); if( at_end ) { ptrace_sig = 0; ret->conditions = COND_TERMINATE; goto end; } /* we only want child-generated SIGINTs now */ do { old = setsig( SIGINT, SIG_IGN ); if( step ) { Out( "PTRACE_SINGLESTEP\n" ); if( ptrace( PTRACE_SINGLESTEP, pid, NULL, (void *)ptrace_sig ) == -1 ) perror( "PTRACE_SINGLESTEP" ); } else { Out( "PTRACE_CONT\n" ); if( ptrace( PTRACE_CONT, pid, NULL, (void *)ptrace_sig ) == -1 ) perror( "PTRACE_CONT" ); } waitpid( pid, &status, 0 ); setsig( SIGINT, old ); #if defined( MD_x86 ) ptrace( PTRACE_GETREGS, pid, NULL, ®s ); #elif defined( MD_ppc ) regs.eip = ptrace( PTRACE_PEEKUSER, pid, REGSIZE * PT_NIP, NULL ); regs.esp = ptrace( PTRACE_PEEKUSER, pid, REGSIZE * PT_R1, NULL ); #elif defined( MD_mips ) regs.eip = ptrace( PTRACE_PEEKUSER, pid, (void *)PC, NULL ); regs.esp = ptrace( PTRACE_PEEKUSER, pid, (void *)29, NULL ); #endif Out( " eip " ); OutNum( regs.eip ); Out( "\n" ); debug_continue = FALSE; if( WIFSTOPPED( status ) ) { switch( ( ptrace_sig = WSTOPSIG( status ) ) ) { case SIGSEGV: case SIGILL: case SIGFPE: case SIGABRT: case SIGBUS: case SIGQUIT: case SIGSYS: last_sig = ptrace_sig; ret->conditions = COND_EXCEPTION; ptrace_sig = 0; break; case SIGINT: ret->conditions = COND_USER; ptrace_sig = 0; break; case SIGTRAP: ret->conditions = step ? COND_TRACE : COND_BREAK; Out( "sigtrap\n" ); ptrace_sig = 0; break; default: /* For signals that we do not wish to handle, we need * to continue the debuggee until we get a signal * that we need to handle */ Out( "Unknown signal " ); OutNum( ptrace_sig ); Out( "\n" ); debug_continue = TRUE; break; } } else if( WIFEXITED( status ) ) { Out( "WIFEXITED\n" ); at_end = TRUE; ret->conditions = COND_TERMINATE; ptrace_sig = 0; goto end; } } while( debug_continue ); if( ret->conditions == COND_BREAK ) { #if defined( MD_x86 ) if( regs.eip == rdebug.r_brk + sizeof( old_ld_bp ) ) { #elif defined( MD_ppc ) || defined( MD_mips ) if( regs.eip == rdebug.r_brk ) { #endif int psig = 0; void (*oldsig)(int); bp_t opcode = BRK_POINT; /* The dynamic linker breakpoint was hit, meaning that * libraries are being loaded or unloaded. This gets a bit * tricky because we must restore the original code that was * at the breakpoint and execute it, but we still want to * keep the breakpoint. */ WriteMem( pid, &old_ld_bp, rdebug.r_brk, sizeof( old_ld_bp ) ); ReadMem( pid, &rdebug, (addr48_off)dbg_rdebug, sizeof( rdebug ) ); Out( "ld breakpoint hit, state is " ); switch( rdebug.r_state ) { case RT_ADD: Out( "RT_ADD\n" ); ld_state = RT_ADD; AddOneLib( rdebug.r_map ); break; case RT_DELETE: Out( "RT_DELETE\n" ); ld_state = RT_DELETE; break; case RT_CONSISTENT: Out( "RT_CONSISTENT\n" ); if( ld_state == RT_DELETE ) DelOneLib( rdebug.r_map ); ld_state = RT_CONSISTENT; break; default: Out( "error!\n" ); break; } regs.orig_eax = -1; #if defined( MD_x86 ) regs.eip--; ptrace( PTRACE_SETREGS, pid, NULL, ®s ); #endif oldsig = setsig( SIGINT, SIG_IGN ); ptrace( PTRACE_SINGLESTEP, pid, NULL, (void *)psig ); waitpid( pid, &status, 0 ); setsig( SIGINT, oldsig ); WriteMem( pid, &opcode, rdebug.r_brk, sizeof( old_ld_bp ) ); ret->conditions = COND_LIBRARIES; } else { #if defined( MD_x86 ) Out( "decrease eip(sigtrap)\n" ); regs.orig_eax = -1; regs.eip--; ptrace( PTRACE_SETREGS, pid, NULL, ®s ); #endif } } orig_eax = regs.orig_eax; last_eip = regs.eip; ret->program_counter.offset = regs.eip; ret->program_counter.segment = regs.cs; ret->stack_pointer.offset = regs.esp; ret->stack_pointer.segment = regs.ss; ret->conditions |= COND_CONFIG; /* If debuggee has dynamic section, try getting the r_debug struct * every time the debuggee stops. The r_debug data may not be available * immediately after the debuggee process loads. */ if( !have_rdebug && (dbg_dyn != NULL) ) { if( Get_ld_info( pid, dbg_dyn, &rdebug, &dbg_rdebug ) ) { bp_t opcode; AddInitialLibs( rdebug.r_map ); have_rdebug = TRUE; ret->conditions |= COND_LIBRARIES; /* Set a breakpoint in dynamic linker. That way we can be * informed on dynamic library load/unload events. */ ReadMem( pid, &old_ld_bp, rdebug.r_brk, sizeof( old_ld_bp ) ); Out( "Setting ld breakpoint at " ); OutNum( rdebug.r_brk ); Out( " old opcode was " ); OutNum( old_ld_bp ); Out( "\n" ); opcode = BRK_POINT; WriteMem( pid, &opcode, rdebug.r_brk, sizeof( opcode ) ); } } end: CONV_LE_32( ret->stack_pointer.offset ); CONV_LE_16( ret->stack_pointer.segment ); CONV_LE_32( ret->program_counter.offset ); CONV_LE_16( ret->program_counter.segment ); CONV_LE_16( ret->conditions ); return( sizeof( *ret ) ); } unsigned ReqProg_step( void ) { return( ProgRun( TRUE ) ); } unsigned ReqProg_go( void ) { return( ProgRun( FALSE ) ); } unsigned ReqRedirect_stdin( void ) { redirect_stdin_ret *ret; ret = GetOutPtr( 0 ); ret->err = 1; return( sizeof( *ret ) ); }
void amd64_linux32_syscall_entry(struct trussinfo *trussinfo, int nargs) { struct reg regs; struct linux_syscall *fsc; struct syscall *sc; lwpid_t tid; int i, syscall_num; tid = trussinfo->curthread->tid; if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } syscall_num = regs.r_rax; fsc = alloc_fsc(); if (fsc == NULL) return; fsc->number = syscall_num; fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? NULL : linux32_syscallnames[syscall_num]; if (!fsc->name) { fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num); } if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && (strcmp(fsc->name, "linux_fork") == 0 || strcmp(fsc->name, "linux_vfork") == 0)) trussinfo->curthread->in_fork = 1; if (nargs == 0) return; /* * Linux passes syscall arguments in registers, not * on the stack. Fortunately, we've got access to the * register set. Note that we don't bother checking the * number of arguments. And what does linux do for syscalls * that have more than five arguments? */ fsc->args[0] = regs.r_rbx; fsc->args[1] = regs.r_rcx; fsc->args[2] = regs.r_rdx; fsc->args[3] = regs.r_rsi; fsc->args[4] = regs.r_rdi; sc = get_syscall(fsc->name); if (sc) fsc->nargs = sc->nargs; else { #if DEBUG fprintf(trussinfo->outfile, "unknown syscall %s -- setting " "args to %d\n", fsc->name, nargs); #endif fsc->nargs = nargs; } fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); fsc->sc = sc; /* * At this point, we set up the system call arguments. * We ignore any OUT ones, however -- those are arguments that * are set by the system call, and so are probably meaningless * now. This doesn't currently support arguments that are * passed in *and* out, however. */ if (fsc->name) { #if DEBUG fprintf(stderr, "syscall %s(", fsc->name); #endif for (i = 0; i < fsc->nargs; i++) { #if DEBUG fprintf(stderr, "0x%x%s", sc ? fsc->args[sc->args[i].offset] : fsc->args[i], i < (fsc->nargs - 1) ? "," : ""); #endif if (sc && !(sc->args[i].type & OUT)) { fsc->s_args[i] = print_arg(&sc->args[i], fsc->args, 0, trussinfo); } } #if DEBUG fprintf(stderr, ")\n"); #endif } #if DEBUG fprintf(trussinfo->outfile, "\n"); #endif if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 || strcmp(fsc->name, "exit") == 0)) { /* * XXX * This could be done in a more general * manner but it still wouldn't be very pretty. */ if (strcmp(fsc->name, "linux_execve") == 0) { if ((trussinfo->flags & EXECVEARGS) == 0) { if (fsc->s_args[1]) { free(fsc->s_args[1]); fsc->s_args[1] = NULL; } } if ((trussinfo->flags & EXECVEENVS) == 0) { if (fsc->s_args[2]) { free(fsc->s_args[2]); fsc->s_args[2] = NULL; } } } } trussinfo->curthread->fsc = fsc; }
static void linux_resume_one_process (struct inferior_list_entry *entry, int step, int signal) { struct process_info *process = (struct process_info *) entry; struct thread_info *saved_inferior; if (process->stopped == 0) return; /* If we have pending signals or status, and a new signal, enqueue the signal. Also enqueue the signal if we are waiting to reinsert a breakpoint; it will be picked up again below. */ if (signal != 0 && (process->status_pending_p || process->pending_signals != NULL || process->bp_reinsert != 0)) { struct pending_signals *p_sig; p_sig = malloc (sizeof (*p_sig)); p_sig->prev = process->pending_signals; p_sig->signal = signal; process->pending_signals = p_sig; } if (process->status_pending_p) return; saved_inferior = current_inferior; current_inferior = get_process_thread (process); if (debug_threads) fprintf (stderr, "Resuming process %d (%s, signal %d, stop %s)\n", inferior_pid, step ? "step" : "continue", signal, process->stop_expected ? "expected" : "not expected"); /* This bit needs some thinking about. If we get a signal that we must report while a single-step reinsert is still pending, we often end up resuming the thread. It might be better to (ew) allow a stack of pending events; then we could be sure that the reinsert happened right away and not lose any signals. Making this stack would also shrink the window in which breakpoints are uninserted (see comment in linux_wait_for_process) but not enough for complete correctness, so it won't solve that problem. It may be worthwhile just to solve this one, however. */ if (process->bp_reinsert != 0) { if (debug_threads) fprintf (stderr, " pending reinsert at %08lx", (long)process->bp_reinsert); if (step == 0) fprintf (stderr, "BAD - reinserting but not stepping.\n"); step = 1; /* Postpone any pending signal. It was enqueued above. */ signal = 0; } check_removed_breakpoint (process); if (debug_threads && the_low_target.get_pc != NULL) { fprintf (stderr, " "); (long) (*the_low_target.get_pc) (); } /* If we have pending signals, consume one unless we are trying to reinsert a breakpoint. */ if (process->pending_signals != NULL && process->bp_reinsert == 0) { struct pending_signals **p_sig; p_sig = &process->pending_signals; while ((*p_sig)->prev != NULL) p_sig = &(*p_sig)->prev; signal = (*p_sig)->signal; free (*p_sig); *p_sig = NULL; } regcache_invalidate_one ((struct inferior_list_entry *) get_process_thread (process)); errno = 0; process->stopped = 0; process->stepping = step; ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, process->lwpid, 0, signal); current_inferior = saved_inferior; if (errno) perror_with_name ("ptrace"); }
int main(int argc, char **argv) { int i; long page_size=getpagesize(); double error; long long start_before,stop_after; void *addr[MAX_EVENTS],*addr2[MAX_EVENTS]; struct perf_event_attr pe; int fd[MAX_EVENTS],fd2[MAX_EVENTS],ret1,ret2; int status; unsigned long long values[MAX_EVENTS],enabled[MAX_EVENTS],running[MAX_EVENTS]; unsigned long long values2[MAX_EVENTS],enabled2[MAX_EVENTS],running2[MAX_EVENTS]; int count=2; pid_t pid,pid2; quiet=test_quiet(); if (!quiet) { printf("This test checks if rdpmc multi-attach works.\n\n"); } /* See if we support rdpmc access */ if (!detect_rdpmc(quiet)) { test_skip(test_string); } /*********************************/ /* start and pause two children */ /*********************************/ /* fork a child */ pid = fork(); if ( pid < 0 ) { fprintf(stderr,"Failed fork\n"); test_fail(test_string); } else if (pid==0) { /* in child */ exit(wait_for_attach_and_loop(1)); } if ( ptrace( PTRACE_ATTACH, pid, NULL, NULL ) == -1 ) { fprintf(stderr,"Error attaching to %d\n",pid); return -1; } if ( waitpid( pid, &status, 0 ) == -1 ) { fprintf(stderr,"Error waitpid %d\n",pid); return -1; } if ( WIFSTOPPED( status ) == 0 ) { fprintf(stderr,"WIFSTOPPED didn't happen %d\n",pid); test_fail(test_string); } /* fork a second child */ pid2 = fork(); if ( pid2 < 0 ) { fprintf(stderr,"Failed fork\n"); test_fail(test_string); } else if (pid2==0) { /* in child */ exit(wait_for_attach_and_loop(2)); } if ( ptrace( PTRACE_ATTACH, pid2, NULL, NULL ) == -1 ) { fprintf(stderr,"Error attaching to %d\n",pid2); return -1; } if ( waitpid( pid2, &status, 0 ) == -1 ) { fprintf(stderr,"Error waitpid %d\n",pid2); return -1; } if ( WIFSTOPPED( status ) == 0 ) { fprintf(stderr,"WIFSTOPPED didn't happen %d\n",pid2); test_fail(test_string); } /*****************************/ /* TEST START/WORK/READ/STOP */ /*****************************/ /* Open event, pid1 */ memset(&pe,0,sizeof(struct perf_event_attr)); pe.type=PERF_TYPE_HARDWARE; pe.size=sizeof(struct perf_event_attr); fd[0]=-1; for(i=0;i<count;i++) { if (i==0) { pe.config=PERF_COUNT_HW_INSTRUCTIONS; pe.disabled=1; pe.pinned=1; } else { pe.config=PERF_COUNT_HW_CPU_CYCLES; pe.disabled=0; pe.pinned=0; } fd[i]=perf_event_open(&pe,pid,-1,fd[0],0); if (fd[i]<0) { fprintf(stderr,"Error opening event %d\n",i); test_fail(test_string); } /* mmap() event */ addr[i]=mmap(NULL,page_size, PROT_READ, MAP_SHARED,fd[i],0); if (addr[i] == MAP_FAILED) { fprintf(stderr,"Error mmap()ing event %d!\n",i); test_fail(test_string); } } /* Open event, pid2 */ memset(&pe,0,sizeof(struct perf_event_attr)); pe.type=PERF_TYPE_HARDWARE; pe.size=sizeof(struct perf_event_attr); fd2[0]=-1; for(i=0;i<count;i++) { if (i==0) { pe.config=PERF_COUNT_HW_INSTRUCTIONS; pe.disabled=1; pe.pinned=1; } else { pe.config=PERF_COUNT_HW_CPU_CYCLES; pe.disabled=0; pe.pinned=0; } fd2[i]=perf_event_open(&pe,pid2,-1,fd2[0],0); if (fd2[i]<0) { fprintf(stderr,"Error opening event %d\n",i); test_fail(test_string); } /* mmap() event */ addr2[i]=mmap(NULL,page_size, PROT_READ, MAP_SHARED,fd2[i],0); if (addr2[i] == MAP_FAILED) { fprintf(stderr,"Error mmap()ing event %d!\n",i); test_fail(test_string); } } /* start */ start_before=rdtsc(); ret1=ioctl(fd[0], PERF_EVENT_IOC_ENABLE,0); /* start up pid */ if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) { fprintf(stderr,"Couldn't continue %d\n",pid); return -1; } if ( waitpid( pid, &status, 0 ) == -1 ) { fprintf(stderr,"Couldn't waitpid() %d\n",pid ); return -1; } if ( WIFSTOPPED( status ) == 0 ) { test_fail(test_string); } if ( WSTOPSIG( status ) != SIGSTOP ) { test_fail(test_string); } ret1=ioctl(fd2[0], PERF_EVENT_IOC_ENABLE,0); /* start up pid2 */ if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) { fprintf(stderr,"Couldn't continue %d\n",pid2); return -1; } if ( waitpid( pid2, &status, 0 ) == -1 ) { fprintf(stderr,"Couldn't waitpid() %d\n",pid2 ); return -1; } if ( WIFSTOPPED( status ) == 0 ) { test_fail(test_string); } if ( WSTOPSIG( status ) != SIGSTOP ) { test_fail(test_string); } /* Wait for the SIGSTOP. */ if ( ptrace( PTRACE_CONT, pid, NULL, NULL ) == -1 ) { fprintf(stderr, "sigstop fail\n" ); return -1; } if ( waitpid( pid, &status, 0 ) == -1 ) { fprintf(stderr, "waitpid() pid\n" ); return -1; } if ( WIFSTOPPED( status ) == 0 ) { test_fail(test_string); } if ( WSTOPSIG( status ) != SIGSTOP ) { test_fail(test_string); } /* Wait for the SIGSTOP. */ if ( ptrace( PTRACE_CONT, pid2, NULL, NULL ) == -1 ) { fprintf(stderr, "sigstop fail\n" ); return -1; } if ( waitpid( pid2, &status, 0 ) == -1 ) { fprintf(stderr, "waitpid() pid\n" ); return -1; } if ( WIFSTOPPED( status ) == 0 ) { test_fail(test_string); } if ( WSTOPSIG( status ) != SIGSTOP ) { test_fail(test_string); } /* read */ for(i=0;i<count;i++) { values[i] = mmap_read_self(addr[i], &enabled[i], &running[i]); } /* stop */ ret2=ioctl(fd[0], PERF_EVENT_IOC_DISABLE,0); ret2=ioctl(fd2[0], PERF_EVENT_IOC_DISABLE,0); for(i=0;i<count;i++) { values2[i] = mmap_read_self(addr2[i], &enabled2[i], &running2[i]); } stop_after=rdtsc(); if (ret1<0) { fprintf(stderr,"Error starting!\n"); test_fail(test_string); } if (ret2<0) { fprintf(stderr,"Error stopping!\n"); test_fail(test_string); } if (values[0]<0) { if (!quiet) printf("rdpmc support not available.\n"); test_yellow_no(test_string); } for(i=0;i<count;i++) { close(fd[i]); close(fd2[i]); munmap(addr[i],page_size); munmap(addr2[i],page_size); } if (!quiet) { printf("Trying attach: %lld cycles\n", stop_after-start_before); for(i=0;i<count;i++) { if (values[i]==-1) { printf("\t* RDPMC 1 Event %x -- rdpmc not supported\n",i); } else { printf("\t* RDPMC 1 Event %x -- count: %lld enabled %lld running: %lld\n", i,values[i],enabled[i],running[i]); } } for(i=0;i<count;i++) { if (values2[i]==-1) { printf("\t* RDPMC 2 Event %x -- rdpmc not supported\n",i); } else { printf("\t* RDPMC 2 Event %x -- count: %lld enabled %lld running: %lld\n", i,values2[i],enabled2[i],running2[i]); } } } if (!quiet) printf("\n"); if ((values[0]!=-1) || (values2[0]!=-1)) { error=display_error(values[0], values[0], values[0], 1000000ULL,quiet); if ((error>10.0) || ( error<-10.0)) { if (!quiet) printf("Error out of range!\n"); test_fail(test_string); } error=display_error(values2[0], values2[0], values2[0], 2000000ULL,quiet); if ((error>10.0) || ( error<-10.0)) { if (!quiet) printf("Error out of range!\n"); test_fail(test_string); } if (!quiet) { printf("Should not have worked\n"); } test_fail(test_string); } for(i=0;i<count;i++) { close(fd[i]); munmap(addr[i],page_size); } test_pass(test_string); return 0; }
void * get_instruction_pointer(Process *proc) { return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_PC, 0); }
void sys_ptrace_cont(pid_t pid) { ptrace(PTRACE_CONT, pid, 0, 0); }
void set_instruction_pointer(Process *proc, void *addr) { ptrace(PTRACE_POKEUSER, proc->pid, 4 * PT_PC, addr); }
void check_trace(int start) { if (trace == DET_IGNORE || trace == DET_WARN) trace = DET_DIE; // return; #ifdef DEBUG trace = DET_IGNORE; #endif /* DEBUG */ if (trace == DET_IGNORE) return; pid_t parent = getpid(); /* we send ourselves a SIGTRAP, if we recieve, we're not being traced, otherwise we are. */ signal(SIGTRAP, got_sigtrap); traced = 1; raise(SIGTRAP); /* no longer need this__asm__("INT3"); //SIGTRAP */ signal(SIGTRAP, SIG_DFL); if (!traced) { signal(SIGINT, got_sigtrap); traced = 1; raise(SIGINT); signal(SIGINT, SIG_DFL); } if (traced) { if (start) { kill(parent, SIGKILL); exit(1); } else detected(DETECT_TRACE, STR("I'm being traced!")); } else { if (!start) return; #ifndef __sun__ int x, i; /* now, let's attempt to ptrace ourself */ switch ((x = fork())) { case -1: return; case 0: //child i = ptrace(PT_ATTACH, parent, 0, 0); /* EPERM is given on fbsd when security.bsd.unprivileged_proc_debug=0 */ if (i == -1 && errno != EPERM) { if (start) { kill(parent, SIGKILL); exit(1); } else detected(DETECT_TRACE, STR("I'm being traced!")); } else { waitpid(parent, NULL, 0); ptrace(PT_DETACH, parent, (char *) 1, 0); kill(parent, SIGCHLD); } exit(0); default: //parent waitpid(x, NULL, 0); } #endif } }
void * get_stack_pointer(Process *proc) { return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_USP, 0); }
static void found(int fd, char* peer_sig, pid_t pid) { UT_hash_table *tbl=NULL; UT_hash_bucket *bkts=NULL; UT_hash_handle hh; size_t i, bloom_len, bloom_bitlen, bloom_on_bits=0,bloom_off_bits=0; char *peer_tbl, *peer_bloom_sig, *peer_bloom_nbits, *peer_bloombv_ptr, *peer_bloombv, *peer_bkts, *peer_key, *peer_hh, *key=NULL; const char *hash_fcn = NULL; unsigned char *bloombv=NULL; static int fileno=0; char keyfile[50]; unsigned char bloom_nbits=0; int keyfd=-1, mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, hash_fcn_hits[NUM_HASH_FUNCS], hash_fcn_winner; unsigned max_chain=0; uint32_t bloomsig; int has_bloom_filter_fields = 0; for(i=0; i < NUM_HASH_FUNCS; i++) { hash_fcn_hits[i]=0; } if (getkeys) { snprintf(keyfile, sizeof(keyfile), "/tmp/%u-%u.key", (unsigned)pid,fileno++); if ( (keyfd = open(keyfile, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { fprintf(stderr, "can't open %s: %s\n", keyfile, strerror(errno)); exit(-1); } } vv("found signature at peer %p\n", (void*)peer_sig); peer_tbl = tbl_from_sig_addr(peer_sig); vvv("reading table at peer %p\n", (void*)peer_tbl); if ( (tbl = (UT_hash_table*)malloc(sizeof(UT_hash_table))) == NULL) { fprintf(stderr, "out of memory\n"); exit(-1); } #ifdef __FreeBSD__ if (read_mem(tbl, pid, (void *)peer_tbl, sizeof(UT_hash_table)) != 0) { #else if (read_mem(tbl, fd, (off_t)peer_tbl, sizeof(UT_hash_table)) != 0) { #endif fprintf(stderr, "failed to read peer memory\n"); goto done; } /* got the table. how about the buckets */ peer_bkts = (char*)tbl->buckets; vvv("reading buckets at peer %p\n", (void*)peer_bkts); bkts = (UT_hash_bucket*)malloc(sizeof(UT_hash_bucket)*tbl->num_buckets); if (bkts == NULL) { fprintf(stderr, "out of memory\n"); exit(-1); } #ifdef __FreeBSD__ if (read_mem(bkts, pid, (void *)peer_bkts, sizeof(UT_hash_bucket)*tbl->num_buckets) != 0) { #else if (read_mem(bkts, fd, (off_t)peer_bkts, sizeof(UT_hash_bucket)*tbl->num_buckets) != 0) { #endif fprintf(stderr, "failed to read peer memory\n"); goto done; } vvv("scanning %u peer buckets\n", tbl->num_buckets); for(i=0; i < tbl->num_buckets; i++) { vvv("bucket %u has %u items\n", (unsigned)i, (unsigned)(bkts[i].count)); if (bkts[i].count > max_chain) { max_chain = bkts[i].count; } if (bkts[i].expand_mult) { vvv(" bucket %u has expand_mult %u\n", (unsigned)i, (unsigned)(bkts[i].expand_mult)); } vvv("scanning bucket %u chain:\n", (unsigned)i); peer_hh = (char*)bkts[i].hh_head; while(peer_hh) { #ifdef __FreeBSD__ if (read_mem(&hh, pid, (void *)peer_hh, sizeof(hh)) != 0) { #else if (read_mem(&hh, fd, (off_t)peer_hh, sizeof(hh)) != 0) { #endif fprintf(stderr, "failed to read peer memory\n"); goto done; } if ((char*)hh.tbl != peer_tbl) { goto done; } peer_hh = (char*)hh.hh_next; peer_key = (char*)(hh.key); /* malloc space to read the key, and read it */ if ( (key = (char*)malloc(sizeof(hh.keylen))) == NULL) { fprintf(stderr, "out of memory\n"); exit(-1); } #ifdef __FreeBSD__ if (read_mem(key, pid, (void*)peer_key, hh.keylen) != 0) { #else if (read_mem(key, fd, (off_t)peer_key, hh.keylen) != 0) { #endif fprintf(stderr, "failed to read peer memory\n"); goto done; } hash_fcn_hits[infer_hash_function(key,hh.keylen,hh.hashv)]++; /* write the key if requested */ if (getkeys) { write(keyfd, &hh.keylen, sizeof(unsigned)); write(keyfd, key, hh.keylen); } free(key); key=NULL; } } /* does it have a bloom filter? */ peer_bloom_sig = peer_tbl + offsetof(UT_hash_table, bloom_sig); peer_bloombv_ptr = peer_tbl + offsetof(UT_hash_table, bloom_bv); peer_bloom_nbits = peer_tbl + offsetof(UT_hash_table, bloom_nbits); vvv("looking for bloom signature at peer %p\n", (void*)peer_bloom_sig); #ifdef __FreeBSD__ if ((read_mem(&bloomsig, pid, (void *)peer_bloom_sig, sizeof(uint32_t)) == 0) && (bloomsig == HASH_BLOOM_SIGNATURE)) { #else if ((read_mem(&bloomsig, fd, (off_t)peer_bloom_sig, sizeof(uint32_t)) == 0) && (bloomsig == HASH_BLOOM_SIGNATURE)) { #endif vvv("bloom signature (%x) found\n",bloomsig); /* bloom found. get at bv, nbits */ #ifdef __FreeBSD__ if (read_mem(&bloom_nbits, pid, (void *)peer_bloom_nbits, sizeof(char)) == 0) { #else if (read_mem(&bloom_nbits, fd, (off_t)peer_bloom_nbits, sizeof(char)) == 0) { #endif /* scan bloom filter, calculate saturation */ bloom_bitlen = (1ULL << bloom_nbits); bloom_len = (bloom_bitlen / 8) + ((bloom_bitlen % 8) ? 1 : 0); vvv("bloom bitlen is %u, bloom_bytelen is %u\n", (unsigned)bloom_bitlen, (unsigned)bloom_len); if ( (bloombv = (unsigned char*)malloc(bloom_len)) == NULL) { fprintf(stderr, "out of memory\n"); exit(-1); } /* read the address of the bitvector in the peer, then read the bv itself */ #ifdef __FreeBSD__ if ((read_mem(&peer_bloombv, pid, (void *)peer_bloombv_ptr, sizeof(void*)) == 0) && (read_mem(bloombv, pid, (void *)peer_bloombv, bloom_len) == 0)) { #else if ((read_mem(&peer_bloombv, fd, (off_t)peer_bloombv_ptr, sizeof(void*)) == 0) && (read_mem(bloombv, fd, (off_t)peer_bloombv, bloom_len) == 0)) { #endif /* calculate saturation */ vvv("read peer bloom bitvector from %p (%u bytes)\n", (void*)peer_bloombv, (unsigned)bloom_len); for(i=0; i < bloom_bitlen; i++) { if (HS_BIT_TEST(bloombv,(unsigned)i)) { /* vvv("bit %u set\n",(unsigned)i); */ bloom_on_bits++; } else { bloom_off_bits++; } } has_bloom_filter_fields = 1; vvv("there were %u on_bits among %u total bits\n", (unsigned)bloom_on_bits, (unsigned)bloom_bitlen); } } } /* choose apparent hash function */ hash_fcn_winner=0; for(i=0; i<NUM_HASH_FUNCS; i++) { if (hash_fcn_hits[i] > hash_fcn_hits[hash_fcn_winner]) { hash_fcn_winner=i; } } hash_fcn = hash_fcns[hash_fcn_winner]; /* Address ideal items buckets mc fl bloom sat fcn keys saved to ------------------ ----- -------- -------- -- -- ----- ----- --- ------------- 0x10aa4090 98% 10000000 32000000 10 ok BER /tmp/9110-0.key 0x10abcdef 100% 10000000 32000000 9 NX 27 12% BER /tmp/9110-1.key */ printf("Address ideal items buckets mc fl bloom sat fcn keys saved to\n"); printf("------------------ ----- -------- -------- -- -- ----- ----- --- -------------\n"); if (has_bloom_filter_fields) { printf("%-18p %4.0f%% %8u %8u %2u %2s %5u %4.0f%c %3s %s\n", (void*)peer_tbl, (tbl->num_items - tbl->nonideal_items) * 100.0 / tbl->num_items, tbl->num_items, tbl->num_buckets, max_chain, tbl->noexpand ? "NX" : "ok", bloom_nbits, bloom_on_bits * 100.0 / bloom_bitlen, '%', hash_fcn, (getkeys ? keyfile : "")); } else { printf("%-18p %4.0f%% %8u %8u %2u %2s %5s %4s%c %3s %s\n", (void*)peer_tbl, (tbl->num_items - tbl->nonideal_items) * 100.0 / tbl->num_items, tbl->num_items, tbl->num_buckets, max_chain, tbl->noexpand ? "NX" : "ok", "", "", ' ', hash_fcn, (getkeys ? keyfile : "")); } #if 0 printf("read peer tbl:\n"); printf("num_buckets: %u\n", tbl->num_buckets); printf("num_items: %u\n", tbl->num_items); printf("nonideal_items: %u (%.2f%%)\n", tbl->nonideal_items, tbl->nonideal_items*100.0/tbl->num_items); printf("expand: %s\n", tbl->noexpand ? "inhibited": "normal"); if (getkeys) { printf("keys written to %s\n", keyfile); } #endif done: if (bkts) { free(bkts); } if (tbl) { free(tbl); } if (key) { free(key); } if (keyfd != -1) { close(keyfd); } if (bloombv) { free(bloombv); } } #ifdef __FreeBSD__ static void sigscan(pid_t pid, void *start, void *end, uint32_t sig) { struct ptrace_io_desc io_desc; int page_size = getpagesize(); char *buf; char *pos; /* make sure page_size is a multiple of the signature size, code below assumes this */ assert(page_size % sizeof(sig) == 0); buf = malloc(page_size); if (buf == NULL) { fprintf(stderr, "malloc failed in sigscan()\n"); return; } io_desc.piod_op = PIOD_READ_D; io_desc.piod_offs = start; io_desc.piod_addr = buf; io_desc.piod_len = page_size; /* read in one page after another and search sig */ while(!ptrace(PT_IO, pid, (void *) &io_desc, 0)) { if (io_desc.piod_len != page_size) { fprintf(stderr, "PT_IO returned less than page size in sigscan()\n"); return; } /* iterate over the the page using the signature size and look for the sig */ for (pos = buf; pos < (buf + page_size); pos += sizeof(sig)) { if (*(uint32_t *) pos == sig) { found(pid, (char *) io_desc.piod_offs + (pos - buf), pid); } } /* * 'end' is inclusive (the address of the last valid byte), so if the current offset * plus a page is beyond 'end', we're already done. since all vm map entries consist * of entire pages and 'end' is inclusive, current offset plus one page should point * exactly one byte beyond 'end'. this is assert()ed below to be on the safe side. */ if (io_desc.piod_offs + page_size > end) { assert(io_desc.piod_offs + page_size == (end + 1)); break; } /* advance to the next page */ io_desc.piod_offs += page_size; } } #else static void sigscan(int fd, off_t start, off_t end, uint32_t sig, pid_t pid) { int rlen; uint32_t u; off_t at=0; if (lseek(fd, start, SEEK_SET) == (off_t)-1) { fprintf(stderr, "lseek failed: %s\n", strerror(errno)); return; } while ( (rlen = read(fd,&u,sizeof(u))) == sizeof(u)) { if (!memcmp(&u,&sig,sizeof(u))) { found(fd, (char*)(start+at),pid); } at += sizeof(u); if ((off_t)(at + sizeof(u)) > end-start) { break; } } if (rlen == -1) { //fprintf(stderr,"read failed: %s\n", strerror(errno)); //exit(-1); } } #endif #ifdef __FreeBSD__ static int scan(pid_t pid) { vma_t *vmas=NULL, vma; unsigned i, num_vmas = 0; int ret; struct ptrace_vm_entry vm_entry; char path[MAXPATHLEN]; vv("attaching to peer\n"); if (ptrace(PT_ATTACH,pid,NULL,0) == -1) { fprintf(stderr,"failed to attach to %u: %s\n", (unsigned)pid, strerror(errno)); exit(EXIT_FAILURE); } vv("waiting for peer to suspend temporarily\n"); if (waitpid(pid,NULL,0) != pid) { fprintf(stderr,"failed to wait for pid %u: %s\n",(unsigned)pid, strerror(errno)); goto die; } /* read memory map using ptrace */ vv("listing peer virtual memory areas\n"); vm_entry.pve_entry = 0; vm_entry.pve_path = path; /* not used but required to make vm_entry.pve_pathlen work */ while(1) { /* set pve_pathlen every turn, it gets overwritten by ptrace */ vm_entry.pve_pathlen = MAXPATHLEN; errno = 0; ret = ptrace(PT_VM_ENTRY, pid, (void *) &vm_entry, 0); if (ret) { if (errno == ENOENT) { /* we've reached the last entry */ break; } fprintf(stderr, "fetching vm map entry failed: %s (%i)\n", strerror(errno), errno); goto die; } vvv("vmmap entry: start: %p, end: %p", (void *) vm_entry.pve_start, (void *) vm_entry.pve_end); /* skip unreadable or vnode-backed entries */ if (!(vm_entry.pve_prot & VM_PROT_READ) || vm_entry.pve_pathlen > 0) { vvv(" -> skipped (not readable or vnode-backed)\n"); vm_entry.pve_path[0] = 0; continue; } /* useful entry, add to list */ vvv(" -> will be scanned\n"); vma.start = (void *)vm_entry.pve_start; vma.end = (void *)vm_entry.pve_end; vmas = (vma_t *) realloc(vmas, (num_vmas + 1) * sizeof(vma_t)); if (vmas == NULL) { exit(-1); } vmas[num_vmas++] = vma; } vv("peer has %u virtual memory areas\n", num_vmas); /* look for the hash signature */ vv("scanning peer memory for hash table signatures\n"); for(i=0; i<num_vmas; i++) { vma = vmas[i]; sigscan(pid, vma.start, vma.end, sig); } die: vv("detaching and resuming peer\n"); if (ptrace(PT_DETACH, pid, NULL, 0) == -1) { fprintf(stderr,"failed to detach from %u: %s\n", (unsigned)pid, strerror(errno)); } return 0; } # else static int scan(pid_t pid) { FILE *mapf; char mapfile[30], memfile[30], line[100]; vma_t *vmas=NULL, vma; unsigned i, num_vmas = 0; int memfd; void *pstart, *pend, *unused; /* attach to the target process and wait for it to suspend */ vv("attaching to peer\n"); if (ptrace(PTRACE_ATTACH,pid,NULL,NULL) == -1) { fprintf(stderr,"failed to attach to %u: %s\n", (unsigned)pid, strerror(errno)); exit(-1); } vv("waiting for peer to suspend temporarily\n"); if (waitpid(pid,NULL,0) != pid) { fprintf(stderr,"failed to wait for pid %u: %s\n",(unsigned)pid, strerror(errno)); goto die; } /* get ready to open its memory map. this gives us its valid memory areas */ snprintf(mapfile,sizeof(mapfile),"/proc/%u/maps",(unsigned)pid); snprintf(memfile,sizeof(memfile),"/proc/%u/mem", (unsigned)pid); vv("opening peer memory map [%s]\n", mapfile); if ( (mapf = fopen(mapfile,"r")) == NULL) { fprintf(stderr,"failed to open %s: %s\n", mapfile, strerror(errno)); goto die; } vv("listing peer virtual memory areas\n"); while(fgets(line,sizeof(line),mapf)) { if (sscanf(line, "%p-%p %4c %p %5c", &pstart, &pend, vma.perms, &unused, vma.device) == 5) { vma.start = (off_t)pstart; vma.end = (off_t)pend; if (vma.perms[0] != 'r') { continue; /* only readable vma's */ } if (memcmp(vma.device,"fd",2)==0) { continue; /* skip mapped files */ } vmas = (vma_t*)realloc(vmas, (num_vmas+1) * sizeof(vma_t)); if (vmas == NULL) { exit(-1); } vmas[num_vmas++] = vma; } } vv("peer has %u virtual memory areas\n",num_vmas); fclose(mapf); /* ok, open up its memory and start looking around in there */ vv("opening peer memory\n"); if ( (memfd=open(memfile,O_RDONLY)) == -1) { fprintf(stderr,"failed to open %s: %s\n", memfile, strerror(errno)); goto die; } /* look for the hash signature */ vv("scanning peer memory for hash table signatures\n"); for(i=0; i<num_vmas; i++) { vma = vmas[i]; pstart = (void*)vma.start; pend = (void*)vma.end; /*fprintf(stderr,"scanning %p-%p %.4s %.5s\n", pstart, pend, vma.perms, vma.device);*/ sigscan(memfd, vma.start, vma.end, sig, pid); } /* done. close memory and detach. this resumes the target process */ close(memfd); die: vv("detaching and resuming peer\n"); if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) { fprintf(stderr,"failed to detach from %u: %s\n", (unsigned)pid, strerror(errno)); } return 0; } #endif static int usage(const char *prog) { fprintf(stderr,"usage: %s [-v] [-k] <pid>\n", prog); return -1; } int main(int argc, char *argv[]) { int opt; while ( (opt = getopt(argc, argv, "kv")) != -1) { switch (opt) { case 'v': verbose++; break; case 'k': getkeys++; break; default: return usage(argv[0]); } } if (optind < argc) { pid_t pid = atoi(argv[optind++]); return scan(pid); } else { return usage(argv[0]); } }
void * get_return_addr(Process *proc, void *stack_pointer) { return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0); }
int save_fp_registers(int pid, unsigned long *fp_regs) { if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) return -errno; return 0; }
static void store_register (const struct regcache *regcache, int regno) { struct gdbarch *gdbarch = get_regcache_arch (regcache); struct reg inferior_registers; int ret; ret = ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid), (PTRACE_TYPE_ARG3) &inferior_registers, ptid_get_lwp(inferior_ptid)); if (ret < 0) { warning (_("unable to fetch general registers")); return; } switch (regno) { case ARM_SP_REGNUM: regcache_raw_collect (regcache, ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); break; case ARM_LR_REGNUM: regcache_raw_collect (regcache, ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); break; case ARM_PC_REGNUM: if (arm_apcs_32) regcache_raw_collect (regcache, ARM_PC_REGNUM, (char *) &inferior_registers.r_pc); else { unsigned pc_val; regcache_raw_collect (regcache, ARM_PC_REGNUM, (char *) &pc_val); pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val); inferior_registers.r_pc ^= gdbarch_addr_bits_remove (gdbarch, inferior_registers.r_pc); inferior_registers.r_pc |= pc_val; } break; case ARM_PS_REGNUM: if (arm_apcs_32) regcache_raw_collect (regcache, ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr); else { unsigned psr_val; regcache_raw_collect (regcache, ARM_PS_REGNUM, (char *) &psr_val); psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val); inferior_registers.r_pc = gdbarch_addr_bits_remove (gdbarch, inferior_registers.r_pc); inferior_registers.r_pc |= psr_val; } break; default: regcache_raw_collect (regcache, regno, (char *) &inferior_registers.r[regno]); break; } ret = ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid), (PTRACE_TYPE_ARG3) &inferior_registers, ptid_get_lwp(inferior_ptid)); if (ret < 0) warning (_("unable to write register %d to inferior"), regno); }