1//===-- ThreadElfCoreTest.cpp ------------------------------------*- C++
2//-*-===//
3//
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
7//
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"
21
22#include <memory>
23#include <mutex>
24#include <sys/resource.h>
25#include <unistd.h>
26
27#ifndef HAVE_GETTID
28#include <sys/syscall.h>
29pid_t gettid() { return ((pid_t)syscall(SYS_gettid)); }
30#endif
31
32using namespace lldb_private;
33
34namespace {
35
36struct ElfCoreTest : public testing::Test {
37 static void SetUpTestCase() {
38 FileSystem::Initialize();
39 HostInfo::Initialize();
40 platform_linux::PlatformLinux::Initialize();
41 std::call_once(once&: TestUtilities::g_debugger_initialize_flag,
42 f: []() { Debugger::Initialize(load_plugin_callback: nullptr); });
43 }
44 static void TearDownTestCase() {
45 platform_linux::PlatformLinux::Terminate();
46 HostInfo::Terminate();
47 FileSystem::Terminate();
48 }
49};
50
51struct DummyProcess : public Process {
52 DummyProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
53 : Process(target_sp, listener_sp) {
54 SetID(getpid());
55 }
56
57 bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
58 return true;
59 }
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 {
64 return 0;
65 }
66 bool DoUpdateThreadList(ThreadList &old_thread_list,
67 ThreadList &new_thread_list) override {
68 return false;
69 }
70 llvm::StringRef GetPluginName() override { return "Dummy"; }
71};
72
73struct DummyThread : public Thread {
74 using Thread::Thread;
75
76 ~DummyThread() override { DestroyThread(); }
77
78 void RefreshStateAfterStop() override {}
79
80 lldb::RegisterContextSP GetRegisterContext() override { return nullptr; }
81
82 lldb::RegisterContextSP
83 CreateRegisterContextForFrame(StackFrame *frame) override {
84 return nullptr;
85 }
86
87 bool CalculateStopInfo() override { return false; }
88};
89
90lldb::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&: *debugger_sp, user_exe_path: "", arch, get_dependent_modules: eLoadDependentsNo, platform_sp, target_sp);
95 return target_sp;
96}
97
98lldb::ThreadSP CreateThread(lldb::ProcessSP &process_sp) {
99 lldb::ThreadSP thread_sp =
100 std::make_shared<DummyThread>(args&: *process_sp.get(), args: gettid());
101 if (thread_sp == nullptr) {
102 return nullptr;
103 }
104 process_sp->GetThreadList().AddThread(thread_sp);
105
106 return thread_sp;
107}
108
109} // namespace
110
111TEST_F(ElfCoreTest, PopulatePrpsInfoTest) {
112 ArchSpec arch{HostInfo::GetTargetTriple()};
113 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
114 ASSERT_TRUE(debugger_sp);
115
116 lldb::TargetSP target_sp = CreateTarget(debugger_sp, arch);
117 ASSERT_TRUE(target_sp);
118
119 lldb::ListenerSP listener_sp(Listener::MakeListener(name: "dummy"));
120 lldb::ProcessSP process_sp =
121 std::make_shared<DummyProcess>(args&: target_sp, args&: 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, who: getpid());
130 if (priority == -1)
131 ASSERT_EQ(errno, 0);
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(argv: args, first_arg_is_executable: true);
146 prpsinfo_opt =
147 ELFLinuxPrPsInfo::Populate(info, state: 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");
155}
156
157TEST_F(ElfCoreTest, PopulatePrStatusTest) {
158 ArchSpec arch{HostInfo::GetTargetTriple()};
159 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
160 ASSERT_TRUE(debugger_sp);
161
162 lldb::TargetSP target_sp = CreateTarget(debugger_sp, arch);
163 ASSERT_TRUE(target_sp);
164
165 lldb::ListenerSP listener_sp(Listener::MakeListener(name: "dummy"));
166 lldb::ProcessSP process_sp =
167 std::make_shared<DummyProcess>(args&: target_sp, args&: 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())));
183}
184

source code of lldb/unittests/Process/elf-core/ThreadElfCoreTest.cpp