1 //===-- NativeProcessELFTest.cpp ------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "TestingSupport/Host/NativeProcessTestUtils.h"
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"
19 #include "gmock/gmock.h"
21 using namespace lldb_private
;
23 using namespace testing
;
26 class MockProcessELF
: public MockProcess
<NativeProcessELF
> {
28 using MockProcess::MockProcess
;
29 using NativeProcessELF::GetAuxValue
;
30 using NativeProcessELF::GetELFImageInfoAddress
;
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
);
41 return llvm::MemoryBuffer::getMemBufferCopy(
42 llvm::toStringRef(encoder
.GetData()), "");
47 TEST(NativeProcessELFTest
, GetAuxValue
) {
48 NiceMock
<MockDelegate
> DummyDelegate
;
49 MockProcessELF
process(DummyDelegate
, ArchSpec("i386-pc-linux"));
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
))));
57 ASSERT_EQ(phdr_addr
, process
.GetAuxValue(AuxVector::AUXV_AT_PHDR
));
60 TEST(NativeProcessELFTest
, GetELFImageInfoAddress
) {
61 NiceMock
<MockDelegate
> DummyDelegate
;
62 MockProcessELF
process(DummyDelegate
, ArchSpec("i386-pc-linux"));
64 uint32_t load_base
= 0x1000;
65 uint32_t info_addr
= 0x3741;
66 uint32_t phdr_addr
= load_base
+ sizeof(llvm::ELF::Elf32_Ehdr
);
68 auto auxv_buffer
= CreateAuxvData(
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
))));
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
;
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
;
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
);
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
;
96 FakeMemory
M(&MC
, sizeof(MC
), phdr_addr
);
97 EXPECT_CALL(process
, ReadMemory(_
, _
))
98 .WillRepeatedly(Invoke(&M
, &FakeMemory::Read
));
100 lldb::addr_t elf_info_addr
= process
.GetELFImageInfoAddress
<
101 llvm::ELF::Elf32_Ehdr
, llvm::ELF::Elf32_Phdr
, llvm::ELF::Elf32_Dyn
>();
103 // Read the address at the elf_info_addr location to make sure we're reading
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
);
111 TEST(NativeProcessELFTest
, GetELFImageInfoAddress_NoDebugEntry
) {
112 NiceMock
<MockDelegate
> DummyDelegate
;
113 MockProcessELF
process(DummyDelegate
, ArchSpec("i386-pc-linux"));
115 uint32_t phdr_addr
= sizeof(llvm::ELF::Elf32_Ehdr
);
117 auto auxv_buffer
= CreateAuxvData(
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
))));
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
;
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
;
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
);
140 // Setup the single entry in the .dynamic section
141 MC
.dyn_notdebug
.d_tag
= llvm::ELF::DT_NULL
;
143 FakeMemory
M(&MC
, sizeof(MC
), phdr_addr
);
144 EXPECT_CALL(process
, ReadMemory(_
, _
))
145 .WillRepeatedly(Invoke(&M
, &FakeMemory::Read
));
147 lldb::addr_t elf_info_addr
= process
.GetELFImageInfoAddress
<
148 llvm::ELF::Elf32_Ehdr
, llvm::ELF::Elf32_Phdr
, llvm::ELF::Elf32_Dyn
>();
150 ASSERT_EQ(elf_info_addr
, LLDB_INVALID_ADDRESS
);