Initial checkin of lldb code from internal Apple repo.


git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@105619 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
new file mode 100644
index 0000000..c2fb2a5
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -0,0 +1,428 @@
+//===-- ObjectContainerBSDArchive.cpp ---------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectContainerBSDArchive.h"
+
+#include <ar.h>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+ObjectContainerBSDArchive::Object::Object() :
+    ar_name(),
+    ar_date(0),
+    ar_uid(0),
+    ar_gid(0),
+    ar_mode(0),
+    ar_size(0),
+    ar_file_offset(0),
+    ar_file_size(0)
+{
+}
+
+void
+ObjectContainerBSDArchive::Object::Clear()
+{
+    ar_name.Clear();
+    ar_date = 0;
+    ar_uid  = 0;
+    ar_gid  = 0;
+    ar_mode = 0;
+    ar_size = 0;
+    ar_file_offset = 0;
+    ar_file_size = 0;
+}
+
+uint32_t
+ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, uint32_t offset)
+{
+    size_t ar_name_len = 0;
+    std::string str;
+    char *err;
+    str.assign ((const char *)data.GetData(&offset, 16),    16);
+    if (str.find(AR_EFMT1) == 0)
+    {
+        // If the name is longer than 16 bytes, or contains an embedded space
+        // then it will use this format where the length of the name is
+        // here and the name characters are after this header.
+        ar_name_len = strtoul(str.c_str() + 3, &err, 10);
+    }
+    else
+    {
+        // Strip off any spaces (if the object file name contains spaces it
+        // will use the extended format above).
+        str.erase (str.find(' '));
+        ar_name.SetCString(str.c_str());
+    }
+
+    str.assign ((const char *)data.GetData(&offset, 12),    12);
+    ar_date = strtoul(str.c_str(), &err, 10);
+
+    str.assign ((const char *)data.GetData(&offset, 6), 6);
+    ar_uid  = strtoul(str.c_str(), &err, 10);
+
+    str.assign ((const char *)data.GetData(&offset, 6), 6);
+    ar_gid  = strtoul(str.c_str(), &err, 10);
+
+    str.assign ((const char *)data.GetData(&offset, 8), 8);
+    ar_mode = strtoul(str.c_str(), &err, 8);
+
+    str.assign ((const char *)data.GetData(&offset, 10),    10);
+    ar_size = strtoul(str.c_str(), &err, 10);
+
+    str.assign ((const char *)data.GetData(&offset, 2), 2);
+    if (str == ARFMAG)
+    {
+        if (ar_name_len > 0)
+        {
+            str.assign ((const char *)data.GetData(&offset, ar_name_len), ar_name_len);
+            ar_name.SetCString (str.c_str());
+        }
+        ar_file_offset = offset;
+        ar_file_size = ar_size - ar_name_len;
+        return offset;
+    }
+    return LLDB_INVALID_INDEX32;
+}
+
+ObjectContainerBSDArchive::Archive::Archive
+(
+    const lldb_private::ArchSpec &arch,
+    const lldb_private::TimeValue &time
+) :
+    m_arch (arch),
+    m_time (time),
+    m_objects()
+{
+}
+
+ObjectContainerBSDArchive::Archive::~Archive ()
+{
+}
+
+size_t
+ObjectContainerBSDArchive::Archive::ParseObjects (DataExtractor &data)
+{
+    std::string str;
+    uint32_t offset = 0;
+    str.assign((const char *)data.GetData(&offset, SARMAG), SARMAG);
+    if (str == ARMAG)
+    {
+        Object obj;
+        do
+        {
+            offset = obj.Extract (data, offset);
+            if (offset == LLDB_INVALID_INDEX32)
+                break;
+            uint32_t obj_idx = m_objects.size();
+            m_objects.push_back(obj);
+            // Insert all of the C strings out of order for now...
+            m_object_name_to_index_map.Append (obj.ar_name.GetCString(), obj_idx);
+            offset += obj.ar_file_size;
+            obj.Clear();
+        } while (data.ValidOffset(offset));
+
+        // Now sort all of the object name pointers
+        m_object_name_to_index_map.Sort ();
+    }
+    return m_objects.size();
+}
+
+ObjectContainerBSDArchive::Object *
+ObjectContainerBSDArchive::Archive::FindObject (const ConstString &object_name)
+{
+    const UniqueCStringMap<uint32_t>::Entry *match = m_object_name_to_index_map.FindFirstValueForName (object_name.GetCString());
+    if (match)
+        return &m_objects[match->value];
+    return NULL;
+}
+
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::FindCachedArchive (const FileSpec &file, const ArchSpec &arch, const TimeValue &time)
+{
+    Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
+    shared_ptr archive_sp;
+    Archive::Map &archive_map = Archive::GetArchiveCache ();
+    Archive::Map::iterator pos;
+    for (pos = archive_map.find (file); pos != archive_map.end() && pos->first == file; ++pos)
+    {
+        if (pos->second->GetArchitecture() == arch &&
+            pos->second->GetModificationTime() == time)
+        {
+            archive_sp = pos->second;
+        }
+    }
+    return archive_sp;
+}
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile
+(
+    const FileSpec &file,
+    const ArchSpec &arch,
+    const TimeValue &time,
+    DataExtractor &data
+)
+{
+    shared_ptr archive_sp(new Archive (arch, time));
+    if (archive_sp)
+    {
+        if (archive_sp->ParseObjects (data) > 0)
+        {
+            Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
+            Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp));
+        }
+        else
+        {
+            archive_sp.reset();
+        }
+    }
+    return archive_sp;
+}
+
+ObjectContainerBSDArchive::Archive::Map &
+ObjectContainerBSDArchive::Archive::GetArchiveCache ()
+{
+    static Archive::Map g_archive_map;
+    return g_archive_map;
+}
+
+Mutex &
+ObjectContainerBSDArchive::Archive::GetArchiveCacheMutex ()
+{
+    static Mutex g_archive_map_mutex (Mutex::eMutexTypeRecursive);
+    return g_archive_map_mutex;
+}
+
+
+void
+ObjectContainerBSDArchive::Initialize()
+{
+    PluginManager::RegisterPlugin (GetPluginNameStatic(),
+                                   GetPluginDescriptionStatic(),
+                                   CreateInstance);
+}
+
+void
+ObjectContainerBSDArchive::Terminate()
+{
+    PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+ObjectContainerBSDArchive::GetPluginNameStatic()
+{
+    return "object-container.bsd-archive";
+}
+
+const char *
+ObjectContainerBSDArchive::GetPluginDescriptionStatic()
+{
+    return "BSD Archive object container reader.";
+}
+
+
+ObjectContainer *
+ObjectContainerBSDArchive::CreateInstance
+(
+    Module* module,
+    DataBufferSP& dataSP,
+    const FileSpec *file,
+    addr_t offset,
+    addr_t length)
+{
+    if (file)
+    {
+        std::string object;
+
+        Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file, module->GetArchitecture(), module->GetModificationTime()));
+
+        if (archive_sp)
+        {
+            // We already have this archive in our cache, use it
+            std::auto_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module, dataSP, file, offset, length));
+            if (container_ap.get())
+            {
+                container_ap->SetArchive (archive_sp);
+                return container_ap.release();
+            }
+        }
+
+        if (dataSP)
+        {
+            if (ObjectContainerBSDArchive::MagicBytesMatch(dataSP))
+            {
+                // Read everything since we need that in order to index all the
+                // objects in the archive
+                dataSP = file->ReadFileContents(offset, length);
+
+                std::auto_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module, dataSP, file, offset, length));
+                if (container_ap->ParseHeader())
+                    return container_ap.release();
+            }
+        }
+    }
+    return NULL;
+}
+
+
+
+bool
+ObjectContainerBSDArchive::MagicBytesMatch (DataBufferSP& dataSP)
+{
+    DataExtractor data(dataSP, eByteOrderHost, 4);
+    uint32_t offset = 0;
+    const char* armag = (const char* )data.PeekData (offset, sizeof(ar_hdr));
+    if (armag && ::strncmp(armag, ARMAG, SARMAG) == 0)
+    {
+        armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG;
+        if (strncmp(armag, ARFMAG, 2) == 0)
+            return true;
+    }
+    return false;
+}
+
+ObjectContainerBSDArchive::ObjectContainerBSDArchive
+(
+    Module* module,
+    DataBufferSP& dataSP,
+    const lldb_private::FileSpec *file,
+    lldb::addr_t offset,
+    lldb::addr_t size
+) :
+    ObjectContainer (module, file, offset, size, dataSP),
+    m_archive_sp ()
+{
+}
+void
+ObjectContainerBSDArchive::SetArchive (Archive::shared_ptr &archive_sp)
+{
+    m_archive_sp  = archive_sp;
+}
+
+
+
+ObjectContainerBSDArchive::~ObjectContainerBSDArchive()
+{
+}
+
+bool
+ObjectContainerBSDArchive::ParseHeader ()
+{
+    if (m_archive_sp.get() == NULL)
+    {
+        if (m_data.GetByteSize() > 0)
+        {
+            m_archive_sp = Archive::ParseAndCacheArchiveForFile (m_file,
+                                                                 m_module->GetArchitecture(),
+                                                                 m_module->GetModificationTime(),
+                                                                 m_data);
+            // The archive might be huge, so clear "m_data" to free up the
+            // memory since it will contain the entire file (possibly more than
+            // one architecture slice). We already have an index of all objects
+            // in the file, so we will be ready to serve up those objects.
+            m_data.Clear();
+        }
+    }
+    return m_archive_sp.get() != NULL;
+}
+
+void
+ObjectContainerBSDArchive::Dump (Stream *s) const
+{
+    s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+    s->Indent();
+    const size_t num_archs = GetNumArchitectures();
+    const size_t num_objects = GetNumObjects();
+    s->Printf("ObjectContainerBSDArchive, num_archs = %u, num_objects = %u", 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", arch.AsCString());
+    }
+    for (i=0; i<num_objects; i++)
+    {
+        s->Indent();
+        s->Printf("object[%u] = %s\n", GetObjectNameAtIndex (i));
+    }
+    s->IndentLess();
+    s->EOL();
+}
+
+ObjectFile *
+ObjectContainerBSDArchive::GetObjectFile (const FileSpec *file)
+{
+    if (m_module->GetObjectName() && m_archive_sp)
+    {
+        Object *object = m_archive_sp->FindObject (m_module->GetObjectName());
+        if (object)
+            return ObjectFile::FindPlugin (m_module, file, m_offset + object->ar_file_offset, object->ar_file_size);
+    }
+    return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectContainerBSDArchive::GetPluginName()
+{
+    return "object-container.bsd-archive";
+}
+
+const char *
+ObjectContainerBSDArchive::GetShortPluginName()
+{
+    return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectContainerBSDArchive::GetPluginVersion()
+{
+    return 1;
+}
+
+void
+ObjectContainerBSDArchive::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectContainerBSDArchive::ExecutePluginCommand (Args &command, Stream *strm)
+{
+    Error error;
+    error.SetErrorString("No plug-in command are currently supported.");
+    return error;
+}
+
+Log *
+ObjectContainerBSDArchive::EnablePluginLogging (Stream *strm, Args &command)
+{
+    return NULL;
+}
+
+
+
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
new file mode 100644
index 0000000..88aba01
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
@@ -0,0 +1,183 @@
+//===-- ObjectContainerBSDArchive.h -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ObjectContainerBSDArchive_h_
+#define liblldb_ObjectContainerBSDArchive_h_
+
+#include "lldb/Symbol/ObjectContainer.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/FileSpec.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Host/TimeValue.h"
+
+class ObjectContainerBSDArchive :
+    public lldb_private::ObjectContainer
+{
+public:
+
+    //------------------------------------------------------------------
+    // Static Functions
+    //------------------------------------------------------------------
+    static void
+    Initialize();
+
+    static void
+    Terminate();
+
+    static const char *
+    GetPluginNameStatic();
+
+    static const char *
+    GetPluginDescriptionStatic();
+
+    static lldb_private::ObjectContainer *
+    CreateInstance (lldb_private::Module* module,
+                    lldb::DataBufferSP& dataSP,
+                    const lldb_private::FileSpec *file,
+                    lldb::addr_t offset,
+                    lldb::addr_t length);
+
+    static bool
+    MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+    //------------------------------------------------------------------
+    // Member Functions
+    //------------------------------------------------------------------
+    ObjectContainerBSDArchive (lldb_private::Module* module,
+                               lldb::DataBufferSP& dataSP,
+                               const lldb_private::FileSpec *file,
+                               lldb::addr_t offset,
+                               lldb::addr_t length);
+
+    virtual
+    ~ObjectContainerBSDArchive();
+
+    virtual bool
+    ParseHeader ();
+
+    virtual void
+    Dump (lldb_private::Stream *s) const;
+
+    virtual lldb_private::ObjectFile *
+    GetObjectFile (const lldb_private::FileSpec *file);
+
+    //------------------------------------------------------------------
+    // PluginInterface protocol
+    //------------------------------------------------------------------
+    virtual const char *
+    GetPluginName();
+
+    virtual const char *
+    GetShortPluginName();
+
+    virtual uint32_t
+    GetPluginVersion();
+
+    virtual void
+    GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+    virtual lldb_private::Error
+    ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+    virtual lldb_private::Log *
+    EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+
+protected:
+
+    struct Object
+    {
+        Object();
+
+        void
+        Clear();
+
+        uint32_t
+        Extract (const lldb_private::DataExtractor& data, uint32_t offset);
+
+        lldb_private::ConstString       ar_name;        // name
+        uint32_t        ar_date;        // modification time
+        uint16_t        ar_uid;         // user id
+        uint16_t        ar_gid;         // group id
+        uint16_t        ar_mode;        // octal file permissions
+        uint32_t        ar_size;        // size in bytes
+        uint32_t        ar_file_offset; // file offset in bytes from the beginning of the file of the object data
+        uint32_t        ar_file_size;   // length of the object data
+
+        typedef std::vector<Object>         collection;
+        typedef collection::iterator        iterator;
+        typedef collection::const_iterator  const_iterator;
+    };
+
+    class Archive
+    {
+    public:
+        typedef lldb::SharedPtr<Archive>::Type shared_ptr;
+        typedef std::multimap<lldb_private::FileSpec, shared_ptr> Map;
+
+        static Map &
+        GetArchiveCache ();
+
+        static lldb_private::Mutex &
+        GetArchiveCacheMutex ();
+
+        static Archive::shared_ptr
+        FindCachedArchive (const lldb_private::FileSpec &file,
+                           const lldb_private::ArchSpec &arch,
+                           const lldb_private::TimeValue &mod_time);
+
+        static Archive::shared_ptr
+        ParseAndCacheArchiveForFile (const lldb_private::FileSpec &file,
+                                     const lldb_private::ArchSpec &arch,
+                                     const lldb_private::TimeValue &mod_time,
+                                     lldb_private::DataExtractor &data);
+
+        Archive (const lldb_private::ArchSpec &arch,
+                 const lldb_private::TimeValue &mod_time);
+
+        ~Archive ();
+
+        size_t
+        ParseObjects (lldb_private::DataExtractor &data);
+
+        Object *
+        FindObject (const lldb_private::ConstString &object_name);
+
+        const lldb_private::TimeValue &
+        GetModificationTime()
+        {
+            return m_time;
+        }
+
+        const lldb_private::ArchSpec &
+        GetArchitecture ()
+        {
+            return m_arch;
+        }
+
+    protected:
+
+        //----------------------------------------------------------------------
+        // Member Variables
+        //----------------------------------------------------------------------
+        lldb_private::ArchSpec m_arch;
+        lldb_private::TimeValue m_time;
+        Object::collection  m_objects;
+        lldb_private::UniqueCStringMap<uint32_t> m_object_name_to_index_map;
+    };
+
+    void
+    SetArchive (Archive::shared_ptr &archive_sp);
+
+    Archive::shared_ptr m_archive_sp;
+};
+
+#endif  // liblldb_ObjectContainerBSDArchive_h_
diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
new file mode 100644
index 0000000..015e498
--- /dev/null
+++ b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
@@ -0,0 +1,259 @@
+//===-- 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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+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
+(
+    Module* module,
+    DataBufferSP& dataSP,
+    const FileSpec *file,
+    addr_t offset,
+    addr_t length
+)
+{
+    if (ObjectContainerUniversalMachO::MagicBytesMatch(dataSP))
+    {
+        std::auto_ptr<ObjectContainerUniversalMachO> container_ap(new ObjectContainerUniversalMachO (module, dataSP, file, offset, length));
+        if (container_ap->ParseHeader())
+        {
+            return container_ap.release();
+        }
+    }
+    return NULL;
+}
+
+
+
+bool
+ObjectContainerUniversalMachO::MagicBytesMatch (DataBufferSP& dataSP)
+{
+    DataExtractor data(dataSP, eByteOrderHost, 4);
+    uint32_t offset = 0;
+    uint32_t magic = data.GetU32(&offset);
+    return magic == FAT_MAGIC || magic == FAT_CIGAM;
+}
+
+ObjectContainerUniversalMachO::ObjectContainerUniversalMachO
+(
+    Module* module,
+    DataBufferSP& dataSP,
+    const FileSpec *file,
+    addr_t offset,
+    addr_t length
+) :
+    ObjectContainer (module, 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 == FAT_MAGIC)
+    {
+        m_data.SetAddressByteSize(4);
+
+        m_header.nfat_arch = m_data.GetU32(&offset);
+
+        const size_t nfat_arch_size = sizeof(fat_arch_t) * m_header.nfat_arch;
+        // See if the current data we have is enough for all of the fat headers?
+        if (!m_data.ValidOffsetForDataOfSize(offset, nfat_arch_size))
+        {
+            // The fat headers are larger than the number of bytes we have been
+            // given when this class was constructed. We will read the exact number
+            // of bytes that we need.
+            DataBufferSP data_sp(m_file.ReadFileContents(m_offset, nfat_arch_size + sizeof(fat_header_t)));
+            m_data.SetData (data_sp);
+        }
+
+        // Now we should have enough data for all of the fat headers, so lets index
+        // them so we know how many architectures that this univeral 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_t)))
+            {
+                fat_arch_t arch;
+                if (m_data.GetU32(&offset, &arch, sizeof(fat_arch_t)/sizeof(uint32_t)))
+                {
+                    m_fat_archs.push_back(arch);
+                }
+            }
+        }
+        // Now that we have indexed the universal headers, we no longer need any cached data.
+        m_data.Clear();
+
+        return true;
+    }
+    else
+    {
+        memset(&m_header, 0, sizeof(m_header));
+    }
+
+    return false;
+}
+
+void
+ObjectContainerUniversalMachO::Dump (Stream *s) const
+{
+    s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+    s->Indent();
+    const size_t num_archs = GetNumArchitectures();
+    const size_t num_objects = GetNumObjects();
+    s->Printf("ObjectContainerUniversalMachO, num_archs = %u, num_objects = %u", 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", arch.AsCString());
+    }
+    for (i=0; i<num_objects; i++)
+    {
+        s->Indent();
+        s->Printf("object[%u] = %s\n", 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.SetArch(m_fat_archs[idx].cputype, m_fat_archs[idx].cpusubtype);
+        return true;
+    }
+    return false;
+}
+
+ObjectFile *
+ObjectContainerUniversalMachO::GetObjectFile (const FileSpec *file)
+{
+    uint32_t arch_idx = 0;
+    const ArchSpec arch = m_module->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 (m_module, file, m_offset + m_fat_archs[arch_idx].offset, m_fat_archs[arch_idx].size);
+            }
+        }
+    }
+    return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ObjectContainerUniversalMachO::GetPluginName()
+{
+    return "ObjectContainerUniversalMachO";
+}
+
+const char *
+ObjectContainerUniversalMachO::GetShortPluginName()
+{
+    return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectContainerUniversalMachO::GetPluginVersion()
+{
+    return 1;
+}
+
+void
+ObjectContainerUniversalMachO::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ObjectContainerUniversalMachO::ExecutePluginCommand (Args &command, Stream *strm)
+{
+    Error error;
+    error.SetErrorString("No plug-in command are currently supported.");
+    return error;
+}
+
+Log *
+ObjectContainerUniversalMachO::EnablePluginLogging (Stream *strm, Args &command)
+{
+    return NULL;
+}
+
+
+
diff --git a/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
new file mode 100644
index 0000000..8a7f975
--- /dev/null
+++ b/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
@@ -0,0 +1,103 @@
+//===-- ObjectContainerUniversalMachO.h -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ObjectContainerUniversalMachO_h_
+#define liblldb_ObjectContainerUniversalMachO_h_
+
+#include <mach-o/fat.h>
+
+#include "lldb/Symbol/ObjectContainer.h"
+#include "lldb/Core/FileSpec.h"
+
+class ObjectContainerUniversalMachO :
+    public lldb_private::ObjectContainer
+{
+public:
+    //------------------------------------------------------------------
+    // Static Functions
+    //------------------------------------------------------------------
+    static void
+    Initialize();
+
+    static void
+    Terminate();
+
+    static const char *
+    GetPluginNameStatic();
+
+    static const char *
+    GetPluginDescriptionStatic();
+
+    static lldb_private::ObjectContainer *
+    CreateInstance (lldb_private::Module* module,
+                    lldb::DataBufferSP& dataSP,
+                    const lldb_private::FileSpec *file,
+                    lldb::addr_t offset,
+                    lldb::addr_t length);
+
+    static bool
+    MagicBytesMatch (lldb::DataBufferSP& dataSP);
+
+    //------------------------------------------------------------------
+    // Member Functions
+    //------------------------------------------------------------------
+    ObjectContainerUniversalMachO (lldb_private::Module* module,
+                                   lldb::DataBufferSP& dataSP,
+                                   const lldb_private::FileSpec *file,
+                                   lldb::addr_t offset,
+                                   lldb::addr_t length);
+
+    virtual
+    ~ObjectContainerUniversalMachO();
+
+    virtual bool
+    ParseHeader ();
+
+    virtual void
+    Dump (lldb_private::Stream *s) const;
+
+    virtual size_t
+    GetNumArchitectures () const;
+
+    virtual bool
+    GetArchitectureAtIndex (uint32_t cpu_idx, lldb_private::ArchSpec& arch) const;
+
+    virtual lldb_private::ObjectFile *
+    GetObjectFile (const lldb_private::FileSpec *file);
+
+    //------------------------------------------------------------------
+    // PluginInterface protocol
+    //------------------------------------------------------------------
+    virtual const char *
+    GetPluginName();
+
+    virtual const char *
+    GetShortPluginName();
+
+    virtual uint32_t
+    GetPluginVersion();
+
+    virtual void
+    GetPluginCommandHelp (const char *command, lldb_private::Stream *strm);
+
+    virtual lldb_private::Error
+    ExecutePluginCommand (lldb_private::Args &command, lldb_private::Stream *strm);
+
+    virtual lldb_private::Log *
+    EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
+
+
+protected:
+    typedef struct fat_header fat_header_t;
+    typedef struct fat_arch fat_arch_t;
+    fat_header_t m_header;
+    std::vector<fat_arch_t> m_fat_archs;
+};
+
+#endif  // liblldb_ObjectContainerUniversalMachO_h_