
ObjectFileELF::GetModuleSpecifications contained a lot of tip-toing code which was trying to avoid loading the full object file into memory. It did this by trying to load data only up to the offset if was accessing. However, in practice this was useless, as 99% of object files we encounter have section headers at the end, so we would load the whole file as soon as we start parsing the section headers. In fact, this would break as soon as we encounter a file which does *not* have section headers at the end (yaml2obj produces these), as the access to .strtab (which we need to get the section names) was not guarded by this offset check. As this strategy was completely ineffective anyway, I do not attempt to proliferate it further by guarding the .strtab accesses. Instead I just lead the full file as soon as we are reasonably sure that we are indeed processing an elf file. If we really care about the load size here, we would need to reimplement this to just load the bits of the object file we need, instead of loading everything from the start of the object file to the given offset. However, given that the OS will do this for us for free when using mmap, I think think this is really necessary. For testing this I check a (tiny) SO file instead of yaml2obj-ing it because the fact that they come out first is an implementation detail of yaml2obj that can change in the future. llvm-svn: 324254
115 lines
4.4 KiB
C++
115 lines
4.4 KiB
C++
//===-- TestObjectFileELF.cpp -----------------------------------*- C++ -*-===//
|
|
//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
|
|
#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
|
|
#include "TestingSupport/TestUtilities.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/ModuleSpec.h"
|
|
#include "lldb/Core/Section.h"
|
|
#include "lldb/Host/HostInfo.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 "gtest/gtest.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb;
|
|
|
|
class ObjectFileELFTest : public testing::Test {
|
|
public:
|
|
void SetUp() override {
|
|
HostInfo::Initialize();
|
|
ObjectFileELF::Initialize();
|
|
SymbolVendorELF::Initialize();
|
|
}
|
|
|
|
void TearDown() override {
|
|
SymbolVendorELF::Terminate();
|
|
ObjectFileELF::Terminate();
|
|
HostInfo::Terminate();
|
|
}
|
|
|
|
protected:
|
|
};
|
|
|
|
#define ASSERT_NO_ERROR(x) \
|
|
if (std::error_code ASSERT_NO_ERROR_ec = x) { \
|
|
llvm::SmallString<128> MessageStorage; \
|
|
llvm::raw_svector_ostream Message(MessageStorage); \
|
|
Message << #x ": did not return errc::success.\n" \
|
|
<< "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
|
|
<< "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
|
|
GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
|
|
} else { \
|
|
}
|
|
|
|
TEST_F(ObjectFileELFTest, SectionsResolveConsistently) {
|
|
std::string yaml = GetInputFilePath("sections-resolve-consistently.yaml");
|
|
llvm::SmallString<128> obj;
|
|
ASSERT_NO_ERROR(llvm::sys::fs::createTemporaryFile(
|
|
"sections-resolve-consistently-%%%%%%", "obj", obj));
|
|
|
|
llvm::FileRemover remover(obj);
|
|
const char *args[] = {YAML2OBJ, yaml.c_str(), nullptr};
|
|
llvm::StringRef obj_ref = obj;
|
|
const llvm::Optional<llvm::StringRef> redirects[] = {llvm::None, obj_ref,
|
|
llvm::None};
|
|
ASSERT_EQ(0, llvm::sys::ExecuteAndWait(YAML2OBJ, args, nullptr, redirects));
|
|
uint64_t size;
|
|
ASSERT_NO_ERROR(llvm::sys::fs::file_size(obj, size));
|
|
ASSERT_GT(size, 0u);
|
|
|
|
ModuleSpec spec{FileSpec(obj, false)};
|
|
spec.GetSymbolFileSpec().SetFile(obj, false);
|
|
auto module_sp = std::make_shared<Module>(spec);
|
|
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_F(ObjectFileELFTest, GetModuleSpecifications_EarlySectionHeaders) {
|
|
std::string SO = GetInputFilePath("early-section-headers.so");
|
|
ModuleSpecList Specs;
|
|
ASSERT_EQ(1u, ObjectFile::GetModuleSpecifications(FileSpec(SO, false), 0, 0, Specs));
|
|
ModuleSpec Spec;
|
|
ASSERT_TRUE(Specs.GetModuleSpecAtIndex(0, Spec)) ;
|
|
UUID Uuid;
|
|
Uuid.SetFromStringRef("1b8a73ac238390e32a7ff4ac8ebe4d6a41ecf5c9", 20);
|
|
EXPECT_EQ(Spec.GetUUID(), Uuid);
|
|
}
|