This is the mail archive of the archer@sourceware.org mailing list for the Archer 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: Syscall tracing


> I've been thinking about pretty-printing as being a type-specific
> thing -- that is, the C++ cases of having some class or template with
> a printer which is always used to display objects of that type.

That seems like a fine and natural thing to be the main implicit way that
such code gets used.  I presume it's not the only way you'll ever want to
be able to invoke it.

> With syscalls, I think the printer could not really work this way.

I don't really see why not.  

A system call is a prologue breakpoint where you can see arguments, and an
after-finish breakpoint where you can see the return value.  If you have
"catch syscall" where it stops like for a breakpoint, then it should
display:

	System call 27, frobozz (foo=42, bar=0x123, baz=0x789 "hello")
	(gdb) 

or whatever it would do for a function entry breakpoint.  If you want to
pretty-print foo and bar there, then that would be driven by their types.
Just like typing "p bar->field" is driven by bar's type, and you better
want to let me do that or else I'm taking my marbles and going home.  
(No comments from the peanut gallery about if I have any such marbles.)

If you want "strace-like" output for syscalls, then however you make that
happen you should be able to make it happen for chosen functions too
("ltrace-like" output).  In both cases, it's: get a stop at "entry", fetch
the arguments, virtual "finish", fetch the return value.  (Except that for
syscalls, "error return" really is distinct from just a given return value,
almost like an exception.)

> Also, I'm wondering about ioctl, where the last argument can take many
> different forms.  To do an excellent, strace-esque job of display,
> this information would have to come from the kernel as well (IMO), in
> a usable form ... "request X" corresponds to "struct Y *" or whatever.

Where this information is maintained in source form is the same not a
technical subject as for the rest of the ABI info and I'm not going
to get into it right now.

You could treat ioctl as a special case.  But it should be possible to
describe it completely within the type system.  This approach (as for
syscalls generally) naturally makes the decoding fully accessible to
expression evaluation and everything else, not just a special feature in
pretty-printing.  Here's how I would do it.

The ioctl syscall actually takes three args (fd, request, arg).
But the C prototype is (int fd, unsigned long int request, ...).
Some requests ignore ARG, so calls are actually ioctl (fd, XIOFOOBAR).
(Technically, this means there is a third arg to the syscall that
is garbage, though is presumed ignored by the kernel.)

What I'd describe in DWARF is two args:

	formal_parameter
		name: "fd"
		type: [int] (or whatever fancy-business type)
		location: {DW_OP_reg5}		# (x86-64 example) %rdi
	formal_parameter
		type: [big hairy anonymous type below]
		location: {DW_OP_reg4 DW_OP_piece(8) DW_OP_reg1 DW_OP_piece(8)}

Note the second parameter has no name.  That location is the combination of
registers %rsi,%rdx taken as a two-word structure.  The example is x86-64,
whose first 3 syscall args are found in rdi(5),rsi(4),rdx(1).

Here I'm deciding that the debugger should take an anonymous
formal_parameter (with no DW_AT_artificial), whose type is a
struct/etc (has subfields), and treat it, for display and parameter
name binding, as if each subfield were a separate parameter.

The big hairy type would be:

structure_type
	artifical: true
	variant_part
		discr: [member "request"]
		member
			name: "request"
			type: [unsigned long int] # or better, an enum
			data_member_location: +0
		variant
			discr_value: 0x1234 (aka XIOFOO)
		variant
			discr_value: 0x1235 (aka XIOBAR)
			member
				name: "arg"
				type: [struct bar *]
				data_member_location: +8
		variant
			discr_value: 0x1236 (aka XIOBAZ)
			member
				name: "arg"
				type: [int]
				data_member_location: +8

Here it's handling:

	ioctl(fd, XIOFOO)
	ioctl(fd, XIOBAR, &bar)
	ioctl(fd, XIOBAZ, 27)

There are numerous sets that all take the same pointer type, so those would
use discr_list attributes to collapse the duplicate variants.  (The actual
type for Linux ioctls would be a monster with dozens of variant DIEs.)

This is the same DWARF that would be generated for:

	datatype ioctl_arg = XIOFOO | XIOBAR of bar | XIOBAZ of int

or whatever, except that the descriminator is named.  (Sorry, can't think
off hand of a language with variant records, aka descriminated unions,
other than SML, and it doesn't have named descriminators. ;-)

The location expression to treat two syscall argument registers as this one
type fudges the "what is an argument" semantics a bit.  But it's already
supported from the authentic case of a "struct { long a,b; } x;" local in
two registers.  Exploiting the variant record encodings in DWARF might do
something gdb hasn't had to do (since best-supported languages don't have
them), but it's well-defined DWARF stuff.  Knowing to print an anonymous
parameter might be new, and certainly the binding of "p fd" and "p *arg"
to "p <anonymous arg>.fd" and "p *<anonymous arg>.arg" would be new.

Of course, the stuff maintained by humans that feeds into generating this
DWARF would have to be straightforward to deal with.  This implies having
some useful tools to generate specialized fancy DWARF, which we are not yet
very near to having.  But, as usual, I'm just lodging my theses (and a
brief treatise) on the door in favor of fancy tools and a thousand little
pieces coming together to make a superpowered giant flying robot that will
wash our socks for years to come, rather than the most straightforward
implementation to address today's immediate need.


Thanks,
Roland


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