blob: ea5fc03af5a5c379db1f1cb1ecc223543ae0dd01 [file] [edit]
//===----------------------------------------------------------------------===//
//
// 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 "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ArchSpec.h"
#include "gtest/gtest.h"
#include <mutex>
using namespace lldb_private;
using namespace lldb;
namespace {
// Paths below target.process, as "settings set" would spell them.
constexpr const char *k_reports_all_threads =
"experimental.os-plugin-reports-all-threads";
constexpr const char *k_trace_thread = "thread.trace-thread";
class DummyProcess : public Process {
public:
DummyProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
: Process(target_sp, listener_sp) {}
bool CanDebug(lldb::TargetSP, bool) override { return true; }
size_t DoReadMemory(const ProcessAddress &, void *, size_t,
Status &) override {
return 0;
}
Status DoDestroy() override { return {}; }
void RefreshStateAfterStop() override {}
bool DoUpdateThreadList(ThreadList &, ThreadList &) override { return false; }
llvm::StringRef GetPluginName() override { return "Dummy"; }
};
class ProcessPropertiesTest : public ::testing::Test {
public:
SubsystemRAII<FileSystem, HostInfo, PlatformMacOSX> subsystems;
protected:
void SetUp() override {
std::call_once(TestUtilities::g_debugger_initialize_flag,
[] { Debugger::Initialize(nullptr); });
Platform::SetHostPlatform(
PlatformRemoteMacOSX::CreateInstance(true, &m_arch));
m_debugger_sp = Debugger::CreateInstance();
}
void TearDown() override {
// Both settings are global and outlive this test.
Process::GetGlobalProperties().SetPropertyValue(
nullptr, eVarSetOperationClear, k_reports_all_threads, "");
Process::GetGlobalProperties().SetPropertyValue(
nullptr, eVarSetOperationClear, k_trace_thread, "");
if (m_debugger_sp)
Debugger::Destroy(m_debugger_sp);
}
ProcessSP CreateProcess() {
PlatformSP platform_sp;
TargetSP target_sp;
m_debugger_sp->GetTargetList().CreateTarget(
*m_debugger_sp, "", m_arch, eLoadDependentsNo, platform_sp, target_sp);
if (!target_sp)
return nullptr;
return std::make_shared<DummyProcess>(target_sp,
Listener::MakeListener("dummy"));
}
static void SetReportsAllThreads(const char *value) {
Process::GetGlobalProperties().SetPropertyValue(
nullptr, eVarSetOperationAssign, k_reports_all_threads, value);
}
ArchSpec m_arch = ArchSpec("x86_64-apple-macosx-");
DebuggerSP m_debugger_sp;
};
} // namespace
TEST_F(ProcessPropertiesTest, OSPluginReportsAllThreadsDefaultsToTrue) {
ASSERT_TRUE(m_debugger_sp);
EXPECT_TRUE(Process::GetGlobalProperties().GetOSPluginReportsAllThreads());
ProcessSP process_sp = CreateProcess();
ASSERT_TRUE(process_sp);
EXPECT_TRUE(process_sp->GetOSPluginReportsAllThreads());
}
// "settings set target.process.experimental.os-plugin-reports-all-threads"
// must reach what a process reads, not only the global properties.
TEST_F(ProcessPropertiesTest, OSPluginReportsAllThreadsFollowsGlobalSetting) {
ASSERT_TRUE(m_debugger_sp);
ProcessSP process_sp = CreateProcess();
ASSERT_TRUE(process_sp);
SetReportsAllThreads("false");
EXPECT_FALSE(Process::GetGlobalProperties().GetOSPluginReportsAllThreads());
EXPECT_FALSE(process_sp->GetOSPluginReportsAllThreads());
// The collection is shared, so a process created afterwards sees it too.
ProcessSP later_process_sp = CreateProcess();
ASSERT_TRUE(later_process_sp);
EXPECT_FALSE(later_process_sp->GetOSPluginReportsAllThreads());
SetReportsAllThreads("true");
EXPECT_TRUE(Process::GetGlobalProperties().GetOSPluginReportsAllThreads());
EXPECT_TRUE(process_sp->GetOSPluginReportsAllThreads());
}
// The setter must write the experimental collection and leave the thread
// collection alone.
TEST_F(ProcessPropertiesTest, SetOSPluginReportsAllThreadsWritesTheSetting) {
ASSERT_TRUE(m_debugger_sp);
ProcessSP process_sp = CreateProcess();
ASSERT_TRUE(process_sp);
const bool trace_thread =
Thread::GetGlobalProperties().GetTraceEnabledState();
process_sp->SetOSPluginReportsAllThreads(false);
EXPECT_FALSE(process_sp->GetOSPluginReportsAllThreads());
EXPECT_EQ(trace_thread, Thread::GetGlobalProperties().GetTraceEnabledState());
process_sp->SetOSPluginReportsAllThreads(true);
EXPECT_TRUE(process_sp->GetOSPluginReportsAllThreads());
EXPECT_EQ(trace_thread, Thread::GetGlobalProperties().GetTraceEnabledState());
// The collection is shared, so writing through a process is visible on the
// global properties.
EXPECT_TRUE(Process::GetGlobalProperties().GetOSPluginReportsAllThreads());
}