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