010710.1 | A | R. Brender | Representation | Eliminate DW_OP_calli |
PROBLEM:
At the meeting of 10 July, the committee adopted proposal 010503.1 which
adds the DW_OP_call_ref operator. As a result,
- much of the original motivation for DW_OP_calli is eliminated
- the dynamic aspect of DW_OP_calli becomes incomplete because it
does not allow calls between shared executables
This leads to the following proposal.
PROPOSAL:
Withdraw DW_OP_calli from DWARF (and don't replace it).
WORDING CHANGES:
DW_OP_calli is mentioned in these sections:
2.4.1.5, Bullet 4 (as modified by 010503.1)
5.15 (describes DW_TAG_dwarf_procedure and lists DW_OP_calli as
one way to call such a procedure)
7.7.1, Figure 22 (defines the code)
App B, Figure 39 (shows section relationships, mentions DW_OP_calli)
Deletion of DW_OP_calli is easy and requires at most minor editorial fixup.
DISCUSSION:
DW_OP_calli was not part of the original proposal 000217.1 from Felix
(which included only DW_OP_call2 and DW_OP_call4). My recollection is that
DW_OP_calli was invented at the meeting that considered his proposal (see
the minutes for 21 March 2000) when someone observed that we probably also
needed DW_OP_call8 to go with the then still evolving 64-bit DWARF format.
Somehow the notion of DW_OP_calli came up with the expection that the
64-bit format could use DW_OP_addr to materialize the .debug_info offset;
the notion of a computed target DIE seemed like a neat "free one-plus".
We now understand that a DW_OP_addr/DW_OP_calli (or any other DW_OP_*/
DW_OP_calli combination) is inheritently limited to referencing only
a DIE in the containing executable/shared image. As a result, a key part
of DW_OP_calli's purpose -- to call any DIE outside of the containing
module -- has been made unneeded by DW_OP_call_ref, which works both within
and between shared executables.
Further, the remaining dynamic/indirect aspect can often be accomplished
using some form of test and conditional flow to the desired DW_OP_call2/4/_ref
operator. There remain but a very few cases (such as passing the target DIE
offset into a DWARF procedure) that cannot be easily emulated -- but there
is no evidence or implementation experience to date to indicate that this
is really important.
Even if it is important, there is a problem. DW_OP_calli does not work
across shared executables and it may be difficult to assure that its
possible targets are necessarily all in the same shared executable as
the call. So it is potentially unsafe to use it at all.
If you really think that the indirect aspect of DW_OP_calli is important,
then it should be replaced with something that will work across shared
objects. One way to accomplish that would be something like the following:
- Add new DW_OP_push_ref
The operand is used to push two values on the stack; the first is
a debugger-defined handle that identifies the target executable or
shared object, and the second (which becomes the top of the stack)
is the .debug_info offset that applies in that object. The operand
is interpreted like a DW_FORM_ref_addr value wrt size, etc.
The .debug_info offset is made the top of stack so the it can
be conveniently manipulated, if desired, to compute the target DIE
for use in the next operator.
- Add new DW_OP_call_refi
Pops two values from the debug stack. The second must be a handle
from a previous DW_OP_push_ref operation that identifies the
target image for the call, and the first (top of stack) is the
.debug_info offset of the target DIE in that object. Calls the
DW_AT_location expression of the target DIE.
If you do that, then DW_OP_calli is unneeded. I suppose it could be
retained as currently formulated as an "optimization" for the special
case where that target DIE is known a priori to be in the containing
image. But why bother?
I don't think the dynamic aspect of DW_OP_calli is worthwhile enough
to justify adding DW_OP_push_ref and DW_OP_call_refi, however.
I recommend we just delete DW_OP_calli and leave it at that.
Adopted.