Issue 230109.2: Inferior calls in DWARF expressions

Author: Jakub Jelinek
Champion: Jakub Jelinek
Date submitted: 2023-01-09
Date revised: 2023-10-02
Date closed:
Type: Enhancement
Status: Deferred
DWARF Version: 6

Section, pg 38

As has been discussed in DW_AT_default_value discussions, it might be useful to be able to call a user function during evaluation of DWARF expressions, pass it arguments popped from the DWARF stack and push the return value which was returned back on DWARF stack.

Most debuggers already have the possibility to invoke inferior calls, and especially for calls which don't have side-effects on global memory it might be useful to arrange for such calls during computation of value of some optimized out variables.

Say, if one has:

#include <math.h>
void foo (float x) { float f = sqrtf (x) * 4.0f; }

if the debug info producer decides to optimize away the call because it isn't really used afterwards (and user tells that e.g. floating point exceptions aren't important), then currently there is nothing that can describe the value of variable f, while in debugger one can

print sqrtf (x) * 4.0f

and get the value.

Changes relative to dwarf6-20221116.pdf:

In add:

4. DW_OP_call_value

The DW_OP_call_value operation pushes the value that a function return. It has three operands, the first is an unsigned LEB128 integer that represents the offset of a debugging information entry in the current compilation unit, or value 0 which represents the generic type. If the first operand is non-zero, the referenced entry must be a DW_TAG_base_type entry that provides the type to which the returned value is converted.

The second operand is in the 32-bit DWARF a 4-byte unsigned value, in the 64-bit DWARF format an 8-byte unsigned value, which is the offset of a DW_TAG_subprogram debugging information entry in a .debug_info section for a function to be called. The third operand is an unsigned ULEB128 number of arguments. The DW_OP_call_value operation pops that number of entries from the stack, constructs a call to the specified function with the popped entries as argument values (the first popped entry (topmost) being the first argument, executes the function and pushes the value the function returned converted to the type indicated by the first operand.

In 7.7.1 add to Table 7.9:

DW_OP_call_value ‡   0xac    3   ULEB128 type entry offset
                                 4- or 8-byte offset of DIE
                                 ULEB128 number of arguments