diff options
| -rw-r--r-- | md/issues/221105.1.md | 309 | 
1 files changed, 184 insertions, 125 deletions
diff --git a/md/issues/221105.1.md b/md/issues/221105.1.md index 76ddf99..72fa899 100644 --- a/md/issues/221105.1.md +++ b/md/issues/221105.1.md  | |||
| @@ -2,207 +2,266 @@ Title: Add a mechanism for specifying subprogram return value locations | |||
| 2 | Author: Kyle Huey | 2 | Author: Kyle Huey | 
| 3 | Champion: Andrew Cagney | 3 | Champion: Andrew Cagney | 
| 4 | Submit-Date: 2022-11-05 | 4 | Submit-Date: 2022-11-05 | 
| 5 | Revised-Date: 2024-04-29 | 5 | Revised-Date: 2024-12-09 | 
| 6 | Closed-Date: | 6 | Closed-Date: | 
| 7 | Propid: 221105.1 | 7 | Propid: 221105.1 | 
| 8 | Type: Enhancement | 8 | Type: Enhancement | 
| 9 | Status: Open | 9 | Status: Open | 
| 10 | Version: 6 | 10 | Version: 6 | 
| 11 | Format: markdown | 11 | Format: markdown | 
| 12 | Revisions: 2023-08-01, 2023-12-06, 2024-01-21, 2024-02-05, 2024-03-06 | ||
| 12 | 13 | ||
| 13 | Section 3.3.2, pg 78 | 14 | Section 3.3.2, pg 78 | 
| 14 | 15 | ||
| 15 | ## Background | 16 | ## Background | 
| 16 | 17 | ||
| 17 | A debug feature is to print the result of a subroutine at exit. | 18 | A debug feature is to print the value returned by a subprogram. | 
| 18 | 19 | ||
| 19 | One way this is implemented is: | 20 | In GDB (and I assume LLDB) this is implemented as follows: | 
| 20 | 21 | ||
| 21 | - run the called subroutine until it exits | 22 | - create an identifier of the caller of the subprogram instance | 
| 22 | 23 | ||
| 23 | i.e., the return instruction has been completed and the program is | 24 | for instance, { function's entry point, the CFI's CFA } | 
| 24 | in the calling subprogram | ||
| 25 | 25 | ||
| 26 | - extract the result from the calling subprogram's frame | 26 | When there's recursion this is to differentiate between otherwise | 
| 27 | identical instances. | ||
| 28 | |||
| 29 | - breakpoint the instruction that the subprogram will return to, i.e., | ||
| 30 | in the calling subprogram | ||
| 31 | |||
| 32 | for instance, CFI's return address | ||
| 33 | |||
| 34 | - breakpoint any code that can longjump around caller | ||
| 35 | |||
| 36 | so that the return breakpoint can be deleted | ||
| 37 | |||
| 38 | - resume the program | ||
| 39 | |||
| 40 | - when the breakpoint hits: | ||
| 41 | |||
| 42 | - if the frame is older then the caller - longjump - abort | ||
| 43 | - if the frame is newer than the caller - recursion - continue | ||
| 44 | - if the frame matches, ya! | ||
| 45 | |||
| 46 | - extract and display the return value using the callers context | ||
| 27 | 47 | ||
| 28 | While DWARF makes available the type of the return value (`DW_AT_type` | 48 | While DWARF makes available the type of the return value (`DW_AT_type` | 
| 29 | attached to `DW_TAG_subprogram`, as detailed in Section 3.3.2.) it | 49 | attached to `DW_TAG_subprogram`, as detailed in Section 3.3.2), it | 
| 30 | does not provide any information about the return value's location. | 50 | does not provide a mechanism for obtaining the value being returned by | 
| 31 | Debuggers instead use the platform's calling convention to determine | 51 | a subprogram immediately after the return instuction. Instead | 
| 32 | the return value's location. | 52 | consumers use hardwired, and assumed, ABI knowlege to obtain the | 
| 53 | value. | ||
| 54 | |||
| 55 | This has a number of limitations: | ||
| 56 | |||
| 57 | - the consumer's ABI knowledge is hard-wired | ||
| 58 | |||
| 59 | It isn't possible for a producer to generate code following | ||
| 60 | different conventions without also modifying the consumer. | ||
| 61 | |||
| 62 | For instance: a Language (here Rust) uses a calling convention not | ||
| 63 | covered by the ABI; the compiler optimises a subprogram causing the | ||
| 64 | calling convention to change. | ||
| 33 | 65 | ||
| 34 | However, for subprograms that do not follow the standard calling | 66 | - the returned value's location may be unknown | 
| 35 | convention (i.e., (hopefully) have `DW_AT_calling_convention` | ||
| 36 | `DW_CC_nocall` attached to `DW_TAG_subprogram`), locating the return | ||
| 37 | value may not be possible. | ||
| 38 | 67 | ||
| 39 | Inline functions are similar (using `DW_TAG_inlined_subroutine` via | 68 | For instance, when the the return value's memory location is passed | 
| 40 | `DW_AT_abstract_origin`). Run the code block until the inlined | 69 | in as a hidden first parameter (aka struct return) that location is | 
| 41 | function has "exited", and then extract the returned value. However, | 70 | unknown at the time of return | 
| 42 | here things are even more challenging. It is very unlikely that the | ||
| 43 | inlined and optimized code ever follows anything approaching an ABI. | ||
| 44 | 71 | ||
| 45 | ## Proposal | 72 | - when a subprogram is inlined | 
| 46 | 73 | ||
| 47 | Attach a location description to the subprogram's debug information | 74 | Similar to the non-inline case, DWARF makes available tye | 
| 48 | describing the location of the return value immediately after the | 75 | subprogram's return type (`DW_AT_type` in `DW_TAG_inlined_subroutine` | 
| 49 | subprogram has returned. | 76 | via `DW_AT_abstract_origin`) but not the location of the returned | 
| 77 | value. | ||
| 50 | 78 | ||
| 51 | _Why not describe the value at the return instruction?_ | 79 | However, it is very unlikely that the inlined code follows any | 
| 80 | calling convention. | ||
| 52 | 81 | ||
| 53 | - this is addressing the above existing practice | 82 | (While attaching `DW_AT_calling_convention` `DW_CC_nocall` to the | 
| 83 | subprogram could be used to signal that the ABI is not being followed, | ||
| 84 | this isn't about the consumer simulating a call). | ||
| 54 | 85 | ||
| 55 | - informally, the completion of the return instruction acts as a | 86 | Please note that this is not proposing a mechanism for locating a | 
| 56 | synchronization point | 87 | subprogram's return value while inside the function such as at the | 
| 88 | return instruction. | ||
| 57 | 89 | ||
| 58 | - for delayed branch and VLIW architectures, it is often only after | 90 | |
| 59 | the completion of the return instruction (bundle) that the | 91 | ## Proposal Part 1: add `DW_AT_result_location` to `DW_AT_subprogram` | 
| 60 | subprogram result is in a known location | 92 | |
| 93 | Add the attribute `DW_AT_result_location` to `DW_AT_subprogram`. This | ||
| 94 | attribute describes the location of the value returned by the program | ||
| 95 | after the subprogram has returned. | ||
| 96 | |||
| 97 | Because the subprogram has exited it uses the CFI of the calling | ||
| 98 | subprogram. | ||
| 99 | |||
| 100 | Some notes: | ||
| 101 | |||
| 102 | - Why the new attribute `DW_AT_result_location` (instead of using | ||
| 103 | `DW_AT_location`)? | ||
| 104 | |||
| 105 | A location description: | ||
| 106 | |||
| 107 | > _Single location descriptions_, [...]. They are sufficient for | ||
| 108 | > describing the location of any object as long as its lifetime is | ||
| 109 | > either static or the same as the lexical block that owns it, [...] | ||
| 110 | > Location descriptions | ||
| 111 | |||
| 112 | Here the description, while owned by the subprogram, is interpreted | ||
| 113 | using the lexcial block of the caller. | ||
| 61 | 114 | ||
| 62 | ## Change Details | 115 | ## Change Details | 
| 63 | 116 | ||
| 64 | ### Called Subprograms | 117 | ### Called Subprograms | 
| 65 | 118 | ||
| 66 | In 3.3.2 Subroutine and Entry Point Return Types, | 119 | In 3.3.2 Subroutine and Entry Point Return Types, change the section | 
| 67 | change the section heading to: | 120 | heading to: | 
| 68 | 121 | ||
| 69 | > 3.3.2 Subroutine and Entry Point Return Type and Value | 122 | > 3.3.2 Subroutine and Entry Point Return Type and Value | 
| 70 | 123 | ||
| 71 | At the end of the section, which currently reads: | 124 | At the end of the section, which currently reads: | 
| 72 | 125 | ||
| 73 | > If the subroutine or entry point is a function that returns a | 126 | > If the subroutine or entry point is a function that returns a value, | 
| 74 | > value, then its debugging information entry has a `DW_AT_type` | 127 | > then its debugging information entry has a `DW_AT_type` attribute to | 
| 75 | > attribute to denote the type returned by that function. | 128 | > denote the type returned by that function. | 
| 76 | > | ||
| 77 | > [non-normative text] | ||
| 78 | |||
| 79 | append the text: | ||
| 80 | |||
| 81 | > A subroutine or entry point that is a function that returns a | ||
| 82 | > value and has a `DW_AT_type` attribute may also have a | ||
| 83 | > `DW_AT_location` attribute. This attribute specifies the | ||
| 84 | > location of the return value after the called function has | ||
| 85 | > returned and the calling subprogram is about to be resumed. | ||
| 86 | > | ||
| 87 | > [begin non-normative] | ||
| 88 | > | ||
| 89 | > Since the called subprogram has returned, the location | ||
| 90 | > description is relative to the calling subprogram. For | ||
| 91 | > instance, for a sliding window architecture such as SPARC, the | ||
| 92 | > location description will refer to the output registers of the | ||
| 93 | > caller, and not the input registers of the callee. | ||
| 94 | > | ||
| 95 | > Since the called subprogram is expected to return the value in | ||
| 96 | > a specific location, the `DW_AT_location` should be a Single | ||
| 97 | > Location Description. | ||
| 98 | > | ||
| 99 | > When the both the attribute and DW_CC_nocall are both omitted, | ||
| 100 | > the subprogram is assumed to comply with ABI calling | ||
| 101 | > conventions. | ||
| 102 | > | ||
| 103 | > [end non-normative] | ||
| 104 | |||
| 105 | _Notes:_ | ||
| 106 | |||
| 107 | - should this attribute get a new name other than `DW_AT_location` or | ||
| 108 | stick with that since it goes with `DW_AT_type`? | ||
| 109 | |||
| 110 | - Since `DW_AT_location` is useless with out `DW_AT_type` I made | ||
| 111 | `DW_AT_type` a predicate. Should it instead be non-normative text? | ||
| 112 | |||
| 113 | - Is my assumption that the `DW_AT_location` can only be for a Single | ||
| 114 | Location (i.e., not a location list) correct? | ||
| 115 | |||
| 116 | - If a subprogram were to be included in multiple objects then, | ||
| 117 | presumably, each would define its own `DW_AT_location`. | ||
| 118 | |||
| 119 | - This is a technical violation of: | ||
| 120 | |||
| 121 | _Single location descriptions_, [...]. They are sufficient for | ||
| 122 | describing the location of any object as long as its lifetime is | ||
| 123 | either static or the same as the lexical block that owns it, [...] | ||
| 124 | |||
| 125 | ### Call Sites | ||
| 126 | |||
| 127 | In 3.4.2 Call Site Parameters, | ||
| 128 | change the section title to: | ||
| 129 | 129 | ||
| 130 | > 3.4.2 Call Site Parameters and Return Value | 130 | Add the paragraph and non-normative text: | 
| 131 | |||
| 132 | > A subroutine or entry point that is a function that returns a value | ||
| 133 | > and has a `DW_AT_type` attribute may also have a | ||
| 134 | > `DW_AT_result_location` attribute. This attribute specifies the | ||
| 135 | > location of the return value after the called function has returned | ||
| 136 | > and the calling subprogram is about to be resumed. | ||
| 131 | 137 | ||
| 132 | (or a new section?) | 138 | > _Since the called subprogram has returned, the location description | 
| 139 | > is relative to the calling subprogram. For instance, for a sliding | ||
| 140 | > window architecture such as SPARC, the location description refers | ||
| 141 | > to the output registers of the caller, and not the input registers | ||
| 142 | > of the callee._ | ||
| 133 | 143 | ||
| 134 | At the end of the section add the text: | 144 | > _When the both the attribute `DW_AT_result_location` and | 
| 145 | > `DW_CC_nocall` are both omitted, the subprogram is assumed to comply | ||
| 146 | > with ABI calling conventions._ | ||
| 135 | 147 | ||
| 136 | > A call site entry that has a `DW_AT_type` attribute for the type | 148 | |
| 137 | > of the called function, may have a `DW_AT_location` attribute | 149 | ### Call Site Entries and Parameters | 
| 150 | |||
| 151 | In 3.4 Call Site Entries and Parameters, change the section title to: | ||
| 152 | |||
| 153 | > 3.4 Call Site Entries, Parameters, and Return Value | ||
| 154 | |||
| 155 | Change the opening non-normative paragraph from: | ||
| 156 | |||
| 157 | > _A call site entry describes a call from one subprogram to another | ||
| 158 | > in the source program. It provides information about the actual | ||
| 159 | > parameters of the call so that they may be more easily accessed by a | ||
| 160 | > debugger. When used together with call frame information (see | ||
| 161 | > Section 6.4 on page 178), call site entries can be useful for | ||
| 162 | > computing the value of an actual parameter passed by a caller, even | ||
| 163 | > when the location description for the callee’s corresponding formal | ||
| 164 | > parameter does not provide a current location for the formal | ||
| 165 | > parameter._ | ||
| 166 | |||
| 167 | to: | ||
| 168 | |||
| 169 | > _A call site entry describes a call from one subprogram to another | ||
| 170 | > in the source program. It provides information about both the | ||
| 171 | > actual parameters of the call, and the location of the return value | ||
| 172 | > after the subprogram returns, so that they may be more easily | ||
| 173 | > accessed by a debugger. Independent of the location description of | ||
| 174 | > the callee’s corresponding formal parameters and | ||
| 175 | > `DW_AT_result_location` attribute, the Call Site entry can be used | ||
| 176 | > together with call frame information (see Section 6.4 on page 178) | ||
| 177 | > to compute the value of an actual parameter passed by a caller and | ||
| 178 | > the return value after the callee returns. | ||
| 179 | |||
| 180 | In 3.4.2 Call Site Parameters, change the section title to: | ||
| 181 | |||
| 182 | > 3.4.2 Call Site Parameters and Return Value | ||
| 183 | |||
| 184 | At the end of the section add the paragraph and non-normative text: | ||
| 185 | |||
| 186 | > A call site entry that has a `DW_AT_type` attribute for the type of | ||
| 187 | > the called function, may have a `DW_AT_result_location` attribute | ||
| 138 | > specifying the location of the return value after the called | 188 | > specifying the location of the return value after the called | 
| 139 | > function has returned and the calling subprogram is about to | 189 | > function has returned and the calling subprogram is about to be | 
| 140 | > be resumed. | 190 | > resumed. | 
| 141 | > | 191 | |
| 142 | > [non-normative] | 192 | > _Since the function described by the Call Site Entry's `DW_AT_type` | 
| 143 | > _Since Call Site Entry's `DW_AT_type` attribute can describe an | 193 | > attribute can be abstract, the return type and location may be | 
| 144 | > abstract function, the return type and location may be | ||
| 145 | > different between the Call Site and the subprogram._ | 194 | > different between the Call Site and the subprogram._ | 
| 146 | 195 | ||
| 196 | |||
| 147 | ### Inlined Subprograms | 197 | ### Inlined Subprograms | 
| 148 | 198 | ||
| 149 | In 3.3.8.1 Abstract Instances, | 199 | In 3.3.8.1 Abstract Instances | 
| 150 | in the non-normative text: | 200 | |
| 201 | Change the non-normative text: | ||
| 151 | 202 | ||
| 152 | > For example, the `DW_AT_low_pc`, [...] attributes typically | 203 | > _For example, the `DW_AT_low_pc`, `DW_AT_high_pc`, `DW_AT_ranges`, | 
| 153 | > should be omitted; | 204 | > `DW_AT_entry_pc`, `DW_AT_location`, `DW_AT_return_addr` and | 
| 205 | > `DW_AT_start_scope` attributes typically should be omitted; however, | ||
| 206 | > this list is not exhaustive._ | ||
| 154 | 207 | ||
| 155 | add `DW_AT_location`. | 208 | to: | 
| 156 | 209 | ||
| 157 | In 3.3.8.2 Concrete Instances, | 210 | > _For example, the `DW_AT_low_pc`, `DW_AT_high_pc`, `DW_AT_ranges`, | 
| 158 | following the paragraph: | 211 | > `DW_AT_entry_pc`, `DW_AT_location`, `DW_AT_return_addr`, | 
| 212 | > `DW_AT_result_location`, and `DW_AT_start_scope` attributes typically | ||
| 213 | > should be omitted; however, this list is not exhaustive._ | ||
| 214 | |||
| 215 | (i.e, add `DW_AT_result_location`) | ||
| 216 | |||
| 217 | In 3.3.8.2 Concrete Instances, following the paragraph: | ||
| 159 | 218 | ||
| 160 | > An inlined subroutine entry may have a `DW_AT_const_expr` | 219 | > An inlined subroutine entry may have a `DW_AT_const_expr` | 
| 161 | > attribute, [...], represented as it would be on the target | 220 | > attribute, [...], represented as it would be on the target | 
| 162 | > architecture. | 221 | > architecture. .... | 
| 163 | 222 | ||
| 164 | Add the paragraph and non-normative text: | 223 | Add the paragraph and non-normative text: | 
| 165 | 224 | ||
| 166 | > An inlined subroutine entry that is a function that returns a | 225 | > An inlined subroutine entry that is a function that returns a | 
| 167 | > value and and has `DW_AT_type` defined in the Abstract Instance | 226 | > value and and has `DW_AT_type` defined in the Abstract Instance | 
| 168 | > may have a `DW_AT_location` attribute. This attribute | 227 | > may have a `DW_AT_result_location` attribute. This attribute | 
| 169 | > describes the location of the return value immediately after | 228 | > describes the location of the return value immediately after | 
| 170 | > the concrete instance has completed execution of the contiguous | 229 | > the concrete instance has completed execution of the contiguous | 
| 171 | > or non-contiguous machine instructions generated for the | 230 | > or non-contiguous machine instructions generated for the | 
| 172 | > inlined subroutine. | 231 | > inlined subroutine. | 
| 173 | > | 232 | |
| 174 | > [non-normative] | ||
| 175 | > _Since the concrete instance may consist of non-contiguous | 233 | > _Since the concrete instance may consist of non-contiguous | 
| 176 | > instructions, `DW_AT_location` may be defined using a Location | 234 | > instructions, `DW_AT_result_location` may be defined using a Location | 
| 177 | > List. Within that list, each bounded entry identifies an | 235 | > List. Within that list, each bounded entry identifies an | 
| 178 | > instruction immediately after the concrete instance has | 236 | > instruction immediately after the concrete instance has | 
| 179 | > completed execution. That list of locations may not be | 237 | > completed execution. That list of locations may not be | 
| 180 | > exhaustive._ | 238 | > exhaustive._ | 
| 181 | 239 | ||
| 182 | _Notes:_ | ||
| 183 | |||
| 184 | - Since `DW_AT_location` is useless with out `DW_AT_type` I made | ||
| 185 | `DW_AT_type` a predicate. Should it instead be non-normative text? | ||
| 186 | 240 | ||
| 187 | ### Appendix A. Attributes by Tag (Informative) | 241 | ### Appendix A. Attributes by Tag (Informative) | 
| 188 | 242 | ||
| 189 | Under TAG name `DW_TAG_subprogram`, add `DW_AT_location` to the | 243 | Add `DW_AT_result_location` to: | 
| 190 | applicable attributes. | ||
| 191 | 244 | ||
| 192 | ### Appendix D | 245 | - `DW_TAG_subprogram` | 
| 246 | - `DW_TAG_call_site` | ||
| 247 | - `DW_TAG_inlined_subroute | ||
| 193 | 248 | ||
| 194 | _Questions:_ | 249 | ### Appendix D | 
| 195 | 250 | ||
| 196 | - do we want to attempt an example? | 251 | [Example TBD] | 
| 197 | 252 | ||
| 198 | --- | 253 | --- | 
| 199 | 254 | ||
| 200 | 2023-11-05: Rewrote. | 255 | 2022-11-05: [Original proposal][orig]. | 
| 201 | 256 | ||
| 202 | 2024-01-08: Revised with more non-normative text. | 257 | 2023-11-05: [Rewrote][diff1]. | 
| 203 | 258 | ||
| 204 | 2024-02-05: Added section on call sites. | 259 | 2024-01-08: [Revised][diff2] with more non-normative text. | 
| 205 | 260 | ||
| 206 | 2024-03-04: Revised to add ABI fallback and address questions about call sites. | 261 | 2024-02-05: [Added section on call sites][diff3]. | 
| 262 | |||
| 263 | 2024-03-04: [Revised][diff4] to add ABI fallback and address questions about call sites. | ||
| 207 | 264 | ||
| 208 | 2024-04-29: Needs revision to use `DW_AT_result_location`. | 265 | 2024-04-29: Needs revision to use `DW_AT_result_location`. | 
| 266 | |||
| 267 | 2024-12-09: [Revised][diff5]. | ||
