1//===-- NativeProcessELFTest.cpp ------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "TestingSupport/Host/NativeProcessTestUtils.h"
10
11#include "Plugins/Process/POSIX/NativeProcessELF.h"
12#include "Plugins/Process/Utility/AuxVector.h"
13#include "lldb/Utility/DataBufferHeap.h"
14#include "lldb/Utility/DataEncoder.h"
15#include "lldb/Utility/DataExtractor.h"
16#include "llvm/BinaryFormat/ELF.h"
17#include "llvm/Support/MemoryBuffer.h"
18
19#include "gmock/gmock.h"
20
21using namespace lldb_private;
22using namespace lldb;
23using namespace testing;
24
25namespace {
26class MockProcessELF : public MockProcess<NativeProcessELF> {
27public:
28 using MockProcess::MockProcess;
29 using NativeProcessELF::GetAuxValue;
30 using NativeProcessELF::GetELFImageInfoAddress;
31};
32
33std::unique_ptr<llvm::MemoryBuffer> CreateAuxvData(
34 MockProcessELF &process,
35 llvm::ArrayRef<std::pair<AuxVector::EntryType, uint32_t>> auxv_data) {
36 DataEncoder encoder(process.GetByteOrder(), process.GetAddressByteSize());
37 for (auto &pair : auxv_data) {
38 encoder.AppendAddress(addr: pair.first);
39 encoder.AppendAddress(addr: pair.second);
40 }
41 return llvm::MemoryBuffer::getMemBufferCopy(
42 InputData: llvm::toStringRef(Input: encoder.GetData()), BufferName: "");
43}
44
45} // namespace
46
47TEST(NativeProcessELFTest, GetAuxValue) {
48 NiceMock<MockDelegate> DummyDelegate;
49 MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
50
51 uint64_t phdr_addr = 0x42;
52 auto auxv_buffer = CreateAuxvData(
53 process, auxv_data: {std::make_pair(x: AuxVector::AUXV_AT_PHDR, y&: phdr_addr)});
54 EXPECT_CALL(process, GetAuxvData())
55 .WillOnce(once_action: Return(value: ByMove(x: std::move(auxv_buffer))));
56
57 ASSERT_EQ(phdr_addr, process.GetAuxValue(AuxVector::AUXV_AT_PHDR));
58}
59
60TEST(NativeProcessELFTest, GetELFImageInfoAddress) {
61 NiceMock<MockDelegate> DummyDelegate;
62 MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
63
64 uint32_t load_base = 0x1000;
65 uint32_t info_addr = 0x3741;
66 uint32_t phdr_addr = load_base + sizeof(llvm::ELF::Elf32_Ehdr);
67
68 auto auxv_buffer = CreateAuxvData(
69 process,
70 auxv_data: {std::make_pair(x: AuxVector::AUXV_AT_PHDR, y&: phdr_addr),
71 std::make_pair(x: AuxVector::AUXV_AT_PHENT, y: sizeof(llvm::ELF::Elf32_Phdr)),
72 std::make_pair(x: AuxVector::AUXV_AT_PHNUM, y: 2)});
73 EXPECT_CALL(process, GetAuxvData())
74 .WillOnce(once_action: Return(value: ByMove(x: std::move(auxv_buffer))));
75
76 // We're going to set up a fake memory with 2 program headers and 1 entry in
77 // the dynamic section. For simplicity sake they will be contiguous in memory.
78 struct MemoryContents {
79 llvm::ELF::Elf32_Phdr phdr_load;
80 llvm::ELF::Elf32_Phdr phdr_dynamic;
81 llvm::ELF::Elf32_Dyn dyn_debug;
82 } MC;
83 // Setup the 2 program header entries
84 MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
85 MC.phdr_load.p_vaddr = phdr_addr - load_base;
86
87 MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
88 MC.phdr_dynamic.p_vaddr =
89 (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr)) - load_base;
90 MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
91
92 // Setup the single entry in the .dynamic section
93 MC.dyn_debug.d_tag = llvm::ELF::DT_DEBUG;
94 MC.dyn_debug.d_un.d_ptr = info_addr;
95
96 FakeMemory M(&MC, sizeof(MC), phdr_addr);
97 EXPECT_CALL(process, ReadMemory(_, _))
98 .WillRepeatedly(action: Invoke(obj_ptr: &M, method_ptr: &FakeMemory::Read));
99
100 lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
101 llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
102
103 // Read the address at the elf_info_addr location to make sure we're reading
104 // the correct one.
105 lldb::offset_t info_addr_offset = elf_info_addr - phdr_addr;
106 DataExtractor mem_extractor(&MC, sizeof(MC), process.GetByteOrder(),
107 process.GetAddressByteSize());
108 ASSERT_EQ(mem_extractor.GetAddress(&info_addr_offset), info_addr);
109}
110
111TEST(NativeProcessELFTest, GetELFImageInfoAddress_NoDebugEntry) {
112 NiceMock<MockDelegate> DummyDelegate;
113 MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
114
115 uint32_t phdr_addr = sizeof(llvm::ELF::Elf32_Ehdr);
116
117 auto auxv_buffer = CreateAuxvData(
118 process,
119 auxv_data: {std::make_pair(x: AuxVector::AUXV_AT_PHDR, y&: phdr_addr),
120 std::make_pair(x: AuxVector::AUXV_AT_PHENT, y: sizeof(llvm::ELF::Elf32_Phdr)),
121 std::make_pair(x: AuxVector::AUXV_AT_PHNUM, y: 2)});
122 EXPECT_CALL(process, GetAuxvData())
123 .WillOnce(once_action: Return(value: ByMove(x: std::move(auxv_buffer))));
124
125 // We're going to set up a fake memory with 2 program headers and 1 entry in
126 // the dynamic section. For simplicity sake they will be contiguous in memory.
127 struct MemoryContents {
128 llvm::ELF::Elf32_Phdr phdr_load;
129 llvm::ELF::Elf32_Phdr phdr_dynamic;
130 llvm::ELF::Elf32_Dyn dyn_notdebug;
131 } MC;
132 // Setup the 2 program header entries
133 MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
134 MC.phdr_load.p_vaddr = phdr_addr;
135
136 MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
137 MC.phdr_dynamic.p_vaddr = (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr));
138 MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
139
140 // Setup the single entry in the .dynamic section
141 MC.dyn_notdebug.d_tag = llvm::ELF::DT_NULL;
142
143 FakeMemory M(&MC, sizeof(MC), phdr_addr);
144 EXPECT_CALL(process, ReadMemory(_, _))
145 .WillRepeatedly(action: Invoke(obj_ptr: &M, method_ptr: &FakeMemory::Read));
146
147 lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
148 llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
149
150 ASSERT_EQ(elf_info_addr, LLDB_INVALID_ADDRESS);
151}
152

source code of lldb/unittests/Process/POSIX/NativeProcessELFTest.cpp