blob: 7ff54c7ed8e1abb6c1872ad99915fdaf5b536af8 [file] [log] [blame]
//===-- 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("#1/") == 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, lldb::endian::InlHostByteOrder(), 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.GetArchitectureName());
}
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;
}