[ltrace-commits] 01/02: Implement x8 support on aarch64

Petr Machata pmachata-guest at moszumanska.debian.org
Wed Feb 5 01:00:55 UTC 2014


This is an automated email from the git hooks/post-receive script.

pmachata-guest pushed a commit to branch pmachata/aarch64
in repository ltrace.

commit d10c86f5460180995519cfca988a87d1dc6b2bb6
Author: Petr Machata <pmachata at apm-mustang-ev2-02.ml3.eng.bos.redhat.com>
Date:   Tue Feb 4 19:57:09 2014 -0500

    Implement x8 support on aarch64
---
 sysdeps/linux-gnu/aarch64/fetch.c | 166 +++++++++++++++++++++++++++++---------
 1 file changed, 129 insertions(+), 37 deletions(-)

diff --git a/sysdeps/linux-gnu/aarch64/fetch.c b/sysdeps/linux-gnu/aarch64/fetch.c
index d6fb1ed..8779f03 100644
--- a/sysdeps/linux-gnu/aarch64/fetch.c
+++ b/sysdeps/linux-gnu/aarch64/fetch.c
@@ -39,10 +39,11 @@ struct fetch_context
 	arch_addr_t nsaa;
 	unsigned ngrn;
 	unsigned nsrn;
+	arch_addr_t x8;
 };
 
 static int
-context_init(struct fetch_context *context, enum tof type, struct process *proc)
+context_init(struct fetch_context *context, struct process *proc)
 {
 	if (aarch64_read_gregs(proc, &context->gregs) < 0
 	    || aarch64_read_fregs(proc, &context->fpregs) < 0)
@@ -52,6 +53,7 @@ context_init(struct fetch_context *context, enum tof type, struct process *proc)
 	context->nsrn = 0;
 	/* XXX double cast */
 	context->nsaa = (arch_addr_t) (uintptr_t) context->gregs.sp;
+	context->x8 = 0;
 
 	return 0;
 }
@@ -144,42 +146,66 @@ fetch_stack(struct fetch_context *context, struct value *value,
 	return 0;
 }
 
