| # Allow Location Descriptions on the DWARF Expression Stack <!-- omit in toc --> |
| |
| ```{contents} |
| --- |
| local: |
| --- |
| ``` |
| |
| # 1. Extension |
| |
| In DWARF 5, expressions are evaluated using a typed value stack, a separate |
| location area, and an independent loclist mechanism. This extension unifies all |
| three mechanisms into a single generalized DWARF expression evaluation model |
| that allows both typed values and location descriptions to be manipulated on the |
| evaluation stack. Both single and multiple location descriptions are supported |
| on the stack. In addition, the call frame information (CFI) is extended to |
| support the full generality of location descriptions. This is done in a manner |
| that is backwards compatible with DWARF 5. The extension involves changes to the |
| DWARF 5 sections 2.5 (pp 26-38), 2.6 (pp 38-45), and 6.4 (pp 171-182). |
| |
| The extension permits operations to act on location descriptions in an |
| incremental, consistent, and composable manner. It allows a small number of |
| operations to be defined to address the requirements of heterogeneous devices as |
| well as providing benefits to non-heterogeneous devices. It acts as a foundation |
| to provide support for other issues that have been raised that would benefit all |
| devices. |
| |
| Other approaches were explored that involved adding specialized operations and |
| rules. However, these resulted in the need for more operations that did not |
| compose. It also resulted in operations with context sensitive semantics and |
| corner cases that had to be defined. The observation was that numerous |
| specialized context sensitive operations are harder for both producers and |
| consumers than a smaller number of general composable operations that have |
| consistent semantics regardless of context. |
| |
| First, section [2. Heterogeneous Computing Devices](#heterogeneous-computing-devices) |
| describes heterogeneous devices and the features they have that are not addressed by DWARF 5. |
| Then section [3. DWARF5](#dwarf-5) presents a brief simplified overview of the DWARF 5 expression |
| evaluation model that highlights the difficulties for supporting the |
| heterogeneous features. Next, section [4. Extension |
| Solution](#extension-solution) provides an overview of the proposal, using |
| simplified examples to illustrate how it can address the issues of heterogeneous |
| devices and also benefit non-heterogeneous devices. Then overall conclusions are |
| covered in section [5. Conclusion](#conclusion). |
| Appendix [A. Changes to DWARF Debugging Information Format Version 5](#changes-to-dwarf-debugging-information-format-version-5) gives changes |
| relative to the DWARF Version 5 standard. Finally, appendix |
| [B. Further Information](#further-information) has references to further information. |
| |
| # 2. Heterogeneous Computing Devices |
| |
| GPUs and other heterogeneous computing devices have features not common to CPU |
| computing devices. |
| |
| These devices often have many more registers than a CPU. This helps reduce |
| memory accesses which tend to be more expensive than on a CPU due to the much |
| larger number of threads concurrently executing. In addition to traditional |
| scalar registers of a CPU, these devices often have many wide vector registers. |
| |
|  |
| |
| They may support masked vector instructions that are used by the compiler to map |
| high level language threads onto the lanes of the vector registers. As a |
| consequence, multiple language threads execute in lockstep as the vector |
| instructions are executed. This is termed single instruction multiple thread |
| (SIMT) execution. |
| |
|  |
| |
| GPUs can have multiple memory address spaces in addition to the single global |
| memory address space of a CPU. These additional address spaces are accessed |
| using distinct instructions and are often local to a particular thread or group |
| of threads. |
| |
| For example, a GPU may have a per thread block address space that is implemented |
| as scratch pad memory with explicit hardware support to isolate portions to |
| specific groups of threads created as a single thread block. |
| |
| A GPU may also use global memory in a non linear manner. For example, to support |
| providing a SIMT per lane address space efficiently, there may be instructions |
| that support interleaved access. |
| |
| Through optimization, the source variables may be located across these different |
| storage kinds. SIMT execution requires locations to be able to express selection |
| of runtime defined pieces of vector registers. With the more complex locations, |
| there is a benefit to be able to factorize their calculation which requires all |
| location kinds to be supported uniformly, otherwise duplication is necessary. |
| |
| # 3. DWARF 5 |
| |
| Before presenting the proposed solution to supporting heterogeneous devices, a |
| brief overview of the DWARF 5 expression evaluation model will be given to |
| highlight the aspects being addressed by the extension. |
| |
| ## 3.1 How DWARF Maps Source Language To Hardware |
| |
| DWARF is a standardized way to specify debug information. It describes source |
| language entities such as compilation units, functions, types, variables, etc. |
| It is either embedded directly in sections of the code object executables, or |
| split into separate files that they reference. |
| |
| DWARF maps between source program language entities and their hardware |
| representations. For example: |
| |
| - It maps a hardware instruction program counter to a source language program |
| line, and vice versa. |
| - It maps a source language function to the hardware instruction program counter |
| for its entry point. |
| - It maps a source language variable to its hardware location when at a |
| particular program counter. |
| - It provides information to allow virtual unwinding of hardware registers for a |
| source language function call stack. |
| - In addition, it provides numerous other information about the source language |
| program. |
| |
| In particular, there is great diversity in the way a source language entity |
| could be mapped to a hardware location. The location may involve runtime values. |
| For example, a source language variable location could be: |
| |
| - In register. |
| - At a memory address. |
| - At an offset from the current stack pointer. |
| - Optimized away, but with a known compiler time value. |
| - Optimized away, but with an unknown value, such as happens for unused |
| variables. |
| - Spread across combination of the above kinds of locations. |
| - At a memory address, but also transiently loaded into registers. |
| |
| To support this DWARF 5 defines a rich expression language comprised of loclist |
| expressions and operation expressions. Loclist expressions allow the result to |
| vary depending on the PC. Operation expressions are made up of a list of |
| operations that are evaluated on a simple stack machine. |
| |
| A DWARF expression can be used as the value of different attributes of different |
| debug information entries (DIE). A DWARF expression can also be used as an |
| argument to call frame information information (CFI) entry operations. An |
| expression is evaluated in a context dictated by where it is used. The context |
| may include: |
| |
| - Whether the expression needs to produce a value or the location of an entity. |
| - The current execution point including process, thread, PC, and stack frame. |
| - Some expressions are evaluated with the stack initialized with a specific |
| value or with the location of a base object that is available using the |
| DW_OP_push_object_address operation. |
| |
| ## 3.2 Examples |
| |
| The following examples illustrate how DWARF expressions involving operations are |
| evaluated in DWARF 5. DWARF also has expressions involving location lists that |
| are not covered in these examples. |
| |
| ### 3.2.1 Dynamic Array Size |
| |
| The first example is for an operation expression associated with a DIE attribute |
| that provides the number of elements in a dynamic array type. Such an attribute |
| dictates that the expression must be evaluated in the context of providing a |
| value result kind. |
| |
|  |
| |
| In this hypothetical example, the compiler has allocated an array descriptor in |
| memory and placed the descriptor's address in architecture register SGPR0. The |
| first location of the array descriptor is the runtime size of the array. |
| |
| A possible expression to retrieve the dynamic size of the array is: |
| |
| DW_OP_regval_type SGPR0 Generic |
| DW_OP_deref |
| |
| The expression is evaluated one operation at a time. Operations have operands |
| and can pop and push entries on a stack. |
| |
|  |
| |
| The expression evaluation starts with the first DW_OP_regval_type operation. |
| This operation reads the current value of an architecture register specified by |
| its first operand: SGPR0. The second operand specifies the size of the data to |
| read. The read value is pushed on the stack. Each stack element is a value and |
| its associated type. |
| |
|  |
| |
| The type must be a DWARF base type. It specifies the encoding, byte ordering, |
| and size of values of the type. DWARF defines that each architecture has a |
| default generic type: it is an architecture specific integral encoding and byte |
| ordering, that is the size of the architecture's global memory address. |
| |
| The DW_OP_deref operation pops a value off the stack, treats it as a global |
| memory address, and reads the contents of that location using the generic type. |
| It pushes the read value on the stack as the value and its associated generic |
| type. |
| |
|  |
| |
| The evaluation stops when it reaches the end of the expression. The result of an |
| expression that is evaluated with a value result kind context is the top element |
| of the stack, which provides the value and its type. |
| |
| ### 3.2.2 Variable Location in Register |
| |
| This example is for an operation expression associated with a DIE attribute that |
| provides the location of a source language variable. Such an attribute dictates |
| that the expression must be evaluated in the context of providing a location |
| result kind. |
| |
| DWARF defines the locations of objects in terms of location descriptions. |
| |
| In this example, the compiler has allocated a source language variable in |
| architecture register SGPR0. |
| |
|  |
| |
| A possible expression to specify the location of the variable is: |
| |
| DW_OP_regx SGPR0 |
| |
|  |
| |
| The DW_OP_regx operation creates a location description that specifies the |
| location of the architecture register specified by the operand: SGPR0. Unlike |
| values, location descriptions are not pushed on the stack. Instead they are |
| conceptually placed in a location area. Unlike values, location descriptions do |
| not have an associated type, they only denote the location of the base of the |
| object. |
| |
|  |
| |
| Again, evaluation stops when it reaches the end of the expression. The result of |
| an expression that is evaluated with a location result kind context is the |
| location description in the location area. |
| |
| ### 3.2.3 Variable Location in Memory |
| |
| The next example is for an operation expression associated with a DIE attribute |
| that provides the location of a source language variable that is allocated in a |
| stack frame. The compiler has placed the stack frame pointer in architecture |
| register SGPR0, and allocated the variable at offset 0x10 from the stack frame |
| base. The stack frames are allocated in global memory, so SGPR0 contains a |
| global memory address. |
| |
|  |
| |
| A possible expression to specify the location of the variable is: |
| |
| DW_OP_regval_type SGPR0 Generic |
| DW_OP_plus_uconst 0x10 |
| |
|  |
| |
| As in the previous example, the DW_OP_regval_type operation pushes the stack |
| frame pointer global memory address onto the stack. The generic type is the size |
| of a global memory address. |
| |
|  |
| |
| The DW_OP_plus_uconst operation pops a value from the stack, which must have a |
| type with an integral encoding, adds the value of its operand, and pushes the |
| result back on the stack with the same associated type. In this example, that |
| computes the global memory address of the source language variable. |
| |
|  |
| |
| Evaluation stops when it reaches the end of the expression. If the expression |
| that is evaluated has a location result kind context, and the location area is |
| empty, then the top stack element must be a value with the generic type. The |
| value is implicitly popped from the stack, and treated as a global memory |
| address to create a global memory location description, which is placed in the |
| location area. The result of the expression is the location description in the |
| location area. |
| |
|  |
| |
| ### 3.2.4 Variable Spread Across Different Locations |
| |
| This example is for a source variable that is partly in a register, partly undefined, and partly in memory. |
| |
|  |
| |
| DWARF defines composite location descriptions that can have one or more parts. |
| Each part specifies a location description and the number of bytes used from it. |
| The following operation expression creates a composite location description. |
| |
| DW_OP_regx SGPR3 |
| DW_OP_piece 4 |
| DW_OP_piece 2 |
| DW_OP_bregx SGPR0 0x10 |
| DW_OP_piece 2 |
| |
|  |
| |
| The DW_OP_regx operation creates a register location description in the location |
| area. |
| |
|  |
| |
| The first DW_OP_piece operation creates an incomplete composite location |
| description in the location area with a single part. The location description in |
| the location area is used to define the beginning of the part for the size |
| specified by the operand, namely 4 bytes. |
| |
|  |
| |
| A subsequent DW_OP_piece adds a new part to an incomplete composite location |
| description already in the location area. The parts form a contiguous set of |
| bytes. If there are no other location descriptions in the location area, and no |
| value on the stack, then the part implicitly uses the undefined location |
| description. Again, the operand specifies the size of the part in bytes. The |
| undefined location description can be used to indicate a part that has been |
| optimized away. In this case, 2 bytes of undefined value. |
| |
|  |
| |
| The DW_OP_bregx operation reads the architecture register specified by the first |
| operand (SGPR0) as the generic type, adds the value of the second operand |
| (0x10), and pushes the value on the stack. |
| |
|  |
| |
| The next DW_OP_piece operation adds another part to the already created |
| incomplete composite location. |
| |
| If there is no other location in the location area, but there is a value on |
| stack, the new part is a memory location description. The memory address used is |
| popped from the stack. In this case, the operand of 2 indicates there are 2 |
| bytes from memory. |
| |
|  |
| |
| Evaluation stops when it reaches the end of the expression. If the expression |
| that is evaluated has a location result kind context, and the location area has |
| an incomplete composite location description, the incomplete composite location |
| is implicitly converted to a complete composite location description. The result |
| of the expression is the location description in the location area. |
| |
|  |
| |
| ### 3.2.5 Offsetting a Composite Location |
| |
| This example attempts to extend the previous example to offset the composite |
| location description it created. The [3.2.3 Variable Location in |
| Memory](#variable-location-in-memory) example conveniently used the DW_OP_plus |
| operation to offset a memory address. |
| |
| DW_OP_regx SGPR3 |
| DW_OP_piece 4 |
| DW_OP_piece 2 |
| DW_OP_bregx SGPR0 0x10 |
| DW_OP_piece 2 |
| DW_OP_plus_uconst 5 |
| |
|  |
| |
| However, DW_OP_plus cannot be used to offset a composite location. It only |
| operates on the stack. |
| |
|  |
| |
| To offset a composite location description, the compiler would need to make a |
| different composite location description, starting at the part corresponding to |
| the offset. For example: |
| |
| DW_OP_piece 1 |
| DW_OP_bregx SGPR0 0x10 |
| DW_OP_piece 2 |
| |
| This illustrates that operations on stack values are not composable with |
| operations on location descriptions. |
| |
| ### 3.2.6 Pointer to Member |
| |
| > NOTE: Without loss of generality, DWARF 4 is used in this example as full |
| > support for DWARF 5 is not present in the versions of the tools used. No |
| > feature of DWARF 5 provides a remedy for this issue. |
| |
| This example highlights the inability of DWARF 5 to describe C++ |
| pointer-to-member use semantics. |
| |
| The mechanism DWARF 5 provides for describing pointer-to-member use is |
| `DW_AT_use_location`, which is defined as encoding a location description which |
| computes the address of the member pointed to by a pointer-to-member, given the |
| pointer-to-member object and the address of the containing object. |
| |
| That is, when a debug agent wishes to evaluate a pointer-to-member access |
| operation, it first pushes two values onto the DWARF expression stack: |
| |
| * The pointer-to-member object |
| * The address of the containing object |
| |
| It then evaluates the location description associated with the |
| `DW_AT_use_location` of the pointer-to-member type, and interprets the result |
| as the address of the member pointed to by the pointer-to-member. |
| |
| Consider the following C++ source file `s.cc`: |
| |
| ```cpp |
| struct s { |
| int m; |
| int n; |
| }; |
| int s::* p; |
| ``` |
| |
| When compiled with GCC and inspected with dwarfdump: |
| |
| ``` |
| $ g++ -gdwarf-5 -O3 -c s.cc |
| $ dwarfdump s.o |
| < 1><0x0000001e> DW_TAG_structure_type |
| DW_AT_name s |
| DW_AT_byte_size 0x00000008 |
| DW_AT_sibling <0x0000003c> |
| < 2><0x00000029> DW_TAG_member |
| DW_AT_name m |
| DW_AT_type <0x0000003c> |
| DW_AT_data_member_location 0 |
| < 2><0x00000032> DW_TAG_member |
| DW_AT_name n |
| DW_AT_type <0x0000003c> |
| DW_AT_data_member_location 4 |
| < 1><0x0000003c> DW_TAG_base_type |
| DW_AT_byte_size 0x00000004 |
| DW_AT_encoding DW_ATE_signed |
| DW_AT_name int |
| < 1><0x00000043> DW_TAG_ptr_to_member_type |
| DW_AT_containing_type <0x0000001e> |
| DW_AT_type <0x0000003c> |
| DW_AT_use_location len 0x0001: 22: DW_OP_plus |
| < 1><0x0000004e> DW_TAG_variable |
| DW_AT_name p |
| DW_AT_type <0x00000043> |
| DW_AT_external yes(1) |
| DW_AT_location len 0x0009: 030000000000000000: DW_OP_addr 0x00000000 |
| ``` |
| |
| Note the location description for `DW_AT_use_location` is `DW_OP_plus`, which |
| reflects the GCC implementation of the pointer-to-member as an integral byte |
| offset within the containing object. For example, the value of `&s::m` in this |
| implementation is `offsetof(s, m)` and the value of `&s::n` is `offsetof(s, n)`: |
| |
| ```cpp |
| struct s { |
| int m; // offsetof(s, m) == 0 |
| int n; // offsetof(s, n) == 4 |
| } o; // &o == 0xff00 |
| int s::* p; |
| int *i; |
| |
| p = &s::m; // p == 0 |
| i = &(o.*p); // i == 0xff00 + 0 |
| p = &s::n; // p == 4 |
| i = &(o.*p); // i == 0xff00 + 4 |
| ``` |
| |
| The expression `DW_OP_plus` accurately describes this implementation so long as |
| the entire containing object resides in memory in the default address space. |
| |
| However, what if the containing object or the member pointed to are not at any |
| default address space address? |
| |
| The compiler may store the containing object in memory in any address space, |
| in a register, recompute its value at each use, or compose any of these in |
| arbitrary ways. |
| |
| The richness of the existing DWARF 5 expression language is a reflection of the |
| diversity of possible implementation strategies and optimization choices |
| affecting the location of an object in a program, and (modulo address spaces) |
| it can describe all of these locations for variables. However, the moment we |
| look at a pointer-to-member use we are restricted to only objects residing in a |
| contiguous piece of memory in the default address space. |
| |
| To demonstrate the problem, consider a program which GCC chooses to optimize in |
| such a way that the containing object is not in memory at all: |
| |
| ptm.h: |
| ```cpp |
| struct s { |
| int m; |
| int n; |
| }; |
| void i(int); |
| extern int t; |
| void f(s x, int s::* p); |
| ``` |
| |
| ptm.cc: |
| ```cpp |
| #include "ptm.h" |
| void f(s x, int s::* p) { |
| for (int a = 0; a < t; ++a) { |
| x.m += a + x.n; |
| i(x.*p); |
| } |
| } |
| ``` |
| |
| main.cc: |
| ```cpp |
| #include "ptm.h" |
| int t = 100; |
| void i(int) {} |
| int main(int argc, char *argv[]) { |
| s x = { 0, 1 }; |
| f(x, &s::m); |
| } |
| ``` |
| |
| When compiled and run under GDB: |
| |
| ``` |
| $ g++-9 -gdwarf-4 -O3 -c main.cc -o main.o |
| $ g++-9 -gdwarf-4 -O3 -c ptm.cc -o ptm.o |
| $ g++-9 main.o ptm.o -o use_location.out |
| $ gdb ./use_location.out |
| (gdb) maint set dwarf always-disassemble |
| (gdb) b ptm.cc:5 |
| Breakpoint 1 at 0x119e: file ptm.cc, line 5. |
| (gdb) r |
| |
| Breakpoint 1, f (x=..., p=<optimized out>) at ptm.cc:5 |
| 5 i(x.*p); |
| ``` |
| |
| Note that the compiler has promoted the entire object `x` into register `rdi` |
| for the body of the loop: |
| |
| ``` |
| (gdb) info addr x |
| Symbol "x" is multi-location: |
| Range 0x555555555160-0x5555555551af: a complex DWARF expression: |
| 0: DW_OP_reg5 [$rdi] |
| |
| Range 0x5555555551af-0x5555555551ba: a complex DWARF expression: |
| 0: DW_OP_fbreg -56 |
| |
| . |
| (gdb) p $pc |
| $1 = (void (*)(void)) 0x55555555519e <f(s, int s::*)+62> |
| ``` |
| |
| And so it is impossible to interpret `DW_OP_use_location` in this case: |
| |
| ``` |
| (gdb) p x.*p |
| Address requested for identifier "x" which is in register $rdi |
| ``` |
| |
| With location descriptions on the stack, the definition of `DW_OP_use_location` |
| can be modified by replacing every instance of "address" with "location |
| description", as is described in [Type Entries](#type-entries). |
| |
| To implement the fully generalized version of this attribute, GCC would only |
| need to change the expression from `DW_OP_plus` to `DW_OP_swap, |
| DW_OP_LLVM_offset`. |
| |
| ### 3.2.7 Virtual Base Class |
| |
| > NOTE: Without loss of generality, DWARF 4 is used in this example as full |
| > support for DWARF 5 is not present in the versions of the tools used. No |
| > feature of DWARF 5 provides a remedy for this issue. |
| |
| This example highlights the inability of DWARF 5 to describe C++ |
| virtual inheritance semantics. |
| |
| The mechanism DWARF 5 provides for describing the location of an inherited |
| subobject is `DW_AT_data_member_location`. This attribute is overloaded to |
| describe both data member locations and inherited subobject locations, and |
| in each case has multiple possible forms: |
| |
| * If an integral constant form, it encodes the byte offset from the derived |
| object to the data member or subobject. |
| * Otherwise, it encodes a location description to compute the address of the |
| data member or subobject given the address of the derived object. |
| |
| Only the attribute describing a subobject, and only the location description |
| form are considered here. |
| |
| In this case, when a debug agent wishes to locate the subobject, it first |
| pushes the address of the derived object onto the DWARF expression stack. It |
| then evaluates the location description associated with the |
| `DW_AT_data_member_location` of the `DW_TAG_inheritence` DIE corresponding to |
| the inherited subobject. |
| |
| Consider the following C++ source file `ab.cc`: |
| |
| ```cpp |
| class A { |
| public: |
| char x; |
| }; |
| class B |
| : public virtual A {} o; |
| ``` |
| |
| When compiled with GCC and inspected with dwarfdump: |
| |
| ``` |
| $ g++ -gdwarf-5 -O3 -c ab.cc |
| $ dwarfdump ab.o |
| < 1><0x0000002a> DW_TAG_class_type |
| DW_AT_name A |
| DW_AT_byte_size 0x00000001 |
| DW_AT_sibling <0x00000042> |
| < 1><0x00000049> DW_TAG_class_type |
| DW_AT_name B |
| DW_AT_byte_size 0x00000010 |
| DW_AT_containing_type <0x00000049> |
| DW_AT_sibling <0x000000f9> |
| < 2><0x00000058> DW_TAG_inheritance |
| DW_AT_type <0x0000002a> |
| DW_AT_data_member_location len 0x0006: 1206481c0622: |
| DW_OP_dup DW_OP_deref DW_OP_lit24 DW_OP_minus DW_OP_deref DW_OP_plus |
| DW_AT_virtuality DW_VIRTUALITY_virtual |
| DW_AT_accessibility DW_ACCESS_public |
| ``` |
| |
| This `DW_AT_data_member_location` expression describes the dynamic process of |
| locating the `A`-in-`B` subobject according to the [Itanium |
| ABI](https://refspecs.linuxfoundation.org/cxxabi-1.86.html#layout). A diagram |
| of the logical layout of class `B` is: |
| |
| ``` |
| 0: class B |
| 0: vptr B |
| 8: class A |
| 8: A::x |
| ``` |
| |
| That is, the address of an object of class `B` is equivalent to the address for |
| the `vtable` pointer for `B`. As there are no other direct data members of `B` |
| the primary base class subobject of class `A` comes next, and there is no |
| intervening padding as the subobject alignment requirements are already |
| satisfied. |
| |
| The `vtable` pointer for `B` contains an entry `vbase_offset` for each virtual |
| base class. In this case, that table layout is: |
| |
| ``` |
| -24: vbase_offset[A]=8 |
| -16: offset_to_top=0 |
| -8: B RTTI |
| 0: <vtable for B> |
| ``` |
| |
| That is, to find the `vbase_offset` for the `A`-in-`B` subobject the address |
| `vptr B` is offset by the statically determined value `-24`. |
| |
| Thus, in order to implement `DW_AT_data_member_location` for `A`-in-`B`, the |
| expression needs to index to a statically known byte offset of `-24` through |
| `vptr B` to lookup `vbase_offset` for `A`-in-`B`. It must then offset the |
| location of `B` by the dynamic value of `vbase_offset` (in this case `8`) to |
| arrive at the location of the inherited subobject. |
| |
| This definition shares the same problem as example [3.2.6](#pointer-to-member) |
| in that it relies on the address of the derived object and inherited subobject, |
| when there is no guarantee either or both have any address at all. |
| |
| To demonstrate the problem, consider a program which GCC chooses to optimize in |
| such a way that the derived object is not in memory at all: |
| |
| f.h: |
| ```cpp |
| class A { |
| public: |
| char x; |
| }; |
| class B |
| : public virtual A {}; |
| void f(B b); |
| ``` |
| |
| f.cc: |
| ```cpp |
| #include "f.h" |
| void f(B b) {} |
| ``` |
| |
| main.cc: |
| ```cpp |
| #include "f.h" |
| int main(int argc, char *argv[]) { |
| B b; |
| b.x = 42; |
| f(b); |
| return b.x; |
| } |
| ``` |
| |
| When compiled and run under GDB: |
| |
| ``` |
| $ g++-9 -gdwarf-4 -O3 -c main.cc -o main.o |
| $ g++-9 -gdwarf-4 -O3 -c f.cc -o f.o |
| $ g++-9 main.o f.o -o cpp-vbase.out |
| (gdb) maint set dwarf always-disassemble |
| (gdb) b main.cc:6 |
| Breakpoint 1 at 0x1090: file main.cc, line 6. |
| (gdb) r |
| |
| Breakpoint 1, main (argc=<optimized out>, argv=<optimized out>) at main.cc:6 |
| 6 return b.x; |
| ``` |
| |
| Note that the compiler has elided storage for the entire object `x` in the |
| body of `main()`: |
| |
| ``` |
| (gdb) info addr b |
| Symbol "b" is multi-location: |
| Range 0x555555555078-0x5555555550af: a complex DWARF expression: |
| 0: DW_OP_piece 8 (bytes) |
| 2: DW_OP_const1u 42 |
| 4: DW_OP_stack_value |
| 5: DW_OP_piece 1 (bytes) |
| 7: DW_OP_piece 7 (bytes) |
| |
| . |
| (gdb) p $pc |
| $1 = (void (*)(void)) 0x555555555090 <main(int, char**)+48> |
| ``` |
| |
| And so it is impossible to interpret `DW_OP_data_member_location` in this case: |
| |
| ``` |
| (gdb) p b |
| $2 = {<A> = <invalid address>, _vptr.B = <optimized out>} |
| ``` |
| |
| > NOTE: The `vptr B` which should occupy the first 8 bytes of the object `b` |
| > are undefined in the DWARF, but could be described as an implicit value by |
| > the compiler. This change would be trivial and would directly expose the |
| > issue in DWARF 5 described here. |
| |
| With location descriptions on the stack, the definition of |
| `DW_OP_data_member_location` can be modified by replacing every instance of |
| "address" with "location description", as is described in [A.5 Type Entries](#type-entries). |
| |
| To implement the fully generalized version of this attribute, GCC would only |
| need to change the last operation in the expression from `DW_OP_plus` to |
| `DW_OP_LLVM_offset`. |
| |
| ## 3.3 Limitations |
| |
| DWARF 5 is unable to describe variables in runtime indexed parts of registers. |
| This is required to describe a source variable that is located in a lane of a |
| SIMT vector register. |
| |
| Some features only work when located in global memory. The type attribute |
| expressions require a base object which could be in any kind of location. |
| |
| DWARF procedures can only accept global memory address arguments. This limits |
| the ability to factorize the creation of locations that involve other location |
| kinds. |
| |
| There are no vector base types. This is required to describe vector registers. |
| |
| There is no operation to create a memory location in a non-global address space. |
| Only the dereference operation supports providing an address space. |
| |
| CFI location expressions do not allow composite locations or non-global address |
| space memory locations. Both these are needed in optimized code for devices with |
| vector registers and address spaces. |
| |
| Bit field offsets are only supported in a limited way for register locations. |
| Supporting them in a uniform manner for all location kinds is required to |
| support languages with bit sized entities. |
| |
| # 4. Extension Solution |
| |
| This section outlines the extension to generalize the DWARF expression evaluation |
| model to allow location descriptions to be manipulated on the stack. It presents |
| a number of simplified examples to demonstrate the benefits and how the extension |
| solves the issues of heterogeneous devices. It presents how this is done in |
| a manner that is backwards compatible with DWARF 5. |
| |
| ## 4.1 Location Description |
| |
| In order to have consistent, composable operations that act on location |
| descriptions, the extension defines a uniform way to handle all location kinds. |
| That includes memory, register, implicit, implicit pointer, undefined, and |
| composite location descriptions. |
| |
| Each kind of location description is conceptually a zero-based offset within a |
| piece of storage. The storage is a contiguous linear organization of a certain |
| number of bytes (see below for how this is extended to support bit sized |
| storage). |
| |
| - For global memory, the storage is the linear stream of bytes of the |
| architecture's address size. |
| - For each separate architecture register, it is the linear stream of bytes of |
| the size of that specific register. |
| - For an implicit, it is the linear stream of bytes of the value when |
| represented using the value's base type which specifies the encoding, size, |
| and byte ordering. |
| - For undefined, it is an infinitely sized linear stream where every byte is |
| undefined. |
| - For composite, it is a linear stream of bytes defined by the composite's parts. |
| |
| ## 4.2 Stack Location Description Operations |
| |
| The DWARF expression stack is extended to allow each stack entry to either be a |
| value or a location description. |
| |
| Evaluation rules are defined to implicitly convert a stack element that is a |
| value to a location description, or vice versa, so that all DWARF 5 expressions |
| continue to have the same semantics. This reflects that a memory address is |
| effectively used as a proxy for a memory location description. |
| |
| For each place that allows a DWARF expression to be specified, it is defined if |
| the expression is to be evaluated as a value or a location description. |
| |
| Existing DWARF expression operations that are used to act on memory addresses |
| are generalized to act on any location description kind. For example, the |
| DW_OP_deref operation pops a location description rather than a memory address |
| value from the stack and reads the storage associated with the location kind |
| starting at the location description's offset. |
| |
| Existing DWARF expression operations that create location descriptions are |
| changed to pop and push location descriptions on the stack. For example, the |
| DW_OP_value, DW_OP_regx, DW_OP_implicit_value, DW_OP_implicit_pointer, |
| DW_OP_stack_value, and DW_OP_piece. |
| |
| New operations that act on location descriptions can be added. For example, a |
| DW_OP_offset operation that modifies the offset of the location description on |
| top of the stack. Unlike the DW_OP_plus operation that only works with memory |
| address, a DW_OP_offset operation can work with any location kind. |
| |
| To allow incremental and nested creation of composite location descriptions, a |
| DW_OP_piece_end can be defined to explicitly indicate the last part of a |
| composite. Currently, creating a composite must always be the last operation of |
| an expression. |
| |
| A DW_OP_undefined operation can be defined that explicitly creates the undefined |
| location description. Currently this is only possible as a piece of a composite |
| when the stack is empty. |
| |
| ## 4.3 Examples |
| |
| This section provides some motivating examples to illustrate the benefits that |
| result from allowing location descriptions on the stack. |
| |
| ### 4.3.1 Source Language Variable Spilled to Part of a Vector Register |
| |
| A compiler generating code for a GPU may allocate a source language variable |
| that it proves has the same value for every lane of a SIMT thread in a scalar |
| register. It may then need to spill that scalar register. To avoid the high cost |
| of spilling to memory, it may spill to a fixed lane of one of the numerous |
| vector registers. |
| |
|  |
| |
| The following expression defines the location of a source language variable that |
| the compiler allocated in a scalar register, but had to spill to lane 5 of a |
| vector register at this point of the code. |
| |
| DW_OP_regx VGPR0 |
| DW_OP_offset_uconst 20 |
| |
|  |
| |
| The DW_OP_regx pushes a register location description on the stack. The storage |
| for the register is the size of the vector register. The register location |
| description conceptually references that storage with an initial offset of 0. |
| The architecture defines the byte ordering of the register. |
| |
|  |
| |
| The DW_OP_offset_uconst pops a location description off the stack, adds its |
| operand value to the offset, and pushes the updated location description back on |
| the stack. In this case the source language variable is being spilled to lane 5 |
| and each lane's component which is 32-bits (4 bytes), so the offset is 5*4=20. |
| |
|  |
| |
| The result of the expression evaluation is the location description on the top |
| of the stack. |
| |
| An alternative approach could be for the target to define distinct register |
| names for each part of each vector register. However, this is not practical for |
| GPUs due to the sheer number of registers that would have to be defined. It |
| would also not permit a runtime index into part of the whole register to be used |
| as shown in the next example. |
| |
| ### 4.3.2 Source Language Variable Spread Across Multiple Vector Registers |
| |
| A compiler may generate SIMT code for a GPU. Each source language thread of |
| execution is mapped to a single lane of the GPU thread. Source language |
| variables that are mapped to a register, are mapped to the lane component of the |
| vector registers corresponding to the source language's thread of execution. |
| |
| The location expression for such variables must therefore be executed in the |
| context of the focused source language thread of execution. A DW_OP_push_lane |
| operation can be defined to push the value of the lane for the currently focused |
| source language thread of execution. The value to use would be provided by the |
| consumer of DWARF when it evaluates the location expression. |
| |
| If the source language variable is larger than the size of the vector register |
| lane component, then multiple vector registers are used. Each source language |
| thread of execution will only use the vector register components for its |
| associated lane. |
| |
|  |
| |
| The following expression defines the location of a source language variable that |
| has to occupy two vector registers. A composite location description is created |
| that combines the two parts. It will give the correct result regardless of which |
| lane corresponds to the source language thread of execution that the user is |
| focused on. |
| |
| DW_OP_regx VGPR0 |
| DW_OP_push_lane |
| DW_OP_uconst 4 |
| DW_OP_mul |
| DW_OP_offset |
| DW_OP_piece 4 |
| DW_OP_regx VGPR1 |
| DW_OP_push_lane |
| DW_OP_uconst 4 |
| DW_OP_mul |
| DW_OP_offset |
| DW_OP_piece 4 |
| |
|  |
| |
| The DW_OP_regx VGPR0 pushes a location description for the first register. |
| |
|  |
| |
| The DW_OP_push_lane; DW_OP_uconst 4; DW_OP_mul calculates the offset for the |
| focused lanes vector register component as 4 times the lane number. |
| |
|  |
| |
|  |
| |
|  |
| |
| The DW_OP_offset adjusts the register location description's offset to the |
| runtime computed value. |
| |
|  |
| |
| The DW_OP_piece either creates a new composite location description, or adds a |
| new part to an existing incomplete one. It pops the location description to use |
| for the new part. It then pops the next stack element if it is an incomplete |
| composite location description, otherwise it creates a new incomplete composite |
| location description with no parts. Finally it pushes the incomplete composite |
| after adding the new part. |
| |
| In this case a register location description is added to a new incomplete |
| composite location description. The 4 of the DW_OP_piece specifies the size of |
| the register storage that comprises the part. Note that the 4 bytes start at the |
| computed register offset. |
| |
| For backwards compatibility, if the stack is empty or the top stack element is |
| an incomplete composite, an undefined location description is used for the part. |
| If the top stack element is a generic base type value, then it is implicitly |
| converted to a global memory location description with an offset equal to the |
| value. |
| |
|  |
| |
| The rest of the expression does the same for VGPR1. However, when the |
| DW_OP_piece is evaluated there is an incomplete composite on the stack. So the |
| VGPR1 register location description is added as a second part. |
| |
|  |
| |
|  |
| |
|  |
| |
|  |
| |
|  |
| |
|  |
| |
| At the end of the expression, if the top stack element is an incomplete |
| composite location description, it is converted to a complete location |
| description and returned as the result. |
| |
|  |
| |
| ### 4.3.3 Source Language Variable Spread Across Multiple Kinds of Locations |
| |
| This example is the same as the previous one, except the first 2 bytes of the |
| second vector register have been spilled to memory, and the last 2 bytes have |
| been proven to be a constant and optimized away. |
| |
|  |
| |
| DW_OP_regx VGPR0 |
| DW_OP_push_lane |
| DW_OP_uconst 4 |
| DW_OP_mul |
| DW_OP_offset |
| DW_OP_piece 4 |
| DW_OP_addr 0xbeef |
| DW_OP_piece 2 |
| DW_OP_uconst 0xf00d |
| DW_OP_stack_value |
| DW_OP_piece 2 |
| DW_OP_piece_end |
| |
| The first 6 operations are the same. |
| |
|  |
| |
| The DW_OP_addr operation pushes a global memory location description on the |
| stack with an offset equal to the address. |
| |
|  |
| |
| The next DW_OP_piece adds the global memory location description as the next 2 |
| byte part of the composite. |
| |
|  |
| |
| The DW_OP_uconst 0xf00d; DW_OP_stack_value pushes an implicit location |
| description on the stack. The storage of the implicit location description is |
| the representation of the value 0xf00d using the generic base type's encoding, |
| size, and byte ordering. |
| |
|  |
| |
|  |
| |
| The final DW_OP_piece adds 2 bytes of the implicit location description as the |
| third part of the composite location description. |
| |
|  |
| |
| The DW_OP_piece_end operation explicitly makes the incomplete composite location |
| description into a complete location description. This allows a complete |
| composite location description to be created on the stack that can be used as |
| the location description of another following operation. For example, the |
| DW_OP_offset can be applied to it. More practically, it permits creation of |
| multiple composite location descriptions on the stack which can be used to pass |
| arguments to a DWARF procedure using a DW_OP_call* operation. This can be |
| beneficial to factor the incrementally creation of location descriptions. |
| |
|  |
| |
| ### 4.3.4 Address Spaces |
| |
| Heterogeneous devices can have multiple hardware supported address spaces which |
| use specific hardware instructions to access them. |
| |
| For example, GPUs that use SIMT execution may provide hardware support to access |
| memory such that each lane can see a linear memory view, while the backing |
| memory is actually being accessed in an interleaved manner so that the locations |
| for each lanes Nth dword are contiguous. This minimizes cache lines read by the |
| SIMT execution. |
| |
|  |
| |
| The following expression defines the location of a source language variable that |
| is allocated at offset 0x10 in the current subprograms stack frame. The |
| subprogram stack frames are per lane and reside in an interleaved address space. |
| |
| DW_OP_regval_type SGPR0 Generic |
| DW_OP_uconst 1 |
| DW_OP_form_aspace_address |
| DW_OP_offset 0x10 |
| |
|  |
| |
| The DW_OP_regval_type operation pushes the contents of SGPR0 as a generic value. |
| This is the register that holds the address of the current stack frame. |
| |
|  |
| |
| The DW_OP_uconst operation pushes the address space number. Each architecture |
| defines the numbers it uses in DWARF. In this case, address space 1 is being |
| used as the per lane memory. |
| |
|  |
| |
| The DW_OP_form_aspace_address operation pops a value and an address space |
| number. Each address space is associated with a separate storage. A memory |
| location description is pushed which refers to the address space's storage, with |
| an offset of the popped value. |
| |
|  |
| |
| All operations that act on location descriptions work with memory locations |
| regardless of their address space. |
| |
| Every architecture defines address space 0 as the default global memory address |
| space. |
| |
| Generalizing memory location descriptions to include an address space component |
| avoids having to create specialized operations to work with address spaces. |
| |
| The source variable is at offset 0x10 in the stack frame. The DW_OP_offset |
| operation works on memory location descriptions that have an address space just |
| like for any other kind of location description. |
| |
|  |
| |
| The only operations in DWARF 5 that take an address space are DW_OP_xderef*. |
| They treat a value as the address in a specified address space, and read its |
| contents. There is no operation to actually create a location description that |
| references an address space. There is no way to include address space memory |
| locations in parts of composite locations. |
| |
| Since DW_OP_piece now takes any kind of location description for its pieces, it |
| is now possible for parts of a composite to involve locations in different |
| address spaces. For example, this can happen when parts of a source variable |
| allocated in a register are spilled to a stack frame that resides in the |
| non-global address space. |
| |
| ### 4.3.5 Bit Offsets |
| |
| With the generalization of location descriptions on the stack, it is possible to |
| define a DW_OP_bit_offset operation that adjusts the offset of any kind of |
| location in terms of bits rather than bytes. The offset can be a runtime |
| computed value. This is generally useful for any source language that support |
| bit sized entities, and for registers that are not a whole number of bytes. |
| |
| DWARF 5 only supports bit fields in composites using DW_OP_bit_piece. It does |
| not support runtime computed offsets which can happen for bit field packed |
| arrays. It is also not generally composable as it must be the last part of an |
| expression. |
| |
| The following example defines a location description for a source variable that |
| is allocated starting at bit 20 of a register. A similar expression could be |
| used if the source variable was at a bit offset within memory or a particular |
| address space, or if the offset is a runtime value. |
| |
|  |
| |
| DW_OP_regx SGPR3 |
| DW_OP_uconst 20 |
| DW_OP_bit_offset |
| |
|  |
| |
|  |
| |
|  |
| |
| The DW_OP_bit_offset operation pops a value and location description from the |
| stack. It pushes the location description after updating its offset using the |
| value as a bit count. |
| |
|  |
| |
| The ordering of bits within a byte, like byte ordering, is defined by the target |
| architecture. A base type could be extended to specify bit ordering in addition |
| to byte ordering. |
| |
| ## 4.4 Call Frame Information (CFI) |
| |
| DWARF defines call frame information (CFI) that can be used to virtually unwind |
| the subprogram call stack. This involves determining the location where register |
| values have been spilled. DWARF 5 limits these locations to either be registers |
| or global memory. As shown in the earlier examples, heterogeneous devices may |
| spill registers to parts of other registers, to non-global memory address |
| spaces, or even a composite of different location kinds. |
| |
| Therefore, the extension extends the CFI rules to support any kind of location |
| description, and operations to create locations in address spaces. |
| |
| ## 4.5 Objects Not In Byte Aligned Global Memory |
| |
| DWARF 5 only effectively supports byte aligned memory locations on the stack by |
| using a global memory address as a proxy for a memory location description. This |
| is a problem for attributes that define DWARF expressions that require the |
| location of some source language entity that is not allocated in byte aligned |
| global memory. |
| |
| For example, the DWARF expression of the DW_AT_data_member_location attribute is |
| evaluated with an initial stack containing the location of a type instance |
| object. That object could be located in a register, in a non-global memory |
| address space, be described by a composite location description, or could even |
| be an implicit location description. |
| |
| A similar problem exists for DWARF expressions that use the |
| DW_OP_push_object_address operation. This operation pushes the location of a |
| program object associated with the attribute that defines the expression. |
| |
| Allowing any kind of location description on the stack permits the DW_OP_call* |
| operations to be used to factor the creation of location descriptions. The |
| inputs and outputs of the call are passed on the stack. For example, on GPUs an |
| expression can be defined to describe the effective PC of inactive lanes of SIMT |
| execution. This is naturally done by composing the result of expressions for |
| each nested control flow region. This can be done by making each control flow |
| region have its own DWARF procedure, and then calling it from the expressions of |
| the nested control flow regions. The alternative is to make each control flow |
| region have the complete expression which results in much larger DWARF and is |
| less convenient to generate. |
| |
| GPU compilers work hard to allocate objects in the larger number of registers to |
| reduce memory accesses, they have to use different memory address spaces, and |
| they perform optimizations that result in composites of these. Allowing |
| operations to work with any kind of location description enables creating |
| expressions that support all of these. |
| |
| Full general support for bit fields and implicit locations benefits |
| optimizations on any target. |
| |
| ## 4.6 Higher Order Operations |
| |
| The generalization allows an elegant way to add higher order operations that |
| create location descriptions out of other location descriptions in a general |
| composable manner. |
| |
| For example, a DW_OP_extend operation could create a composite location |
| description out of a location description, an element size, and an element |
| count. The resulting composite would effectively be a vector of element count |
| elements with each element being the same location description of the specified |
| bit size. |
| |
| A DW_OP_select_bit_piece operation could create a composite location description |
| out of two location descriptions, a bit mask value, and an element size. The |
| resulting composite would effectively be a vector of elements, selecting from |
| one of the two input locations according to the bit mask. |
| |
| These could be used in the expression of an attribute that computes the |
| effective PC of lanes of SIMT execution. The vector result efficiently computes |
| the PC for each SIMT lane at once. The mask could be the hardware execution mask |
| register that controls which SIMT lanes are executing. For active divergent |
| lanes the vector element would be the current PC, and for inactive divergent |
| lanes the PC would correspond to the source language line at which the lane is |
| logically positioned. |
| |
| Similarly, a DW_OP_overlay_piece operation could be defined that creates a |
| composite location description out of two location descriptions, an offset |
| value, and a size. The resulting composite would consist of parts that are |
| equivalent to one of the location descriptions, but with the other location |
| description replacing a slice defined by the offset and size. This could be used |
| to efficiently express a source language array that has had a set of elements |
| promoted into a vector register when executing a set of iterations of a loop in |
| a SIMD manner. |
| |
| ## 4.7 Objects In Multiple Places |
| |
| A compiler may allocate a source variable in stack frame memory, but for some |
| range of code may promote it to a register. If the generated code does not |
| change the register value, then there is no need to save it back to memory. |
| Effectively, during that range, the source variable is in both memory and a |
| register. If a consumer, such as a debugger, allows the user to change the value |
| of the source variable in that PC range, then it would need to change both |
| places. |
| |
| DWARF 5 supports loclists which are able to specify the location of a source |
| language entity is in different places at different PC locations. It can also |
| express that a source language entity is in multiple places at the same time. |
| |
| DWARF 5 defines operation expressions and loclists separately. In general, this |
| is adequate as non-memory location descriptions can only be computed as the last |
| step of an expression evaluation. |
| |
| However, allowing location descriptions on the stack permits non-memory location |
| descriptions to be used in the middle of expression evaluation. For example, the |
| DW_OP_call* and DW_OP_implicit_pointer operations can result in evaluating the |
| expression of a DW_AT_location attribute of a DIE. The DW_AT_location attribute |
| allows the loclist form. So the result could include multiple location |
| descriptions. |
| |
| Similarly, the DWARF expression associated with attributes such as |
| DW_AT_data_member_location that are evaluated with an initial stack containing a |
| location description, or a DWARF operation expression that uses the |
| DW_OP_push_object_address operation, may want to act on the result of another |
| expression that returned a location description involving multiple places. |
| |
| Therefore, the extension needs to define how expression operations that use those |
| results will behave. The extension does this by generalizing the expression stack |
| to allow an entry to be one or more single location descriptions. In doing this, |
| it unifies the definitions of DWARF operation expressions and loclist |
| expressions in a natural way. |
| |
| All operations that act on location descriptions are extended to act on multiple |
| single location descriptions. For example, the DW_OP_offset operation adds the |
| offset to each single location description. The DW_OP_deref* operations simply |
| read the storage of one of the single location descriptions, since multiple |
| single location descriptions must all hold the same value. Similarly, if the |
| evaluation of a DWARF expression results in multiple single location |
| descriptions, the consumer can ensure any updates are done to all of them, and |
| any reads can use any one of them. |
| |
| # 5. Conclusion |
| |
| A strength of DWARF is that it has generally sought to provide generalized |
| composable solutions that address many problems, rather than solutions that only |
| address one-off issues. This extension attempts to follow that tradition by |
| defining a backwards compatible composable generalization that can address a |
| significant family of issues. It addresses the specific issues present for |
| heterogeneous computing devices, provides benefits for non-heterogeneous |
| devices, and can help address a number of other previously reported issues. |
| |
| # A. Changes to DWARF Debugging Information Format Version 5 |
| |
| > NOTE: This appendix provides changes relative to DWARF Version 5. It has been |
| > defined such that it is backwards compatible with DWARF Version 5. |
| > Non-normative text is shown in <i>italics</i>. The section numbers generally |
| > correspond to those in the DWARF Version 5 standard unless specified |
| > otherwise. Definitions are given to clarify how existing expression |
| > operations, CFI operations, and attributes behave with respect to generalized |
| > location descriptions that support multiple places. |
| > |
| > > NOTE: Notes are included to describe how the changes are to be applied to |
| > > the DWARF Version 5 standard. They also describe rational and issues that |
| > > may need further consideration. |
| |
| ## A.2 General Description |
| |
| ### A.2.5 DWARF Expressions |
| |
| > NOTE: This section, and its nested sections, replaces DWARF Version 5 section |
| > 2.5 and section 2.6. It is based on the text of the existing DWARF Version 5 |
| > standard. |
| |
| DWARF expressions describe how to compute a value or specify a location. |
| |
| <i>The evaluation of a DWARF expression can provide the location of an object, |
| the value of an array bound, the length of a dynamic string, the desired value |
| itself, and so on.</i> |
| |
| If the evaluation of a DWARF expression does not encounter an error, then it can |
| either result in a value (see [2.5.2 DWARF Expression |
| Value](#dwarf-expression-value)) or a location description (see [2.5.3 DWARF |
| Location Description](#dwarf-location-description)). When a DWARF expression |
| is evaluated, it may be specified whether a value or location description is |
| required as the result kind. |
| |
| If a result kind is specified, and the result of the evaluation does not match |
| the specified result kind, then the implicit conversions described in |
| [2.5.4.4.3 Memory Location Description Operations](#memory-location-description-operations) |
| are performed if valid. Otherwise, the DWARF expression is ill-formed. |
| |
| If the evaluation of a DWARF expression encounters an evaluation error, then the |
| result is an evaluation error. |
| |
| > NOTE: Decided to define the concept of an evaluation error. An alternative is |
| > to introduce an undefined value base type in a similar way to location |
| > descriptions having an undefined location description. Then operations that |
| > encounter an evaluation error can return the undefined location description or |
| > value with an undefined base type. |
| > |
| > All operations that act on values would return an undefined entity if given an |
| > undefined value. The expression would then always evaluate to completion, and |
| > can be tested to determine if it is an undefined entity. |
| > |
| > However, this would add considerable additional complexity and does not match |
| > that GDB throws an exception when these evaluation errors occur. |
| |
| If a DWARF expression is ill-formed, then the result is undefined. |
| |
| The following sections detail the rules for when a DWARF expression is |
| ill-formed or results in an evaluation error. |
| |
| A DWARF expression can either be encoded as an operation expression (see [2.5.4 |
| DWARF Operation Expressions](#dwarf-operation-expressions)), or as a |
| location list expression (see [2.5.5 DWARF Location List |
| Expressions](#dwarf-location-list-expressions)). |
| |
| #### A.2.5.1 DWARF Expression Evaluation Context |
| |
| A DWARF expression is evaluated in a context that can include a number of |
| context elements. If multiple context elements are specified then they must be |
| self consistent or the result of the evaluation is undefined. The context |
| elements that can be specified are: |
| |
| 1. <i>A current result kind</i> |
| |
| The kind of result required by the DWARF expression evaluation. If specified |
| it can be a location description or a value. |
| |
| 2. <i>A current thread</i> |
| |
| The target architecture thread identifier of the source program thread of |
| execution for which a user presented expression is currently being |
| evaluated. |
| |
| It is required for operations that are related to target architecture |
| threads. |
| |
| <i>For example, the `DW_OP_regval_type` operation.</i> |
| |
| 3. <i>A current call frame</i> |
| |
| The target architecture call frame identifier. It identifies a call frame |
| that corresponds to an active invocation of a subprogram in the current |
| thread. It is identified by its address on the call stack. The address is |
| referred to as the Canonical Frame Address (CFA). The call frame information |
| is used to determine the CFA for the call frames of the current thread's |
| call stack (see [6.4 Call Frame Information](#call-frame-information)). |
| |
| It is required for operations that specify target architecture registers to |
| support virtual unwinding of the call stack. |
| |
| <i>For example, the `DW_OP_*reg*` operations.</i> |
| |
| If specified, it must be an active call frame in the current thread. |
| Otherwise the result is undefined. |
| |
| If it is the currently executing call frame, then it is termed the top call |
| frame. |
| |
| 4. <i>A current program location</i> |
| |
| The target architecture program location corresponding to the current call |
| frame of the current thread. |
| |
| The program location of the top call frame is the target architecture |
| program counter for the current thread. The call frame information is used |
| to obtain the value of the return address register to determine the program |
| location of the other call frames (see [6.4 Call Frame |
| Information](#call-frame-information)). |
| |
| It is required for the evaluation of location list expressions to select |
| amongst multiple program location ranges. It is required for operations that |
| specify target architecture registers to support virtual unwinding of the |
| call stack (see [6.4 Call Frame Information](#call-frame-information)). |
| |
| If specified: |
| |
| - If the current call frame is the top call frame, it must be the current |
| target architecture program location. |
| - If the current call frame F is not the top call frame, it must be the |
| program location associated with the call site in the current caller frame |
| F that invoked the callee frame. |
| - Otherwise the result is undefined. |
| |
| 5. <i>A current compilation unit</i> |
| |
| The compilation unit debug information entry that contains the DWARF |
| expression being evaluated. |
| |
| It is required for operations that reference debug information associated |
| with the same compilation unit, including indicating if such references use |
| the 32-bit or 64-bit DWARF format. It can also provide the default address |
| space address size if no current target architecture is specified. |
| |
| <i>For example, the `DW_OP_constx` and `DW_OP_addrx` operations.</i> |
| |
| <i>Note that this compilation unit may not be the same as the compilation |
| unit determined from the loaded code object corresponding to the current |
| program location. For example, the evaluation of the expression E associated |
| with a `DW_AT_location` attribute of the debug information entry operand of |
| the `DW_OP_call*` operations is evaluated with the compilation unit that |
| contains E and not the one that contains the `DW_OP_call*` operation |
| expression.</i> |
| |
| 6. <i>A current target architecture</i> |
| |
| The target architecture. |
| |
| It is required for operations that specify target architecture specific |
| entities. |
| |
| <i>For example, target architecture specific entities include DWARF register |
| identifiers, DWARF address space identifiers, the default address space, and |
| the address space address sizes.</i> |
| |
| If specified: |
| |
| - If the current frame is specified, then the current target architecture |
| must be the same as the target architecture of the current frame. |
| |
| - If the current frame is specified and is the top frame, and if the current |
| thread is specified, then the current target architecture must be the same |
| as the target architecture of the current thread. |
| |
| - If the current compilation unit is specified, then the current target |
| architecture default address space address size must be the same as the |
| `address_size` field in the header of the current compilation unit and any |
| associated entry in the `.debug_aranges` section. |
| - If the current program location is specified, then the current target |
| architecture must be the same as the target architecture of any line |
| number information entry (see [6.2 Line Number |
| Information](#line-number-information)) corresponding to the current |
| program location. |
| - If the current program location is specified, then the current target |
| architecture default address space address size must be the same as the |
| `address_size` field in the header of any entry corresponding to the |
| current program location in the `.debug_addr`, `.debug_line`, |
| `.debug_rnglists`, `.debug_rnglists.dwo`, `.debug_loclists`, and |
| `.debug_loclists.dwo` sections. |
| - Otherwise the result is undefined. |
| |
| 7. <i>A current object</i> |
| |
| The location description of a program object. |
| |
| It is required for the `DW_OP_push_object_address` operation. |
| |
| <i>For example, the `DW_AT_data_location` attribute on type debug |
| information entries specifies the program object corresponding to a runtime |
| descriptor as the current object when it evaluates its associated |
| expression.</i> |
| |
| The result is undefined if the location description is invalid (see [2.5.3 |
| DWARF Location Description](#dwarf-location-description)). |
| |
| 8. <i>An initial stack</i> |
| |
| This is a list of values or location descriptions that will be pushed on the |
| operation expression evaluation stack in the order provided before |
| evaluation of an operation expression starts. |
| |
| Some debugger information entries have attributes that evaluate their DWARF |
| expression value with initial stack entries. In all other cases the initial |
| stack is empty. |
| |
| The result is undefined if any location descriptions are invalid (see [2.5.3 |
| DWARF Location Description](#dwarf-location-description)). |
| |
| If the evaluation requires a context element that is not specified, then the |
| result of the evaluation is an error. |
| |
| <i>A DWARF expression for a location description may be able to be evaluated |
| without a thread, call frame, program location, or architecture context. For |
| example, the location of a global variable may be able to be evaluated without |
| such context. If the expression evaluates with an error then it may indicate the |
| variable has been optimized and so requires more context.</i> |
| |
| <i>The DWARF expression for call frame information (see [6.4 Call Frame |
| Information](#call-frame-information)) operations are restricted to those |
| that do not require the compilation unit context to be specified.</i> |
| |
| The DWARF is ill-formed if all the `address_size` fields in the headers of all |
| the entries in the `.debug_info`, `.debug_addr`, `.debug_line`, |
| `.debug_rnglists`, `.debug_rnglists.dwo`, `.debug_loclists`, and |
| `.debug_loclists.dwo` sections corresponding to any given program location do |
| not match. |
| |
| #### A.2.5.2 DWARF Expression Value |
| |
| A value has a type and a literal value. It can represent a literal value of any |
| supported base type of the target architecture. The base type specifies the |
| size, encoding, and endianity of the literal value. |
| |
| > NOTE: It may be desirable to add an implicit pointer base type encoding. It |
| > would be used for the type of the value that is produced when the |
| > `DW_OP_deref*` operation retrieves the full contents of an implicit pointer |
| > location storage created by the `DW_OP_implicit_pointer` operation. The |
| > literal value would record the debugging information entry and byte |
| > displacement specified by the associated `DW_OP_implicit_pointer` operation. |
| |
| There is a distinguished base type termed the generic type, which is an integral |
| type that has the size of an address in the target architecture default address |
| space, a target architecture defined endianity, and unspecified signedness. |
| |
| <i>The generic type is the same as the unspecified type used for stack |
| operations defined in DWARF Version 4 and before.</i> |
| |
| An integral type is a base type that has an encoding of `DW_ATE_signed`, |
| `DW_ATE_signed_char`, `DW_ATE_unsigned`, `DW_ATE_unsigned_char`, |
| `DW_ATE_boolean`, or any target architecture defined integral encoding in the |
| inclusive range `DW_ATE_lo_user` to `DW_ATE_hi_user`. |
| |
| > NOTE: It is unclear if `DW_ATE_address` is an integral type. GDB does not seem |
| > to consider it as integral. |
| |
| #### A.2.5.3 DWARF Location Description |
| |
| <i>Debugging information must provide consumers a way to find the location of |
| program variables, determine the bounds of dynamic arrays and strings, and |
| possibly to find the base address of a subprogram's call frame or the return |
| address of a subprogram. Furthermore, to meet the needs of recent computer |
| architectures and optimization techniques, debugging information must be able to |
| describe the location of an object whose location changes over the object's |
| lifetime, and may reside at multiple locations simultaneously during parts of an |
| object's lifetime.</i> |
| |
| Information about the location of program objects is provided by location |
| descriptions. |
| |
| Location descriptions can consist of one or more single location descriptions. |
| |
| A single location description specifies the location storage that holds a |
| program object and a position within the location storage where the program |
| object starts. The position within the location storage is expressed as a bit |
| offset relative to the start of the location storage. |
| |
| A location storage is a linear stream of bits that can hold values. Each |
| location storage has a size in bits and can be accessed using a zero-based bit |
| offset. The ordering of bits within a location storage uses the bit numbering |
| and direction conventions that are appropriate to the current language on the |
| target architecture. |
| |
| There are five kinds of location storage: |
| |
| 1. <i>memory location storage</i> |
| |
| Corresponds to the target architecture memory address spaces. |
| |
| 2. <i>register location storage</i> |
| |
| Corresponds to the target architecture registers. |
| |
| 3. <i>implicit location storage</i> |
| |
| Corresponds to fixed values that can only be read. |
| |
| 4. <i>undefined location storage</i> |
| |
| Indicates no value is available and therefore cannot be read or written. |
| |
| 5. <i>composite location storage</i> |
| |
| Allows a mixture of these where some bits come from one location storage and |
| some from another location storage, or from disjoint parts of the same |
| location storage. |
| |
| > NOTE: It may be better to add an implicit pointer location storage kind used |
| > by the `DW_OP_implicit_pointer` operation. It would specify the debugger |
| > information entry and byte offset provided by the operations. |
| |
| <i>Location descriptions are a language independent representation of addressing |
| rules.</i> |
| |
| - <i>They can be the result of evaluating a debugger information entry attribute |
| that specifies an operation expression of arbitrary complexity. In this usage |
| they can describe the location of an object as long as its lifetime is either |
| static or the same as the lexical block (see [3.5 Lexical Block |
| Entries](#lexical-block-entries)) that owns it, and it does not move during |
| its lifetime.</i> |
| |
| - <i>They can be the result of evaluating a debugger information entry attribute |
| that specifies a location list expression. In this usage they can describe the |
| location of an object that has a limited lifetime, changes its location during |
| its lifetime, or has multiple locations over part or all of its lifetime.</i> |
| |
| If a location description has more than one single location description, the |
| DWARF expression is ill-formed if the object value held in each single location |
| description's position within the associated location storage is not the same |
| value, except for the parts of the value that are uninitialized. |
| |
| <i>A location description that has more than one single location description can |
| only be created by a location list expression that has overlapping program |
| location ranges, or certain expression operations that act on a location |
| description that has more than one single location description. There are no |
| operation expression operations that can directly create a location description |
| with more than one single location description.</i> |
| |
| <i>A location description with more than one single location description can be |
| used to describe objects that reside in more than one piece of storage at the |
| same time. An object may have more than one location as a result of |
| optimization. For example, a value that is only read may be promoted from memory |
| to a register for some region of code, but later code may revert to reading the |
| value from memory as the register may be used for other purposes. For the code |
| region where the value is in a register, any change to the object value must be |
| made in both the register and the memory so both regions of code will read the |
| updated value.</i> |
| |
| <i>A consumer of a location description with more than one single location |
| description can read the object's value from any of the single location |
| descriptions (since they all refer to location storage that has the same value), |
| but must write any changed value to all the single location descriptions.</i> |
| |
| Updating a location description L by a bit offset B is defined as adding the |
| value of B to the bit offset of each single location description SL of L. It is |
| an evaluation error if the updated bit offset of any SL is less than 0 or |
| greater than or equal to the size of the location storage specified by SL. |
| |
| The evaluation of an expression may require context elements to create a |
| location description. If such a location description is accessed, the storage it |
| denotes is that associated with the context element values specified when the |
| location description was created, which may differ from the context at the time |
| it is accessed. |
| |
| <i>For example, creating a register location description requires the thread |
| context: the location storage is for the specified register of that thread. |
| Creating a memory location description for an address space may required a |
| thread context: the location storage is the memory associated with that |
| thread.</i> |
| |
| If any of the context elements required to create a location description change, |
| the location description becomes invalid and accessing it is undefined. |
| |
| <i>Examples of context that can invalidate a location description are:</i> |
| |
| - <i>The thread context is required and execution causes the thread to |
| terminate.</i> |
| - <i>The call frame context is required and further execution causes the call |
| frame to return to the calling frame.</i> |
| - <i>The program location is required and further execution of the thread |
| occurs. That could change the location list entry or call frame information |
| entry that applies.</i> |
| - <i>An operation uses call frame information:</i> |
| - <i>Any of the frames used in the virtual call frame unwinding return.</i> |
| - <i>The top call frame is used, the program location is used to select the |
| call frame information entry, and further execution of the thread |
| occurs.</i> |
| |
| <i>A DWARF expression can be used to compute a location description for an |
| object. A subsequent DWARF expression evaluation can be given the object |
| location description as the object context or initial stack context to compute a |
| component of the object. The final result is undefined if the object location |
| description becomes invalid between the two expression evaluations.</i> |
| |
| A change of a thread's program location may not make a location description |
| invalid, yet may still render it as no longer meaningful. Accessing such a |
| location description, or using it as the object context or initial stack context |
| of an expression evaluation, may produce an undefined result. |
| |
| <i>For example, a location description may specify a register that no longer |
| holds the intended program object after a program location change. One way to |
| avoid such problems is to recompute location descriptions associated with |
| threads when their program locations change.</i> |
| |
| #### A.2.5.4 DWARF Operation Expressions |
| |
| An operation expression is comprised of a stream of operations, each consisting |
| of an opcode followed by zero or more operands. The number of operands is |
| implied by the opcode. |
| |
| Operations represent a postfix operation on a simple stack machine. Each stack |
| entry can hold either a value or a location description. Operations can act on |
| entries on the stack, including adding entries and removing entries. If the kind |
| of a stack entry does not match the kind required by the operation and is not |
| implicitly convertible to the required kind |
| (see [2.5.4.4.3 Memory Location Description Operations](#memory-location-description-operations)), |
| then the DWARF operation expression is ill-formed. |
| |
| Evaluation of an operation expression starts with an empty stack on which the |
| entries from the initial stack provided by the context are pushed in the order |
| provided. Then the operations are evaluated, starting with the first operation |
| of the stream. Evaluation continues until either an operation has an evaluation |
| error, or until one past the last operation of the stream is reached. |
| |
| The result of the evaluation is: |
| |
| - If an operation has an evaluation error, or an operation evaluates an |
| expression that has an evaluation error, then the result is an evaluation |
| error. |
| - If the current result kind specifies a location description, then: |
| - If the stack is empty, the result is a location description with one |
| undefined location description. |
| |
| <i>This rule is for backwards compatibility with DWARF Version 5 which uses |
| an empty operation expression for this purpose.</i> |
| |
| - If the top stack entry is a location description, or can be converted to one |
| (see [2.5.4.4.3 Memory Location Description Operations](#memory-location-description-operations)), |
| then the result is that, possibly converted, location description. Any other entries on the |
| stack are discarded. |
| - Otherwise the DWARF expression is ill-formed. |
| |
| > NOTE: Could define this case as returning an implicit location description |
| > as if the `DW_OP_implicit` operation is performed. |
| |
| - If the current result kind specifies a value, then: |
| - If the top stack entry is a value, or can be converted to one (see |
| [2.5.4.4.3 Memory Location Description Operations](#memory-location-description-operations)), |
| then the result is that, possibly converted, value. Any other entries on the stack are |
| discarded. |
| - Otherwise the DWARF expression is ill-formed. |
| - If the current result kind is not specified, then: |
| - If the stack is empty, the result is a location description with one |
| undefined location description. |
| |
| <i>This rule is for backwards compatibility with DWARF Version 5 which uses |
| an empty operation expression for this purpose.</i> |
| |
| > NOTE: This rule is consistent with the rule above for when a location |
| > description is requested. However, GDB appears to report this as an error |
| > and no GDB tests appear to cause an empty stack for this case. |
| |
| - Otherwise, the top stack entry is returned. Any other entries on the stack |
| are discarded. |
| |
| An operation expression is encoded as a byte block with some form of prefix that |
| specifies the byte count. It can be used: |
| |
| - as the value of a debugging information entry attribute that is encoded using |
| class `exprloc` (see [7.5.5 Classes and Forms](#classes-and-forms)), |
| - as the operand to certain operation expression operations, |
| - as the operand to certain call frame information operations (see [6.4 Call |
| Frame Information](#call-frame-information)), |
| - and in location list entries (see [2.5.5 DWARF Location List |
| Expressions](#dwarf-location-list-expressions)). |
| |
| ##### A.2.5.4.1 Stack Operations |
| |
| > NOTE: This section replaces DWARF Version 5 section 2.5.1.3. |
| |
| The following operations manipulate the DWARF stack. Operations that index the |
| stack assume that the top of the stack (most recently added entry) has index 0. |
| They allow the stack entries to be either a value or location description. |
| |
| If any stack entry accessed by a stack operation is an incomplete composite |
| location description (see [2.5.4.4.6 Composite Location Description Operations] |
| (#composite-location-description-operations)), then the DWARF expression is ill-formed. |
| |
| > NOTE: These operations now support stack entries that are values and location |
| > descriptions. |
| |
| > NOTE: If it is desired to also make them work with incomplete composite |
| > location descriptions, then would need to define that the composite location |
| > storage specified by the incomplete composite location description is also |
| > replicated when a copy is pushed. This ensures that each copy of the |
| > incomplete composite location description can update the composite location |
| > storage they specify independently. |
| |
| 1. `DW_OP_dup` |
| |
| `DW_OP_dup` duplicates the stack entry at the top of the stack. |
| |
| 2. `DW_OP_drop` |
| |
| `DW_OP_drop` pops the stack entry at the top of the stack and discards it. |
| |
| 3. `DW_OP_pick` |
| |
| `DW_OP_pick` has a single unsigned 1-byte operand that represents an index |
| I. A copy of the stack entry with index I is pushed onto the stack. |
| |
| 4. `DW_OP_over` |
| |
| `DW_OP_over` pushes a copy of the entry with index 1. |
| |
| <i>This is equivalent to a `DW_OP_pick 1` operation.</i> |
| |
| 5. `DW_OP_swap` |
| |
| `DW_OP_swap` swaps the top two stack entries. The entry at the top of the |
| stack becomes the second stack entry, and the second stack entry becomes the |
| top of the stack. |
| |
| 6. `DW_OP_rot` |
| |
| `DW_OP_rot` rotates the first three stack entries. The entry at the top of |
| the stack becomes the third stack entry, the second entry becomes the top of |
| the stack, and the third entry becomes the second entry. |
| |
| <i>Examples illustrating many of these stack operations are found in Appendix |
| D.1.2 on page 289.</i> |
| |
| ##### A.2.5.4.2 Control Flow Operations |
| |
| > NOTE: This section replaces DWARF Version 5 section 2.5.1.5. |
| |
| The following operations provide simple control of the flow of a DWARF operation |
| expression. |
| |
| 1. `DW_OP_nop` |
| |
| `DW_OP_nop` is a place holder. It has no effect on the DWARF stack entries. |
| |
| 2. `DW_OP_le`, `DW_OP_ge`, `DW_OP_eq`, `DW_OP_lt`, `DW_OP_gt`, |
| `DW_OP_ne` |
| |
| > NOTE: The same as in DWARF Version 5 section 2.5.1.5. |
| |
| 3. `DW_OP_skip` |
| |
| `DW_OP_skip` is an unconditional branch. Its single operand is a 2-byte |
| signed integer constant. The 2-byte constant is the number of bytes of the |
| DWARF expression to skip forward or backward from the current operation, |
| beginning after the 2-byte constant. |
| |
| If the updated position is at one past the end of the last operation, then |
| the operation expression evaluation is complete. |
| |
| Otherwise, the DWARF expression is ill-formed if the updated operation |
| position is not in the range of the first to last operation inclusive, or |
| not at the start of an operation. |
| |
| 4. `DW_OP_bra` |
| |
| `DW_OP_bra` is a conditional branch. Its single operand is a 2-byte signed |
| integer constant. This operation pops the top of stack. If the value popped |
| is not the constant 0, the 2-byte constant operand is the number of bytes of |
| the DWARF operation expression to skip forward or backward from the current |
| operation, beginning after the 2-byte constant. |
| |
| If the updated position is at one past the end of the last operation, then |
| the operation expression evaluation is complete. |
| |
| Otherwise, the DWARF expression is ill-formed if the updated operation |
| position is not in the range of the first to last operation inclusive, or |
| not at the start of an operation. |
| |
| 5. `DW_OP_call2, DW_OP_call4, DW_OP_call_ref` |
| |
| `DW_OP_call2`, `DW_OP_call4`, and `DW_OP_call_ref` perform DWARF procedure |
| calls during evaluation of a DWARF operation expression. |
| |
| `DW_OP_call2` and `DW_OP_call4`, have one operand that is, respectively, a |
| 2-byte or 4-byte unsigned offset DR that represents the byte offset of a |
| debugging information entry D relative to the beginning of the current |
| compilation unit. |
| |
| `DW_OP_call_ref` has one operand that is a 4-byte unsigned value in the |
| 32-bit DWARF format, or an 8-byte unsigned value in the 64-bit DWARF format, |
| that represents the byte offset DR of a debugging information entry D |
| relative to the beginning of the `.debug_info` section that contains the |
| current compilation unit. D may not be in the current compilation unit. |
| |
| > NOTE: DWARF Version 5 states that DR can be an offset in a `.debug_info` |
| > section other than the one that contains the current compilation unit. It |
| > states that relocation of references from one executable or shared object |
| > file to another must be performed by the consumer. But given that DR is |
| > defined as an offset in a `.debug_info` section this seems impossible. If |
| > DR was defined as an implementation defined value, then the consumer could |
| > choose to interpret the value in an implementation defined manner to |
| > reference a debug information in another executable or shared object. |
| > |
| > In ELF the `.debug_info` section is in a non-`PT_LOAD` segment so standard |
| > dynamic relocations cannot be used. But even if they were loaded segments |
| > and dynamic relocations were used, DR would need to be the address of D, |
| > not an offset in a `.debug_info` section. That would also need DR to be |
| > the size of a global address. So it would not be possible to use the |
| > 32-bit DWARF format in a 64-bit global address space. In addition, the |
| > consumer would need to determine what executable or shared object the |
| > relocated address was in so it could determine the containing compilation |
| > unit. |
| > |
| > GDB only interprets DR as an offset in the `.debug_info` section that |
| > contains the current compilation unit. |
| > |
| > This comment also applies to `DW_OP_implicit_pointer`. |
| |
| <i>Operand interpretation of `DW_OP_call2`, `DW_OP_call4`, and |
| `DW_OP_call_ref` is exactly like that for `DW_FORM_ref2`, `DW_FORM_ref4`, |
| and `DW_FORM_ref_addr`, respectively.</i> |
| |
| The call operation is evaluated by: |
| |
| - If D has a `DW_AT_location` attribute that is encoded as a `exprloc` that |
| specifies an operation expression E, then execution of the current |
| operation expression continues from the first operation of E. Execution |
| continues until one past the last operation of E is reached, at which |
| point execution continues with the operation following the call operation. |
| The operations of E are evaluated with the same current context, except |
| current compilation unit is the one that contains D and the stack is the |
| same as that being used by the call operation. After the call operation |
| has been evaluated, the stack is therefore as it is left by the evaluation |
| of the operations of E. Since E is evaluated on the same stack as the call |
| operation, E can use, and/or remove entries already on the stack, and can |
| add new entries to the stack. |
| |
| <i>Values on the stack at the time of the call may be used as parameters |
| by the called expression and values left on the stack by the called |
| expression may be used as return values by prior agreement between the |
| calling and called expressions.</i> |
| |
| - If D has a `DW_AT_location` attribute that is encoded as a `loclist` or |
| `loclistsptr`, then the specified location list expression E is evaluated. |
| The evaluation of E uses the current context, except the result kind is a |
| location description, the compilation unit is the one that contains D, and |
| the initial stack is empty. The location description result is pushed on |
| the stack. |
| |
| > NOTE: This rule avoids having to define how to execute a matched |
| > location list entry operation expression on the same stack as the call |
| > when there are multiple matches. But it allows the call to obtain the |
| > location description for a variable or formal parameter which may use a |
| > location list expression. |
| > |
| > An alternative is to treat the case when D has a `DW_AT_location` |
| > attribute that is encoded as a `loclist` or `loclistsptr`, and the |
| > specified location list expression E' matches a single location list |
| > entry with operation expression E, the same as the `exprloc` case and |
| > evaluate on the same stack. |
| > |
| > But this is not attractive as if the attribute is for a variable that |
| > happens to end with a non-singleton stack, it will not simply put a |
| > location description on the stack. Presumably the intent of using |
| > `DW_OP_call*` on a variable or formal parameter debugger information |
| > entry is to push just one location description on the stack. That |
| > location description may have more than one single location description. |
| > |
| > The previous rule for `exprloc` also has the same problem, as normally a |
| > variable or formal parameter location expression may leave multiple |
| > entries on the stack and only return the top entry. |
| > |
| > GDB implements `DW_OP_call*` by always executing E on the same stack. If |
| > the location list has multiple matching entries, it simply picks the |
| > first one and ignores the rest. This seems fundamentally at odds with |
| > the desire to support multiple places for variables. |
| > |
| > So, it feels like `DW_OP_call*` should both support pushing a location |
| > description on the stack for a variable or formal parameter, and also |
| > support being able to execute an operation expression on the same stack. |
| > Being able to specify a different operation expression for different |
| > program locations seems a desirable feature to retain. |
| > |
| > A solution to that is to have a distinct `DW_AT_proc` attribute for the |
| > `DW_TAG_dwarf_procedure` debugging information entry. Then the |
| > `DW_AT_location` attribute expression is always executed separately and |
| > pushes a location description (that may have multiple single location |
| > descriptions), and the `DW_AT_proc` attribute expression is always |
| > executed on the same stack and can leave anything on the stack. |
| > |
| > The `DW_AT_proc` attribute could have the new classes `exprproc`, |
| > `loclistproc`, and `loclistsptrproc` to indicate that the expression is |
| > executed on the same stack. `exprproc` is the same encoding as |
| > `exprloc`. `loclistproc` and `loclistsptrproc` are the same encoding as |
| > their non-`proc` counterparts, except the DWARF is ill-formed if the |
| > location list does not match exactly one location list entry and a |
| > default entry is required. These forms indicate explicitly that the |
| > matched single operation expression must be executed on the same stack. |
| > This is better than ad hoc special rules for `loclistproc` and |
| > `loclistsptrproc` which are currently clearly defined to always return a |
| > location description. The producer then explicitly indicates the intent |
| > through the attribute classes. |
| > |
| > Such a change would be a breaking change for how GDB implements |
| > `DW_OP_call*`. However, are the breaking cases actually occurring in |
| > practice? GDB could implement the current approach for DWARF Version 5, |
| > and the new semantics for DWARF Version 6 which has been done for some |
| > other features. |
| > |
| > Another option is to limit the execution to be on the same stack only to |
| > the evaluation of an expression E that is the value of a |
| > `DW_AT_location` attribute of a `DW_TAG_dwarf_procedure` debugging |
| > information entry. The DWARF would be ill-formed if E is a location list |
| > expression that does not match exactly one location list entry. In all |
| > other cases the evaluation of an expression E that is the value of a |
| > `DW_AT_location` attribute would evaluate E with the current context, |
| > except the result kind is a location description, the compilation unit |
| > is the one that contains D, and the initial stack is empty. The location |
| > description result is pushed on the stack. |
| |
| - If D has a `DW_AT_const_value` attribute with a value V, then it is as if |
| a `DW_OP_implicit_value V` operation was executed. |
| |
| <i>This allows a call operation to be used to compute the location |
| description for any variable or formal parameter regardless of whether the |
| producer has optimized it to a constant. This is consistent with the |
| `DW_OP_implicit_pointer` operation.</i> |
| |
| > NOTE: Alternatively, could deprecate using `DW_AT_const_value` for |
| > `DW_TAG_variable` and `DW_TAG_formal_parameter` debugger information |
| > entries that are constants and instead use `DW_AT_location` with an |
| > operation expression that results in a location description with one |
| > implicit location description. Then this rule would not be required. |
| |
| - Otherwise, there is no effect and no changes are made to the stack. |
| |
| > NOTE: In DWARF Version 5, if D does not have a `DW_AT_location` then |
| > `DW_OP_call*` is defined to have no effect. It is unclear that this is |
| > the right definition as a producer should be able to rely on using |
| > `DW_OP_call*` to get a location description for any |
| > non-`DW_TAG_dwarf_procedure` debugging information entries. Also, the |
| > producer should not be creating DWARF with `DW_OP_call*` to a |
| > `DW_TAG_dwarf_procedure` that does not have a `DW_AT_location` |
| > attribute. So, should this case be defined as an ill-formed DWARF |
| > expression? |
| |
| <i>The `DW_TAG_dwarf_procedure` debugging information entry can be used to |
| define DWARF procedures that can be called.</i> |
| |
| ##### A.2.5.4.3 Value Operations |
| |
| This section describes the operations that push values on the stack. |
| |
| Each value stack entry has a type and a literal value. It can represent a |
| literal value of any supported base type of the target architecture. The base |
| type specifies the size, encoding, and endianity of the literal value. |
| |
| The base type of value stack entries can be the distinguished generic type. |
| |
| ###### A.2.5.4.3.1 Literal Operations |
| |
| > NOTE: This section replaces DWARF Version 5 section 2.5.1.1. |
| |
| The following operations all push a literal value onto the DWARF stack. |
| |
| Operations other than `DW_OP_const_type` push a value V with the generic type. |
| If V is larger than the generic type, then V is truncated to the generic type |
| size and the low-order bits used. |
| |
| 1. `DW_OP_lit0`, `DW_OP_lit1`, ..., `DW_OP_lit31` |
| |
| `DW_OP_lit<N>` operations encode an unsigned literal value N from 0 through |
| 31, inclusive. They push the value N with the generic type. |
| |
| 2. `DW_OP_const1u`, `DW_OP_const2u`, `DW_OP_const4u`, `DW_OP_const8u` |
| |
| `DW_OP_const<N>u` operations have a single operand that is a 1, 2, 4, or |
| 8-byte unsigned integer constant U, respectively. They push the value U with |
| the generic type. |
| |
| 3. `DW_OP_const1s`, `DW_OP_const2s`, `DW_OP_const4s`, `DW_OP_const8s` |
| |
| `DW_OP_const<N>s` operations have a single operand that is a 1, 2, 4, or |
| 8-byte signed integer constant S, respectively. They push the value S with |
| the generic type. |
| |
| 4. `DW_OP_constu` |
| |
| `DW_OP_constu` has a single unsigned LEB128 integer operand N. It pushes the |
| value N with the generic type. |
| |
| 5. `DW_OP_consts` |
| |
| `DW_OP_consts` has a single signed LEB128 integer operand N. It pushes the |
| value N with the generic type. |
| |
| 6. `DW_OP_constx` |
| |
| `DW_OP_constx` has a single unsigned LEB128 integer operand that represents |
| a zero-based index into the `.debug_addr` section relative to the value of |
| the `DW_AT_addr_base` attribute of the associated compilation unit. The |
| value N in the `.debug_addr` section has the size of the generic type. It |
| pushes the value N with the generic type. |
| |
| <i>The `DW_OP_constx` operation is provided for constants that require |
| link-time relocation but should not be interpreted by the consumer as a |
| relocatable address (for example, offsets to thread-local storage).</i> |
| |
| 7. `DW_OP_const_type` |
| |
| `DW_OP_const_type` has three operands. The first is an unsigned LEB128 |
| integer DR that represents the byte offset of a debugging information entry |
| D relative to the beginning of the current compilation unit, that provides |
| the type T of the constant value. The second is a 1-byte unsigned integral |
| constant S. The third is a block of bytes B, with a length equal to S. |
| |
| TS is the bit size of the type T. The least significant TS bits of B are |
| interpreted as a value V of the type D. It pushes the value V with the type |
| D. |
| |
| The DWARF is ill-formed if D is not a `DW_TAG_base_type` debugging |
| information entry in the current compilation unit, or if TS divided by 8 |
| (the byte size) and rounded up to a whole number is not equal to S. |
| |
| <i>While the size of the byte block B can be inferred from the type D |
| definition, it is encoded explicitly into the operation so that the |
| operation can be parsed easily without reference to the `.debug_info` |
| section.</i> |
| |
| ###### A.2.5.4.3.2 Arithmetic and Logical Operations |
| |
| > NOTE: This section is the same as DWARF Version 5 section 2.5.1.4. |
| |
| ###### A.2.5.4.3.3 Type Conversion Operations |
| |
| > NOTE: This section is the same as DWARF Version 5 section 2.5.1.6. |
| |
| ###### A.2.5.4.3.4 Special Value Operations |
| |
| > NOTE: This section replaces parts of DWARF Version 5 sections 2.5.1.2, |
| 2.5.1.3, and 2.5.1.7. |
| |
| There are these special value operations currently defined: |
| |
| 1. `DW_OP_regval_type` |
| |
| `DW_OP_regval_type` has two operands. The first is an unsigned LEB128 |
| integer that represents a register number R. The second is an unsigned |
| LEB128 integer DR that represents the byte offset of a debugging information |
| entry D relative to the beginning of the current compilation unit, that |
| provides the type T of the register value. |
| |
| The operation is equivalent to performing `DW_OP_regx R; DW_OP_deref_type |
| DR`. |
| |
| > NOTE: Should DWARF allow the type T to be a larger size than the size of |
| > the register R? Restricting a larger bit size avoids any issue of |
| > conversion as the, possibly truncated, bit contents of the register is |
| > simply interpreted as a value of T. If a conversion is wanted it can be |
| > done explicitly using a `DW_OP_convert` operation. |
| > |
| > GDB has a per register hook that allows a target specific conversion on a |
| > register by register basis. It defaults to truncation of bigger registers. |
| > Removing use of the target hook does not cause any test failures in common |
| > architectures. If the compiler for a target architecture did want some |
| > form of conversion, including a larger result type, it could always |
| > explicitly use the `DW_OP_convert` operation. |
| > |
| > If T is a larger type than the register size, then the default GDB |
| > register hook reads bytes from the next register (or reads out of bounds |
| > for the last register!). Removing use of the target hook does not cause |
| > any test failures in common architectures (except an illegal hand written |
| > assembly test). If a target architecture requires this behavior, these |
| > extensions allow a composite location description to be used to combine |
| > multiple registers. |
| |
| 2. `DW_OP_deref` |
| |
| S is the bit size of the generic type divided by 8 (the byte size) and |
| rounded up to a whole number. DR is the offset of a hypothetical debug |
| information entry D in the current compilation unit for a base type of the |
| generic type. |
| |
| The operation is equivalent to performing `DW_OP_deref_type S, DR`. |
| |
| 3. `DW_OP_deref_size` |
| |
| `DW_OP_deref_size` has a single 1-byte unsigned integral constant that |
| represents a byte result size S. |
| |
| TS is the smaller of the generic type bit size and S scaled by 8 (the byte |
| size). If TS is smaller than the generic type bit size then T is an unsigned |
| integral type of bit size TS, otherwise T is the generic type. DR is the |
| offset of a hypothetical debug information entry D in the current |
| compilation unit for a base type T. |
| |
| > NOTE: Truncating the value when S is larger than the generic type matches |
| > what GDB does. This allows the generic type size to not be an integral |
| > byte size. It does allow S to be arbitrarily large. Should S be restricted |
| > to the size of the generic type rounded up to a multiple of 8? |
| |
| The operation is equivalent to performing `DW_OP_deref_type S, DR`, except |
| if T is not the generic type, the value V pushed is zero-extended to the |
| generic type bit size and its type changed to the generic type. |
| |
| 4. `DW_OP_deref_type` |
| |
| `DW_OP_deref_type` has two operands. The first is a 1-byte unsigned integral |
| constant S. The second is an unsigned LEB128 integer DR that represents the |
| byte offset of a debugging information entry D relative to the beginning of |
| the current compilation unit, that provides the type T of the result value. |
| |
| TS is the bit size of the type T. |
| |
| <i>While the size of the pushed value V can be inferred from the type T, it |
| is encoded explicitly as the operand S so that the operation can be parsed |
| easily without reference to the `.debug_info` section.</i> |
| |
| > NOTE: It is unclear why the operand S is needed. Unlike |
| > `DW_OP_const_type`, the size is not needed for parsing. Any evaluation |
| > needs to get the base type T to push with the value to know its encoding |
| > and bit size. |
| |
| It pops one stack entry that must be a location description L. |
| |
| A value V of TS bits is retrieved from the location storage LS specified by |
| one of the single location descriptions SL of L. |
| |
| <i>If L, or the location description of any composite location description |
| part that is a subcomponent of L, has more than one single location |
| description, then any one of them can be selected as they are required to |
| all have the same value. For any single location description SL, bits are |
| retrieved from the associated storage location starting at the bit offset |
| specified by SL. For a composite location description, the retrieved bits |
| are the concatenation of the N bits from each composite location part PL, |
| where N is limited to the size of PL.</i> |
| |
| V is pushed on the stack with the type T. |
| |
| > NOTE: This definition makes it an evaluation error if L is a register |
| > location description that has less than TS bits remaining in the register |
| > storage. Particularly since these extensions extend location descriptions |
| > to have a bit offset, it would be odd to define this as performing sign |
| > extension based on the type, or be target architecture dependent, as the |
| > number of remaining bits could be any number. This matches the GDB |
| > implementation for `DW_OP_deref_type`. |
| > |
| > These extensions define `DW_OP_*breg*` in terms of `DW_OP_regval_type`. |
| > `DW_OP_regval_type` is defined in terms of `DW_OP_regx`, which uses a 0 |
| > bit offset, and `DW_OP_deref_type`. Therefore, it requires the register |
| > size to be greater or equal to the address size of the address space. This |
| > matches the GDB implementation for `DW_OP_*breg*`. |
| |
| The DWARF is ill-formed if D is not in the current compilation unit, D is |
| not a `DW_TAG_base_type` debugging information entry, or if TS divided by 8 |
| (the byte size) and rounded up to a whole number is not equal to S. |
| |
| > NOTE: This definition allows the base type to be a bit size since there |
| > seems no reason to restrict it. |
| |
| It is an evaluation error if any bit of the value is retrieved from the |
| undefined location storage or the offset of any bit exceeds the size of the |
| location storage LS specified by any single location description SL of L. |
| |
| See [2.5.4.4.5 Implicit Location Description Operations](#implicit-location-description-operations) |
| for special rules concerning implicit location descriptions created by the |
| `DW_OP_implicit_pointer` operation. |
| |
| 5. `DW_OP_xderef` |
| |
| `DW_OP_xderef` pops two stack entries. The first must be an integral type |
| value that represents an address A. The second must be an integral type |
| value that represents a target architecture specific address space |
| identifier AS. |
| |
| The address size S is defined as the address bit size of the target |
| architecture specific address space that corresponds to AS. |
| |
| A is adjusted to S bits by zero extending if necessary, and then treating |
| the least significant S bits as an unsigned value A'. |
| |
| It creates a location description L with one memory location description SL. |
| SL specifies the memory location storage LS that corresponds to AS with a |
| bit offset equal to A' scaled by 8 (the byte size). |
| |
| If AS is an address space that is specific to context elements, then LS |
| corresponds to the location storage associated with the current context. |
| |
| <i>For example, if AS is for per thread storage then LS is the location |
| storage for the current thread. Therefore, if L is accessed by an operation, |
| the location storage selected when the location description was created is |
| accessed, and not the location storage associated with the current context |
| of the access operation.</i> |
| |
| The DWARF expression is ill-formed if AS is not one of the values defined by |
| the target architecture specific `DW_ASPACE_*` values. |
| |
| The operation is equivalent to popping A and AS, pushing L, and then |
| performing `DW_OP_deref`. The value V retrieved is left on the stack with |
| the generic type. |
| |
| 6. `DW_OP_xderef_size` |
| |
| `DW_OP_xderef_size` has a single 1-byte unsigned integral constant that |
| represents a byte result size S. |
| |
| It pops two stack entries. The first must be an integral type value |
| that represents an address A. The second must be an integral type |
| value that represents a target architecture specific address space |
| identifier AS. |
| |
| It creates a location description L as described for `DW_OP_xderef`. |
| |
| The operation is equivalent to popping A and AS, pushing L, and then |
| performing `DW_OP_deref_size S` . The zero-extended value V retrieved is |
| left on the stack with the generic type. |
| |
| 7. `DW_OP_xderef_type` |
| |
| `DW_OP_xderef_type` has two operands. The first is a 1-byte unsigned |
| integral constant S. The second operand is an unsigned LEB128 integer DR |
| that represents the byte offset of a debugging information entry D relative |
| to the beginning of the current compilation unit, that provides the type T |
| of the result value. |
| |
| It pops two stack entries. The first must be an integral type value that |
| represents an address A. The second must be an integral type value that |
| represents a target architecture specific address space identifier AS. |
| |
| It creates a location description L as described for `DW_OP_xderef`. |
| |
| The operation is equivalent to popping A and AS, pushing L, and then |
| performing `DW_OP_deref_type DR` . The value V retrieved is left on the |
| stack with the type T. |
| |
| 8. `DW_OP_entry_value` <i>Deprecated</i> |
| |
| `DW_OP_entry_value` pushes the value of an expression that is evaluated in |
| the context of the calling frame. |
| |
| <i>It may be used to determine the value of arguments on entry to the |
| current call frame provided they are not clobbered.</i> |
| |
| It has two operands. The first is an unsigned LEB128 integer S. The second |
| is a block of bytes, with a length equal S, interpreted as a DWARF operation |
| expression E. |
| |
| E is evaluated with the current context, except the result kind is |
| unspecified, the call frame is the one that called the current frame, the |
| program location is the call site in the calling frame, the object is |
| unspecified, and the initial stack is empty. The calling frame information |
| is obtained by virtually unwinding the current call frame using the call |
| frame information (see [6.4 Call Frame |
| Information](#call-frame-information)). |
| |
| If the result of E is a location description L (see [2.5.4.4.4 Register |
| Location Description |
| Operations](#register-location-description-operations)), and the last |
| operation executed by E is a `DW_OP_reg*` for register R with a target |
| architecture specific base type of T, then the contents of the register are |
| retrieved as if a `DW_OP_deref_type DR` operation was performed where DR is |
| the offset of a hypothetical debug information entry in the current |
| compilation unit for T. The resulting value V is pushed on the stack. |
| |
| <i>Using `DW_OP_reg*` provides a more compact form for the case where the |
| value was in a register on entry to the subprogram.</i> |
| |
| > NOTE: It is unclear how this provides a more compact expression, as |
| > `DW_OP_regval_type` could be used which is marginally larger. |
| |
| If the result of E is a value V, then V is pushed on the stack. |
| |
| Otherwise, the DWARF expression is ill-formed. |
| |
| <i>The `DW_OP_entry_value` operation is deprecated as its main usage is |
| provided by other means. DWARF Version 5 added the |
| `DW_TAG_call_site_parameter` debugger information entry for call sites that |
| has `DW_AT_call_value`, `DW_AT_call_data_location`, and |
| `DW_AT_call_data_value` attributes that provide DWARF expressions to compute |
| actual parameter values at the time of the call, and requires the producer |
| to ensure the expressions are valid to evaluate even when virtually |
| unwound.</i> |
| |
| > NOTE: GDB only implements `DW_OP_entry_value` when E is exactly |
| > `DW_OP_reg*` or `DW_OP_breg*; DW_OP_deref*`. |
| |
| ##### A.2.5.4.4 Location Description Operations |
| |
| This section describes the operations that push location descriptions on the |
| stack. |
| |
| ###### A.2.5.4.4.1 General Location Description Operations |
| |
| > NOTE: This section replaces part of DWARF Version 5 section 2.5.1.3. |
| |
| 1. `DW_OP_push_object_address` |
| |
| `DW_OP_push_object_address` pushes the location description L of the current |
| object. |
| |
| <i>This object may correspond to an independent variable that is part of a |
| user presented expression that is being evaluated. The object location |
| description may be determined from the variable's own debugging information |
| entry or it may be a component of an array, structure, or class whose |
| address has been dynamically determined by an earlier step during user |
| expression evaluation.</i> |
| |
| <i>This operation provides explicit functionality (especially for arrays |
| involving descriptors) that is analogous to the implicit push of the base |
| location description of a structure prior to evaluation of a |
| `DW_AT_data_member_location` to access a data member of a structure.</i> |
| |
| > NOTE: This operation could be removed and the object location description |
| > specified as the initial stack as for `DW_AT_data_member_location`. |
| > |
| > Or this operation could be used instead of needing to specify an initial |
| > stack. The latter approach is more composable as access to the object may |
| > be needed at any point of the expression, and passing it as the initial |
| > stack requires the entire expression to be aware where on the stack it is. |
| > If this were done, ``DW_AT_use_location`` would require a |
| > ``DW_OP_push_object2_address`` operation for the second object. |
| > |
| > Or a more general way to pass an arbitrary number of arguments in and an |
| > operation to get the Nth one such as ``DW_OP_arg N``. A vector of |
| > arguments would then be passed in the expression context rather than an |
| > initial stack. This could also resolve the issues with ``DW_OP_call*`` by |
| > allowing a specific number of arguments passed in and returned to be |
| > specified. The ``DW_OP_call*`` operation could then always execute on a |
| > separate stack: the number of arguments would be specified in a new call |
| > operation and taken from the callers stack, and similarly the number of |
| > return results specified and copied from the called stack back to the |
| > callee stack when the called expression was complete. |
| > |
| > The only attribute that specifies a current object is |
| > `DW_AT_data_location` so the non-normative text seems to overstate how |
| > this is being used. Or are there other attributes that need to state they |
| > pass an object? |
| |
| ###### A.2.5.4.4.2 Undefined Location Description Operations |
| |
| > NOTE: This section replaces DWARF Version 5 section 2.6.1.1.1. |
| |
| <i>The undefined location storage represents a piece or all of an object that is |
| present in the source but not in the object code (perhaps due to optimization). |
| Neither reading nor writing to the undefined location storage is meaningful.</i> |
| |
| An undefined location description specifies the undefined location storage. |
| There is no concept of the size of the undefined location storage, nor of a bit |
| offset for an undefined location description. The `DW_OP_*piece` operations can |
| implicitly specify an undefined location description, allowing any size and |
| offset to be specified, and results in a part with all undefined bits. |
| |
| ###### A.2.5.4.4.3 Memory Location Description Operations |
| |
| > NOTE: This section replaces parts of DWARF Version 5 section 2.5.1.1, 2.5.1.2, |
| > 2.5.1.3, and 2.6.1.1.2. |
| |
| Each of the target architecture specific address spaces has a corresponding |
| memory location storage that denotes the linear addressable memory of that |
| address space. The size of each memory location storage corresponds to the range |
| of the addresses in the corresponding address space. |
| |
| <i>It is target architecture defined how address space location storage maps to |
| target architecture physical memory. For example, they may be independent |
| memory, or more than one location storage may alias the same physical memory |
| possibly at different offsets and with different interleaving. The mapping may |
| also be dictated by the source language address classes.</i> |
| |
| A memory location description specifies a memory location storage. The bit |
| offset corresponds to a bit position within a byte of the memory. Bits accessed |
| using a memory location description, access the corresponding target |
| architecture memory starting at the bit position within the byte specified by |
| the bit offset. |
| |
| A memory location description that has a bit offset that is a multiple of 8 (the |
| byte size) is defined to be a byte address memory location description. It has a |
| memory byte address A that is equal to the bit offset divided by 8. |
| |
| A memory location description that does not have a bit offset that is a multiple |
| of 8 (the byte size) is defined to be a bit field memory location description. |
| It has a bit position B equal to the bit offset modulo 8, and a memory byte |
| address A equal to the bit offset minus B that is then divided by 8. |
| |
| The address space AS of a memory location description is defined to be the |
| address space that corresponds to the memory location storage associated with |
| the memory location description. |
| |
| A location description that is comprised of one byte address memory location |
| description SL is defined to be a memory byte address location description. It |
| has a byte address equal to A and an address space equal to AS of the |
| corresponding SL. |
| |
| `DW_ASPACE_none` is defined as the target architecture default address space. |
| |
| If a stack entry is required to be a location description, but it is a value V |
| with the generic type, then it is implicitly converted to a location description |
| L with one memory location description SL. SL specifies the memory location |
| storage that corresponds to the target architecture default address space with a |
| bit offset equal to V scaled by 8 (the byte size). |
| |
| > NOTE: If it is wanted to allow any integral type value to be implicitly |
| > converted to a memory location description in the target architecture default |
| > address space: |
| > |
| > > If a stack entry is required to be a location description, but is a value V |
| > > with an integral type, then it is implicitly converted to a location |
| > > description L with a one memory location description SL. If the type size of |
| > > V is less than the generic type size, then the value V is zero extended to |
| > > the size of the generic type. The least significant generic type size bits |
| > > are treated as an unsigned value to be used as an address A. SL specifies |
| > > memory location storage corresponding to the target architecture default |
| > > address space with a bit offset equal to A scaled by 8 (the byte size). |
| > |
| > The implicit conversion could also be defined as target architecture specific. |
| > For example, GDB checks if V is an integral type. If it is not it gives an |
| > error. Otherwise, GDB zero-extends V to 64 bits. If the GDB target defines a |
| > hook function, then it is called. The target specific hook function can modify |
| > the 64-bit value, possibly sign extending based on the original value type. |
| > Finally, GDB treats the 64-bit value V as a memory location address. |
| |
| If a stack entry is required to be a location description, but it is an implicit |
| pointer value IPV with the target architecture default address space, then it is |
| implicitly converted to a location description with one single location |
| description specified by IPV. See |
| [2.5.4.4.5 Implicit Location Description Operations](#implicit-location-description-operations). |
| |
| If a stack entry is required to be a value, but it is a location description L |
| with one memory location description SL in the target architecture default |
| address space with a bit offset B that is a multiple of 8, then it is implicitly |
| converted to a value equal to B divided by 8 (the byte size) with the generic |
| type. |
| |
| 1. `DW_OP_addr` |
| |
| `DW_OP_addr` has a single byte constant value operand, which has the size of |
| the generic type, that represents an address A. |
| |
| It pushes a location description L with one memory location description SL |
| on the stack. SL specifies the memory location storage corresponding to the |
| target architecture default address space with a bit offset equal to A |
| scaled by 8 (the byte size). |
| |
| <i>If the DWARF is part of a code object, then A may need to be relocated. |
| For example, in the ELF code object format, A must be adjusted by the |
| difference between the ELF segment virtual address and the virtual address |
| at which the segment is loaded.</i> |
| |
| 2. `DW_OP_addrx` |
| |
| `DW_OP_addrx` has a single unsigned LEB128 integer operand that represents a |
| zero-based index into the `.debug_addr` section relative to the value of the |
| `DW_AT_addr_base` attribute of the associated compilation unit. The address |
| value A in the `.debug_addr` section has the size of the generic type. |
| |
| It pushes a location description L with one memory location description SL |
| on the stack. SL specifies the memory location storage corresponding to the |
| target architecture default address space with a bit offset equal to A |
| scaled by 8 (the byte size). |
| |
| <i>If the DWARF is part of a code object, then A may need to be relocated. |
| For example, in the ELF code object format, A must be adjusted by the |
| difference between the ELF segment virtual address and the virtual address |
| at which the segment is loaded.</i> |
| |
| 3. `DW_OP_form_tls_address` |
| |
| `DW_OP_form_tls_address` pops one stack entry that must be an integral type |
| value and treats it as a thread-local storage address TA. |
| |
| It pushes a location description L with one memory location description SL |
| on the stack. SL is the target architecture specific memory location |
| description that corresponds to the thread-local storage address TA. |
| |
| The meaning of the thread-local storage address TA is defined by the |
| run-time environment. If the run-time environment supports multiple |
| thread-local storage blocks for a single thread, then the block |
| corresponding to the executable or shared library containing this DWARF |
| expression is used. |
| |
| <i>Some implementations of C, C++, Fortran, and other languages, support a |
| thread-local storage class. Variables with this storage class have distinct |
| values and addresses in distinct threads, much as automatic variables have |
| distinct values and addresses in each subprogram invocation. Typically, |
| there is a single block of storage containing all thread-local variables |
| declared in the main executable, and a separate block for the variables |
| declared in each shared library. Each thread-local variable can then be |
| accessed in its block using an identifier. This identifier is typically a |
| byte offset into the block and pushed onto the DWARF stack by one of the |
| `DW_OP_const*` operations prior to the `DW_OP_form_tls_address` operation. |
| Computing the address of the appropriate block can be complex (in some |
| cases, the compiler emits a function call to do it), and difficult to |
| describe using ordinary DWARF location descriptions. Instead of forcing |
| complex thread-local storage calculations into the DWARF expressions, the |
| `DW_OP_form_tls_address` allows the consumer to perform the computation |
| based on the target architecture specific run-time environment.</i> |
| |
| 4. `DW_OP_call_frame_cfa` |
| |
| `DW_OP_call_frame_cfa` pushes the location description L of the Canonical |
| Frame Address (CFA) of the current subprogram, obtained from the call frame |
| information on the stack. See [6.4 Call Frame |
| Information](#call-frame-information). |
| |
| <i>Although the value of the `DW_AT_frame_base` attribute of the debugger |
| information entry corresponding to the current subprogram can be computed |
| using a location list expression, in some cases this would require an |
| extensive location list because the values of the registers used in |
| computing the CFA change during a subprogram execution. If the call frame |
| information is present, then it already encodes such changes, and it is |
| space efficient to reference that using the `DW_OP_call_frame_cfa` |
| operation.</i> |
| |
| 5. `DW_OP_fbreg` |
| |
| `DW_OP_fbreg` has a single signed LEB128 integer operand that represents a |
| byte displacement B. |
| |
| The location description L for the <i>frame base</i> of the current |
| subprogram is obtained from the `DW_AT_frame_base` attribute of the debugger |
| information entry corresponding to the current subprogram as described in |
| [3.3.5 Low-Level Information](#low-level-information). |
| |
| The location description L is updated by bit offset B scaled by 8 (the byte |
| size) and pushed on the stack. |
| |
| 6. `DW_OP_breg0`, `DW_OP_breg1`, ..., `DW_OP_breg31` |
| |
| The `DW_OP_breg<N>` operations encode the numbers of up to 32 registers, |
| numbered from 0 through 31, inclusive. The register number R corresponds to |
| the N in the operation name. |
| |
| They have a single signed LEB128 integer operand that represents a byte |
| displacement B. |
| |
| The address space identifier AS is defined as the one corresponding to the |
| target architecture specific default address space. |
| |
| The address size S is defined as the address bit size of the target |
| architecture specific address space corresponding to AS. |
| |
| The contents of the register specified by R are retrieved as if a |
| `DW_OP_regval_type R, DR` operation was performed where DR is the offset of |
| a hypothetical debug information entry in the current compilation unit for |
| an unsigned integral base type of size S bits. B is added and the least |
| significant S bits are treated as an unsigned value to be used as an address |
| A. |
| |
| They push a location description L comprising one memory location |
| description LS on the stack. LS specifies the memory location storage that |
| corresponds to AS with a bit offset equal to A scaled by 8 (the byte size). |
| |
| 7. `DW_OP_bregx` |
| |
| `DW_OP_bregx` has two operands. The first is an unsigned LEB128 integer that |
| represents a register number R. The second is a signed LEB128 integer that |
| represents a byte displacement B. |
| |
| The action is the same as for `DW_OP_breg<N>`, except that R is used as the |
| register number and B is used as the byte displacement. |
| |
| ###### A.2.5.4.4.4 Register Location Description Operations |
| |
| > NOTE: This section replaces DWARF Version 5 section 2.6.1.1.3. |
| |
| There is a register location storage that corresponds to each of the target |
| architecture registers. The size of each register location storage corresponds |
| to the size of the corresponding target architecture register. |
| |
| A register location description specifies a register location storage. The bit |
| offset corresponds to a bit position within the register. Bits accessed using a |
| register location description access the corresponding target architecture |
| register starting at the specified bit offset. |
| |
| 1. `DW_OP_reg0`, `DW_OP_reg1`, ..., `DW_OP_reg31` |
| |
| `DW_OP_reg<N>` operations encode the numbers of up to 32 registers, numbered |
| from 0 through 31, inclusive. The target architecture register number R |
| corresponds to the N in the operation name. |
| |
| The operation is equivalent to performing `DW_OP_regx R`. |
| |
| 2. `DW_OP_regx` |
| |
| `DW_OP_regx` has a single unsigned LEB128 integer operand that represents a |
| target architecture register number R. |
| |
| If the current call frame is the top call frame, it pushes a location |
| description L that specifies one register location description SL on the |
| stack. SL specifies the register location storage that corresponds to R with |
| a bit offset of 0 for the current thread. |
| |
| If the current call frame is not the top call frame, call frame information |
| (see [6.4 Call Frame Information](#call-frame-information)) is used to |
| determine the location description that holds the register for the current |
| call frame and current program location of the current thread. The resulting |
| location description L is pushed. |
| |
| <i>Note that if call frame information is used, the resulting location |
| description may be register, memory, or undefined.</i> |
| |
| <i>An implementation may evaluate the call frame information immediately, or |
| may defer evaluation until L is accessed by an operation. If evaluation is |
| deferred, R and the current context can be recorded in L. When accessed, the |
| recorded context is used to evaluate the call frame information, not the |
| current context of the access operation.</i> |
| |
| <i>These operations obtain a register location. To fetch the contents of a |
| register, it is necessary to use `DW_OP_regval_type`, use one of the |
| `DW_OP_breg*` register-based addressing operations, or use `DW_OP_deref*` on a |
| register location description.</i> |
| |
| ###### A.2.5.4.4.5 Implicit Location Description Operations |
| |
| > NOTE: This section replaces DWARF Version 5 section 2.6.1.1.4. |
| |
| Implicit location storage represents a piece or all of an object which has no |
| actual location in the program but whose contents are nonetheless known, either |
| as a constant or can be computed from other locations and values in the program. |
| |
| An implicit location description specifies an implicit location storage. The bit |
| offset corresponds to a bit position within the implicit location storage. Bits |
| accessed using an implicit location description, access the corresponding |
| implicit storage value starting at the bit offset. |
| |
| 1. `DW_OP_implicit_value` |
| |
| `DW_OP_implicit_value` has two operands. The first is an unsigned LEB128 |
| integer that represents a byte size S. The second is a block of bytes with a |
| length equal to S treated as a literal value V. |
| |
| An implicit location storage LS is created with the literal value V and a |
| size of S. |
| |
| It pushes location description L with one implicit location description SL |
| on the stack. SL specifies LS with a bit offset of 0. |
| |
| 2. `DW_OP_stack_value` |
| |
| `DW_OP_stack_value` pops one stack entry that must be a value V. |
| |
| An implicit location storage LS is created with the literal value V using |
| the size, encoding, and endianity specified by V's base type. |
| |
| It pushes a location description L with one implicit location description SL |
| on the stack. SL specifies LS with a bit offset of 0. |
| |
| <i>The `DW_OP_stack_value` operation specifies that the object does not |
| exist in memory, but its value is nonetheless known. In this form, the |
| location description specifies the actual value of the object, rather than |
| specifying the memory or register storage that holds the value.</i> |
| |
| See `DW_OP_implicit_pointer` (following) for special rules concerning |
| implicit pointer values produced by dereferencing implicit location |
| descriptions created by the `DW_OP_implicit_pointer` operation. |
| |
| Note: Since location descriptions are allowed on the stack, the |
| `DW_OP_stack_value` operation no longer terminates the DWARF operation |
| expression execution as in DWARF Version 5. |
| |
| 3. `DW_OP_implicit_pointer` |
| |
| <i>An optimizing compiler may eliminate a pointer, while still retaining the |
| value that the pointer addressed. `DW_OP_implicit_pointer` allows a producer |
| to describe this value.</i> |
| |
| <i>`DW_OP_implicit_pointer` specifies an object is a pointer to the target |
| architecture default address space that cannot be represented as a real |
| pointer, even though the value it would point to can be described. In this |
| form, the location description specifies a debugging information entry that |
| represents the actual location description of the object to which the |
| pointer would point. Thus, a consumer of the debug information would be able |
| to access the dereferenced pointer, even when it cannot access the pointer |
| itself.</i> |
| |
| `DW_OP_implicit_pointer` has two operands. The first operand is a 4-byte |
| unsigned value in the 32-bit DWARF format, or an 8-byte unsigned value in |
| the 64-bit DWARF format, that represents the byte offset DR of a debugging |
| information entry D relative to the beginning of the `.debug_info` section |
| that contains the current compilation unit. The second operand is a signed |
| LEB128 integer that represents a byte displacement B. |
| |
| <i>Note that D might not be in the current compilation unit.</i> |
| |
| <i>The first operand interpretation is exactly like that for |
| `DW_FORM_ref_addr`.</i> |
| |
| The address space identifier AS is defined as the one corresponding to the |
| target architecture specific default address space. |
| |
| The address size S is defined as the address bit size of the target |
| architecture specific address space corresponding to AS. |
| |
| An implicit location storage LS is created with the debugging information |
| entry D, address space AS, and size of S. |
| |
| It pushes a location description L that comprises one implicit location |
| description SL on the stack. SL specifies LS with a bit offset of 0. |
| |
| It is an evaluation error if a `DW_OP_deref*` operation pops a location |
| description L', and retrieves S bits, such that any retrieved bits come from |
| an implicit location storage that is the same as LS, unless both the |
| following conditions are met: |
| |
| 1. All retrieved bits come from an implicit location description that |
| refers to an implicit location storage that is the same as LS. |
| |
| <i>Note that all bits do not have to come from the same implicit |
| location description, as L' may involve composite location |
| descriptions.</i> |
| |
| 2. The bits come from consecutive ascending offsets within their respective |
| implicit location storage. |
| |
| <i>These rules are equivalent to retrieving the complete contents of LS.</i> |
| |
| If both the above conditions are met, then the value V pushed by the |
| `DW_OP_deref*` operation is an implicit pointer value IPV with a target |
| architecture specific address space of AS, a debugging information entry of |
| D, and a base type of T. If AS is the target architecture default address |
| space, then T is the generic type. Otherwise, T is a target architecture |
| specific integral type with a bit size equal to S. |
| |
| If IPV is either implicitly converted to a location description (only done |
| if AS is the target architecture default address space), then the resulting |
| location description RL is: |
| |
| - If D has a `DW_AT_location` attribute, the DWARF expression E from the |
| `DW_AT_location` attribute is evaluated with the current context, except |
| that the result kind is a location description, the compilation unit is |
| the one that contains D, the object is unspecified, and the initial stack |
| is empty. RL is the expression result. |
| |
| <i>Note that E is evaluated with the context of the expression accessing |
| IPV, and not the context of the expression that contained the |
| `DW_OP_implicit_pointer` operation that created L.</i> |
| |
| - If D has a `DW_AT_const_value` attribute, then an implicit location |
| storage RLS is created from the `DW_AT_const_value` attribute's value with |
| a size matching the size of the `DW_AT_const_value` attribute's value. RL |
| comprises one implicit location description SRL. SRL specifies RLS with a |
| bit offset of 0. |
| |
| > NOTE: If using `DW_AT_const_value` for variables and formal parameters |
| > is deprecated and instead `DW_AT_location` is used with an implicit |
| > location description, then this rule would not be required. |
| |
| - Otherwise, it is an evaluation error. |
| |
| The location description RL is updated by bit offset B scaled by 8 (the byte |
| size). |
| |
| If a `DW_OP_stack_value` operation pops a value that is the same as IPV, |
| then it pushes a location description that is the same as L. |
| |
| It is an evaluation error if LS or IPV is accessed in any other manner. |
| |
| <i>The restrictions on how an implicit pointer location description created |
| by `DW_OP_implicit_pointer` can be used are to simplify the DWARF consumer. |
| Similarly, for an implicit pointer value created by `DW_OP_deref*` and |
| `DW_OP_stack_value`.</i> |
| |
| <i>Typically a `DW_OP_implicit_pointer` operation is used in a DWARF expression |
| E<sub>1</sub> of a `DW_TAG_variable` or `DW_TAG_formal_parameter` debugging |
| information entry D<sub>1</sub>'s `DW_AT_location` attribute. The debugging |
| information entry referenced by the `DW_OP_implicit_pointer` operation is |
| typically itself a `DW_TAG_variable` or `DW_TAG_formal_parameter` debugging |
| information entry D<sub>2</sub> whose `DW_AT_location` attribute gives a second |
| DWARF expression E<sub>2</sub>.</i> |
| |
| <i>D<sub>1</sub> and E<sub>1</sub> are describing the location of a pointer type |
| object. D<sub>2</sub> and E<sub>2</sub> are describing the location of the |
| object pointed to by that pointer object.</i> |
| |
| <i>However, D<sub>2</sub> may be any debugging information entry that contains a |
| `DW_AT_location` or `DW_AT_const_value` attribute (for example, |
| `DW_TAG_dwarf_procedure`). By using E<sub>2</sub>, a consumer can reconstruct |
| the value of the object when asked to dereference the pointer described by |
| E<sub>1</sub> which contains the `DW_OP_implicit_pointer` operation.</i> |
| |
| ###### A.2.5.4.4.6 Composite Location Description Operations |
| |
| > NOTE: This section replaces DWARF Version 5 section 2.6.1.2. |
| |
| A composite location storage represents an object or value which may be |
| contained in part of another location storage or contained in parts of more than |
| one location storage. |
| |
| Each part has a part location description L and a part bit size S. L can have |
| one or more single location descriptions SL. If there are more than one SL then |
| that indicates that part is located in more than one place. The bits of each |
| place of the part comprise S contiguous bits from the location storage LS |
| specified by SL starting at the bit offset specified by SL. All the bits must be |
| within the size of LS or the DWARF expression is ill-formed. |
| |
| A composite location storage can have zero or more parts. The parts are |
| contiguous such that the zero-based location storage bit index will range over |
| each part with no gaps between them. Therefore, the size of a composite location |
| storage is the sum of the size of its parts. The DWARF expression is ill-formed |
| if the size of the contiguous location storage is larger than the size of the |
| memory location storage corresponding to the largest target architecture |
| specific address space. |
| |
| A composite location description specifies a composite location storage. The bit |
| offset corresponds to a bit position within the composite location storage. |
| |
| There are operations that create a composite location storage. |
| |
| There are other operations that allow a composite location storage to be |
| incrementally created. Each part is created by a separate operation. There may |
| be one or more operations to create the final composite location storage. A |
| series of such operations describes the parts of the composite location storage |
| that are in the order that the associated part operations are executed. |
| |
| To support incremental creation, a composite location storage can be in an |
| incomplete state. When an incremental operation operates on an incomplete |
| composite location storage, it adds a new part. |
| |
| A composite location description that specifies a composite location storage |
| that is incomplete is termed an incomplete composite location description. A |
| composite location description that specifies a composite location storage that |
| is complete is termed a complete composite location description. |
| |
| If the top stack entry is a location description that has one incomplete |
| composite location description SL after the execution of an operation expression |
| has completed, SL is converted to a complete composite location description. |
| |
| <i>Note that this conversion does not happen after the completion of an |
| operation expression that is evaluated on the same stack by the `DW_OP_call*` |
| operations. Such executions are not a separate evaluation of an operation |
| expression, but rather the continued evaluation of the same operation expression |
| that contains the `DW_OP_call*` operation.</i> |
| |
| If a stack entry is required to be a location description L, but L has an |
| incomplete composite location description, then the DWARF expression is |
| ill-formed. The exception is for the operations involved in incrementally |
| creating a composite location description as described below. |
| |
| <i>Note that a DWARF operation expression may arbitrarily compose composite |
| location descriptions from any other location description, including those that |
| have multiple single location descriptions, and those that have composite |
| location descriptions.</i> |
| |
| <i>The incremental composite location description operations are defined to be |
| compatible with the definitions in DWARF Version 5.</i> |
| |
| 1. `DW_OP_piece` |
| |
| `DW_OP_piece` has a single unsigned LEB128 integer that represents a byte |
| size S. |
| |
| The action is based on the context: |
| |
| - If the stack is empty, then a location description L comprised of one |
| incomplete composite location description SL is pushed on the stack. |
| |
| An incomplete composite location storage LS is created with a single part |
| P. P specifies a location description PL and has a bit size of S scaled by |
| 8 (the byte size). PL is comprised of one undefined location description |
| PSL. |
| |
| SL specifies LS with a bit offset of 0. |
| |
| - Otherwise, if the top stack entry is a location description L comprised of |
| one incomplete composite location description SL, then the incomplete |
| composite location storage LS that SL specifies is updated to append a new |
| part P. P specifies a location description PL and has a bit size of S |
| scaled by 8 (the byte size). PL is comprised of one undefined location |
| description PSL. L is left on the stack. |
| - Otherwise, if the top stack entry is a location description or can be |
| converted to one, then it is popped and treated as a part location |
| description PL. Then: |
| |
| - If the top stack entry (after popping PL) is a location description L |
| comprised of one incomplete composite location description SL, then the |
| incomplete composite location storage LS that SL specifies is updated to |
| append a new part P. P specifies the location description PL and has a |
| bit size of S scaled by 8 (the byte size). L is left on the stack. |
| - Otherwise, a location description L comprised of one |
| incomplete composite location description SL is pushed on |
| the stack. |
| |
| An incomplete composite location storage LS is created with a single |
| part P. P specifies the location description PL and has a bit size of S |
| scaled by 8 (the byte size). |
| |
| SL specifies LS with a bit offset of 0. |
| |
| - Otherwise, the DWARF expression is ill-formed |
| |
| <i>Many compilers store a single variable in sets of registers or store a |
| variable partially in memory and partially in registers. `DW_OP_piece` |
| provides a way of describing where a part of a variable is located.</i> |
| |
| <i>The evaluation rules for the `DW_OP_piece` operation allow it to be |
| compatible with the DWARF Version 5 definition.</i> |
| |
| > NOTE: Since these extensions allow location descriptions to be entries on |
| > the stack, a simpler operation to create composite location descriptions |
| > could be defined. For example, just one operation that specifies how many |
| > parts, and pops pairs of stack entries for the part size and location |
| > description. Not only would this be a simpler operation and avoid the |
| > complexities of incomplete composite location descriptions, but it may |
| > also have a smaller encoding in practice. However, the desire for |
| > compatibility with DWARF Version 5 is likely a stronger consideration. |
| |
| 2. `DW_OP_bit_piece` |
| |
| `DW_OP_bit_piece` has two operands. The first is an unsigned LEB128 integer |
| that represents the part bit size S. The second is an unsigned LEB128 |
| integer that represents a bit displacement B. |
| |
| The action is the same as for `DW_OP_piece`, except that any part created |
| has the bit size S, and the location description PL of any created part is |
| updated by a bit offset B. |
| |
| <i>`DW_OP_bit_piece` is used instead of `DW_OP_piece` when the piece to be |
| assembled is not byte-sized or is not at the start of the part location |
| description.</i> |
| |
| #### A.2.5.5 DWARF Location List Expressions |
| |
| > NOTE: This section replaces DWARF Version 5 section 2.6.2. |
| |
| <i>To meet the needs of recent computer architectures and optimization |
| techniques, debugging information must be able to describe the location of an |
| object whose location changes over the object's lifetime, and may reside at |
| multiple locations during parts of an object's lifetime. Location list |
| expressions are used in place of operation expressions whenever the object whose |
| location is being described has these requirements.</i> |
| |
| A location list expression consists of a series of location list entries. Each |
| location list entry is one of the following kinds: |
| |
| 1. <i>Bounded location description</i> |
| |
| This kind of location list entry provides an operation expression that |
| evaluates to the location description of an object that is valid over a |
| lifetime bounded by a starting and ending address. The starting address is |
| the lowest address of the address range over which the location is valid. |
| The ending address is the address of the first location past the highest |
| address of the address range. |
| |
| The location list entry matches when the current program location is within |
| the given range. |
| |
| There are several kinds of bounded location description entries which differ |
| in the way that they specify the starting and ending addresses. |
| |
| 2. <i>Default location description</i> |
| |
| This kind of location list entry provides an operation expression that |
| evaluates to the location description of an object that is valid when no |
| bounded location description entry applies. |
| |
| The location list entry matches when the current program location is not |
| within the range of any bounded location description entry. |
| |
| 3. <i>Base address</i> |
| |
| This kind of location list entry provides an address to be used as the base |
| address for beginning and ending address offsets given in certain kinds of |
| bounded location description entries. The applicable base address of a |
| bounded location description entry is the address specified by the closest |
| preceding base address entry in the same location list. If there is no |
| preceding base address entry, then the applicable base address defaults to |
| the base address of the compilation unit (see DWARF Version 5 section |
| 3.1.1). |
| |
| In the case of a compilation unit where all of the machine code is contained |
| in a single contiguous section, no base address entry is needed. |
| |
| 4. <i>End-of-list</i> |
| |
| This kind of location list entry marks the end of the location list |
| expression. |
| |
| The address ranges defined by the bounded location description entries of a |
| location list expression may overlap. When they do, they describe a situation in |
| which an object exists simultaneously in more than one place. |
| |
| If all of the address ranges in a given location list expression do not |
| collectively cover the entire range over which the object in question is |
| defined, and there is no following default location description entry, it is |
| assumed that the object is not available for the portion of the range that is |
| not covered. |
| |
| The result of the evaluation of a DWARF location list expression is: |
| |
| - If the current program location is not specified, then it is an evaluation |
| error. |
| |
| > NOTE: If the location list only has a single default entry, should that be |
| > considered a match if there is no program location? If there are non-default |
| > entries then it seems it has to be an evaluation error when there is no |
| > program location as that indicates the location depends on the program |
| > location which is not known. |
| |
| - If there are no matching location list entries, then the result is a location |
| description that comprises one undefined location description. |
| - Otherwise, the operation expression E of each matching location list entry is |
| evaluated with the current context, except that the result kind is a location |
| description, the object is unspecified, and the initial stack is empty. The |
| location list entry result is the location description returned by the |
| evaluation of E. |
| |
| The result is a location description that is comprised of the union of the |
| single location descriptions of the location description result of each |
| matching location list entry. |
| |
| A location list expression can only be used as the value of a debugger |
| information entry attribute that is encoded using class `loclist` or |
| `loclistsptr` (see [7.5.5 Classes and Forms](#classes-and-forms)). The value of |
| the attribute provides an index into a separate object file section called |
| `.debug_loclists` or `.debug_loclists.dwo` (for split DWARF object files) that |
| contains the location list entries. |
| |
| A `DW_OP_call*` and `DW_OP_implicit_pointer` operation can be used to specify a |
| debugger information entry attribute that has a location list expression. |
| Several debugger information entry attributes allow DWARF expressions that are |
| evaluated with an initial stack that includes a location description that may |
| originate from the evaluation of a location list expression. |
| |
| <i>This location list representation, the `loclist` and `loclistsptr` class, and |
| the related `DW_AT_loclists_base` attribute are new in DWARF Version 5. Together |
| they eliminate most, or all of the code object relocations previously needed for |
| location list expressions.</i> |
| |
| > NOTE: The rest of this section is the same as DWARF Version 5 section 2.6.2. |
| |
| ## A.3 Program Scope Entries |
| |
| > NOTE: This section provides changes to existing debugger information entry |
| > attributes. These would be incorporated into the corresponding DWARF Version 5 |
| > chapter 3 sections. |
| |
| ### A.3.3 Subroutine and Entry Point Entries |
| |
| #### A.3.3.5 Low-Level Information |
| |
| 1. A `DW_TAG_subprogram`, `DW_TAG_inlined_subroutine`, or `DW_TAG_entry_point` |
| debugger information entry may have a `DW_AT_return_addr` attribute, whose |
| value is a DWARF expression E. |
| |
| The result of the attribute is obtained by evaluating E with a context that |
| has a result kind of a location description, an unspecified object, the |
| compilation unit that contains E, an empty initial stack, and other context |
| elements corresponding to the source language thread of execution upon which |
| the user is focused, if any. The result of the evaluation is the location |
| description L of the place where the return address for the current call |
| frame's subprogram or entry point is stored. |
| |
| The DWARF is ill-formed if L is not comprised of one memory location |
| description for one of the target architecture specific address spaces. |
| |
| > NOTE: It is unclear why `DW_TAG_inlined_subroutine` has a |
| > `DW_AT_return_addr` attribute but not a `DW_AT_frame_base` or |
| > `DW_AT_static_link` attribute. Seems it would either have all of them or |
| > none. Since inlined subprograms do not have a call frame it seems they |
| > would have none of these attributes. |
| |
| 2. A `DW_TAG_subprogram` or `DW_TAG_entry_point` debugger information entry may |
| have a `DW_AT_frame_base` attribute, whose value is a DWARF expression E. |
| |
| The result of the attribute is obtained by evaluating E with a context that |
| has a result kind of a location description, an unspecified object, the |
| compilation unit that contains E, an empty initial stack, and other context |
| elements corresponding to the source language thread of execution upon which |
| the user is focused, if any. |
| |
| The DWARF is ill-formed if E contains a `DW_OP_fbreg` operation, or the |
| resulting location description L is not comprised of one single location |
| description SL. |
| |
| If SL is a register location description for register R, then L is replaced |
| with the result of evaluating a `DW_OP_bregx R, 0` operation. This computes |
| the frame base memory location description in the target architecture |
| default address space. |
| |
| <i>This allows the more compact `DW_OP_reg*` to be used instead of |
| `DW_OP_breg* 0`.</i> |
| |
| > NOTE: This rule could be removed and require the producer to create the |
| > required location description directly using `DW_OP_call_frame_cfa` or |
| > `DW_OP_breg*`. This would also then allow a target to implement the call |
| > frames within a large register. |
| |
| Otherwise, the DWARF is ill-formed if SL is not a memory location |
| description in any of the target architecture specific address spaces. |
| |
| The resulting L is the <i>frame base</i> for the subprogram or entry point. |
| |
| <i>Typically, E will use the `DW_OP_call_frame_cfa` operation or be a stack |
| pointer register plus or minus some offset.</i> |
| |
| 3. If a `DW_TAG_subprogram` or `DW_TAG_entry_point` debugger information entry |
| is lexically nested, it may have a `DW_AT_static_link` attribute, whose |
| value is a DWARF expression E. |
| |
| The result of the attribute is obtained by evaluating E with a context that |
| has a result kind of a location description, an unspecified object, the |
| compilation unit that contains E, an empty initial stack, and other context |
| elements corresponding to the source language thread of execution upon which |
| the user is focused, if any. The result of the evaluation is the location |
| description L of the <i>canonical frame address</i> (see [6.4 Call Frame |
| Information](#call-frame-information)) of the relevant call frame of the |
| subprogram instance that immediately lexically encloses the current call |
| frame's subprogram or entry point. |
| |
| The DWARF is ill-formed if L is is not comprised of one memory location |
| description for one of the target architecture specific address spaces. |
| |
| ### A.3.4 Call Site Entries and Parameters |
| |
| #### A.3.4.2 Call Site Parameters |
| |
| 1. A `DW_TAG_call_site_parameter` debugger information entry may have a |
| `DW_AT_call_value` attribute, whose value is a DWARF operation expression |
| E<sub>1</sub>. |
| |
| The result of the `DW_AT_call_value` attribute is obtained by evaluating |
| E<sub>1</sub> with a context that has a result kind of a value, an unspecified |
| object, the compilation unit that contains E, an empty initial stack, and other |
| context elements corresponding to the source language thread of execution upon |
| which the user is focused, if any. The resulting value V<sub>1</sub> is the |
| value of the parameter at the time of the call made by the call site. |
| |
| For parameters passed by reference, where the code passes a pointer to a |
| location which contains the parameter, or for reference type parameters, the |
| `DW_TAG_call_site_parameter` debugger information entry may also have a |
| `DW_AT_call_data_location` attribute whose value is a DWARF operation expression |
| E<sub>2</sub>, and a `DW_AT_call_data_value` attribute whose value is a DWARF |
| operation expression E<sub>3</sub>. |
| |
| The value of the `DW_AT_call_data_location` attribute is obtained by evaluating |
| E<sub>2</sub> with a context that has a result kind of a location description, |
| an unspecified object, the compilation unit that contains E, an empty initial |
| stack, and other context elements corresponding to the source language thread of |
| execution upon which the user is focused, if any. The resulting location |
| description L<sub>2</sub> is the location where the referenced parameter lives |
| during the call made by the call site. If E<sub>2</sub> would just be a |
| `DW_OP_push_object_address`, then the `DW_AT_call_data_location` attribute may |
| be omitted. |
| |
| > NOTE: The DWARF Version 5 implies that `DW_OP_push_object_address` may be |
| > used but does not state what object must be specified in the context. |
| > Either `DW_OP_push_object_address` cannot be used, or the object to be |
| > passed in the context must be defined. |
| |
| The value of the `DW_AT_call_data_value` attribute is obtained by evaluating |
| E<sub>3</sub> with a context that has a result kind of a value, an unspecified |
| object, the compilation unit that contains E, an empty initial stack, and other |
| context elements corresponding to the source language thread of execution upon |
| which the user is focused, if any. The resulting value V<sub>3</sub> is the |
| value in L<sub>2</sub> at the time of the call made by the call site. |
| |
| The result of these attributes is undefined if the current call frame is not for |
| the subprogram containing the `DW_TAG_call_site_parameter` debugger information |
| entry or the current program location is not for the call site containing the |
| `DW_TAG_call_site_parameter` debugger information entry in the current call |
| frame. |
| |
| <i>The consumer may have to virtually unwind to the call site (see [6.4 Call |
| Frame Information](#call-frame-information)) in order to evaluate these |
| attributes. This will ensure the source language thread of execution upon which |
| the user is focused corresponds to the call site needed to evaluate the |
| expression.</i> |
| |
| If it is not possible to avoid the expressions of these attributes from |
| accessing registers or memory locations that might be clobbered by the |
| subprogram being called by the call site, then the associated attribute should |
| not be provided. |
| |
| <i>The reason for the restriction is that the parameter may need to be accessed |
| during the execution of the callee. The consumer may virtually unwind from the |
| called subprogram back to the caller and then evaluate the attribute |
| expressions. The call frame information (see [6.4 Call Frame |
| Information](#call-frame-information)) will not be able to restore registers |
| that have been clobbered, and clobbered memory will no longer have the value at |
| the time of the call.</i> |
| |
| ### A.3.5 Lexical Block Entries |
| |
| > NOTE: This section is the same as DWARF Version 5 section 3.5. |
| |
| ## A.4 Data Object and Object List Entries |
| |
| > NOTE: This section provides changes to existing debugger information entry |
| > attributes. These would be incorporated into the corresponding DWARF Version 5 |
| > chapter 4 sections. |
| |
| ### A.4.1 Data Object Entries |
| |
| Program variables, formal parameters and constants are represented by debugging |
| information entries with the tags `DW_TAG_variable`, `DW_TAG_formal_parameter` |
| and `DW_TAG_constant`, respectively. |
| |
| *The tag `DW_TAG_constant` is used for languages that have true named constants.* |
| |
| The debugging information entry for a program variable, formal parameter or |
| constant may have the following attributes: |
| |
| 1. A `DW_AT_location` attribute, whose value is a DWARF expression E that |
| describes the location of a variable or parameter at run-time. |
| |
| The result of the attribute is obtained by evaluating E with a context that |
| has a result kind of a location description, an unspecified object, the |
| compilation unit that contains E, an empty initial stack, and other context |
| elements corresponding to the source language thread of execution upon which |
| the user is focused, if any. The result of the evaluation is the location |
| description of the base of the data object. |
| |
| See [2.5.4.2 Control Flow Operations](#control-flow-operations) for special |
| evaluation rules used by the `DW_OP_call*` operations. |
| |
| > NOTE: Delete the description of how the `DW_OP_call*` operations evaluate |
| > a `DW_AT_location` attribute as that is now described in the operations. |
| |
| > NOTE: See the discussion about the `DW_AT_location` attribute in the |
| > `DW_OP_call*` operation. Having each attribute only have a single purpose |
| > and single execution semantics seems desirable. It makes it easier for the |
| > consumer that no longer have to track the context. It makes it easier for |
| > the producer as it can rely on a single semantics for each attribute. |
| > |
| > For that reason, limiting the `DW_AT_location` attribute to only |
| > supporting evaluating the location description of an object, and using a |
| > different attribute and encoding class for the evaluation of DWARF |
| > expression <i>procedures</i> on the same operation expression stack seems |
| > desirable. |
| |
| 2. `DW_AT_const_value` |
| |
| > NOTE: Could deprecate using the `DW_AT_const_value` attribute for |
| > `DW_TAG_variable` or `DW_TAG_formal_parameter` debugger information |
| > entries that have been optimized to a constant. Instead, `DW_AT_location` |
| > could be used with a DWARF expression that produces an implicit location |
| > description now that any location description can be used within a DWARF |
| > expression. This allows the `DW_OP_call*` operations to be used to push |
| > the location description of any variable regardless of how it is |
| > optimized. |
| |
| ### A.4.2 Common Block Entries |
| |
| A common block entry also has a DW_AT_location attribute whose value is a DWARF |
| expression E that describes the location of the common block at run-time. The |
| result of the attribute is obtained by evaluating E with a context that has a |
| result kind of a location description, an unspecified object, the compilation |
| unit that contains E, an empty initial stack, and other context elements |
| corresponding to the source language thread of execution upon which the user is |
| focused, if any. The result of the evaluation is the location description of the |
| base of the common block. See 2.5.4.2 Control Flow Operations for special |
| evaluation rules used by the DW_OP_call* operations. |
| |
| ## A.5 Type Entries |
| |
| > NOTE: This section provides changes to existing debugger information entry |
| > attributes. These would be incorporated into the corresponding DWARF Version 5 |
| > chapter 5 sections. |
| |
| ### A.5.7 Structure, Union, Class and Interface Type Entries |
| |
| #### A.5.7.3 Derived or Extended Structures, Classes and Interfaces |
| |
| 1. For a `DW_AT_data_member_location` attribute there are two cases: |
| |
| 1. If the attribute is an integer constant B, it provides the offset in |
| bytes from the beginning of the containing entity. |
| |
| The result of the attribute is obtained by updating the bit offset of |
| the location description of the beginning of the containing entity by B |
| scaled by 8 (the byte size). The result is the location description of |
| the base of the member entry. |
| |
| <i>If the beginning of the containing entity is not byte aligned, then |
| the beginning of the member entry has the same bit displacement within a |
| byte.</i> |
| |
| 2. Otherwise, the attribute must be a DWARF expression E which is evaluated |
| with a context that has a result kind of a location description, an |
| unspecified object, the compilation unit that contains E, an initial |
| stack comprising the location description of the beginning of the |
| containing entity, and other context elements corresponding to the |
| source language thread of execution upon which the user is focused, if |
| any. The result of the evaluation is the location description of the |
| base of the member entry. |
| |
| > NOTE: The beginning of the containing entity can now be any location |
| > description, including those with more than one single location |
| > description, and those with single location descriptions that are of any |
| > kind and have any bit offset. |
| |
| #### A.5.7.8 Member Function Entries |
| |
| 1. An entry for a virtual function also has a `DW_AT_vtable_elem_location` |
| attribute whose value is a DWARF expression E. |
| |
| The result of the attribute is obtained by evaluating E with a context that |
| has a result kind of a location description, an unspecified object, the |
| compilation unit that contains E, an initial stack comprising the location |
| description of the object of the enclosing type, and other context elements |
| corresponding to the source language thread of execution upon which the user |
| is focused, if any. The result of the evaluation is the location description |
| of the slot for the function within the virtual function table for the |
| enclosing class. |
| |
| ### A.5.14 Pointer to Member Type Entries |
| |
| 1. The `DW_TAG_ptr_to_member_type` debugging information entry has a |
| `DW_AT_use_location` attribute whose value is a DWARF expression E. It is used |
| to compute the location description of the member of the class to which the |
| pointer to member entry points. |
| |
| <i>The method used to find the location description of a given member of a |
| class, structure, or union is common to any instance of that class, structure, |
| or union and to any instance of the pointer to member type. The method is thus |
| associated with the pointer to member type, rather than with each object that |
| has a pointer to member type.</i> |
| |
| The `DW_AT_use_location` DWARF expression is used in conjunction with the |
| location description for a particular object of the given pointer to member type |
| and for a particular structure or class instance. |
| |
| The result of the attribute is obtained by evaluating E with a context that has |
| a result kind of a location description, an unspecified object, the compilation |
| unit that contains E, an initial stack comprising two entries, and other context |
| elements corresponding to the source language thread of execution upon which the |
| user is focused, if any. The first stack entry is the value of the pointer to |
| member object itself. The second stack entry is the location description of the |
| base of the entire class, structure, or union instance containing the member |
| whose location is being calculated. The result of the evaluation is the location |
| description of the member of the class to which the pointer to member entry |
| points. |
| |
| ### A.5.18 Dynamic Properties of Types |
| |
| #### A.5.18.1 Data Location |
| |
| 1. The `DW_AT_data_location` attribute may be used with any type that provides one |
| or more levels of hidden indirection and/or run-time parameters in its |
| representation. Its value is a DWARF operation expression E which computes the |
| location description of the data for an object. When this attribute is omitted, |
| the location description of the data is the same as the location description of |
| the object. |
| |
| The result of the attribute is obtained by evaluating E with a context that has |
| a result kind of a location description, an object that is the location |
| description of the data descriptor, the compilation unit that contains E, an |
| empty initial stack, and other context elements corresponding to the source |
| language thread of execution upon which the user is focused, if any. The result |
| of the evaluation is the location description of the base of the member entry. |
| |
| <i>E will typically involve an operation expression that begins with a |
| `DW_OP_push_object_address` operation which loads the location description |
| of the object which can then serve as a descriptor in subsequent |
| calculation.</i> |
| |
| > NOTE: Since `DW_AT_data_member_location`, `DW_AT_use_location`, and |
| > `DW_AT_vtable_elem_location` allow both operation expressions and location |
| > list expressions, why does `DW_AT_data_location` not allow both? In all cases |
| > they apply to data objects so less likely that optimization would cause |
| > different operation expressions for different program location ranges. But if |
| > supporting for some then should be for all. |
| > |
| > It seems odd this attribute is not the same as `DW_AT_data_member_location` in |
| > having an initial stack with the location description of the object since the |
| > expression has to need it. |
| |
| ## A.6 Other Debugging Information |
| |
| > NOTE: This section provides changes to existing debugger information entry |
| > attributes. These would be incorporated into the corresponding DWARF Version 5 |
| > chapter 6 sections. |
| |
| ### A.6.2 Line Number Information |
| |
| > NOTE: This section is the same as DWARF Version 5 section 6.2. |
| |
| ### A.6.4 Call Frame Information |
| |
| > NOTE: This section provides changes to DWARF Version 5 section 6.4. Register |
| > unwind DWARF expressions are generalized to allow any location description, |
| > including those with composite and implicit location descriptions. |
| |
| #### A.6.4.1 Structure of Call Frame Information |
| |
| The register rules are: |
| |
| 1. <i>undefined</i> |
| |
| A register that has this rule has no recoverable value in the previous |
| frame. The previous value of this register is the undefined location |
| description (see [2.5.4.4.2 Undefined Location Description |
| Operations](#undefined-location-description-operations)). |
| |
| <i>By convention, the register is not preserved by a callee.</i> |
| |
| 2. <i>same value</i> |
| |
| This register has not been modified from the previous caller frame. |
| |
| If the current frame is the top frame, then the previous value of this |
| register is the location description L that specifies one register location |
| description SL. SL specifies the register location storage that corresponds |
| to the register with a bit offset of 0 for the current thread. |
| |
| If the current frame is not the top frame, then the previous value of this |
| register is the location description obtained using the call frame |
| information for the callee frame and callee program location invoked by the |
| current caller frame for the same register. |
| |
| <i>By convention, the register is preserved by the callee, but the callee |
| has not modified it.</i> |
| |
| 3. <i>offset(N)</i> |
| |
| N is a signed byte offset. The previous value of this register is saved at |
| the location description L. Where L is the location description of the |
| current CFA (see [2.5.4 DWARF Operation |
| Expressions](#dwarf-operation-expressions)) updated with the bit offset N |
| scaled by 8 (the byte size). |
| |
| 4. <i>val_offset(N)</i> |
| |
| N is a signed byte offset. The previous value of this register is the memory |
| byte address of the location description L. Where L is the location |
| description of the current CFA (see [2.5.4 DWARF Operation |
| Expressions](#dwarf-operation-expressions)) updated with the bit offset N |
| scaled by 8 (the byte size). |
| |
| The DWARF is ill-formed if the CFA location description is not a memory byte |
| address location description, or if the register size does not match the |
| size of an address in the target architecture default address space. |
| |
| <i>Since the CFA location description is required to be a memory byte |
| address location description, the value of val_offset(N) will also be a |
| memory byte address location description since it is offsetting the CFA |
| location description by N bytes. Furthermore, the value of val_offset(N) |
| will be a memory byte address in the target architecture default address |
| space.</i> |
| |
| > NOTE: Should DWARF allow the address size to be a different size to the |
| > size of the register? Requiring them to be the same bit size avoids any |
| > issue of conversion as the bit contents of the register is simply |
| > interpreted as a value of the address. |
| > |
| > GDB has a per register hook that allows a target specific conversion on a |
| > register by register basis. It defaults to truncation of bigger registers, |
| > and to actually reading bytes from the next register (or reads out of |
| > bounds for the last register) for smaller registers. There are no GDB |
| > tests that read a register out of bounds (except an illegal hand written |
| > assembly test). |
| |
| 5. <i>register(R)</i> |
| |
| This register has been stored in another register numbered R. |
| |
| The previous value of this register is the location description obtained |
| using the call frame information for the current frame and current program |
| location for register R. |
| |
| The DWARF is ill-formed if the size of this register does not match the size |
| of register R or if there is a cyclic dependency in the call frame |
| information. |
| |
| > NOTE: Should this also allow R to be larger than this register? If so is |
| > the value stored in the low order bits and it is undefined what is stored |
| > in the extra upper bits? |
| |
| 6. <i>expression(E)</i> |
| |
| The previous value of this register is located at the location description |
| produced by evaluating the DWARF operation expression E (see [2.5.4 DWARF |
| Operation Expressions](#dwarf-operation-expressions)). |
| |
| E is evaluated with the current context, except the result kind is a |
| location description, the compilation unit is unspecified, the object is |
| unspecified, and an initial stack comprising the location description of the |
| current CFA (see [2.5.4 DWARF Operation |
| Expressions](#dwarf-operation-expressions)). |
| |
| 7. <i>val_expression(E)</i> |
| |
| The previous value of this register is located at the implicit location |
| description created from the value produced by evaluating the DWARF |
| operation expression E (see [2.5.4 DWARF Operation |
| Expressions](#dwarf-operation-expressions)). |
| |
| E is evaluated with the current context, except the result kind is a value, |
| the compilation unit is unspecified, the object is unspecified, and an |
| initial stack comprising the location description of the current CFA (see |
| [2.5.4 DWARF Operation Expressions](#dwarf-operation-expressions)). |
| |
| The DWARF is ill-formed if the resulting value type size does not match the |
| register size. |
| |
| > NOTE: This has limited usefulness as the DWARF expression E can only |
| > produce values up to the size of the generic type. This is due to not |
| > allowing any operations that specify a type in a CFI operation expression. |
| > This makes it unusable for registers that are larger than the generic |
| > type. However, <i>expression(E)</i> can be used to create an implicit |
| > location description of any size. |
| |
| 8. <i>architectural</i> |
| |
| The rule is defined externally to this specification by the augmenter. |
| |
| A Common Information Entry (CIE) holds information that is shared among many |
| Frame Description Entries (FDE). There is at least one CIE in every non-empty |
| `.debug_frame` section. A CIE contains the following fields, in order: |
| |
| 1. `length` (initial length) |
| |
| A constant that gives the number of bytes of the CIE structure, not |
| including the length field itself. The size of the length field plus the |
| value of length must be an integral multiple of the address size specified |
| in the `address_size` field. |
| |
| 2. `CIE_id` (4 or 8 bytes, see [7.4 32-Bit and 64-Bit DWARF Formats](#bit-and-64-bit-dwarf-formats)) |
| |
| A constant that is used to distinguish CIEs from FDEs. |
| |
| In the 32-bit DWARF format, the value of the CIE id in the CIE header is |
| 0xffffffff; in the 64-bit DWARF format, the value is 0xffffffffffffffff. |
| |
| 3. `version` (ubyte) |
| |
| A version number. This number is specific to the call frame information and |
| is independent of the DWARF version number. |
| |
| The value of the CIE version number is 4. |
| |
| > NOTE: Would this be increased to 5 to reflect the changes in these |
| > extensions? |
| |
| 4. `augmentation` (sequence of UTF-8 characters) |
| |
| A null-terminated UTF-8 string that identifies the augmentation to this CIE |
| or to the FDEs that use it. If a reader encounters an augmentation string |
| that is unexpected, then only the following fields can be read: |
| |
| - CIE: length, CIE_id, version, augmentation |
| - FDE: length, CIE_pointer, initial_location, address_range |
| |
| If there is no augmentation, this value is a zero byte. |
| |
| <i>The augmentation string allows users to indicate that there is additional |
| vendor and target architecture specific information in the CIE or FDE which |
| is needed to virtually unwind a stack frame. For example, this might be |
| information about dynamically allocated data which needs to be freed on exit |
| from the routine.</i> |
| |
| <i>Because the `.debug_frame` section is useful independently of any |
| `.debug_info` section, the augmentation string always uses UTF-8 |
| encoding.</i> |
| |
| 5. `address_size` (ubyte) |
| |
| The size of a target address in this CIE and any FDEs that use it, in bytes. |
| If a compilation unit exists for this frame, its address size must match the |
| address size here. |
| |
| 6. `segment_selector_size` (ubyte) |
| |
| The size of a segment selector in this CIE and any FDEs that use it, in |
| bytes. |
| |
| 7. `code_alignment_factor` (unsigned LEB128) |
| |
| A constant that is factored out of all advance location instructions (see |
| [6.4.2.1 Row Creation Instructions](#row-creation-instructions)). The |
| resulting value is `(operand * code_alignment_factor)`. |
| |
| 8. `data_alignment_factor` (signed LEB128) |
| |
| A constant that is factored out of certain offset instructions (see [6.4.2.2 |
| CFA Definition Instructions](#cfa-definition-instructions) and [6.4.2.3 |
| Register Rule Instructions](#register-rule-instructions)). The |
| resulting value is `(operand * data_alignment_factor)`. |
| |
| 9. `return_address_register` (unsigned LEB128) |
| |
| An unsigned LEB128 constant that indicates which column in the rule table |
| represents the return address of the subprogram. Note that this column might |
| not correspond to an actual machine register. |
| |
| The value of the return address register is used to determine the program |
| location of the caller frame. The program location of the top frame is the |
| target architecture program counter value of the current thread. |
| |
| 10. `initial_instructions` (array of ubyte) |
| |
| A sequence of rules that are interpreted to create the initial setting of |
| each column in the table. |
| |
| The default rule for all columns before interpretation of the initial |
| instructions is the undefined rule. However, an ABI authoring body or a |
| compilation system authoring body may specify an alternate default value for |
| any or all columns. |
| |
| 11. `padding` (array of ubyte) |
| |
| Enough `DW_CFA_nop` instructions to make the size of this entry match the |
| length value above. |
| |
| An FDE contains the following fields, in order: |
| |
| 1. `length` (initial length) |
| |
| A constant that gives the number of bytes of the header and instruction |
| stream for this subprogram, not including the length field itself. The size |
| of the length field plus the value of length must be an integral multiple of |
| the address size. |
| |
| 2. `CIE_pointer` (4 or 8 bytes, see [7.4 32-Bit and 64-Bit DWARF Formats](#bit-and-64-bit-dwarf-formats)) |
| |
| A constant offset into the `.debug_frame` section that denotes the CIE that |
| is associated with this FDE. |
| |
| 3. `initial_location` (segment selector and target address) |
| |
| The address of the first location associated with this table entry. If the |
| segment_selector_size field of this FDE's CIE is non-zero, the initial |
| location is preceded by a segment selector of the given length. |
| |
| 4. `address_range` (target address) |
| |
| The number of bytes of program instructions described by this entry. |
| |
| 5. `instructions` (array of ubyte) |
| |
| A sequence of table defining instructions that are described in [6.4.2 Call |
| Frame Instructions](#call-frame-instructions). |
| |
| 6. `padding` (array of ubyte) |
| |
| Enough `DW_CFA_nop` instructions to make the size of this entry match the |
| length value above. |
| |
| #### A.6.4.2 Call Frame Instructions |
| |
| Some call frame instructions have operands that are encoded as DWARF operation |
| expressions E (see [2.5.4 DWARF Operation |
| Expressions](#dwarf-operation-expressions)). The DWARF operations that can be |
| used in E have the following restrictions: |
| |
| - `DW_OP_addrx`, `DW_OP_call2`, `DW_OP_call4`, `DW_OP_call_ref`, |
| `DW_OP_const_type`, `DW_OP_constx`, `DW_OP_convert`, `DW_OP_deref_type`, |
| `DW_OP_fbreg`, `DW_OP_implicit_pointer`, `DW_OP_regval_type`, |
| `DW_OP_reinterpret`, and `DW_OP_xderef_type` operations are not allowed |
| because the call frame information must not depend on other debug sections. |
| - `DW_OP_push_object_address` is not allowed because there is no object context |
| to provide a value to push. |
| - `DW_OP_call_frame_cfa` and `DW_OP_entry_value` are not allowed because their |
| use would be circular. |
| |
| <i>Call frame instructions to which these restrictions apply include |
| `DW_CFA_def_cfa_expression`, `DW_CFA_expression`, and |
| `DW_CFA_val_expression`.</i> |
| |
| ##### A.6.4.2.1 Row Creation Instructions |
| |
| > NOTE: These instructions are the same as in DWARF Version 5 section 6.4.2.1. |
| |
| ##### A.6.4.2.2 CFA Definition Instructions |
| |
| 1. `DW_CFA_def_cfa` |
| |
| The `DW_CFA_def_cfa` instruction takes two unsigned LEB128 operands |
| representing a register number R and a (non-factored) byte displacement B. |
| The required action is to define the current CFA rule to be equivalent to |
| the result of evaluating the DWARF operation expression `DW_OP_bregx R, B` |
| as a location description. |
| |
| 2. `DW_CFA_def_cfa_sf` |
| |
| The `DW_CFA_def_cfa_sf` instruction takes two operands: an unsigned LEB128 |
| value representing a register number R and a signed LEB128 factored byte |
| displacement B. The required action is to define the current CFA rule to be |
| equivalent to the result of evaluating the DWARF operation expression |
| `DW_OP_bregx R, B * data_alignment_factor` as a location description. |
| |
| <i>The action is the same as `DW_CFA_def_cfa`, except that the second |
| operand is signed and factored.</i> |
| |
| 3. `DW_CFA_def_cfa_register` |
| |
| The `DW_CFA_def_cfa_register` instruction takes a single unsigned LEB128 |
| operand representing a register number R. The required action is to define |
| the current CFA rule to be equivalent to the result of evaluating the DWARF |
| operation expression `DW_OP_bregx R, B` as a location description. B is the |
| old CFA byte displacement. |
| |
| If the subprogram has no current CFA rule, or the rule was defined by a |
| `DW_CFA_def_cfa_expression` instruction, then the DWARF is ill-formed. |
| |
| 4. `DW_CFA_def_cfa_offset` |
| |
| The `DW_CFA_def_cfa_offset` instruction takes a single unsigned LEB128 |
| operand representing a (non-factored) byte displacement B. The required |
| action is to define the current CFA rule to be equivalent to the result of |
| evaluating the DWARF operation expression `DW_OP_bregx R, B` as a location |
| description. R is the old CFA register number. |
| |
| If the subprogram has no current CFA rule, or the rule was defined by a |
| `DW_CFA_def_cfa_expression` instruction, then the DWARF is ill-formed. |
| |
| 5. `DW_CFA_def_cfa_offset_sf` |
| |
| The `DW_CFA_def_cfa_offset_sf` instruction takes a signed LEB128 operand |
| representing a factored byte displacement B. The required action is to |
| define the current CFA rule to be equivalent to the result of evaluating the |
| DWARF operation expression `DW_OP_bregx R, B * data_alignment_factor` as a |
| location description. R is the old CFA register number. |
| |
| If the subprogram has no current CFA rule, or the rule was defined by a |
| `DW_CFA_def_cfa_expression` instruction, then the DWARF is ill-formed. |
| |
| <i>The action is the same as `DW_CFA_def_cfa_offset`, except that the |
| operand is signed and factored.</i> |
| |
| 6. `DW_CFA_def_cfa_expression` |
| |
| The `DW_CFA_def_cfa_expression` instruction takes a single operand encoded |
| as a `DW_FORM_exprloc` value representing a DWARF operation expression E. |
| The required action is to define the current CFA rule to be equivalent to |
| the result of evaluating E with the current context, except the result kind |
| is a location description, the compilation unit is unspecified, the object |
| is unspecified, and an empty initial stack. |
| |
| <i>See [6.4.2 Call Frame Instructions](#call-frame-instructions) regarding |
| restrictions on the DWARF expression operations that can be used in E.</i> |
| |
| The DWARF is ill-formed if the result of evaluating E is not a memory byte |
| address location description. |
| |
| ##### A.6.4.2.3 Register Rule Instructions |
| |
| 1. `DW_CFA_undefined` |
| |
| The `DW_CFA_undefined` instruction takes a single unsigned LEB128 operand |
| that represents a register number R. The required action is to set the rule |
| for the register specified by R to `undefined`. |
| |
| 2. `DW_CFA_same_value` |
| |
| The `DW_CFA_same_value` instruction takes a single unsigned LEB128 operand |
| that represents a register number R. The required action is to set the rule |
| for the register specified by R to `same value`. |
| |
| 3. `DW_CFA_offset` |
| |
| The `DW_CFA_offset` instruction takes two operands: a register number R |
| (encoded with the opcode) and an unsigned LEB128 constant representing a |
| factored displacement B. The required action is to change the rule for the |
| register specified by R to be an <i>offset(B * data_alignment_factor)</i> |
| rule. |
| |
| > NOTE: Seems this should be named `DW_CFA_offset_uf` since the offset is |
| > unsigned factored. |
| |
| 4. `DW_CFA_offset_extended` |
| |
| The `DW_CFA_offset_extended` instruction takes two unsigned LEB128 operands |
| representing a register number R and a factored displacement B. This |
| instruction is identical to `DW_CFA_offset`, except for the encoding and |
| size of the register operand. |
| |
| > NOTE: Seems this should be named `DW_CFA_offset_extended_uf` since the |
| > displacement is unsigned factored. |
| |
| 5. `DW_CFA_offset_extended_sf` |
| |
| The `DW_CFA_offset_extended_sf` instruction takes two operands: an unsigned |
| LEB128 value representing a register number R and a signed LEB128 factored |
| displacement B. This instruction is identical to `DW_CFA_offset_extended`, |
| except that B is signed. |
| |
| 6. `DW_CFA_val_offset` |
| |
| The `DW_CFA_val_offset` instruction takes two unsigned LEB128 operands |
| representing a register number R and a factored displacement B. The required |
| action is to change the rule for the register indicated by R to be a |
| <i>val_offset(B * data_alignment_factor)</i> rule. |
| |
| > NOTE: Seems this should be named `DW_CFA_val_offset_uf` since the |
| displacement is unsigned factored. |
| |
| 7. `DW_CFA_val_offset_sf` |
| |
| The `DW_CFA_val_offset_sf` instruction takes two operands: an unsigned |
| LEB128 value representing a register number R and a signed LEB128 factored |
| displacement B. This instruction is identical to `DW_CFA_val_offset`, except |
| that B is signed. |
| |
| 8. `DW_CFA_register` |
| |
| The `DW_CFA_register` instruction takes two unsigned LEB128 operands |
| representing register numbers R1 and R2 respectively. The required action is |
| to set the rule for the register specified by R1 to be a <i>register(R2)</i> |
| rule. |
| |
| 9. `DW_CFA_expression` |
| |
| The `DW_CFA_expression` instruction takes two operands: an unsigned LEB128 |
| value representing a register number R, and a `DW_FORM_block` value |
| representing a DWARF operation expression E. The required action is to |
| change the rule for the register specified by R to be an |
| <i>expression(E)</i> rule. |
| |
| <i>That is, E computes the location description where the register value can |
| be retrieved.</i> |
| |
| <i>See [6.4.2 Call Frame Instructions](#call-frame-instructions) regarding |
| restrictions on the DWARF expression operations that can be used in E.</i> |
| |
| 10. `DW_CFA_val_expression` |
| |
| The `DW_CFA_val_expression` instruction takes two operands: an unsigned |
| LEB128 value representing a register number R, and a `DW_FORM_block` value |
| representing a DWARF operation expression E. The required action is to |
| change the rule for the register specified by R to be a |
| <i>val_expression(E)</i> rule. |
| |
| <i>That is, E computes the value of register R.</i> |
| |
| <i>See [6.4.2 Call Frame Instructions](#call-frame-instructions) regarding |
| restrictions on the DWARF expression operations that can be used in E.</i> |
| |
| If the result of evaluating E is not a value with a base type size that |
| matches the register size, then the DWARF is ill-formed. |
| |
| 11. `DW_CFA_restore` |
| |
| The `DW_CFA_restore` instruction takes a single operand (encoded with the |
| opcode) that represents a register number R. The required action is to |
| change the rule for the register specified by R to the rule assigned it by |
| the `initial_instructions` in the CIE. |
| |
| 12. `DW_CFA_restore_extended` |
| |
| The `DW_CFA_restore_extended` instruction takes a single unsigned LEB128 |
| operand that represents a register number R. This instruction is identical |
| to `DW_CFA_restore`, except for the encoding and size of the register |
| operand. |
| |
| ##### A.6.4.2.4 Row State Instructions |
| |
| > NOTE: These instructions are the same as in DWARF Version 5 section 6.4.2.4. |
| |
| ##### A.6.4.2.5 Padding Instruction |
| |
| > NOTE: These instructions are the same as in DWARF Version 5 section 6.4.2.5. |
| |
| #### A.6.4.3 Call Frame Instruction Usage |
| |
| > NOTE: The same as in DWARF Version 5 section 6.4.3. |
| |
| #### A.6.4.4 Call Frame Calling Address |
| |
| > NOTE: The same as in DWARF Version 5 section 6.4.4. |
| |
| ## A.7 Data Representation |
| |
| > NOTE: This section provides changes to existing debugger information entry |
| > attributes. These would be incorporated into the corresponding DWARF Version 5 |
| > chapter 7 sections. |
| |
| ### A.7.4 32-Bit and 64-Bit DWARF Formats |
| |
| > NOTE: This augments DWARF Version 5 section 7.4 list item 3's table. |
| |
| Form Role |
| ------------------------ -------------------------------------- |
| DW_OP_implicit_pointer offset in `.debug_info` |
| |
| ### A.7.5 Format of Debugging Information |
| |
| #### A.7.5.5 Classes and Forms |
| |
| > NOTE: The same as in DWARF Version 5 section 7.5.5. |
| |
| ### A.7.7 DWARF Expressions |
| |
| > NOTE: Rename DWARF Version 5 section 7.7 to reflect the unification of |
| > location descriptions into DWARF expressions. |
| |
| #### A.7.7.1 Operation Expressions |
| |
| > NOTE: Rename DWARF Version 5 section 7.7.1 and delete section 7.7.2 to reflect |
| > the unification of location descriptions into DWARF expressions. |
| |
| #### A.7.7.3 Location List Expressions |
| |
| > NOTE: Rename DWARF Version 5 section 7.7.3 to reflect that location lists are |
| > a kind of DWARF expression. |
| |
| # B. Further Information |
| |
| The following references provide additional information on the extension. |
| |
| A reference to the DWARF standard is provided. |
| |
| A formatted version of this extension is available on the LLVM site. It includes |
| many figures that help illustrate the textual description, especially of the |
| example DWARF expression evaluations. |
| |
| Slides and a video of a presentation at the Linux Plumbers Conference 2021 |
| related to this extension are available. |
| |
| The LLVM compiler extension includes the operations mentioned in the motivating |
| examples. It also covers other extensions needed for heterogeneous devices. |
| |
| - [DWARF Debugging Information Format](https://dwarfstd.org/) |
| - [DWARF Debugging Information Format Version 5](https://dwarfstd.org/Dwarf5Std.php) |
| - [Allow Location Descriptions on the DWARF Expression Stack](https://llvm.org/docs/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack.html) |
| - DWARF extensions for optimized SIMT/SIMD (GPU) debugging - Linux Plumbers Conference 2021 |
| - [Video](https://www.youtube.com/watch?v=QiR0ra0ymEY&t=10015s) |
| - [Slides](https://linuxplumbersconf.org/event/11/contributions/1012/attachments/798/1505/DWARF_Extensions_for_Optimized_SIMT-SIMD_GPU_Debugging-LPC2021.pdf) |
| - [DWARF Extensions For Heterogeneous Debugging](https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html) |