In implementing this test one of the assertions assumes that the priority is the default in linux (0) but, evidently, some of the build runners prioritize the test to, at least, 5. This ensures that regardless of the priority the test passes by validating that its the process's priority ``` fgrim@host001 :~/llvm-project/debug_build> nice -n 15 tools/lldb/unittests/Process/elf-core/ProcessElfCoreTests [==========] Running 2 tests from 1 test suite. [----------] Global test environment set-up. [----------] 2 tests from ElfCoreTest [ RUN ] ElfCoreTest.PopulatePrpsInfoTest [ OK ] ElfCoreTest.PopulatePrpsInfoTest (4 ms) [ RUN ] ElfCoreTest.PopulatePrStatusTest [ OK ] ElfCoreTest.PopulatePrStatusTest (3 ms) [----------] 2 tests from ElfCoreTest (7 ms total) [----------] Global test environment tear-down [==========] 2 tests from 1 test suite ran. (8 ms total) [ PASSED ] 2 tests. ===(10:03)=== fgrim@host001 :~/llvm-project/debug_build> ```
179 lines
6.1 KiB
C++
179 lines
6.1 KiB
C++
//===-- ThreadElfCoreTest.cpp ------------------------------------*- C++
|
|
//-*-===//
|
|
//
|
|
// 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/Process/elf-core/ThreadElfCore.h"
|
|
#include "Plugins/Platform/Linux/PlatformLinux.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/Listener.h"
|
|
#include "llvm/TargetParser/Triple.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <sys/resource.h>
|
|
#include <unistd.h>
|
|
|
|
using namespace lldb_private;
|
|
|
|
namespace {
|
|
|
|
struct ElfCoreTest : public testing::Test {
|
|
static void SetUpTestCase() {
|
|
FileSystem::Initialize();
|
|
HostInfo::Initialize();
|
|
platform_linux::PlatformLinux::Initialize();
|
|
std::call_once(TestUtilities::g_debugger_initialize_flag,
|
|
[]() { Debugger::Initialize(nullptr); });
|
|
}
|
|
static void TearDownTestCase() {
|
|
platform_linux::PlatformLinux::Terminate();
|
|
HostInfo::Terminate();
|
|
FileSystem::Terminate();
|
|
}
|
|
};
|
|
|
|
struct DummyProcess : public Process {
|
|
DummyProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
|
|
: Process(target_sp, listener_sp) {
|
|
SetID(getpid());
|
|
}
|
|
|
|
bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
|
|
return true;
|
|
}
|
|
Status DoDestroy() override { return {}; }
|
|
void RefreshStateAfterStop() override {}
|
|
size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
|
|
Status &error) override {
|
|
return 0;
|
|
}
|
|
bool DoUpdateThreadList(ThreadList &old_thread_list,
|
|
ThreadList &new_thread_list) override {
|
|
return false;
|
|
}
|
|
llvm::StringRef GetPluginName() override { return "Dummy"; }
|
|
};
|
|
|
|
struct DummyThread : public Thread {
|
|
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; }
|
|
};
|
|
|
|
lldb::TargetSP CreateTarget(lldb::DebuggerSP &debugger_sp, ArchSpec &arch) {
|
|
lldb::PlatformSP platform_sp;
|
|
lldb::TargetSP target_sp;
|
|
debugger_sp->GetTargetList().CreateTarget(
|
|
*debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
|
|
return target_sp;
|
|
}
|
|
|
|
lldb::ThreadSP CreateThread(lldb::ProcessSP &process_sp) {
|
|
lldb::ThreadSP thread_sp =
|
|
std::make_shared<DummyThread>(*process_sp.get(), gettid());
|
|
if (thread_sp == nullptr) {
|
|
return nullptr;
|
|
}
|
|
process_sp->GetThreadList().AddThread(thread_sp);
|
|
|
|
return thread_sp;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_F(ElfCoreTest, PopulatePrpsInfoTest) {
|
|
ArchSpec arch{HostInfo::GetTargetTriple()};
|
|
lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
|
|
ASSERT_TRUE(debugger_sp);
|
|
|
|
lldb::TargetSP target_sp = CreateTarget(debugger_sp, arch);
|
|
ASSERT_TRUE(target_sp);
|
|
|
|
lldb::ListenerSP listener_sp(Listener::MakeListener("dummy"));
|
|
lldb::ProcessSP process_sp =
|
|
std::make_shared<DummyProcess>(target_sp, listener_sp);
|
|
ASSERT_TRUE(process_sp);
|
|
auto prpsinfo_opt = ELFLinuxPrPsInfo::Populate(process_sp);
|
|
ASSERT_TRUE(prpsinfo_opt.has_value());
|
|
ASSERT_EQ(prpsinfo_opt->pr_pid, getpid());
|
|
ASSERT_EQ(prpsinfo_opt->pr_state, 0);
|
|
ASSERT_EQ(prpsinfo_opt->pr_sname, 'R');
|
|
ASSERT_EQ(prpsinfo_opt->pr_zomb, 0);
|
|
int priority = getpriority(PRIO_PROCESS, getpid());
|
|
if (priority == -1)
|
|
ASSERT_EQ(errno, 0);
|
|
ASSERT_EQ(prpsinfo_opt->pr_nice, priority);
|
|
ASSERT_EQ(prpsinfo_opt->pr_flag, 0UL);
|
|
ASSERT_EQ(prpsinfo_opt->pr_uid, getuid());
|
|
ASSERT_EQ(prpsinfo_opt->pr_gid, getgid());
|
|
ASSERT_EQ(prpsinfo_opt->pr_pid, getpid());
|
|
ASSERT_EQ(prpsinfo_opt->pr_ppid, getppid());
|
|
ASSERT_EQ(prpsinfo_opt->pr_pgrp, getpgrp());
|
|
ASSERT_EQ(prpsinfo_opt->pr_sid, getsid(getpid()));
|
|
ASSERT_EQ(std::string{prpsinfo_opt->pr_fname}, "ProcessElfCoreT");
|
|
ASSERT_TRUE(std::string{prpsinfo_opt->pr_psargs}.empty());
|
|
lldb_private::ProcessInstanceInfo info;
|
|
ASSERT_TRUE(process_sp->GetProcessInfo(info));
|
|
const char *args[] = {"a.out", "--foo=bar", "--baz=boo", nullptr};
|
|
info.SetArguments(args, true);
|
|
prpsinfo_opt =
|
|
ELFLinuxPrPsInfo::Populate(info, lldb::StateType::eStateStopped);
|
|
ASSERT_TRUE(prpsinfo_opt.has_value());
|
|
ASSERT_EQ(prpsinfo_opt->pr_pid, getpid());
|
|
ASSERT_EQ(prpsinfo_opt->pr_state, 3);
|
|
ASSERT_EQ(prpsinfo_opt->pr_sname, 'T');
|
|
ASSERT_EQ(std::string{prpsinfo_opt->pr_fname}, "a.out");
|
|
ASSERT_FALSE(std::string{prpsinfo_opt->pr_psargs}.empty());
|
|
ASSERT_EQ(std::string{prpsinfo_opt->pr_psargs}, "a.out --foo=bar --baz=boo");
|
|
}
|
|
|
|
TEST_F(ElfCoreTest, PopulatePrStatusTest) {
|
|
ArchSpec arch{HostInfo::GetTargetTriple()};
|
|
lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
|
|
ASSERT_TRUE(debugger_sp);
|
|
|
|
lldb::TargetSP target_sp = CreateTarget(debugger_sp, arch);
|
|
ASSERT_TRUE(target_sp);
|
|
|
|
lldb::ListenerSP listener_sp(Listener::MakeListener("dummy"));
|
|
lldb::ProcessSP process_sp =
|
|
std::make_shared<DummyProcess>(target_sp, listener_sp);
|
|
ASSERT_TRUE(process_sp);
|
|
lldb::ThreadSP thread_sp = CreateThread(process_sp);
|
|
ASSERT_TRUE(thread_sp);
|
|
auto prstatus_opt = ELFLinuxPrStatus::Populate(thread_sp);
|
|
ASSERT_TRUE(prstatus_opt.has_value());
|
|
ASSERT_EQ(prstatus_opt->si_signo, 0);
|
|
ASSERT_EQ(prstatus_opt->si_code, 0);
|
|
ASSERT_EQ(prstatus_opt->si_errno, 0);
|
|
ASSERT_EQ(prstatus_opt->pr_cursig, 0);
|
|
ASSERT_EQ(prstatus_opt->pr_sigpend, 0UL);
|
|
ASSERT_EQ(prstatus_opt->pr_sighold, 0UL);
|
|
ASSERT_EQ(prstatus_opt->pr_pid, static_cast<uint32_t>(gettid()));
|
|
ASSERT_EQ(prstatus_opt->pr_ppid, static_cast<uint32_t>(getppid()));
|
|
ASSERT_EQ(prstatus_opt->pr_pgrp, static_cast<uint32_t>(getpgrp()));
|
|
ASSERT_EQ(prstatus_opt->pr_sid, static_cast<uint32_t>(getsid(gettid())));
|
|
}
|