Files
llvm-project/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
Jason Molenda ba813dc03c Add new ArchSpec methods, IsCompatibleMatch() and IsExactMatch().
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
2012-11-04 03:20:05 +00:00

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;
}