This is the mail archive of the gdb-patches@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: [PATCH] New port: ia64-*-freebsd


On Jul 14, 2005, at 7:16 PM, Daniel Jacobowitz wrote:

On Thu, Jul 14, 2005 at 07:08:09PM -0700, Marcel Moolenaar wrote:
The comment on TARGET_OBJECT_DIRTY says "see ia64-tdep.c", which has
basically no comments explaining what it does, or why it is necessary
for FreeBSD when it isn't for GNU/Linux.

A quick explanation then: Stacked registers are either dirty or flushed when it comes to accessing them. Stacked registers that are flushed have been written to the backing store by the processor -- they are in the target's memory. Stacked registers that are dirty are still in the processor. They end up on the kernel's stack of the corresponding process whenever there's a kernel context switch. Linux abstracts this and allows them both to be read and written the same way. FreeBSD doesn't abstract this. The reason FreeBSD doesn't abstract it is because it is not always possible to do so, nor is it always beneficial to do so. So, in order for gdb to handle all possible failure modes, it needs to be aware of the difference so that it can access the registers accordingly.

A typical example of a failure mode that cannot be debugged with
abstraction, is a core file created when the backing store overflows.
The kernel will not be able to move the dirty stacked registers
in the core file, because there's no room for it (there's no space
on the backing store where they would normally go). They need to
be written into the core file as a note (like the general registers)
and fetched seperately.

Thank you! This needs to be described in the source somewhere.

I'll add this (or the gist of it) to ia64-tdep.c.


  I'd
like to see a more descriptive name for TARGET_OBJECT_DIRTY, also,
though I don't have any advice - right now it would be a good place to
stick a dirty hack.  Or dirty laundry.

:-)


An alternative would be TARGET_OBJECT_RSE or TARGET_OBJECT_IA64_RSE.
RSE stands for Register Stack Engine, which is where the dirty
registers live in the CPU. This would actually make a lot of sense,
because we're going to access the registers in the RSE "object".

The corelow.c implementation of TARGET_OBJECT_DIRTY looks pretty
sketchy for target-independent code.

What exactly do you mean?

+ case TARGET_OBJECT_DIRTY:
+ {
+ ULONGEST addr;
+ addr = *(ULONGEST*)annex + offset;
+ if (readbuf)
+ return (*ops->deprecated_xfer_memory) (addr, readbuf, len,
+ 0/*read*/, NULL, ops);
+ if (writebuf)
+ return (*ops->deprecated_xfer_memory) (addr, writebuf, len,
+ 1/*write*/, NULL, ops);
+ return -1;
+ }
+


So, it treats the annex as a memory pointer and returns the contents of
memory there.  Why?  And why is this a useful generic implementation?

Yeah, that's a bit tricky. Here's why:


The stacked registers that are flushed, live in memory below the
address pointed to by the BSPSTORE register. The stacked registers
that are dirty would be flushed to memory between the values of
BSPSTORE (bottom) and BSP (top) if and when they are being flushed.

I figured that from an API point of view it's safer to access the
dirty registers by their index or offset relative to BSPSTORE, and
not by their absolute memory address, because their corresponding
memory address is unreal. I can change the backing store pointer
(i.e. BSPSTORE) and then flush the dirty registers. So, tying the
dirty registers to their would-be memory address seemed "wrong".
Hence, the offset is the offset relative to BSPSTORE.

However when the dirty registers need to be accessed as if they
were flushed, as needs to be done on Linux, then we need to know
to value of BSPSTORE so that we can map the relative offset to
an absolute memory location. For this reason I use the annex.
To support cross-debugging when gdb runs on a 32-bit host, I
cannot pass BSPSTORE by value (sizeof(void*) < sizeof(CORE_ADDR)).
So, I pass it by reference. Hence the indirection.

I couldn't think of a better way to do this without changing the
ptrace(2) implementation in FreeBSD. Mind you, I have no problem
changing the ptrace(2) in FreeBSD if that makes for a better
interface, but I cannot really create a generic ptrace(2)
interface that's tailored to the quirks of gdb and as such is
unusable or unnatural to use by any other application that needs
to use ptrace(2). It was a balancing act...

What I would really like to see in the end is to have the dirty
registers in the regcache. That way the interface to the target
becomes simpler. For core files we can fetch the entire note and
store its contents in the regcache. For ptrace(2) we get something
similar. The ptrace(2) interface on FreeBSD allows fetching and
storing dirty registers one by one. And it's easy to add a second
form that allows fetching them all at once.

There's just one slight problem: the number of dirty registers is
variable, but bounded. Unfortunately the upper bound is rather
high: 16383. This yields a worse-case memory footprint of 128KB :-/
(8 bytes per register and NaT collection).
I think that on average the number of dirty registers is something
like 128. I doesn't really look like a good idea to create the 128KB
of memory for the worst-case when 1KB would be sufficient on
avarage.

Oh, BTW: On HP-UX the dirty registers are in the ucontext, so for
HP-UX it's also required to make the distinction and as far as I
can tell, the way TARGET_OBJECT_DIRTY currently works also works
well for HP-UX. This can be beneficial if someone eventually ports
(the one true) gdb to HP-UX.

From your description abov it sounds like these ought to be in their
own core file note anyway; why have they ended up in "memory"?

That's currently how Linux works and it's also currently how FreeBSD creates the core files. Linux cannot do it any other way, because it's all abstracted by the kernel on live processes and if gdb doesn't know the difference between flushed and dirty stacked registers, you cannot dump the dirty stacked registers to a core file anywhere else then where they would be when they were flushed.

On FreeBSD the note isn't yet created because that requires a bit of
work and we had the plans to revamp the core file notes anyway (due
to threading). So, I decided to first get the port contributed and
then work on how best to deal with the dirty stacked registers. This
then could be part of a larger (cross-platform) revamp of how FreeBSD
creates core files, which would also result in a rather large set of
changes to binutils.

Anyway: since some targets work with the abstraction, there need to
be a couple places where accessing dirty registers need to be mapped
to memory references. This may change in the future.

You have a lot of non-GNUish formatting issues - mostly the pesky
spacing rules.

No doubt. I'm not used to the GNU formatting :-)

You did better than most people not used to it can manage :-)

Thanks!


--
 Marcel Moolenaar         USPA: A-39004          marcel@xcllnt.net


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