Skip to content

Commit 98abfda

Browse files
committed
[lldb][SymbolFileDWARF] Share GetDIEToType between SymbolFiles of a SymbolFileDWARFDebugMap (llvm#120569)
The problem here manifests as follows: 1. We are stopped in main.o, so the first `ParseTypeFromDWARF` on `FooImpl<char>` gets called on `main.o`'s SymbolFile. This adds a mapping from *declaration die* -> `TypeSP` into `main.o`'s `GetDIEToType` map. 2. We then `CompleteType(FooImpl<char>)`. Depending on the order of entries in the debug-map, this might call `CompleteType` on `lib.o`'s SymbolFile. In which case, `GetDIEToType().lookup(decl_die)` will return a `nullptr`. This is already a bit iffy because some of the surrounding code assumes we don't call `CompleteTypeFromDWARF` with a `nullptr` `Type*`. E.g., `CompleteEnumType` blindly dereferences it (though enums will never encounter this because their definition is fetched in ParseEnum, unlike for structures). 3. While in `CompleteTypeFromDWARF`, we call `ParseTypeFromDWARF` again. This will parse the member function `FooImpl::Create` and its return type which is a typedef to `FooImpl*`. But now we're inside `lib.o`'s SymbolFile, so we call it on the definition DIE. In step (2) we just inserted a `nullptr` into `GetDIEToType` for the definition DIE, so we trivially return a `nullptr` from `ParseTypeFromDWARF`. Instead of reporting back this parse failure to the user LLDB trucks on and marks `FooImpl::Ref` to be `void*`. This test-case will trigger an assert in `TypeSystemClang::VerifyDecl` even if we just `frame var` (but only in debug-builds). In release builds where this function is a no-op, we'll create an incorrect Clang AST node for the `Ref` typedef. The proposed fix here is to share the `GetDIEToType` map between SymbolFiles if a debug-map exists. **Alternatives considered** * Check the `GetDIEToType` map of the `SymbolFile` that the declaration DIE belongs to. The assumption here being that if we called `ParseTypeFromDWARF` on a declaration, the `GetDIEToType` map that the result was inserted into was the one on that DIE's SymbolFile. This was the first version of this patch, but that felt like a weaker version sharing the map. It complicates the code in `CompleteType` and is less consistent with the other bookkeeping structures we already share between SymbolFiles * Return from `SymbolFileDWARF::CompleteType` if there is no type in the current `GetDIEToType`. Then `SymbolFileDWARFDebugMap::CompleteType` could continue to the next `SymbolFile` which does own the type. But that didn't quite work because we remove the `GetForwardCompilerTypeToDie` entry in `SymbolFile::CompleteType`, which `SymbolFileDWARFDebugMap::CompleteType` relies upon for iterating (cherry picked from commit 28d1490)
1 parent 58eafe7 commit 98abfda

File tree

11 files changed

+91
-8
lines changed

11 files changed

+91
-8
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3892,8 +3892,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
38923892
static_cast<DWARFASTParserClang *>(
38933893
SymbolFileDWARF::GetDWARFParser(*dst_class_die.GetCU()));
38943894
auto link = [&](DWARFDIE src, DWARFDIE dst) {
3895-
SymbolFileDWARF::DIEToTypePtr &die_to_type =
3896-
dst_class_die.GetDWARF()->GetDIEToType();
3895+
auto &die_to_type = dst_class_die.GetDWARF()->GetDIEToType();
38973896
clang::DeclContext *dst_decl_ctx =
38983897
dst_dwarf_ast_parser->m_die_to_decl_ctx[dst.GetDIE()];
38993898
if (dst_decl_ctx)

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,13 @@ static ConstString GetDWARFMachOSegmentName() {
481481
return g_dwarf_section_name;
482482
}
483483

484+
llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> &
485+
SymbolFileDWARF::GetDIEToType() {
486+
if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile())
487+
return debug_map_symfile->GetDIEToType();
488+
return m_die_to_type;
489+
}
490+
484491
llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> &
485492
SymbolFileDWARF::GetForwardDeclCompilerTypeToDIE() {
486493
if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile())
@@ -1674,6 +1681,8 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
16741681
if (!dwarf_ast)
16751682
return false;
16761683
Type *type = GetDIEToType().lookup(decl_die.GetDIE());
1684+
assert(type);
1685+
16771686
if (decl_die != def_die) {
16781687
GetDIEToType()[def_die.GetDIE()] = type;
16791688
DWARFASTParserClang *ast_parser =

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,7 @@ class SymbolFileDWARF : public SymbolFileCommon {
356356
m_file_index = file_index;
357357
}
358358

359-
typedef llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> DIEToTypePtr;
360-
361-
virtual DIEToTypePtr &GetDIEToType() { return m_die_to_type; }
359+
virtual llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> &GetDIEToType();
362360

363361
virtual llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> &
364362
GetForwardDeclCompilerTypeToDIE();
@@ -562,7 +560,7 @@ class SymbolFileDWARF : public SymbolFileCommon {
562560
UniqueDWARFASTTypeMap m_unique_ast_type_map;
563561
// A map from DIE to lldb_private::Type. For record type, the key might be
564562
// either declaration DIE or definition DIE.
565-
DIEToTypePtr m_die_to_type;
563+
llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> m_die_to_type;
566564
DIEToVariableSP m_die_to_variable_sp;
567565
// A map from CompilerType to the struct/class/union/enum DIE (might be a
568566
// declaration or a definition) that is used to construct it.

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
305305
return m_unique_ast_type_map;
306306
}
307307

308+
llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> &GetDIEToType() {
309+
return m_die_to_type;
310+
}
311+
308312
// OSOEntry
309313
class OSOEntry {
310314
public:
@@ -343,6 +347,8 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
343347
llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef>
344348
m_forward_decl_compiler_type_to_die;
345349
UniqueDWARFASTTypeMap m_unique_ast_type_map;
350+
llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> m_die_to_type;
351+
346352
DebugMap m_debug_map;
347353

348354
// When an object file from the debug map gets parsed in

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ bool SymbolFileDWARFDwo::ParseVendorDWARFOpcode(
102102
return GetBaseSymbolFile().ParseVendorDWARFOpcode(op, opcodes, offset, stack);
103103
}
104104

105-
SymbolFileDWARF::DIEToTypePtr &SymbolFileDWARFDwo::GetDIEToType() {
105+
llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> &
106+
SymbolFileDWARFDwo::GetDIEToType() {
106107
return GetBaseSymbolFile().GetDIEToType();
107108
}
108109

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class SymbolFileDWARFDwo : public SymbolFileDWARF {
7070
SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref) override;
7171

7272
protected:
73-
DIEToTypePtr &GetDIEToType() override;
73+
llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> &GetDIEToType() override;
7474

7575
DIEToVariableSP &GetDIEToVariable() override;
7676

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := lib.cpp main.cpp
2+
3+
include Makefile.rules
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test import lldbutil
5+
6+
7+
class TestCaseTypedefToOuterFwd(TestBase):
8+
"""
9+
We find a global variable whose type is forward declared
10+
(whose definition is in either main.o or lib.o). We then
11+
try to get the 'Ref' typedef nested within that forward
12+
declared type. This test makes sure we correctly resolve
13+
this typedef.
14+
15+
We test this for two cases, where the definition lives
16+
in main.o or lib.o.
17+
"""
18+
19+
def check_global_var(self, target, name: str):
20+
var = target.FindFirstGlobalVariable(name)
21+
self.assertSuccess(var.GetError(), f"Found {name}")
22+
23+
var_type = var.GetType()
24+
self.assertTrue(var_type)
25+
26+
impl = var_type.GetPointeeType()
27+
self.assertTrue(impl)
28+
29+
ref = impl.FindDirectNestedType("Ref")
30+
self.assertTrue(ref)
31+
32+
self.assertEqual(ref.GetCanonicalType(), var_type)
33+
34+
def test(self):
35+
self.build()
36+
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
37+
self.check_global_var(target, "gLibExternalDef")
38+
self.check_global_var(target, "gMainExternalDef")
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include "lib.h"
2+
3+
template <typename T> struct FooImpl {
4+
using Ref = FooImpl<T> *;
5+
6+
Ref Create() { return new FooImpl<T>(); }
7+
};
8+
9+
FooImpl<char> gLibLocalDef;
10+
BarImpl<char> *gLibExternalDef = nullptr;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef LIB_H_IN
2+
#define LIB_H_IN
3+
4+
template <typename T> struct FooImpl;
5+
template <typename T> struct BarImpl;
6+
7+
#endif // LIB_H_IN
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include "lib.h"
2+
3+
template <typename T> struct BarImpl {
4+
using Ref = BarImpl<T> *;
5+
6+
Ref Create() { return new BarImpl<T>(); }
7+
};
8+
9+
BarImpl<char> gMainLocalDef;
10+
FooImpl<char> *gMainExternalDef = nullptr;
11+
12+
int main() { return 0; }

0 commit comments

Comments
 (0)