[Ltrace-devel] Support for ppc64el patch

Petr Machata pmachata at redhat.com
Wed Apr 9 21:52:53 UTC 2014


"Thierry Fauck at linux.vnet.ibm.com" <thierry at linux.vnet.ibm.com> writes:

> @@ -34,7 +34,29 @@
>  #ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target.
>  #define LT_ELFCLASS2	ELFCLASS64
>  #define LT_ELF_MACHINE2	EM_PPC64
> -#define ARCH_SUPPORTS_OPD
> +
> +#ifdef __LITTLE_ENDIAN__
> +# define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f }
> +# define ARCH_ENDIAN_LITTLE
> +#else
> +# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
> +# define ARCH_SUPPORTS_OPD
> +# define ARCH_ENDIAN_BIG
> +#ifndef PPC64_LOCAL_ENTRY_OFFSET
> +#define PPC64_LOCAL_ENTRY_OFFSET(other) other
> +#endif

This has wrong indentation.  Please indent a space for each nested
preprocessor level.  (Though I suppose the include guard ifdefs don't
count.)

> @@ -55,14 +57,19 @@ struct fetch_context {
>  	arch_addr_t stack_pointer;
>  	int greg;
>  	int freg;
> -	int ret_struct;
> +	bool ret_struct:1;
>  
>  	union {
>  		gregs32_t r32;
>  		gregs64_t r64;
>  	} regs;
> -	struct fpregs_t fpregs;
>  
> +	struct fpregs_t fpregs;
> +	bool heterog:1;
> +	bool hfa_type:1;

According to the code below, heterog and hfa_type are not part of
_state_.  You don't need to keep their values between calls.  Why are
they in context?

Also, hfa_type is a good name for something that is a type (in ltrace
typically a variable of type enum arg_type or possibly struct
arg_type_info).  A predicate might be called is_hfa_type, or hfa_type_p,
or some such.

> @@ -124,9 +132,36 @@ arch_fetch_arg_init(enum tof type, struct process *proc,

[...]

> +	if (context->ret_struct) {
> +#if _CALL_ELF != 2
>  		context->greg++;
> +#else
> +		/* if R3 points to stack, parameters will be in R4 */
> +		long pstack_end = ptrace(PTRACE_PEEKTEXT, proc->pid,
> +					proc->stack_pointer,0);

There should be a space after comma.

> +		if (( (long)context->regs.r64[3] > (long)proc->stack_pointer )
> +		    && ( (long)context->regs.r64[3] < pstack_end ) ) {
> +			context->greg++;
> +			context->stack_pointer += 8;
> +		}

Don't put spaces around parenthesized arguments.

Also, the first cast should be to arch_addr_t, the second should be
absent altogether.  If you make pstack_end unsigned, I suspect you will
be able to avoid the bottom cast as well.

> @@ -216,18 +258,34 @@ align_small_int(unsigned char *buf, size_t w, size_t sz)

[...]

> +
> +#if _CALL_ELF == 2
> +	/* Consume the stack slot corresponding to this arg */
> +	if ( (int)(sz + off ) >= 8 ) {

Why do you cast to int here?
There should be a period and two spaces before */
There shouldn't be spaces around the parenthesized argument.

> +		ctx->greg++;
> +	}
> +	if ( ctx->hfa_type )
> +		ctx->stack_pointer += sz ;
> +	else
> +		ctx->stack_pointer += 8 ;

There should be no space before a semicolon.  The if has wrong spacing
as well.

> @@ -258,7 +317,10 @@ allocate_float(struct fetch_context *ctx, struct process *proc,
>  
>  		ctx->freg++;
>  		if (proc->e_machine == EM_PPC64)
> -			allocate_gpr(ctx, proc, info, NULL);
> +			allocate_gpr(ctx, proc, info, NULL, off);
> +
> +		if ( ! ctx->hfa_type )
> +			ctx->vgreg++;

Again, no spaces inside parentheses.

> @@ -276,9 +338,140 @@ allocate_float(struct fetch_context *ctx, struct process *proc,
>  }
>  
>  static int
> +allocate_hfa(struct fetch_context *ctx, struct process *proc,
> +	      struct arg_type_info *info, struct value *valuep,
> +	      enum arg_type hfa_type, size_t hfa_count)
> + {
> +	 size_t sz = type_sizeof(proc, info);
> +	 if (sz == (size_t)-1)
> +		 return -1;
> +
> +	ctx->hfa_size += sz;;

No double semicolons please.

> +	 unsigned char *buf = value_reserve(valuep, sz);
> +	 if (buf == NULL)
> +		 return -1;

Up here, you have a tab followed by a space.  That's probably wrong.
It's OK down here:

> +
> +	ctx->hfa_type = 1 ;

true, not 1.  Also, no space before semicolon.

> +	ctx->heterog = 0 ;
> +	if ( hfa_count > 8 ) {
> +		ctx->heterog = 1 ;
> +	}

Again, too much spacing throughout.

> +
> +
> +	 struct arg_type_info *hfa_info = type_get_simple(hfa_type);
> +	 size_t hfa_sz = type_sizeof(proc, hfa_info);
> +
> +

The following while has again wrong indentation:

> +	 while ( hfa_count > 0 && ctx->freg <= 13 ) {
> +		int rc;
> +		 struct value tmp;
> +
> +		 value_init(&tmp, proc, NULL, hfa_info, 0);
> +
> +		/* Hetereogeneous struct - get value on GPR or stack */

You keep saying hetereogeneous and I keep wondering whether you mean
homogeneous, or whether heterogeneous structs really are something in
context of ELFv2 ABI.  Like, I could imagine mixed float/double structs
(i.e. heterogeneous) getting the sort of optimization that homogeneous
normally do.  But I don't know.  Could you explain this to me, please?

> +		if ( ((hfa_type == ARGTYPE_FLOAT
> +		    || hfa_type == ARGTYPE_DOUBLE )
> +			&& hfa_count <= 8 ) )
> +			rc = allocate_float(ctx, proc, hfa_info, &tmp,
> +					slot_off);
> +		else
> +			rc = allocate_gpr(ctx, proc, hfa_info, &tmp,
> +					slot_off );
> +
> +		memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
> +
> +		slot_off += hfa_sz;
> +		buf += hfa_sz;
> +		hfa_count--;
> +		if ( slot_off == 8 ) {
> +			slot_off = 0;
> +			ctx->vgreg++;
> +		}

Spacing.

> +
> +
> +		 value_destroy(&tmp);
> +		 if (rc < 0)
> +			 return -1;
> +	}
> +	if ( ! hfa_count ) {
> +		return 0;
> +	}

Spacing.

> +	if ( ! hfa_count )
> +		return 0;

hfa_count is not a boolean, say if (hfa_count == 0).

> +		
> +	/* Remaining values are on stack */
> +	while ( hfa_count ) {
> +		/* allocate_stack_slot(ctx, proc, info, valuep); */

Why this comment?  Also, spacing at while is wrong.

> +		 struct value tmp;
> +		 value_init(&tmp, proc, NULL, hfa_info, 0);

This has one extra space of indentation.

> +
> +		value_in_inferior(&tmp, ctx->stack_pointer);
> +		memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
> +		ctx->stack_pointer += hfa_sz ;
> +		buf += hfa_sz ;
> +		hfa_count--;

No spaces before semicolons.

> +	}
> +	return 0;
> + }
> +
> +static int
>  allocate_argument(struct fetch_context *ctx, struct process *proc,
>  		  struct arg_type_info *info, struct value *valuep)
>  {
> +	ctx->hfa_type = 0;

false, not 0.

> @@ -287,13 +480,26 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
>  
>  	case ARGTYPE_FLOAT:
>  	case ARGTYPE_DOUBLE:
> -		return allocate_float(ctx, proc, info, valuep);
> +		return allocate_float(ctx, proc, info, valuep,
> +				      8 - type_sizeof(proc,info));
>  
>  	case ARGTYPE_STRUCT:
>  		if (proc->e_machine == EM_PPC) {
>  			if (value_pass_by_reference(valuep) < 0)
>  				return -1;
>  		} else {
> +#if _CALL_ELF != 2
> +			break;
> +#endif
> +			struct arg_type_info *hfa_info;
> +			size_t hfa_size;
> +			hfa_info = type_get_hfa_type(info, &hfa_size);
> +			if (hfa_info != NULL ) {
> +				size_t sz = type_sizeof(proc, info);
> +				ctx->struct_size += sz;
> +				return allocate_hfa(ctx, proc, info, valuep,
> +						hfa_info->type, hfa_size);
> +			}

It would be better to wrap the new code in #if _CALL_ELF == 2 / #endif.
If you think the break makes things clear (there's a fall-through below,
but it just falls through to a break), then place it explicitly after
the endif, and possibly after the below comment as well (instead of the
fall-through).

>  			/* PPC64: Fixed size aggregates and unions passed by
>  			 * value are mapped to as many doublewords of the
>  			 * parameter save area as the value uses in memory.
> @@ -326,6 +532,10 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
>  	size_t sz = type_sizeof(proc, valuep->type);
>  	if (sz == (size_t)-1)
>  		return -1;
> +
> +	if ( ctx->ret_struct )
> +		ctx->struct_size += sz;

Spacing.

> @@ -346,9 +556,11 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
>  		struct arg_type_info *fp_info
>  			= type_get_fp_equivalent(valuep->type);
>  		if (fp_info != NULL)
> -			rc = allocate_float(ctx, proc, fp_info, &val);
> +			rc = allocate_float(ctx, proc, fp_info, &val,
> +					8-type_sizeof(proc,info));
>  		else
> -			rc = allocate_gpr(ctx, proc, long_info, &val);
> +			rc = allocate_gpr(ctx, proc, long_info, &val,
> +					0);

The 0 would fit to the previous line.

> @@ -411,7 +625,22 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
>  		  struct process *proc, struct arg_type_info *info,
>  		  struct value *valuep)
>  {
> +	if (fetch_context_init(proc, ctx) < 0)
> +		return -1;
> +
> +
> +#if _CALL_ELF != 2
>  	if (ctx->ret_struct) {
> +#else
> +	void *ptr=(void *) (ctx->regs.r64[1]+32);

There should be spaces around the =.

> +	long val = ptrace(PTRACE_PEEKTEXT, proc->pid, ptr , 0);
> +	if ( ctx->ret_struct &&
> +	   ( ( ( ctx->struct_size > 64 || ctx->heterog ) )
> +	     || (ctx->struct_size > 56 && ! ctx->hfa_type )
> +	     || ( (void *)ctx->regs.r64[3] == (void *)(ctx->regs.r64[1]+32) )

Why is the void* necessary?

> +	     || ( ctx->regs.r64[3] == (uint64_t)val) )) {

Also, please fix spacing in this whole expression.

> diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
> @@ -430,7 +450,10 @@ reloc_copy_if_irelative(GElf_Rela *rela, void *data)
>  int
>  arch_elf_init(struct ltelf *lte, struct library *lib)
>  {
> +	lte->arch.elfv2_abi=((lte->ehdr.e_flags & 3) & 2);

Uhh, do these things have symbolic names by any chance?
Also, why & 3 & 2?  That's the same as & 2...

> @@ -541,6 +564,10 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
>  
>  			const char *name = lte->strtab + sym.st_name;
>  
> +/*			if ( ! strlen(name) )
> +				continue;
> +*/

Just drop it instead of commenting out.

> @@ -616,21 +643,58 @@ unresolve_plt_slot(struct process *proc, GElf_Addr addr, GElf_Addr value)

[...]

> +extern void delete_symbol_chain(struct library_symbol *);
> +

This belongs to ltrace-elf.h.

>  enum plt_status
>  arch_elf_add_func_entry(struct process *proc, struct ltelf *lte,
>  			const GElf_Sym *sym,
>  			arch_addr_t addr, const char *name,
>  			struct library_symbol **ret)
>  {
> -	if (lte->ehdr.e_machine != EM_PPC || lte->ehdr.e_type == ET_DYN)
> +	/* With ABIv2 st_other field contains an offset */
> +	if ( lte->arch.elfv2_abi )
> +		addr += PPC64_LOCAL_ENTRY_OFFSET(sym->st_other);
> +
> +	int st_info=GELF_ST_TYPE(sym->st_info);

Spaces around =.

> +
> +	if ( (lte->ehdr.e_machine != EM_PPC && ! sym->st_other )

st_other is not a boolean, please use sym->st_other == 0.

> diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
> index ee9a6b5..03d9d51 100644
> --- a/sysdeps/linux-gnu/ppc/trace.c
> +++ b/sysdeps/linux-gnu/ppc/trace.c
> @@ -66,7 +66,11 @@ syscall_p(struct process *proc, int status, int *sysnum)
>  	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
>  		long pc = (long)get_instruction_pointer(proc);
>  		int insn =
> +#ifndef __LITTLE_ENDIAN__
>  		    (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long),
> +#else
> +		    (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(int),
> +#endif
>  				0);

Please wrap syntactically meaningful units in preprocessor directives.
At least bring inside the 0, possibly even the declarator.

Thank you,
PM



More information about the Ltrace-devel mailing list