1//===-- TestObjectFileELF.cpp ---------------------------------------------===//
2//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
11#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
12#include "TestingSupport/SubsystemRAII.h"
13#include "TestingSupport/TestUtilities.h"
14#include "lldb/Core/Module.h"
15#include "lldb/Core/ModuleSpec.h"
16#include "lldb/Core/Section.h"
17#include "lldb/Host/FileSystem.h"
18#include "lldb/Host/HostInfo.h"
19#include "lldb/Utility/DataBufferHeap.h"
20#include "llvm/Support/Compression.h"
21#include "llvm/Support/FileUtilities.h"
22#include "llvm/Support/Path.h"
23#include "llvm/Support/Program.h"
24#include "llvm/Support/raw_ostream.h"
25#include "llvm/Testing/Support/Error.h"
26#include "gtest/gtest.h"
27
28using namespace lldb_private;
29using namespace lldb;
30
31class ObjectFileELFTest : public testing::Test {
32 SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
33 subsystems;
34};
35
36TEST_F(ObjectFileELFTest, SectionsResolveConsistently) {
37 auto ExpectedFile = TestFile::fromYaml(Yaml: R"(
38--- !ELF
39FileHeader:
40 Class: ELFCLASS64
41 Data: ELFDATA2LSB
42 Type: ET_EXEC
43 Machine: EM_X86_64
44 Entry: 0x0000000000400180
45Sections:
46 - Name: .note.gnu.build-id
47 Type: SHT_NOTE
48 Flags: [ SHF_ALLOC ]
49 Address: 0x0000000000400158
50 AddressAlign: 0x0000000000000004
51 Content: 040000001400000003000000474E55003F3EC29E3FD83E49D18C4D49CD8A730CC13117B6
52 - Name: .text
53 Type: SHT_PROGBITS
54 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
55 Address: 0x0000000000400180
56 AddressAlign: 0x0000000000000010
57 Content: 554889E58B042500106000890425041060005DC3
58 - Name: .data
59 Type: SHT_PROGBITS
60 Flags: [ SHF_WRITE, SHF_ALLOC ]
61 Address: 0x0000000000601000
62 AddressAlign: 0x0000000000000004
63 Content: 2F000000
64 - Name: .bss
65 Type: SHT_NOBITS
66 Flags: [ SHF_WRITE, SHF_ALLOC ]
67 Address: 0x0000000000601004
68 AddressAlign: 0x0000000000000004
69 Size: 0x0000000000000004
70Symbols:
71 - Name: Y
72 Type: STT_OBJECT
73 Section: .data
74 Value: 0x0000000000601000
75 Size: 0x0000000000000004
76 Binding: STB_GLOBAL
77 - Name: _start
78 Type: STT_FUNC
79 Section: .text
80 Value: 0x0000000000400180
81 Size: 0x0000000000000014
82 Binding: STB_GLOBAL
83 - Name: X
84 Type: STT_OBJECT
85 Section: .bss
86 Value: 0x0000000000601004
87 Size: 0x0000000000000004
88 Binding: STB_GLOBAL
89...
90)");
91 ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
92
93 auto module_sp = std::make_shared<Module>(args: ExpectedFile->moduleSpec());
94 SectionList *list = module_sp->GetSectionList();
95 ASSERT_NE(nullptr, list);
96
97 auto bss_sp = list->FindSectionByName(section_dstr: ConstString(".bss"));
98 ASSERT_NE(nullptr, bss_sp);
99 auto data_sp = list->FindSectionByName(section_dstr: ConstString(".data"));
100 ASSERT_NE(nullptr, data_sp);
101 auto text_sp = list->FindSectionByName(section_dstr: ConstString(".text"));
102 ASSERT_NE(nullptr, text_sp);
103
104 const Symbol *X = module_sp->FindFirstSymbolWithNameAndType(name: ConstString("X"),
105 symbol_type: eSymbolTypeAny);
106 ASSERT_NE(nullptr, X);
107 EXPECT_EQ(bss_sp, X->GetAddress().GetSection());
108
109 const Symbol *Y = module_sp->FindFirstSymbolWithNameAndType(name: ConstString("Y"),
110 symbol_type: eSymbolTypeAny);
111 ASSERT_NE(nullptr, Y);
112 EXPECT_EQ(data_sp, Y->GetAddress().GetSection());
113
114 const Symbol *start = module_sp->FindFirstSymbolWithNameAndType(
115 name: ConstString("_start"), symbol_type: eSymbolTypeAny);
116 ASSERT_NE(nullptr, start);
117 EXPECT_EQ(text_sp, start->GetAddress().GetSection());
118}
119
120// Test that GetModuleSpecifications works on an "atypical" object file which
121// has section headers right after the ELF header (instead of the more common
122// layout where the section headers are at the very end of the object file).
123//
124// Test file generated with yaml2obj (@svn rev 324254) from the following input:
125/*
126--- !ELF
127FileHeader:
128 Class: ELFCLASS64
129 Data: ELFDATA2LSB
130 Type: ET_EXEC
131 Machine: EM_X86_64
132 Entry: 0x00000000004003D0
133Sections:
134 - Name: .note.gnu.build-id
135 Type: SHT_NOTE
136 Flags: [ SHF_ALLOC ]
137 Address: 0x0000000000400274
138 AddressAlign: 0x0000000000000004
139 Content: 040000001400000003000000474E55001B8A73AC238390E32A7FF4AC8EBE4D6A41ECF5C9
140 - Name: .text
141 Type: SHT_PROGBITS
142 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
143 Address: 0x00000000004003D0
144 AddressAlign: 0x0000000000000010
145 Content: DEADBEEFBAADF00D
146...
147*/
148TEST_F(ObjectFileELFTest, GetModuleSpecifications_EarlySectionHeaders) {
149 std::string SO = GetInputFilePath(name: "early-section-headers.so");
150 ModuleSpecList Specs;
151 ASSERT_EQ(1u, ObjectFile::GetModuleSpecifications(FileSpec(SO), 0, 0, Specs));
152 ModuleSpec Spec;
153 ASSERT_TRUE(Specs.GetModuleSpecAtIndex(0, Spec)) ;
154 UUID Uuid;
155 Uuid.SetFromStringRef("1b8a73ac238390e32a7ff4ac8ebe4d6a41ecf5c9");
156 EXPECT_EQ(Spec.GetUUID(), Uuid);
157}
158
159TEST_F(ObjectFileELFTest, GetModuleSpecifications_OffsetSizeWithNormalFile) {
160 std::string SO = GetInputFilePath(name: "liboffset-test.so");
161 ModuleSpecList Specs;
162 ASSERT_EQ(1u, ObjectFile::GetModuleSpecifications(FileSpec(SO), 0, 0, Specs));
163 ModuleSpec Spec;
164 ASSERT_TRUE(Specs.GetModuleSpecAtIndex(0, Spec)) ;
165 UUID Uuid;
166 Uuid.SetFromStringRef("7D6E4738");
167 EXPECT_EQ(Spec.GetUUID(), Uuid);
168 EXPECT_EQ(Spec.GetObjectOffset(), 0UL);
169 EXPECT_EQ(Spec.GetObjectSize(), 3600UL);
170 EXPECT_EQ(FileSystem::Instance().GetByteSize(FileSpec(SO)), 3600UL);
171}
172
173TEST_F(ObjectFileELFTest, GetModuleSpecifications_OffsetSizeWithOffsetFile) {
174 // The contents of offset-test.bin are
175 // - 0-1023: \0
176 // - 1024-4623: liboffset-test.so (offset: 1024, size: 3600, CRC32: 7D6E4738)
177 // - 4624-4639: \0
178 std::string SO = GetInputFilePath(name: "offset-test.bin");
179 ModuleSpecList Specs;
180 ASSERT_EQ(
181 1u, ObjectFile::GetModuleSpecifications(FileSpec(SO), 1024, 3600, Specs));
182 ModuleSpec Spec;
183 ASSERT_TRUE(Specs.GetModuleSpecAtIndex(0, Spec)) ;
184 UUID Uuid;
185 Uuid.SetFromStringRef("7D6E4738");
186 EXPECT_EQ(Spec.GetUUID(), Uuid);
187 EXPECT_EQ(Spec.GetObjectOffset(), 1024UL);
188 EXPECT_EQ(Spec.GetObjectSize(), 3600UL);
189 EXPECT_EQ(FileSystem::Instance().GetByteSize(FileSpec(SO)), 4640UL);
190}
191
192TEST_F(ObjectFileELFTest, GetSymtab_NoSymEntryPointArmThumbAddressClass) {
193 /*
194 // nosym-entrypoint-arm-thumb.s
195 .thumb_func
196 _start:
197 mov r0, #42
198 mov r7, #1
199 svc #0
200 // arm-linux-androideabi-as nosym-entrypoint-arm-thumb.s
201 // -o nosym-entrypoint-arm-thumb.o
202 // arm-linux-androideabi-ld nosym-entrypoint-arm-thumb.o
203 // -o nosym-entrypoint-arm-thumb -e 0x8075 -s
204 */
205 auto ExpectedFile = TestFile::fromYaml(Yaml: R"(
206--- !ELF
207FileHeader:
208 Class: ELFCLASS32
209 Data: ELFDATA2LSB
210 Type: ET_EXEC
211 Machine: EM_ARM
212 Flags: [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
213 Entry: 0x0000000000008075
214Sections:
215 - Name: .text
216 Type: SHT_PROGBITS
217 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
218 Address: 0x0000000000008074
219 AddressAlign: 0x0000000000000002
220 Content: 2A20012700DF
221 - Name: .data
222 Type: SHT_PROGBITS
223 Flags: [ SHF_WRITE, SHF_ALLOC ]
224 Address: 0x0000000000009000
225 AddressAlign: 0x0000000000000001
226 Content: ''
227 - Name: .bss
228 Type: SHT_NOBITS
229 Flags: [ SHF_WRITE, SHF_ALLOC ]
230 Address: 0x0000000000009000
231 AddressAlign: 0x0000000000000001
232 - Name: .note.gnu.gold-version
233 Type: SHT_NOTE
234 AddressAlign: 0x0000000000000004
235 Content: 040000000900000004000000474E5500676F6C6420312E3131000000
236 - Name: .ARM.attributes
237 Type: SHT_ARM_ATTRIBUTES
238 AddressAlign: 0x0000000000000001
239 Content: '4113000000616561626900010900000006020901'
240...
241)");
242 ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
243
244 auto module_sp = std::make_shared<Module>(args: ExpectedFile->moduleSpec());
245
246 auto entry_point_addr = module_sp->GetObjectFile()->GetEntryPointAddress();
247 ASSERT_TRUE(entry_point_addr.GetOffset() & 1);
248 // Decrease the offsite by 1 to make it into a breakable address since this
249 // is Thumb.
250 entry_point_addr.SetOffset(entry_point_addr.GetOffset() - 1);
251 ASSERT_EQ(entry_point_addr.GetAddressClass(),
252 AddressClass::eCodeAlternateISA);
253}
254
255TEST_F(ObjectFileELFTest, GetSymtab_NoSymEntryPointArmAddressClass) {
256 /*
257 // nosym-entrypoint-arm.s
258 _start:
259 movs r0, #42
260 movs r7, #1
261 svc #0
262 // arm-linux-androideabi-as nosym-entrypoint-arm.s
263 // -o nosym-entrypoint-arm.o
264 // arm-linux-androideabi-ld nosym-entrypoint-arm.o
265 // -o nosym-entrypoint-arm -e 0x8074 -s
266 */
267 auto ExpectedFile = TestFile::fromYaml(Yaml: R"(
268--- !ELF
269FileHeader:
270 Class: ELFCLASS32
271 Data: ELFDATA2LSB
272 Type: ET_EXEC
273 Machine: EM_ARM
274 Flags: [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
275 Entry: 0x0000000000008074
276Sections:
277 - Name: .text
278 Type: SHT_PROGBITS
279 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
280 Address: 0x0000000000008074
281 AddressAlign: 0x0000000000000004
282 Content: 2A00A0E30170A0E3000000EF
283 - Name: .data
284 Type: SHT_PROGBITS
285 Flags: [ SHF_WRITE, SHF_ALLOC ]
286 Address: 0x0000000000009000
287 AddressAlign: 0x0000000000000001
288 Content: ''
289 - Name: .bss
290 Type: SHT_NOBITS
291 Flags: [ SHF_WRITE, SHF_ALLOC ]
292 Address: 0x0000000000009000
293 AddressAlign: 0x0000000000000001
294 - Name: .note.gnu.gold-version
295 Type: SHT_NOTE
296 AddressAlign: 0x0000000000000004
297 Content: 040000000900000004000000474E5500676F6C6420312E3131000000
298 - Name: .ARM.attributes
299 Type: SHT_ARM_ATTRIBUTES
300 AddressAlign: 0x0000000000000001
301 Content: '4113000000616561626900010900000006010801'
302...
303)");
304 ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
305
306 auto module_sp = std::make_shared<Module>(args: ExpectedFile->moduleSpec());
307
308 auto entry_point_addr = module_sp->GetObjectFile()->GetEntryPointAddress();
309 ASSERT_EQ(entry_point_addr.GetAddressClass(), AddressClass::eCode);
310}
311

source code of lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp