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