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

8d9cfe
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
8d9cfe
index d5ad759..a8b67bb 100644
8d9cfe
--- a/sysdeps/linux-gnu/ppc/arch.h
8d9cfe
+++ b/sysdeps/linux-gnu/ppc/arch.h
8d9cfe
@@ -32,36 +32,45 @@
8d9cfe
 #define LT_ELF_MACHINE	EM_PPC
8d9cfe
 
8d9cfe
 #ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target.
8d9cfe
-#define LT_ELFCLASS2	ELFCLASS64
8d9cfe
-#define LT_ELF_MACHINE2	EM_PPC64
8d9cfe
+# define LT_ELFCLASS2	ELFCLASS64
8d9cfe
+# define LT_ELF_MACHINE2	EM_PPC64
8d9cfe
 
8d9cfe
 # ifdef __LITTLE_ENDIAN__
8d9cfe
-# define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f }
8d9cfe
-# define ARCH_ENDIAN_LITTLE
8d9cfe
+#  define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f }
8d9cfe
+#  define ARCH_ENDIAN_LITTLE
8d9cfe
 # else
8d9cfe
-# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
8d9cfe
-# define ARCH_SUPPORTS_OPD
8d9cfe
-# define ARCH_ENDIAN_BIG
8d9cfe
+#  define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
8d9cfe
+#  define ARCH_SUPPORTS_OPD
8d9cfe
+#  define ARCH_ENDIAN_BIG
8d9cfe
 # endif
8d9cfe
 
8d9cfe
-# if _CALL_ELF != 2
8d9cfe
-# define ARCH_SUPPORTS_OPD
8d9cfe
-# define STACK_FRAME_OVERHEAD 112
8d9cfe
+# if !defined(_CALL_ELF) || _CALL_ELF < 2
8d9cfe
+#  define ARCH_SUPPORTS_OPD
8d9cfe
+#  define STACK_FRAME_OVERHEAD 112
8d9cfe
 #  ifndef EF_PPC64_ABI
8d9cfe
-#  define EF_PPC64_ABI 3
8d9cfe
+#   define EF_PPC64_ABI 3
8d9cfe
 #  endif
8d9cfe
-# else /* _CALL_ELF == 2 ABIv2 */
8d9cfe
-# define STACK_FRAME_OVERHEAD 32
8d9cfe
+# elif _CALL_ELF == 2  /* ELFv2 ABI */
8d9cfe
+#  define STACK_FRAME_OVERHEAD 32
8d9cfe
+# else
8d9cfe
+#  error Unsupported PowerPC64 ABI.
8d9cfe
 # endif /* CALL_ELF */
8d9cfe
 
8d9cfe
 #else
8d9cfe
-#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
8d9cfe
-#define ARCH_ENDIAN_BIG
8d9cfe
+# define STACK_FRAME_OVERHEAD 112
8d9cfe
+# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
8d9cfe
+# define ARCH_ENDIAN_BIG
8d9cfe
 # ifndef EF_PPC64_ABI
8d9cfe
-# define EF_PPC64_ABI 3
8d9cfe
+#  define EF_PPC64_ABI 3
8d9cfe
 # endif
8d9cfe
 #endif 	/* __powerpc64__ */
8d9cfe
 
8d9cfe
+#ifdef _CALL_ELF
8d9cfe
+enum { ppc64_call_elf_abi = _CALL_ELF };
8d9cfe
+#else
8d9cfe
+enum { ppc64_call_elf_abi = 0 };
8d9cfe
+#endif
8d9cfe
+
8d9cfe
 #define ARCH_HAVE_SW_SINGLESTEP
8d9cfe
 #define ARCH_HAVE_ADD_PLT_ENTRY
8d9cfe
 #define ARCH_HAVE_ADD_FUNC_ENTRY