-static int
-pass_arg(struct fetch_context *context, enum tof type,
-	 struct process *proc, struct arg_type_info *info,
-	 struct value *value)
+enum convert_method {
+	CVT_ERR = -1,
+	CVT_NOP = 0,
+	CVT_BYREF,
+};
+
+enum fetch_method {
+	FETCH_NOP,
+	FETCH_STACK,
+	FETCH_GPR,
+	FETCH_SSE,
+	FETCH_HFA,
+};
+
+struct fetch_script {
+	enum convert_method c;
+	enum fetch_method f;
+	size_t sz;
+	struct arg_type_info *hfa_t;
+	size_t count;
+};
+
+static struct fetch_script
+pass_arg(struct fetch_context const *context,
+	 struct process *proc, struct arg_type_info *info)
 {
+	enum fetch_method cvt = CVT_NOP;
+
 	size_t sz = type_sizeof(proc, info);
 	if (sz == (size_t) -1)
-		return -1;
+		return (struct fetch_script) { CVT_ERR, FETCH_NOP, sz };
 
 	switch (info->type) {
 	case ARGTYPE_VOID:
-		return 0;
+		return (struct fetch_script) { cvt, FETCH_NOP, sz };
 
 	case ARGTYPE_STRUCT:
 	case ARGTYPE_ARRAY:;
 		size_t count;
-		struct arg_type_info *hfa_t
-			= type_get_hfa_type(info, &count);
+		struct arg_type_info *hfa_t = type_get_hfa_type(info, &count);
 		if (hfa_t != NULL && count <= 4) {
 			if (context->nsrn + count <= 8)
-				return fetch_hfa(context, value, hfa_t, count);
-			context->nsrn = 8;
-			return fetch_stack(context, value,
-					   type_alignof(proc, info), sz);
+				return (struct fetch_script)
+					{ cvt, FETCH_HFA, sz, hfa_t, count };
+			return (struct fetch_script)
+				{ cvt, FETCH_STACK, sz, hfa_t, count };
 		}
 
 		if (sz <= 16) {
 			size_t count = sz / 8;
 			if (context->ngrn + count <= 8)
-				return fetch_gpr(context, value, sz);
+				return (struct fetch_script)
+					{ cvt, FETCH_GPR, sz };
 		}
 
-		if (value_pass_by_reference(value) < 0)
-			return -1;
+		cvt = CVT_BYREF;
 		sz = 8;
+		/* Fall through.  */
 
+	case ARGTYPE_POINTER:
 	case ARGTYPE_INT:
 	case ARGTYPE_UINT:
 	case ARGTYPE_LONG:
@@ -187,51 +213,110 @@ pass_arg(struct fetch_context *context, enum tof type,
 	case ARGTYPE_CHAR:
 	case ARGTYPE_SHORT:
 	case ARGTYPE_USHORT:
-	case ARGTYPE_POINTER:
 		if (context->ngrn < 8 && sz <= 8)
-			return fetch_gpr(context, value, sz);
+			return (struct fetch_script) { cvt, FETCH_GPR, sz };
 		/* We don't support types wider than 8 bytes as of
 		 * now.  */
 		assert(sz <= 8);
 
-		return fetch_stack(context, value,
-				   type_alignof(proc, info), sz);
+		return (struct fetch_script) { cvt, FETCH_STACK, sz };
 
 	case ARGTYPE_FLOAT:
 	case ARGTYPE_DOUBLE:
 		if (context->nsrn < 8) {
 			/* ltrace doesn't support float128.  */
 			assert(sz <= 8);
-			return fetch_sse(context, value, sz);
+			return (struct fetch_script) { cvt, FETCH_SSE, sz };
 		}
 
+		return (struct fetch_script) { cvt, FETCH_STACK, sz };
+	}
+
+	assert(! "Failed to allocate argument.");
+	abort();
+}
+
+static int
+convert_arg(struct value *value, struct fetch_script how)
+{
+	switch (how.c) {
+	case CVT_NOP:
+		return 0;
+	case CVT_BYREF:
+		return value_pass_by_reference(value);
+	case CVT_ERR:
+		return -1;
+	}
+
+	assert(! "Don't know how to convert argument.");
+	abort();
+}
+
+static int
+fetch_arg(struct fetch_context *context,
+	  struct process *proc, struct arg_type_info *info,
+	  struct value *value, struct fetch_script how)
+{
+	if (convert_arg(value, how) < 0)
+		return -1;
+
+	switch (how.f) {
+	case FETCH_NOP:
+		return 0;
+
+	case FETCH_STACK:
+		if (how.hfa_t != NULL && how.count != 0 && how.count <= 8)
+			context->nsrn = 8;
 		return fetch_stack(context, value,
-				   type_alignof(proc, info), sz);
+				   type_alignof(proc, info), how.sz);
+
+	case FETCH_GPR:
+		return fetch_gpr(context, value, how.sz);
+
+	case FETCH_SSE:
+		return fetch_sse(context, value, how.sz);
+
+	case FETCH_HFA:
+		return fetch_hfa(context, value, how.hfa_t, how.count);
 	}
-	return -1;
+
+	assert(! "Don't know how to fetch argument.");
+	abort();
 }
 
 struct fetch_context *
 arch_fetch_arg_init(enum tof type, struct process *proc,
 		    struct arg_type_info *ret_info)
 {
-	struct fetch_context *ret = malloc(sizeof *ret);
-	if (ret == NULL || context_init(ret, type, proc) < 0) {
+	struct fetch_context *context = malloc(sizeof *context);
+	if (context == NULL || context_init(context, proc) < 0) {
 	fail:
-		free(ret);
+		free(context);
 		return NULL;
 	}
 
-	// XXX !!! return value location not properly saved here
-	struct fetch_context tmp = *ret;
-	struct value value;
-	value_init(&value, proc, NULL, ret_info, 0);
-	int rc = pass_arg(&tmp, type, proc, ret_info, &value);
-	value_destroy(&value);
-	if (rc < 0)
+	/* There's a provision in ARMv8 parameter passing convention
+	 * for returning types that, if passed as first argument to a
+	 * function, would be passed on stack.  For those types, x8
+	 * contains an address where the return argument should be
+	 * placed.  The callee doesn't need to preserve the value of
+	 * x8, so we need to fetch it now.
+	 *
+	 * To my knowledge, there are currently no types where this
+	 * holds, but the code is here, utterly untested.  */
+
+	struct fetch_script how = pass_arg(context, proc, ret_info);
+	if (how.c == CVT_ERR)
 		goto fail;
+	if (how.c == CVT_NOP && how.f == FETCH_STACK) {
+		/* XXX double cast.  */
+		context->x8 = (arch_addr_t) (uintptr_t) context->gregs.regs[8];
+		/* See the comment above about the assert.  */
+		assert(! "Unexpected: first argument passed on stack.");
+		abort();
+	}
 
-	return ret;
+	return context;
 }
 
 int
@@ -239,7 +324,8 @@ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
 		    struct process *proc, struct arg_type_info *info,
 		    struct value *value)
 {
-	return pass_arg(context, type, proc, info, value);
+	return fetch_arg(context, proc, info, value,
+			 pass_arg(context, proc, info));
 }
 
 int
@@ -247,10 +333,16 @@ arch_fetch_retval(struct fetch_context *context, enum tof type,
 		  struct process *proc, struct arg_type_info *info,
 		  struct value *value)
 {
-	if (context_init(context, type, proc) < 0)
+	if (context->x8 != 0) {
+		value_in_inferior(value, context->x8);
+		return 0;
+	}
+
+	if (context_init(context, proc) < 0)
 		return -1;
 
-	return pass_arg(context, type, proc, info, value);
+	return fetch_arg(context, proc, info, value,
+			 pass_arg(context, proc, info));
 }
 
 void

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/ltrace.git



More information about the ltrace-commits mailing list