231 lines · cpp
1//===-- ThreadTest.cpp ------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Target/Thread.h"10#include "Plugins/Platform/Linux/PlatformLinux.h"11#include <thread>12#ifdef _WIN3213#include "lldb/Host/windows/HostThreadWindows.h"14#include "lldb/Host/windows/windows.h"15 16#include "Plugins/Platform/Windows/PlatformWindows.h"17#include "Plugins/Process/Windows/Common/LocalDebugDelegate.h"18#include "Plugins/Process/Windows/Common/ProcessWindows.h"19#include "Plugins/Process/Windows/Common/TargetThreadWindows.h"20#endif21#include "lldb/Core/Debugger.h"22#include "lldb/Host/FileSystem.h"23#include "lldb/Host/HostInfo.h"24#include "lldb/Host/HostThread.h"25#include "lldb/Target/Process.h"26#include "lldb/Target/StopInfo.h"27#include "lldb/Utility/ArchSpec.h"28#include "gtest/gtest.h"29 30using namespace lldb_private;31using namespace lldb;32 33namespace {34 35#ifdef _WIN3236using SetThreadDescriptionFunctionPtr =37 HRESULT(WINAPI *)(HANDLE hThread, PCWSTR lpThreadDescription);38 39static SetThreadDescriptionFunctionPtr SetThreadName;40#endif41 42class ThreadTest : public ::testing::Test {43public:44 void SetUp() override {45 FileSystem::Initialize();46 HostInfo::Initialize();47#ifdef _WIN3248 HMODULE hModule = ::LoadLibraryW(L"Kernel32.dll");49 if (hModule) {50 SetThreadName = reinterpret_cast<SetThreadDescriptionFunctionPtr>(51 (void *)::GetProcAddress(hModule, "SetThreadDescription"));52 }53 PlatformWindows::Initialize();54#endif55 platform_linux::PlatformLinux::Initialize();56 }57 void TearDown() override {58#ifdef _WIN3259 PlatformWindows::Terminate();60#endif61 platform_linux::PlatformLinux::Terminate();62 HostInfo::Terminate();63 FileSystem::Terminate();64 }65};66 67class DummyProcess : public Process {68public:69 DummyProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)70 : Process(target_sp, listener_sp) {}71 72 bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {73 return true;74 }75 Status DoDestroy() override { return {}; }76 void RefreshStateAfterStop() override {}77 size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,78 Status &error) override {79 return 0;80 }81 bool DoUpdateThreadList(ThreadList &old_thread_list,82 ThreadList &new_thread_list) override {83 return false;84 }85 llvm::StringRef GetPluginName() override { return "Dummy"; }86 87 ProcessModID &GetModIDNonConstRef() { return m_mod_id; }88};89 90class DummyThread : public Thread {91public:92 using Thread::Thread;93 94 ~DummyThread() override { DestroyThread(); }95 96 void RefreshStateAfterStop() override {}97 98 lldb::RegisterContextSP GetRegisterContext() override { return nullptr; }99 100 lldb::RegisterContextSP101 CreateRegisterContextForFrame(StackFrame *frame) override {102 return nullptr;103 }104 105 bool CalculateStopInfo() override { return false; }106 107 bool IsStillAtLastBreakpointHit() override { return true; }108};109} // namespace110 111TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {112 PlatformSP platform_sp;113 TargetSP target_sp;114 debugger_sp->GetTargetList().CreateTarget(115 *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);116 117 return target_sp;118}119 120#ifdef _WIN32121std::shared_ptr<TargetThreadWindows>122CreateWindowsThread(const ProcessWindowsSP &process_sp, std::thread &t) {123 HostThread host_thread((lldb::thread_t)t.native_handle());124 ThreadSP thread_sp =125 std::make_shared<TargetThreadWindows>(*process_sp.get(), host_thread);126 return std::static_pointer_cast<TargetThreadWindows>(thread_sp);127}128 129TEST_F(ThreadTest, GetThreadDescription) {130 if (!SetThreadName)131 return;132 133 ArchSpec arch(HostInfo::GetArchitecture());134 Platform::SetHostPlatform(PlatformWindows::CreateInstance(true, &arch));135 136 DebuggerSP debugger_sp = Debugger::CreateInstance();137 ASSERT_TRUE(debugger_sp);138 139 TargetSP target_sp = CreateTarget(debugger_sp, arch);140 ASSERT_TRUE(target_sp);141 142 ListenerSP listener_sp(Listener::MakeListener("dummy"));143 auto process_sp = std::static_pointer_cast<ProcessWindows>(144 ProcessWindows::CreateInstance(target_sp, listener_sp, nullptr, false));145 ASSERT_TRUE(process_sp);146 147 std::thread t([]() {});148 auto thread_sp = CreateWindowsThread(process_sp, t);149 DWORD tid = thread_sp->GetHostThread().GetNativeThread().GetThreadId();150 HANDLE hThread = ::OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, tid);151 ASSERT_TRUE(hThread);152 153 SetThreadName(hThread, L"thread name");154 ::CloseHandle(hThread);155 ASSERT_STREQ(thread_sp->GetName(), "thread name");156 157 t.join();158}159#endif160 161TEST_F(ThreadTest, SetStopInfo) {162 ArchSpec arch("powerpc64-pc-linux");163 164 Platform::SetHostPlatform(165 platform_linux::PlatformLinux::CreateInstance(true, &arch));166 167 DebuggerSP debugger_sp = Debugger::CreateInstance();168 ASSERT_TRUE(debugger_sp);169 170 TargetSP target_sp = CreateTarget(debugger_sp, arch);171 ASSERT_TRUE(target_sp);172 173 ListenerSP listener_sp(Listener::MakeListener("dummy"));174 ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);175 ASSERT_TRUE(process_sp);176 177 DummyProcess *process = static_cast<DummyProcess *>(process_sp.get());178 179 ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);180 ASSERT_TRUE(thread_sp);181 182 StopInfoSP stopinfo_sp =183 StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp.get(), 0);184 ASSERT_TRUE(stopinfo_sp->IsValid() == true);185 186 /*187 Should make stopinfo valid.188 */189 process->GetModIDNonConstRef().BumpStopID();190 ASSERT_TRUE(stopinfo_sp->IsValid() == false);191 192 thread_sp->SetStopInfo(stopinfo_sp);193 ASSERT_TRUE(stopinfo_sp->IsValid() == true);194}195 196TEST_F(ThreadTest, GetPrivateStopInfo) {197 ArchSpec arch("powerpc64-pc-linux");198 199 Platform::SetHostPlatform(200 platform_linux::PlatformLinux::CreateInstance(true, &arch));201 202 DebuggerSP debugger_sp = Debugger::CreateInstance();203 ASSERT_TRUE(debugger_sp);204 205 TargetSP target_sp = CreateTarget(debugger_sp, arch);206 ASSERT_TRUE(target_sp);207 208 ListenerSP listener_sp(Listener::MakeListener("dummy"));209 ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);210 ASSERT_TRUE(process_sp);211 212 DummyProcess *process = static_cast<DummyProcess *>(process_sp.get());213 214 ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);215 ASSERT_TRUE(thread_sp);216 217 StopInfoSP stopinfo_sp =218 StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp.get(), 0);219 ASSERT_TRUE(stopinfo_sp);220 221 thread_sp->SetStopInfo(stopinfo_sp);222 223 /*224 Should make stopinfo valid if thread is at last breakpoint hit.225 */226 process->GetModIDNonConstRef().BumpStopID();227 ASSERT_TRUE(stopinfo_sp->IsValid() == false);228 StopInfoSP new_stopinfo_sp = thread_sp->GetPrivateStopInfo();229 ASSERT_TRUE(new_stopinfo_sp && stopinfo_sp->IsValid() == true);230}231