Re: [RFC] Register sets

Mark Kettenis
2003-08-31T14:04:01Z

Daniel Jacobowitz <drow@mvista.com> writes:

> On Tue, Aug 26, 2003 at 11:49:07AM -0400, Andrew Cagney wrote:

> > Need to figure out how to relate these regsets back to ptrace/proc
> > requests in some sort of generic way. Doing the same for remote would
> > hopefully then fall out.
>
> I'm not sure that it's possible to relate them back in any generic way;
> ptrace is just too quirky. The closest I can picture is the way I did
> it in gdbserver, which is really more of a common-code thing than a
> generic-interface thing:
>
> struct regset_info target_regsets[] = {
> { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
> GENERAL_REGS,
> i386_fill_gregset, i386_store_gregset },
> { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
> FP_REGS,
> i386_fill_fpregset, i386_store_fpregset },
> { 0, 0, -1, -1, NULL, NULL }
> };

I agree with Daniel here. Trying to have some sort of generic
interface for ptrace(2)/proc(4) isn't worth the trouble, since there
are too many quirks. We should still try to use common code where
appropriate though (I'm usually able to share the ptrace(2) code
between the various BSD's).

Daniel's post put me on the right track on what to do about core files
though. If we look at how BFD munges core files, we see that it puts
registers in sections. Generally speaking it puts the general-purpose
registers in a section named ".reg" and the floating-point registers
(if any, and if they're not included in ".reg") in ".reg2". On the
i386, the SSE registers end up in ".reg-xfp". Currently we have these
strings hard-coded into GDB and convert them to a number, which we
then use in the various fetch_core_registers functions to identify the
register. However, why do we need this extra conversion step? If we
just include the BFD sectionname in the definition of the register set
GDB will be able to match things up. That way, it's easy to add new
register sets if they arise.

I'm not going to make the necessary changes to GDB to recognize
section names instead of numbers right now. However, I'll propose an
interface that will make this possible in the future. For now, I'd
like to propose the following definition of a `struct regset':

struct regset
{
/* Section name for core files as used by BFD. */
const char *name;

void (*supply_regset)(struct gdbarch *, struct regcache *,
const void *, size_t, int);
void (*read_regset)(struct gdbarch *, struct regcache *,
void *, size_t, int);
};

The supply_regset function will be used to supply registers from a
core file to GDB's register cache. It's signature is as follows:

void supply_regset (struct gdbarch *gdbarch, struct regcache *regcache,
const void *regs, size_t len, int regnum);

Here, GDBARCH is the architecture of the core file, REGCACHE the
register cache to store the information, REGS the (raw) buffer
containing the registers in the OS/ABI-dependent format, LEN the size
of this buffer, and REGNUM the register to supply. The latter can be
-1 to indicate that all registers in REGS are to be supplied to the
register cache.

I think with those arguments, the function has all information
available that it will need. I hope it is clear why we need the
REGCACHE, REGS and REGNUM arguments. Let me explain why we need the
GDBARCH and LEN arguments.

Andrew already suggested we need the latter to avoid buffer overruns.
The supply_regset function should check whether the buffer has the
appropriate size. Having LEN as argument also makes it easier to
support different releases of an OS since sometimes extra registers
get included in a register set with a new OS release. We can't detect
simple layout changes that don't change the size though.

Including GDBARCH has its purpose too. There are several cases where
the architecture of the core file and the executable don't match, even
though the core file in question was generated by that particular
executable:

* When a Linux binary running on FreeBSD dumps core, it will produce
a FreeBSD core dump.

* When a 32-bit binary running on FreeBSD/amd64 or Linux x86-64 dumps
core, it will produce a 64-bit coredump.

Now, if we supply the GDBARCH associated with the core file
architecture to supply_regset, it can do something intelligent with
it. And yes, it is possible to detect this case since we can get the
architecture associated with the register cache from its `struct
regcache_descr'.

The read_regset function is necessary to support the `gcore' command.
It should use regcache_raw_read to fetch all relevant registers from
the running target, such that we don't need target_fetch_registers(-1)
first.

How does this sound?

Mark