This is the mail archive of the gdb@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] Register sets


On Sun, Aug 24, 2003 at 12:49:57AM +0200, Mark Kettenis wrote:
> Folks (and especially Andrew),
> 
> A while back, Andrew submitted a patch that made it possible to read
> Linux/i386 corefiles on Linux/x86-64.  He tricked me into fixing the
> "gcore" command for this case, which forced me to think a bit more
> about how we can solve this cleanly.  Here's what I think is the
> solution.

Hi Mark,

I've been thinking about the same problem for a while now.  I have a
slightly different mental picture; let's see if we can put them
together.

> Registers sets
> --------------
> 
> In most hosted environments, the underlying OS devides the ISA's
> registers in groups.  Typically there is a set of general-purpose
> (which usually includes all integer register)s and a set of
> floating-point registers.  That's one of the reasons why we have
> reggroups in GDB.
> 
> Most OS'es define data structures for dealing with these groups of
> registers:
> 
>  * Modern BSD's have `struct reg' and `struct fpreg'.
> 
>  * System V has `gregset_t' and `fpregset_t'.  Solaris (as an
>    SVR4-derivative) has `prgregset_t' and `fpregset_t' and the
>    provision for an `xregset'.
> 
>  * QNX has `procfs_greg', `procfs_fpreg' and `procfs_altreg'.
> 
>  * Linux is a bit messy, but tries to mimic SVR4/Solaris.
> 
> These data structures are used in several interfaces:
> 
>  * ptrace(2) (for systems that have PT_GETREGS/PTRACE_GETREGS and
>    friends, e.g. modern BSD's and most Linuxen).
> 
>  * proc(4) filesystem (a.k.a. procfs on e.g. SVR4/Solaris and QNX).
> 
>  * libthread_db(3)/proc_service(3) debugging interface (on Solaris and
>    Linux).
> 
>  * core(5) memory dumps (on ELF systems, but also in some cases,
>    traditional a.out systems).
> 
> As a result, we use these data structures all over the place in GDB,
> usually in ways that make it difficult to re-use code and/or
> multi-arch things.  I'd like to introduce a more unified approach to
> handling these data structures, which I propose to call register sets,
> or regsets for short.  Basically a register set is just a block of
> memory of a certain size.  We may want to put these register sets (or
> a single register from them) into GDB's register cache.  We also need
> to be able to grab these register sets (or a single register in them)
> from the register cache.
> 
> It seems that we need a maximum of three of these sets.  I propose to
> name these register sets as follows:
> 
>  * `gregset' for the general-purpose registers.
> 
>  * `fpregset' for the floating-point registers.
> 
>  * `xregset' for any "extra" registers.

I don't think this is a good assumption.  There are two problems with
it:
  - It assumes that everything relating to a particular target uses the
same register set format.  In general (there are exceptions where
libthread_db will zero the regset instead of calling ps_*getregs) we
can pass regsets through libthread_db as opaque objects; we might wish
to include registers that are not available in a core dump.  Then we've
got two different "general" regsets.  There are some other examples.

  - It assumes that there is one possible xregset for a target. 
Suppose that you have two ARM targets with different vector extensions;
I'll pick Cirrus/Maverick and iWMMXt, since there happen to be two ARM
targets with different vector extensions.  We may not know right away
which regset is available.  I'm not sure this is a problem; we could
just define the architecture appropriately; but another example is the
embedded x86 architecture registers, which a remote stub might want to
transfer.

(Choice of iWMMXt isn't just an example.  I need to add gdbserver
support for iWMMXt, and I want to do it without changing the g/G
packet.  See below...)

> For each register set we have to provide a function that takes apart
> the register set and stores it in GDB's register cache, and a
> functions that puts together a register set from GDB's register set.
> For these functions I propose the functions:
> 
> void <prefix>_supply_<regset> (struct regcache *regcache,
>                                const void *regs, int regnum);
> 
> for supplying register REGNUM from register set REGS into the cache
> REGCACHE, and
> 
> void <prefix>_collect_<regset> (const struct regcache *regcache,
> 				void *regs, int regnum)
> 
> for collecting register REGNUM from the cache REGCACHE into register
> set REGS.
> 
> If REGNUM is -1, these function operate on all registers within the set.

Can we define the REGNUM != -1 case a little more clearly?  Is the
regnum a hint, what registers must be valid in the regcache when
collecting, what registers must be valid in the regset when supplying,
et cetera.  Right now we're a bit inconsistent between targets.

> For each architecture we will have a structure that contains all
> information about the register sets:
> 
> struct regset_info
> {
>   size_t sizeof_gregset;
>   void (*supply_gregset)(struct regcache *, const void *, int);
>   void (*collect_gregset)(const struct regcache *, void *, int);
>   size_t sizeof_fpregset;
>   void (*supply_fpregset)(struct regcache *, const void *, int);
>   void (*collect_fpregset)(const struct regcache *, void *, int);
>   size_t sizeof_xregset;
>   void (*supply_xregset)(const struct regcache *, void *, int);
>   void (*collect_xregset)(const struct regcache *, void *, int);
> };
> 
> A pointer to this structure will be stored in the architecture vector,
> such that we can use this from various places in GDB.
> 
> Thoughts?

I was thinking of something like this, very roughly:

struct regset
{
  size_t size;
  mapping_of_registers_and_sizes_and_offsets mapping;
};

struct native_regsets
{
  struct regset *gregset, *fpregset, *xregset;
};

struct regset *
gdbarch_core_section_to_regset (int which, int sizeof);

This would replace lots of identical copies of fetch_core_registers all
over GDB.


And then:

struct regset *
gdbarch_remote_name_to_regset (int which, int sizeof);

The companion to this would be some remote protocol work:
-> qRegsets::
<- qRegsets:General,FP,iWMMXt

[Local GDB calls gdbarch_remote_name_to_regset on each of these]

-> g
<- 0000102109210831973987etc

[This would be the General set.]

-> qFetchRegset:FP
<- 000000831092831098201923etc

-> qSetRegset:FP:100000831092831098201923etc
<- OK

[This would be the FP set.]

Also available might be:

-> qDescribeRegset:General
<- a0:8;a1:8;a2:8;a3:8;v0:8;sp:8;pc:8

which could be used before trying the gdbarch_remote_name_to_regset as
a fallback.  And this logically extends to a CLI command to specify the
format of the G packet, which I think there's a PR requesting?


How does that sound?  I'll implement it if folks like it.  Open to
any/all suggestions.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]