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