[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