On s390{,x}, r2 is scrambled after syscall entry
authorPetr Machata <pmachata@redhat.com>
Tue, 26 Nov 2013 23:42:51 +0000 (00:42 +0100)
committerChanho Park <chanho61.park@samsung.com>
Fri, 22 Aug 2014 11:38:24 +0000 (20:38 +0900)
This was caught by system_call_params.exp test case:

   exe->mount("source", "target", "filesystemtype", 0, nil <unfinished ...>
   mount@SYS("", "target", "filesystemtype", 0, nil)                 = -2
   <... mount resumed>                                               = -1

Note how the first parameter disappears--r2 now holds syscall number
(21 in this case), and the original value is stored in orig_gpr2 in
save area.

sysdeps/linux-gnu/s390/fetch.c

index 0b68dbc..4ad5951 100644 (file)
@@ -23,6 +23,7 @@
 #include <sys/ucontext.h>
 #include <assert.h>
 #include <errno.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -61,7 +62,8 @@ s390x(struct fetch_context *ctx)
 }
 
 static int
-fetch_register_banks(struct process *proc, struct fetch_context *ctx)
+fetch_register_banks(struct process *proc, struct fetch_context *ctx,
+                    bool syscall_enter)
 {
        ptrace_area parea;
        parea.len = sizeof(ctx->regs);
@@ -72,15 +74,20 @@ fetch_register_banks(struct process *proc, struct fetch_context *ctx)
                        strerror(errno));
                return -1;
        }
+
+       if (syscall_enter)
+               ctx->regs.gprs[2] = ctx->regs.orig_gpr2;
+
        return 0;
 }
 
 static int
-fetch_context_init(struct process *proc, struct fetch_context *context)
+fetch_context_init(struct process *proc, struct fetch_context *context,
+                  bool syscall_enter)
 {
        context->greg = 2;
        context->freg = 0;
-       return fetch_register_banks(proc, context);
+       return fetch_register_banks(proc, context, syscall_enter);
 }
 
 struct fetch_context *
@@ -89,7 +96,7 @@ arch_fetch_arg_init(enum tof type, struct process *proc,
 {
        struct fetch_context *context = malloc(sizeof(*context));
        if (context == NULL
-           || fetch_context_init(proc, context) < 0) {
+           || fetch_context_init(proc, context, type == LT_TOF_SYSCALL) < 0) {
                fprintf(stderr, "arch_fetch_arg_init: %s\n",
                        strerror(errno));
                free(context);
@@ -277,7 +284,7 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
                return 0;
        }
 
-       if (fetch_context_init(proc, ctx) < 0)
+       if (fetch_context_init(proc, ctx, false) < 0)
                return -1;
        return arch_fetch_arg_next(ctx, type, proc, info, valuep);
 }