1 //===-- ThreadTest.cpp ------------------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Target/Thread.h"
10 #include "Plugins/Platform/Linux/PlatformLinux.h"
13 #include "lldb/Host/windows/HostThreadWindows.h"
14 #include "lldb/Host/windows/windows.h"
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"
21 #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"
30 using namespace lldb_private
;
31 using namespace lldb_private::repro
;
37 using SetThreadDescriptionFunctionPtr
=
38 HRESULT(WINAPI
*)(HANDLE hThread
, PCWSTR lpThreadDescription
);
40 static SetThreadDescriptionFunctionPtr SetThreadName
;
43 class ThreadTest
: public ::testing::Test
{
45 void SetUp() override
{
46 FileSystem::Initialize();
47 HostInfo::Initialize();
49 HMODULE hModule
= ::LoadLibraryW(L
"Kernel32.dll");
51 SetThreadName
= reinterpret_cast<SetThreadDescriptionFunctionPtr
>(
52 ::GetProcAddress(hModule
, "SetThreadDescription"));
54 PlatformWindows::Initialize();
56 platform_linux::PlatformLinux::Initialize();
58 void TearDown() override
{
60 PlatformWindows::Terminate();
62 platform_linux::PlatformLinux::Terminate();
63 HostInfo::Terminate();
64 FileSystem::Terminate();
68 class DummyProcess
: public Process
{
70 DummyProcess(lldb::TargetSP target_sp
, lldb::ListenerSP listener_sp
)
71 : Process(target_sp
, listener_sp
) {}
73 bool CanDebug(lldb::TargetSP target
, bool plugin_specified_by_name
) override
{
76 Status
DoDestroy() override
{ return {}; }
77 void RefreshStateAfterStop() override
{}
78 size_t DoReadMemory(lldb::addr_t vm_addr
, void *buf
, size_t size
,
79 Status
&error
) override
{
82 bool DoUpdateThreadList(ThreadList
&old_thread_list
,
83 ThreadList
&new_thread_list
) override
{
86 llvm::StringRef
GetPluginName() override
{ return "Dummy"; }
88 ProcessModID
&GetModIDNonConstRef() { return m_mod_id
; }
91 class DummyThread
: public Thread
{
95 ~DummyThread() override
{ DestroyThread(); }
97 void RefreshStateAfterStop() override
{}
99 lldb::RegisterContextSP
GetRegisterContext() override
{ return nullptr; }
101 lldb::RegisterContextSP
102 CreateRegisterContextForFrame(StackFrame
*frame
) override
{
106 bool CalculateStopInfo() override
{ return false; }
108 bool IsStillAtLastBreakpointHit() override
{ return true; }
112 TargetSP
CreateTarget(DebuggerSP
&debugger_sp
, ArchSpec
&arch
) {
113 PlatformSP platform_sp
;
115 debugger_sp
->GetTargetList().CreateTarget(
116 *debugger_sp
, "", arch
, eLoadDependentsNo
, platform_sp
, target_sp
);
122 std::shared_ptr
<TargetThreadWindows
>
123 CreateWindowsThread(const ProcessWindowsSP
&process_sp
, std::thread
&t
) {
124 HostThread
host_thread((lldb::thread_t
)t
.native_handle());
126 std::make_shared
<TargetThreadWindows
>(*process_sp
.get(), host_thread
);
127 return std::static_pointer_cast
<TargetThreadWindows
>(thread_sp
);
130 TEST_F(ThreadTest
, GetThreadDescription
) {
134 ArchSpec
arch(HostInfo::GetArchitecture());
135 Platform::SetHostPlatform(PlatformWindows::CreateInstance(true, &arch
));
137 DebuggerSP debugger_sp
= Debugger::CreateInstance();
138 ASSERT_TRUE(debugger_sp
);
140 TargetSP target_sp
= CreateTarget(debugger_sp
, arch
);
141 ASSERT_TRUE(target_sp
);
143 ListenerSP
listener_sp(Listener::MakeListener("dummy"));
144 auto process_sp
= std::static_pointer_cast
<ProcessWindows
>(
145 ProcessWindows::CreateInstance(target_sp
, listener_sp
, nullptr, false));
146 ASSERT_TRUE(process_sp
);
148 std::thread
t([]() {});
149 auto thread_sp
= CreateWindowsThread(process_sp
, t
);
150 DWORD tid
= thread_sp
->GetHostThread().GetNativeThread().GetThreadId();
151 HANDLE hThread
= ::OpenThread(THREAD_SET_LIMITED_INFORMATION
, FALSE
, tid
);
152 ASSERT_TRUE(hThread
);
154 SetThreadName(hThread
, L
"thread name");
155 ::CloseHandle(hThread
);
156 ASSERT_STREQ(thread_sp
->GetName(), "thread name");
162 TEST_F(ThreadTest
, SetStopInfo
) {
163 ArchSpec
arch("powerpc64-pc-linux");
165 Platform::SetHostPlatform(
166 platform_linux::PlatformLinux::CreateInstance(true, &arch
));
168 DebuggerSP debugger_sp
= Debugger::CreateInstance();
169 ASSERT_TRUE(debugger_sp
);
171 TargetSP target_sp
= CreateTarget(debugger_sp
, arch
);
172 ASSERT_TRUE(target_sp
);
174 ListenerSP
listener_sp(Listener::MakeListener("dummy"));
175 ProcessSP process_sp
= std::make_shared
<DummyProcess
>(target_sp
, listener_sp
);
176 ASSERT_TRUE(process_sp
);
178 DummyProcess
*process
= static_cast<DummyProcess
*>(process_sp
.get());
180 ThreadSP thread_sp
= std::make_shared
<DummyThread
>(*process_sp
.get(), 0);
181 ASSERT_TRUE(thread_sp
);
183 StopInfoSP stopinfo_sp
=
184 StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp
.get(), 0);
185 ASSERT_TRUE(stopinfo_sp
->IsValid() == true);
188 Should make stopinfo valid.
190 process
->GetModIDNonConstRef().BumpStopID();
191 ASSERT_TRUE(stopinfo_sp
->IsValid() == false);
193 thread_sp
->SetStopInfo(stopinfo_sp
);
194 ASSERT_TRUE(stopinfo_sp
->IsValid() == true);
197 TEST_F(ThreadTest
, GetPrivateStopInfo
) {
198 ArchSpec
arch("powerpc64-pc-linux");
200 Platform::SetHostPlatform(
201 platform_linux::PlatformLinux::CreateInstance(true, &arch
));
203 DebuggerSP debugger_sp
= Debugger::CreateInstance();
204 ASSERT_TRUE(debugger_sp
);
206 TargetSP target_sp
= CreateTarget(debugger_sp
, arch
);
207 ASSERT_TRUE(target_sp
);
209 ListenerSP
listener_sp(Listener::MakeListener("dummy"));
210 ProcessSP process_sp
= std::make_shared
<DummyProcess
>(target_sp
, listener_sp
);
211 ASSERT_TRUE(process_sp
);
213 DummyProcess
*process
= static_cast<DummyProcess
*>(process_sp
.get());
215 ThreadSP thread_sp
= std::make_shared
<DummyThread
>(*process_sp
.get(), 0);
216 ASSERT_TRUE(thread_sp
);
218 StopInfoSP stopinfo_sp
=
219 StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp
.get(), 0);
220 ASSERT_TRUE(stopinfo_sp
);
222 thread_sp
->SetStopInfo(stopinfo_sp
);
225 Should make stopinfo valid if thread is at last breakpoint hit.
227 process
->GetModIDNonConstRef().BumpStopID();
228 ASSERT_TRUE(stopinfo_sp
->IsValid() == false);
229 StopInfoSP new_stopinfo_sp
= thread_sp
->GetPrivateStopInfo();
230 ASSERT_TRUE(new_stopinfo_sp
&& stopinfo_sp
->IsValid() == true);