Skip to content

Commit 12f3d97

Browse files
committed
[lldb] Support recursive record types in CTF
Support recursive record types in CTF, for example a struct that contains a pointer to itself: struct S { struct S *n; }; We are now more lazy when creating LLDB types. When encountering a record type (struct or union) we create a forward declaration and only complete it when requested. Differential revision: https://reviews.llvm.org/D156498
1 parent c835dca commit 12f3d97

File tree

4 files changed

+60
-15
lines changed

4 files changed

+60
-15
lines changed

lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -503,26 +503,59 @@ SymbolFileCTF::CreateFunction(const CTFFunction &ctf_function) {
503503
llvm::Expected<lldb::TypeSP>
504504
SymbolFileCTF::CreateRecord(const CTFRecord &ctf_record) {
505505
const clang::TagTypeKind tag_kind = TranslateRecordKind(ctf_record.kind);
506-
507506
CompilerType record_type =
508507
m_ast->CreateRecordType(nullptr, OptionalClangModuleID(), eAccessPublic,
509508
ctf_record.name.data(), tag_kind, eLanguageTypeC);
509+
m_compiler_types[record_type.GetOpaqueQualType()] = &ctf_record;
510+
Declaration decl;
511+
return MakeType(ctf_record.uid, ConstString(ctf_record.name), ctf_record.size,
512+
nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID,
513+
decl, record_type, lldb_private::Type::ResolveState::Forward);
514+
}
515+
516+
bool SymbolFileCTF::CompleteType(CompilerType &compiler_type) {
517+
// Check if we have a CTF type for the given incomplete compiler type.
518+
auto it = m_compiler_types.find(compiler_type.GetOpaqueQualType());
519+
if (it == m_compiler_types.end())
520+
return false;
521+
522+
const CTFType *ctf_type = it->second;
523+
assert(ctf_type && "m_compiler_types should only contain valid CTF types");
524+
525+
// We only support resolving record types.
526+
assert(ctf_type->kind == CTFType::Kind::eStruct ||
527+
ctf_type->kind == CTFType::Kind::eUnion);
510528

511-
m_ast->StartTagDeclarationDefinition(record_type);
512-
for (const CTFRecord::Field &field : ctf_record.fields) {
513-
if (Type *field_type = ResolveTypeUID(field.type)) {
514-
const uint32_t field_size = field_type->GetByteSize(nullptr).value_or(0);
515-
TypeSystemClang::AddFieldToRecordType(record_type, field.name,
516-
field_type->GetFullCompilerType(),
517-
eAccessPublic, field_size);
529+
// Cast to the appropriate CTF type.
530+
const CTFRecord *ctf_record = static_cast<const CTFRecord *>(ctf_type);
531+
532+
// If any of the fields are incomplete, we cannot complete the type.
533+
for (const CTFRecord::Field &field : ctf_record->fields) {
534+
if (!ResolveTypeUID(field.type)) {
535+
LLDB_LOG(GetLog(LLDBLog::Symbols),
536+
"Cannot complete type {0} because field {1} is incomplete",
537+
ctf_type->uid, field.type);
538+
return false;
518539
}
519540
}
520-
m_ast->CompleteTagDeclarationDefinition(record_type);
521541

522-
Declaration decl;
523-
return MakeType(ctf_record.uid, ConstString(ctf_record.name), ctf_record.size,
524-
nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID,
525-
decl, record_type, lldb_private::Type::ResolveState::Full);
542+
// Complete the record type.
543+
m_ast->StartTagDeclarationDefinition(compiler_type);
544+
for (const CTFRecord::Field &field : ctf_record->fields) {
545+
Type *field_type = ResolveTypeUID(field.type);
546+
assert(field_type && "field must be complete");
547+
const uint32_t field_size = field_type->GetByteSize(nullptr).value_or(0);
548+
TypeSystemClang::AddFieldToRecordType(compiler_type, field.name,
549+
field_type->GetFullCompilerType(),
550+
eAccessPublic, field_size);
551+
}
552+
m_ast->CompleteTagDeclarationDefinition(compiler_type);
553+
554+
// Now that the compiler type is no longer incomplete we don't need to
555+
// remember it anymore.
556+
m_compiler_types.erase(compiler_type.GetOpaqueQualType());
557+
558+
return true;
526559
}
527560

528561
llvm::Expected<lldb::TypeSP>
@@ -960,7 +993,6 @@ lldb_private::Type *SymbolFileCTF::ResolveTypeUID(lldb::user_id_t type_uid) {
960993
if (!ctf_type)
961994
return nullptr;
962995

963-
m_types[type_uid] = TypeSP();
964996
Log *log = GetLog(LLDBLog::Symbols);
965997

966998
llvm::Expected<TypeSP> type_or_error = CreateType(ctf_type);

lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class SymbolFileCTF : public lldb_private::SymbolFileCommon {
9393
return std::nullopt;
9494
}
9595

96-
bool CompleteType(CompilerType &compiler_type) override { return false; }
96+
bool CompleteType(CompilerType &compiler_type) override;
9797

9898
uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr,
9999
lldb::SymbolContextItem resolve_scope,
@@ -247,6 +247,11 @@ class SymbolFileCTF : public lldb_private::SymbolFileCommon {
247247

248248
std::vector<std::unique_ptr<CTFType>> m_ctf_types;
249249

250+
/// To complete types, we need a way to map (imcomplete) compiler types back
251+
/// to parsed CTF types.
252+
llvm::DenseMap<lldb::opaque_compiler_type_t, const CTFType *>
253+
m_compiler_types;
254+
250255
llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types;
251256

252257
std::vector<lldb::FunctionSP> m_functions;

lldb/test/API/macosx/ctf/TestCTF.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,5 @@ def do_test(self):
9191
"}",
9292
],
9393
)
94+
95+
self.expect("type lookup RecursiveStruct", substrs=["RecursiveStruct *n;"])

lldb/test/API/macosx/ctf/test.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@ struct LargeStruct {
3636
int b;
3737
};
3838

39+
struct RecursiveStruct {
40+
struct RecursiveStruct *n;
41+
};
42+
3943
MyStructT foo;
4044
struct ForwardDecl *forward;
4145
struct LargeStruct bar;
46+
struct RecursiveStruct ke;
4247

4348
void populate(MyInt i) {
4449
foo.n.i = i;
@@ -52,6 +57,7 @@ void populate(MyInt i) {
5257
foo.f = NULL;
5358
forward = NULL;
5459
bar.b = i;
60+
ke.n = NULL;
5561
}
5662

5763
int main(int argc, char** argv) {

0 commit comments

Comments
 (0)