Older glibc versions do not provide `gettid`. Provide our own `gettid` in these cases. Fixes a build failure caused by #104109.
184 lines
6.2 KiB
C++
184 lines
6.2 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>
|
|
|
|
#ifndef HAVE_GETTID
|
|
#include <sys/syscall.h>
|
|
pid_t gettid() { return ((pid_t)syscall(SYS_gettid)); }
|
|
#endif
|
|
|
|
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())));
|
|
}
|