long int ptrace (enum __ptrace_request __request, ...) { pid_t pid; void *addr, *data; va_list ap; va_start(ap, __request); pid = va_arg(ap, pid_t); addr = va_arg(ap, void *); data = va_arg(ap, void *); va_end(ap); if(__request == PTRACE_GETREGS) { return get_regs(pid, addr, data); } else if(__request == PTRACE_SETREGS) { return set_regs(pid, addr, data); } #if 0 //some old system may require this command to get register else if(__request == PTRACE_PEEKUSER) { } #endif else if(__request == PTRACE_GETFPREGS) { return get_fpregs(pid, addr, data, FALSE); } else if(__request == PTRACE_SETFPREGS) { return set_fpregs(pid, addr, data, FALSE); } else if(__request == PTRACE_GETFPXREGS) { return get_fpregs(pid, addr, data, TRUE); } else if(__request == PTRACE_SETFPXREGS) { return set_fpregs(pid, addr, data, TRUE); } //xstave for avx else if(__request == PTRACE_GETREGSET) { return get_regset(pid, addr, data); } else if(__request == PTRACE_SETREGSET) { return set_regset(pid, addr, data); } //For other request just forward it to real ptrace call; return g_sys_ptrace(__request, pid, addr, data); }
static long get_regset(pid_t pid) { # ifdef ARCH_IOVEC_FOR_GETREGSET /* variable iovec */ ARCH_IOVEC_FOR_GETREGSET.iov_len = sizeof(ARCH_REGS_FOR_GETREGSET); return ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &ARCH_IOVEC_FOR_GETREGSET); # else /* constant iovec */ static struct iovec io = { .iov_base = &ARCH_REGS_FOR_GETREGSET, .iov_len = sizeof(ARCH_REGS_FOR_GETREGSET) }; return ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &io); # endif } #endif /* ARCH_REGS_FOR_GETREGSET */ void get_regs(pid_t pid) { #ifdef ARCH_REGS_FOR_GETREGSET # ifdef X86_64 /* Try PTRACE_GETREGSET first, fallback to PTRACE_GETREGS. */ static int getregset_support; if (getregset_support >= 0) { get_regs_error = get_regset(pid); if (getregset_support > 0) return; if (get_regs_error >= 0) { getregset_support = 1; return; } if (errno == EPERM || errno == ESRCH) return; getregset_support = -1; } getregs_old(pid); # else /* !X86_64 */ /* Assume that PTRACE_GETREGSET works. */ get_regs_error = get_regset(pid); # endif #elif defined ARCH_REGS_FOR_GETREGS # if defined SPARC || defined SPARC64 /* SPARC systems have the meaning of data and addr reversed */ get_regs_error = ptrace(PTRACE_GETREGS, pid, (char *)&ARCH_REGS_FOR_GETREGS, 0); # elif defined POWERPC static bool old_kernel = 0; if (old_kernel) goto old; get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, &ARCH_REGS_FOR_GETREGS); if (get_regs_error && errno == EIO) { old_kernel = 1; old: get_regs_error = getregs_old(pid); } # else /* Assume that PTRACE_GETREGS works. */ get_regs_error = ptrace(PTRACE_GETREGS, pid, NULL, &ARCH_REGS_FOR_GETREGS); # endif #else /* !ARCH_REGS_FOR_GETREGSET && !ARCH_REGS_FOR_GETREGS */ # warning get_regs is not implemented for this architecture yet get_regs_error = 0; #endif } /* Returns: * 0: "ignore this ptrace stop", bail out of trace_syscall_entering() silently. * 1: ok, continue in trace_syscall_entering(). * other: error, trace_syscall_entering() should print error indicator * ("????" etc) and bail out. */ int get_scno(struct tcb *tcp) { if (get_regs_error) return -1; long scno = 0; #include "get_scno.c" tcp->scno = scno; if (SCNO_IS_VALID(tcp->scno)) { tcp->s_ent = &sysent[scno]; tcp->qual_flg = qual_flags[scno]; } else { static const struct_sysent unknown = { .nargs = MAX_ARGS, .sys_flags = 0, .sys_func = printargs, .sys_name = "system call", }; tcp->s_ent = &unknown; tcp->qual_flg = UNDEFINED_SCNO | QUAL_RAW | DEFAULT_QUAL_FLAGS; if (debug_flag) fprintf(stderr, "pid %d invalid syscall %ld\n", tcp->pid, scno); } return 1; } /* Return -1 on error or 1 on success (never 0!) */ static int get_syscall_args(struct tcb *tcp) { #include "get_syscall_args.c" return 1; } static void get_error(struct tcb *tcp) { const bool check_errno = !(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS); tcp->u_error = 0; #include "get_error.c" } /* Returns: * 1: ok, continue in trace_syscall_exiting(). * -1: error, trace_syscall_exiting() should print error indicator * ("????" etc) and bail out. */ static int get_syscall_result(struct tcb *tcp) { #if defined ARCH_REGS_FOR_GETREGSET || defined ARCH_REGS_FOR_GETREGS /* already done by get_regs */ #else # include "get_syscall_result.c" #endif get_error(tcp); return 1; }