//===-- 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 #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::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 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 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; iIndent(); GetArchitectureAtIndex(i, arch); s->Printf("arch[%u] = %s\n", arch.GetArchitectureName()); } for (i=0; iIndent(); 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; }