[Ltrace-devel] [PATCH] Add fetch back end for m68k

Andreas Schwab schwab at linux-m68k.org
Wed Sep 12 12:02:29 UTC 2012


This ports the m68k backend to ARCH_HAVE_FETCH_ARG, which fixes all
remaining testsuite failures.

Andreas.

---
 sysdeps/linux-gnu/m68k/Makefile.am |   3 +-
 sysdeps/linux-gnu/m68k/arch.h      |   2 +
 sysdeps/linux-gnu/m68k/fetch.c     | 242 +++++++++++++++++++++++++++++++++++++
 sysdeps/linux-gnu/m68k/trace.c     |  40 ------
 4 files changed, 246 insertions(+), 41 deletions(-)
 create mode 100644 sysdeps/linux-gnu/m68k/fetch.c

diff --git a/sysdeps/linux-gnu/m68k/Makefile.am b/sysdeps/linux-gnu/m68k/Makefile.am
index a79d2f7..766a9bb 100644
--- a/sysdeps/linux-gnu/m68k/Makefile.am
+++ b/sysdeps/linux-gnu/m68k/Makefile.am
@@ -4,7 +4,8 @@ noinst_LTLIBRARIES = \
 ___libcpu_la_SOURCES = \
 	plt.c \
 	regs.c \
-	trace.c
+	trace.c \
+	fetch.c
 
 noinst_HEADERS = \
 	arch.h \
diff --git a/sysdeps/linux-gnu/m68k/arch.h b/sysdeps/linux-gnu/m68k/arch.h
index 9ca08ca..3829901 100644
--- a/sysdeps/linux-gnu/m68k/arch.h
+++ b/sysdeps/linux-gnu/m68k/arch.h
@@ -18,6 +18,8 @@
  * 02110-1301 USA
  */
 
+#define ARCH_HAVE_FETCH_ARG
+
 #define BREAKPOINT_VALUE { 0x4e, 0x4f }
 #define BREAKPOINT_LENGTH 2
 #define DECR_PC_AFTER_BREAK 2
