DWARF Standard


HOME
SPECIFICATIONS
FAQ
ISSUES



221105.1 Kyle Huey Add a mechanism for specifying subprogram return value locations Enhancement Open Caroline Tice


Section 3.3.2, pg 78

DWARF allows a DW_TAG_subprogram/DW_TAG_inlined_subroutine (the latter 
via DW_AT_abstract_origin) to note their return type with a DW_AT_type, 
as detailed in Section 3.3.2. It does not, however, provide any 
information about where the return type is in the program at the 
subprogram boundary. Debuggers that support printing return values 
at function exit (e.g. gdb) currently infer this from the platform ABI 
(e.g. `amd64_return_value` in gdb/amd64-tdep.c). There is no requirement 
that arbitrary functions actually follow the platform's standard ABI 
though, and when this inference fails, it fails silently, presenting 
the wrong value to users.

There are, in my opinion, two interesting cases:

1) Cases where the function follows some sort of ABI, just not the 
platform's standard ABI.

The Rust compiler, for instance, doesn't always follow the standard 
SYSV AMD64 ABI when compiling for that platform. 
See https://github.com/rust-lang/rust/issues/85641 for one real world 
example that silently breaks gdb.

In theory this case could be covered by adding a DW_CC_rust value for 
the DW_AT_calling_convention attribute to the spec, and downstream 
tools could be taught what that means and how to process it accordingly. 
I think this is more complicated than having the compiler directly emit 
the location information, and it wouldn't cover the second case.

2) Inline functions.

Inline functions don't necessarily follow any ABI. Depending on the 
optimizations performed after inlining, they may not even have proper 
bounds to determine what constitutes a single invocation of the function 
(imagine an inline function whose instructions have been intermingled 
by the optimizer with the instructions of its containing function). 
But there are common cases where a inlined function does have a 
meaningful and easy-to-determine return value.

Consider the simple C++ program

#include <iostream>

using namespace std;

inline bool greater_than(int x, int y) {
    return x > y;
}

int main(int argc) {
    if (greater_than(argc, 4)) {
        cout << "I have more than 3 arguments\n";
    } else {
        cout << "I have 3 or fewer arguments\n";
    }
    return 0;
}

An optimizing compiler (e.g. gcc 12.2 with -O2) can convert the 
greater_than function into a single comparison instruction inlined 
into main. The corresponding bit in the flags register is clearly 
not the ABI-specified location for the return value.


I propose to add language to the spec allowing DW_AT_location to be 
present on DW_TAG_subprogram/DW_TAG_inlined_subroutine. When present, 
it would contain a location expression specifying the location of the 
function's return value. (In the two examples above, on x86-64, the 
expressions "DW_OP_reg0 DW_OP_piece 4 DW_OP_reg1 DW_OP_piece 4" and 
"DW_OP_regx 49 DW_OP_dup DW_OP_const1u 64 DW_OP_and DW_OP_lit6 
DW_OP_shr DW_OP_lit0 DW_OP_eq DW_OP_swap DW_OP_dup DW_OP_const1u 128 
DW_OP_and DW_OP_lit7 DW_OP_shr DW_OP_swap DW_OP_lit1 DW_OP_and 
DW_OP_eq DW_OP_eq" respectively are capable of encoding the return 
values). If it's not present, debuggers and other tools can fall back 
to their current behavior.



All logos and trademarks in this site are property of their respective owner.
The comments are property of their posters, all the rest © 2007-2022 by DWARF Standards Committee.