Skip to content
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] add support for thread names on Windows #74731

Merged
merged 3 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +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 "ProcessWindows.h"
#include "ProcessWindowsLog.h"
#include "TargetThreadWindows.h"
#include "lldb/Host/windows/HostThreadWindows.h"
#include <llvm/Support/ConvertUTF.h>

#if defined(__x86_64__) || defined(_M_AMD64)
#include "x64/RegisterContextWindows_x64.h"
Expand All @@ -33,6 +29,9 @@
using namespace lldb;
using namespace lldb_private;

using GetThreadDescriptionFunctionPtr = HRESULT
WINAPI (*)(HANDLE hThread, PWSTR *ppszThreadDescription);

oltolm marked this conversation as resolved.
Show resolved Hide resolved
TargetThreadWindows::TargetThreadWindows(ProcessWindows &process,
const HostThread &thread)
: Thread(process, thread.GetNativeThread().GetThreadId()),
Expand Down Expand Up @@ -175,3 +174,29 @@ Status TargetThreadWindows::DoResume() {

return Status();
}

const char *TargetThreadWindows::GetName() {
Log *log = GetLog(LLDBLog::Thread);
static GetThreadDescriptionFunctionPtr GetThreadDescription = []() {
HMODULE hModule = ::LoadLibraryW(L"Kernel32.dll");
return hModule ? reinterpret_cast<GetThreadDescriptionFunctionPtr>(
::GetProcAddress(hModule, "GetThreadDescription"))
: nullptr;
}();
LLDB_LOGF(log, "GetProcAddress: %p",
reinterpret_cast<void *>(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<char *>(pszThreadName),
wcslen(pszThreadName) * sizeof(wchar_t)),
m_name);
::LocalFree(pszThreadName);
}

return m_name.c_str();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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

Expand Down
2 changes: 2 additions & 0 deletions lldb/unittests/Thread/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ add_lldb_unittest(ThreadTests
lldbInterpreter
lldbBreakpoint
lldbPluginPlatformLinux
lldbPluginPlatformWindows
lldbPluginProcessWindowsCommon
)

71 changes: 71 additions & 0 deletions lldb/unittests/Thread/ThreadTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,20 @@

#include "lldb/Target/Thread.h"
#include "Plugins/Platform/Linux/PlatformLinux.h"
#include <thread>
#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"
Expand All @@ -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<SetThreadDescriptionFunctionPtr>(
::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();
Expand Down Expand Up @@ -88,6 +118,47 @@ TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
return target_sp;
}

#ifdef _WIN32
std::shared_ptr<TargetThreadWindows>
CreateWindowsThread(const ProcessWindowsSP &process_sp, std::thread &t) {
HostThread host_thread((lldb::thread_t)t.native_handle());
ThreadSP thread_sp =
std::make_shared<TargetThreadWindows>(*process_sp.get(), host_thread);
return std::static_pointer_cast<TargetThreadWindows>(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>(
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");

Expand Down