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