Files
binutils-gdb/gdbserver/linux-x86-tdesc.h
Andrew Burgess 61bb321605 gdbserver: update target description creation for x86/linux
This commit is part of a series which aims to share more of the target
description creation between GDB and gdbserver for x86/Linux.

After some refactoring, the previous commit actually started to share
some code, we added the shared x86_linux_tdesc_for_tid function into
nat/x86-linux-tdesc.c.  However, this function still relies on
amd64_linux_read_description and i386_linux_read_description which are
implemented separately for both gdbserver and GDB.  Given that at
their core, all these functions to is:

  1. take an xcr0 value as input,
  2. mask out some feature bits,
  3. look for a cached pre-generated target description and return it
     if found,
  4. if no cached target description is found then call either
     amd64_create_target_description or
     i386_create_target_description to create a new target
     description, which is then added to the cache.  Return the newly
     created target description.

The inner functions amd64_create_target_description and
i386_create_target_description are already shared between GDB and
gdbserver (in the gdb/arch/ directory), so the only thing that
the *_read_description functions really do is add the caching layer,
and it feels like this really could be shared.

However, we have a small problem.

On the GDB side we create target descriptions using a different set of
cpu features than on the gdbserver side!  This means that for the
exact same target, we might get a different target description when
using native GDB vs using gdbserver.  This surely feels like a
mistake, I would expect to get the same target description on each.

The table below shows the number of possible different target
descriptions that we can create on the GDB side vs on the gdbserver
side for each target type:

        | GDB | gdbserver
  ------|-----|----------
  i386  | 64  | 7
  amd64 | 32  | 7
  x32   | 16  | 7

So in theory, all I want to do is move the GDB version
of *_read_description into the nat/ directory and have gdbserver use
that, then both GDB and gdbserver would be able to create any of the
possible target descriptions.

Unfortunately it's a little more complex than that due to the in
process agent (IPA).

When the IPA is in use, gdbserver sends a target description index to
the IPA, and the IPA uses this to find the correct target description
to use.

** START OF AN ASIDE **

Back in the day I suspect this approach made perfect sense.  However
since this commit:

  commit a880623024
  Date:   Thu Dec 7 17:07:01 2017 +0000

      Initialize target description early in IPA

I think passing the index is now more trouble than its worth.

We used to pass the index, and then use that index to lookup which
target description to instantiate and use.  However, the above commit
fixed an issue where we can't call malloc() within (certain parts of)
the IPA (apparently), so instead we now pre-compute _every_ possible
target description within the IPA.  The index is now only used to
lookup which of the (many) pre-computed target descriptions to use.

It would (I think) have been easier all around if the IPA just
self-inspected, figured out its own xcr0 value, and used that to
create the one target description that is required.  So long as the
xcr0 to target description code is shared (at compile time) with
gdbserver, then we can be sure that the IPA will derive the same
target description as gdbserver, and we would avoid all this index
passing business, which has made this commit so very, very painful.

** END OF AN ASIDE **

Currently then for x86/linux, gdbserver sends a number between 0 and 7
to the IPA, and the IPA uses this to create a target description.

However, I am proposing that gdbserver should now create one of (up
to) 64 different target descriptions for i386, so this 0 to 7 index
isn't going to be good enough any more (amd64 and x32 have slightly
fewer possible target descriptions, but still more than 8, so the
problem is the same).

For a while I wondered if I was going to have to try and find some
backward compatible solution for this mess.  But after seeing how
lightly the IPA is actually documented, I wonder if it is not the case
that there is a tight coupling between a version of gdbserver and a
version of the IPA?  At least I'm hoping so.

In this commit I have thrown out the old IPA target description index
numbering scheme, and switched to a completely new numbering scheme.
Instead of the index that is passed being arbitrary, the index is
instead calculated from the set of cpu features that are present on
the target.  Within the IPA we can then reverse this logic to recreate
the xcr0 value based on the index, and from the xcr0 value we can
create the correct target description.

With the gdbserver to IPA numbering scheme issue resolved I have then
update the gdbserver versions of amd64_linux_read_description and
i386_linux_read_description so that they create target descriptions
using the same set of cpu features as GDB itself.

After this gdbserver should now always come up with the same target
description as GDB does on any x86/Linux target.

This commit does not introduce any new code sharing between GDB and
gdbserver as previous commits in this series does.  Instead this
commit is all about bringing GDB and gdbserver into alignment
functionally so that the next commit can merge the GDB and gdbserver
versions of these functions.

Approved-By: John Baldwin <jhb@FreeBSD.org>
2024-03-25 17:14:19 +00:00

51 lines
1.8 KiB
C

/* Low level support for x86 (i386 and x86-64), shared between gdbserver
and IPA.
Copyright (C) 2016-2024 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef GDBSERVER_LINUX_X86_TDESC_H
#define GDBSERVER_LINUX_X86_TDESC_H
/* Convert an xcr0 value into an integer. The integer will be passed to
the in-process-agent where it will then be passed to
x86_linux_tdesc_idx_to_xcr0 to get back the xcr0 value. */
extern int x86_linux_xcr0_to_tdesc_idx (uint64_t xcr0);
#ifdef IN_PROCESS_AGENT
/* Convert an index number (as returned from x86_linux_xcr0_to_tdesc_idx)
into an xcr0 value which can then be used to create a target
description. */
extern uint64_t x86_linux_tdesc_idx_to_xcr0 (int idx);
/* Within the in-process-agent we need to pre-initialise all of the target
descriptions, to do this we need to know how many target descriptions
there are for each different target type. These functions return the
target description count for the relevant target. */
extern int x86_linux_amd64_ipa_tdesc_count ();
extern int x86_linux_x32_ipa_tdesc_count ();
extern int x86_linux_i386_ipa_tdesc_count ();
#endif /* IN_PROCESS_AGENT */
#endif /* GDBSERVER_LINUX_X86_TDESC_H */