On Wed, Apr 16, 2025 at 3:15 PM Cary Coutant <ccout...@gmail.com> wrote: > > Alternatively, what if DW_AT_object_pointer could also take a locdesc-class > with a location description? Then, in cases where 'this' is not a formal > parameter, it could provide a location description in the same manner as the > other captured locals you mentioned (presumably with an fbreg-based > computation).
I don't think that would work because it also needs to carry a DW_AT_type. - Kyle > Whichever way we want to go, it sounds like the DWARF spec should provide the > necessary guidance. This looks like a good start to a proposal—Kyle, would > you like to write one? (See https://dwarfstd.org/comment.html.) > > -cary > > > On Wed, Apr 16, 2025 at 2:11 PM David Blaikie via Dwarf-discuss > <dwarf-discuss@lists.dwarfstd.org> wrote: >> >> >> >> On Wed, Apr 16, 2025 at 8:59 AM Kyle Huey via Dwarf-discuss >> <dwarf-discuss@lists.dwarfstd.org> wrote: >>> >>> This may be more of an implementation question than a spec question, >>> but this seems like the place to have the discussion regardless. >>> >>> C++ debuggers that support expression evaluation need to identify the >>> `this` pointer argument of member functions because C++ permits >>> unqualified access to member variables. DWARF 3 introduced the >>> DW_AT_object_pointer attribute for this purpose, and modern versions >>> of clang and gcc emit it. lldb actually uses this attribute when >>> present to find the this pointer argument, falling back to checking to >>> see if the first formal parameter to the function looks "this-like", >>> while gdb appears to use a name lookup at all times. Regardless, these >>> end up being interoperable for normal member functions. >>> >>> lambdas that capture the `this` of a member function present the same >>> need for debuggers, as unqualified accesses within the lambda can also >>> access member variables of `this`. Both clang and gcc desugar lambdas >>> to an anonymous struct type whose members are the captured variables, >>> with an operator() implementation that contains the body of the >>> lambda. They, however, different in their representation of a captured >>> `this` pointer. >>> >>> In clang's case the DWARF for the operator() contains a >>> DW_TAG_formal_parameter for a `this` parameter which is a pointer to >>> the anonymous struct type. That anonymous struct then contains its own >>> `this` member which is the captured `this`. lldb then contains code in >>> GetLambdaValueObject that recognizes this "double this" pattern and >>> deals with it appropriately. >>> >>> In gcc's case the DWARF for the operator() contains a >>> DW_TAG_formal_parameter for a `__closure` parameter which is a pointer >>> to the anonymous struct type. That anonymous struct contains a >>> `__this` member which is the captured `this`. Additionally, gcc emits >>> a DW_TAG_variable inside the operator() named `this` with the >>> appropriate DW_AT_location that traverses the anonymous struct (as it >>> does for all captured variables). >>> >>> In both cases the compilers emit a DW_AT_object_pointer on the >>> operator() pointing to the anonymous struct pointer parameter. >>> >>> This results in neither debugger being able to understand the output >>> of the opposite compiler. gdb cannot understand what clang has emitted >>> because it looks at the `this` parameter (which points to the >>> anonymous struct) and lldb cannot understand what gcc has emitted >>> because it expects the "double this" pattern. This is also annoying >>> for third party debuggers (like the one I maintain) because we need to >>> recognize and explicitly support both patterns. >>> >>> I haven't done any research into why the compilers chose to emit what >>> they do, but it seems to me[0] like things would be better if clang >>> copied gcc's "repeat the captured variables as locals inside >>> operator()" behavior (which would make gdb understand clang binaries) >>> and then both compilers switched their DW_AT_object_pointers to point >>> to the captured `this` if and only if it exists (which would make lldb >>> understand gcc binaries), ignoring the anonymous compiler-generated >>> struct entirely. Then lambdas that capture `this` would look like >>> member functions to debuggers and "just work" without any special >>> lambda-aware code. >>> >>> This would require at least some clarification in the spec since the >>> subprogram's DW_AT_object_pointer would point to a local, not a >>> parameter, and would point to an object of a different type than the >>> DW_TAG_class_type containing the subprogram (or would exist on a >>> subprogram not contained in a class at all if compilers elided the >>> anonymous struct from DWARF entirely). >>> >>> Any thoughts? >> >> >> As a clang developer, I've some bias for the Clang representation here - and >> lambdas are classes (per the C++ spec) so it still makes sense to me that >> op() is a member function, though, yeah, having its "this" pointer given >> another name since users can't refer to it by that name. >> >> Introducing a bunch of locals that expose the right names/types - seems OK >> to me. >> >> Using object_pointer to refer to a local "this" could have other uses too - >> some languages (I forget which ones) have a scope based object usage, like >> "foo f; f.x();" -> "using (foo f) { x(); }" and so using object_pointer on >> the scope to refer to the local could be used to support that feature. >> -- >> Dwarf-discuss mailing list >> Dwarf-discuss@lists.dwarfstd.org >> https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss -- Dwarf-discuss mailing list Dwarf-discuss@lists.dwarfstd.org https://lists.dwarfstd.org/mailman/listinfo/dwarf-discuss