-
Notifications
You must be signed in to change notification settings - Fork 333
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
[lldb] Swift OS plugin #9839
base: swift/release/6.1
Are you sure you want to change the base?
[lldb] Swift OS plugin #9839
Changes from all commits
c59e235
dd5b8ec
9a6d8b6
902888e
46e1709
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
if (LLDB_ENABLE_PYTHON) | ||
add_subdirectory(Python) | ||
add_subdirectory(Swift) | ||
endif() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
add_lldb_library(lldbPluginOperatingSystemSwift PLUGIN | ||
OperatingSystemSwift.cpp | ||
|
||
LINK_LIBS | ||
lldbCore | ||
lldbInterpreter | ||
lldbSymbol | ||
lldbTarget | ||
lldbValueObject | ||
lldbPluginProcessUtility | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
//===-- OperatingSystemSwift.cpp -----------------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#if LLDB_ENABLE_SWIFT | ||
|
||
#include "OperatingSystemSwift.h" | ||
|
||
#include "Plugins/Process/Utility/ThreadMemory.h" | ||
#include "lldb/Core/Debugger.h" | ||
#include "lldb/Core/Module.h" | ||
#include "lldb/Core/PluginManager.h" | ||
#include "lldb/Target/Process.h" | ||
#include "lldb/Target/Thread.h" | ||
#include "lldb/Target/ThreadList.h" | ||
#include "lldb/Utility/LLDBLog.h" | ||
#include "lldb/Utility/StructuredData.h" | ||
|
||
#include "swift/Threading/ThreadLocalStorage.h" | ||
|
||
#include <memory> | ||
|
||
using namespace lldb; | ||
using namespace lldb_private; | ||
|
||
LLDB_PLUGIN_DEFINE(OperatingSystemSwift) | ||
|
||
void OperatingSystemSwift::Initialize() { | ||
PluginManager::RegisterPlugin(GetPluginNameStatic(), | ||
GetPluginDescriptionStatic(), CreateInstance, | ||
nullptr); | ||
} | ||
|
||
void OperatingSystemSwift::Terminate() { | ||
PluginManager::UnregisterPlugin(CreateInstance); | ||
} | ||
|
||
OperatingSystem *OperatingSystemSwift::CreateInstance(Process *process, | ||
bool force) { | ||
if (!process) | ||
return nullptr; | ||
|
||
/// Heuristic to only load the plugin for swift programs. | ||
FileSpec swift_module_name = FileSpec("libswiftCore.dylib"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This only works in a very narrow subset of Swift programs. You should defer to SwiftLanguageRuntime's helper code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have a helper function mind? The only thing I found is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could also arrange that this can only be accessed by the SwiftLanguageRuntime, and then its loading will be gated on the Runtime loading, which already has to do this sort of computation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jimingham I looked into that option, but AFAICT the SwiftLanguageRuntime is loaded regardless of modules. |
||
if (process->GetTarget().GetImages().FindFirstModule(swift_module_name)) | ||
return new OperatingSystemSwift(*process); | ||
return nullptr; | ||
} | ||
|
||
llvm::StringRef OperatingSystemSwift::GetPluginDescriptionStatic() { | ||
return "Operating system plug-in converting Swift Tasks into Threads."; | ||
} | ||
|
||
OperatingSystemSwift::~OperatingSystemSwift() = default; | ||
|
||
OperatingSystemSwift::OperatingSystemSwift(lldb_private::Process &process) | ||
: OperatingSystem(&process) { | ||
size_t ptr_size = process.GetAddressByteSize(); | ||
// Offset of the Task pointer in a Thread's local storage. | ||
m_task_ptr_offset_in_tls = | ||
swift::tls_get_key(swift::tls_key::concurrency_task) * ptr_size; | ||
// Offset of a Task ID inside a Task data structure, guaranteed by the ABI. | ||
// See Job in swift/RemoteInspection/RuntimeInternals.h. | ||
m_task_id_offset = 4 * ptr_size + 4; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should check that the swift concurrency version is still 1 here. |
||
} | ||
|
||
bool OperatingSystemSwift::UpdateThreadList(ThreadList &old_thread_list, | ||
ThreadList &core_thread_list, | ||
ThreadList &new_thread_list) { | ||
Log *log = GetLog(LLDBLog::OS); | ||
LLDB_LOG(log, "OperatingSystemSwift: Updating thread list"); | ||
|
||
for (const ThreadSP &real_thread : core_thread_list.Threads()) { | ||
std::optional<uint64_t> task_id = FindTaskId(*real_thread); | ||
|
||
// If this is not a thread running a Task, add it to the list as is. | ||
if (!task_id) { | ||
new_thread_list.AddThread(real_thread); | ||
LLDB_LOGF(log, | ||
"OperatingSystemSwift: thread %" PRIx64 | ||
" is not executing a Task", | ||
real_thread->GetID()); | ||
continue; | ||
} | ||
|
||
// Mask higher bits to avoid conflicts with core thread IDs. | ||
uint64_t masked_task_id = 0xdeadbeef00000000 | *task_id; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Btw it is probably fine to not do this, TIDs are generally higher numbers and there might be value in exposing the task id directly. If we do mask, we should use some other mask There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be the visible "TID" for running tasks, right? And what I'd have to type if I wanted to set a "task specific" breakpoint? If so, we might not want it to be deadbeef. That's cute if you know the reference, but otherwise somewhat off-putting... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh yeah, I'm actually looking for suggestions here, if we should mask it at all and what to use if we do |
||
|
||
ThreadSP swift_thread = [&]() -> ThreadSP { | ||
// If we already had a thread for this Task in the last stop, re-use it. | ||
if (ThreadSP old_thread = old_thread_list.FindThreadByID(masked_task_id); | ||
IsOperatingSystemPluginThread(old_thread)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have to handle the case where when you stopped the first time, this Task was backed by "core thread 1" but the next time you stopped it was backed by a different core thread? I don't see where you are changing the backing thread in this case? |
||
return old_thread; | ||
|
||
std::string name = llvm::formatv("Swift Task {0:x}", *task_id); | ||
llvm::StringRef queue_name = ""; | ||
return std::make_shared<ThreadMemory>(*m_process, masked_task_id, name, | ||
queue_name, | ||
/*register_data_addr*/ 0); | ||
}(); | ||
|
||
swift_thread->SetBackingThread(real_thread); | ||
new_thread_list.AddThread(swift_thread); | ||
LLDB_LOGF(log, | ||
"OperatingSystemSwift: mapping thread IDs: %" PRIx64 | ||
" -> %" PRIx64, | ||
real_thread->GetID(), swift_thread->GetID()); | ||
} | ||
return true; | ||
} | ||
|
||
void OperatingSystemSwift::ThreadWasSelected(Thread *thread) {} | ||
|
||
RegisterContextSP | ||
OperatingSystemSwift::CreateRegisterContextForThread(Thread *thread, | ||
addr_t reg_data_addr) { | ||
if (!thread || !IsOperatingSystemPluginThread(thread->shared_from_this())) | ||
return nullptr; | ||
return thread->GetRegisterContext(); | ||
} | ||
|
||
StopInfoSP | ||
OperatingSystemSwift::CreateThreadStopReason(lldb_private::Thread *thread) { | ||
return thread->GetStopInfo(); | ||
} | ||
|
||
std::optional<uint64_t> OperatingSystemSwift::FindTaskId(Thread &thread) { | ||
// Compute the thread local storage address for this thread. | ||
StructuredData::ObjectSP info_root_sp = thread.GetExtendedInfo(); | ||
if (!info_root_sp) | ||
return {}; | ||
StructuredData::ObjectSP node = | ||
info_root_sp->GetObjectForDotSeparatedPath("tsd_address"); | ||
if (!node) | ||
return {}; | ||
StructuredData::UnsignedInteger *raw_tsd_addr = node->GetAsUnsignedInteger(); | ||
if (!raw_tsd_addr) | ||
return {}; | ||
addr_t tsd_addr = raw_tsd_addr->GetUnsignedIntegerValue(); | ||
|
||
// The Task address is at offset m_task_ptr_offset_in_tls from the thread | ||
// local storage base pointer. | ||
addr_t task_addr_location = tsd_addr + m_task_ptr_offset_in_tls; | ||
Status error; | ||
addr_t task_addr = | ||
m_process->ReadPointerFromMemory(task_addr_location, error); | ||
if (error.Fail()) | ||
return {}; | ||
|
||
// The Task ID is at offset m_task_id_offset from the Task pointer. | ||
constexpr uint32_t num_bytes_task_id = 4; | ||
auto task_id = m_process->ReadUnsignedIntegerFromMemory( | ||
task_addr + m_task_id_offset, num_bytes_task_id, LLDB_INVALID_ADDRESS, | ||
error); | ||
if (error.Fail()) | ||
return {}; | ||
return task_id; | ||
} | ||
|
||
#endif // #if LLDB_ENABLE_SWIFT |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
//===-- OperatingSystemSwift.h ---------------------------------*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef liblldb_OperatingSystemSwift_h_ | ||
#define liblldb_OperatingSystemSwift_h_ | ||
|
||
#if LLDB_ENABLE_SWIFT | ||
|
||
#include "lldb/Target/OperatingSystem.h" | ||
|
||
namespace lldb_private { | ||
class OperatingSystemSwift : public OperatingSystem { | ||
public: | ||
OperatingSystemSwift(Process &process); | ||
~OperatingSystemSwift() override; | ||
|
||
static OperatingSystem *CreateInstance(Process *process, bool force); | ||
static void Initialize(); | ||
static void Terminate(); | ||
static llvm::StringRef GetPluginNameStatic() { return "swift"; } | ||
static llvm::StringRef GetPluginDescriptionStatic(); | ||
|
||
/// PluginInterface Methods | ||
|
||
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } | ||
|
||
/// OperatingSystem Methods | ||
|
||
bool UpdateThreadList(ThreadList &old_thread_list, | ||
ThreadList &real_thread_list, | ||
ThreadList &new_thread_list) override; | ||
|
||
void ThreadWasSelected(Thread *thread) override; | ||
|
||
lldb::RegisterContextSP | ||
CreateRegisterContextForThread(Thread *thread, | ||
lldb::addr_t reg_data_addr) override; | ||
|
||
lldb::StopInfoSP CreateThreadStopReason(Thread *thread) override; | ||
|
||
std::optional<bool> DoesPluginReportAllThreads() override { return false; } | ||
|
||
private: | ||
/// Find the Task ID of the task being executed by `thread`, if any. | ||
std::optional<uint64_t> FindTaskId(Thread &thread); | ||
|
||
/// The offset of the Task pointer inside thread local storage. | ||
size_t m_task_ptr_offset_in_tls; | ||
|
||
/// The offset of the Task ID inside a Task data structure. | ||
size_t m_task_id_offset; | ||
}; | ||
} // namespace lldb_private | ||
|
||
#endif // LLDB_ENABLE_SWIFT | ||
|
||
#endif // liblldb_OperatingSystemSwift_h_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not important. "OperatingSystemSwift" sounds slightly wrong to me. What about "OperatingSystemSwiftTasks" or "OperatingSystemSwiftConcurrency"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah the name seems misleading the full lldb affordance name is "Operating System Thread Plugin"