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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Target/Thread.h"
10#include "Plugins/Platform/Linux/PlatformLinux.h"
11#include <thread>
12#ifdef _WIN32
13#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#endif
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"
29
30using namespace lldb_private;
31using namespace lldb;
32
33namespace {
34
35#ifdef _WIN32
36using SetThreadDescriptionFunctionPtr =
37 HRESULT(WINAPI *)(HANDLE hThread, PCWSTR lpThreadDescription);
38
39static SetThreadDescriptionFunctionPtr SetThreadName;
40#endif
41
42class ThreadTest : public ::testing::Test {
43public:
44 void SetUp() override {
45 FileSystem::Initialize();
46 HostInfo::Initialize();
47#ifdef _WIN32
48 HMODULE hModule = ::LoadLibraryW(L"Kernel32.dll");
49 if (hModule) {
50 SetThreadName = reinterpret_cast<SetThreadDescriptionFunctionPtr>(
51 (void *)::GetProcAddress(hModule, "SetThreadDescription"));
52 }
53 PlatformWindows::Initialize();
54#endif
55 platform_linux::PlatformLinux::Initialize();
56 }
57 void TearDown() override {
58#ifdef _WIN32
59 PlatformWindows::Terminate();
60#endif
61 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::RegisterContextSP
101 CreateRegisterContextForFrame(StackFrame *frame) override {
102 return nullptr;
103 }
104
105 bool CalculateStopInfo() override { return false; }
106
107 bool IsStillAtLastBreakpointHit() override { return true; }
108};
109} // namespace
110
111TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
112 PlatformSP platform_sp;
113 TargetSP target_sp;
114 debugger_sp->GetTargetList().CreateTarget(
115 debugger&: *debugger_sp, user_exe_path: "", arch, get_dependent_modules: eLoadDependentsNo, platform_sp, target_sp);
116
117 return target_sp;
118}
119
120#ifdef _WIN32
121std::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#endif
160
161TEST_F(ThreadTest, SetStopInfo) {
162 ArchSpec arch("powerpc64-pc-linux");
163
164 Platform::SetHostPlatform(
165 platform_linux::PlatformLinux::CreateInstance(force: true, arch: &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(name: "dummy"));
174 ProcessSP process_sp = std::make_shared<DummyProcess>(args&: target_sp, args&: 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>(args&: *process_sp.get(), args: 0);
180 ASSERT_TRUE(thread_sp);
181
182 StopInfoSP stopinfo_sp =
183 StopInfo::CreateStopReasonWithBreakpointSiteID(thread&: *thread_sp.get(), break_id: 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(force: true, arch: &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(name: "dummy"));
209 ProcessSP process_sp = std::make_shared<DummyProcess>(args&: target_sp, args&: 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>(args&: *process_sp.get(), args: 0);
215 ASSERT_TRUE(thread_sp);
216
217 StopInfoSP stopinfo_sp =
218 StopInfo::CreateStopReasonWithBreakpointSiteID(thread&: *thread_sp.get(), break_id: 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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/unittests/Thread/ThreadTest.cpp