[Dwarf-Discuss] DW_OP_call* referencing DIE without DW_AT_location
jakub at redhat.com
Fri Oct 1 12:49:21 PDT 2010
What is the rationale for specifying that DW_OP_call* to
DIE without DW_AT_location acts like DW_OP_nop? It doesn't make
much sense to emit the DW_OP_call* in that case.
We would see a use for a different behavior, though of course
another possibility is to add yet another DW_OP_* opcode.
The problem we are trying to solve are addresses of external symbols.
extern int foo, bar;
int fn1 (void)
int *p = &foo;
p = &bar;
we don't want to emit DW_OP_addr <foo> and DW_OP_addr <bar> in .debug_loc
for p, because
1) we want code compiled with debug info to behave the same as the same code
compiled without debug info. In the above, when all references to foo
and bar are optimized away in real code, having them left only in
.debug_* sections would mean -g compiled code wouldn't link if there
is no foo or bar definition, while -g0 code would link fine
2) our linker doesn't create relocation sections for binaries or
shared libraries against .debug_* sections, relocations are there only
for object files and are resolved during linking; the debugger
just uses the DWARF forms etc. to find out what needs to be relocated
by the shared library load bias and what should be kept.
Even if foo or bar are known to be defined in current CU (or within the
same shared library or binary if we ignore 1) ), for ELF shared libraries
there could be a symbol with the same name earlier in the search scope
and thus &foo and/or &bar should in that case resolve to that instead of
the local address.
If we could use DW_OP_call4 to the DW_AT_declaration DIE in the current CU
instead of DW_OP_addr, and let the debug info consumer find the matching
definition DIE and use DW_AT_location of the definition as the DWARF call
procedure, this problem would be solved.
If there is a reason for DW_OP_call4 being a nop if the exactly referenced
DIE has no DW_AT_location, we could use a new opcode for it instead.
Another thing that could be solvable with DW_AT_call* with no DW_AT_location
could be conditionally optimized away variables.
Currently DWARF says that empty DW_AT_location is considered as
<optimized away> status of the DIE (and we treat missing
DW_AT_location/DW_AT_const_value on DIE definition similarly).
But consider say:
int foo (int x)
int p = x ? x + 4 : y + 5;
bar (); // Could clobber y.
// What is p value now?
return x; // Assume x is originally in reg5 (%rdi) and right before bar
// copied into some other register (say reg3 (%rbx)).
If p is optimized away in the program, before the bar () call
we can use e.g.
DW_OP_breg5 <4> DW_OP_addr <y> DW_OP_deref_size <4> DW_OP_plus_uconst <5> \
DW_OP_breg5 <0> DW_OP_bra <1> DW_OP_swap DW_OP_drop DW_OP_stack_value
as p's location, but in the middle of bar or after bar y could have been
already modified. If the y value isn't saved anywhere, if x was 0 all we
can print for p is <optimized away>. But if it was non-zero, we could do
better. Something like
DW_OP_breg5 <4> DW_OP_breg5 <0> DW_OP_bra <NN> <some magic sequence of length NN>
where <some magic sequence of length NN> would be something to cause
<optimized away> status. It could be DW_OP_call2 to a DIE definition (say
DW_TAG_dwarf_procedure) with no DW_AT_location, if DW_OP_call* didn't
specify it as nop, or something else (new opcode, division by zero,
pop everything from the DWARF stack and branch to end of the DWARF
expression, dereferencing NULL, DW_OP_deref_size with 0 size, something
else? Suggestions welcome.
More information about the Dwarf-Discuss