diff --git a/sysdeps/linux-gnu/m68k/fetch.c b/sysdeps/linux-gnu/m68k/fetch.c
new file mode 100644
index 0000000..f193438
--- /dev/null
+++ b/sysdeps/linux-gnu/m68k/fetch.c
@@ -0,0 +1,242 @@
+/*
+ * This file is part of ltrace.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/procfs.h>
+#include <sys/reg.h>
+
+#include "backend.h"
+#include "expr.h"
+#include "fetch.h"
+#include "proc.h"
+#include "ptrace.h"
+#include "type.h"
+#include "value.h"
+
+struct fetch_context
+{
+	elf_gregset_t regs;
+	elf_fpregset_t fpregs;
+
+	int arg_num;
+	void *stack_pointer;
+	struct value retval;
+};
+
+static int
+fetch_register_banks(struct Process *proc, struct fetch_context *context,
+		     int floating)
+{
+	if (ptrace(PTRACE_GETREGS, proc->pid, 0, &context->regs) < 0)
+		return -1;
+
+	if (floating
+	    && ptrace(PTRACE_GETFPREGS, proc->pid, 0, &context->fpregs) < 0)
+		return -1;
+
+	return 0;
+}
+
+struct fetch_context *
+arch_fetch_arg_init(enum tof type, struct Process *proc,
+		    struct arg_type_info *ret_info)
+{
+	struct fetch_context *context = malloc(sizeof(*context));
+	if (context == NULL)
+		return NULL;
+
+	assert(type != LT_TOF_FUNCTIONR && type != LT_TOF_SYSCALLR);
+	if (fetch_register_banks(proc, context, type == LT_TOF_FUNCTION) < 0) {
+	fail:
+		free(context);
+		return NULL;
+	}
+
+	context->arg_num = 0;
+	context->stack_pointer = (arch_addr_t)context->regs[PT_USP] + 4;
+
+	size_t sz = type_sizeof(proc, ret_info);
+	if (sz == (size_t)-1)
+		goto fail;
+
+	if (ret_info->type == ARGTYPE_STRUCT && !(sz <= 4 || sz == 8)) {
+		value_init(&context->retval, proc, NULL, ret_info, 0);
+
+		if (value_pass_by_reference(&context->retval) < 0)
+			goto fail;
+		context->retval.where = VAL_LOC_WORD;
+		context->retval.u.value = context->regs[PT_A1];
+	} else {
+		value_init_detached(&context->retval, NULL, NULL, 0);
+	}
+
+	return context;
+}
+
+struct fetch_context *
+arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
+{
+	struct fetch_context *ret = malloc(sizeof(*ret));
+	if (ret == NULL)
+		return NULL;
+	*ret = *context;
+	return ret;
+}
+
+int
+arch_fetch_arg_next(struct fetch_context *context, enum tof type,
+		    struct Process *proc, struct arg_type_info *info,
+		    struct value *valuep)
+{
+	size_t sz = type_sizeof(proc, info);
+	if (sz == (size_t)-1)
+		return -1;
+
+	if (type == LT_TOF_SYSCALL) {
+		int reg;
+
+		switch (context->arg_num++) {
+		case 0: reg = PT_D1; break;
+		case 1: reg = PT_D2; break;
+		case 2: reg = PT_D3; break;
+		case 3: reg = PT_D4; break;
+		case 4: reg = PT_D5; break;
+		case 5: reg = PT_A0; break;
+		default:
+			assert(!"More than six syscall arguments???");
+			abort();
+		}
+		valuep->where = VAL_LOC_WORD;
+		valuep->u.value = context->regs[reg];
+	} else {
+		size_t a = type_alignof(valuep->inferior, valuep->type);
+		if (a < 4)
+			a = 4;
+		context->stack_pointer
+			= (void *)align((unsigned long)context->stack_pointer, a);
+		if (sz < 4)
+			context->stack_pointer += 4 - sz;
+
+		valuep->where = VAL_LOC_INFERIOR;
+		valuep->u.address = context->stack_pointer;
+		context->stack_pointer += sz;
+	}
+
+	return 0;
+}
+
+int
+arch_fetch_retval(struct fetch_context *context, enum tof type,
+		  struct Process *proc, struct arg_type_info *info,
+		  struct value *valuep)
+{
+	if (fetch_register_banks(proc, context, type == LT_TOF_FUNCTIONR) < 0)
+		return -1;
+
+	if (context->retval.type != NULL) {
+		/* Struct return value was extracted when in fetch
+		 * init.  */
+		*valuep = context->retval;
+		return 0;
+	}
+
+	size_t sz = type_sizeof(proc, info);
+	if (sz == (size_t)-1)
+		return -1;
+	if (value_reserve(valuep, sz) == NULL)
+		return -1;
+
+	switch (info->type) {
+	case ARGTYPE_VOID:
+		return 0;
+
+	case ARGTYPE_INT:
+	case ARGTYPE_UINT:
+	case ARGTYPE_LONG:
+	case ARGTYPE_ULONG:
+	case ARGTYPE_CHAR:
+	case ARGTYPE_SHORT:
+	case ARGTYPE_USHORT:
+	case ARGTYPE_POINTER:
+		{
+			unsigned char *buf = value_get_raw_data(valuep);
+			int reg = info->type == ARGTYPE_POINTER ? PT_A0 : PT_D0;
+			unsigned char *val = (unsigned char *)&context->regs[reg];
+			if (sz < 4) val += 4 - sz;
+			memcpy(buf, val, sz);
+		}
+		return 0;
+
+	case ARGTYPE_FLOAT:
+	case ARGTYPE_DOUBLE:
+		{
+			union {
+				long double ld;
+				double d;
+				float f;
+				char buf[0];
+			} u;
+
+			unsigned long *reg = &context->fpregs.fpregs[0];
+			memcpy (&u.ld, reg, sizeof (u.ld));
+			if (valuep->type->type == ARGTYPE_FLOAT)
+				u.f = (float)u.ld;
+			else if (valuep->type->type == ARGTYPE_DOUBLE)
+				u.d = (double)u.ld;
+			else {
+				assert(!"Unexpected floating type!");
+				abort();
+			}
+			unsigned char *buf = value_get_raw_data (valuep);
+			memcpy (buf, u.buf, sz);
+		}
+		return 0;
+
+	case ARGTYPE_STRUCT:
+		{
+			unsigned char *buf = value_get_raw_data(valuep);
+			unsigned char *val = (unsigned char *)&context->regs[PT_D0];
+
+			assert(sz <= 4 || sz == 8);
+			if (sz < 4) val += 4 - sz;
+			memcpy(buf, val, sz <= 4 ? sz : 4);
+			if (sz == 8)
+				memcpy(buf + 4, &context->regs[PT_D1], 4);
+		}
+		return 0;
+
+	case ARGTYPE_ARRAY:
+		assert(!"Unexpected m68k retval type!");
+		abort();
+	}
+
+	abort();
+}
+
+void
+arch_fetch_arg_done(struct fetch_context *context)
+{
+	if (context != NULL)
+		free(context);
+}
diff --git a/sysdeps/linux-gnu/m68k/trace.c b/sysdeps/linux-gnu/m68k/trace.c
index 4bec016..75b2a78 100644
--- a/sysdeps/linux-gnu/m68k/trace.c
+++ b/sysdeps/linux-gnu/m68k/trace.c
@@ -45,43 +45,3 @@ syscall_p(Process *proc, int status, int *sysnum) {
 	}
 	return 0;
 }
-
-long
-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
-{
-	if (arg_num == -1) {	/* return value */
-		return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D0, 0);
-	}
-
-	if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
-		return ptrace(PTRACE_PEEKTEXT, proc->pid,
-			      proc->stack_pointer + 4 * (arg_num + 1), 0);
-	} else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) {
-#if 0
-		switch (arg_num) {
-		case 0:
-			return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D1, 0);
-		case 1:
-			return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D2, 0);
-		case 2:
-			return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D3, 0);
-		case 3:
-			return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D4, 0);
-		case 4:
-			return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D5, 0);
-		default:
-			fprintf(stderr,
-				"gimme_arg called with wrong arguments\n");
-			exit(2);
-		}
-#else
-		/* That hack works on m68k, too */
-		return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 0);
-#endif
-	} else {
-		fprintf(stderr, "gimme_arg called with wrong arguments\n");
-		exit(1);
-	}
-
-	return 0;
-}
-- 
1.7.12


-- 
Andreas Schwab, schwab at linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."



More information about the Ltrace-devel mailing list