/* * PTRACE_GETREGS was added to the PowerPC kernel in v2.6.23, * we provide a slow fallback for old kernels. */ static int getregs_old(pid_t pid) { int i; long r; if (iflag) { r = upeek(pid, sizeof(long) * PT_NIP, (long *)&ppc_regs.nip); if (r) goto out; } #ifdef POWERPC64 /* else we never use it */ r = upeek(pid, sizeof(long) * PT_MSR, (long *)&ppc_regs.msr); if (r) goto out; #endif r = upeek(pid, sizeof(long) * PT_CCR, (long *)&ppc_regs.ccr); if (r) goto out; r = upeek(pid, sizeof(long) * PT_ORIG_R3, (long *)&ppc_regs.orig_gpr3); if (r) goto out; for (i = 0; i <= 8; i++) { r = upeek(pid, sizeof(long) * (PT_R0 + i), (long *)&ppc_regs.gpr[i]); if (r) goto out; } out: return r; }
/* Return codes: 1 - ok, 0 - ignore, other - error. */ static int arch_get_scno(struct tcb *tcp) { long scno = 0; /* * In the new syscall ABI, the system call number is in R3. */ if (upeek(tcp->pid, 4*(REG_REG0+3), &scno) < 0) return -1; if (scno < 0) { /* Odd as it may seem, a glibc bug has been known to cause glibc to issue bogus negative syscall numbers. So for our purposes, make strace print what it *should* have been */ long correct_scno = (scno & 0xff); if (debug_flag) error_msg("Detected glibc bug: bogus system call" " number = %ld, correcting to %ld", scno, correct_scno); scno = correct_scno; } tcp->scno = scno; return 1; }
/* Return -1 on error or 1 on success (never 0!). */ static int get_syscall_args(struct tcb *tcp) { unsigned int i; for (i = 0; i < tcp->s_ent->nargs; ++i) if (upeek(tcp->pid, (5 + i) * 4, &tcp->u_arg[i]) < 0) return -1; return 1; }
/* Return -1 on error or 1 on success (never 0!). */ static int get_syscall_args(struct tcb *tcp) { /* Registers used by SH5 Linux system calls for parameters */ static const int syscall_regs[MAX_ARGS] = { 2, 3, 4, 5, 6, 7 }; unsigned int i; for (i = 0; i < tcp->s_ent->nargs; ++i) if (upeek(tcp->pid, REG_GENERAL(syscall_regs[i]), &tcp->u_arg[i]) < 0) return -1; return 1; }
/* Return -1 on error or 1 on success (never 0!). */ static int get_syscall_args(struct tcb *tcp) { static const int argreg[MAX_ARGS] = { PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5 }; unsigned int i; for (i = 0; i < tcp->s_ent->nargs; ++i) if (upeek(tcp, argreg[i], &tcp->u_arg[i]) < 0) return -1; return 1; }
/* Return -1 on error or 1 on success (never 0!). */ static int get_syscall_args(struct tcb *tcp) { static const int crisregs[MAX_ARGS] = { 4*PT_ORIG_R10, 4*PT_R11, 4*PT_R12, 4*PT_R13 , 4*PT_MOF, 4*PT_SRP }; unsigned int i; for (i = 0; i < tcp->s_ent->nargs; ++i) if (upeek(tcp->pid, crisregs[i], &tcp->u_arg[i]) < 0) return -1; return 1; }
static int get_syscall_result_regs(struct tcb *tcp) { return (upeek(tcp, REG_A3, &alpha_a3) < 0 || upeek(tcp, REG_R0, &alpha_r0) < 0) ? -1 : 0; }
int sys_sigreturn(struct tcb *tcp) { #if defined(ARM) if (entering(tcp)) { struct sigcontext_struct sc; sigset_t sigm; if (umove(tcp, arm_regs.ARM_sp, &sc) < 0) return 0; long_to_sigset(sc.oldmask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(S390) || defined(S390X) if (entering(tcp)) { long usp; struct sigcontext_struct sc; if (upeek(tcp, PT_GPR15, &usp) < 0) return 0; if (umove(tcp, usp + __SIGNAL_FRAMESIZE, &sc) < 0) return 0; tprints(sprintsigmask(") (mask ", (sigset_t *)&sc.oldmask[0], 0)); } #elif defined(I386) if (entering(tcp)) { struct sigcontext_struct sc; /* Note: on i386, sc is followed on stack by struct fpstate * and after it an additional u32 extramask[1] which holds * upper half of the mask. We can fetch it there * if/when we'd want to display the full mask... */ sigset_t sigm; if (umove(tcp, i386_regs.esp, &sc) < 0) return 0; long_to_sigset(sc.oldmask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(IA64) if (entering(tcp)) { struct sigcontext sc; long sp; sigset_t sigm; /* offset of sigcontext in the kernel's sigframe structure: */ # define SIGFRAME_SC_OFFSET 0x90 if (upeek(tcp, PT_R12, &sp) < 0) return 0; if (umove(tcp, sp + 16 + SIGFRAME_SC_OFFSET, &sc) < 0) return 0; sigemptyset(&sigm); memcpy(&sigm, &sc.sc_mask, NSIG / 8); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(POWERPC) if (entering(tcp)) { long esp; struct sigcontext_struct sc; sigset_t sigm; if (upeek(tcp, sizeof(unsigned long) * PT_R1, &esp) < 0) return 0; /* Skip dummy stack frame. */ #ifdef POWERPC64 if (current_personality == 0) esp += 128; else esp += 64; #else esp += 64; #endif if (umove(tcp, esp, &sc) < 0) return 0; long_to_sigset(sc.oldmask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(M68K) if (entering(tcp)) { long usp; struct sigcontext sc; sigset_t sigm; if (upeek(tcp, 4*PT_USP, &usp) < 0) return 0; if (umove(tcp, usp, &sc) < 0) return 0; long_to_sigset(sc.sc_mask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(ALPHA) if (entering(tcp)) { long fp; struct sigcontext_struct sc; sigset_t sigm; if (upeek(tcp, REG_FP, &fp) < 0) return 0; if (umove(tcp, fp, &sc) < 0) return 0; long_to_sigset(sc.sc_mask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(SPARC) || defined(SPARC64) if (entering(tcp)) { long i1; m_siginfo_t si; sigset_t sigm; i1 = sparc_regs.u_regs[U_REG_O1]; if (umove(tcp, i1, &si) < 0) { perror_msg("%s", "sigreturn: umove"); return 0; } long_to_sigset(si.si_mask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64) /* This decodes rt_sigreturn. The 64-bit ABIs do not have sigreturn. */ if (entering(tcp)) { long sp; struct ucontext uc; sigset_t sigm; if (upeek(tcp, REG_SP, &sp) < 0) return 0; /* There are six words followed by a 128-byte siginfo. */ sp = sp + 6 * 4 + 128; if (umove(tcp, sp, &uc) < 0) return 0; long_to_sigset(*(long *) &uc.uc_sigmask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(MIPS) if (entering(tcp)) { long sp; struct pt_regs regs; m_siginfo_t si; sigset_t sigm; if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { perror_msg("%s", "sigreturn: PTRACE_GETREGS"); return 0; } sp = regs.regs[29]; if (umove(tcp, sp, &si) < 0) return 0; long_to_sigset(si.si_mask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(CRISV10) || defined(CRISV32) if (entering(tcp)) { struct sigcontext sc; long regs[PT_MAX+1]; sigset_t sigm; if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long)regs) < 0) { perror_msg("%s", "sigreturn: PTRACE_GETREGS"); return 0; } if (umove(tcp, regs[PT_USP], &sc) < 0) return 0; long_to_sigset(sc.oldmask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(TILE) if (entering(tcp)) { struct ucontext uc; sigset_t sigm; /* offset of ucontext in the kernel's sigframe structure */ # define SIGFRAME_UC_OFFSET C_ABI_SAVE_AREA_SIZE + sizeof(struct siginfo) if (umove(tcp, tile_regs.sp + SIGFRAME_UC_OFFSET, &uc) < 0) return 0; sigemptyset(&sigm); memcpy(&sigm, &uc.uc_sigmask, NSIG / 8); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(MICROBLAZE) /* TODO: Verify that this is correct... */ if (entering(tcp)) { struct sigcontext sc; long sp; sigset_t sigm; /* Read r1, the stack pointer. */ if (upeek(tcp, 1 * 4, &sp) < 0) return 0; if (umove(tcp, sp, &sc) < 0) return 0; long_to_sigset(sc.oldmask, &sigm); tprints(sprintsigmask(") (mask ", &sigm, 0)); } #elif defined(X86_64) /* no need to remind */ #else # warning No sys_sigreturn() for this architecture # warning (no problem, just a reminder :-) #endif return 0; }
int sys_sigreturn(struct tcb *tcp) { #if defined(ARM) if (entering(tcp)) { struct arm_sigcontext { unsigned long trap_no; unsigned long error_code; unsigned long oldmask; unsigned long arm_r0; unsigned long arm_r1; unsigned long arm_r2; unsigned long arm_r3; unsigned long arm_r4; unsigned long arm_r5; unsigned long arm_r6; unsigned long arm_r7; unsigned long arm_r8; unsigned long arm_r9; unsigned long arm_r10; unsigned long arm_fp; unsigned long arm_ip; unsigned long arm_sp; unsigned long arm_lr; unsigned long arm_pc; unsigned long arm_cpsr; unsigned long fault_address; }; struct arm_ucontext { unsigned long uc_flags; unsigned long uc_link; /* struct ucontext* */ /* The next three members comprise stack_t struct: */ unsigned long ss_sp; /* void* */ unsigned long ss_flags; /* int */ unsigned long ss_size; /* size_t */ struct arm_sigcontext sc; /* These two members are sigset_t: */ unsigned long uc_sigmask[2]; /* more fields follow, which we aren't interested in */ }; struct arm_ucontext uc; if (umove(tcp, arm_regs.ARM_sp, &uc) < 0) return 0; /* * Kernel fills out uc.sc.oldmask too when it sets up signal stack, * but for sigmask restore, sigreturn syscall uses uc.uc_sigmask instead. */ tprintsigmask_addr(") (mask ", uc.uc_sigmask); } #elif defined(S390) || defined(S390X) if (entering(tcp)) { long usp; struct sigcontext sc; if (upeek(tcp->pid, PT_GPR15, &usp) < 0) return 0; if (umove(tcp, usp + __SIGNAL_FRAMESIZE, &sc) < 0) return 0; tprintsigmask_addr(") (mask ", sc.oldmask); } #elif defined(I386) || defined(X86_64) # if defined(X86_64) if (current_personality == 0) /* 64-bit */ return 0; # endif if (entering(tcp)) { struct i386_sigcontext_struct { uint16_t gs, __gsh; uint16_t fs, __fsh; uint16_t es, __esh; uint16_t ds, __dsh; uint32_t edi; uint32_t esi; uint32_t ebp; uint32_t esp; uint32_t ebx; uint32_t edx; uint32_t ecx; uint32_t eax; uint32_t trapno; uint32_t err; uint32_t eip; uint16_t cs, __csh; uint32_t eflags; uint32_t esp_at_signal; uint16_t ss, __ssh; uint32_t i387; uint32_t oldmask; uint32_t cr2; }; struct i386_fpstate { uint32_t cw; uint32_t sw; uint32_t tag; uint32_t ipoff; uint32_t cssel; uint32_t dataoff; uint32_t datasel; uint8_t st[8][10]; /* 8*10 bytes: FP regs */ uint16_t status; uint16_t magic; uint32_t fxsr_env[6]; uint32_t mxcsr; uint32_t reserved; uint8_t stx[8][16]; /* 8*16 bytes: FP regs, each padded to 16 bytes */ uint8_t xmm[8][16]; /* 8 XMM regs */ uint32_t padding1[44]; uint32_t padding2[12]; /* union with struct _fpx_sw_bytes */ }; struct { struct i386_sigcontext_struct sc; struct i386_fpstate fp; uint32_t extramask[1]; } signal_stack; /* On i386, sc is followed on stack by struct fpstate * and after it an additional u32 extramask[1] which holds * upper half of the mask. */ uint32_t sigmask[2]; if (umove(tcp, *i386_esp_ptr, &signal_stack) < 0) return 0; sigmask[0] = signal_stack.sc.oldmask; sigmask[1] = signal_stack.extramask[0]; tprintsigmask_addr(") (mask ", sigmask); } #elif defined(IA64) if (entering(tcp)) { struct sigcontext sc; long sp; /* offset of sigcontext in the kernel's sigframe structure: */ # define SIGFRAME_SC_OFFSET 0x90 if (upeek(tcp->pid, PT_R12, &sp) < 0) return 0; if (umove(tcp, sp + 16 + SIGFRAME_SC_OFFSET, &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.sc_mask); } #elif defined(POWERPC) if (entering(tcp)) { long esp; struct sigcontext sc; esp = ppc_regs.gpr[1]; /* Skip dummy stack frame. */ #ifdef POWERPC64 if (current_personality == 0) esp += 128; else esp += 64; #else esp += 64; #endif if (umove(tcp, esp, &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.oldmask); } #elif defined(M68K) if (entering(tcp)) { long usp; struct sigcontext sc; if (upeek(tcp->pid, 4*PT_USP, &usp) < 0) return 0; if (umove(tcp, usp, &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.sc_mask); } #elif defined(ALPHA) if (entering(tcp)) { long fp; struct sigcontext sc; if (upeek(tcp->pid, REG_FP, &fp) < 0) return 0; if (umove(tcp, fp, &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.sc_mask); } #elif defined(SPARC) || defined(SPARC64) if (entering(tcp)) { long i1; m_siginfo_t si; i1 = sparc_regs.u_regs[U_REG_O1]; if (umove(tcp, i1, &si) < 0) { perror_msg("sigreturn: umove"); return 0; } tprintsigmask_val(") (mask ", si.si_mask); } #elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64) /* This decodes rt_sigreturn. The 64-bit ABIs do not have sigreturn. */ if (entering(tcp)) { long sp; struct ucontext uc; if (upeek(tcp->pid, REG_SP, &sp) < 0) return 0; /* There are six words followed by a 128-byte siginfo. */ sp = sp + 6 * 4 + 128; if (umove(tcp, sp, &uc) < 0) return 0; tprintsigmask_val(") (mask ", uc.uc_sigmask); } #elif defined(MIPS) if (entering(tcp)) { long sp; struct pt_regs regs; m_siginfo_t si; if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { perror_msg("sigreturn: PTRACE_GETREGS"); return 0; } sp = regs.regs[29]; if (umove(tcp, sp, &si) < 0) return 0; tprintsigmask_val(") (mask ", si.si_mask); } #elif defined(CRISV10) || defined(CRISV32) if (entering(tcp)) { struct sigcontext sc; long regs[PT_MAX+1]; if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long)regs) < 0) { perror_msg("sigreturn: PTRACE_GETREGS"); return 0; } if (umove(tcp, regs[PT_USP], &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.oldmask); } #elif defined(TILE) if (entering(tcp)) { struct ucontext uc; /* offset of ucontext in the kernel's sigframe structure */ # define SIGFRAME_UC_OFFSET C_ABI_SAVE_AREA_SIZE + sizeof(siginfo_t) if (umove(tcp, tile_regs.sp + SIGFRAME_UC_OFFSET, &uc) < 0) return 0; tprintsigmask_val(") (mask ", uc.uc_sigmask); } #elif defined(MICROBLAZE) /* TODO: Verify that this is correct... */ if (entering(tcp)) { struct sigcontext sc; long sp; /* Read r1, the stack pointer. */ if (upeek(tcp->pid, 1 * 4, &sp) < 0) return 0; if (umove(tcp, sp, &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.oldmask); } #elif defined(XTENSA) /* Xtensa only has rt_sys_sigreturn */ #elif defined(ARC) /* ARC syscall ABI only supports rt_sys_sigreturn */ #else # warning No sys_sigreturn() for this architecture # warning (no problem, just a reminder :-) #endif return 0; }
static int get_syscall_result_regs(struct tcb *tcp) { /* ABI defines result returned in r9 */ return upeek(tcp->pid, REG_GENERAL(9), &sh64_r9) < 0 ? -1 : 0; }
static int get_syscall_result_regs(struct tcb *tcp) { return upeek(tcp->pid, PT_GR28, &hppa_r28) < 0 ? -1 : 0; }
/* Return codes: 1 - ok, 0 - ignore, other - error. */ static int arch_get_scno(struct tcb *tcp) { return upeek(tcp, 0, &tcp->scno) < 0 ? -1 : 1; }