From: Michael H. <HO...@de...> - 2004-02-26 14:43:54
|
Hi all, The clone() system call is not handled correctly in strace for s390(x) under Linux. The following testprogram under linux 2.6 fails: #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <sched.h> #include <signal.h> char stack[10000]; int childfn(void* arg) { printf("CHILD\n"); return 0; } int main(void) { pid_t child; int status,rc; child = clone(&childfn,stack+sizeof(stack) ,CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD ,NULL); rc = waitpid(child,&status,0); printf("parent rc: %i\n",rc); return 0; } >>> strace -f ./test .... clone(Process 15636 attached child_stack=0x403fec, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0) = 15636 [pid 15635] --- SIGCHLD (Child exited) @ 0 (0) --- [pid 15635] wait4(15636, Process 15635 suspended <strace hangs here> The problem is that on s390 the paramters of clone() are ordered in a different way than on all other platforms. When tracing the clone() system call the argument 0 (the flags argument which is argument 1 on s390) is or'd with CLONE_PTRACE and is written back. Because on s390 the arguments are swapped, we overwrite the old clone flags here. Here is a fix for the problem: --- util.c.orig 2004-02-25 16:26:10.268979783 +0100 +++ util.c 2004-02-26 15:01:25.048979783 +0100 @@ -1230,14 +1230,8 @@ #else # if defined S390 || defined S390X -/* Note: this is only true for the `clone' system call, which handles - arguments specially. We could as well say that its first two arguments - are swapped relative to other architectures, but that would just be - another #ifdef in the calls. */ -# define arg0_offset PT_GPR3 -# define arg1_offset PT_ORIGGPR2 -# define restore_arg0(tcp, state, val) ((void) (state), 0) -# define restore_arg1(tcp, state, val) ((void) (state), 0) +# define arg0_offset PT_ORIGGPR2 +# define arg1_offset PT_GPR3 # elif defined (ALPHA) || defined (MIPS) # define arg0_offset REG_A0 # define arg1_offset (REG_A0+1) @@ -1317,6 +1311,21 @@ case SYS_fork: #endif #if defined SYS_fork || defined SYS_vfork +#if defined(S390) || defined(S390X) +/* Note: On s390(x) the `clone' system call arguments are arranged differnt + then on other architectures +*/ + if (arg_setup (tcp, &state) < 0 + || get_arg0 (tcp, &state, &tcp->inst[0]) < 0 + || get_arg1 (tcp, &state, &tcp->inst[1]) < 0 + || change_syscall(tcp, SYS_clone) < 0 + || set_arg1 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0 + || set_arg0 (tcp, &state, 0) < 0 + || arg_finish_change (tcp, &state) < 0) + return -1; + tcp->u_arg[0] = 0; + tcp->u_arg[1] = CLONE_PTRACE|SIGCHLD; +#else if (arg_setup (tcp, &state) < 0 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0 @@ -1327,6 +1336,7 @@ return -1; tcp->u_arg[0] = CLONE_PTRACE|SIGCHLD; tcp->u_arg[1] = 0; +#endif tcp->flags |= TCB_BPTSET; return 0; #endif @@ -1335,11 +1345,19 @@ #ifdef SYS_clone2 case SYS_clone2: #endif +#if defined(S390) || defined(S390X) + if ((tcp->u_arg[1] & CLONE_PTRACE) == 0 + && (arg_setup (tcp, &state) < 0 + || set_arg1 (tcp, &state, tcp->u_arg[1] | CLONE_PTRACE) < 0 + || arg_finish_change (tcp, &state) < 0)) + return -1; +#else if ((tcp->u_arg[0] & CLONE_PTRACE) == 0 && (arg_setup (tcp, &state) < 0 || set_arg0 (tcp, &state, tcp->u_arg[0] | CLONE_PTRACE) < 0 || arg_finish_change (tcp, &state) < 0)) return -1; +#endif tcp->flags |= TCB_BPTSET; tcp->inst[0] = tcp->u_arg[0]; tcp->inst[1] = tcp->u_arg[1]; (See attached file: strace-4.5.1-clone.diff) Best Regards Michael ------------------------------------------------------------------------ Linux for E-Server Development Phone: +49-7031-16-2360, Bld 71032-03-U09 Email: ho...@de... |