diff --git a/defs.h b/defs.h index b42d114c..98c75b97 100644 --- a/defs.h +++ b/defs.h @@ -318,7 +318,7 @@ struct tcb { #define TCB_FOLLOWFORK 00400 /* Process should have forks followed */ #define TCB_REPRINT 01000 /* We should reprint this syscall on exit */ #ifdef LINUX -# if defined(ALPHA) || defined(SPARC) || defined(POWERPC) || defined(IA64) || defined(HPPA) || defined(SH) || defined(SHMEDIA) || defined(S390) || defined(S390X) +# if defined(ALPHA) || defined(SPARC) || defined(POWERPC) || defined(IA64) || defined(HPPA) || defined(SH) || defined(SHMEDIA) || defined(S390) || defined(S390X) || defined(ARM) # define TCB_WAITEXECVE 02000 /* ignore SIGTRAP after exceve */ # endif # define TCB_CLONE_DETACHED 04000 /* CLONE_DETACHED set in creating syscall */ diff --git a/process.c b/process.c index bb33a202..9f117e4e 100644 --- a/process.c +++ b/process.c @@ -2626,6 +2626,25 @@ struct xlat struct_user_offsets[] = { { uoff(regs), "offsetof(struct user, regs)" }, { uoff(fpu), "offsetof(struct user, fpu)" }, #endif +#ifdef ARM + { uoff(regs.ARM_r0), "r0" }, + { uoff(regs.ARM_r1), "r1" }, + { uoff(regs.ARM_r2), "r2" }, + { uoff(regs.ARM_r3), "r3" }, + { uoff(regs.ARM_r4), "r4" }, + { uoff(regs.ARM_r5), "r5" }, + { uoff(regs.ARM_r6), "r6" }, + { uoff(regs.ARM_r7), "r7" }, + { uoff(regs.ARM_r8), "r8" }, + { uoff(regs.ARM_r9), "r9" }, + { uoff(regs.ARM_r10), "r10" }, + { uoff(regs.ARM_fp), "fp" }, + { uoff(regs.ARM_ip), "ip" }, + { uoff(regs.ARM_sp), "sp" }, + { uoff(regs.ARM_lr), "lr" }, + { uoff(regs.ARM_pc), "pc" }, + { uoff(regs.ARM_cpsr), "cpsr" }, +#endif #if !defined(S390) && !defined(S390X) && !defined(MIPS) { uoff(u_fpvalid), "offsetof(struct user, u_fpvalid)" }, diff --git a/signal.c b/signal.c index 43982942..e393b0fd 100644 --- a/signal.c +++ b/signal.c @@ -1183,26 +1183,51 @@ int sys_sigreturn(tcp) struct tcb *tcp; { -#if defined(S390) || defined(S390X) - long usp; - struct sigcontext_struct sc; +#ifdef ARM + struct pt_regs regs; + struct sigcontext_struct sc; - if (entering(tcp)) { - tcp->u_arg[0] = 0; - if (upeek(tcp->pid,PT_GPR15,&usp)<0) - return 0; - if (umove(tcp, usp+__SIGNAL_FRAMESIZE, &sc) < 0) - return 0; - tcp->u_arg[0] = 1; - memcpy(&tcp->u_arg[1],&sc.oldmask[0],sizeof(sigset_t)); - } else { - tcp->u_rval = tcp->u_error = 0; - if (tcp->u_arg[0] == 0) - return 0; - tcp->auxstr = sprintsigmask("mask now ",(sigset_t *)&tcp->u_arg[1],0); - return RVAL_NONE | RVAL_STR; - } - return 0; + if (entering(tcp)) { + tcp->u_arg[0] = 0; + + if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)®s) == -1) + return 0; + + if (umove(tcp, regs.ARM_sp, &sc) < 0) + return 0; + + tcp->u_arg[0] = 1; + tcp->u_arg[1] = sc.oldmask; + } else { + sigset_t sigm; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) + return 0; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; + } + return 0; +#elif defined(S390) || defined(S390X) + long usp; + struct sigcontext_struct sc; + + if (entering(tcp)) { + tcp->u_arg[0] = 0; + if (upeek(tcp->pid,PT_GPR15,&usp)<0) + return 0; + if (umove(tcp, usp+__SIGNAL_FRAMESIZE, &sc) < 0) + return 0; + tcp->u_arg[0] = 1; + memcpy(&tcp->u_arg[1],&sc.oldmask[0],sizeof(sigset_t)); + } else { + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) + return 0; + tcp->auxstr = sprintsigmask("mask now ",(sigset_t *)&tcp->u_arg[1],0); + return RVAL_NONE | RVAL_STR; + } + return 0; #else #ifdef I386 long esp; @@ -1256,50 +1281,50 @@ struct tcb *tcp; return 0; #else /* !IA64 */ #ifdef POWERPC - long esp; - struct sigcontext_struct sc; + long esp; + struct sigcontext_struct sc; - if (entering(tcp)) { - tcp->u_arg[0] = 0; - if (upeek(tcp->pid, sizeof(unsigned long)*PT_R1, &esp) < 0) - return 0; - if (umove(tcp, esp, &sc) < 0) - return 0; - tcp->u_arg[0] = 1; - tcp->u_arg[1] = sc.oldmask; - } - else { - sigset_t sigm; - long_to_sigset(tcp->u_arg[1], &sigm); - tcp->u_rval = tcp->u_error = 0; - if (tcp->u_arg[0] == 0) - return 0; - tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); - return RVAL_NONE | RVAL_STR; - } - return 0; + if (entering(tcp)) { + tcp->u_arg[0] = 0; + if (upeek(tcp->pid, sizeof(unsigned long)*PT_R1, &esp) < 0) + return 0; + if (umove(tcp, esp, &sc) < 0) + return 0; + tcp->u_arg[0] = 1; + tcp->u_arg[1] = sc.oldmask; + } + else { + sigset_t sigm; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) + return 0; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; + } + return 0; #else /* !POWERPC */ #ifdef M68K long usp; struct sigcontext sc; if (entering(tcp)) { - tcp->u_arg[0] = 0; - if (upeek(tcp->pid, 4*PT_USP, &usp) < 0) + tcp->u_arg[0] = 0; + if (upeek(tcp->pid, 4*PT_USP, &usp) < 0) return 0; - if (umove(tcp, usp, &sc) < 0) + if (umove(tcp, usp, &sc) < 0) return 0; - tcp->u_arg[0] = 1; - tcp->u_arg[1] = sc.sc_mask; + tcp->u_arg[0] = 1; + tcp->u_arg[1] = sc.sc_mask; } else { - sigset_t sigm; - long_to_sigset(tcp->u_arg[1], &sigm); - tcp->u_rval = tcp->u_error = 0; - if (tcp->u_arg[0] == 0) + sigset_t sigm; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) return 0; - tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); - return RVAL_NONE | RVAL_STR; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; } return 0; #else /* !M68K */ @@ -1308,22 +1333,22 @@ struct tcb *tcp; struct sigcontext_struct sc; if (entering(tcp)) { - tcp->u_arg[0] = 0; - if (upeek(tcp->pid, REG_FP, &fp) < 0) + tcp->u_arg[0] = 0; + if (upeek(tcp->pid, REG_FP, &fp) < 0) return 0; - if (umove(tcp, fp, &sc) < 0) + if (umove(tcp, fp, &sc) < 0) return 0; - tcp->u_arg[0] = 1; - tcp->u_arg[1] = sc.sc_mask; + tcp->u_arg[0] = 1; + tcp->u_arg[1] = sc.sc_mask; } else { - sigset_t sigm; - long_to_sigset(tcp->u_arg[1], &sigm); - tcp->u_rval = tcp->u_error = 0; - if (tcp->u_arg[0] == 0) + sigset_t sigm; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) return 0; - tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); - return RVAL_NONE | RVAL_STR; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; } return 0; #else @@ -1333,8 +1358,8 @@ struct tcb *tcp; m_siginfo_t si; if(ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { - perror("sigreturn: PTRACE_GETREGS "); - return 0; + perror("sigreturn: PTRACE_GETREGS "); + return 0; } if(entering(tcp)) { tcp->u_arg[0] = 0; diff --git a/syscall.c b/syscall.c index f06e172c..39ee93c3 100644 --- a/syscall.c +++ b/syscall.c @@ -695,7 +695,7 @@ struct tcb *tcp; #elif defined (M68K) static int d0; #elif defined (ARM) - static int r0; + static struct pt_regs regs; #elif defined (ALPHA) static long r0; static long a3; @@ -714,7 +714,7 @@ struct tcb *tcp; #elif defined(SH) static long r0; #elif defined(SHMEDIA) - static long r9; + static long r9; #elif defined(X86_64) static long rax; #endif @@ -939,11 +939,59 @@ struct tcb *tcp; return -1; } #elif defined (ARM) - { - long pc; - upeek(pid, 4*15, &pc); - umoven(tcp, pc-4, 4, (char *)&scno); - scno &= 0x000fffff; + /* + * Read complete register set in one go. + */ + if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)®s) == -1) + return -1; + + /* + * We only need to grab the syscall number on syscall entry. + */ + if (regs.ARM_ip == 0) { + /* + * Note: we only deal with only 32-bit CPUs here. + */ + if (regs.ARM_cpsr & 0x20) { + /* + * Get the Thumb-mode system call number + */ + scno = regs.ARM_r7; + } else { + /* + * Get the ARM-mode system call number + */ + errno = 0; + scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL); + if (errno) + return -1; + + if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) { + tcp->flags &= ~TCB_WAITEXECVE; + return 0; + } + + if ((scno & 0x0ff00000) != 0x0f900000) { + fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n", + scno); + return -1; + } + + /* + * Fixup the syscall number + */ + scno &= 0x000fffff; + } + + if (tcp->flags & TCB_INSYSCALL) { + fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid); + tcp->flags &= ~TCB_INSYSCALL; + } + } else { + if (!(tcp->flags & TCB_INSYSCALL)) { + fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid); + tcp->flags |= TCB_INSYSCALL; + } } #elif defined (M68K) if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0) @@ -1272,13 +1320,9 @@ struct tcb *tcp; return 0; } #elif defined (ARM) - if (upeek(pid, 4*0, (long *)&r0) < 0) - return -1; - if ( 0 && r0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) { - if (debug) - fprintf(stderr, "stray syscall exit: d0 = %ld\n", r0); - return 0; - } + /* + * Nothing required + */ #elif defined (HPPA) if (upeek(pid, PT_GR28, &r28) < 0) return -1; @@ -1386,12 +1430,12 @@ struct tcb *tcp; } #else /* !M68K */ #ifdef ARM - if (r0 && (unsigned) -r0 < nerrnos) { + if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) { tcp->u_rval = -1; - u_error = -r0; + u_error = -regs.ARM_r0; } else { - tcp->u_rval = r0; + tcp->u_rval = regs.ARM_r0; u_error = 0; } #else /* !ARM */ @@ -1864,6 +1908,17 @@ struct tcb *tcp; return -1; } } +#elif defined(ARM) + { + int i; + + if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) + tcp->u_nargs = sysent[tcp->scno].nargs; + else + tcp->u_nargs = MAX_ARGS; + for (i = 0; i < tcp->u_nargs; i++) + tcp->u_arg[i] = regs.uregs[i]; + } #elif defined(SH) { int i;