Skip to content

Commit 707ab21

Browse files
committed
[lldb] Implement formatting of Swift types in C++ frames via interop
Swift types imported in C++ are wrapped by compiler generated types. This patch adds functionality to recognize those types, and present the underlying Swift types via synthetic child providers. rdar://100285269
1 parent 9f793aa commit 707ab21

File tree

18 files changed

+397
-6
lines changed

18 files changed

+397
-6
lines changed

lldb/packages/Python/lldbsuite/test/builders/builder.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ def getLibCxxArgs(self):
139139
"LIBCPP_LIBRARY_DIR={}".format(configuration.libcxx_library_dir)]
140140
return []
141141

142+
def getLLDBSwiftLibs(self):
143+
if configuration.swift_libs_dir:
144+
return ["SWIFT_LIBS_DIR={}".format(
145+
configuration.swift_libs_dir)]
146+
return []
147+
142148
def _getDebugInfoArgs(self, debug_info):
143149
if debug_info is None:
144150
return []
@@ -163,7 +169,8 @@ def getBuildCommand(self, debug_info, architecture=None, compiler=None,
163169
self.getSwiftTargetFlags(architecture), self.getCCSpec(compiler),
164170
self.getSwiftCSpec(), self.getExtraMakeArgs(),
165171
self.getSDKRootSpec(), self.getModuleCacheSpec(),
166-
self.getLibCxxArgs(), self.getCmdLine(dictionary)]
172+
self.getLibCxxArgs(), self.getLLDBSwiftLibs(),
173+
self.getCmdLine(dictionary)]
167174
command = list(itertools.chain(*command_parts))
168175

169176
return command

lldb/packages/Python/lldbsuite/test/configuration.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@
118118
# The clang module cache directory used by clang.
119119
clang_module_cache_dir = None
120120

121+
swift_libs_dir = None
122+
121123
# Test results handling globals
122124
test_result = None
123125

lldb/packages/Python/lldbsuite/test/dotest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,9 @@ def parseOptionsAndInitTestdirs():
428428
configuration.clang_module_cache_dir = os.path.join(
429429
configuration.test_build_dir, 'module-cache-clang')
430430

431+
if args.swift_libs_dir:
432+
configuration.swift_libs_dir = args.swift_libs_dir
433+
431434
if args.lldb_libs_dir:
432435
configuration.lldb_libs_dir = args.lldb_libs_dir
433436

