aboutsummaryrefslogtreecommitdiff
path: root/lldb/unittests/Process/ProcessEventDataTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/unittests/Process/ProcessEventDataTest.cpp')
-rw-r--r--lldb/unittests/Process/ProcessEventDataTest.cpp256
1 files changed, 256 insertions, 0 deletions
diff --git a/lldb/unittests/Process/ProcessEventDataTest.cpp b/lldb/unittests/Process/ProcessEventDataTest.cpp
new file mode 100644
index 0000000..0f032a7
--- /dev/null
+++ b/lldb/unittests/Process/ProcessEventDataTest.cpp
@@ -0,0 +1,256 @@
+//===-- ProcessEventDataTest.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/Event.h"
+#include "lldb/Utility/Reproducer.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb_private::repro;
+using namespace lldb;
+
+namespace {
+class ProcessEventDataTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
+ FileSystem::Initialize();
+ HostInfo::Initialize();
+ PlatformMacOSX::Initialize();
+ }
+ void TearDown() override {
+ PlatformMacOSX::Terminate();
+ HostInfo::Terminate();
+ FileSystem::Terminate();
+ Reproducer::Terminate();
+ }
+};
+
+class DummyProcess : public Process {
+public:
+ using Process::Process;
+
+ virtual bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) {
+ return true;
+ }
+ virtual Status DoDestroy() { return {}; }
+ virtual void RefreshStateAfterStop() {}
+ virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Status &error) {
+ return 0;
+ }
+ virtual bool UpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
+ return false;
+ }
+ virtual ConstString GetPluginName() { return ConstString("Dummy"); }
+ virtual uint32_t GetPluginVersion() { return 0; }
+
+ ProcessModID &GetModIDNonConstRef() { return m_mod_id; }
+};
+
+class DummyThread : public Thread {
+public:
+ using Thread::Thread;
+
+ ~DummyThread() override { DestroyThread(); }
+
+ void RefreshStateAfterStop() override {}
+
+ lldb::RegisterContextSP GetRegisterContext() override { return nullptr; }
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(StackFrame *frame) override {
+ return nullptr;
+ }
+
+ bool CalculateStopInfo() override { return false; }
+};
+
+class DummyStopInfo : public StopInfo {
+public:
+ DummyStopInfo(Thread &thread, uint64_t value)
+ : StopInfo(thread, value), m_should_stop(true),
+ m_stop_reason(eStopReasonBreakpoint) {}
+
+ bool ShouldStop(Event *event_ptr) override { return m_should_stop; }
+
+ StopReason GetStopReason() const override { return m_stop_reason; }
+
+ bool m_should_stop;
+ StopReason m_stop_reason;
+};
+
+class DummyProcessEventData : public Process::ProcessEventData {
+public:
+ DummyProcessEventData(ProcessSP &process_sp, StateType state)
+ : ProcessEventData(process_sp, state), m_should_stop_hit_count(0) {}
+ bool ShouldStop(Event *event_ptr, bool &found_valid_stopinfo) override {
+ m_should_stop_hit_count++;
+ return false;
+ }
+
+ int m_should_stop_hit_count;
+};
+} // namespace
+
+typedef std::shared_ptr<Process::ProcessEventData> ProcessEventDataSP;
+typedef std::shared_ptr<Event> EventSP;
+
+TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
+ Status error;
+ PlatformSP platform_sp;
+ TargetSP target_sp;
+ error = debugger_sp->GetTargetList().CreateTarget(
+ *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
+
+ if (target_sp) {
+ debugger_sp->GetTargetList().SetSelectedTarget(target_sp.get());
+ }
+
+ return target_sp;
+}
+
+ThreadSP CreateThread(ProcessSP &process_sp, bool should_stop,
+ bool has_valid_stopinfo) {
+ ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);
+ if (thread_sp == nullptr) {
+ return nullptr;
+ }
+
+ if (has_valid_stopinfo) {
+ StopInfoSP stopinfo_sp =
+ std::make_shared<DummyStopInfo>(*thread_sp.get(), 0);
+ static_cast<DummyStopInfo *>(stopinfo_sp.get())->m_should_stop =
+ should_stop;
+ if (stopinfo_sp == nullptr) {
+ return nullptr;
+ }
+
+ thread_sp->SetStopInfo(stopinfo_sp);
+ }
+
+ process_sp->GetThreadList().AddThread(thread_sp);
+
+ return thread_sp;
+}
+
+TEST_F(ProcessEventDataTest, DoOnRemoval) {
+ ArchSpec arch("x86_64-apple-macosx-");
+
+ Platform::SetHostPlatform(PlatformMacOSX::CreateInstance(true, &arch));
+
+ DebuggerSP debugger_sp = Debugger::CreateInstance();
+ ASSERT_TRUE(debugger_sp);
+
+ TargetSP target_sp = CreateTarget(debugger_sp, arch);
+ ASSERT_TRUE(target_sp);
+
+ ListenerSP listener_sp(Listener::MakeListener("dummy"));
+ ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
+ ASSERT_TRUE(process_sp);
+
+ /*
+ Should hit ShouldStop if state is eStateStopped
+ */
+ ProcessEventDataSP event_data_sp =
+ std::make_shared<DummyProcessEventData>(process_sp, eStateStopped);
+ EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
+ event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
+ event_data_sp->DoOnRemoval(event_sp.get());
+ bool result = static_cast<DummyProcessEventData *>(event_data_sp.get())
+ ->m_should_stop_hit_count == 1;
+ ASSERT_TRUE(result);
+
+ /*
+ Should not hit ShouldStop if state is not eStateStopped
+ */
+ event_data_sp =
+ std::make_shared<DummyProcessEventData>(process_sp, eStateStepping);
+ event_sp = std::make_shared<Event>(0, event_data_sp);
+ event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
+ event_data_sp->DoOnRemoval(event_sp.get());
+ result = static_cast<DummyProcessEventData *>(event_data_sp.get())
+ ->m_should_stop_hit_count == 0;
+ ASSERT_TRUE(result);
+}
+
+TEST_F(ProcessEventDataTest, ShouldStop) {
+ ArchSpec arch("x86_64-apple-macosx-");
+
+ Platform::SetHostPlatform(PlatformMacOSX::CreateInstance(true, &arch));
+
+ DebuggerSP debugger_sp = Debugger::CreateInstance();
+ ASSERT_TRUE(debugger_sp);
+
+ TargetSP target_sp = CreateTarget(debugger_sp, arch);
+ ASSERT_TRUE(target_sp);
+
+ ListenerSP listener_sp(Listener::MakeListener("dummy"));
+ ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
+ ASSERT_TRUE(process_sp);
+
+ // wants to stop and has valid StopInfo
+ ThreadSP thread_sp = CreateThread(process_sp, true, true);
+
+ ProcessEventDataSP event_data_sp =
+ std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
+ EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
+ /*
+ Should stop if thread has valid StopInfo and not suspended
+ */
+ bool found_valid_stopinfo = false;
+ bool should_stop =
+ event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
+ ASSERT_TRUE(should_stop == true && found_valid_stopinfo == true);
+
+ /*
+ Should not stop if thread has valid StopInfo but was suspended
+ */
+ found_valid_stopinfo = false;
+ thread_sp->SetResumeState(eStateSuspended);
+ should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
+ ASSERT_TRUE(should_stop == false && found_valid_stopinfo == false);
+
+ /*
+ Should not stop, thread-reason of stop does not want to stop in its
+ callback and suspended thread who wants to (from previous stop)
+ must be ignored.
+ */
+ event_data_sp =
+ std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
+ event_sp = std::make_shared<Event>(0, event_data_sp);
+ process_sp->GetThreadList().Clear();
+
+ for (int i = 0; i < 6; i++) {
+ if (i == 2) {
+ // Does not want to stop but has valid StopInfo
+ thread_sp = CreateThread(process_sp, false, true);
+ } else if (i == 5) {
+ // Wants to stop and has valid StopInfo
+ thread_sp = CreateThread(process_sp, true, true);
+ thread_sp->SetResumeState(eStateSuspended);
+ } else {
+ // Thread has no StopInfo i.e is not the reason of stop
+ thread_sp = CreateThread(process_sp, false, false);
+ }
+ }
+ ASSERT_TRUE(process_sp->GetThreadList().GetSize() == 6);
+
+ found_valid_stopinfo = false;
+ should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
+ ASSERT_TRUE(should_stop == false && found_valid_stopinfo == true);
+}