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 | |
33 | std::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 | |
47 | TEST(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 | |
60 | TEST(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 (&MC, sizeof(MC), process.GetByteOrder(), |
107 | process.GetAddressByteSize()); |
108 | ASSERT_EQ(mem_extractor.GetAddress(&info_addr_offset), info_addr); |
109 | } |
110 | |
111 | TEST(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 | |