Re: remote protocol support for TARGET_OBJECT_AUXV

Andrew Cagney
2004-02-05T15:54:58Z

> I am proposing a new query packet `qAuxVector' to support reading
> TARGET_OBJECT_AUXV data. Here's the proposed docs addition describing it.
> After that, I've appended (short) patches implementing it in gdb and
> gdbserver so you can see concretely what I mean.

(roland, in case you're confused - this gets discussed as a protocol
change and also approved as a doco change)

> Index: gdb.texinfo
> ===================================================================
> RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
> retrieving revision 1.192
> diff -u -b -p -r1.192 gdb.texinfo
> --- gdb.texinfo 4 Feb 2004 23:24:43 -0000 1.192
> +++ gdb.texinfo 4 Feb 2004 23:56:55 -0000
> @@ -20420,6 +20420,23 @@ The target does not need to look up any
> The target requests the value of a new symbol @var{sym_name} (hex
> encoded). @value{GDBN} will continue to supply the values of symbols
> (if available), until the target ceases to request them.
> +@end table
> +
> +@item @code{qAuxVector}:@var{offset},@var{length} --- auxiliary vector data

The underlying target methods that this is adding support for are:

/* Request the transfer of up to LEN 8-bit bytes of the target's
OBJECT. The OFFSET, for a seekable object, specifies the starting
point. The ANNEX can be used to provide additional data-specific
information to the target.

Return the number of bytes actually transfered, zero when no
further transfer is possible, and -1 when the transfer is not
supported.

NOTE: cagney/2003-10-17: The current interface does not support a
"retry" mechanism. Instead it assumes that at least one byte will
be transfered on each call.

NOTE: cagney/2003-10-17: The current interface can lead to
fragmented transfers. Lower target levels should not implement
hacks, such as enlarging the transfer, in an attempt to compensate
for this. Instead, the target stack should be extended so that it
implements supply/collect methods and a look-aside object cache.
With that available, the lowest target can safely and freely "push"
data up the stack.

NOTE: cagney/2003-10-17: Unlike the old query and the memory
transfer mechanisms, these methods are explicitly parameterized by
the target that it should be applied to.

NOTE: cagney/2003-10-17: Just like the old query and memory xfer
methods, these new methods perform partial transfers. The only
difference is that these new methods thought to include "partial"
in the name. The old code's failure to do this lead to much
confusion and duplication of effort as each target object attempted
to locally take responsibility for something it didn't have to
worry about.

NOTE: cagney/2003-10-17: With a TARGET_OBJECT_KOD object, for
backward compatibility with the "target_query" method that this
replaced, when OFFSET and LEN are both zero, return the "minimum"
buffer size. See "remote.c" for further information. */

enum target_object
{
/* Kernel Object Display transfer. See "kod.c" and "remote.c". */
TARGET_OBJECT_KOD,
/* AVR target specific transfer. See "avr-tdep.c" and "remote.c". */
TARGET_OBJECT_AVR,
/* Transfer up-to LEN bytes of memory starting at OFFSET. */
TARGET_OBJECT_MEMORY,
/* Kernel Unwind Table. See "ia64-tdep.c". */
TARGET_OBJECT_UNWIND_TABLE,
/* Transfer auxilliary vector. */
TARGET_OBJECT_AUXV,
/* StackGhost cookie. See "sparc-tdep.c". */
TARGET_OBJECT_WCOOKIE

/* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC,
... */
};

extern LONGEST target_read_partial (struct target_ops *ops,
enum target_object object,
const char *annex, void *buf,
ULONGEST offset, LONGEST len);

extern LONGEST target_write_partial (struct target_ops *ops,
enum target_object object,
const char *annex, const void *buf,
ULONGEST offset, LONGEST len);

I think it would be better to specify something that accomodates this
(to my suprise) rapidly expanding interface.
Otherwize, in a month or so, we'll find ourselves discussing the exact
saome problem for "unwind-table", "wcookie", "avr", and "kod".

I also think that the protocol semantics should reflect this interfaces
semantics (or a superset of it).

> +Read from the target's @dfn{auxiliary vector}, treated as an
> +uninterpreted block of bytes. (@xref{Auxiliary Vector}.)
> +Request @var{length} bytes starting at @var{offset} bytes into the data.
> +
> +Reply:
> +@table @samp
> +@item @code{=}@var{data}
> +@var{data} (hex encoded) contains the data bytes read.
> +There is no more auxiliary data after what was requested.
> +
> +@item @code{+}@var{data}
> +@var{data} (hex encoded) contains the data bytes read.
> +There may be additional data that can be read with another request.
> @end table

(technical nit "+" can't be used. For want of a better term, it acts as
a [re]sync character and hence can't appear in the middle of a packet.
Also see note at end.)

Lets start with this:

-> qPartial:<obj>:read:<x-annex>:<x-offset>,<x-length>
<- OK -- implicit zero length returned EOF
<- <x-data> -- must contain the byte @<x-offset>
<- "" -- packet not recognized
<- Enn - something wrong with the request

-> qPartial:<obj>:write:<x-annex>:<x-offset>:<x-data>
<- <x-be-length> -- number of bytes actially written
<- "" -- packet not recognized
<- Enn -- something wrong with the request

-> qPartial:<obj>?
<- OK -- queries of type <obj> are supported
<- "" -- queries of type <obj> are not supported

a variation being something like:
qPartial:obj=<obj>:op=write[:annex=<x-annex>]:offset=<x-offset>:data=<x-data>
which makes it more extensible.

Anyway, this would give us:
-> qPartial:auxv?
OK
-> qPartial:auxv:read::0,ff
123456....

And closely parallels the read/write partial methods.

Once that's been used for a bit, and its performance evaluated, we can
look to refine it. Perhaphs by adding additional replies to the read
side (and even the write side).

--

Looking more closely at this fragment of the committed code:

> LONGEST
> target_auxv_read (struct target_ops *ops, char **data)
> {
> size_t auxv_alloc = 512, auxv_pos = 0;
> char *auxv = xmalloc (auxv_alloc);
> int n;
>
> while (1)
> {
> n = target_read_partial (ops, TARGET_OBJECT_AUXV,
> NULL, &auxv[auxv_pos], 0,
> auxv_alloc - auxv_pos);
> if (n <= 0)
> break;
> auxv_pos += n;
> if (auxv_pos < auxv_alloc) /* Read all there was. */
> break;

the it must assume that the transfer was fragmented, and attempt a re-fetch.

Andrew