blob: 88ea394bbb1e5a705121f0a507383b9cfdc5ee15 [file] [log] [blame]
Ilya Bukonkin3b43f002020-06-11 21:59:191//===-- ProcessEventDataTest.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 "Plugins/Platform/MacOSX/PlatformMacOSX.h"
Jonas Devliegheredd2054d2020-12-03 00:26:1110#include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
Med Ismail Bennanif32c6b22024-03-04 19:42:0411#include "TestingSupport/TestUtilities.h"
Ilya Bukonkin3b43f002020-06-11 21:59:1912#include "lldb/Core/Debugger.h"
13#include "lldb/Host/FileSystem.h"
14#include "lldb/Host/HostInfo.h"
15#include "lldb/Target/Process.h"
16#include "lldb/Target/StopInfo.h"
17#include "lldb/Target/Thread.h"
18#include "lldb/Utility/ArchSpec.h"
19#include "lldb/Utility/Event.h"
Ilya Bukonkin3b43f002020-06-11 21:59:1920#include "gtest/gtest.h"
21
22using namespace lldb_private;
Ilya Bukonkin3b43f002020-06-11 21:59:1923using namespace lldb;
24
25namespace {
26class ProcessEventDataTest : public ::testing::Test {
27public:
28 void SetUp() override {
Ilya Bukonkin3b43f002020-06-11 21:59:1929 FileSystem::Initialize();
30 HostInfo::Initialize();
31 PlatformMacOSX::Initialize();
Med Ismail Bennanif32c6b22024-03-04 19:42:0432 std::call_once(TestUtilities::g_debugger_initialize_flag,
33 []() { Debugger::Initialize(nullptr); });
Ilya Bukonkin3b43f002020-06-11 21:59:1934 }
35 void TearDown() override {
36 PlatformMacOSX::Terminate();
37 HostInfo::Terminate();
38 FileSystem::Terminate();
Ilya Bukonkin3b43f002020-06-11 21:59:1939 }
40};
41
42class DummyProcess : public Process {
43public:
Michał Górny9b031d52022-08-05 17:39:4244 DummyProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
45 : Process(target_sp, listener_sp) {}
Ilya Bukonkin3b43f002020-06-11 21:59:1946
David Blaikie68466862021-01-25 23:03:3847 bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
Ilya Bukonkin3b43f002020-06-11 21:59:1948 return true;
49 }
David Blaikie68466862021-01-25 23:03:3850 Status DoDestroy() override { return {}; }
51 void RefreshStateAfterStop() override {}
52 size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
53 Status &error) override {
Ilya Bukonkin3b43f002020-06-11 21:59:1954 return 0;
55 }
Walter Erquinigo4bb62442021-01-22 18:22:2656 bool DoUpdateThreadList(ThreadList &old_thread_list,
57 ThreadList &new_thread_list) override {
Ilya Bukonkin3b43f002020-06-11 21:59:1958 return false;
59 }
Pavel Labatha3939e12021-10-15 11:07:3960 llvm::StringRef GetPluginName() override { return "Dummy"; }
Ilya Bukonkin3b43f002020-06-11 21:59:1961
62 ProcessModID &GetModIDNonConstRef() { return m_mod_id; }
63};
64
65class DummyThread : public Thread {
66public:
67 using Thread::Thread;
68
69 ~DummyThread() override { DestroyThread(); }
70
71 void RefreshStateAfterStop() override {}
72
73 lldb::RegisterContextSP GetRegisterContext() override { return nullptr; }
74
75 lldb::RegisterContextSP
76 CreateRegisterContextForFrame(StackFrame *frame) override {
77 return nullptr;
78 }
79
80 bool CalculateStopInfo() override { return false; }
81};
82
83class DummyStopInfo : public StopInfo {
84public:
Shafik Yaghmour28c878a2022-03-14 20:32:0385 DummyStopInfo(Thread &thread, uint64_t value) : StopInfo(thread, value) {}
Ilya Bukonkin3b43f002020-06-11 21:59:1986
87 bool ShouldStop(Event *event_ptr) override { return m_should_stop; }
88
89 StopReason GetStopReason() const override { return m_stop_reason; }
90
Shafik Yaghmour28c878a2022-03-14 20:32:0391 bool m_should_stop = true;
92 StopReason m_stop_reason = eStopReasonBreakpoint;
Ilya Bukonkin3b43f002020-06-11 21:59:1993};
94
95class DummyProcessEventData : public Process::ProcessEventData {
96public:
97 DummyProcessEventData(ProcessSP &process_sp, StateType state)
Shafik Yaghmour28c878a2022-03-14 20:32:0398 : ProcessEventData(process_sp, state) {}
Ilya Bukonkin3b43f002020-06-11 21:59:1999 bool ShouldStop(Event *event_ptr, bool &found_valid_stopinfo) override {
100 m_should_stop_hit_count++;
101 return false;
102 }
103
Shafik Yaghmour28c878a2022-03-14 20:32:03104 int m_should_stop_hit_count = 0;
Ilya Bukonkin3b43f002020-06-11 21:59:19105};
106} // namespace
107
108typedef std::shared_ptr<Process::ProcessEventData> ProcessEventDataSP;
109typedef std::shared_ptr<Event> EventSP;
110
111TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
Ilya Bukonkin3b43f002020-06-11 21:59:19112 PlatformSP platform_sp;
113 TargetSP target_sp;
Tatyana Krasnukha2634ec62020-12-11 08:09:39114 debugger_sp->GetTargetList().CreateTarget(
Ilya Bukonkin3b43f002020-06-11 21:59:19115 *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
116
Ilya Bukonkin3b43f002020-06-11 21:59:19117 return target_sp;
118}
119
120ThreadSP CreateThread(ProcessSP &process_sp, bool should_stop,
121 bool has_valid_stopinfo) {
122 ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);
123 if (thread_sp == nullptr) {
124 return nullptr;
125 }
126
127 if (has_valid_stopinfo) {
128 StopInfoSP stopinfo_sp =
129 std::make_shared<DummyStopInfo>(*thread_sp.get(), 0);
130 static_cast<DummyStopInfo *>(stopinfo_sp.get())->m_should_stop =
131 should_stop;
132 if (stopinfo_sp == nullptr) {
133 return nullptr;
134 }
135
136 thread_sp->SetStopInfo(stopinfo_sp);
137 }
138
139 process_sp->GetThreadList().AddThread(thread_sp);
140
141 return thread_sp;
142}
143
Jim Inghama7816c82024-07-15 23:00:58144// Disable this test till I figure out why changing how events are sent
145// to Secondary Listeners (44d9692e6a657ec46e98e4912ac56417da67cfee)
146// caused this test to fail. It is testing responses to events that are
147// not delivered in the way Process events are meant to be delivered, it
148// bypasses the private event queue, and I'm not sure is testing real
149// behaviors.
150#if 0
Ilya Bukonkin3b43f002020-06-11 21:59:19151TEST_F(ProcessEventDataTest, DoOnRemoval) {
152 ArchSpec arch("x86_64-apple-macosx-");
153
Med Ismail Bennanid6678402023-01-13 16:51:03154 Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
Ilya Bukonkin3b43f002020-06-11 21:59:19155
156 DebuggerSP debugger_sp = Debugger::CreateInstance();
157 ASSERT_TRUE(debugger_sp);
158
159 TargetSP target_sp = CreateTarget(debugger_sp, arch);
160 ASSERT_TRUE(target_sp);
161
162 ListenerSP listener_sp(Listener::MakeListener("dummy"));
163 ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
164 ASSERT_TRUE(process_sp);
165
166 /*
167 Should hit ShouldStop if state is eStateStopped
168 */
169 ProcessEventDataSP event_data_sp =
170 std::make_shared<DummyProcessEventData>(process_sp, eStateStopped);
171 EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
172 event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
173 event_data_sp->DoOnRemoval(event_sp.get());
174 bool result = static_cast<DummyProcessEventData *>(event_data_sp.get())
175 ->m_should_stop_hit_count == 1;
176 ASSERT_TRUE(result);
177
178 /*
179 Should not hit ShouldStop if state is not eStateStopped
180 */
181 event_data_sp =
182 std::make_shared<DummyProcessEventData>(process_sp, eStateStepping);
183 event_sp = std::make_shared<Event>(0, event_data_sp);
184 event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
185 event_data_sp->DoOnRemoval(event_sp.get());
186 result = static_cast<DummyProcessEventData *>(event_data_sp.get())
187 ->m_should_stop_hit_count == 0;
188 ASSERT_TRUE(result);
189}
Jim Inghama7816c82024-07-15 23:00:58190#endif
Ilya Bukonkin3b43f002020-06-11 21:59:19191
192TEST_F(ProcessEventDataTest, ShouldStop) {
193 ArchSpec arch("x86_64-apple-macosx-");
194
Med Ismail Bennanid6678402023-01-13 16:51:03195 Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
Ilya Bukonkin3b43f002020-06-11 21:59:19196
197 DebuggerSP debugger_sp = Debugger::CreateInstance();
198 ASSERT_TRUE(debugger_sp);
199
200 TargetSP target_sp = CreateTarget(debugger_sp, arch);
201 ASSERT_TRUE(target_sp);
202
203 ListenerSP listener_sp(Listener::MakeListener("dummy"));
204 ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
205 ASSERT_TRUE(process_sp);
206
207 // wants to stop and has valid StopInfo
208 ThreadSP thread_sp = CreateThread(process_sp, true, true);
209
210 ProcessEventDataSP event_data_sp =
211 std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
212 EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
213 /*
214 Should stop if thread has valid StopInfo and not suspended
215 */
216 bool found_valid_stopinfo = false;
217 bool should_stop =
218 event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
219 ASSERT_TRUE(should_stop == true && found_valid_stopinfo == true);
220
221 /*
222 Should not stop if thread has valid StopInfo but was suspended
223 */
224 found_valid_stopinfo = false;
225 thread_sp->SetResumeState(eStateSuspended);
226 should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
227 ASSERT_TRUE(should_stop == false && found_valid_stopinfo == false);
228
229 /*
230 Should not stop, thread-reason of stop does not want to stop in its
231 callback and suspended thread who wants to (from previous stop)
232 must be ignored.
233 */
234 event_data_sp =
235 std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
236 event_sp = std::make_shared<Event>(0, event_data_sp);
237 process_sp->GetThreadList().Clear();
238
239 for (int i = 0; i < 6; i++) {
240 if (i == 2) {
241 // Does not want to stop but has valid StopInfo
242 thread_sp = CreateThread(process_sp, false, true);
243 } else if (i == 5) {
244 // Wants to stop and has valid StopInfo
245 thread_sp = CreateThread(process_sp, true, true);
246 thread_sp->SetResumeState(eStateSuspended);
247 } else {
248 // Thread has no StopInfo i.e is not the reason of stop
249 thread_sp = CreateThread(process_sp, false, false);
250 }
251 }
252 ASSERT_TRUE(process_sp->GetThreadList().GetSize() == 6);
253
254 found_valid_stopinfo = false;
255 should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
256 ASSERT_TRUE(should_stop == false && found_valid_stopinfo == true);
257}