1 //===-- ThreadElfCoreTest.cpp ------------------------------------*- C++
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
9 #include "Plugins/Process/elf-core/ThreadElfCore.h"
10 #include "Plugins/Platform/Linux/PlatformLinux.h"
11 #include "TestingSupport/TestUtilities.h"
12 #include "lldb/Core/Debugger.h"
13 #include "lldb/Host/FileSystem.h"
14 #include "lldb/Host/HostInfo.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Target/Thread.h"
18 #include "lldb/Utility/Listener.h"
19 #include "llvm/TargetParser/Triple.h"
20 #include "gtest/gtest.h"
24 #include <sys/resource.h>
28 #include <sys/syscall.h>
29 pid_t
gettid() { return ((pid_t
)syscall(SYS_gettid
)); }
32 using namespace lldb_private
;
36 struct ElfCoreTest
: public testing::Test
{
37 static void SetUpTestCase() {
38 FileSystem::Initialize();
39 HostInfo::Initialize();
40 platform_linux::PlatformLinux::Initialize();
41 std::call_once(TestUtilities::g_debugger_initialize_flag
,
42 []() { Debugger::Initialize(nullptr); });
44 static void TearDownTestCase() {
45 platform_linux::PlatformLinux::Terminate();
46 HostInfo::Terminate();
47 FileSystem::Terminate();
51 struct DummyProcess
: public Process
{
52 DummyProcess(lldb::TargetSP target_sp
, lldb::ListenerSP listener_sp
)
53 : Process(target_sp
, listener_sp
) {
57 bool CanDebug(lldb::TargetSP target
, bool plugin_specified_by_name
) override
{
60 Status
DoDestroy() override
{ return {}; }
61 void RefreshStateAfterStop() override
{}
62 size_t DoReadMemory(lldb::addr_t vm_addr
, void *buf
, size_t size
,
63 Status
&error
) override
{
66 bool DoUpdateThreadList(ThreadList
&old_thread_list
,
67 ThreadList
&new_thread_list
) override
{
70 llvm::StringRef
GetPluginName() override
{ return "Dummy"; }
73 struct DummyThread
: public Thread
{
76 ~DummyThread() override
{ DestroyThread(); }
78 void RefreshStateAfterStop() override
{}
80 lldb::RegisterContextSP
GetRegisterContext() override
{ return nullptr; }
82 lldb::RegisterContextSP
83 CreateRegisterContextForFrame(StackFrame
*frame
) override
{
87 bool CalculateStopInfo() override
{ return false; }
90 lldb::TargetSP
CreateTarget(lldb::DebuggerSP
&debugger_sp
, ArchSpec
&arch
) {
91 lldb::PlatformSP platform_sp
;
92 lldb::TargetSP target_sp
;
93 debugger_sp
->GetTargetList().CreateTarget(
94 *debugger_sp
, "", arch
, eLoadDependentsNo
, platform_sp
, target_sp
);
98 lldb::ThreadSP
CreateThread(lldb::ProcessSP
&process_sp
) {
99 lldb::ThreadSP thread_sp
=
100 std::make_shared
<DummyThread
>(*process_sp
.get(), gettid());
101 if (thread_sp
== nullptr) {
104 process_sp
->GetThreadList().AddThread(thread_sp
);
111 TEST_F(ElfCoreTest
, PopulatePrpsInfoTest
) {
112 ArchSpec arch
{HostInfo::GetTargetTriple()};
113 lldb::DebuggerSP debugger_sp
= Debugger::CreateInstance();
114 ASSERT_TRUE(debugger_sp
);
116 lldb::TargetSP target_sp
= CreateTarget(debugger_sp
, arch
);
117 ASSERT_TRUE(target_sp
);
119 lldb::ListenerSP
listener_sp(Listener::MakeListener("dummy"));
120 lldb::ProcessSP process_sp
=
121 std::make_shared
<DummyProcess
>(target_sp
, listener_sp
);
122 ASSERT_TRUE(process_sp
);
123 auto prpsinfo_opt
= ELFLinuxPrPsInfo::Populate(process_sp
);
124 ASSERT_TRUE(prpsinfo_opt
.has_value());
125 ASSERT_EQ(prpsinfo_opt
->pr_pid
, getpid());
126 ASSERT_EQ(prpsinfo_opt
->pr_state
, 0);
127 ASSERT_EQ(prpsinfo_opt
->pr_sname
, 'R');
128 ASSERT_EQ(prpsinfo_opt
->pr_zomb
, 0);
129 int priority
= getpriority(PRIO_PROCESS
, getpid());
132 ASSERT_EQ(prpsinfo_opt
->pr_nice
, priority
);
133 ASSERT_EQ(prpsinfo_opt
->pr_flag
, 0UL);
134 ASSERT_EQ(prpsinfo_opt
->pr_uid
, getuid());
135 ASSERT_EQ(prpsinfo_opt
->pr_gid
, getgid());
136 ASSERT_EQ(prpsinfo_opt
->pr_pid
, getpid());
137 ASSERT_EQ(prpsinfo_opt
->pr_ppid
, getppid());
138 ASSERT_EQ(prpsinfo_opt
->pr_pgrp
, getpgrp());
139 ASSERT_EQ(prpsinfo_opt
->pr_sid
, getsid(getpid()));
140 ASSERT_EQ(std::string
{prpsinfo_opt
->pr_fname
}, "ProcessElfCoreT");
141 ASSERT_TRUE(std::string
{prpsinfo_opt
->pr_psargs
}.empty());
142 lldb_private::ProcessInstanceInfo info
;
143 ASSERT_TRUE(process_sp
->GetProcessInfo(info
));
144 const char *args
[] = {"a.out", "--foo=bar", "--baz=boo", nullptr};
145 info
.SetArguments(args
, true);
147 ELFLinuxPrPsInfo::Populate(info
, lldb::StateType::eStateStopped
);
148 ASSERT_TRUE(prpsinfo_opt
.has_value());
149 ASSERT_EQ(prpsinfo_opt
->pr_pid
, getpid());
150 ASSERT_EQ(prpsinfo_opt
->pr_state
, 3);
151 ASSERT_EQ(prpsinfo_opt
->pr_sname
, 'T');
152 ASSERT_EQ(std::string
{prpsinfo_opt
->pr_fname
}, "a.out");
153 ASSERT_FALSE(std::string
{prpsinfo_opt
->pr_psargs
}.empty());
154 ASSERT_EQ(std::string
{prpsinfo_opt
->pr_psargs
}, "a.out --foo=bar --baz=boo");
157 TEST_F(ElfCoreTest
, PopulatePrStatusTest
) {
158 ArchSpec arch
{HostInfo::GetTargetTriple()};
159 lldb::DebuggerSP debugger_sp
= Debugger::CreateInstance();
160 ASSERT_TRUE(debugger_sp
);
162 lldb::TargetSP target_sp
= CreateTarget(debugger_sp
, arch
);
163 ASSERT_TRUE(target_sp
);
165 lldb::ListenerSP
listener_sp(Listener::MakeListener("dummy"));
166 lldb::ProcessSP process_sp
=
167 std::make_shared
<DummyProcess
>(target_sp
, listener_sp
);
168 ASSERT_TRUE(process_sp
);
169 lldb::ThreadSP thread_sp
= CreateThread(process_sp
);
170 ASSERT_TRUE(thread_sp
);
171 auto prstatus_opt
= ELFLinuxPrStatus::Populate(thread_sp
);
172 ASSERT_TRUE(prstatus_opt
.has_value());
173 ASSERT_EQ(prstatus_opt
->si_signo
, 0);
174 ASSERT_EQ(prstatus_opt
->si_code
, 0);
175 ASSERT_EQ(prstatus_opt
->si_errno
, 0);
176 ASSERT_EQ(prstatus_opt
->pr_cursig
, 0);
177 ASSERT_EQ(prstatus_opt
->pr_sigpend
, 0UL);
178 ASSERT_EQ(prstatus_opt
->pr_sighold
, 0UL);
179 ASSERT_EQ(prstatus_opt
->pr_pid
, static_cast<uint32_t>(gettid()));
180 ASSERT_EQ(prstatus_opt
->pr_ppid
, static_cast<uint32_t>(getppid()));
181 ASSERT_EQ(prstatus_opt
->pr_pgrp
, static_cast<uint32_t>(getpgrp()));
182 ASSERT_EQ(prstatus_opt
->pr_sid
, static_cast<uint32_t>(getsid(gettid())));