The operator== method is a synonym for IsExactMatch(). The essential difference between these two is that IsCompatibleMatch() will say that armv7 and armv7s are compatible and return true. IsExactMatch() will say that armv7 and armv7s are not a match. An armv7s cpu can run either generic armv7 binaries or armv7s binaries (the latter being tuned for it). When we're picking the slice of a universal Mach-O file to load in an armv7s Target, we need to be able to first look for an exact cpu subtype match (armv7s == armv7s) and failing that, looking for a slice with a compatible architecture. Update ObjectContainerUniversalMachO::GetObjectFile to prefer an exact match of the cpu type, falling back to a compatible match if necessary. <rdar://problem/12593515> llvm-svn: 167365
265 lines
7.2 KiB
C++
265 lines
7.2 KiB
C++
//===-- ObjectContainerUniversalMachO.cpp -----------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ObjectContainerUniversalMachO.h"
|
|
#include "lldb/Core/Stream.h"
|
|
#include "lldb/Core/ArchSpec.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/PluginManager.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Target/Target.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace llvm::MachO;
|
|
|
|
void
|
|
ObjectContainerUniversalMachO::Initialize()
|
|
{
|
|
PluginManager::RegisterPlugin (GetPluginNameStatic(),
|
|
GetPluginDescriptionStatic(),
|
|
CreateInstance);
|
|
}
|
|
|
|
void
|
|
ObjectContainerUniversalMachO::Terminate()
|
|
{
|
|
PluginManager::UnregisterPlugin (CreateInstance);
|
|
}
|
|
|
|
|
|
const char *
|
|
ObjectContainerUniversalMachO::GetPluginNameStatic()
|
|
{
|
|
return "object-container.mach-o";
|
|
}
|
|
|
|
const char *
|
|
ObjectContainerUniversalMachO::GetPluginDescriptionStatic()
|
|
{
|
|
return "Universal mach-o object container reader.";
|
|
}
|
|
|
|
|
|
ObjectContainer *
|
|
ObjectContainerUniversalMachO::CreateInstance
|
|
(
|
|
const lldb::ModuleSP &module_sp,
|
|
DataBufferSP& data_sp,
|
|
const FileSpec *file,
|
|
addr_t offset,
|
|
addr_t length
|
|
)
|
|
{
|
|
DataExtractor data;
|
|
data.SetData (data_sp, offset, length);
|
|
if (ObjectContainerUniversalMachO::MagicBytesMatch(data))
|
|
{
|
|
std::auto_ptr<ObjectContainerUniversalMachO> container_ap(new ObjectContainerUniversalMachO (module_sp, data_sp, file, offset, length));
|
|
if (container_ap->ParseHeader())
|
|
{
|
|
return container_ap.release();
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
ObjectContainerUniversalMachO::MagicBytesMatch (const DataExtractor &data)
|
|
{
|
|
uint32_t offset = 0;
|
|
uint32_t magic = data.GetU32(&offset);
|
|
return magic == UniversalMagic || magic == UniversalMagicSwapped;
|
|
}
|
|
|
|
ObjectContainerUniversalMachO::ObjectContainerUniversalMachO
|
|
(
|
|
const lldb::ModuleSP &module_sp,
|
|
DataBufferSP& dataSP,
|
|
const FileSpec *file,
|
|
addr_t offset,
|
|
addr_t length
|
|
) :
|
|
ObjectContainer (module_sp, file, offset, length, dataSP),
|
|
m_header(),
|
|
m_fat_archs()
|
|
{
|
|
memset(&m_header, 0, sizeof(m_header));
|
|
}
|
|
|
|
|
|
ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO()
|
|
{
|
|
}
|
|
|
|
bool
|
|
ObjectContainerUniversalMachO::ParseHeader ()
|
|
{
|
|
// Store the file offset for this universal file as we could have a universal .o file
|
|
// in a BSD archive, or be contained in another kind of object.
|
|
uint32_t offset = 0;
|
|
// Universal mach-o files always have their headers in big endian.
|
|
m_data.SetByteOrder (eByteOrderBig);
|
|
m_header.magic = m_data.GetU32(&offset);
|
|
|
|
if (m_header.magic == UniversalMagic)
|
|
{
|
|
m_data.SetAddressByteSize(4);
|
|
|
|
m_header.nfat_arch = m_data.GetU32(&offset);
|
|
|
|
// Now we should have enough data for all of the fat headers, so lets index
|
|
// them so we know how many architectures that this universal binary contains.
|
|
uint32_t arch_idx = 0;
|
|
for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
|
|
{
|
|
if (m_data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch)))
|
|
{
|
|
fat_arch arch;
|
|
if (m_data.GetU32(&offset, &arch, sizeof(fat_arch)/sizeof(uint32_t)))
|
|
{
|
|
m_fat_archs.push_back(arch);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
memset(&m_header, 0, sizeof(m_header));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
ObjectContainerUniversalMachO::Dump (Stream *s) const
|
|
{
|
|
s->Printf("%p: ", this);
|
|
s->Indent();
|
|
const size_t num_archs = GetNumArchitectures();
|
|
const size_t num_objects = GetNumObjects();
|
|
s->Printf("ObjectContainerUniversalMachO, num_archs = %lu, num_objects = %lu", num_archs, num_objects);
|
|
uint32_t i;
|
|
ArchSpec arch;
|
|
s->IndentMore();
|
|
for (i=0; i<num_archs; i++)
|
|
{
|
|
s->Indent();
|
|
GetArchitectureAtIndex(i, arch);
|
|
s->Printf("arch[%u] = %s\n", i, arch.GetArchitectureName());
|
|
}
|
|
for (i=0; i<num_objects; i++)
|
|
{
|
|
s->Indent();
|
|
s->Printf("object[%u] = %s\n", i, GetObjectNameAtIndex (i));
|
|
}
|
|
s->IndentLess();
|
|
s->EOL();
|
|
}
|
|
|
|
size_t
|
|
ObjectContainerUniversalMachO::GetNumArchitectures () const
|
|
{
|
|
return m_header.nfat_arch;
|
|
}
|
|
|
|
bool
|
|
ObjectContainerUniversalMachO::GetArchitectureAtIndex (uint32_t idx, ArchSpec& arch) const
|
|
{
|
|
if (idx < m_header.nfat_arch)
|
|
{
|
|
arch.SetArchitecture (eArchTypeMachO, m_fat_archs[idx].cputype, m_fat_archs[idx].cpusubtype);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ObjectFileSP
|
|
ObjectContainerUniversalMachO::GetObjectFile (const FileSpec *file)
|
|
{
|
|
uint32_t arch_idx = 0;
|
|
ArchSpec arch;
|
|
// If the module hasn't specified an architecture yet, set it to the default
|
|
// architecture:
|
|
ModuleSP module_sp (GetModule());
|
|
if (module_sp)
|
|
{
|
|
if (!module_sp->GetArchitecture().IsValid())
|
|
{
|
|
arch = Target::GetDefaultArchitecture ();
|
|
if (!arch.IsValid())
|
|
arch.SetTriple (LLDB_ARCH_DEFAULT);
|
|
}
|
|
else
|
|
arch = module_sp->GetArchitecture();
|
|
|
|
ArchSpec curr_arch;
|
|
// First, try to find an exact match for the Arch of the Target.
|
|
for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
|
|
{
|
|
if (GetArchitectureAtIndex (arch_idx, curr_arch))
|
|
{
|
|
if (arch.IsExactMatch(curr_arch))
|
|
{
|
|
return ObjectFile::FindPlugin (module_sp,
|
|
file,
|
|
m_offset + m_fat_archs[arch_idx].offset,
|
|
m_fat_archs[arch_idx].size,
|
|
m_data.GetSharedDataBuffer());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Failing an exact match, try to find a compatible Arch of the Target.
|
|
for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
|
|
{
|
|
if (GetArchitectureAtIndex (arch_idx, curr_arch))
|
|
{
|
|
if (arch.IsCompatibleMatch(curr_arch))
|
|
{
|
|
return ObjectFile::FindPlugin (module_sp,
|
|
file,
|
|
m_offset + m_fat_archs[arch_idx].offset,
|
|
m_fat_archs[arch_idx].size,
|
|
m_data.GetSharedDataBuffer());
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return ObjectFileSP();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------
|
|
// PluginInterface protocol
|
|
//------------------------------------------------------------------
|
|
const char *
|
|
ObjectContainerUniversalMachO::GetPluginName()
|
|
{
|
|
return "ObjectContainerUniversalMachO";
|
|
}
|
|
|
|
const char *
|
|
ObjectContainerUniversalMachO::GetShortPluginName()
|
|
{
|
|
return GetPluginNameStatic();
|
|
}
|
|
|
|
uint32_t
|
|
ObjectContainerUniversalMachO::GetPluginVersion()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|