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(pair.first); 39 encoder.AppendAddress(pair.second); 40 } 41 return llvm::MemoryBuffer::getMemBufferCopy( 42 llvm::toStringRef(encoder.GetData()), ""); 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, {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr)}); 54 EXPECT_CALL(process, GetAuxvData()) 55 .WillOnce(Return(ByMove(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 {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr), 71 std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)), 72 std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)}); 73 EXPECT_CALL(process, GetAuxvData()) 74 .WillOnce(Return(ByMove(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(Invoke(&M, &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 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 {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr), 120 std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)), 121 std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)}); 122 EXPECT_CALL(process, GetAuxvData()) 123 .WillOnce(Return(ByMove(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(Invoke(&M, &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