[Dwarf-Discuss] DWARF Issue 071227.1

Roland McGrath roland@redhat.com
Fri Apr 11 23:32:01 GMT 2008

> Re: http://dwarfstd.org/ShowIssue.php?issue=071227.1

I have only just now looked at this, though it's very similar to what
I proposed on this list.  An unfortunate effect of moving a subject
that arose here onto a private list excluding some participants in the
original discussion.

I don't understand DW_OP_fetch at all.  
How does it differ from DW_OP_deref/DW_OP_deref_size?

I don't see why the proposal defines the term "reference" as what a
location expression yields (address or register).  That is what
"location" means in the standard.  I don't think the new term clarifies
anything.  In fact, using "pseudo-address" to refer to register locations
just obfuscates things IMHO.  Rather, we are just adding a new kind of
"location" (formally per 2.6.2, a "simple location expression"), which is
"in value space" rather than "in register space" or an address in actual
memory space.

What's the benefit of the notion, "That reference can now be used as
though it were an address in the target for other operations." ?
How would a computed value be used in other operations that's worthwhile?
I can't see what would ever follow DW_OP_value except DW_OP_piece or
DW_OP_bit_piece.  That makes an expression ending in DW_OP_value akin
to a DW_OP_reg* expression, which we do not describe as "pushing a
virtual location onto the stack"--it's clear in the spec that the only
thing that can follow is a composition operator.

I wonder if it's really worthwhile to have a DW_OP_value with argument,
separate from composition operators.  It feels awkward to me.  AFAICT
the only benefit of this style is to make it more explicit to the human
eye how many stack pops are entailed.  It's already specified (2.5.1)
that the size of stack elements is the size of target addresses.  The
use of the phrase "size in stack elements" in the DW_OP_value makes it
sound like this is a new or unknown quantity.  Every other place says
"size of an address on the target machine".  Since that's what it is,
the producer of the expression and the consumer really do already share
an understanding of the relationship of stack elements to explicit sizes
in bits and bytes.

I think the last iteration I proposed was DW_OP_val_piece and
DW_OP_val_bit_piece composition operators.  When composition is
required, that takes two bytes fewer to encode than DW_OP_value
followed by DW_OP_piece and it's the same space cost as DW_OP_value
when no composition is required.

> - smaller-than-word objects can't be handled efficiently if the
> endianness isn't right.  

With DW_OP_val_piece I would address this by making the order
endian-dependent.  (Perhaps formally "defined by the ABI", but it
would in practice always be one canonical way for each endian,
address-size combination.)  

DW_OP_val_piece takes an ULEB128 operand that's a number of bytes.
This pops roundup(bytes, address_size_in_bytes) elements off the
stack.  Consider:

				little-endian 32-bit	big-endian 32-bit
	DW_OP_lit1		TOS: 0x00000001		TOS: 0x00000001
	DW_OP_val_piece 1	yield: "\x01"		yield: "\x01"

little-endian 32-bit:
	DW_OP_const4u 0xaa 0xbb 0xcc 0xdd	TOS: 0xddccbbaa
	DW_OP_const1u 0xee			TOS: 0x000000ee
	DW_OP_val_piece 5			yield: "\xaa\xbb\xcc\xdd\xee"

big-endian 32-bit:
	DW_OP_const1u 0xaa			TOS: 0x000000aa
	DW_OP_const4u 0xbb 0xcc 0xdd 0xee	TOS: 0xbbccddee
	DW_OP_val_piece 5			yield: "\xaa\xbb\xcc\xdd\xee"

> - AFAIK it is not possible to carry data over across DW_OP_piece or
> DW_OP_bit_piece. [...]

I don't think the spec is very clear or explicit about this at all.
I'd tend to read it that way too, but that is based more on a guess of
intent than on a pedantic reading of the spec.  It's as easy to read
it as not ruling out extra state left of the stack after each simple
location expression.  If there is any need for this, then I think the
simplest thing is just to declare it official kosher to have
additional elements left on the stack when you hit a composition
operator, that are there for the next subexpression to use.

> - It occurs to me that it would be useful to be able to refer to the
> value of other varibles in debug information.  It appears to me that
> DW_OP_call* can be used for this purpose.  However, I don't quite see
> how this works in case a variable is encoded in multiple location
> pieces, or even in case multiple location list entries match for the
> called variable.  Am I making some fundamental mistake in my
> understanding of how these opcodes are supposed to be used?

I suspect it's just that they were specified before complex
considerations of DW_OP_piece et al were.

> DW_OP_call_ref supposed to behave?  And then, if it was to select the
> DW_OP_reg entry, would DW_OP_deref still work?  And how about the
> DW_OP_piece entry?  Is DW_OP_deref supposed to handle that correctly?

That's a lot to read into the DW_OP_deref description.  But it's not
that different in kind from the implicit reading of what it means to
compose a DW_OP_reg* or DW_OP_piece location with an expression from
DW_AT_data_member_location, which is described as taking an address on
the stack and yielding a modified address.  Maybe DW_OP_deref with
this fancy reading was what they meant by DW_OP_fetch. ;-)

The only way I can really find to try to keep things straight is to
say it's equivalent to inlining the called expression right there as
part of the larger expression.  To look at it that way, you have to
loosen from the specified way of looking at DW_OP_reg* (always has to
be a singleton).  I think of it as the TOS containing any of memory
address, register name, or value word.  (To describe it that way
formally, I think you don't need to generalize it to describe all
stack elements that way, just the top.)

> And then, even if DW_OP_deref works, what if we had to modify the
> address before dereferencing it, say, to access the second 4-byte word
> of a 2-word variable that was scalarized by the compiler?
> I.e., given:
> struct { int a, int b; } lother;
> /* x can be computed as other.b + 1: */
>   DW_OP_call_ref <other>
>   DW_OP_plus_uconst 4
>   DW_OP_deref
>   DW_OP_plus_uconst 1
>   DW_OP_value 1
> is lother defined like this supposed to work?

That is consistent in an abstract sense with:

	lother location: DW_OP_reg1 DW_OP_piece 4 DW_OP_reg7 DW_OP_piece 4
	struct.b data_member_location: DW_plus_uconst 4

> Do these sound like reasonable ideas to propose formally, or are they
> already addressed somehow in the current specification, and I just
> don't quite get it?

I think the related simpler things that are already commonly supported
(like composition of "address-relative" expressions with composites
and register name expressions) are not addressed with sufficient
clarity in the spec.  I'd like to see the whole subject specified more


More information about the Dwarf-discuss mailing list