xref: /llvm-project/lldb/unittests/Process/ProcessEventDataTest.cpp (revision a7816c8e0086c1ae9b8ea15a6c252ca97f0405d1)
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"
11f32c6b28SMed Ismail Bennani #include "TestingSupport/TestUtilities.h"
123b43f006SIlya Bukonkin #include "lldb/Core/Debugger.h"
133b43f006SIlya Bukonkin #include "lldb/Host/FileSystem.h"
143b43f006SIlya Bukonkin #include "lldb/Host/HostInfo.h"
153b43f006SIlya Bukonkin #include "lldb/Target/Process.h"
163b43f006SIlya Bukonkin #include "lldb/Target/StopInfo.h"
173b43f006SIlya Bukonkin #include "lldb/Target/Thread.h"
183b43f006SIlya Bukonkin #include "lldb/Utility/ArchSpec.h"
193b43f006SIlya Bukonkin #include "lldb/Utility/Event.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:
293b43f006SIlya Bukonkin   void SetUp() override {
303b43f006SIlya Bukonkin     FileSystem::Initialize();
313b43f006SIlya Bukonkin     HostInfo::Initialize();
323b43f006SIlya Bukonkin     PlatformMacOSX::Initialize();
33f32c6b28SMed Ismail Bennani     std::call_once(TestUtilities::g_debugger_initialize_flag,
34f32c6b28SMed Ismail Bennani                    []() { Debugger::Initialize(nullptr); });
353b43f006SIlya Bukonkin   }
363b43f006SIlya Bukonkin   void TearDown() override {
373b43f006SIlya Bukonkin     PlatformMacOSX::Terminate();
383b43f006SIlya Bukonkin     HostInfo::Terminate();
393b43f006SIlya Bukonkin     FileSystem::Terminate();
403b43f006SIlya Bukonkin   }
413b43f006SIlya Bukonkin };
423b43f006SIlya Bukonkin 
433b43f006SIlya Bukonkin class DummyProcess : public Process {
443b43f006SIlya Bukonkin public:
459b031d5eSMichał Górny   DummyProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
469b031d5eSMichał Górny       : Process(target_sp, listener_sp) {}
473b43f006SIlya Bukonkin 
4868466861SDavid Blaikie   bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
493b43f006SIlya Bukonkin     return true;
503b43f006SIlya Bukonkin   }
5168466861SDavid Blaikie   Status DoDestroy() override { return {}; }
5268466861SDavid Blaikie   void RefreshStateAfterStop() override {}
5368466861SDavid Blaikie   size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
5468466861SDavid Blaikie                       Status &error) override {
553b43f006SIlya Bukonkin     return 0;
563b43f006SIlya Bukonkin   }
574bb62448SWalter Erquinigo   bool DoUpdateThreadList(ThreadList &old_thread_list,
584bb62448SWalter Erquinigo                           ThreadList &new_thread_list) override {
593b43f006SIlya Bukonkin     return false;
603b43f006SIlya Bukonkin   }
61a3939e15SPavel Labath   llvm::StringRef GetPluginName() override { return "Dummy"; }
623b43f006SIlya Bukonkin 
633b43f006SIlya Bukonkin   ProcessModID &GetModIDNonConstRef() { return m_mod_id; }
643b43f006SIlya Bukonkin };
653b43f006SIlya Bukonkin 
663b43f006SIlya Bukonkin class DummyThread : public Thread {
673b43f006SIlya Bukonkin public:
683b43f006SIlya Bukonkin   using Thread::Thread;
693b43f006SIlya Bukonkin 
703b43f006SIlya Bukonkin   ~DummyThread() override { DestroyThread(); }
713b43f006SIlya Bukonkin 
723b43f006SIlya Bukonkin   void RefreshStateAfterStop() override {}
733b43f006SIlya Bukonkin 
743b43f006SIlya Bukonkin   lldb::RegisterContextSP GetRegisterContext() override { return nullptr; }
753b43f006SIlya Bukonkin 
763b43f006SIlya Bukonkin   lldb::RegisterContextSP
773b43f006SIlya Bukonkin   CreateRegisterContextForFrame(StackFrame *frame) override {
783b43f006SIlya Bukonkin     return nullptr;
793b43f006SIlya Bukonkin   }
803b43f006SIlya Bukonkin 
813b43f006SIlya Bukonkin   bool CalculateStopInfo() override { return false; }
823b43f006SIlya Bukonkin };
833b43f006SIlya Bukonkin 
843b43f006SIlya Bukonkin class DummyStopInfo : public StopInfo {
853b43f006SIlya Bukonkin public:
8628c878aeSShafik Yaghmour   DummyStopInfo(Thread &thread, uint64_t value) : StopInfo(thread, value) {}
873b43f006SIlya Bukonkin 
883b43f006SIlya Bukonkin   bool ShouldStop(Event *event_ptr) override { return m_should_stop; }
893b43f006SIlya Bukonkin 
903b43f006SIlya Bukonkin   StopReason GetStopReason() const override { return m_stop_reason; }
913b43f006SIlya Bukonkin 
9228c878aeSShafik Yaghmour   bool m_should_stop = true;
9328c878aeSShafik Yaghmour   StopReason m_stop_reason = eStopReasonBreakpoint;
943b43f006SIlya Bukonkin };
953b43f006SIlya Bukonkin 
963b43f006SIlya Bukonkin class DummyProcessEventData : public Process::ProcessEventData {
973b43f006SIlya Bukonkin public:
983b43f006SIlya Bukonkin   DummyProcessEventData(ProcessSP &process_sp, StateType state)
9928c878aeSShafik Yaghmour       : ProcessEventData(process_sp, state) {}
1003b43f006SIlya Bukonkin   bool ShouldStop(Event *event_ptr, bool &found_valid_stopinfo) override {
1013b43f006SIlya Bukonkin     m_should_stop_hit_count++;
1023b43f006SIlya Bukonkin     return false;
1033b43f006SIlya Bukonkin   }
1043b43f006SIlya Bukonkin 
10528c878aeSShafik Yaghmour   int m_should_stop_hit_count = 0;
1063b43f006SIlya Bukonkin };
1073b43f006SIlya Bukonkin } // namespace
1083b43f006SIlya Bukonkin 
1093b43f006SIlya Bukonkin typedef std::shared_ptr<Process::ProcessEventData> ProcessEventDataSP;
1103b43f006SIlya Bukonkin typedef std::shared_ptr<Event> EventSP;
1113b43f006SIlya Bukonkin 
1123b43f006SIlya Bukonkin TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
1133b43f006SIlya Bukonkin   PlatformSP platform_sp;
1143b43f006SIlya Bukonkin   TargetSP target_sp;
1152634ec6cSTatyana Krasnukha   debugger_sp->GetTargetList().CreateTarget(
1163b43f006SIlya Bukonkin       *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
1173b43f006SIlya Bukonkin 
1183b43f006SIlya Bukonkin   return target_sp;
1193b43f006SIlya Bukonkin }
1203b43f006SIlya Bukonkin 
1213b43f006SIlya Bukonkin ThreadSP CreateThread(ProcessSP &process_sp, bool should_stop,
1223b43f006SIlya Bukonkin                       bool has_valid_stopinfo) {
1233b43f006SIlya Bukonkin   ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);
1243b43f006SIlya Bukonkin   if (thread_sp == nullptr) {
1253b43f006SIlya Bukonkin     return nullptr;
1263b43f006SIlya Bukonkin   }
1273b43f006SIlya Bukonkin 
1283b43f006SIlya Bukonkin   if (has_valid_stopinfo) {
1293b43f006SIlya Bukonkin     StopInfoSP stopinfo_sp =
1303b43f006SIlya Bukonkin         std::make_shared<DummyStopInfo>(*thread_sp.get(), 0);
1313b43f006SIlya Bukonkin     static_cast<DummyStopInfo *>(stopinfo_sp.get())->m_should_stop =
1323b43f006SIlya Bukonkin         should_stop;
1333b43f006SIlya Bukonkin     if (stopinfo_sp == nullptr) {
1343b43f006SIlya Bukonkin       return nullptr;
1353b43f006SIlya Bukonkin     }
1363b43f006SIlya Bukonkin 
1373b43f006SIlya Bukonkin     thread_sp->SetStopInfo(stopinfo_sp);
1383b43f006SIlya Bukonkin   }
1393b43f006SIlya Bukonkin 
1403b43f006SIlya Bukonkin   process_sp->GetThreadList().AddThread(thread_sp);
1413b43f006SIlya Bukonkin 
1423b43f006SIlya Bukonkin   return thread_sp;
1433b43f006SIlya Bukonkin }
1443b43f006SIlya Bukonkin 
145*a7816c8eSJim Ingham // Disable this test till I figure out why changing how events are sent
146*a7816c8eSJim Ingham // to Secondary Listeners (44d9692e6a657ec46e98e4912ac56417da67cfee)
147*a7816c8eSJim Ingham // caused this test to fail.  It is testing responses to events that are
148*a7816c8eSJim Ingham // not delivered in the way Process events are meant to be delivered, it
149*a7816c8eSJim Ingham // bypasses the private event queue, and I'm not sure is testing real
150*a7816c8eSJim Ingham // behaviors.
151*a7816c8eSJim Ingham #if 0
1523b43f006SIlya Bukonkin TEST_F(ProcessEventDataTest, DoOnRemoval) {
1533b43f006SIlya Bukonkin   ArchSpec arch("x86_64-apple-macosx-");
1543b43f006SIlya Bukonkin 
155d6678404SMed Ismail Bennani   Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
1563b43f006SIlya Bukonkin 
1573b43f006SIlya Bukonkin   DebuggerSP debugger_sp = Debugger::CreateInstance();
1583b43f006SIlya Bukonkin   ASSERT_TRUE(debugger_sp);
1593b43f006SIlya Bukonkin 
1603b43f006SIlya Bukonkin   TargetSP target_sp = CreateTarget(debugger_sp, arch);
1613b43f006SIlya Bukonkin   ASSERT_TRUE(target_sp);
1623b43f006SIlya Bukonkin 
1633b43f006SIlya Bukonkin   ListenerSP listener_sp(Listener::MakeListener("dummy"));
1643b43f006SIlya Bukonkin   ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
1653b43f006SIlya Bukonkin   ASSERT_TRUE(process_sp);
1663b43f006SIlya Bukonkin 
1673b43f006SIlya Bukonkin   /*
1683b43f006SIlya Bukonkin    Should hit ShouldStop if state is eStateStopped
1693b43f006SIlya Bukonkin    */
1703b43f006SIlya Bukonkin   ProcessEventDataSP event_data_sp =
1713b43f006SIlya Bukonkin       std::make_shared<DummyProcessEventData>(process_sp, eStateStopped);
1723b43f006SIlya Bukonkin   EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
1733b43f006SIlya Bukonkin   event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
1743b43f006SIlya Bukonkin   event_data_sp->DoOnRemoval(event_sp.get());
1753b43f006SIlya Bukonkin   bool result = static_cast<DummyProcessEventData *>(event_data_sp.get())
1763b43f006SIlya Bukonkin                     ->m_should_stop_hit_count == 1;
1773b43f006SIlya Bukonkin   ASSERT_TRUE(result);
1783b43f006SIlya Bukonkin 
1793b43f006SIlya Bukonkin   /*
1803b43f006SIlya Bukonkin    Should not hit ShouldStop if state is not eStateStopped
1813b43f006SIlya Bukonkin    */
1823b43f006SIlya Bukonkin   event_data_sp =
1833b43f006SIlya Bukonkin       std::make_shared<DummyProcessEventData>(process_sp, eStateStepping);
1843b43f006SIlya Bukonkin   event_sp = std::make_shared<Event>(0, event_data_sp);
1853b43f006SIlya Bukonkin   event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
1863b43f006SIlya Bukonkin   event_data_sp->DoOnRemoval(event_sp.get());
1873b43f006SIlya Bukonkin   result = static_cast<DummyProcessEventData *>(event_data_sp.get())
1883b43f006SIlya Bukonkin                ->m_should_stop_hit_count == 0;
1893b43f006SIlya Bukonkin   ASSERT_TRUE(result);
1903b43f006SIlya Bukonkin }
191*a7816c8eSJim Ingham #endif
1923b43f006SIlya Bukonkin 
1933b43f006SIlya Bukonkin TEST_F(ProcessEventDataTest, ShouldStop) {
1943b43f006SIlya Bukonkin   ArchSpec arch("x86_64-apple-macosx-");
1953b43f006SIlya Bukonkin 
196d6678404SMed Ismail Bennani   Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
1973b43f006SIlya Bukonkin 
1983b43f006SIlya Bukonkin   DebuggerSP debugger_sp = Debugger::CreateInstance();
1993b43f006SIlya Bukonkin   ASSERT_TRUE(debugger_sp);
2003b43f006SIlya Bukonkin 
2013b43f006SIlya Bukonkin   TargetSP target_sp = CreateTarget(debugger_sp, arch);
2023b43f006SIlya Bukonkin   ASSERT_TRUE(target_sp);
2033b43f006SIlya Bukonkin 
2043b43f006SIlya Bukonkin   ListenerSP listener_sp(Listener::MakeListener("dummy"));
2053b43f006SIlya Bukonkin   ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
2063b43f006SIlya Bukonkin   ASSERT_TRUE(process_sp);
2073b43f006SIlya Bukonkin 
2083b43f006SIlya Bukonkin   // wants to stop and has valid StopInfo
2093b43f006SIlya Bukonkin   ThreadSP thread_sp = CreateThread(process_sp, true, true);
2103b43f006SIlya Bukonkin 
2113b43f006SIlya Bukonkin   ProcessEventDataSP event_data_sp =
2123b43f006SIlya Bukonkin       std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
2133b43f006SIlya Bukonkin   EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
2143b43f006SIlya Bukonkin   /*
2153b43f006SIlya Bukonkin    Should stop if thread has valid StopInfo and not suspended
2163b43f006SIlya Bukonkin    */
2173b43f006SIlya Bukonkin   bool found_valid_stopinfo = false;
2183b43f006SIlya Bukonkin   bool should_stop =
2193b43f006SIlya Bukonkin       event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
2203b43f006SIlya Bukonkin   ASSERT_TRUE(should_stop == true && found_valid_stopinfo == true);
2213b43f006SIlya Bukonkin 
2223b43f006SIlya Bukonkin   /*
2233b43f006SIlya Bukonkin    Should not stop if thread has valid StopInfo but was suspended
2243b43f006SIlya Bukonkin    */
2253b43f006SIlya Bukonkin   found_valid_stopinfo = false;
2263b43f006SIlya Bukonkin   thread_sp->SetResumeState(eStateSuspended);
2273b43f006SIlya Bukonkin   should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
2283b43f006SIlya Bukonkin   ASSERT_TRUE(should_stop == false && found_valid_stopinfo == false);
2293b43f006SIlya Bukonkin 
2303b43f006SIlya Bukonkin   /*
2313b43f006SIlya Bukonkin    Should not stop, thread-reason of stop does not want to stop in its
2323b43f006SIlya Bukonkin    callback and suspended thread who wants to (from previous stop)
2333b43f006SIlya Bukonkin    must be ignored.
2343b43f006SIlya Bukonkin    */
2353b43f006SIlya Bukonkin   event_data_sp =
2363b43f006SIlya Bukonkin       std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
2373b43f006SIlya Bukonkin   event_sp = std::make_shared<Event>(0, event_data_sp);
2383b43f006SIlya Bukonkin   process_sp->GetThreadList().Clear();
2393b43f006SIlya Bukonkin 
2403b43f006SIlya Bukonkin   for (int i = 0; i < 6; i++) {
2413b43f006SIlya Bukonkin     if (i == 2) {
2423b43f006SIlya Bukonkin       // Does not want to stop but has valid StopInfo
2433b43f006SIlya Bukonkin       thread_sp = CreateThread(process_sp, false, true);
2443b43f006SIlya Bukonkin     } else if (i == 5) {
2453b43f006SIlya Bukonkin       // Wants to stop and has valid StopInfo
2463b43f006SIlya Bukonkin       thread_sp = CreateThread(process_sp, true, true);
2473b43f006SIlya Bukonkin       thread_sp->SetResumeState(eStateSuspended);
2483b43f006SIlya Bukonkin     } else {
2493b43f006SIlya Bukonkin       // Thread has no StopInfo i.e is not the reason of stop
2503b43f006SIlya Bukonkin       thread_sp = CreateThread(process_sp, false, false);
2513b43f006SIlya Bukonkin     }
2523b43f006SIlya Bukonkin   }
2533b43f006SIlya Bukonkin   ASSERT_TRUE(process_sp->GetThreadList().GetSize() == 6);
2543b43f006SIlya Bukonkin 
2553b43f006SIlya Bukonkin   found_valid_stopinfo = false;
2563b43f006SIlya Bukonkin   should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
2573b43f006SIlya Bukonkin   ASSERT_TRUE(should_stop == false && found_valid_stopinfo == true);
2583b43f006SIlya Bukonkin }
259