xref: /llvm-project/lldb/unittests/Process/ProcessEventDataTest.cpp (revision 68466861283fe5913a384d4f7bf28f60aa5dc3c2)
1 //===-- 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"
10 #include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Host/FileSystem.h"
13 #include "lldb/Host/HostInfo.h"
14 #include "lldb/Target/Process.h"
15 #include "lldb/Target/StopInfo.h"
16 #include "lldb/Target/Thread.h"
17 #include "lldb/Utility/ArchSpec.h"
18 #include "lldb/Utility/Event.h"
19 #include "lldb/Utility/Reproducer.h"
20 #include "gtest/gtest.h"
21 
22 using namespace lldb_private;
23 using namespace lldb_private::repro;
24 using namespace lldb;
25 
26 namespace {
27 class ProcessEventDataTest : public ::testing::Test {
28 public:
29   void SetUp() override {
30     llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
31     FileSystem::Initialize();
32     HostInfo::Initialize();
33     PlatformMacOSX::Initialize();
34   }
35   void TearDown() override {
36     PlatformMacOSX::Terminate();
37     HostInfo::Terminate();
38     FileSystem::Terminate();
39     Reproducer::Terminate();
40   }
41 };
42 
43 class DummyProcess : public Process {
44 public:
45   using Process::Process;
46 
47   bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
48     return true;
49   }
50   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 {
54     return 0;
55   }
56   bool DoUpdateThreadList(ThreadList &old_thread_list,
57                           ThreadList &new_thread_list) override {
58     return false;
59   }
60   ConstString GetPluginName() override { return ConstString("Dummy"); }
61   uint32_t GetPluginVersion() override { return 0; }
62 
63   ProcessModID &GetModIDNonConstRef() { return m_mod_id; }
64 };
65 
66 class DummyThread : public Thread {
67 public:
68   using Thread::Thread;
69 
70   ~DummyThread() override { DestroyThread(); }
71 
72   void RefreshStateAfterStop() override {}
73 
74   lldb::RegisterContextSP GetRegisterContext() override { return nullptr; }
75 
76   lldb::RegisterContextSP
77   CreateRegisterContextForFrame(StackFrame *frame) override {
78     return nullptr;
79   }
80 
81   bool CalculateStopInfo() override { return false; }
82 };
83 
84 class DummyStopInfo : public StopInfo {
85 public:
86   DummyStopInfo(Thread &thread, uint64_t value)
87       : StopInfo(thread, value), m_should_stop(true),
88         m_stop_reason(eStopReasonBreakpoint) {}
89 
90   bool ShouldStop(Event *event_ptr) override { return m_should_stop; }
91 
92   StopReason GetStopReason() const override { return m_stop_reason; }
93 
94   bool m_should_stop;
95   StopReason m_stop_reason;
96 };
97 
98 class DummyProcessEventData : public Process::ProcessEventData {
99 public:
100   DummyProcessEventData(ProcessSP &process_sp, StateType state)
101       : ProcessEventData(process_sp, state), m_should_stop_hit_count(0) {}
102   bool ShouldStop(Event *event_ptr, bool &found_valid_stopinfo) override {
103     m_should_stop_hit_count++;
104     return false;
105   }
106 
107   int m_should_stop_hit_count;
108 };
109 } // namespace
110 
111 typedef std::shared_ptr<Process::ProcessEventData> ProcessEventDataSP;
112 typedef std::shared_ptr<Event> EventSP;
113 
114 TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
115   PlatformSP platform_sp;
116   TargetSP target_sp;
117   debugger_sp->GetTargetList().CreateTarget(
118       *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
119 
120   return target_sp;
121 }
122 
123 ThreadSP CreateThread(ProcessSP &process_sp, bool should_stop,
124                       bool has_valid_stopinfo) {
125   ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);
126   if (thread_sp == nullptr) {
127     return nullptr;
128   }
129 
130   if (has_valid_stopinfo) {
131     StopInfoSP stopinfo_sp =
132         std::make_shared<DummyStopInfo>(*thread_sp.get(), 0);
133     static_cast<DummyStopInfo *>(stopinfo_sp.get())->m_should_stop =
134         should_stop;
135     if (stopinfo_sp == nullptr) {
136       return nullptr;
137     }
138 
139     thread_sp->SetStopInfo(stopinfo_sp);
140   }
141 
142   process_sp->GetThreadList().AddThread(thread_sp);
143 
144   return thread_sp;
145 }
146 
147 TEST_F(ProcessEventDataTest, DoOnRemoval) {
148   ArchSpec arch("x86_64-apple-macosx-");
149 
150   Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
151 
152   DebuggerSP debugger_sp = Debugger::CreateInstance();
153   ASSERT_TRUE(debugger_sp);
154 
155   TargetSP target_sp = CreateTarget(debugger_sp, arch);
156   ASSERT_TRUE(target_sp);
157 
158   ListenerSP listener_sp(Listener::MakeListener("dummy"));
159   ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
160   ASSERT_TRUE(process_sp);
161 
162   /*
163    Should hit ShouldStop if state is eStateStopped
164    */
165   ProcessEventDataSP event_data_sp =
166       std::make_shared<DummyProcessEventData>(process_sp, eStateStopped);
167   EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
168   event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
169   event_data_sp->DoOnRemoval(event_sp.get());
170   bool result = static_cast<DummyProcessEventData *>(event_data_sp.get())
171                     ->m_should_stop_hit_count == 1;
172   ASSERT_TRUE(result);
173 
174   /*
175    Should not hit ShouldStop if state is not eStateStopped
176    */
177   event_data_sp =
178       std::make_shared<DummyProcessEventData>(process_sp, eStateStepping);
179   event_sp = std::make_shared<Event>(0, event_data_sp);
180   event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
181   event_data_sp->DoOnRemoval(event_sp.get());
182   result = static_cast<DummyProcessEventData *>(event_data_sp.get())
183                ->m_should_stop_hit_count == 0;
184   ASSERT_TRUE(result);
185 }
186 
187 TEST_F(ProcessEventDataTest, ShouldStop) {
188   ArchSpec arch("x86_64-apple-macosx-");
189 
190   Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
191 
192   DebuggerSP debugger_sp = Debugger::CreateInstance();
193   ASSERT_TRUE(debugger_sp);
194 
195   TargetSP target_sp = CreateTarget(debugger_sp, arch);
196   ASSERT_TRUE(target_sp);
197 
198   ListenerSP listener_sp(Listener::MakeListener("dummy"));
199   ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
200   ASSERT_TRUE(process_sp);
201 
202   // wants to stop and has valid StopInfo
203   ThreadSP thread_sp = CreateThread(process_sp, true, true);
204 
205   ProcessEventDataSP event_data_sp =
206       std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
207   EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
208   /*
209    Should stop if thread has valid StopInfo and not suspended
210    */
211   bool found_valid_stopinfo = false;
212   bool should_stop =
213       event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
214   ASSERT_TRUE(should_stop == true && found_valid_stopinfo == true);
215 
216   /*
217    Should not stop if thread has valid StopInfo but was suspended
218    */
219   found_valid_stopinfo = false;
220   thread_sp->SetResumeState(eStateSuspended);
221   should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
222   ASSERT_TRUE(should_stop == false && found_valid_stopinfo == false);
223 
224   /*
225    Should not stop, thread-reason of stop does not want to stop in its
226    callback and suspended thread who wants to (from previous stop)
227    must be ignored.
228    */
229   event_data_sp =
230       std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
231   event_sp = std::make_shared<Event>(0, event_data_sp);
232   process_sp->GetThreadList().Clear();
233 
234   for (int i = 0; i < 6; i++) {
235     if (i == 2) {
236       // Does not want to stop but has valid StopInfo
237       thread_sp = CreateThread(process_sp, false, true);
238     } else if (i == 5) {
239       // Wants to stop and has valid StopInfo
240       thread_sp = CreateThread(process_sp, true, true);
241       thread_sp->SetResumeState(eStateSuspended);
242     } else {
243       // Thread has no StopInfo i.e is not the reason of stop
244       thread_sp = CreateThread(process_sp, false, false);
245     }
246   }
247   ASSERT_TRUE(process_sp->GetThreadList().GetSize() == 6);
248 
249   found_valid_stopinfo = false;
250   should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
251   ASSERT_TRUE(should_stop == false && found_valid_stopinfo == true);
252 }
253