
Summary: This patch extends the ModuleSpec class to include a DataBufferSP which contains the module data. If this data is provided, LLDB won't try to hit the filesystem to create the Module, but use only the data stored in the ModuleSpec. Reviewers: labath, espindola Subscribers: emaste, MaskRay, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D83512
279 lines
9.6 KiB
C++
279 lines
9.6 KiB
C++
//===-- TestObjectFileELF.cpp ---------------------------------------------===//
|
|
//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
|
|
#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
|
|
#include "TestingSupport/SubsystemRAII.h"
|
|
#include "TestingSupport/TestUtilities.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/ModuleSpec.h"
|
|
#include "lldb/Core/Section.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/HostInfo.h"
|
|
#include "lldb/Utility/DataBufferHeap.h"
|
|
#include "llvm/ADT/Optional.h"
|
|
#include "llvm/Support/Compression.h"
|
|
#include "llvm/Support/FileUtilities.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/Support/Program.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb;
|
|
|
|
class ObjectFileELFTest : public testing::Test {
|
|
SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
|
|
subsystems;
|
|
};
|
|
|
|
TEST_F(ObjectFileELFTest, SectionsResolveConsistently) {
|
|
auto ExpectedFile = TestFile::fromYaml(R"(
|
|
--- !ELF
|
|
FileHeader:
|
|
Class: ELFCLASS64
|
|
Data: ELFDATA2LSB
|
|
Type: ET_EXEC
|
|
Machine: EM_X86_64
|
|
Entry: 0x0000000000400180
|
|
Sections:
|
|
- Name: .note.gnu.build-id
|
|
Type: SHT_NOTE
|
|
Flags: [ SHF_ALLOC ]
|
|
Address: 0x0000000000400158
|
|
AddressAlign: 0x0000000000000004
|
|
Content: 040000001400000003000000474E55003F3EC29E3FD83E49D18C4D49CD8A730CC13117B6
|
|
- Name: .text
|
|
Type: SHT_PROGBITS
|
|
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
|
Address: 0x0000000000400180
|
|
AddressAlign: 0x0000000000000010
|
|
Content: 554889E58B042500106000890425041060005DC3
|
|
- Name: .data
|
|
Type: SHT_PROGBITS
|
|
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
|
Address: 0x0000000000601000
|
|
AddressAlign: 0x0000000000000004
|
|
Content: 2F000000
|
|
- Name: .bss
|
|
Type: SHT_NOBITS
|
|
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
|
Address: 0x0000000000601004
|
|
AddressAlign: 0x0000000000000004
|
|
Size: 0x0000000000000004
|
|
Symbols:
|
|
- Name: Y
|
|
Type: STT_OBJECT
|
|
Section: .data
|
|
Value: 0x0000000000601000
|
|
Size: 0x0000000000000004
|
|
Binding: STB_GLOBAL
|
|
- Name: _start
|
|
Type: STT_FUNC
|
|
Section: .text
|
|
Value: 0x0000000000400180
|
|
Size: 0x0000000000000014
|
|
Binding: STB_GLOBAL
|
|
- Name: X
|
|
Type: STT_OBJECT
|
|
Section: .bss
|
|
Value: 0x0000000000601004
|
|
Size: 0x0000000000000004
|
|
Binding: STB_GLOBAL
|
|
...
|
|
)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
|
|
|
|
auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
|
|
SectionList *list = module_sp->GetSectionList();
|
|
ASSERT_NE(nullptr, list);
|
|
|
|
auto bss_sp = list->FindSectionByName(ConstString(".bss"));
|
|
ASSERT_NE(nullptr, bss_sp);
|
|
auto data_sp = list->FindSectionByName(ConstString(".data"));
|
|
ASSERT_NE(nullptr, data_sp);
|
|
auto text_sp = list->FindSectionByName(ConstString(".text"));
|
|
ASSERT_NE(nullptr, text_sp);
|
|
|
|
const Symbol *X = module_sp->FindFirstSymbolWithNameAndType(ConstString("X"),
|
|
eSymbolTypeAny);
|
|
ASSERT_NE(nullptr, X);
|
|
EXPECT_EQ(bss_sp, X->GetAddress().GetSection());
|
|
|
|
const Symbol *Y = module_sp->FindFirstSymbolWithNameAndType(ConstString("Y"),
|
|
eSymbolTypeAny);
|
|
ASSERT_NE(nullptr, Y);
|
|
EXPECT_EQ(data_sp, Y->GetAddress().GetSection());
|
|
|
|
const Symbol *start = module_sp->FindFirstSymbolWithNameAndType(
|
|
ConstString("_start"), eSymbolTypeAny);
|
|
ASSERT_NE(nullptr, start);
|
|
EXPECT_EQ(text_sp, start->GetAddress().GetSection());
|
|
}
|
|
|
|
// Test that GetModuleSpecifications works on an "atypical" object file which
|
|
// has section headers right after the ELF header (instead of the more common
|
|
// layout where the section headers are at the very end of the object file).
|
|
//
|
|
// Test file generated with yaml2obj (@svn rev 324254) from the following input:
|
|
/*
|
|
--- !ELF
|
|
FileHeader:
|
|
Class: ELFCLASS64
|
|
Data: ELFDATA2LSB
|
|
Type: ET_EXEC
|
|
Machine: EM_X86_64
|
|
Entry: 0x00000000004003D0
|
|
Sections:
|
|
- Name: .note.gnu.build-id
|
|
Type: SHT_NOTE
|
|
Flags: [ SHF_ALLOC ]
|
|
Address: 0x0000000000400274
|
|
AddressAlign: 0x0000000000000004
|
|
Content: 040000001400000003000000474E55001B8A73AC238390E32A7FF4AC8EBE4D6A41ECF5C9
|
|
- Name: .text
|
|
Type: SHT_PROGBITS
|
|
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
|
Address: 0x00000000004003D0
|
|
AddressAlign: 0x0000000000000010
|
|
Content: DEADBEEFBAADF00D
|
|
...
|
|
*/
|
|
TEST_F(ObjectFileELFTest, GetModuleSpecifications_EarlySectionHeaders) {
|
|
std::string SO = GetInputFilePath("early-section-headers.so");
|
|
ModuleSpecList Specs;
|
|
ASSERT_EQ(1u, ObjectFile::GetModuleSpecifications(FileSpec(SO), 0, 0, Specs));
|
|
ModuleSpec Spec;
|
|
ASSERT_TRUE(Specs.GetModuleSpecAtIndex(0, Spec)) ;
|
|
UUID Uuid;
|
|
Uuid.SetFromStringRef("1b8a73ac238390e32a7ff4ac8ebe4d6a41ecf5c9");
|
|
EXPECT_EQ(Spec.GetUUID(), Uuid);
|
|
}
|
|
|
|
TEST_F(ObjectFileELFTest, GetSymtab_NoSymEntryPointArmThumbAddressClass) {
|
|
/*
|
|
// nosym-entrypoint-arm-thumb.s
|
|
.thumb_func
|
|
_start:
|
|
mov r0, #42
|
|
mov r7, #1
|
|
svc #0
|
|
// arm-linux-androideabi-as nosym-entrypoint-arm-thumb.s
|
|
// -o nosym-entrypoint-arm-thumb.o
|
|
// arm-linux-androideabi-ld nosym-entrypoint-arm-thumb.o
|
|
// -o nosym-entrypoint-arm-thumb -e 0x8075 -s
|
|
*/
|
|
auto ExpectedFile = TestFile::fromYaml(R"(
|
|
--- !ELF
|
|
FileHeader:
|
|
Class: ELFCLASS32
|
|
Data: ELFDATA2LSB
|
|
Type: ET_EXEC
|
|
Machine: EM_ARM
|
|
Flags: [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
|
|
Entry: 0x0000000000008075
|
|
Sections:
|
|
- Name: .text
|
|
Type: SHT_PROGBITS
|
|
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
|
Address: 0x0000000000008074
|
|
AddressAlign: 0x0000000000000002
|
|
Content: 2A20012700DF
|
|
- Name: .data
|
|
Type: SHT_PROGBITS
|
|
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
|
Address: 0x0000000000009000
|
|
AddressAlign: 0x0000000000000001
|
|
Content: ''
|
|
- Name: .bss
|
|
Type: SHT_NOBITS
|
|
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
|
Address: 0x0000000000009000
|
|
AddressAlign: 0x0000000000000001
|
|
- Name: .note.gnu.gold-version
|
|
Type: SHT_NOTE
|
|
AddressAlign: 0x0000000000000004
|
|
Content: 040000000900000004000000474E5500676F6C6420312E3131000000
|
|
- Name: .ARM.attributes
|
|
Type: SHT_ARM_ATTRIBUTES
|
|
AddressAlign: 0x0000000000000001
|
|
Content: '4113000000616561626900010900000006020901'
|
|
...
|
|
)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
|
|
|
|
auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
|
|
|
|
auto entry_point_addr = module_sp->GetObjectFile()->GetEntryPointAddress();
|
|
ASSERT_TRUE(entry_point_addr.GetOffset() & 1);
|
|
// Decrease the offsite by 1 to make it into a breakable address since this
|
|
// is Thumb.
|
|
entry_point_addr.SetOffset(entry_point_addr.GetOffset() - 1);
|
|
ASSERT_EQ(entry_point_addr.GetAddressClass(),
|
|
AddressClass::eCodeAlternateISA);
|
|
}
|
|
|
|
TEST_F(ObjectFileELFTest, GetSymtab_NoSymEntryPointArmAddressClass) {
|
|
/*
|
|
// nosym-entrypoint-arm.s
|
|
_start:
|
|
movs r0, #42
|
|
movs r7, #1
|
|
svc #0
|
|
// arm-linux-androideabi-as nosym-entrypoint-arm.s
|
|
// -o nosym-entrypoint-arm.o
|
|
// arm-linux-androideabi-ld nosym-entrypoint-arm.o
|
|
// -o nosym-entrypoint-arm -e 0x8074 -s
|
|
*/
|
|
auto ExpectedFile = TestFile::fromYaml(R"(
|
|
--- !ELF
|
|
FileHeader:
|
|
Class: ELFCLASS32
|
|
Data: ELFDATA2LSB
|
|
Type: ET_EXEC
|
|
Machine: EM_ARM
|
|
Flags: [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
|
|
Entry: 0x0000000000008074
|
|
Sections:
|
|
- Name: .text
|
|
Type: SHT_PROGBITS
|
|
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
|
Address: 0x0000000000008074
|
|
AddressAlign: 0x0000000000000004
|
|
Content: 2A00A0E30170A0E3000000EF
|
|
- Name: .data
|
|
Type: SHT_PROGBITS
|
|
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
|
Address: 0x0000000000009000
|
|
AddressAlign: 0x0000000000000001
|
|
Content: ''
|
|
- Name: .bss
|
|
Type: SHT_NOBITS
|
|
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
|
Address: 0x0000000000009000
|
|
AddressAlign: 0x0000000000000001
|
|
- Name: .note.gnu.gold-version
|
|
Type: SHT_NOTE
|
|
AddressAlign: 0x0000000000000004
|
|
Content: 040000000900000004000000474E5500676F6C6420312E3131000000
|
|
- Name: .ARM.attributes
|
|
Type: SHT_ARM_ATTRIBUTES
|
|
AddressAlign: 0x0000000000000001
|
|
Content: '4113000000616561626900010900000006010801'
|
|
...
|
|
)");
|
|
ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
|
|
|
|
auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
|
|
|
|
auto entry_point_addr = module_sp->GetObjectFile()->GetEntryPointAddress();
|
|
ASSERT_EQ(entry_point_addr.GetAddressClass(), AddressClass::eCode);
|
|
}
|