lldb/packages/Python/lldbsuite/test/dotest_args.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ def create_parser():
164164
dest='clang_module_cache_dir',
165165
metavar='The clang module cache directory used by Clang',
166166
help='The clang module cache directory used in the Make files by Clang while building tests. Defaults to <test build directory>/module-cache-clang.')
167+
group.add_argument(
168+
'--swift-libs-dir',
169+
dest='swift_libs_dir',
170+
metavar='The lib directory inside the Swift build directory',
171+
help='The lib directory inside the Swift build directory.')
167172
group.add_argument(
168173
'--lldb-libs-dir',
169174
dest='lldb_libs_dir',

lldb/packages/Python/lldbsuite/test/make/Makefile.rules

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,12 @@ ifndef NO_TEST_COMMON_H
280280
CFLAGS += -include $(THIS_FILE_DIR)/test_common.h
281281
endif
282282

283+
# If C++ interop is enabled, the generated header file will try to include
284+
# SWIFT_LIBS_DIR/swiftToCxx/_SwiftCxxInteroperability.h
285+
ifneq "$(SWIFT_CXX_INTEROP)" ""
286+
CFLAGS += -I$(SWIFT_LIBS_DIR)
287+
endif
288+
283289
CFLAGS += $(NO_LIMIT_DEBUG_INFO_FLAGS) $(ARCH_CFLAGS)
284290
SWIFTFLAGS += $(SWIFTFLAGS_EXTRAS)
285291
SWIFTFLAGS += $(FRAMEWORK_INCLUDES)
@@ -563,6 +569,11 @@ ifneq "$(strip $(DYLIB_SWIFT_SOURCES))" ""
563569
USESWIFTDRIVER = 1
564570
endif
565571

572+
ifneq "$(strip $(SWIFT_SOURCES_FOR_CXX_HEADER))" ""
573+
SWIFT_CXX_HEADER =$(strip $(SWIFT_SOURCES:.swift=.o))
574+
USESWIFTDRIVER = 1
575+
endif
576+
566577
ifeq "$(USESWIFTDRIVER)" "1"
567578
LDFLAGS +=-L"$(SWIFTLIBS)"
568579
ifeq "$(OS)" "Darwin"
@@ -706,6 +717,14 @@ $(SWIFT_OBJC_HEADER): $(SWIFT_SOURCES) $(DYLIB_SWIFT_SOURCES)
706717
-emit-objc-header-path $(SWIFT_OBJC_HEADER)
707718
endif
708719

720+
ifneq "$(SWIFT_CXX_HEADER)" ""
721+
$(SWIFT_CXX_HEADER): $(SWIFT_SOURCES) $(SWIFT_BRIDGING_PCH)
722+
@echo "### Building C++ header from Swift" $<
723+
$(SWIFT_FE) -typecheck $(VPATHSOURCES) \
724+
$(SWIFT_FEFLAGS) $(SWIFT_HFLAGS) -module-name $(MODULENAME) \
725+
-clang-header-expose-decls=all-public -emit-clang-header-path $(SWIFT_CXX_HEADER)
726+
endif
727+
709728
else # USESWIFTDRIVER = 0
710729
#----------------------------------------------------------------------
711730

@@ -850,7 +869,7 @@ endif
850869
%.o: %.c %.d
851870
$(CC) $(CFLAGS) -MT $@ -MD -MP -MF $*.d -c -o $@ $<
852871

853-
%.o: %.cpp %.d $(PCH_OUTPUT)
872+
%.o: %.cpp %.d $(PCH_OUTPUT) $(SWIFT_CXX_HEADER)
854873
$(CXX) $(PCHFLAGS) $(CXXFLAGS) -MT $@ -MD -MP -MF $*.d -c -o $@ $<
855874

856875
%.o: %.m %.d

lldb/source/DataFormatters/FormatManager.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,11 +573,15 @@ FormatManager::GetCandidateLanguages(lldb::LanguageType lang_type) {
573573
case lldb::eLanguageTypeC89:
574574
case lldb::eLanguageTypeC99:
575575
case lldb::eLanguageTypeC11:
576+
// BEGIN SWIFT
577+
return {lldb::eLanguageTypeC_plus_plus, lldb::eLanguageTypeObjC};
576578
case lldb::eLanguageTypeC_plus_plus:
577579
case lldb::eLanguageTypeC_plus_plus_03:
578580
case lldb::eLanguageTypeC_plus_plus_11:
579581
case lldb::eLanguageTypeC_plus_plus_14:
580-
return {lldb::eLanguageTypeC_plus_plus, lldb::eLanguageTypeObjC};
582+
// Swift can format C++ types due to Swift/C++ iterop.
583+
return {lldb::eLanguageTypeC_plus_plus, lldb::eLanguageTypeObjC, lldb::eLanguageTypeSwift};
584+
// END SWIFT
581585
default:
582586
return {lang_type};
583587
}

lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include "lldb/Symbol/Function.h"
2828
#include "lldb/Symbol/Variable.h"
2929
#include "lldb/Symbol/VariableList.h"
30+
#include "lldb/Utility/Log.h"
31+
#include "lldb/Utility/LLDBLog.h"
3032

3133
#include "LogChannelSwift.h"
3234
#include "ObjCRuntimeSyntheticProvider.h"
@@ -856,6 +858,134 @@ SwiftLanguage::GetHardcodedSynthetics() {
856858
}
857859
return nullptr;
858860
});
861+
g_formatters.push_back([](lldb_private::ValueObject &valobj,
862+
lldb::DynamicValueType dyn_type,
863+
FormatManager &format_manager)
864+
-> lldb::SyntheticChildrenSP {
865+
// Try to recognize a Swift type wrapped in a C++ interop wrapper class.
866+
// These types have a typedef from a char to the swift mangled name, and a
867+
// static constexpr char field whose type is the typedef, and whose name
868+
// is $__swift_mangled_name.
869+
870+
Log *log(GetLog(LLDBLog::DataFormatters));
871+
872+
ProcessSP process_sp(valobj.GetProcessSP());
873+
auto *swift_runtime = SwiftLanguageRuntime::Get(process_sp);
874+
if (!swift_runtime) {
875+
LLDB_LOGV(log, "[Matching CxxBridgedSyntheticChildProvider] - "
876+
"Could not get the swift runtime.");
877+
return nullptr;
878+
}
879+
880+
auto scratch_ctx = valobj.GetSwiftScratchContext();
881+
if (!scratch_ctx) {
882+
LLDB_LOGV(log, "[Matching CxxBridgedSyntheticChildProvider] - "
883+
"Could not get the swift scratch context.");
884+
return nullptr;
885+
}
886+
auto &type_system_swift = **scratch_ctx;
887+
888+
// This only makes sense for Clang types.
889+
auto type = valobj.GetCompilerType();
890+
auto tsc = type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
891+
if (!tsc) {
892+
LLDB_LOGV(log, "[Matching CxxBridgedSyntheticChildProvider] - "
893+
"Type is not a clang type.");
894+
return nullptr;
895+
}
896+
897+
// We operate directly on the qualified type because the TypeSystem
898+
// interface doesn't allow us to check for static constexpr members.
899+
auto qual_type = TypeSystemClang::GetQualType(type.GetOpaqueQualType());
900+
auto *record_type = llvm::dyn_cast_or_null<clang::RecordType>(
901+
qual_type.getTypePtrOrNull());
902+
if (!record_type) {
903+
LLDB_LOGV(log, "[Matching CxxBridgedSyntheticChildProvider] - "
904+
"Type is not a record type.");
905+
return nullptr;
906+
}
907+
908+
const clang::RecordDecl *record_decl = record_type->getDecl();
909+
CompilerType swift_type;
910+
911+
for (auto *child_decl : record_decl->decls()) {
912+
auto *var_decl = llvm::dyn_cast<clang::VarDecl>(child_decl);
913+
if (!var_decl)
914+
continue;
915+
916+
auto name = var_decl->getName();
917+
if (name != "__swift_mangled_name")
918+
continue;
919+
920+
const auto *typedef_type =
921+
llvm::dyn_cast<clang::TypedefType>(var_decl->getType());
922+
if (!typedef_type)
923+
break;
924+
925+
auto *decl = typedef_type->getDecl();
926+
if (!decl)
927+
break;
928+
929+
auto swift_name = decl->getName();
930+
if (!swift::Demangle::isMangledName(swift_name))
931+
break;
932+
933+
swift_type = type_system_swift.GetTypeFromMangledTypename(
934+
ConstString(swift_name));
935+
break;
936+
}
937+
938+
if (!swift_type) {
939+
LLDB_LOGV(log, "[Matching CxxBridgedSyntheticChildProvider] - "
940+
"Did not find Swift type.");
941+
return nullptr;
942+
}
943+
944+
auto swift_valobj =
945+
SwiftLanguageRuntime::ExtractSwiftValueObjectFromCxxWrapper(valobj);
946+
if (!swift_valobj) {
947+
StreamString clang_desc;
948+
type.DumpTypeDescription(&clang_desc);
949+
950+
StreamString swift_desc;
951+
type.DumpTypeDescription(&swift_desc);
952+
953+
LLDB_LOGF(log,
954+
"[Matching CxxBridgedSyntheticChildProvider] - "
955+
"Was not able to extract Swift value object. Clang type: %s. "
956+
"Swift type: %s",
957+
clang_desc.GetData(), swift_desc.GetData());
958+
return nullptr;
959+
}
960+
// Cast it to a Swift type since thhe swift runtime expects a Swift value
961+
// object.
962+
auto casted_to_swift = swift_valobj->Cast(swift_type);
963+
if (!casted_to_swift) {
964+
LLDB_LOGF(log, "[Matching CxxBridgedSyntheticChildProvider] - "
965+
"Could not cast value object to swift type.");
966+
return nullptr;
967+
}
968+
969+
TypeAndOrName type_or_name;
970+
Address address;
971+
Value::ValueType value_type;
972+
// Try to find the dynamic type of the Swift type.
973+
// TODO: find a way to get the dyamic value type from the
974+
// command.
975+
if (swift_runtime->GetDynamicTypeAndAddress(
976+
*casted_to_swift.get(),
977+
lldb::DynamicValueType::eDynamicCanRunTarget, type_or_name,
978+
address, value_type)) {
979+
if (type_or_name.HasCompilerType()) {
980+
swift_type = type_or_name.GetCompilerType();
981+
// Cast it to the more specific type.
982+
casted_to_swift = casted_to_swift->Cast(swift_type);
983+
}
984+
}
985+
986+
return swift_runtime->GetCxxBridgedSyntheticChildProvider(
987+
casted_to_swift);
988+
});
859989
});
860990

861991
return g_formatters;

0 commit comments

Comments
 (0)