blob: 1abb0293e619783194140f49806687ff8c6d4f22 [file] [log] [blame]
//===-- 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, NULL);
}
else
arch = module_sp->GetArchitecture();
ArchSpec curr_arch;
for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
{
if (GetArchitectureAtIndex (arch_idx, curr_arch))
{
if (arch == 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;
}