| 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 | |