Blame SOURCES/ltrace-0.7.91-ppc64le-support.patch

2e4be5
From eea4ad2cce289753aaa35b4e0258a76d8f8f367c Mon Sep 17 00:00:00 2001
2e4be5
From: Thierry Fauck <thierry@linux.vnet.ibm.com>
2e4be5
Date: Tue, 13 May 2014 07:48:24 -0400
2e4be5
Subject: [PATCH] Support for powerpc64 arch ppc64el
2e4be5
2e4be5
Signed-off-by: Thierry Fauck <thierry@linux.vnet.ibm.com>
2e4be5
2e4be5
	Add support for ppc64le proc and ELF ABIv2.
2e4be5
	Provides support for irelative and wchar
2e4be5
---
2e4be5
 ltrace-elf.c                           |    2 +-
2e4be5
 ltrace-elf.h                           |    1 +
2e4be5
 sysdeps/linux-gnu/ppc/arch.h           |   35 ++++-
2e4be5
 sysdeps/linux-gnu/ppc/fetch.c          |  244 +++++++++++++++++++++++++++++---
2e4be5
 sysdeps/linux-gnu/ppc/plt.c            |   98 ++++++++++++--
2e4be5
 sysdeps/linux-gnu/ppc/trace.c          |   10 ++
2e4be5
 testsuite/ltrace.main/system_calls.exp |    2 +-
2e4be5
 7 files changed, 356 insertions(+), 36 deletions(-)
2e4be5
2e4be5
diff --git a/ltrace-elf.c b/ltrace-elf.c
2e4be5
index 8997518..f638342 100644
2e4be5
--- a/ltrace-elf.c
2e4be5
+++ b/ltrace-elf.c
2e4be5
@@ -859,7 +859,7 @@ populate_plt(struct process *proc, const char *filename,
2e4be5
 	return 0;
2e4be5
 }
2e4be5
 
2e4be5
-static void
2e4be5
+void
2e4be5
 delete_symbol_chain(struct library_symbol *libsym)
