The shared cache index only had accessors for getting a file from a shared cache by filename. In some environments like iOS Simulator, a filename can be either the actual realpath name of the framework in an SDK or simulator runtime install location, or rooted on / like /System/LibraryFrameworks/SwiftUI.framework. Because the searches for binaries were by filename, this divergence would be a problem. However, searching for binaries by the binary's UUID can remove that ambiguity. I changed HostInfoMacOSX's store of SharedCacheImageInfo's to have a std::vector of all of the SharedCacheImageInfo's in a shared cache. Then I create a mapping of filename-to-SharedCacheImageInfo* and a mapping of UUID-to-SharedCacheImageInfo*, both pointing into the now-frozen std::vector. I added a HostInfo::GetSharedCacheImageInfo method to fetch an entry by shared-cache UUID + file UUID, in addition to the previous shared-cache UUID + filename. Have HostInfoMacOSX store the filenames it gets from the libdyld SPI in ConstStrings to make it clear that they have infinite lifetime in the process, and we don't need to do anything further. rdar://148939795 --------- Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
110 lines
3.9 KiB
C++
110 lines
3.9 KiB
C++
//===-- ObjectFileMachOTest.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/Mach-O/ObjectFileMachO.h"
|
|
#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
|
|
#include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
|
|
#include "TestingSupport/SubsystemRAII.h"
|
|
#include "TestingSupport/TestUtilities.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/ModuleSpec.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/HostInfo.h"
|
|
#include "lldb/Utility/FileSpec.h"
|
|
#include "lldb/lldb-defines.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#ifdef __APPLE__
|
|
#include <dlfcn.h>
|
|
#endif
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
class ObjectFileMachOTest : public ::testing::Test {
|
|
SubsystemRAII<FileSystem, HostInfo, ObjectFileMachO> subsystems;
|
|
};
|
|
} // namespace
|
|
|
|
#if defined(__APPLE__)
|
|
TEST_F(ObjectFileMachOTest, ModuleFromSharedCacheInfo) {
|
|
ArchSpec arch("arm64-apple-macosx-");
|
|
|
|
Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
|
|
|
|
SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo(
|
|
ConstString("/usr/lib/libobjc.A.dylib"),
|
|
lldb::eSymbolSharedCacheUseHostSharedCache);
|
|
EXPECT_TRUE(image_info.GetUUID());
|
|
EXPECT_TRUE(image_info.GetExtractor());
|
|
|
|
ModuleSpec spec(FileSpec(), UUID(), image_info.GetExtractor());
|
|
lldb::ModuleSP module = std::make_shared<Module>(spec);
|
|
ObjectFile *OF = module->GetObjectFile();
|
|
ASSERT_TRUE(llvm::isa<ObjectFileMachO>(OF));
|
|
EXPECT_TRUE(
|
|
OF->GetArchitecture().IsCompatibleMatch(HostInfo::GetArchitecture()));
|
|
Symtab *symtab = OF->GetSymtab();
|
|
ASSERT_NE(symtab, nullptr);
|
|
void *libobjc = dlopen("/usr/lib/libobjc.A.dylib", RTLD_LAZY);
|
|
ASSERT_NE(libobjc, nullptr);
|
|
|
|
// This function checks that if we read something from the
|
|
// ObjectFile we get through the shared cache in-mmeory
|
|
// buffer, it matches what we get by reading directly the
|
|
// memory of the symbol.
|
|
auto check_symbol = [&](const char *sym_name) {
|
|
std::vector<uint32_t> symbol_indices;
|
|
symtab->FindAllSymbolsWithNameAndType(ConstString(sym_name),
|
|
lldb::eSymbolTypeAny, symbol_indices);
|
|
EXPECT_EQ(symbol_indices.size(), 1u);
|
|
|
|
const Symbol *sym = symtab->SymbolAtIndex(symbol_indices[0]);
|
|
ASSERT_NE(sym, nullptr);
|
|
Address base = sym->GetAddress();
|
|
size_t size = sym->GetByteSize();
|
|
ASSERT_NE(size, 0u);
|
|
uint8_t buffer[size];
|
|
EXPECT_EQ(OF->ReadSectionData(base.GetSection().get(), base.GetOffset(),
|
|
buffer, size),
|
|
size);
|
|
|
|
void *sym_addr = dlsym(libobjc, sym_name);
|
|
ASSERT_NE(sym_addr, nullptr);
|
|
EXPECT_EQ(memcmp(buffer, sym_addr, size), 0);
|
|
};
|
|
|
|
// Read a symbol from the __TEXT segment...
|
|
check_symbol("objc_msgSend");
|
|
// ... and one from the __DATA segment
|
|
check_symbol("OBJC_IVAR_$_NSObject.isa");
|
|
}
|
|
|
|
TEST_F(ObjectFileMachOTest, IndirectSymbolsInTheSharedCache) {
|
|
SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo(
|
|
ConstString(
|
|
"/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit"),
|
|
lldb::eSymbolSharedCacheUseHostSharedCache);
|
|
ModuleSpec spec(FileSpec(), UUID(), image_info.GetExtractor());
|
|
lldb::ModuleSP module = std::make_shared<Module>(spec);
|
|
|
|
ObjectFile *OF = module->GetObjectFile();
|
|
ASSERT_TRUE(llvm::isa<ObjectFileMachO>(OF));
|
|
EXPECT_TRUE(
|
|
OF->GetArchitecture().IsCompatibleMatch(HostInfo::GetArchitecture()));
|
|
|
|
// Check that we can parse the symbol table several times over without
|
|
// crashing.
|
|
Symtab symtab(OF);
|
|
for (size_t i = 0; i < 10; i++)
|
|
OF->ParseSymtab(symtab);
|
|
}
|
|
#endif
|