13b43f006SIlya Bukonkin //===-- ProcessEventDataTest.cpp ------------------------------------------===//
23b43f006SIlya Bukonkin //
33b43f006SIlya Bukonkin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43b43f006SIlya Bukonkin // See https://llvm.org/LICENSE.txt for license information.
53b43f006SIlya Bukonkin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63b43f006SIlya Bukonkin //
73b43f006SIlya Bukonkin //===----------------------------------------------------------------------===//
83b43f006SIlya Bukonkin 
93b43f006SIlya Bukonkin #include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
10dd2054d3SJonas Devlieghere #include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
113b43f006SIlya Bukonkin #include "lldb/Core/Debugger.h"
123b43f006SIlya Bukonkin #include "lldb/Host/FileSystem.h"
133b43f006SIlya Bukonkin #include "lldb/Host/HostInfo.h"
143b43f006SIlya Bukonkin #include "lldb/Target/Process.h"
153b43f006SIlya Bukonkin #include "lldb/Target/StopInfo.h"
163b43f006SIlya Bukonkin #include "lldb/Target/Thread.h"
173b43f006SIlya Bukonkin #include "lldb/Utility/ArchSpec.h"
183b43f006SIlya Bukonkin #include "lldb/Utility/Event.h"
193b43f006SIlya Bukonkin #include "lldb/Utility/Reproducer.h"
203b43f006SIlya Bukonkin #include "gtest/gtest.h"
213b43f006SIlya Bukonkin 
223b43f006SIlya Bukonkin using namespace lldb_private;
233b43f006SIlya Bukonkin using namespace lldb_private::repro;
243b43f006SIlya Bukonkin using namespace lldb;
253b43f006SIlya Bukonkin 
263b43f006SIlya Bukonkin namespace {
273b43f006SIlya Bukonkin class ProcessEventDataTest : public ::testing::Test {
283b43f006SIlya Bukonkin public:
SetUp()293b43f006SIlya Bukonkin   void SetUp() override {
303b43f006SIlya Bukonkin     llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
313b43f006SIlya Bukonkin     FileSystem::Initialize();
323b43f006SIlya Bukonkin     HostInfo::Initialize();
333b43f006SIlya Bukonkin     PlatformMacOSX::Initialize();
343b43f006SIlya Bukonkin   }
TearDown()353b43f006SIlya Bukonkin   void TearDown() override {
363b43f006SIlya Bukonkin     PlatformMacOSX::Terminate();
373b43f006SIlya Bukonkin     HostInfo::Terminate();
383b43f006SIlya Bukonkin     FileSystem::Terminate();
393b43f006SIlya Bukonkin     Reproducer::Terminate();
403b43f006SIlya Bukonkin   }
413b43f006SIlya Bukonkin };
423b43f006SIlya Bukonkin 
433b43f006SIlya Bukonkin class DummyProcess : public Process {
443b43f006SIlya Bukonkin public:
453b43f006SIlya Bukonkin   using Process::Process;
463b43f006SIlya Bukonkin 
CanDebug(lldb::TargetSP target,bool plugin_specified_by_name)4768466861SDavid Blaikie   bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
483b43f006SIlya Bukonkin     return true;
493b43f006SIlya Bukonkin   }
DoDestroy()5068466861SDavid Blaikie   Status DoDestroy() override { return {}; }
RefreshStateAfterStop()5168466861SDavid Blaikie   void RefreshStateAfterStop() override {}
DoReadMemory(lldb::addr_t vm_addr,void * buf,size_t size,Status & error)5268466861SDavid Blaikie   size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
5368466861SDavid Blaikie                       Status &error) override {
543b43f006SIlya Bukonkin     return 0;
553b43f006SIlya Bukonkin   }
DoUpdateThreadList(ThreadList & old_thread_list,ThreadList & new_thread_list)564bb62448SWalter Erquinigo   bool DoUpdateThreadList(ThreadList &old_thread_list,
574bb62448SWalter Erquinigo                           ThreadList &new_thread_list) override {
583b43f006SIlya Bukonkin     return false;
593b43f006SIlya Bukonkin   }
GetPluginName()60a3939e15SPavel Labath   llvm::StringRef GetPluginName() override { return "Dummy"; }
613b43f006SIlya Bukonkin 
GetModIDNonConstRef()623b43f006SIlya Bukonkin   ProcessModID &GetModIDNonConstRef() { return m_mod_id; }
633b43f006SIlya Bukonkin };
643b43f006SIlya Bukonkin 
653b43f006SIlya Bukonkin class DummyThread : public Thread {
663b43f006SIlya Bukonkin public:
673b43f006SIlya Bukonkin   using Thread::Thread;
683b43f006SIlya Bukonkin 
~DummyThread()693b43f006SIlya Bukonkin   ~DummyThread() override { DestroyThread(); }
703b43f006SIlya Bukonkin 
RefreshStateAfterStop()713b43f006SIlya Bukonkin   void RefreshStateAfterStop() override {}
723b43f006SIlya Bukonkin 
GetRegisterContext()733b43f006SIlya Bukonkin   lldb::RegisterContextSP GetRegisterContext() override { return nullptr; }
743b43f006SIlya Bukonkin 
753b43f006SIlya Bukonkin   lldb::RegisterContextSP
CreateRegisterContextForFrame(StackFrame * frame)763b43f006SIlya Bukonkin   CreateRegisterContextForFrame(StackFrame *frame) override {
773b43f006SIlya Bukonkin     return nullptr;
783b43f006SIlya Bukonkin   }
793b43f006SIlya Bukonkin 
CalculateStopInfo()803b43f006SIlya Bukonkin   bool CalculateStopInfo() override { return false; }
813b43f006SIlya Bukonkin };
823b43f006SIlya Bukonkin 
833b43f006SIlya Bukonkin class DummyStopInfo : public StopInfo {
843b43f006SIlya Bukonkin public:
DummyStopInfo(Thread & thread,uint64_t value)85*28c878aeSShafik Yaghmour   DummyStopInfo(Thread &thread, uint64_t value) : StopInfo(thread, value) {}
863b43f006SIlya Bukonkin 
ShouldStop(Event * event_ptr)873b43f006SIlya Bukonkin   bool ShouldStop(Event *event_ptr) override { return m_should_stop; }
883b43f006SIlya Bukonkin 
GetStopReason() const893b43f006SIlya Bukonkin   StopReason GetStopReason() const override { return m_stop_reason; }
903b43f006SIlya Bukonkin 
91*28c878aeSShafik Yaghmour   bool m_should_stop = true;
92*28c878aeSShafik Yaghmour   StopReason m_stop_reason = eStopReasonBreakpoint;
933b43f006SIlya Bukonkin };
943b43f006SIlya Bukonkin 
953b43f006SIlya Bukonkin class DummyProcessEventData : public Process::ProcessEventData {
963b43f006SIlya Bukonkin public:
DummyProcessEventData(ProcessSP & process_sp,StateType state)973b43f006SIlya Bukonkin   DummyProcessEventData(ProcessSP &process_sp, StateType state)
98*28c878aeSShafik Yaghmour       : ProcessEventData(process_sp, state) {}
ShouldStop(Event * event_ptr,bool & found_valid_stopinfo)993b43f006SIlya Bukonkin   bool ShouldStop(Event *event_ptr, bool &found_valid_stopinfo) override {
1003b43f006SIlya Bukonkin     m_should_stop_hit_count++;
1013b43f006SIlya Bukonkin     return false;
1023b43f006SIlya Bukonkin   }
1033b43f006SIlya Bukonkin 
104*28c878aeSShafik Yaghmour   int m_should_stop_hit_count = 0;
1053b43f006SIlya Bukonkin };
1063b43f006SIlya Bukonkin } // namespace
1073b43f006SIlya Bukonkin 
1083b43f006SIlya Bukonkin typedef std::shared_ptr<Process::ProcessEventData> ProcessEventDataSP;
1093b43f006SIlya Bukonkin typedef std::shared_ptr<Event> EventSP;
1103b43f006SIlya Bukonkin 
CreateTarget(DebuggerSP & debugger_sp,ArchSpec & arch)1113b43f006SIlya Bukonkin TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
1123b43f006SIlya Bukonkin   PlatformSP platform_sp;
1133b43f006SIlya Bukonkin   TargetSP target_sp;
1142634ec6cSTatyana Krasnukha   debugger_sp->GetTargetList().CreateTarget(
1153b43f006SIlya Bukonkin       *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
1163b43f006SIlya Bukonkin 
1173b43f006SIlya Bukonkin   return target_sp;
1183b43f006SIlya Bukonkin }
1193b43f006SIlya Bukonkin 
CreateThread(ProcessSP & process_sp,bool should_stop,bool has_valid_stopinfo)1203b43f006SIlya Bukonkin ThreadSP CreateThread(ProcessSP &process_sp, bool should_stop,
1213b43f006SIlya Bukonkin                       bool has_valid_stopinfo) {
1223b43f006SIlya Bukonkin   ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);
1233b43f006SIlya Bukonkin   if (thread_sp == nullptr) {
1243b43f006SIlya Bukonkin     return nullptr;
1253b43f006SIlya Bukonkin   }
1263b43f006SIlya Bukonkin 
1273b43f006SIlya Bukonkin   if (has_valid_stopinfo) {
1283b43f006SIlya Bukonkin     StopInfoSP stopinfo_sp =
1293b43f006SIlya Bukonkin         std::make_shared<DummyStopInfo>(*thread_sp.get(), 0);
1303b43f006SIlya Bukonkin     static_cast<DummyStopInfo *>(stopinfo_sp.get())->m_should_stop =
1313b43f006SIlya Bukonkin         should_stop;
1323b43f006SIlya Bukonkin     if (stopinfo_sp == nullptr) {
1333b43f006SIlya Bukonkin       return nullptr;
1343b43f006SIlya Bukonkin     }
1353b43f006SIlya Bukonkin 
1363b43f006SIlya Bukonkin     thread_sp->SetStopInfo(stopinfo_sp);
1373b43f006SIlya Bukonkin   }
1383b43f006SIlya Bukonkin 
1393b43f006SIlya Bukonkin   process_sp->GetThreadList().AddThread(thread_sp);
1403b43f006SIlya Bukonkin 
1413b43f006SIlya Bukonkin   return thread_sp;
1423b43f006SIlya Bukonkin }
1433b43f006SIlya Bukonkin 
TEST_F(ProcessEventDataTest,DoOnRemoval)1443b43f006SIlya Bukonkin TEST_F(ProcessEventDataTest, DoOnRemoval) {
1453b43f006SIlya Bukonkin   ArchSpec arch("x86_64-apple-macosx-");
1463b43f006SIlya Bukonkin 
147dd2054d3SJonas Devlieghere   Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
1483b43f006SIlya Bukonkin 
1493b43f006SIlya Bukonkin   DebuggerSP debugger_sp = Debugger::CreateInstance();
1503b43f006SIlya Bukonkin   ASSERT_TRUE(debugger_sp);
1513b43f006SIlya Bukonkin 
1523b43f006SIlya Bukonkin   TargetSP target_sp = CreateTarget(debugger_sp, arch);
1533b43f006SIlya Bukonkin   ASSERT_TRUE(target_sp);
1543b43f006SIlya Bukonkin 
1553b43f006SIlya Bukonkin   ListenerSP listener_sp(Listener::MakeListener("dummy"));
1563b43f006SIlya Bukonkin   ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
1573b43f006SIlya Bukonkin   ASSERT_TRUE(process_sp);
1583b43f006SIlya Bukonkin 
1593b43f006SIlya Bukonkin   /*
1603b43f006SIlya Bukonkin    Should hit ShouldStop if state is eStateStopped
1613b43f006SIlya Bukonkin    */
1623b43f006SIlya Bukonkin   ProcessEventDataSP event_data_sp =
1633b43f006SIlya Bukonkin       std::make_shared<DummyProcessEventData>(process_sp, eStateStopped);
1643b43f006SIlya Bukonkin   EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
1653b43f006SIlya Bukonkin   event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
1663b43f006SIlya Bukonkin   event_data_sp->DoOnRemoval(event_sp.get());
1673b43f006SIlya Bukonkin   bool result = static_cast<DummyProcessEventData *>(event_data_sp.get())
1683b43f006SIlya Bukonkin                     ->m_should_stop_hit_count == 1;
1693b43f006SIlya Bukonkin   ASSERT_TRUE(result);
1703b43f006SIlya Bukonkin 
1713b43f006SIlya Bukonkin   /*
1723b43f006SIlya Bukonkin    Should not hit ShouldStop if state is not eStateStopped
1733b43f006SIlya Bukonkin    */
1743b43f006SIlya Bukonkin   event_data_sp =
1753b43f006SIlya Bukonkin       std::make_shared<DummyProcessEventData>(process_sp, eStateStepping);
1763b43f006SIlya Bukonkin   event_sp = std::make_shared<Event>(0, event_data_sp);
1773b43f006SIlya Bukonkin   event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
1783b43f006SIlya Bukonkin   event_data_sp->DoOnRemoval(event_sp.get());
1793b43f006SIlya Bukonkin   result = static_cast<DummyProcessEventData *>(event_data_sp.get())
1803b43f006SIlya Bukonkin                ->m_should_stop_hit_count == 0;
1813b43f006SIlya Bukonkin   ASSERT_TRUE(result);
1823b43f006SIlya Bukonkin }
1833b43f006SIlya Bukonkin 
TEST_F(ProcessEventDataTest,ShouldStop)1843b43f006SIlya Bukonkin TEST_F(ProcessEventDataTest, ShouldStop) {
1853b43f006SIlya Bukonkin   ArchSpec arch("x86_64-apple-macosx-");
1863b43f006SIlya Bukonkin 
187dd2054d3SJonas Devlieghere   Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
1883b43f006SIlya Bukonkin 
1893b43f006SIlya Bukonkin   DebuggerSP debugger_sp = Debugger::CreateInstance();
1903b43f006SIlya Bukonkin   ASSERT_TRUE(debugger_sp);
1913b43f006SIlya Bukonkin 
1923b43f006SIlya Bukonkin   TargetSP target_sp = CreateTarget(debugger_sp, arch);
1933b43f006SIlya Bukonkin   ASSERT_TRUE(target_sp);
1943b43f006SIlya Bukonkin 
1953b43f006SIlya Bukonkin   ListenerSP listener_sp(Listener::MakeListener("dummy"));
1963b43f006SIlya Bukonkin   ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
1973b43f006SIlya Bukonkin   ASSERT_TRUE(process_sp);
1983b43f006SIlya Bukonkin 
1993b43f006SIlya Bukonkin   // wants to stop and has valid StopInfo
2003b43f006SIlya Bukonkin   ThreadSP thread_sp = CreateThread(process_sp, true, true);
2013b43f006SIlya Bukonkin 
2023b43f006SIlya Bukonkin   ProcessEventDataSP event_data_sp =
2033b43f006SIlya Bukonkin       std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
2043b43f006SIlya Bukonkin   EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
2053b43f006SIlya Bukonkin   /*
2063b43f006SIlya Bukonkin    Should stop if thread has valid StopInfo and not suspended
2073b43f006SIlya Bukonkin    */
2083b43f006SIlya Bukonkin   bool found_valid_stopinfo = false;
2093b43f006SIlya Bukonkin   bool should_stop =
2103b43f006SIlya Bukonkin       event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
2113b43f006SIlya Bukonkin   ASSERT_TRUE(should_stop == true && found_valid_stopinfo == true);
2123b43f006SIlya Bukonkin 
2133b43f006SIlya Bukonkin   /*
2143b43f006SIlya Bukonkin    Should not stop if thread has valid StopInfo but was suspended
2153b43f006SIlya Bukonkin    */
2163b43f006SIlya Bukonkin   found_valid_stopinfo = false;
2173b43f006SIlya Bukonkin   thread_sp->SetResumeState(eStateSuspended);
2183b43f006SIlya Bukonkin   should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
2193b43f006SIlya Bukonkin   ASSERT_TRUE(should_stop == false && found_valid_stopinfo == false);
2203b43f006SIlya Bukonkin 
2213b43f006SIlya Bukonkin   /*
2223b43f006SIlya Bukonkin    Should not stop, thread-reason of stop does not want to stop in its
2233b43f006SIlya Bukonkin    callback and suspended thread who wants to (from previous stop)
2243b43f006SIlya Bukonkin    must be ignored.
2253b43f006SIlya Bukonkin    */
2263b43f006SIlya Bukonkin   event_data_sp =
2273b43f006SIlya Bukonkin       std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
2283b43f006SIlya Bukonkin   event_sp = std::make_shared<Event>(0, event_data_sp);
2293b43f006SIlya Bukonkin   process_sp->GetThreadList().Clear();
2303b43f006SIlya Bukonkin 
2313b43f006SIlya Bukonkin   for (int i = 0; i < 6; i++) {
2323b43f006SIlya Bukonkin     if (i == 2) {
2333b43f006SIlya Bukonkin       // Does not want to stop but has valid StopInfo
2343b43f006SIlya Bukonkin       thread_sp = CreateThread(process_sp, false, true);
2353b43f006SIlya Bukonkin     } else if (i == 5) {
2363b43f006SIlya Bukonkin       // Wants to stop and has valid StopInfo
2373b43f006SIlya Bukonkin       thread_sp = CreateThread(process_sp, true, true);
2383b43f006SIlya Bukonkin       thread_sp->SetResumeState(eStateSuspended);
2393b43f006SIlya Bukonkin     } else {
2403b43f006SIlya Bukonkin       // Thread has no StopInfo i.e is not the reason of stop
2413b43f006SIlya Bukonkin       thread_sp = CreateThread(process_sp, false, false);
2423b43f006SIlya Bukonkin     }
2433b43f006SIlya Bukonkin   }
2443b43f006SIlya Bukonkin   ASSERT_TRUE(process_sp->GetThreadList().GetSize() == 6);
2453b43f006SIlya Bukonkin 
2463b43f006SIlya Bukonkin   found_valid_stopinfo = false;
2473b43f006SIlya Bukonkin   should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
2483b43f006SIlya Bukonkin   ASSERT_TRUE(should_stop == false && found_valid_stopinfo == true);
2493b43f006SIlya Bukonkin }
250