This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH/RFC] Parsing auxv entries
- From: Pedro Alves <palves at redhat dot com>
- To: Mark Kettenis <mark dot kettenis at xs4all dot nl>
- Cc: gdb-patches at sourceware dot org
- Date: Thu, 27 Feb 2014 13:17:21 +0000
- Subject: Re: [PATCH/RFC] Parsing auxv entries
- Authentication-results: sourceware.org; auth=none
- References: <201402041441 dot s14Efx91011969 at glazunov dot sibelius dot xs4all dot nl> <52F3DC99 dot 8070209 at redhat dot com> <201402062133 dot s16LXBT7005594 at glazunov dot sibelius dot xs4all dot nl> <52F90372 dot 3040207 at redhat dot com> <201402271300 dot s1RD0YhN021204 at glazunov dot sibelius dot xs4all dot nl>
On 02/27/2014 01:00 PM, Mark Kettenis wrote:
>> Date: Mon, 10 Feb 2014 16:50:58 +0000
>> From: Pedro Alves <palves@redhat.com>
>>
>> On 02/06/2014 09:33 PM, Mark Kettenis wrote:
>>>> Date: Thu, 06 Feb 2014 19:03:53 +0000
>>>> From: Pedro Alves <palves@redhat.com>
>>>>
>>>> On 02/04/2014 02:41 PM, Mark Kettenis wrote:
>>>>> The diff below adds a gdbarch method to parse auxv entries. The
>>>>> parsing code currently lives in the target_ops vector, and this poses
>>>>> a problem. Because default_auxv_parse() implements parsing of the
>>>>> non-standard auxv entries used by Linux (where the type is stored in a
>>>>> 'long' instead of an 'int'), it doesn't work on 64-bit big-endian
>>>>> targets that do follow the SVR4 layout. I've worked around this by
>>>>> overriding to_auxv_parse in inf_ptrace_trace() for native BSD targets,
>>>>> but that means the core_ops target is still broken. And as we build
>>>>> binaries as PIE by default on OpenBSD now, where auxv parsing is
>>>>> essential to find out the load address of the executable, reading core
>>>>> dumps on our 64-bit big-endian platforms is pretty much broken right
>>>>> now. And overriding to_auxv_parse for the core_ops target is painful.
>>>>>
>>>>> I believe gdbarch is the right place for this functionality. On many
>>>>> platforms the memory layout of the entries is consistent across the
>>>>> various sources.
>>>>
>>>>> But there may be some issues with running 32-bit
>>>>> binaries on 64-bit systems in relation to things like /proc/*/auxv. I
>>>>> suppose to_auxv_parse was designed to solve such problems, although I
>>>>> fail to see how the current implementation would work in the scenario
>>>>> of running 32-bit binarie on a platform where /proc/*/auxv provides
>>>>> the auxv entries in 64-bit format.
>>>>
>>>> Yeah. See the Solaris version:
>>>>
>>>> #if defined (PR_MODEL_NATIVE) && (PR_MODEL_NATIVE == PR_MODEL_LP64)
>>>> /* When GDB is built as 64-bit application on Solaris, the auxv data
>>>> is presented in 64-bit format. We need to provide a custom parser
>>>> to handle that. */
>>>> static int
>>>> procfs_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
>>>> gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
>>>> {
>>>>
>>>>>
>>>>> Thoughts? OK?
>>>>
>>>> Hmm, thoughts then.
>>>>
>>>> gdbarch does seems the right place, in principle. Though
>>>> things in practice don't look that simple.
>>>>
>>>> Consider for example a 32-bit Solaris gdb, connected to a
>>>> 64-bit gdbserver. In that case, the auxv data is presented
>>>> to gdbserver in a 64-bit format, and then in turn that's what
>>>> gdbserver sends back to GDB in response to TARGET_OBJECT_AUXV.
>>>> GDB won't be able to figure out which layout of auxv it's
>>>> looking at, unless perhaps it looks at the auxv block
>>>> size (ewwwww), or explicitly asks the target/server which
>>>> variant it sends.
>>>>
>>>> Not sure what the real proper fix for this would be. Several
>>>> options I see. There might be more or even better ones.
>>>>
>>>> #1 - Install a solaris-specific gdbarch parse auxv hook
>>>> that has gdb ask the target which variant of auxv is handed
>>>> to gdb to work with.
>>>> #2 - Hide the fact that the auxv data is presented differently
>>>> depending on the bitness of the superior, by making the target
>>>> do layout translation when returning the TARGET_OBJECT_AUXV
>>>> object (like done with TARGET_OBJECT_SIGNAL_INFO on Linux).
>>>> #3 - Hide the fact that the auxv data is presented differently
>>>> depending on the bitness of the superior, by making the target
>>>> always translate the auxv block to a host and target
>>>> independent format that the core consumes (xml?).
>>>>
>>>> #2 seems tempting; though so does #3, a little. Dunno, #1 does
>>>> too, just a little, perhaps not.
>>>>
>>>> And PowerPC has a similar issue:
>>>>
>>>> https://sourceware.org/ml/gdb-patches/2009-01/msg00440.html
>>>>
>>>> And that shows that we can't move the auxv parsing to
>>>> gdbarch by default on Linux either. At least, not if we don't
>>>> consult the target before the gdbarch hook. But then, it
>>>> sounds like 32-bit gdb against 64-bit gdbserver on ppc might
>>>> be similarly broken in some scenarios. #3 above starts
>>>> sounding a little better than #2.
>>>>
>>>> So I swing back -- thought? :-)
>>>
>>> Hmm, gdbserver would be aware of whether it is running a 32-bit or
>>> 64-bit binary would it?
>>
>> One would hope.
>>
>>> So having it translate the auxv entries into
>>> native format should work just fine.
>>
>> Yes, that's #2 above. I'm now wondering what does the Solaris kernel
>> put in the NT_AUXV note in cores generated for 32-bit programs running
>> on a 64-bit kernel. One would hope that that would end up with
>> a 32-bit layout...
>>
>> GDB's gcore does fill in an NT_AUXV, but it does no layout
>> translation:
>>
>> procfs.c:procfs_make_note_section
>> ...
>> auxv_len = target_read_alloc (¤t_target, TARGET_OBJECT_AUXV,
>> NULL, &auxv);
>> if (auxv_len > 0)
>> {
>> note_data = elfcore_write_note (obfd, note_data, note_size,
>> "CORE", NT_AUXV, auxv, auxv_len);
>> xfree (auxv);
>> }
>>
>>
>> so with a 64-bit gdb, that'll always end up with 64-bit layout...
>>
>> If the kernel does 64-bit -> 32-bit translation when generating
>> cores there (I can't imagine otherwise, but who knows), that too
>> argues for GDB doing that (i.e., translate at TARGET_OBJECT_AUXV
>> time) on the Solaris port.
>>
>>> Given the contraints, we'll probably have to live with with having
>>> both the target_ops and the gdbarch methods. I thought about this a
>>> little bit more yesterday and it seems that we want to move to the
>>> situation where we try things in the following order:
>>>
>>> 1. The target_ops method if it has been set.
>>>
>>> 2. The gdbarch method if it has been set.
>>>
>>> 3. default_auxv_parse().
>>>
>>> Targets that always see the auxv entries in the "native" format like
>>> OpenBSD would only set the gdbarch method. Targets that fetch entries
>>> from /proc in a format that doesn't necessary match the bitness of the
>>> binary that's running (Linux, Solaris) would set the target_ops
>>> method.
>>
>> The Linux/PPC issue is not that /proc's format doesn't match
>> the bitness of the binary. It's that the auxv needs to be
>> parsed _before_ the core of GDB even knows the target's
>> architecture, exactly while trying to figure out the
>> architecture of the program, as Ulrich said:
>>
>>> However, there are some scenarios where determining the wordsize
>>> actually matters (e.g. because the exec file cannot be determined).
>>> In those cases, the attempts in ppc_linux_read_description would be
>>> somewhat futile ...
>>
>> I.e., e.g., no binary at all. A bit of chicken and egg.
>> But, that issue can in principle be hidden from core GDB, by
>> making auxv parsing done by the target backend not go through
>> GDB core auvx parsing at all.
>>
>>> Solaris would probably need to set the gdbarch method as well
>>> to avoid using default_auxv_parse() which doesn't do the right thing
>>> for SPARC.
>>
>>>
>>> My diff currently has the order of 1 and 2 reversed. But I think I
>>> can just switch those around.
>>
>> I believe so. I'm trying to figure out whether we actually need
>> auxv parsing on the target vector at all, and setting up direction
>> for the future. Seems very much like we don't, though I'm curious
>> on the Solaris cores issue.
>
> Well, the target delegation reworking made the issue moot, as I can't
> change the order anymore. I think that points out a bit of a problem
> with that change, but as it doesn't matter for OpenBSD, I just added
> the gdbarch method in front.
I think we'd just need to make default_auxv_parse _not_ be
the default to_auxv_parse method, and call it at the end of
target_auxv_parse instead.
/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
Return 0 if *READPTR is already at the end of the buffer.
Return -1 if there is insufficient buffer for a whole entry.
Return 1 if an entry was read into *TYPEP and *VALP. */
int
target_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
{
struct gdbarch *gdbarch = target_gdbarch();
res = current_target.to_auxv_parse (¤t_target, readptr, endptr,
typep, valp);
if (res == ...)
return res;
else if (res == not implemented or some such && gdbarch_auxv_parse_p (gdbarch))
return gdbarch_auxv_parse (gdbarch, readptr, endptr, typep, valp);
else
return default_auxv_parse (...);
}
Anyway, something that can be handled later on.
--
Pedro Alves