This is an archive of the discontinued LLVM Phabricator instance.

[llvm][DebugInfo] Add DW_TAG_imported_declaration to accelerator tables
ClosedPublic

Authored by Michael137 on Feb 6 2023, 7:09 AM.

Details

Summary

Summary

After this patch, DW_TAG_imported_declarations will be emitted into
the DWARF accelerator tables (under .apple_namespaces)

Motivation

Currently LLDB expression evaluation doesn't see through namespace
aliases. This is because LLDB only considers namespaces that are
part of .apple_namespaces when building a nested namespace
identifier for C++, which currently doesn't include import
declarations. The alternative to putting imports into accelerator
tables is to do a linear scan of a DW_TAG_namespace and look
for import declarations that look like they would satisfy the lookup
request, which is prohibitively expensive.

Testing

  • Added unit-test

Diff Detail

Event Timeline

Michael137 created this revision.Feb 6 2023, 7:09 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 6 2023, 7:09 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
Michael137 requested review of this revision.Feb 6 2023, 7:09 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 6 2023, 7:09 AM
Michael137 added inline comments.Feb 6 2023, 7:13 AM
llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
1295

Since import declarations could have empty names I'll have to decide what to do here w.r.t. accelerator tables. The spec says in the case of an empty name we can refer to the entity by the name of the entity it is importing.

It'd be good if this issue were submitted to the DWARF committee as a fix for the .debug_names accelerator tables.

I don't /think/ you need unnamed entries in the index - since these entries are only for finding named entities by unqualified name, so an unnamed using namespace doesn't introduce any new unqualified names?

I guess if the user writes "x::y" (and the code has "z::y" defined and "using namespace z" in namespace x) then you need some breadcrumb that when you do unqualified lookup for "y" and unqualified lookup for "x" you can see that they're connected/actually would resolve to that name? How does this work currently for "z::y"? You do lookup for "y" then check its parent DIE and see that it's "z" and so it satisfies the lookup?

Michael137 added a comment.EditedFeb 6 2023, 9:18 AM

It'd be good if this issue were submitted to the DWARF committee as a fix for the .debug_names accelerator tables.

I don't /think/ you need unnamed entries in the index - since these entries are only for finding named entities by unqualified name, so an unnamed using namespace doesn't introduce any new unqualified names?

I guess if the user writes "x::y" (and the code has "z::y" defined and "using namespace z" in namespace x) then you need some breadcrumb that when you do unqualified lookup for "y" and unqualified lookup for "x" you can see that they're connected/actually would resolve to that name? How does this work currently for "z::y"? You do lookup for "y" then check its parent DIE and see that it's "z" and so it satisfies the lookup?

I don't /think/ you need unnamed entries in the index - since these entries are only for finding named entities by unqualified name, so an unnamed using namespace doesn't introduce any new unqualified names?

Actually I'm not quite sure how we can get empty import declarations (since using namespace Foo is represented by DW_TAG_imported_module)

I guess if the user writes "x::y" (and the code has "z::y" defined and "using namespace z" in namespace x) then you need some breadcrumb that when you do unqualified lookup for "y" and unqualified lookup for "x" you can see that they're connected/actually would resolve to that name?

Good point, currently this isn't supported. And this patch wouldn't help with that. To support x::y in LLDB we'd have to add the DW_TAG_imported_module into the accelerator table too, under the name of the module it's importing (?) Though I'd be fine with not adding support for this for now

How does this work currently for "z::y"? You do lookup for "y" then check its parent DIE and see that it's "z" and so it satisfies the lookup?

The order of operations is:

  1. Lookup z. Finds namespace
  2. Lookup y. Finds namespace
  3. Check that y "is contained in" z (accounts for inline namespaces between the two). This is purely based on walking through the parent DIEs of y

It'd be good if this issue were submitted to the DWARF committee as a fix for the .debug_names accelerator tables.

I don't /think/ you need unnamed entries in the index - since these entries are only for finding named entities by unqualified name, so an unnamed using namespace doesn't introduce any new unqualified names?

I guess if the user writes "x::y" (and the code has "z::y" defined and "using namespace z" in namespace x) then you need some breadcrumb that when you do unqualified lookup for "y" and unqualified lookup for "x" you can see that they're connected/actually would resolve to that name? How does this work currently for "z::y"? You do lookup for "y" then check its parent DIE and see that it's "z" and so it satisfies the lookup?

I don't /think/ you need unnamed entries in the index - since these entries are only for finding named entities by unqualified name, so an unnamed using namespace doesn't introduce any new unqualified names?

