1 //===-- ProcessEventDataTest.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 "Plugins/Platform/MacOSX/PlatformMacOSX.h"
10 #include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
11 #include "TestingSupport/TestUtilities.h"
12 #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"
20 #include "gtest/gtest.h"
22 using namespace lldb_private
;
23 using namespace lldb_private::repro
;
27 class ProcessEventDataTest
: public ::testing::Test
{
29 void SetUp() override
{
30 FileSystem::Initialize();
31 HostInfo::Initialize();
32 PlatformMacOSX::Initialize();
33 std::call_once(TestUtilities::g_debugger_initialize_flag
,
34 []() { Debugger::Initialize(nullptr); });
36 void TearDown() override
{
37 PlatformMacOSX::Terminate();
38 HostInfo::Terminate();
39 FileSystem::Terminate();
43 class DummyProcess
: public Process
{
45 DummyProcess(lldb::TargetSP target_sp
, lldb::ListenerSP listener_sp
)
46 : Process(target_sp
, listener_sp
) {}
48 bool CanDebug(lldb::TargetSP target
, bool plugin_specified_by_name
) override
{
51 Status
DoDestroy() override
{ return {}; }
52 void RefreshStateAfterStop() override
{}
53 size_t DoReadMemory(lldb::addr_t vm_addr
, void *buf
, size_t size
,
54 Status
&error
) override
{
57 bool DoUpdateThreadList(ThreadList
&old_thread_list
,
58 ThreadList
&new_thread_list
) override
{
61 llvm::StringRef
GetPluginName() override
{ return "Dummy"; }
63 ProcessModID
&GetModIDNonConstRef() { return m_mod_id
; }
66 class DummyThread
: public Thread
{
70 ~DummyThread() override
{ DestroyThread(); }
72 void RefreshStateAfterStop() override
{}
74 lldb::RegisterContextSP
GetRegisterContext() override
{ return nullptr; }
76 lldb::RegisterContextSP
77 CreateRegisterContextForFrame(StackFrame
*frame
) override
{
81 bool CalculateStopInfo() override
{ return false; }
84 class DummyStopInfo
: public StopInfo
{
86 DummyStopInfo(Thread
&thread
, uint64_t value
) : StopInfo(thread
, value
) {}
88 bool ShouldStop(Event
*event_ptr
) override
{ return m_should_stop
; }
90 StopReason
GetStopReason() const override
{ return m_stop_reason
; }
92 bool m_should_stop
= true;
93 StopReason m_stop_reason
= eStopReasonBreakpoint
;
96 class DummyProcessEventData
: public Process::ProcessEventData
{
98 DummyProcessEventData(ProcessSP
&process_sp
, StateType state
)
99 : ProcessEventData(process_sp
, state
) {}
100 bool ShouldStop(Event
*event_ptr
, bool &found_valid_stopinfo
) override
{
101 m_should_stop_hit_count
++;
105 int m_should_stop_hit_count
= 0;
109 typedef std::shared_ptr
<Process::ProcessEventData
> ProcessEventDataSP
;
110 typedef std::shared_ptr
<Event
> EventSP
;
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
);
121 ThreadSP
CreateThread(ProcessSP
&process_sp
, bool should_stop
,
122 bool has_valid_stopinfo
) {
123 ThreadSP thread_sp
= std::make_shared
<DummyThread
>(*process_sp
.get(), 0);
124 if (thread_sp
== nullptr) {
128 if (has_valid_stopinfo
) {
129 StopInfoSP stopinfo_sp
=
130 std::make_shared
<DummyStopInfo
>(*thread_sp
.get(), 0);
131 static_cast<DummyStopInfo
*>(stopinfo_sp
.get())->m_should_stop
=
133 if (stopinfo_sp
== nullptr) {
137 thread_sp
->SetStopInfo(stopinfo_sp
);
140 process_sp
->GetThreadList().AddThread(thread_sp
);
145 // Disable this test till I figure out why changing how events are sent
146 // to Secondary Listeners (44d9692e6a657ec46e98e4912ac56417da67cfee)
147 // caused this test to fail. It is testing responses to events that are
148 // not delivered in the way Process events are meant to be delivered, it
149 // bypasses the private event queue, and I'm not sure is testing real
152 TEST_F(ProcessEventDataTest
, DoOnRemoval
) {
153 ArchSpec
arch("x86_64-apple-macosx-");
155 Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch
));
157 DebuggerSP debugger_sp
= Debugger::CreateInstance();
158 ASSERT_TRUE(debugger_sp
);
160 TargetSP target_sp
= CreateTarget(debugger_sp
, arch
);
161 ASSERT_TRUE(target_sp
);
163 ListenerSP
listener_sp(Listener::MakeListener("dummy"));
164 ProcessSP process_sp
= std::make_shared
<DummyProcess
>(target_sp
, listener_sp
);
165 ASSERT_TRUE(process_sp
);
168 Should hit ShouldStop if state is eStateStopped
170 ProcessEventDataSP event_data_sp
=
171 std::make_shared
<DummyProcessEventData
>(process_sp
, eStateStopped
);
172 EventSP event_sp
= std::make_shared
<Event
>(0, event_data_sp
);
173 event_data_sp
->SetUpdateStateOnRemoval(event_sp
.get());
174 event_data_sp
->DoOnRemoval(event_sp
.get());
175 bool result
= static_cast<DummyProcessEventData
*>(event_data_sp
.get())
176 ->m_should_stop_hit_count
== 1;
180 Should not hit ShouldStop if state is not eStateStopped
183 std::make_shared
<DummyProcessEventData
>(process_sp
, eStateStepping
);
184 event_sp
= std::make_shared
<Event
>(0, event_data_sp
);
185 event_data_sp
->SetUpdateStateOnRemoval(event_sp
.get());
186 event_data_sp
->DoOnRemoval(event_sp
.get());
187 result
= static_cast<DummyProcessEventData
*>(event_data_sp
.get())
188 ->m_should_stop_hit_count
== 0;
193 TEST_F(ProcessEventDataTest
, ShouldStop
) {
194 ArchSpec
arch("x86_64-apple-macosx-");
196 Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch
));
198 DebuggerSP debugger_sp
= Debugger::CreateInstance();
199 ASSERT_TRUE(debugger_sp
);
201 TargetSP target_sp
= CreateTarget(debugger_sp
, arch
);
202 ASSERT_TRUE(target_sp
);
204 ListenerSP
listener_sp(Listener::MakeListener("dummy"));
205 ProcessSP process_sp
= std::make_shared
<DummyProcess
>(target_sp
, listener_sp
);
206 ASSERT_TRUE(process_sp
);
208 // wants to stop and has valid StopInfo
209 ThreadSP thread_sp
= CreateThread(process_sp
, true, true);
211 ProcessEventDataSP event_data_sp
=
212 std::make_shared
<Process::ProcessEventData
>(process_sp
, eStateStopped
);
213 EventSP event_sp
= std::make_shared
<Event
>(0, event_data_sp
);
215 Should stop if thread has valid StopInfo and not suspended
217 bool found_valid_stopinfo
= false;
219 event_data_sp
->ShouldStop(event_sp
.get(), found_valid_stopinfo
);
220 ASSERT_TRUE(should_stop
== true && found_valid_stopinfo
== true);
223 Should not stop if thread has valid StopInfo but was suspended
225 found_valid_stopinfo
= false;
226 thread_sp
->SetResumeState(eStateSuspended
);
227 should_stop
= event_data_sp
->ShouldStop(event_sp
.get(), found_valid_stopinfo
);
228 ASSERT_TRUE(should_stop
== false && found_valid_stopinfo
== false);
231 Should not stop, thread-reason of stop does not want to stop in its
232 callback and suspended thread who wants to (from previous stop)
236 std::make_shared
<Process::ProcessEventData
>(process_sp
, eStateStopped
);
237 event_sp
= std::make_shared
<Event
>(0, event_data_sp
);
238 process_sp
->GetThreadList().Clear();
240 for (int i
= 0; i
< 6; i
++) {
242 // Does not want to stop but has valid StopInfo
243 thread_sp
= CreateThread(process_sp
, false, true);
245 // Wants to stop and has valid StopInfo
246 thread_sp
= CreateThread(process_sp
, true, true);
247 thread_sp
->SetResumeState(eStateSuspended
);
249 // Thread has no StopInfo i.e is not the reason of stop
250 thread_sp
= CreateThread(process_sp
, false, false);
253 ASSERT_TRUE(process_sp
->GetThreadList().GetSize() == 6);
255 found_valid_stopinfo
= false;
256 should_stop
= event_data_sp
->ShouldStop(event_sp
.get(), found_valid_stopinfo
);
257 ASSERT_TRUE(should_stop
== false && found_valid_stopinfo
== true);