Issue 221105.1: Add a mechanism for specifying subprogram return value locations
| Author: | Kyle Huey |
|---|---|
| Champion: | Andrew Cagney |
| Date submitted: | 2022-11-05 |
| Date revised: | 2024-12-09 |
| Date closed: | |
| Type: | Enhancement |
| Status: | Open |
| DWARF version: | 6 |
Comparing 2024-03-04 with latest. [ Return to the latest version ]
Section 3.3.2, pg 78 ## Background
A debug feature is to print the result of a subroutine at exit.
A debug feature is to print the value returned by a subprogram.
One way this is implemented is:
In GDB (and I assume LLDB) this is implemented as follows:
- run the called subroutine until it exits
- create an identifier of the caller of the subprogram instance
i.e., the return instruction has been completed and the program is
for instance, { function's entry point, the CFI's CFA }
When there's recursion this is to differentiate between otherwise
identical instances.
- breakpoint the instruction that the subprogram will return to, i.e.,
in the calling subprogram
in the calling subprogram
- extract the result from the calling subprogram's frame
for instance, CFI's return address
- breakpoint any code that can longjump around caller
so that the return breakpoint can be deleted
- resume the program
- when the breakpoint hits:
- if the frame is older then the caller - longjump - abort
- if the frame is newer than the caller - recursion - continue
- if the frame matches, ya!
- extract and display the return value using the callers context
While DWARF makes available the type of the return value (`DW_AT_type`
attached to `DW_TAG_subprogram`, as detailed in Section 3.3.2.) it
attached to `DW_TAG_subprogram`, as detailed in Section 3.3.2), it
does not provide any information about the return value's location. Debuggers instead use the platform's calling convention to determine the return value's location.
does not provide a mechanism for obtaining the value being returned by a subprogram immediately after the return instuction. Instead consumers use hardwired, and assumed, ABI knowlege to obtain the value.
This has a number of limitations:
However, for subprograms that do not follow the standard calling convention (i.e., (hopefully) have `DW_AT_calling_convention` `DW_CC_nocall` attached to `DW_TAG_subprogram`), locating the return value may not be possible.
- the consumer's ABI knowledge is hard-wired
Inline functions are similar (using `DW_TAG_inlined_subroutine` via `DW_AT_abstract_origin`). Run the code block until the inlined function has "exited", and then extract the returned value. However, here things are even more challenging. It is very unlikely that the inlined and optimized code ever follows anything approaching an ABI.
## Proposal
It isn't possible for a producer to generate code following
different conventions without also modifying the consumer.
Attach a location description to the subprogram's debug information describing the location of the return value immediately after the
For instance: a Language (here Rust) uses a calling convention not
covered by the ABI; the compiler optimises a subprogram causing the
calling convention to change.
- the returned value's location may be unknown
For instance, when the the return value's memory location is passed
in as a hidden first parameter (aka struct return) that location is
unknown at the time of return
- when a subprogram is inlined
Similar to the non-inline case, DWARF makes available tye
subprogram's return type (`DW_AT_type` in `DW_TAG_inlined_subroutine`
via `DW_AT_abstract_origin`) but not the location of the returned
value.
However, it is very unlikely that the inlined code follows any
calling convention.
(While attaching `DW_AT_calling_convention` `DW_CC_nocall` to the
subprogram could be used to signal that the ABI is not being followed,
this isn't about the consumer simulating a call).
Please note that this is not proposing a mechanism for locating a
subprogram's return value while inside the function such as at the
return instruction.
## Proposal Part 1: add `DW_AT_result_location` to `DW_AT_subprogram`
Add the attribute `DW_AT_result_location` to `DW_AT_subprogram`. This
attribute describes the location of the value returned by the program
subprogram has returned.
after the subprogram has returned.
_Why not describe the value at the return instruction?_
Because the subprogram has exited it uses the CFI of the calling subprogram.
- this is addressing the above existing practice
Some notes:
- informally, the completion of the return instruction acts as a synchronization point
- Why the new attribute `DW_AT_result_location` (instead of using `DW_AT_location`)?
- for delayed branch and VLIW architectures, it is often only after the completion of the return instruction (bundle) that the subprogram result is in a known location
A location description:
> _Single location descriptions_, [...]. They are sufficient for
> describing the location of any object as long as its lifetime is
> either static or the same as the lexical block that owns it, [...]
Here the description, while owned by the subprogram, is interpreted
using the lexical block of the caller.
## Change Details ### Called Subprograms
In 3.3.2 Subroutine and Entry Point Return Types,
In 3.3.2 Subroutine and Entry Point Return Types, change the section
change the section heading to:
heading to:
> 3.3.2 Subroutine and Entry Point Return Type and Value At the end of the section, which currently reads:
> If the subroutine or entry point is a function that returns a
> If the subroutine or entry point is a function that returns a value,
> value, then its debugging information entry has a `DW_AT_type`
> then its debugging information entry has a `DW_AT_type` attribute to
> attribute to denote the type returned by that function.
> denote the type returned by that function.
> > [non-normative text]
append the text:
Add the paragraph and non-normative text:
> A subroutine or entry point that is a function that returns a
> A subroutine or entry point that is a function that returns a value
> value and has a `DW_AT_type` attribute may also have a
> and has a `DW_AT_type` attribute may also have a
> `DW_AT_location` attribute. This attribute specifies the
> `DW_AT_result_location` attribute. This attribute specifies the
> location of the return value after the called function has
> location of the return value after the called function has returned
> returned and the calling subprogram is about to be resumed.
> and the calling subprogram is about to be resumed.
> > [begin non-normative] > > Since the called subprogram has returned, the location
> _Since the called subprogram has returned, the location description > is relative to the calling subprogram. For instance, for a sliding > window architecture such as SPARC, the location description refers > to the output registers of the caller, and not the input registers > of the callee._
> description is relative to the calling subprogram. For > instance, for a sliding window architecture such as SPARC, the > location description will refer to the output registers of the > caller, and not the input registers of the callee. > > Since the called subprogram is expected to return the value in > a specific location, the `DW_AT_location` should be a Single > Location Description. > > When the both the attribute and DW_CC_nocall are both omitted, > the subprogram is assumed to comply with ABI calling > conventions. > > [end non-normative]
_Notes:_
> _When the both the attribute `DW_AT_result_location` and > `DW_CC_nocall` are both omitted, the subprogram is assumed to comply > with ABI calling conventions._
- should this attribute get a new name other than `DW_AT_location` or stick with that since it goes with `DW_AT_type`?
### Call Site Entries and Parameters
- Since `DW_AT_location` is useless with out `DW_AT_type` I made `DW_AT_type` a predicate. Should it instead be non-normative text?
In 3.4 Call Site Entries and Parameters, change the section title to:
- Is my assumption that the `DW_AT_location` can only be for a Single Location (i.e., not a location list) correct?
> 3.4 Call Site Entries, Parameters, and Return Value
- If a subprogram were to be included in multiple objects then, presumably, each would define its own `DW_AT_location`.
- This is a technical violation of:
Change the opening non-normative paragraph from:
_Single location descriptions_, [...]. They are sufficient for
describing the location of any object as long as its lifetime is
either static or the same as the lexical block that owns it, [...]
> _A call site entry describes a call from one subprogram to another > in the source program. It provides information about the actual > parameters of the call so that they may be more easily accessed by a > debugger. When used together with call frame information (see > Section 6.4 on page 178), call site entries can be useful for > computing the value of an actual parameter passed by a caller, even > when the location description for the callee’s corresponding formal > parameter does not provide a current location for the formal > parameter._
### Call Sites
to:
In 3.4.2 Call Site Parameters, change the section title to:
> _A call site entry describes a call from one subprogram to another > in the source program. It provides information about both the > actual parameters of the call, and the location of the return value > after the subprogram returns, so that they may be more easily > accessed by a debugger. Independent of the location description of > the callee’s corresponding formal parameters and > `DW_AT_result_location` attribute, the Call Site entry can be used > together with call frame information (see Section 6.4 on page 178) > to compute the value of an actual parameter passed by a caller and > the return value after the callee returns._ In 3.4.2 Call Site Parameters, change the section title to:
> 3.4.2 Call Site Parameters and Return Value
(or a new section?)
At the end of the section add the paragraph and non-normative text:
At the end of the section add the text: > A call site entry that has a `DW_AT_type` attribute for the type
> A call site entry that has a `DW_AT_type` attribute for the type of
> of the called function, may have a `DW_AT_location` attribute
> the called function, may have a `DW_AT_result_location` attribute
> specifying the location of the return value after the called
> function has returned and the calling subprogram is about to
> function has returned and the calling subprogram is about to be
> be resumed.
> resumed. > _Since the function described by the Call Site Entry's `DW_AT_type`
> > [non-normative] > _Since Call Site Entry's `DW_AT_type` attribute can describe an > abstract function, the return type and location may be
> attribute can be abstract, the return type and location may be
> different between the Call Site and the subprogram._
### Inlined Subprograms
In 3.3.8.1 Abstract Instances,
In 3.3.8.1 Abstract Instances
in the non-normative text:
Change the non-normative text:
> For example, the `DW_AT_low_pc`, [...] attributes typically > should be omitted;
> _For example, the `DW_AT_low_pc`, `DW_AT_high_pc`, `DW_AT_ranges`, > `DW_AT_entry_pc`, `DW_AT_location`, `DW_AT_return_addr` and > `DW_AT_start_scope` attributes typically should be omitted; however, > this list is not exhaustive._
add `DW_AT_location`.
to:
In 3.3.8.2 Concrete Instances, following the paragraph:
> _For example, the `DW_AT_low_pc`, `DW_AT_high_pc`, `DW_AT_ranges`, > `DW_AT_entry_pc`, `DW_AT_location`, `DW_AT_return_addr`, > `DW_AT_result_location`, and `DW_AT_start_scope` attributes typically > should be omitted; however, this list is not exhaustive._ (i.e, add `DW_AT_result_location`) In 3.3.8.2 Concrete Instances, following the paragraph:
> An inlined subroutine entry may have a `DW_AT_const_expr` > attribute, [...], represented as it would be on the target
> architecture.
> architecture. ....
Add the paragraph and non-normative text: > An inlined subroutine entry that is a function that returns a > value and and has `DW_AT_type` defined in the Abstract Instance
> may have a `DW_AT_location` attribute. This attribute
> may have a `DW_AT_result_location` attribute. This attribute
> describes the location of the return value immediately after > the concrete instance has completed execution of the contiguous > or non-contiguous machine instructions generated for the > inlined subroutine.
> > [non-normative]
> _Since the concrete instance may consist of non-contiguous
> instructions, `DW_AT_location` may be defined using a Location
> instructions, `DW_AT_result_location` may be defined using a Location
> List. Within that list, each bounded entry identifies an > instruction immediately after the concrete instance has > completed execution. That list of locations may not be > exhaustive._
_Notes:_ - Since `DW_AT_location` is useless with out `DW_AT_type` I made `DW_AT_type` a predicate. Should it instead be non-normative text?
### Appendix A. Attributes by Tag (Informative)
Under TAG name `DW_TAG_subprogram`, add `DW_AT_location` to the applicable attributes.
Add `DW_AT_result_location` to: - `DW_TAG_subprogram` - `DW_TAG_call_site` - `DW_TAG_inlined_subroutine`
### Appendix D
[Example TBD]
_Questions:_ - do we want to attempt an example?
---
2022-11-05: [Original proposal][orig].
2023-11-05: Rewrote.
2023-11-05: [Rewrote][diff1].
2024-01-08: Revised with more non-normative text.
2024-01-08: [Revised][diff2] with more non-normative text.
2024-02-05: Added section on call sites.
2024-02-05: [Added section on call sites][diff3].
2024-03-04: Revised to add ABI fallback and address questions about call sites.
2024-03-04: [Revised][diff4] to add ABI fallback and address questions about call sites. 2024-04-29: Needs revision to use `DW_AT_result_location`. 2024-12-09: [Revised][diff5].