static char* undefined_scno_name(struct tcb *tcp) { static char buf[sizeof("syscall_%lu") + sizeof(long)*3]; sprintf(buf, "syscall_%lu", shuffle_scno(tcp->scno)); return buf; }
static long ptrace_getregset(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 } # ifndef HAVE_GETREGS_OLD # define ptrace_setregset_or_setregs ptrace_setregset static int ptrace_setregset(pid_t pid) { # ifdef ARCH_IOVEC_FOR_GETREGSET /* variable iovec */ return ptrace(PTRACE_SETREGSET, 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_SETREGSET, pid, NT_PRSTATUS, &io); # endif } # endif /* !HAVE_GETREGS_OLD */ #elif defined ARCH_REGS_FOR_GETREGS # define ptrace_getregset_or_getregs ptrace_getregs static long ptrace_getregs(pid_t pid) { # if defined SPARC || defined SPARC64 /* SPARC systems have the meaning of data and addr reversed */ return ptrace(PTRACE_GETREGS, pid, (void *) &ARCH_REGS_FOR_GETREGS, 0); # else return ptrace(PTRACE_GETREGS, pid, NULL, &ARCH_REGS_FOR_GETREGS); # endif } # ifndef HAVE_GETREGS_OLD # define ptrace_setregset_or_setregs ptrace_setregs static int ptrace_setregs(pid_t pid) { # if defined SPARC || defined SPARC64 /* SPARC systems have the meaning of data and addr reversed */ return ptrace(PTRACE_SETREGS, pid, (void *) &ARCH_REGS_FOR_GETREGS, 0); # else return ptrace(PTRACE_SETREGS, pid, NULL, &ARCH_REGS_FOR_GETREGS); # endif } # endif /* !HAVE_GETREGS_OLD */ #endif /* ARCH_REGS_FOR_GETREGSET || ARCH_REGS_FOR_GETREGS */ static void get_regs(pid_t pid) { #undef USE_GET_SYSCALL_RESULT_REGS #ifdef ptrace_getregset_or_getregs if (get_regs_error != -1) return; # ifdef HAVE_GETREGS_OLD /* * Try PTRACE_GETREGSET/PTRACE_GETREGS first, * fallback to getregs_old. */ static int use_getregs_old; if (use_getregs_old < 0) { get_regs_error = ptrace_getregset_or_getregs(pid); return; } else if (use_getregs_old == 0) { get_regs_error = ptrace_getregset_or_getregs(pid); if (get_regs_error >= 0) { use_getregs_old = -1; return; } if (errno == EPERM || errno == ESRCH) return; use_getregs_old = 1; } get_regs_error = getregs_old(pid); # else /* !HAVE_GETREGS_OLD */ /* Assume that PTRACE_GETREGSET/PTRACE_GETREGS works. */ get_regs_error = ptrace_getregset_or_getregs(pid); # endif /* !HAVE_GETREGS_OLD */ #else /* !ptrace_getregset_or_getregs */ # define USE_GET_SYSCALL_RESULT_REGS 1 # warning get_regs is not implemented for this architecture yet get_regs_error = 0; #endif /* !ptrace_getregset_or_getregs */ } #ifdef ptrace_setregset_or_setregs static int set_regs(pid_t pid) { return ptrace_setregset_or_setregs(pid); } #endif /* ptrace_setregset_or_setregs */ struct sysent_buf { struct tcb *tcp; struct_sysent ent; char buf[sizeof("syscall_%lu") + sizeof(kernel_ulong_t) * 3]; }; static void free_sysent_buf(void *ptr) { struct sysent_buf *s = ptr; s->tcp->s_prev_ent = s->tcp->s_ent = NULL; free(ptr); } /* * Returns: * 0: "ignore this ptrace stop", syscall_entering_decode() should return a "bail * out silently" code. * 1: ok, continue in syscall_entering_decode(). * other: error, syscall_entering_decode() should print error indicator * ("????" etc) and return an appropriate code. */ int get_scno(struct tcb *tcp) { get_regs(tcp->pid); if (get_regs_error) return -1; int rc = arch_get_scno(tcp); if (rc != 1) return rc; if (scno_is_valid(tcp->scno)) { tcp->s_ent = &sysent[tcp->scno]; tcp->qual_flg = qual_flags(tcp->scno); } else { struct sysent_buf *s = xcalloc(1, sizeof(*s)); s->tcp = tcp; s->ent.nargs = MAX_ARGS; s->ent.sen = SEN_printargs; s->ent.sys_func = printargs; s->ent.sys_name = s->buf; sprintf(s->buf, "syscall_%" PRI_klu, shuffle_scno(tcp->scno)); tcp->s_ent = &s->ent; tcp->qual_flg = QUAL_RAW | DEFAULT_QUAL_FLAGS; set_tcb_priv_data(tcp, s, free_sysent_buf); if (debug_flag) error_msg("pid %d invalid syscall %" PRI_kld, tcp->pid, tcp->scno); } return 1; } #ifdef USE_GET_SYSCALL_RESULT_REGS static int get_syscall_result_regs(struct tcb *); #endif /* Returns: * 1: ok, continue in syscall_exiting_trace(). * -1: error, syscall_exiting_trace() should print error indicator * ("????" etc) and bail out. */ static int get_syscall_result(struct tcb *tcp) { #ifdef USE_GET_SYSCALL_RESULT_REGS if (get_syscall_result_regs(tcp)) return -1; #endif tcp->u_error = 0; get_error(tcp, !(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS)); return 1; } #include "get_scno.c" #include "set_scno.c" #include "get_syscall_args.c" #ifdef USE_GET_SYSCALL_RESULT_REGS # include "get_syscall_result.c" #endif #include "get_error.c" #include "set_error.c" #ifdef HAVE_GETREGS_OLD # include "getregs_old.c" #endif const char * syscall_name(kernel_ulong_t scno) { #if defined X32_PERSONALITY_NUMBER && defined __X32_SYSCALL_BIT if (current_personality == X32_PERSONALITY_NUMBER) scno &= ~__X32_SYSCALL_BIT; #endif return scno_is_valid(scno) ? sysent[scno].sys_name : NULL; }