2e4be5
 {
2e4be5
 	while (libsym != NULL) {
2e4be5
diff --git a/ltrace-elf.h b/ltrace-elf.h
2e4be5
index db4ffe9..4a824c4 100644
2e4be5
--- a/ltrace-elf.h
2e4be5
+++ b/ltrace-elf.h
2e4be5
@@ -166,6 +166,7 @@ int elf_read_next_uleb128(Elf_Data *data, GElf_Xword *offset, uint64_t *retp);
2e4be5
 /* Return whether there's AMOUNT more bytes after OFFSET in DATA.  */
2e4be5
 int elf_can_read_next(Elf_Data *data, GElf_Xword offset, GElf_Xword amount);
2e4be5
 
2e4be5
+void delete_symbol_chain(struct library_symbol *);
2e4be5
 #if __WORDSIZE == 32
2e4be5
 #define PRI_ELF_ADDR		PRIx32
2e4be5
 #define GELF_ADDR_CAST(x)	(void *)(uint32_t)(x)
2e4be5
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
2e4be5
index bf9b5dc..7918a13 100644
2e4be5
--- a/sysdeps/linux-gnu/ppc/arch.h
2e4be5
+++ b/sysdeps/linux-gnu/ppc/arch.h
2e4be5
@@ -23,8 +23,8 @@
2e4be5
 #define LTRACE_PPC_ARCH_H
2e4be5
 
2e4be5
 #include <gelf.h>
2e4be5
+#include <stdbool.h>
2e4be5
 
2e4be5
-#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
2e4be5
 #define BREAKPOINT_LENGTH 4
2e4be5
 #define DECR_PC_AFTER_BREAK 0
2e4be5
 
2e4be5
@@ -34,8 +34,33 @@
2e4be5
 #ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target.
2e4be5
 #define LT_ELFCLASS2	ELFCLASS64
2e4be5
 #define LT_ELF_MACHINE2	EM_PPC64
2e4be5
-#define ARCH_SUPPORTS_OPD
2e4be5
-#endif
2e4be5
+
2e4be5
+# ifdef __LITTLE_ENDIAN__
2e4be5
+# define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f }
2e4be5
+# define ARCH_ENDIAN_LITTLE
2e4be5
+# else
2e4be5
+# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
2e4be5
+# define ARCH_SUPPORTS_OPD
2e4be5
+# define ARCH_ENDIAN_BIG
2e4be5
+# endif
2e4be5
+
2e4be5
+# if _CALL_ELF != 2
2e4be5
+# define ARCH_SUPPORTS_OPD
2e4be5
+# define STACK_FRAME_OVERHEAD 112
2e4be5
+#  ifndef EF_PPC64_ABI
2e4be5
+#  define EF_PPC64_ABI 3
2e4be5
+#  endif
2e4be5
+# else /* _CALL_ELF == 2 ABIv2 */
2e4be5
+# define STACK_FRAME_OVERHEAD 32
2e4be5
+# endif /* CALL_ELF */
2e4be5
+
2e4be5
+#else
2e4be5
+#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
2e4be5
+#define ARCH_ENDIAN_BIG
2e4be5
+# ifndef EF_PPC64_ABI
2e4be5
+# define EF_PPC64_ABI 3
2e4be5
+# endif
2e4be5
+#endif 	/* __powerpc64__ */
2e4be5
 
2e4be5
 #define ARCH_HAVE_SW_SINGLESTEP
2e4be5
 #define ARCH_HAVE_ADD_PLT_ENTRY
2e4be5
@@ -43,7 +68,6 @@
2e4be5
 #define ARCH_HAVE_TRANSLATE_ADDRESS
2e4be5
 #define ARCH_HAVE_DYNLINK_DONE
2e4be5
 #define ARCH_HAVE_FETCH_ARG
2e4be5
-#define ARCH_ENDIAN_BIG
2e4be5
 #define ARCH_HAVE_SIZEOF
2e4be5
 #define ARCH_HAVE_ALIGNOF
2e4be5
 
2e4be5
@@ -56,7 +80,8 @@ struct arch_ltelf_data {
2e4be5
 	Elf_Data *opd_data;
2e4be5
 	GElf_Addr opd_base;
2e4be5
 	GElf_Xword opd_size;
2e4be5
-	int secure_plt;
2e4be5
+	bool secure_plt : 1;
2e4be5
+	bool elfv2_abi  : 1;
2e4be5
 
2e4be5
 	Elf_Data *reladyn;
2e4be5
 	size_t reladyn_count;
2e4be5
diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c
2e4be5
index ed38336..c9381c3 100644
2e4be5
--- a/sysdeps/linux-gnu/ppc/fetch.c
2e4be5
+++ b/sysdeps/linux-gnu/ppc/fetch.c
2e4be5
@@ -30,9 +30,11 @@
2e4be5
 #include "ptrace.h"
2e4be5
 #include "proc.h"
2e4be5
 #include "value.h"
2e4be5
+#include "ltrace-elf.h"
2e4be5
 
2e4be5
 static int allocate_gpr(struct fetch_context *ctx, struct process *proc,
2e4be5
-			struct arg_type_info *info, struct value *valuep);
2e4be5
+			struct arg_type_info *info, struct value *valuep,
2e4be5
+			size_t off, bool is_hfa_type);
2e4be5
 
2e4be5
 /* Floating point registers have the same width on 32-bit as well as
2e4be5
  * 64-bit PPC, but <ucontext.h> presents a different API depending on
2e4be5
@@ -62,7 +64,10 @@ struct fetch_context {
2e4be5
 		gregs64_t r64;
2e4be5
 	} regs;
2e4be5
 	struct fpregs_t fpregs;
2e4be5
-
2e4be5
+	int vgreg;
2e4be5
+	int struct_size;
2e4be5
+	int struct_hfa_size;
2e4be5
+	int struct_hfa_count;
2e4be5
 };
2e4be5
 
2e4be5
 static int
2e4be5
@@ -74,7 +79,8 @@ fetch_context_init(struct process *proc, struct fetch_context *context)
2e4be5
 	if (proc->e_machine == EM_PPC)
2e4be5
 		context->stack_pointer = proc->stack_pointer + 8;
2e4be5
 	else
2e4be5
-		context->stack_pointer = proc->stack_pointer + 112;
2e4be5
+		context->stack_pointer = proc->stack_pointer
2e4be5
+			+ STACK_FRAME_OVERHEAD;
2e4be5
 
2e4be5
 	/* When ltrace is 64-bit, we might use PTRACE_GETREGS to
2e4be5
 	 * obtain 64-bit as well as 32-bit registers.  But if we do it
2e4be5
@@ -118,6 +124,11 @@ arch_fetch_arg_init(enum tof type, struct process *proc,
2e4be5
 		return NULL;
2e4be5
 	}
2e4be5
 
2e4be5
+	context->vgreg = context->greg;
2e4be5
+	context->struct_size = 0;
2e4be5
+	context->struct_hfa_size = 0;
2e4be5
+	context->struct_hfa_count = 0;
2e4be5
+
2e4be5
 	/* Aggregates or unions of any length, and character strings
2e4be5
 	 * of length longer than 8 bytes, will be returned in a
2e4be5
 	 * storage buffer allocated by the caller. The caller will
2e4be5
@@ -125,8 +136,20 @@ arch_fetch_arg_init(enum tof type, struct process *proc,
2e4be5
 	 * in r3, causing the first explicit argument to be passed in
2e4be5
 	 * r4.  */
2e4be5
 	context->ret_struct = ret_info->type == ARGTYPE_STRUCT;
2e4be5
-	if (context->ret_struct)
2e4be5
+	if (context->ret_struct) {
2e4be5
+#if _CALL_ELF == 2
2e4be5
+		/* if R3 points to stack, parameters will be in R4.  */
2e4be5
+		uint64_t pstack_end = ptrace(PTRACE_PEEKTEXT, proc->pid,
2e4be5
+					proc->stack_pointer, 0);
2e4be5
+		if (((arch_addr_t)context->regs.r64[3] > proc->stack_pointer)
2e4be5
+		    && (context->regs.r64[3] < pstack_end)) {
2e4be5
+			context->greg++;
2e4be5
+			context->stack_pointer += 8;
2e4be5
+		}
2e4be5
+#else
2e4be5
 		context->greg++;
2e4be5
+#endif
2e4be5
+	}
2e4be5
 
2e4be5
 	return context;
2e4be5
 }
2e4be5
@@ -144,7 +167,8 @@ arch_fetch_arg_clone(struct process *proc,
2e4be5
 
2e4be5
 static int
2e4be5
 allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
2e4be5
-		    struct arg_type_info *info, struct value *valuep)
2e4be5
+		    struct arg_type_info *info, struct value *valuep,
2e4be5
+		    bool is_hfa_type)
2e4be5
 {
2e4be5
 	size_t sz = type_sizeof(proc, info);
2e4be5
 	if (sz == (size_t)-1)
2e4be5
@@ -154,7 +178,14 @@ allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
2e4be5
 	size_t off = 0;
2e4be5
 	if (proc->e_machine == EM_PPC && a < 4)
2e4be5
 		a = 4;
2e4be5
+#if _CALL_ELF == 2
2e4be5
+	else if (proc->e_machine == EM_PPC64 && sz == 4 && is_hfa_type)
2e4be5
+		a = 4;
2e4be5
+	else
2e4be5
+		a = 8;
2e4be5
+#else
2e4be5
 	else if (proc->e_machine == EM_PPC64 && a < 8)
2e4be5
+#endif
2e4be5
 		a = 8;
2e4be5
 
2e4be5
 	/* XXX Remove the two double casts when arch_addr_t
2e4be5
@@ -164,7 +195,7 @@ allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
2e4be5
 
2e4be5
 	if (valuep != NULL)
2e4be5
 		value_in_inferior(valuep, ctx->stack_pointer + off);
2e4be5
-	ctx->stack_pointer += sz;
2e4be5
+	ctx->stack_pointer += a;
2e4be5
 
2e4be5
 	return 0;
2e4be5
 }
2e4be5
@@ -216,19 +247,34 @@ align_small_int(unsigned char *buf, size_t w, size_t sz)
2e4be5
 
2e4be5
 static int
2e4be5
 allocate_gpr(struct fetch_context *ctx, struct process *proc,
2e4be5
-	     struct arg_type_info *info, struct value *valuep)
2e4be5
+	     struct arg_type_info *info, struct value *valuep,
2e4be5
+	     size_t off, bool is_hfa_type)
2e4be5
 {
2e4be5
 	if (ctx->greg > 10)
2e4be5
-		return allocate_stack_slot(ctx, proc, info, valuep);
2e4be5
+		return allocate_stack_slot(ctx, proc, info, valuep, is_hfa_type);
2e4be5
 
2e4be5
-	int reg_num = ctx->greg++;
2e4be5
-	if (valuep == NULL)
2e4be5
-		return 0;
2e4be5
+	int reg_num = ctx->greg;
2e4be5
 
2e4be5
 	size_t sz = type_sizeof(proc, info);
2e4be5
 	if (sz == (size_t)-1)
2e4be5
 		return -1;
2e4be5
 	assert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
2e4be5
+#if _CALL_ELF == 2
2e4be5
+	/* Consume the stack slot corresponding to this arg.  */
2e4be5
+	if ((sz + off) >= 8)
2e4be5
+		ctx->greg++;
2e4be5
+
2e4be5
+	if (is_hfa_type)
2e4be5
+		ctx->stack_pointer += sz;
2e4be5
+	else
2e4be5
+		ctx->stack_pointer += 8;
2e4be5
+#else
2e4be5
+	ctx->greg++;
2e4be5
+#endif
2e4be5
+
2e4be5
+	if (valuep == NULL)
2e4be5
+		return 0;
2e4be5
+
2e4be5
 	if (value_reserve(valuep, sz) == NULL)
2e4be5
 		return -1;
2e4be5
 
2e4be5
@@ -240,13 +286,14 @@ allocate_gpr(struct fetch_context *ctx, struct process *proc,
2e4be5
 	u.i64 = read_gpr(ctx, proc, reg_num);
2e4be5
 	if (proc->e_machine == EM_PPC)
2e4be5
 		align_small_int(u.buf, 8, sz);
2e4be5
-	memcpy(value_get_raw_data(valuep), u.buf, sz);
2e4be5
+	memcpy(value_get_raw_data(valuep), u.buf + off, sz);
2e4be5
 	return 0;
2e4be5
 }
2e4be5
 
2e4be5
 static int
2e4be5
 allocate_float(struct fetch_context *ctx, struct process *proc,
2e4be5
-	       struct arg_type_info *info, struct value *valuep)
2e4be5
+	       struct arg_type_info *info, struct value *valuep,
2e4be5
+	       size_t off, bool is_hfa_type)
2e4be5
 {
2e4be5
 	int pool = proc->e_machine == EM_PPC64 ? 13 : 8;
2e4be5
 	if (ctx->freg <= pool) {
2e4be5
@@ -257,8 +304,12 @@ allocate_float(struct fetch_context *ctx, struct process *proc,
2e4be5
 		} u = { .d = ctx->fpregs.fpregs[ctx->freg] };
2e4be5
 
2e4be5
 		ctx->freg++;
2e4be5
+
2e4be5
+		if (!is_hfa_type)
2e4be5
+			ctx->vgreg++;
2e4be5
+
2e4be5
 		if (proc->e_machine == EM_PPC64)
2e4be5
-			allocate_gpr(ctx, proc, info, NULL);
2e4be5
+			allocate_gpr(ctx, proc, info, NULL, off, is_hfa_type);
2e4be5
 
2e4be5
 		size_t sz = sizeof(double);
2e4be5
 		if (info->type == ARGTYPE_FLOAT) {
2e4be5
@@ -272,8 +323,128 @@ allocate_float(struct fetch_context *ctx, struct process *proc,
2e4be5
 		memcpy(value_get_raw_data(valuep), u.buf, sz);
2e4be5
 		return 0;
2e4be5
 	}
2e4be5
-	return allocate_stack_slot(ctx, proc, info, valuep);
2e4be5
+	return allocate_stack_slot(ctx, proc, info, valuep, is_hfa_type);
2e4be5
+}
2e4be5
+
2e4be5
+#if _CALL_ELF == 2
2e4be5
+static int
2e4be5
+allocate_hfa(struct fetch_context *ctx, struct process *proc,
2e4be5
+	     struct arg_type_info *info, struct value *valuep,
2e4be5
+	     enum arg_type hfa_type, size_t hfa_count)
2e4be5
+{
2e4be5
+	size_t sz = type_sizeof(proc, info);
2e4be5
+	if (sz == (size_t)-1)
2e4be5
+		return -1;
2e4be5
+
2e4be5
+	ctx->struct_hfa_size += sz;
2e4be5
+
2e4be5
+	/* There are two changes regarding structure return types:
2e4be5
+	 * * heterogeneous float/vector structs are returned
2e4be5
+	 *   in (multiple) FP/vector registers,
2e4be5
+	 *   instead of via implicit reference.
2e4be5
+	 * * small structs (up to 16 bytes) are return
2e4be5
+	 *   in one or two GPRs, instead of via implicit reference.
2e4be5
+	 *
2e4be5
+	 * Other structures (larger than 16 bytes, not heterogeneous)
2e4be5
+	 * are still returned via implicit reference (i.e. a pointer
2e4be5
+	 * to memory where to return the struct being passed in r3).
2e4be5
+	 * Of course, whether or not an implicit reference pointer
2e4be5
+	 * is present will shift the remaining arguments,
2e4be5
+	 * so you need to get this right for ELFv2 in order
2e4be5
+	 * to get the arguments correct.
2e4be5
+	 * If an actual parameter is known to correspond to an HFA
2e4be5
+	 * formal parameter, each element is passed in the next
2e4be5
+	 * available floating-point argument register starting at fp1
2e4be5
+	 * until the fp13. The remaining elements of the aggregate are
2e4be5
+	 * passed on the stack.  */
2e4be5
+	size_t slot_off = 0;
2e4be5
+
2e4be5
+	unsigned char *buf = value_reserve(valuep, sz);
2e4be5
+	if (buf == NULL)
2e4be5
+		return -1;
2e4be5
+
2e4be5
+	struct arg_type_info *hfa_info = type_get_simple(hfa_type);
2e4be5
+	size_t hfa_sz = type_sizeof(proc, hfa_info);
2e4be5
+
2e4be5
+	if (hfa_count > 8)
2e4be5
+		ctx->struct_hfa_count += hfa_count;
2e4be5
+
2e4be5
+	while (hfa_count > 0 && ctx->freg <= 13) {
2e4be5
+		int rc;
2e4be5
+		struct value tmp;
2e4be5
+
2e4be5
+		value_init(&tmp, proc, NULL, hfa_info, 0);
2e4be5
+
2e4be5
+		/* Hetereogeneous struct - get value on GPR or stack.  */
2e4be5
+		if (((hfa_type == ARGTYPE_FLOAT
2e4be5
+		    || hfa_type == ARGTYPE_DOUBLE)
2e4be5
+		      && hfa_count <= 8))
2e4be5
+			rc = allocate_float(ctx, proc, hfa_info, &tmp,
2e4be5
+						slot_off, true);
2e4be5
+		else
2e4be5
+			rc = allocate_gpr(ctx, proc, hfa_info, &tmp,
2e4be5
+						slot_off, true);
2e4be5
+
2e4be5
+		memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
2e4be5
+
2e4be5
+		slot_off += hfa_sz;
2e4be5
+		buf += hfa_sz;
2e4be5
+		hfa_count--;
2e4be5
+		if (slot_off == 8) {
2e4be5
+			slot_off = 0;
2e4be5
+			ctx->vgreg++;
2e4be5
+		}
2e4be5
+
2e4be5
+		value_destroy(&tmp);
2e4be5
+		if (rc < 0)
2e4be5
+			return -1;
2e4be5
+	}
2e4be5
+	if (hfa_count == 0)
2e4be5
+		return 0;
2e4be5
+
2e4be5
+	/* if no remaining FP, GPR corresponding to slot is used
2e4be5
+	* Mostly it is in part of r10.  */
2e4be5
+	if (ctx->struct_hfa_size <= 64 && ctx->vgreg == 10) {
2e4be5
+		while (ctx->vgreg <= 10) {
2e4be5
+			struct value tmp;
2e4be5
+			value_init(&tmp, proc, NULL, hfa_info, 0);
2e4be5
+			union {
2e4be5
+				uint64_t i64;
2e4be5
+				unsigned char buf[0];
2e4be5
+			} u;
2e4be5
+
2e4be5
+			u.i64 = read_gpr(ctx, proc, ctx->vgreg);
2e4be5
+
2e4be5
+			memcpy(buf, u.buf + slot_off, hfa_sz);
2e4be5
+			slot_off += hfa_sz;
2e4be5
+			buf += hfa_sz;
2e4be5
+			hfa_count--;
2e4be5
+			ctx->stack_pointer += hfa_sz;
2e4be5
+			if (slot_off >= 8 ) {
2e4be5
+				slot_off = 0;
2e4be5
+				ctx->vgreg++;
2e4be5
+			}
2e4be5
+			value_destroy(&tmp);
2e4be5
+		}
2e4be5
+	}
2e4be5
+
2e4be5
+	if (hfa_count == 0)
2e4be5
+		return 0;
2e4be5
+
2e4be5
+	/* Remaining values are on stack */
2e4be5
+	while (hfa_count) {
2e4be5
+		struct value tmp;
2e4be5
+		value_init(&tmp, proc, NULL, hfa_info, 0);
2e4be5
+
2e4be5
+		value_in_inferior(&tmp, ctx->stack_pointer);
2e4be5
+		memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
2e4be5
+		ctx->stack_pointer += hfa_sz;
2e4be5
+		buf += hfa_sz;
2e4be5
+		hfa_count--;
2e4be5
+	}
2e4be5
+	return 0;
2e4be5
 }
2e4be5
+#endif
2e4be5
 
2e4be5
 static int
2e4be5
 allocate_argument(struct fetch_context *ctx, struct process *proc,
2e4be5
@@ -287,13 +458,25 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
2e4be5
 
2e4be5
 	case ARGTYPE_FLOAT:
2e4be5
 	case ARGTYPE_DOUBLE:
2e4be5
-		return allocate_float(ctx, proc, info, valuep);
2e4be5
+		return allocate_float(ctx, proc, info, valuep,
2e4be5
+					8 - type_sizeof(proc,info), false);
2e4be5
 
2e4be5
 	case ARGTYPE_STRUCT:
2e4be5
 		if (proc->e_machine == EM_PPC) {
2e4be5
 			if (value_pass_by_reference(valuep) < 0)
2e4be5
 				return -1;
2e4be5
 		} else {
2e4be5
+#if _CALL_ELF == 2
2e4be5
+			struct arg_type_info *hfa_info;
2e4be5
+			size_t hfa_size;
2e4be5
+			hfa_info = type_get_hfa_type(info, &hfa_size);
2e4be5
+			if (hfa_info != NULL ) {
2e4be5
+				size_t sz = type_sizeof(proc, info);
2e4be5
+				ctx->struct_size += sz;
2e4be5
+				return allocate_hfa(ctx, proc, info, valuep,
2e4be5
+						hfa_info->type, hfa_size);
2e4be5
+			}
2e4be5
+#endif
2e4be5
 			/* PPC64: Fixed size aggregates and unions passed by
2e4be5
 			 * value are mapped to as many doublewords of the
2e4be5
 			 * parameter save area as the value uses in memory.
2e4be5
@@ -326,6 +509,10 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
2e4be5
 	size_t sz = type_sizeof(proc, valuep->type);
2e4be5
 	if (sz == (size_t)-1)
2e4be5
 		return -1;
2e4be5
+
2e4be5
+	if (ctx->ret_struct)
2e4be5
+		ctx->struct_size += sz;
2e4be5
+
2e4be5
 	size_t slots = (sz + width - 1) / width;  /* Round up.  */
2e4be5
 	unsigned char *buf = value_reserve(valuep, slots * width);
2e4be5
 	if (buf == NULL)
2e4be5
@@ -346,9 +533,11 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
2e4be5
 		struct arg_type_info *fp_info
2e4be5
 			= type_get_fp_equivalent(valuep->type);
2e4be5
 		if (fp_info != NULL)
2e4be5
-			rc = allocate_float(ctx, proc, fp_info, &val;;
2e4be5
+			rc = allocate_float(ctx, proc, fp_info, &val,
2e4be5
+					8-type_sizeof(proc,info), false);
2e4be5
 		else
2e4be5
-			rc = allocate_gpr(ctx, proc, long_info, &val;;
2e4be5
+			rc = allocate_gpr(ctx, proc, long_info, &val,
2e4be5
+					0, false);
2e4be5
 
2e4be5
 		if (rc >= 0) {
2e4be5
 			memcpy(ptr, value_get_data(&val, NULL), width);
2e4be5
@@ -363,6 +552,7 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
2e4be5
 			return rc;
2e4be5
 	}
2e4be5
 
2e4be5
+#ifndef __LITTLE_ENDIAN__
2e4be5
 	/* Small values need post-processing.  */
2e4be5
 	if (sz < width) {
2e4be5
 		switch (info->type) {
2e4be5
@@ -394,6 +584,7 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
2e4be5
 			break;
2e4be5
 		}
2e4be5
 	}
2e4be5
+#endif
2e4be5
 
2e4be5
 	return 0;
2e4be5
 }
2e4be5
@@ -411,7 +602,22 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
2e4be5
 		  struct process *proc, struct arg_type_info *info,
2e4be5
 		  struct value *valuep)
2e4be5
 {
2e4be5
+	if (fetch_context_init(proc, ctx) < 0)
2e4be5
+		return -1;
2e4be5
+
2e4be5
+#if _CALL_ELF == 2
2e4be5
+	void *ptr = (void *)(ctx->regs.r64[1]+32);
2e4be5
+	uint64_t val = ptrace(PTRACE_PEEKTEXT, proc->pid, ptr, 0);
2e4be5
+
2e4be5
+	if (ctx->ret_struct
2e4be5
+	   && ((ctx->struct_size > 64
2e4be5
+	      || ctx->struct_hfa_count > 8
2e4be5
+	      || (ctx->struct_hfa_size == 0 && ctx->struct_size > 56)
2e4be5
+	      || (ctx->regs.r64[3] == ctx->regs.r64[1]+32)
2e4be5
+	      || (ctx->regs.r64[3] == val )))) {
2e4be5
+#else
2e4be5
 	if (ctx->ret_struct) {
2e4be5
+#endif
2e4be5
 		assert(info->type == ARGTYPE_STRUCT);
2e4be5
 
2e4be5
 		uint64_t addr = read_gpr(ctx, proc, 3);
2e4be5
@@ -424,8 +630,6 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
2e4be5
 		return 0;
2e4be5
 	}
2e4be5
 
2e4be5
-	if (fetch_context_init(proc, ctx) < 0)
2e4be5
-		return -1;
2e4be5
 	return allocate_argument(ctx, proc, info, valuep);
2e4be5
 }
2e4be5
 
2e4be5
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
2e4be5
index 332daa8..45ed7fb 100644
2e4be5
--- a/sysdeps/linux-gnu/ppc/plt.c
2e4be5
+++ b/sysdeps/linux-gnu/ppc/plt.c
2e4be5
@@ -136,7 +136,11 @@
2e4be5
  */
2e4be5
 
2e4be5
 #define PPC_PLT_STUB_SIZE 16
2e4be5
-#define PPC64_PLT_STUB_SIZE 8 //xxx
2e4be5
+#if _CALL_ELF != 2
2e4be5
+#define PPC64_PLT_STUB_SIZE 8
2e4be5
+#else
2e4be5
+#define PPC64_PLT_STUB_SIZE 4
2e4be5
+#endif
2e4be5
 
2e4be5
 static inline int
2e4be5
 host_powerpc64()
2e4be5
@@ -186,8 +190,13 @@ ppc32_delayed_symbol(struct library_symbol *libsym)
2e4be5
 	if ((insn1 & BRANCH_MASK) == B_INSN
2e4be5
 	    || ((insn2 & BRANCH_MASK) == B_INSN
2e4be5
 		/* XXX double cast  */
2e4be5
+#ifdef __LITTLE_ENDIAN__
2e4be5
+		&& (ppc_branch_dest(libsym->enter_addr + 4, insn1)
2e4be5
+		    == (arch_addr_t) (long) libsym->lib->arch.pltgot_addr)))
2e4be5
+#else
2e4be5
 		&& (ppc_branch_dest(libsym->enter_addr + 4, insn2)
2e4be5
 		    == (arch_addr_t) (long) libsym->lib->arch.pltgot_addr)))
2e4be5
+#endif
2e4be5
 	{
2e4be5
 		mark_as_resolved(libsym, libsym->arch.resolved_value);
2e4be5
 	}
2e4be5
@@ -206,7 +215,7 @@ arch_dynlink_done(struct process *proc)
2e4be5
 				"couldn't read PLT value for %s(%p): %s\n",
2e4be5
 				libsym->name, libsym->enter_addr,
2e4be5
 				strerror(errno));
2e4be5
-			return;
2e4be5
+				return;
2e4be5
 		}
2e4be5
 
2e4be5
 		if (proc->e_machine == EM_PPC)
2e4be5
@@ -227,8 +236,14 @@ reloc_is_irelative(int machine, GElf_Rela *rela)
2e4be5
 {
2e4be5
 	bool irelative = false;
2e4be5
 	if (machine == EM_PPC64) {
2e4be5
-#ifdef R_PPC64_JMP_IREL
2e4be5
+#ifdef __LITTLE_ENDIAN__
2e4be5
+# ifdef R_PPC64_IRELATIVE
2e4be5
+		irelative = GELF_R_TYPE(rela->r_info) == R_PPC64_IRELATIVE;
2e4be5
+# endif
2e4be5
+#else
2e4be5
+# ifdef R_PPC64_JMP_IREL
2e4be5
 		irelative = GELF_R_TYPE(rela->r_info) == R_PPC64_JMP_IREL;
2e4be5
+# endif
2e4be5
 #endif
2e4be5
 	} else {
2e4be5
 		assert(machine == EM_PPC);
2e4be5
@@ -285,6 +300,7 @@ arch_translate_address_dyn(struct process *proc,
2e4be5
 			   arch_addr_t addr, arch_addr_t *ret)
2e4be5
 {
2e4be5
 	if (proc->e_machine == EM_PPC64) {
2e4be5
+#if _CALL_ELF != 2
2e4be5
 		uint64_t value;
2e4be5
 		if (proc_read_64(proc, addr, &value) < 0) {
2e4be5
 			fprintf(stderr,
2e4be5
@@ -296,6 +312,7 @@ arch_translate_address_dyn(struct process *proc,
2e4be5
 		 * arch_addr_t becomes integral type.  */
2e4be5
 		*ret = (arch_addr_t)(uintptr_t)value;
2e4be5
 		return 0;
2e4be5
+#endif
2e4be5
 	}
2e4be5
 
2e4be5
 	*ret = addr;
2e4be5
@@ -306,7 +323,8 @@ int
2e4be5
 arch_translate_address(struct ltelf *lte,
2e4be5
 		       arch_addr_t addr, arch_addr_t *ret)
2e4be5
 {
2e4be5
-	if (lte->ehdr.e_machine == EM_PPC64) {
2e4be5
+	if (lte->ehdr.e_machine == EM_PPC64
2e4be5
+	    && !lte->arch.elfv2_abi) {
2e4be5
 		/* XXX The double cast should be removed when
2e4be5
 		 * arch_addr_t becomes integral type.  */
2e4be5
 		GElf_Xword offset
2e4be5
@@ -430,7 +448,16 @@ reloc_copy_if_irelative(GElf_Rela *rela, void *data)
2e4be5
 int
2e4be5
 arch_elf_init(struct ltelf *lte, struct library *lib)
2e4be5
 {
2e4be5
+
2e4be5
+	/* Check for ABIv2 in ELF header processor specific flag.  */
2e4be5
+#ifndef EF_PPC64_ABI
2e4be5
+	assert (! (lte->ehdr.e_flags & 3 ) == 2)
2e4be5
+#else
2e4be5
+	lte->arch.elfv2_abi=((lte->ehdr.e_flags & EF_PPC64_ABI) == 2) ;
2e4be5
+#endif
2e4be5
+
2e4be5
 	if (lte->ehdr.e_machine == EM_PPC64
2e4be5
+	    && !lte->arch.elfv2_abi
2e4be5
 	    && load_opd_data(lte, lib) < 0)
2e4be5
 		return -1;
2e4be5
 
2e4be5
@@ -599,7 +626,7 @@ read_plt_slot_value(struct process *proc, GElf_Addr addr, GElf_Addr *valp)
2e4be5
 	uint64_t l;
2e4be5
 	/* XXX double cast.  */
2e4be5
 	if (proc_read_64(proc, (arch_addr_t)(uintptr_t)addr, &l) < 0) {
2e4be5
-		fprintf(stderr, "ptrace .plt slot value @%#" PRIx64": %s\n",
2e4be5
+		debug(DEBUG_EVENT, "ptrace .plt slot value @%#" PRIx64": %s",
2e4be5
 			addr, strerror(errno));
2e4be5
 		return -1;
2e4be5
 	}
2e4be5
@@ -616,7 +643,7 @@ unresolve_plt_slot(struct process *proc, GElf_Addr addr, GElf_Addr value)
2e4be5
 	 * pointers intact.  Hence the only adjustment that we need to
2e4be5
 	 * do is to IP.  */
2e4be5
 	if (ptrace(PTRACE_POKETEXT, proc->pid, addr, value) < 0) {
2e4be5
-		fprintf(stderr, "failed to unresolve .plt slot: %s\n",
2e4be5
+		debug(DEBUG_EVENT, "failed to unresolve .plt slot: %s",
2e4be5
 			strerror(errno));
2e4be5
 		return -1;
2e4be5
 	}
2e4be5
@@ -629,9 +656,48 @@ arch_elf_add_func_entry(struct process *proc, struct ltelf *lte,
2e4be5
 			arch_addr_t addr, const char *name,
2e4be5
 			struct library_symbol **ret)
2e4be5
 {
2e4be5
-	if (lte->ehdr.e_machine != EM_PPC || lte->ehdr.e_type == ET_DYN)
2e4be5
+#ifndef PPC64_LOCAL_ENTRY_OFFSET
2e4be5
+	assert(! lte->arch.elfv2_abi);
2e4be5
+#else
2e4be5
+	/* With ABIv2 st_other field contains an offset.  */
2e4be5
+	 if (lte->arch.elfv2_abi)
2e4be5
+		addr += PPC64_LOCAL_ENTRY_OFFSET(sym->st_other);
2e4be5
+#endif
2e4be5
+
2e4be5
+	int st_info = GELF_ST_TYPE(sym->st_info);
2e4be5
+
2e4be5
+	if ((lte->ehdr.e_machine != EM_PPC && sym->st_other == 0)
2e4be5
+	    || lte->ehdr.e_type == ET_DYN
2e4be5
+	    || (st_info == STT_FUNC && ! sym->st_other))
2e4be5
 		return PLT_DEFAULT;
2e4be5
 
2e4be5
+	if (st_info == STT_FUNC) {
2e4be5
+		/* Put the default symbol to the chain.
2e4be5
+		 * The addr has already been updated with
2e4be5
+		 * symbol offset  */
2e4be5
+		char *full_name = strdup(name);
2e4be5
+		if (full_name == NULL) {
2e4be5
+			fprintf(stderr, "couldn't copy name of %s: %s\n",
2e4be5
+			name, strerror(errno));
2e4be5
+			free(full_name);
2e4be5
+			return PLT_FAIL;
2e4be5
+		}
2e4be5
+		struct library_symbol *libsym = malloc(sizeof *libsym);
2e4be5
+		if (libsym == NULL
2e4be5
+		    || library_symbol_init(libsym, addr, full_name, 1,
2e4be5
+					   LS_TOPLT_NONE) < 0) {
2e4be5
+			free(libsym);
2e4be5
+			delete_symbol_chain(libsym);
2e4be5
+			libsym = NULL;
2e4be5
+			fprintf(stderr, "Couldn't add symbol %s"
2e4be5
+				"for tracing.\n", name);
2e4be5
+		}
2e4be5
+		full_name = NULL;
2e4be5
+		libsym->next = *ret;
2e4be5
+		*ret = libsym;
2e4be5
+		return PLT_OK;
2e4be5
+	}
2e4be5
+
2e4be5
 	bool ifunc = false;
2e4be5
 #ifdef STT_GNU_IFUNC
2e4be5
 	ifunc = GELF_ST_TYPE(sym->st_info) == STT_GNU_IFUNC;
2e4be5
@@ -761,9 +827,15 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
2e4be5
 	assert(plt_slot_addr >= lte->plt_addr
2e4be5
 	       || plt_slot_addr < lte->plt_addr + lte->plt_size);
2e4be5
 
2e4be5
+	/* Should avoid to do read if dynamic linker hasn't run yet
2e4be5
+	 * or allow -1 a valid return code.  */
2e4be5
 	GElf_Addr plt_slot_value;
2e4be5
-	if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0)
2e4be5
-		goto fail;
2e4be5
+	if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) {
2e4be5
+		if (!lte->arch.elfv2_abi)
2e4be5
+			goto fail;
2e4be5
+		else
2e4be5
+			return PPC_PLT_UNRESOLVED;
2e4be5
+	}
2e4be5
 
2e4be5
 	struct library_symbol *libsym = malloc(sizeof(*libsym));
2e4be5
 	if (libsym == NULL) {
2e4be5
@@ -997,8 +1069,12 @@ ppc_plt_bp_continue(struct breakpoint *bp, struct process *proc)
2e4be5
 			return;
2e4be5
 		}
2e4be5
 
2e4be5
+#if _CALL_ELF == 2
2e4be5
+		continue_after_breakpoint(proc, bp);
2e4be5
+#else
2e4be5
 		jump_to_entry_point(proc, bp);
2e4be5
 		continue_process(proc->pid);
2e4be5
+#endif
2e4be5
 		return;
2e4be5
 
2e4be5
 	case PPC64_PLT_STUB:
2e4be5
@@ -1123,7 +1199,11 @@ arch_library_symbol_init(struct library_symbol *libsym)
2e4be5
 	/* We set type explicitly in the code above, where we have the
2e4be5
 	 * necessary context.  This is for calls from ltrace-elf.c and
2e4be5
 	 * such.  */
2e4be5
+#if _CALL_ELF == 2
2e4be5
+	libsym->arch.type = PPC_PLT_UNRESOLVED;
2e4be5
+#else
2e4be5
 	libsym->arch.type = PPC_DEFAULT;
2e4be5
+#endif
2e4be5
 	return 0;
2e4be5
 }
2e4be5
 
2e4be5
diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
2e4be5
index ee9a6b5..5aab538 100644
2e4be5
--- a/sysdeps/linux-gnu/ppc/trace.c
2e4be5
+++ b/sysdeps/linux-gnu/ppc/trace.c
2e4be5
@@ -65,9 +65,15 @@ syscall_p(struct process *proc, int status, int *sysnum)
2e4be5
 	if (WIFSTOPPED(status)
2e4be5
 	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
2e4be5
 		long pc = (long)get_instruction_pointer(proc);
2e4be5
+#ifndef __LITTLE_ENDIAN__
2e4be5
 		int insn =
2e4be5
 		    (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long),
2e4be5
 				0);
2e4be5
+#else
2e4be5
+		int insn =
2e4be5
+		    (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(int),
2e4be5
+				0);
2e4be5
+#endif
2e4be5
 
2e4be5
 		if (insn == SYSCALL_INSN) {
2e4be5
 			*sysnum =
2e4be5
diff -up ltrace-0.7.91/sysdeps/linux-gnu/ppc/trace.c\~ ltrace-0.7.91/sysdeps/linux-gnu/ppc/trace.c
2e4be5
--- ltrace-0.7.91/sysdeps/linux-gnu/ppc/trace.c~	2014-08-08 14:05:58.000000000 +0200
2e4be5
+++ ltrace-0.7.91/sysdeps/linux-gnu/ppc/trace.c	2014-08-08 14:07:55.000000000 +0200
2e4be5
@@ -133,7 +133,11 @@ arch_sw_singlestep(struct process *proc,
2e4be5
 			return SWS_FAIL;
2e4be5
 		uint32_t insn;
2e4be5
 #ifdef __powerpc64__
2e4be5
+# ifdef __LITTLE_ENDIAN__
2e4be5
+		insn = (uint32_t) l;
2e4be5
+# else
2e4be5
 		insn = l >> 32;
2e4be5
+# endif
2e4be5
 #else
2e4be5
 		insn = l;
2e4be5
 #endif
2e4be5
diff -up ltrace-0.7.91/configure\~ ltrace-0.7.91/configure
2e4be5
--- ltrace-0.7.91/configure~	2014-08-08 14:09:12.000000000 +0200
2e4be5
+++ ltrace-0.7.91/configure	2014-08-08 14:18:30.000000000 +0200
2e4be5
@@ -2555,7 +2555,7 @@ case "${host_cpu}" in
2e4be5
     arm*|sa110)		HOST_CPU="arm" ;;
2e4be5
     cris*)		HOST_CPU="cris" ;;
2e4be5
     mips*)		HOST_CPU="mips" ;;
2e4be5
-    powerpc|powerpc64)	HOST_CPU="ppc" ;;
2e4be5
+    powerpc|powerpc64|powerpc64le)	HOST_CPU="ppc" ;;
2e4be5
     sun4u|sparc64)	HOST_CPU="sparc" ;;
2e4be5
     s390x)		HOST_CPU="s390" ;;
2e4be5
     i?86|x86_64)	HOST_CPU="x86" ;;
2e4be5
@@ -12094,7 +12094,7 @@ if test x"$enable_libunwind" = xyes; the
2e4be5
       arm*|sa110)         UNWIND_ARCH="arm" ;;
2e4be5
       i?86)               UNWIND_ARCH="x86" ;;
2e4be5
       powerpc)            UNWIND_ARCH="ppc32" ;;
2e4be5
-      powerpc64)          UNWIND_ARCH="ppc64" ;;
2e4be5
+      powerpc64|powerpc64le)          UNWIND_ARCH="ppc64" ;;
2e4be5
       mips*)              UNWIND_ARCH="mips" ;;
2e4be5
       *)                  UNWIND_ARCH="${host_cpu}" ;;
2e4be5
   esac