8d9cfe
diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c
8d9cfe
index c9381c3..c6cbd71 100644
8d9cfe
--- a/sysdeps/linux-gnu/ppc/fetch.c
8d9cfe
+++ b/sysdeps/linux-gnu/ppc/fetch.c
8d9cfe
@@ -1,6 +1,6 @@
8d9cfe
 /*
8d9cfe
  * This file is part of ltrace.
8d9cfe
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
8d9cfe
+ * Copyright (C) 2012, 2014 Petr Machata, Red Hat Inc.
8d9cfe
  *
8d9cfe
  * This program is free software; you can redistribute it and/or
8d9cfe
  * modify it under the terms of the GNU General Public License as
8d9cfe
@@ -23,6 +23,7 @@
8d9cfe
 #include <stdlib.h>
8d9cfe
 #include <string.h>
8d9cfe
 #include <sys/ucontext.h>
8d9cfe
+#include <stdio.h>
8d9cfe
 
8d9cfe
 #include "backend.h"
8d9cfe
 #include "fetch.h"
8d9cfe
@@ -57,7 +58,7 @@ struct fetch_context {
8d9cfe
 	arch_addr_t stack_pointer;
8d9cfe
 	int greg;
8d9cfe
 	int freg;
8d9cfe
-	int ret_struct;
8d9cfe
+	bool ret_struct;
8d9cfe
 
8d9cfe
 	union {
8d9cfe
 		gregs32_t r32;
8d9cfe
@@ -65,11 +66,29 @@ struct fetch_context {
8d9cfe
 	} regs;
8d9cfe
 	struct fpregs_t fpregs;
8d9cfe
 	int vgreg;
8d9cfe
-	int struct_size;
8d9cfe
-	int struct_hfa_size;
8d9cfe
-	int struct_hfa_count;
8d9cfe
 };
8d9cfe
 
8d9cfe
+static bool
8d9cfe
+is_eligible_hfa(struct arg_type_info *info,
8d9cfe
+		struct arg_type_info **hfa_infop, size_t *hfa_countp)
8d9cfe
+{
8d9cfe
+	size_t hfa_count;
8d9cfe
+	struct arg_type_info *hfa_info = type_get_hfa_type(info, &hfa_count);
8d9cfe
+
8d9cfe
+	if (hfa_info != NULL && hfa_count <= 8
8d9cfe
+	    && (hfa_info->type == ARGTYPE_FLOAT
8d9cfe
+		|| hfa_info->type == ARGTYPE_DOUBLE)) {
8d9cfe
+
8d9cfe
+		if (hfa_infop != NULL)
8d9cfe
+			*hfa_infop = hfa_info;
8d9cfe
+		if (hfa_countp != NULL)
8d9cfe
+			*hfa_countp = hfa_count;
8d9cfe
+		return true;
8d9cfe
+	}
8d9cfe
+
8d9cfe
+	return false;
8d9cfe
+}
8d9cfe
+
8d9cfe
 static int
8d9cfe
 fetch_context_init(struct process *proc, struct fetch_context *context)
8d9cfe
 {
8d9cfe
@@ -125,30 +144,37 @@ arch_fetch_arg_init(enum tof type, struct process *proc,
8d9cfe
 	}
8d9cfe
 
8d9cfe
 	context->vgreg = context->greg;
8d9cfe
-	context->struct_size = 0;
8d9cfe
-	context->struct_hfa_size = 0;
8d9cfe
-	context->struct_hfa_count = 0;
8d9cfe
 
8d9cfe
 	/* Aggregates or unions of any length, and character strings
8d9cfe
 	 * of length longer than 8 bytes, will be returned in a
8d9cfe
 	 * storage buffer allocated by the caller. The caller will
8d9cfe
 	 * pass the address of this buffer as a hidden first argument
8d9cfe
 	 * in r3, causing the first explicit argument to be passed in
8d9cfe
-	 * r4.  */
8d9cfe
-	context->ret_struct = ret_info->type == ARGTYPE_STRUCT;
8d9cfe
-	if (context->ret_struct) {
8d9cfe
-#if _CALL_ELF == 2
8d9cfe
-		/* if R3 points to stack, parameters will be in R4.  */
8d9cfe
-		uint64_t pstack_end = ptrace(PTRACE_PEEKTEXT, proc->pid,
8d9cfe
-					proc->stack_pointer, 0);
8d9cfe
-		if (((arch_addr_t)context->regs.r64[3] > proc->stack_pointer)
8d9cfe
-		    && (context->regs.r64[3] < pstack_end)) {
8d9cfe
+	 * r4.
8d9cfe
+	 */
8d9cfe
+
8d9cfe
+	context->ret_struct = false;
8d9cfe
+
8d9cfe
+	if (ppc64_call_elf_abi == 2) {
8d9cfe
+		/* With ELFv2 ABI, aggregates that consist
8d9cfe
+		 * (recursively) only of members of the same
8d9cfe
+		 * floating-point or vector type, are passed in a
8d9cfe
+		 * series of floating-point resp. vector registers.
8d9cfe
+		 * Additionally, when returning any aggregate of up to
8d9cfe
+		 * 16 bytes, general-purpose registers are used.  */
8d9cfe
+
8d9cfe
+		if (ret_info->type == ARGTYPE_STRUCT
8d9cfe
+		    && ! is_eligible_hfa(ret_info, NULL, NULL)
8d9cfe
+		    && type_sizeof(proc, ret_info) > 16) {
8d9cfe
+
8d9cfe
+			context->ret_struct = true;
8d9cfe
 			context->greg++;
8d9cfe
 			context->stack_pointer += 8;
8d9cfe
 		}
8d9cfe
-#else
8d9cfe
+
8d9cfe
+	} else if (ret_info->type == ARGTYPE_STRUCT) {
8d9cfe
+		context->ret_struct = true;
8d9cfe
 		context->greg++;
8d9cfe
-#endif
8d9cfe
 	}
8d9cfe
 
8d9cfe
 	return context;
8d9cfe
@@ -176,17 +202,16 @@ allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
8d9cfe
 
8d9cfe
 	size_t a = type_alignof(proc, info);
8d9cfe
 	size_t off = 0;
8d9cfe
-	if (proc->e_machine == EM_PPC && a < 4)
8d9cfe
-		a = 4;
8d9cfe
-#if _CALL_ELF == 2
8d9cfe
-	else if (proc->e_machine == EM_PPC64 && sz == 4 && is_hfa_type)
8d9cfe
+	if (proc->e_machine == EM_PPC && a < 4) {
8d9cfe
 		a = 4;
8d9cfe
-	else
8d9cfe
-		a = 8;
8d9cfe
-#else
8d9cfe
-	else if (proc->e_machine == EM_PPC64 && a < 8)
8d9cfe
-#endif
8d9cfe
+	} else if (ppc64_call_elf_abi == 2) {
8d9cfe
+		if (proc->e_machine == EM_PPC64 && sz == 4 && is_hfa_type) {
8d9cfe
+			a = 4;
8d9cfe
+		} else
8d9cfe
+			a = 8;
8d9cfe
+	} else if (proc->e_machine == EM_PPC64 && a < 8) {
8d9cfe
 		a = 8;
8d9cfe
+	}
8d9cfe
 
8d9cfe
 	/* XXX Remove the two double casts when arch_addr_t
8d9cfe
 	 * becomes integral type.  */
8d9cfe
@@ -259,18 +284,19 @@ allocate_gpr(struct fetch_context *ctx, struct process *proc,
8d9cfe
 	if (sz == (size_t)-1)
8d9cfe
 		return -1;
8d9cfe
 	assert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
8d9cfe
-#if _CALL_ELF == 2
8d9cfe
-	/* Consume the stack slot corresponding to this arg.  */
8d9cfe
-	if ((sz + off) >= 8)
8d9cfe
-		ctx->greg++;
8d9cfe
 
8d9cfe
-	if (is_hfa_type)
8d9cfe
-		ctx->stack_pointer += sz;
8d9cfe
-	else
8d9cfe
-		ctx->stack_pointer += 8;
8d9cfe
-#else
8d9cfe
-	ctx->greg++;
8d9cfe
-#endif
8d9cfe
+	if (ppc64_call_elf_abi == 2) {
8d9cfe
+		/* Consume the stack slot corresponding to this arg.  */
8d9cfe
+		if ((sz + off) >= 8)
8d9cfe
+			ctx->greg++;
8d9cfe
+
8d9cfe
+		if (is_hfa_type)
8d9cfe
+			ctx->stack_pointer += sz;
8d9cfe
+		else
8d9cfe
+			ctx->stack_pointer += 8;
8d9cfe
+	} else {
8d9cfe
+		ctx->greg++;
8d9cfe
+	}
8d9cfe
 
8d9cfe
 	if (valuep == NULL)
8d9cfe
 		return 0;
8d9cfe
@@ -326,7 +352,6 @@ allocate_float(struct fetch_context *ctx, struct process *proc,
8d9cfe
 	return allocate_stack_slot(ctx, proc, info, valuep, is_hfa_type);
8d9cfe
 }
8d9cfe
 
8d9cfe
-#if _CALL_ELF == 2
8d9cfe
 static int
8d9cfe
 allocate_hfa(struct fetch_context *ctx, struct process *proc,
8d9cfe
 	     struct arg_type_info *info, struct value *valuep,
8d9cfe
@@ -336,27 +361,27 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
8d9cfe
 	if (sz == (size_t)-1)
8d9cfe
 		return -1;
8d9cfe
 
8d9cfe
-	ctx->struct_hfa_size += sz;
8d9cfe
-
8d9cfe
 	/* There are two changes regarding structure return types:
8d9cfe
-	 * * heterogeneous float/vector structs are returned
8d9cfe
-	 *   in (multiple) FP/vector registers,
8d9cfe
-	 *   instead of via implicit reference.
8d9cfe
-	 * * small structs (up to 16 bytes) are return
8d9cfe
-	 *   in one or two GPRs, instead of via implicit reference.
8d9cfe
+	 * * heterogeneous float/vector structs are returned in
8d9cfe
+	 *   (multiple) FP/vector registers, instead of via implicit
8d9cfe
+	 *   reference.
8d9cfe
+	 * * small structs (up to 16 bytes) are return in one or two
8d9cfe
+	 *   GPRs, instead of via implicit reference.
8d9cfe
 	 *
8d9cfe
 	 * Other structures (larger than 16 bytes, not heterogeneous)
8d9cfe
 	 * are still returned via implicit reference (i.e. a pointer
8d9cfe
 	 * to memory where to return the struct being passed in r3).
8d9cfe
-	 * Of course, whether or not an implicit reference pointer
8d9cfe
-	 * is present will shift the remaining arguments,
8d9cfe
-	 * so you need to get this right for ELFv2 in order
8d9cfe
-	 * to get the arguments correct.
8d9cfe
+	 * Of course, whether or not an implicit reference pointer is
8d9cfe
+	 * present will shift the remaining arguments, so you need to
8d9cfe
+	 * get this right for ELFv2 in order to get the arguments
8d9cfe
+	 * correct.
8d9cfe
+	 *
8d9cfe
 	 * If an actual parameter is known to correspond to an HFA
8d9cfe
 	 * formal parameter, each element is passed in the next
8d9cfe
 	 * available floating-point argument register starting at fp1
8d9cfe
 	 * until the fp13. The remaining elements of the aggregate are
8d9cfe
-	 * passed on the stack.  */
8d9cfe
+	 * passed on the stack.
8d9cfe
+	 */
8d9cfe
 	size_t slot_off = 0;
8d9cfe
 
8d9cfe
 	unsigned char *buf = value_reserve(valuep, sz);
8d9cfe
@@ -366,26 +391,17 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
8d9cfe
 	struct arg_type_info *hfa_info = type_get_simple(hfa_type);
8d9cfe
 	size_t hfa_sz = type_sizeof(proc, hfa_info);
8d9cfe
 
8d9cfe
-	if (hfa_count > 8)
8d9cfe
-		ctx->struct_hfa_count += hfa_count;
8d9cfe
-
8d9cfe
 	while (hfa_count > 0 && ctx->freg <= 13) {
8d9cfe
-		int rc;
8d9cfe
 		struct value tmp;
8d9cfe
-
8d9cfe
 		value_init(&tmp, proc, NULL, hfa_info, 0);
8d9cfe
+		int rc = allocate_float(ctx, proc, hfa_info,
8d9cfe
+					&tmp, slot_off, true);
8d9cfe
+		if (rc == 0)
8d9cfe
+			memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
8d9cfe
+		value_destroy(&tmp);
8d9cfe
 
8d9cfe
-		/* Hetereogeneous struct - get value on GPR or stack.  */
8d9cfe
-		if (((hfa_type == ARGTYPE_FLOAT
8d9cfe
-		    || hfa_type == ARGTYPE_DOUBLE)
8d9cfe
-		      && hfa_count <= 8))
8d9cfe
-			rc = allocate_float(ctx, proc, hfa_info, &tmp,
8d9cfe
-						slot_off, true);
8d9cfe
-		else
8d9cfe
-			rc = allocate_gpr(ctx, proc, hfa_info, &tmp,
8d9cfe
-						slot_off, true);
8d9cfe
-
8d9cfe
-		memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
8d9cfe
+		if (rc < 0)
8d9cfe
+			return -1;
8d9cfe
 
8d9cfe
 		slot_off += hfa_sz;
8d9cfe
 		buf += hfa_sz;
8d9cfe
@@ -394,17 +410,13 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
8d9cfe
 			slot_off = 0;
8d9cfe
 			ctx->vgreg++;
8d9cfe
 		}
8d9cfe
-
8d9cfe
-		value_destroy(&tmp);
8d9cfe
-		if (rc < 0)
8d9cfe
-			return -1;
8d9cfe
 	}
8d9cfe
 	if (hfa_count == 0)
8d9cfe
 		return 0;
8d9cfe
 
8d9cfe
 	/* if no remaining FP, GPR corresponding to slot is used
8d9cfe
-	* Mostly it is in part of r10.  */
8d9cfe
-	if (ctx->struct_hfa_size <= 64 && ctx->vgreg == 10) {
8d9cfe
+	 * Mostly it is in part of r10.  */
8d9cfe
+	if (ctx->vgreg == 10) {
8d9cfe
 		while (ctx->vgreg <= 10) {
8d9cfe
 			struct value tmp;
8d9cfe
 			value_init(&tmp, proc, NULL, hfa_info, 0);
8d9cfe
@@ -428,11 +440,8 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
8d9cfe
 		}
8d9cfe
 	}
8d9cfe
 
8d9cfe
-	if (hfa_count == 0)
8d9cfe
-		return 0;
8d9cfe
-
8d9cfe
 	/* Remaining values are on stack */
8d9cfe
-	while (hfa_count) {
8d9cfe
+	while (hfa_count > 0) {
8d9cfe
 		struct value tmp;
8d9cfe
 		value_init(&tmp, proc, NULL, hfa_info, 0);
8d9cfe
 
8d9cfe
@@ -444,7 +453,6 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
8d9cfe
 	}
8d9cfe
 	return 0;
8d9cfe
 }
8d9cfe
-#endif
8d9cfe
 
8d9cfe
 static int
8d9cfe
 allocate_argument(struct fetch_context *ctx, struct process *proc,
8d9cfe
@@ -459,24 +467,20 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
8d9cfe
 	case ARGTYPE_FLOAT:
8d9cfe
 	case ARGTYPE_DOUBLE:
8d9cfe
 		return allocate_float(ctx, proc, info, valuep,
8d9cfe
-					8 - type_sizeof(proc,info), false);
8d9cfe
+				      8 - type_sizeof(proc,info), false);
8d9cfe
 
8d9cfe
 	case ARGTYPE_STRUCT:
8d9cfe
 		if (proc->e_machine == EM_PPC) {
8d9cfe
 			if (value_pass_by_reference(valuep) < 0)
8d9cfe
 				return -1;
8d9cfe
-		} else {
8d9cfe
-#if _CALL_ELF == 2
8d9cfe
+		} else if (ppc64_call_elf_abi == 2) {
8d9cfe
 			struct arg_type_info *hfa_info;
8d9cfe
-			size_t hfa_size;
8d9cfe
-			hfa_info = type_get_hfa_type(info, &hfa_size);
8d9cfe
-			if (hfa_info != NULL ) {
8d9cfe
-				size_t sz = type_sizeof(proc, info);
8d9cfe
-				ctx->struct_size += sz;
8d9cfe
+			size_t hfa_count;
8d9cfe
+			if (is_eligible_hfa(info, &hfa_info, &hfa_count)) {
8d9cfe
 				return allocate_hfa(ctx, proc, info, valuep,
8d9cfe
-						hfa_info->type, hfa_size);
8d9cfe
+						hfa_info->type, hfa_count);
8d9cfe
 			}
8d9cfe
-#endif
8d9cfe
+		} else {
8d9cfe
 			/* PPC64: Fixed size aggregates and unions passed by
8d9cfe
 			 * value are mapped to as many doublewords of the
8d9cfe
 			 * parameter save area as the value uses in memory.
8d9cfe
@@ -510,9 +514,6 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
8d9cfe
 	if (sz == (size_t)-1)
8d9cfe
 		return -1;
8d9cfe
 
8d9cfe
-	if (ctx->ret_struct)
8d9cfe
-		ctx->struct_size += sz;
8d9cfe
-
8d9cfe
 	size_t slots = (sz + width - 1) / width;  /* Round up.  */
8d9cfe
 	unsigned char *buf = value_reserve(valuep, slots * width);
8d9cfe
 	if (buf == NULL)
8d9cfe
@@ -605,19 +606,7 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
8d9cfe
 	if (fetch_context_init(proc, ctx) < 0)
8d9cfe
 		return -1;
8d9cfe
 
8d9cfe
-#if _CALL_ELF == 2
8d9cfe
-	void *ptr = (void *)(ctx->regs.r64[1]+32);
8d9cfe
-	uint64_t val = ptrace(PTRACE_PEEKTEXT, proc->pid, ptr, 0);
8d9cfe
-
8d9cfe
-	if (ctx->ret_struct
8d9cfe
-	   && ((ctx->struct_size > 64
8d9cfe
-	      || ctx->struct_hfa_count > 8
8d9cfe
-	      || (ctx->struct_hfa_size == 0 && ctx->struct_size > 56)
8d9cfe
-	      || (ctx->regs.r64[3] == ctx->regs.r64[1]+32)
8d9cfe
-	      || (ctx->regs.r64[3] == val )))) {
8d9cfe
-#else
8d9cfe
 	if (ctx->ret_struct) {
8d9cfe
-#endif
8d9cfe
 		assert(info->type == ARGTYPE_STRUCT);
8d9cfe
 
8d9cfe
 		uint64_t addr = read_gpr(ctx, proc, 3);