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).

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

Reply via email to