Skip to content

[lldb] Add synthetic formatter for Swift.TaskGroup #10143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
#include "Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "Plugins/TypeSystem/Swift/SwiftDemangle.h"
#include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/DataBufferHeap.h"
Expand All @@ -28,11 +30,13 @@
#include "lldb/Utility/Timer.h"
#include "lldb/ValueObject/ValueObject.h"
#include "lldb/lldb-enumerations.h"
#include "swift/ABI/Task.h"
#include "swift/AST/Types.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Demangling/ManglingMacros.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
Expand Down Expand Up @@ -950,6 +954,135 @@ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
ValueObjectSP m_child_tasks_sp;
ValueObjectSP m_is_running_sp;
};

class TaskGroupSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
TaskGroupSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp.get()) {}

llvm::Expected<uint32_t> CalculateNumChildren() override {
return m_group_tasks.size();
}

bool MightHaveChildren() override { return true; }

lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
if (!m_ts || idx >= m_group_tasks.size())
return {};

if (auto valobj_sp = m_children[idx])
return valobj_sp;

// TypeMangling for "Swift.UnsafeCurrentTask"
CompilerType task_type =
m_ts->GetTypeFromMangledTypename(ConstString("$sSctD"));

addr_t task_addr = m_group_tasks[idx];
auto task_sp = ValueObject::CreateValueObjectFromAddress(
"current_task", task_addr, m_backend.GetExecutionContextRef(),
task_type, false);
if (auto synthetic_sp = task_sp->GetSyntheticValue())
task_sp = synthetic_sp;

task_sp->SetName(ConstString(("[" + Twine(idx) + "]").str()));

m_children[idx] = task_sp;
return task_sp;
}

size_t GetIndexOfChildWithName(ConstString name) override {
StringRef buf = name.GetStringRef();
size_t idx = 0;
if (buf.consume_front("[") && buf.consumeInteger(10, idx))
return idx;
return SIZE_T_MAX;
}

lldb::ChildCacheState Update() override {
// Get the (opaque) pointer to the `TaskGroupBase`.
auto opaque_group_ptr_sp = m_backend.GetChildMemberWithName("_group");
addr_t task_group_ptr =
opaque_group_ptr_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
ProcessSP process_sp = m_backend.GetProcessSP();
TaskGroupBase task_group{process_sp, task_group_ptr};
m_group_tasks.clear();
m_children.clear();
auto current_task = task_group.getFirstChild();
while (current_task) {
m_group_tasks.push_back(current_task.addr);
current_task = current_task.getNextTask();
}
m_children.resize(m_group_tasks.size());

ExecutionContext exe_ctx{m_backend.GetExecutionContextRef()};
auto ts_or_err = exe_ctx.GetTargetRef().GetScratchTypeSystemForLanguage(
eLanguageTypeSwift);
if (auto error = ts_or_err.takeError()) {
// TODO: Log the error.
consumeError(std::move(error));
return ChildCacheState::eRefetch;
}

m_ts = llvm::dyn_cast_or_null<TypeSystemSwiftTypeRef>(ts_or_err->get());
return ChildCacheState::eRefetch;
}

private:
struct Task {
ProcessSP process_sp;
addr_t addr;

operator bool() const { return addr && addr != LLDB_INVALID_ADDRESS; }

static constexpr offset_t JobFlagsOffset = 0x20;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these offsets dependent on the target architecture or are they host offsets?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check. I think so, but your question made me realize I have made some assumptions that I'll need to check.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized I can get rid of some of these offsets.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adrian-prantl on review, I think these offsets will need to be adjusted for arm64_32.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would try to compute them as multiples of the pointer size of the target, and in addition verify that the Swift concurrency version (there's a new special symbol for this now) on the target is still 1 and error out otherwise.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this PR checks the swift concurrency version symbol.

I will merge this with 64 bit support and then setup a test for watchOS update for arm64_32 in a follow up.

static constexpr size_t JobFlagsSize = sizeof(uint32_t);
static constexpr uint32_t IsChildTaskMask = 1ULL << 26;

bool isChildTask() {
Status status;
auto flags = process_sp->ReadUnsignedIntegerFromMemory(
addr + JobFlagsOffset, JobFlagsSize, 0, status);
if (status.Success())
return flags & IsChildTaskMask;
return false;
}

static constexpr offset_t AsyncTaskSize = sizeof(::swift::AsyncTask);
static constexpr offset_t ChildFragmentOffset = AsyncTaskSize;
static constexpr offset_t NextChildOffset = ChildFragmentOffset + 0x8;

Task getNextTask() {
Status status;
auto next_task =
process_sp->ReadPointerFromMemory(addr + NextChildOffset, status);
if (status.Success())
return {process_sp, next_task};
return {process_sp, LLDB_INVALID_ADDRESS};
}
};

struct TaskGroupBase {
ProcessSP process_sp;
addr_t addr;

// FirstChild offset for a TaskGroupBase instance.
static constexpr offset_t FirstChildOffset = 0x18;

Task getFirstChild() {
Status status;
auto first_child =
process_sp->ReadPointerFromMemory(addr + FirstChildOffset, status);
if (status.Success())
return {process_sp, first_child};
return {process_sp, LLDB_INVALID_PROCESS};
}
};

private:
TypeSystemSwiftTypeRef *m_ts;
std::vector<addr_t> m_group_tasks;
std::vector<ValueObjectSP> m_children;
};
}
}
}
Expand Down Expand Up @@ -1016,6 +1149,14 @@ lldb_private::formatters::swift::TaskSyntheticFrontEndCreator(
return new TaskSyntheticFrontEnd(valobj_sp);
}

SyntheticChildrenFrontEnd *
lldb_private::formatters::swift::TaskGroupSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
if (!valobj_sp)
return NULL;
return new TaskGroupSyntheticFrontEnd(valobj_sp);
}

bool lldb_private::formatters::swift::ObjC_Selector_SummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
LLDB_SCOPED_TIMER();
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Plugins/Language/Swift/SwiftFormatters.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ SyntheticChildrenFrontEnd *EnumSyntheticFrontEndCreator(CXXSyntheticChildren *,

SyntheticChildrenFrontEnd *TaskSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

SyntheticChildrenFrontEnd *
TaskGroupSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP);
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,11 @@ static void LoadSwiftFormatters(lldb::TypeCategoryImplSP swift_category_sp) {
lldb_private::formatters::swift::TaskSyntheticFrontEndCreator,
"Swift.UnsafeCurrentTask synthetic children",
ConstString("Swift.UnsafeCurrentTask"), synth_flags);
AddCXXSynthetic(
swift_category_sp,
lldb_private::formatters::swift::TaskGroupSyntheticFrontEndCreator,
"Swift.TaskGroup synthetic children",
ConstString("^Swift\\.TaskGroup<.+>"), synth_flags, true);

AddCXXSummary(
swift_category_sp, lldb_private::formatters::swift::Bool_SummaryProvider,
Expand Down