[Ltrace-devel] [RFC][PATCH] Add support for mips64 n32/n64

Petr Machata pmachata at gmail.com
Wed Jul 15 22:24:14 UTC 2015


Faraz Shahbazker <faraz.shahbazker at imgtec.com> writes:

> diff --git a/proc.h b/proc.h
> index a611456..00094e1 100644
> --- a/proc.h
> +++ b/proc.h
> @@ -117,6 +117,7 @@ struct process {
>  	 * nauseam.  */
>  	short e_machine;
>  	char e_class;
> +	char e_abi;

So the part that the diff program snipped says this:

	/* XXX We would like to replace this with a pointer to ABI
	 * object that would provide the relevant services, instead of
	 * checking the necessary flags in the back end ad
	 * nauseam.  */

It seems like e_machine and e_class should be /replaced/ with some sort
of ABI identifier that the backend produces, given an ELF header.  The
comment mentions a full-fledged object, but an integer or even a char
would very likely be enough.  Having a triplet of machine-class-ABI
seems superfluous, the ABI itself subsumes the other two.

That's a more invasive change though and if you simply don't have
resources to pursue this, I'm not going to push it.  The above is fine.

> --- a/sysdeps/linux-gnu/mips/plt.c
> +++ b/sysdeps/linux-gnu/mips/plt.c
> @@ -182,6 +183,11 @@ arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
>  {
>  	arch_addr_t rld_addr;
>  	int r;
> +#ifdef __LP64__
> +	size_t addrsize = proc->mask_32bit ? 4 : (sizeof *ret);
> +#else /* !__LP64__ */
> +	size_t addrsize = sizeof *ret;
> +#endif /* !__LP64__ */
>  
>  	/* MIPS puts the address of the r_debug structure into the
>  	 * DT_MIPS_RLD_MAP entry instead of into the DT_DEBUG entry.  */
> @@ -189,7 +195,7 @@ arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
>  					 DT_MIPS_RLD_MAP, &rld_addr);
>  	if (r == 0) {
>  		if (umovebytes(proc, rld_addr,
> -			       ret, sizeof *ret) != sizeof *ret) {
> +			       ret, addrsize) != addrsize) {

I wonder if you can rely on the fact that *ret will be initialized to
zeroes.  Otherwise, for 64-bit ltrace tracing a 32-bit process, you
should see garbage in the part that's not overwritten.  You might want
to stash a *ret = 0 in front of the umovebytes.

This should also break if MIPS runs in big endian mode, unless I'm
missing something.

Also, you can meld the line into previous, it would be < 80 chars.

> @@ -295,14 +301,25 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
>  
>  	for (j = 0; j < data->d_size / 16; ++j) {
>  		uint32_t insn;
> +		int got_size = 4;
> +		uint32_t load_inst = 0x24180000U; /* addui t8,0,xx  */
> +
> +#ifdef __LP64__
> +		if (arch_get_abi(lte->ehdr) == ABI_N64
> +		    || arch_get_abi(lte->ehdr) == ABI_O64) {
> +			got_size = 8;
> +			load_inst = 0x64180000U; /* daddui t8,0,xx  */
> +		}
> +#endif /* __LP64__ */

Is there a reason that this needs to be between ifdefs?  I'd like to
have as much code exposed to compilation all the time as possible.

> @@ -362,8 +379,17 @@ read_got_entry(struct process *proc, GElf_Addr addr, GElf_Addr *valp)
>  {
>  	/* XXX double cast.  */
>  	arch_addr_t a = (arch_addr_t) (uintptr_t) addr;
> -	uint32_t l;
> -	if (proc_read_32(proc, a, &l) < 0) {
> +	uint64_t l = 0;
> +	int result;
> +
> +#ifdef __LP64__
> +	if (!proc->mask_32bit)
> +		result = proc_read_64(proc, a, &l);
> +	else
> +#endif /* __LP64__ */
> +		result = proc_read_32(proc, a, (uint32_t *) &l);

Here as well.  The above is essentially if (proc->e_class ==
ELFCLASS64).

> @@ -503,13 +529,27 @@ jump_to_entry_point(struct process *proc, struct breakpoint *bp)
[...]
> +#ifdef __LP64__

And here.

> diff --git a/sysdeps/linux-gnu/mips/trace.c b/sysdeps/linux-gnu/mips/trace.c
> index e81b374..d54818e 100644
> --- a/sysdeps/linux-gnu/mips/trace.c
> +++ b/sysdeps/linux-gnu/mips/trace.c

> +/**
> +   \param abi ABI of current process, from mips_abi_type enum
> +   \param list An array of 4 elements, each corresponding to an ABI, in
> +   the order: o32, n32, n64, o64
> +
> +   return value from array corresponding to requested ABI
> + */
> +static int
> +abi_select(const int abi, const int list[])
> +{
> +	int retval;
> +	switch (abi)
> +	{
> +	case ABI_N32:
> +		retval = list[1];

Why not use the enumerators as indices?

> +	const int rt_sigreturn_list[] = {193, 211, 211, 193};
> +	const int sigreturn_list[] = {119, -1, -1, 119};

Use C99 designated initializers:

const int rt_sigreturn_list[] = {
	[ABI_O32] = 193, /* etc. */
};

That makes the parameter passing convention a bit less magic.

> +	/* get the user's pc (plus 8) */

You mean plus 4?

> +	  The above is not necessary in Linux kernel > v2.6.35. Recent
> +	  kernels have a fancy-pants method of restarting syscalls.

:)

> +#ifdef __LP64__
> +size_t
> +arch_type_sizeof(struct process *proc, struct arg_type_info *info)

Define this always, not only on __LP64__.  Make the size contingent on
proc->e_machine, proc->e_class or proc->e_abi.

Thanks for the submission, and sorry it took me this long to get around
to it.  Unfortunately I can't promise this will get better any time
soon.

Petr



More information about the Ltrace-devel mailing list