aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Machata <pmachata@redhat.com>2013-11-27 00:42:51 +0100
committerPetr Machata <pmachata@redhat.com>2013-11-27 00:42:51 +0100
commit42cccc91299718b95eecffa6941e29c33d5616b3 (patch)
tree599183a1306cf3dbcd50ff6b63079836ba8c3ea6
parent7b0088dbf6861987f13ad1e0740d633069fdb9d7 (diff)
downloadltrace-42cccc91299718b95eecffa6941e29c33d5616b3.tar.gz
On s390{,x}, r2 is scrambled after syscall entry
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.
-rw-r--r--sysdeps/linux-gnu/s390/fetch.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/sysdeps/linux-gnu/s390/fetch.c b/sysdeps/linux-gnu/s390/fetch.c
index 0b68dbc..4ad5951 100644
--- a/sysdeps/linux-gnu/s390/fetch.c
+++ b/sysdeps/linux-gnu/s390/fetch.c
@@ -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);
}