|
16 | 16 | #include "Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h"
|
17 | 17 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
|
18 | 18 | #include "Plugins/TypeSystem/Swift/SwiftDemangle.h"
|
| 19 | +#include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h" |
19 | 20 | #include "lldb/DataFormatters/FormattersHelpers.h"
|
20 | 21 | #include "lldb/DataFormatters/StringPrinter.h"
|
21 | 22 | #include "lldb/Symbol/CompilerType.h"
|
| 23 | +#include "lldb/Target/ExecutionContext.h" |
22 | 24 | #include "lldb/Target/Process.h"
|
23 | 25 | #include "lldb/Utility/ConstString.h"
|
24 | 26 | #include "lldb/Utility/DataBufferHeap.h"
|
|
28 | 30 | #include "lldb/Utility/Timer.h"
|
29 | 31 | #include "lldb/ValueObject/ValueObject.h"
|
30 | 32 | #include "lldb/lldb-enumerations.h"
|
| 33 | +#include "swift/ABI/Task.h" |
31 | 34 | #include "swift/AST/Types.h"
|
32 | 35 | #include "swift/Demangling/Demangle.h"
|
33 | 36 | #include "swift/Demangling/ManglingMacros.h"
|
34 | 37 | #include "llvm/ADT/STLExtras.h"
|
35 | 38 | #include "llvm/ADT/StringRef.h"
|
| 39 | +#include "llvm/Support/Error.h" |
36 | 40 | #include "llvm/Support/FormatAdapters.h"
|
37 | 41 | #include "llvm/Support/raw_ostream.h"
|
38 | 42 | #include <optional>
|
@@ -950,6 +954,188 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
|
950 | 954 | ValueObjectSP m_child_tasks_sp;
|
951 | 955 | ValueObjectSP m_is_running_sp;
|
952 | 956 | };
|
| 957 | + |
| 958 | +class TaskGroupSyntheticFrontEnd : public SyntheticChildrenFrontEnd { |
| 959 | +public: |
| 960 | + TaskGroupSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) |
| 961 | + : SyntheticChildrenFrontEnd(*valobj_sp.get()) { |
| 962 | + bool is_64bit = false; |
| 963 | + if (auto target_sp = m_backend.GetTargetSP()) |
| 964 | + is_64bit = target_sp->GetArchitecture().GetTriple().isArch64Bit(); |
| 965 | + |
| 966 | + std::optional<uint32_t> concurrency_version; |
| 967 | + if (auto process_sp = m_backend.GetProcessSP()) |
| 968 | + concurrency_version = |
| 969 | + SwiftLanguageRuntime::FindConcurrencyDebugVersion(*process_sp); |
| 970 | + |
| 971 | + m_is_supported_target = is_64bit && concurrency_version.value_or(0) == 1; |
| 972 | + } |
| 973 | + |
| 974 | + llvm::Expected<uint32_t> CalculateNumChildren() override { |
| 975 | + if (!m_is_supported_target) |
| 976 | + return m_backend.GetNumChildren(); |
| 977 | + |
| 978 | + return m_task_addrs.size(); |
| 979 | + } |
| 980 | + |
| 981 | + bool MightHaveChildren() override { return true; } |
| 982 | + |
| 983 | + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { |
| 984 | + if (!m_is_supported_target) |
| 985 | + return m_backend.GetChildAtIndex(idx); |
| 986 | + |
| 987 | + if (!m_task_type || idx >= m_task_addrs.size()) |
| 988 | + return {}; |
| 989 | + |
| 990 | + if (auto valobj_sp = m_children[idx]) |
| 991 | + return valobj_sp; |
| 992 | + |
| 993 | + addr_t task_addr = m_task_addrs[idx]; |
| 994 | + auto child_name = ("[" + Twine(idx) + "]").str(); |
| 995 | + auto task_sp = ValueObject::CreateValueObjectFromAddress( |
| 996 | + child_name, task_addr, m_backend.GetExecutionContextRef(), m_task_type, |
| 997 | + false); |
| 998 | + if (auto synthetic_sp = task_sp->GetSyntheticValue()) |
| 999 | + task_sp = synthetic_sp; |
| 1000 | + |
| 1001 | + m_children[idx] = task_sp; |
| 1002 | + return task_sp; |
| 1003 | + } |
| 1004 | + |
| 1005 | + size_t GetIndexOfChildWithName(ConstString name) override { |
| 1006 | + if (!m_is_supported_target) |
| 1007 | + return m_backend.GetIndexOfChildWithName(name); |
| 1008 | + |
| 1009 | + StringRef buf = name.GetStringRef(); |
| 1010 | + size_t idx = UINT32_MAX; |
| 1011 | + if (buf.consume_front("[") && !buf.consumeInteger(10, idx) && buf == "]") |
| 1012 | + return idx; |
| 1013 | + return UINT32_MAX; |
| 1014 | + } |
| 1015 | + |
| 1016 | + lldb::ChildCacheState Update() override { |
| 1017 | + if (!m_is_supported_target) |
| 1018 | + return ChildCacheState::eReuse; |
| 1019 | + |
| 1020 | + m_task_addrs.clear(); |
| 1021 | + m_children.clear(); |
| 1022 | + |
| 1023 | + if (!m_task_type) |
| 1024 | + if (auto target_sp = m_backend.GetTargetSP()) { |
| 1025 | + if (auto ts_or_err = target_sp->GetScratchTypeSystemForLanguage( |
| 1026 | + eLanguageTypeSwift)) { |
| 1027 | + if (auto *ts = llvm::dyn_cast_or_null<TypeSystemSwiftTypeRef>( |
| 1028 | + ts_or_err->get())) |
| 1029 | + // TypeMangling for "Swift.UnsafeCurrentTask" |
| 1030 | + m_task_type = ts->GetTypeFromMangledTypename(ConstString("$sSctD")); |
| 1031 | + } else { |
| 1032 | + LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters | LLDBLog::Types), |
| 1033 | + ts_or_err.takeError(), |
| 1034 | + "could not get Swift type system for Task synthetic " |
| 1035 | + "provider: {0}"); |
| 1036 | + return ChildCacheState::eReuse; |
| 1037 | + } |
| 1038 | + } |
| 1039 | + |
| 1040 | + if (!m_task_type) |
| 1041 | + return ChildCacheState::eReuse; |
| 1042 | + |
| 1043 | + // Get the (opaque) pointer to the `TaskGroupBase`. |
| 1044 | + addr_t task_group_ptr = LLDB_INVALID_ADDRESS; |
| 1045 | + if (auto opaque_group_ptr_sp = m_backend.GetChildMemberWithName("_group")) |
| 1046 | + task_group_ptr = |
| 1047 | + opaque_group_ptr_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); |
| 1048 | + |
| 1049 | + TaskGroupBase task_group{m_backend.GetProcessSP(), task_group_ptr}; |
| 1050 | + |
| 1051 | + // Get the TaskGroup's child tasks by getting all tasks in the range |
| 1052 | + // [FirstChild, LastChild]. |
| 1053 | + // |
| 1054 | + // Child tasks are connected together using ChildFragment::NextChild. |
| 1055 | + Status status; |
| 1056 | + auto current_task = task_group.getFirstChild(status); |
| 1057 | + auto last_task = task_group.getLastChild(status); |
| 1058 | + while (current_task) { |
| 1059 | + m_task_addrs.push_back(current_task.addr); |
| 1060 | + if (current_task == last_task) |
| 1061 | + break; |
| 1062 | + current_task = current_task.getNextChild(status); |
| 1063 | + } |
| 1064 | + |
| 1065 | + // Populate the child cache with null values. |
| 1066 | + m_children.resize(m_task_addrs.size()); |
| 1067 | + |
| 1068 | + if (status.Fail()) { |
| 1069 | + LLDB_LOG(GetLog(LLDBLog::DataFormatters | LLDBLog::Types), |
| 1070 | + "could not read TaskGroup's child task pointers: {0}", |
| 1071 | + status.AsCString()); |
| 1072 | + return ChildCacheState::eReuse; |
| 1073 | + } |
| 1074 | + |
| 1075 | + return ChildCacheState::eRefetch; |
| 1076 | + } |
| 1077 | + |
| 1078 | +private: |
| 1079 | + /// Lightweight Task pointer wrapper, for the purpose of traversing to the |
| 1080 | + /// Task's next sibling (via `ChildFragment::NextChild`). |
| 1081 | + struct Task { |
| 1082 | + ProcessSP process_sp; |
| 1083 | + addr_t addr; |
| 1084 | + |
| 1085 | + operator bool() const { return addr && addr != LLDB_INVALID_ADDRESS; } |
| 1086 | + |
| 1087 | + bool operator==(const Task &other) const { return addr == other.addr; } |
| 1088 | + bool operator!=(const Task &other) const { return !(*this == other); } |
| 1089 | + |
| 1090 | + static constexpr offset_t AsyncTaskSize = sizeof(::swift::AsyncTask); |
| 1091 | + static constexpr offset_t ChildFragmentOffset = AsyncTaskSize; |
| 1092 | + static constexpr offset_t NextChildOffset = ChildFragmentOffset + 0x8; |
| 1093 | + |
| 1094 | + Task getNextChild(Status &status) { |
| 1095 | + addr_t next_task = LLDB_INVALID_ADDRESS; |
| 1096 | + if (status.Success()) |
| 1097 | + next_task = |
| 1098 | + process_sp->ReadPointerFromMemory(addr + NextChildOffset, status); |
| 1099 | + return {process_sp, next_task}; |
| 1100 | + } |
| 1101 | + }; |
| 1102 | + |
| 1103 | + /// Lightweight wrapper around TaskGroup opaque pointers (`TaskGroupBase`), |
| 1104 | + /// for the purpose of traversing its child tasks. |
| 1105 | + struct TaskGroupBase { |
| 1106 | + ProcessSP process_sp; |
| 1107 | + addr_t addr; |
| 1108 | + |
| 1109 | + // FirstChild offset for a TaskGroupBase instance. |
| 1110 | + static constexpr offset_t FirstChildOffset = 0x18; |
| 1111 | + static constexpr offset_t LastChildOffset = 0x20; |
| 1112 | + |
| 1113 | + Task getFirstChild(Status &status) { |
| 1114 | + addr_t first_child = LLDB_INVALID_ADDRESS; |
| 1115 | + if (status.Success()) |
| 1116 | + first_child = |
| 1117 | + process_sp->ReadPointerFromMemory(addr + FirstChildOffset, status); |
| 1118 | + return {process_sp, first_child}; |
| 1119 | + } |
| 1120 | + |
| 1121 | + Task getLastChild(Status &status) { |
| 1122 | + addr_t last_child = LLDB_INVALID_ADDRESS; |
| 1123 | + if (status.Success()) |
| 1124 | + last_child = |
| 1125 | + process_sp->ReadPointerFromMemory(addr + LastChildOffset, status); |
| 1126 | + return {process_sp, last_child}; |
| 1127 | + } |
| 1128 | + }; |
| 1129 | + |
| 1130 | +private: |
| 1131 | + bool m_is_supported_target = false; |
| 1132 | + // Type for Swift.UnsafeCurrentTask. |
| 1133 | + CompilerType m_task_type; |
| 1134 | + // The TaskGroup's list of child task addresses. |
| 1135 | + std::vector<addr_t> m_task_addrs; |
| 1136 | + // Cache and storage of constructed child values. |
| 1137 | + std::vector<ValueObjectSP> m_children; |
| 1138 | +}; |
953 | 1139 | }
|
954 | 1140 | }
|
955 | 1141 | }
|
@@ -1016,6 +1202,14 @@ lldb_private::formatters::swift::TaskSyntheticFrontEndCreator(
|
1016 | 1202 | return new TaskSyntheticFrontEnd(valobj_sp);
|
1017 | 1203 | }
|
1018 | 1204 |
|
| 1205 | +SyntheticChildrenFrontEnd * |
| 1206 | +lldb_private::formatters::swift::TaskGroupSyntheticFrontEndCreator( |
| 1207 | + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { |
| 1208 | + if (!valobj_sp) |
| 1209 | + return nullptr; |
| 1210 | + return new TaskGroupSyntheticFrontEnd(valobj_sp); |
| 1211 | +} |
| 1212 | + |
1019 | 1213 | bool lldb_private::formatters::swift::ObjC_Selector_SummaryProvider(
|
1020 | 1214 | ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
|
1021 | 1215 | LLDB_SCOPED_TIMER();
|
|
0 commit comments