xref: /llvm-project/lldb/unittests/Process/ProcessEventDataTest.cpp (revision 9b031d5e3a7b455308257a71116a603e76c8c679)
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   DummyProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
46       : Process(target_sp, listener_sp) {}
47 
48   bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
49     return true;
50   }
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 {
55     return 0;
56   }
57   bool DoUpdateThreadList(ThreadList &old_thread_list,
58                           ThreadList &new_thread_list) override {
59     return false;
60   }
61   llvm::StringRef GetPluginName() override { return "Dummy"; }
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) : StopInfo(thread, value) {}
87 
88   bool ShouldStop(Event *event_ptr) override { return m_should_stop; }
89 
90   StopReason GetStopReason() const override { return m_stop_reason; }
91 
92   bool m_should_stop = true;
93   StopReason m_stop_reason = eStopReasonBreakpoint;
94 };
95 
96 class DummyProcessEventData : public Process::ProcessEventData {
97 public:
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++;
102     return false;
103   }
104 
105   int m_should_stop_hit_count = 0;
106 };
107 } // namespace
108 
109 typedef std::shared_ptr<Process::ProcessEventData> ProcessEventDataSP;
110 typedef std::shared_ptr<Event> EventSP;
111 
112 TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
113   PlatformSP platform_sp;
114   TargetSP target_sp;
115   debugger_sp->GetTargetList().CreateTarget(
116       *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
117 
118   return target_sp;
119 }
120 
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) {
125     return nullptr;
126   }
127 
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 =
132         should_stop;
133     if (stopinfo_sp == nullptr) {
134       return nullptr;
135     }
136 
137     thread_sp->SetStopInfo(stopinfo_sp);
138   }
139 
140   process_sp->GetThreadList().AddThread(thread_sp);
141 
142   return thread_sp;
143 }
144 
145 TEST_F(ProcessEventDataTest, DoOnRemoval) {
146   ArchSpec arch("x86_64-apple-macosx-");
147 
148   Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
149 
150   DebuggerSP debugger_sp = Debugger::CreateInstance();
151   ASSERT_TRUE(debugger_sp);
152 
153   TargetSP target_sp = CreateTarget(debugger_sp, arch);
154   ASSERT_TRUE(target_sp);
155 
156   ListenerSP listener_sp(Listener::MakeListener("dummy"));
157   ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
158   ASSERT_TRUE(process_sp);
159 
160   /*
161    Should hit ShouldStop if state is eStateStopped
162    */
163   ProcessEventDataSP event_data_sp =
164       std::make_shared<DummyProcessEventData>(process_sp, eStateStopped);
165   EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
166   event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
167   event_data_sp->DoOnRemoval(event_sp.get());
168   bool result = static_cast<DummyProcessEventData *>(event_data_sp.get())
169                     ->m_should_stop_hit_count == 1;
170   ASSERT_TRUE(result);
171 
172   /*
173    Should not hit ShouldStop if state is not eStateStopped
174    */
175   event_data_sp =
176       std::make_shared<DummyProcessEventData>(process_sp, eStateStepping);
177   event_sp = std::make_shared<Event>(0, event_data_sp);
178   event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
179   event_data_sp->DoOnRemoval(event_sp.get());
180   result = static_cast<DummyProcessEventData *>(event_data_sp.get())
181                ->m_should_stop_hit_count == 0;
182   ASSERT_TRUE(result);
183 }
184 
185 TEST_F(ProcessEventDataTest, ShouldStop) {
186   ArchSpec arch("x86_64-apple-macosx-");
187 
188   Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
189 
190   DebuggerSP debugger_sp = Debugger::CreateInstance();
191   ASSERT_TRUE(debugger_sp);
192 
193   TargetSP target_sp = CreateTarget(debugger_sp, arch);
194   ASSERT_TRUE(target_sp);
195 
196   ListenerSP listener_sp(Listener::MakeListener("dummy"));
197   ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
198   ASSERT_TRUE(process_sp);
199 
200   // wants to stop and has valid StopInfo
201   ThreadSP thread_sp = CreateThread(process_sp, true, true);
202 
203   ProcessEventDataSP event_data_sp =
204       std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
205   EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
206   /*
207    Should stop if thread has valid StopInfo and not suspended
208    */
209   bool found_valid_stopinfo = false;
210   bool should_stop =
211       event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
212   ASSERT_TRUE(should_stop == true && found_valid_stopinfo == true);
213 
214   /*
215    Should not stop if thread has valid StopInfo but was suspended
216    */
217   found_valid_stopinfo = false;
218   thread_sp->SetResumeState(eStateSuspended);
219   should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
220   ASSERT_TRUE(should_stop == false && found_valid_stopinfo == false);
221 
222   /*
223    Should not stop, thread-reason of stop does not want to stop in its
224    callback and suspended thread who wants to (from previous stop)
225    must be ignored.
226    */
227   event_data_sp =
228       std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
229   event_sp = std::make_shared<Event>(0, event_data_sp);
230   process_sp->GetThreadList().Clear();
231 
232   for (int i = 0; i < 6; i++) {
233     if (i == 2) {
234       // Does not want to stop but has valid StopInfo
235       thread_sp = CreateThread(process_sp, false, true);
236     } else if (i == 5) {
237       // Wants to stop and has valid StopInfo
238       thread_sp = CreateThread(process_sp, true, true);
239       thread_sp->SetResumeState(eStateSuspended);
240     } else {
241       // Thread has no StopInfo i.e is not the reason of stop
242       thread_sp = CreateThread(process_sp, false, false);
243     }
244   }
245   ASSERT_TRUE(process_sp->GetThreadList().GetSize() == 6);
246 
247   found_valid_stopinfo = false;
248   should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
249   ASSERT_TRUE(should_stop == false && found_valid_stopinfo == true);
250 }
251