<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Wed, Apr 16, 2025 at 8:59 AM Kyle Huey via Dwarf-discuss <<a href="mailto:dwarf-discuss@lists.dwarfstd.org">dwarf-discuss@lists.dwarfstd.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This may be more of an implementation question than a spec question,<br>
but this seems like the place to have the discussion regardless.<br>
<br>
C++ debuggers that support expression evaluation need to identify the<br>
`this` pointer argument of member functions because C++ permits<br>
unqualified access to member variables. DWARF 3 introduced the<br>
DW_AT_object_pointer attribute for this purpose, and modern versions<br>
of clang and gcc emit it. lldb actually uses this attribute when<br>
present to find the this pointer argument, falling back to checking to<br>
see if the first formal parameter to the function looks "this-like",<br>
while gdb appears to use a name lookup at all times. Regardless, these<br>
end up being interoperable for normal member functions.<br>
<br>
lambdas that capture the `this` of a member function present the same<br>
need for debuggers, as unqualified accesses within the lambda can also<br>
access member variables of `this`. Both clang and gcc desugar lambdas<br>
to an anonymous struct type whose members are the captured variables,<br>
with an operator() implementation that contains the body of the<br>
lambda. They, however, different in their representation of a captured<br>
`this` pointer.<br>
<br>
In clang's case the DWARF for the operator() contains a<br>
DW_TAG_formal_parameter for a `this` parameter which is a pointer to<br>
the anonymous struct type. That anonymous struct then contains its own<br>
`this` member which is the captured `this`. lldb then contains code in<br>
GetLambdaValueObject that recognizes this "double this" pattern and<br>
deals with it appropriately.<br>
<br>
In gcc's case the DWARF for the operator() contains a<br>
DW_TAG_formal_parameter for a `__closure` parameter which is a pointer<br>
to the anonymous struct type. That anonymous struct contains a<br>
`__this` member which is the captured `this`. Additionally, gcc emits<br>
a DW_TAG_variable inside the operator() named `this` with the<br>
appropriate DW_AT_location that traverses the anonymous struct (as it<br>
does for all captured variables).<br>
<br>
In both cases the compilers emit a DW_AT_object_pointer on the<br>
operator() pointing to the anonymous struct pointer parameter.<br>
<br>
This results in neither debugger being able to understand the output<br>
of the opposite compiler. gdb cannot understand what clang has emitted<br>
because it looks at the `this` parameter (which points to the<br>
anonymous struct) and lldb cannot understand what gcc has emitted<br>
because it expects the "double this" pattern. This is also annoying<br>
for third party debuggers (like the one I maintain) because we need to<br>
recognize and explicitly support both patterns.<br>
<br>
I haven't done any research into why the compilers chose to emit what<br>
they do, but it seems to me[0] like things would be better if clang<br>
copied gcc's "repeat the captured variables as locals inside<br>
operator()" behavior (which would make gdb understand clang binaries)<br>
and then both compilers switched their DW_AT_object_pointers to point<br>
to the captured `this` if and only if it exists (which would make lldb<br>
understand gcc binaries), ignoring the anonymous compiler-generated<br>
struct entirely. Then lambdas that capture `this` would look like<br>
member functions to debuggers and "just work" without any special<br>
lambda-aware code.<br>
<br>
This would require at least some clarification in the spec since the<br>
subprogram's DW_AT_object_pointer would point to a local, not a<br>
parameter, and would point to an object of a different type than the<br>
DW_TAG_class_type containing the subprogram (or would exist on a<br>
subprogram not contained in a class at all if compilers elided the<br>
anonymous struct from DWARF entirely).<br>
<br>
Any thoughts?<br></blockquote><div><br>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.<br><br>Introducing a bunch of locals that expose the right names/types - seems OK to me.<br><br>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.</div></div></div>