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
21 using namespace lldb_private;
22 using namespace lldb;
23 using namespace testing;
24
25 namespace {
26 class MockProcessELF : public MockProcess<NativeProcessELF> {
27 public:
28 using MockProcess::MockProcess;
29 using NativeProcessELF::GetAuxValue;
30 using NativeProcessELF::GetELFImageInfoAddress;
31 };
32
CreateAuxvData(MockProcessELF & process,llvm::ArrayRef<std::pair<AuxVector::EntryType,uint32_t>> auxv_data)33 std::unique_ptr<llvm::MemoryBuffer> CreateAuxvData(
34 MockProcessELF &process,
35 llvm::ArrayRef<std::pair<AuxVector::EntryType, uint32_t>> auxv_data) {
36 auto addr_size = process.GetAddressByteSize();
37 DataBufferSP buffer_sp(
38 new DataBufferHeap(auxv_data.size() * addr_size * 2, 0));
39 DataEncoder encoder(buffer_sp, process.GetByteOrder(), addr_size);
40 uint32_t offset = 0;
41 for (auto &pair : auxv_data) {
42 offset = encoder.PutAddress(offset, pair.first);
43 offset = encoder.PutAddress(offset, pair.second);
44 }
45 return llvm::MemoryBuffer::getMemBufferCopy(
46 llvm::toStringRef(buffer_sp->GetData()), "");
47 }
48
49 } // namespace
50
TEST(NativeProcessELFTest,GetAuxValue)51 TEST(NativeProcessELFTest, GetAuxValue) {
52 NiceMock<MockDelegate> DummyDelegate;
53 MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
54
55 uint64_t phdr_addr = 0x42;
56 auto auxv_buffer = CreateAuxvData(
57 process, {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr)});
58 EXPECT_CALL(process, GetAuxvData())
59 .WillOnce(Return(ByMove(std::move(auxv_buffer))));
60
61 ASSERT_EQ(phdr_addr, process.GetAuxValue(AuxVector::AUXV_AT_PHDR));
62 }
63
TEST(NativeProcessELFTest,GetELFImageInfoAddress)64 TEST(NativeProcessELFTest, GetELFImageInfoAddress) {
65 NiceMock<MockDelegate> DummyDelegate;
66 MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
67
68 uint32_t load_base = 0x1000;
69 uint32_t info_addr = 0x3741;
70 uint32_t phdr_addr = load_base + sizeof(llvm::ELF::Elf32_Ehdr);
71
72 auto auxv_buffer = CreateAuxvData(
73 process,
74 {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr),
75 std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)),
76 std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)});
77 EXPECT_CALL(process, GetAuxvData())
78 .WillOnce(Return(ByMove(std::move(auxv_buffer))));
79
80 // We're going to set up a fake memory with 2 program headers and 1 entry in
81 // the dynamic section. For simplicity sake they will be contiguous in memory.
82 struct MemoryContents {
83 llvm::ELF::Elf32_Phdr phdr_load;
84 llvm::ELF::Elf32_Phdr phdr_dynamic;
85 llvm::ELF::Elf32_Dyn dyn_debug;
86 } MC;
87 // Setup the 2 program header entries
88 MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
89 MC.phdr_load.p_vaddr = phdr_addr - load_base;
90
91 MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
92 MC.phdr_dynamic.p_vaddr =
93 (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr)) - load_base;
94 MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
95
96 // Setup the single entry in the .dynamic section
97 MC.dyn_debug.d_tag = llvm::ELF::DT_DEBUG;
98 MC.dyn_debug.d_un.d_ptr = info_addr;
99
100 FakeMemory M(&MC, sizeof(MC), phdr_addr);
101 EXPECT_CALL(process, ReadMemory(_, _))
102 .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
103
104 lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
105 llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
106
107 // Read the address at the elf_info_addr location to make sure we're reading
108 // the correct one.
109 lldb::offset_t info_addr_offset = elf_info_addr - phdr_addr;
110 DataExtractor mem_extractor(&MC, sizeof(MC), process.GetByteOrder(),
111 process.GetAddressByteSize());
112 ASSERT_EQ(mem_extractor.GetAddress(&info_addr_offset), info_addr);
113 }
114
TEST(NativeProcessELFTest,GetELFImageInfoAddress_NoDebugEntry)115 TEST(NativeProcessELFTest, GetELFImageInfoAddress_NoDebugEntry) {
116 NiceMock<MockDelegate> DummyDelegate;
117 MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
118
119 uint32_t phdr_addr = sizeof(llvm::ELF::Elf32_Ehdr);
120
121 auto auxv_buffer = CreateAuxvData(
122 process,
123 {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr),
124 std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)),
125 std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)});
126 EXPECT_CALL(process, GetAuxvData())
127 .WillOnce(Return(ByMove(std::move(auxv_buffer))));
128
129 // We're going to set up a fake memory with 2 program headers and 1 entry in
130 // the dynamic section. For simplicity sake they will be contiguous in memory.
131 struct MemoryContents {
132 llvm::ELF::Elf32_Phdr phdr_load;
133 llvm::ELF::Elf32_Phdr phdr_dynamic;
134 llvm::ELF::Elf32_Dyn dyn_notdebug;
135 } MC;
136 // Setup the 2 program header entries
137 MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
138 MC.phdr_load.p_vaddr = phdr_addr;
139
140 MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
141 MC.phdr_dynamic.p_vaddr = (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr));
142 MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
143
144 // Setup the single entry in the .dynamic section
145 MC.dyn_notdebug.d_tag = llvm::ELF::DT_NULL;
146
147 FakeMemory M(&MC, sizeof(MC), phdr_addr);
148 EXPECT_CALL(process, ReadMemory(_, _))
149 .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
150
151 lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
152 llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
153
154 ASSERT_EQ(elf_info_addr, LLDB_INVALID_ADDRESS);
155 }
156