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