Actually I'm not quite sure how we can get empty import declarations (since using namespace Foo is represented by DW_TAG_imported_module)

Oh, right, sorry, didn't notice the distinction between imported module and imported declaration. Ah, you're talking about code like this:

namespace ns1 {
struct t1 { };
};
namespace ns2 {
using ns1::t1;
}
namespace ns3 {
using t2 = ns1::t1;
}

So the DWARF for the first DW_TAG_imported_declaration (in ns2) won't have a name - it inherits the name from the entity.

Oh... seems clang just doesn't emit DWARF for the ns2::t1 case - if you try to use that type it resolves to ns1::t1, which is a (minor) bug. I implemented the imported declaration stuff years ago, and it's... not great (Clang doesn't track usage of using namespaces especially - and I guess unnamed using decls - makes it hard to emit them only when needed, and the usual DWARF-reachability that helps trim DWARF during IR optimization/linking can't kick in because nothing references the imported namespaces especially)

I guess if the user writes "x::y" (and the code has "z::y" defined and "using namespace z" in namespace x) then you need some breadcrumb that when you do unqualified lookup for "y" and unqualified lookup for "x" you can see that they're connected/actually would resolve to that name?

Good point, currently this isn't supported. And this patch wouldn't help with that. To support x::y in LLDB we'd have to add the DW_TAG_imported_module into the accelerator table too, under the name of the module it's importing (?) Though I'd be fine with not adding support for this for now

Ah, right, fair enough.

How does this work currently for "z::y"? You do lookup for "y" then check its parent DIE and see that it's "z" and so it satisfies the lookup?

The order of operations is:

  1. Lookup z. Finds namespace
  2. Lookup y. Finds namespace
  3. Check that y "is contained in" z (accounts for inline namespaces between the two). This is purely based on walking through the parent DIEs of y

yeah, easy for the canonical/original namespace - doing that for imported namespaces/entities would be tricky. I guess, yeah, for named imported entities it's possible to put the name in the index, pointing to the imported entity - then you can do the walk up.

But that doesn't work with unnamed using decls where all the names of the other namespace are brought in. :/

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
1295

You could go find the name of the entity it's importing to support this, I suppose? Maybe worth a comment/FIXME/etc?

You could try adding a temporary/non-committed assertion here that Name is !empty & bootstrap clang or the like to see if there are cases where we emit an imported declaration with an empty name?

Michael137 added inline comments.Feb 6 2023, 11:12 AM
llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
1295

Ah apparently things like:

using ::nullptr_t;                        
using ::ptrdiff_t _LIBCPP_USING_IF_EXISTS;
using ::size_t _LIBCPP_USING_IF_EXISTS;

Generate empty DW_AT_imported_declaration entries. But apparently this is not supported for namespaces, so I think we can just not handle the empty name case and add a comment as to why we're not doing that.

Michael137 added a comment.EditedFeb 6 2023, 11:13 AM

yeah, easy for the canonical/original namespace - doing that for imported namespaces/entities would be tricky. I guess, yeah, for named imported entities it's possible to put the name in the index, pointing to the imported entity - then you can do the walk up.

Yup that's exactly how I've prototyped it in LLDB: https://reviews.llvm.org/D143398

But that doesn't work with unnamed using decls where all the names of the other namespace are brought in. :/

True, I think I'll just proceed with not supporting the unnamed (and using namespace ...) cases for now

  • Add FIXME
Michael137 retitled this revision from [WIP][llvm][DebugInfo] Add DW_TAG_imported_declaration to accelerator tables to [llvm][DebugInfo] Add DW_TAG_imported_declaration to accelerator tables.Feb 6 2023, 11:40 AM
  • Added an unnamed import declaration to test

It'd be good if this issue were submitted to the DWARF committee as a fix for the .debug_names accelerator tables.

Would make sense, I'll put something up

Currently section 6.1.1 of the DWARFv5 spec says:

The name index must contain an entry for each debugging information entry that
defines a named subprogram, label, variable, type, or namespace, subject to the
following rules:

Probably just need to adjust this list to include import declarations

It'd be good if this issue were submitted to the DWARF committee as a fix for the .debug_names accelerator tables.

Sounds good to me. Just to clarify — I don't think that should block adopting this extension in LLVM though, do you agree?

aprantl accepted this revision.Feb 9 2023, 11:19 AM
This revision is now accepted and ready to land.Feb 9 2023, 11:19 AM
This revision was landed with ongoing or failed builds.Feb 9 2023, 5:34 PM
This revision was automatically updated to reflect the committed changes.