From 9383b8b92849c71a96b4b4e7e55f615d8f2efedb Mon Sep 17 00:00:00 2001 From: oltolm Date: Fri, 1 Dec 2023 16:49:13 +0100 Subject: [PATCH 1/3] lldb: add support for thread names on Windows --- .../Windows/Common/TargetThreadWindows.cpp | 31 +++++++++++++++++++ .../Windows/Common/TargetThreadWindows.h | 2 ++ 2 files changed, 33 insertions(+) diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp index 37dc8f6d6d14a5..047019ac30f490 100644 --- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp @@ -15,6 +15,7 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" +#include "llvm/Support/ConvertUTF.h" #include "ProcessWindows.h" #include "ProcessWindowsLog.h" @@ -33,6 +34,9 @@ using namespace lldb; using namespace lldb_private; +using GetThreadDescriptionFunctionPtr = HRESULT +WINAPI (*)(HANDLE hThread, PWSTR *ppszThreadDescription); + TargetThreadWindows::TargetThreadWindows(ProcessWindows &process, const HostThread &thread) : Thread(process, thread.GetNativeThread().GetThreadId()), @@ -175,3 +179,30 @@ Status TargetThreadWindows::DoResume() { return Status(); } + +const char *TargetThreadWindows::GetName() { + Log *log = GetLog(LLDBLog::Thread); + HMODULE hModule = ::LoadLibraryW(L"Kernel32.dll"); + if (hModule) { + auto GetThreadDescription = + reinterpret_cast( + ::GetProcAddress(hModule, "GetThreadDescription")); + LLDB_LOGF(log, "GetProcAddress: %p", + reinterpret_cast(GetThreadDescription)); + if (GetThreadDescription) { + PWSTR pszThreadName; + if (SUCCEEDED(GetThreadDescription( + m_host_thread.GetNativeThread().GetSystemHandle(), + &pszThreadName))) { + LLDB_LOGF(log, "GetThreadDescription: %ls", pszThreadName); + llvm::convertUTF16ToUTF8String( + llvm::ArrayRef(reinterpret_cast(pszThreadName), + wcslen(pszThreadName) * sizeof(wchar_t)), + m_name); + ::LocalFree(pszThreadName); + } + } + } + + return m_name.c_str(); +} diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h index 2845847738f60d..07e1db464ad594 100644 --- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.h @@ -34,6 +34,7 @@ class TargetThreadWindows : public lldb_private::Thread { lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame) override; bool CalculateStopInfo() override; + const char *GetName() override; Status DoResume(); @@ -42,6 +43,7 @@ class TargetThreadWindows : public lldb_private::Thread { private: lldb::RegisterContextSP m_thread_reg_ctx_sp; HostThread m_host_thread; + std::string m_name; }; } // namespace lldb_private From 89ea63ca021da9e350bbb3016da601d7543d7e50 Mon Sep 17 00:00:00 2001 From: oltolm Date: Fri, 8 Dec 2023 19:42:48 +0100 Subject: [PATCH 2/3] [lldb] add unit test for Windows thread names --- lldb/unittests/Thread/CMakeLists.txt | 2 + lldb/unittests/Thread/ThreadTest.cpp | 71 ++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/lldb/unittests/Thread/CMakeLists.txt b/lldb/unittests/Thread/CMakeLists.txt index d6e365adac5dd7..f6c8795f349a5e 100644 --- a/lldb/unittests/Thread/CMakeLists.txt +++ b/lldb/unittests/Thread/CMakeLists.txt @@ -11,5 +11,7 @@ add_lldb_unittest(ThreadTests lldbInterpreter lldbBreakpoint lldbPluginPlatformLinux + lldbPluginPlatformWindows + lldbPluginProcessWindowsCommon ) diff --git a/lldb/unittests/Thread/ThreadTest.cpp b/lldb/unittests/Thread/ThreadTest.cpp index bd8cdce99f172c..4c660e9815c3ef 100644 --- a/lldb/unittests/Thread/ThreadTest.cpp +++ b/lldb/unittests/Thread/ThreadTest.cpp @@ -8,9 +8,20 @@ #include "lldb/Target/Thread.h" #include "Plugins/Platform/Linux/PlatformLinux.h" +#include +#ifdef _WIN32 +#include "lldb/Host/windows/HostThreadWindows.h" +#include "lldb/Host/windows/windows.h" + +#include "Plugins/Platform/Windows/PlatformWindows.h" +#include "Plugins/Process/Windows/Common/LocalDebugDelegate.h" +#include "Plugins/Process/Windows/Common/ProcessWindows.h" +#include "Plugins/Process/Windows/Common/TargetThreadWindows.h" +#endif #include "lldb/Core/Debugger.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/HostThread.h" #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Utility/ArchSpec.h" @@ -21,14 +32,33 @@ using namespace lldb_private::repro; using namespace lldb; namespace { + +#ifdef _WIN32 +using SetThreadDescriptionFunctionPtr = HRESULT +WINAPI (*)(HANDLE hThread, PCWSTR lpThreadDescription); + +static SetThreadDescriptionFunctionPtr SetThreadName; +#endif + class ThreadTest : public ::testing::Test { public: void SetUp() override { FileSystem::Initialize(); HostInfo::Initialize(); +#ifdef _WIN32 + HMODULE hModule = ::LoadLibraryW(L"Kernel32.dll"); + if (hModule) { + SetThreadName = reinterpret_cast( + ::GetProcAddress(hModule, "SetThreadDescription")); + } + PlatformWindows::Initialize(); +#endif platform_linux::PlatformLinux::Initialize(); } void TearDown() override { +#ifdef _WIN32 + PlatformWindows::Terminate(); +#endif platform_linux::PlatformLinux::Terminate(); HostInfo::Terminate(); FileSystem::Terminate(); @@ -88,6 +118,47 @@ TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) { return target_sp; } +#ifdef _WIN32 +std::shared_ptr +CreateWindowsThread(const ProcessWindowsSP &process_sp, std::thread &t) { + HostThread host_thread((lldb::thread_t)t.native_handle()); + ThreadSP thread_sp = + std::make_shared(*process_sp.get(), host_thread); + return std::static_pointer_cast(thread_sp); +} + +TEST_F(ThreadTest, GetThreadDescription) { + if (!SetThreadName) + return; + + ArchSpec arch(HostInfo::GetArchitecture()); + Platform::SetHostPlatform(PlatformWindows::CreateInstance(true, &arch)); + + DebuggerSP debugger_sp = Debugger::CreateInstance(); + ASSERT_TRUE(debugger_sp); + + TargetSP target_sp = CreateTarget(debugger_sp, arch); + ASSERT_TRUE(target_sp); + + ListenerSP listener_sp(Listener::MakeListener("dummy")); + auto process_sp = std::static_pointer_cast( + ProcessWindows::CreateInstance(target_sp, listener_sp, nullptr, false)); + ASSERT_TRUE(process_sp); + + std::thread t([]() {}); + auto thread_sp = CreateWindowsThread(process_sp, t); + DWORD tid = thread_sp->GetHostThread().GetNativeThread().GetThreadId(); + HANDLE hThread = ::OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, tid); + ASSERT_TRUE(hThread); + + SetThreadName(hThread, L"thread name"); + ::CloseHandle(hThread); + ASSERT_STREQ(thread_sp->GetName(), "thread name"); + + t.join(); +} +#endif + TEST_F(ThreadTest, SetStopInfo) { ArchSpec arch("powerpc64-pc-linux"); From da9125b54aad77484a87e80dab7cc48c5d774d54 Mon Sep 17 00:00:00 2001 From: oltolm Date: Tue, 12 Dec 2023 20:29:20 +0100 Subject: [PATCH 3/3] lldb: cleanup Windows thread names --- .../Windows/Common/TargetThreadWindows.cpp | 48 ++++++++----------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp index 047019ac30f490..ad67e764fe10f2 100644 --- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp @@ -7,19 +7,14 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/HostInfo.h" -#include "lldb/Host/HostNativeThreadBase.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/Target/RegisterContext.h" #include "lldb/Target/Unwind.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/State.h" -#include "llvm/Support/ConvertUTF.h" #include "ProcessWindows.h" -#include "ProcessWindowsLog.h" #include "TargetThreadWindows.h" +#include "lldb/Host/windows/HostThreadWindows.h" +#include #if defined(__x86_64__) || defined(_M_AMD64) #include "x64/RegisterContextWindows_x64.h" @@ -182,26 +177,25 @@ Status TargetThreadWindows::DoResume() { const char *TargetThreadWindows::GetName() { Log *log = GetLog(LLDBLog::Thread); - HMODULE hModule = ::LoadLibraryW(L"Kernel32.dll"); - if (hModule) { - auto GetThreadDescription = - reinterpret_cast( - ::GetProcAddress(hModule, "GetThreadDescription")); - LLDB_LOGF(log, "GetProcAddress: %p", - reinterpret_cast(GetThreadDescription)); - if (GetThreadDescription) { - PWSTR pszThreadName; - if (SUCCEEDED(GetThreadDescription( - m_host_thread.GetNativeThread().GetSystemHandle(), - &pszThreadName))) { - LLDB_LOGF(log, "GetThreadDescription: %ls", pszThreadName); - llvm::convertUTF16ToUTF8String( - llvm::ArrayRef(reinterpret_cast(pszThreadName), - wcslen(pszThreadName) * sizeof(wchar_t)), - m_name); - ::LocalFree(pszThreadName); - } - } + static GetThreadDescriptionFunctionPtr GetThreadDescription = []() { + HMODULE hModule = ::LoadLibraryW(L"Kernel32.dll"); + return hModule ? reinterpret_cast( + ::GetProcAddress(hModule, "GetThreadDescription")) + : nullptr; + }(); + LLDB_LOGF(log, "GetProcAddress: %p", + reinterpret_cast(GetThreadDescription)); + if (!GetThreadDescription) + return m_name.c_str(); + PWSTR pszThreadName; + if (SUCCEEDED(GetThreadDescription( + m_host_thread.GetNativeThread().GetSystemHandle(), &pszThreadName))) { + LLDB_LOGF(log, "GetThreadDescription: %ls", pszThreadName); + llvm::convertUTF16ToUTF8String( + llvm::ArrayRef(reinterpret_cast(pszThreadName), + wcslen(pszThreadName) * sizeof(wchar_t)), + m_name); + ::LocalFree(pszThreadName); } return m_name.c_str();