15ffd83dbSDimitry Andric //===-- ObjectContainerBSDArchive.cpp -------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "ObjectContainerBSDArchive.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #if defined(_WIN32) || defined(__ANDROID__)
120b57cec5SDimitry Andric // Defines from ar, missing on Windows
130b57cec5SDimitry Andric #define SARMAG 8
140b57cec5SDimitry Andric #define ARFMAG "`\n"
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric typedef struct ar_hdr {
170b57cec5SDimitry Andric char ar_name[16];
180b57cec5SDimitry Andric char ar_date[12];
190b57cec5SDimitry Andric char ar_uid[6], ar_gid[6];
200b57cec5SDimitry Andric char ar_mode[8];
210b57cec5SDimitry Andric char ar_size[10];
220b57cec5SDimitry Andric char ar_fmag[2];
230b57cec5SDimitry Andric } ar_hdr;
240b57cec5SDimitry Andric #else
250b57cec5SDimitry Andric #include <ar.h>
260b57cec5SDimitry Andric #endif
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric #include "lldb/Core/Module.h"
290b57cec5SDimitry Andric #include "lldb/Core/ModuleSpec.h"
300b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h"
310b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
320b57cec5SDimitry Andric #include "lldb/Symbol/ObjectFile.h"
330b57cec5SDimitry Andric #include "lldb/Utility/ArchSpec.h"
34*5f757f3fSDimitry Andric #include "lldb/Utility/LLDBLog.h"
350b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
360b57cec5SDimitry Andric #include "lldb/Utility/Timer.h"
370b57cec5SDimitry Andric
38*5f757f3fSDimitry Andric #include "llvm/Object/Archive.h"
390b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric using namespace lldb;
420b57cec5SDimitry Andric using namespace lldb_private;
430b57cec5SDimitry Andric
44753f127fSDimitry Andric using namespace llvm::object;
45753f127fSDimitry Andric
LLDB_PLUGIN_DEFINE(ObjectContainerBSDArchive)465ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(ObjectContainerBSDArchive)
475ffd83dbSDimitry Andric
48fe6060f1SDimitry Andric ObjectContainerBSDArchive::Object::Object() : ar_name() {}
490b57cec5SDimitry Andric
Clear()500b57cec5SDimitry Andric void ObjectContainerBSDArchive::Object::Clear() {
510b57cec5SDimitry Andric ar_name.Clear();
520b57cec5SDimitry Andric modification_time = 0;
530b57cec5SDimitry Andric size = 0;
540b57cec5SDimitry Andric file_offset = 0;
550b57cec5SDimitry Andric file_size = 0;
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric
Dump() const58*5f757f3fSDimitry Andric void ObjectContainerBSDArchive::Object::Dump() const {
59*5f757f3fSDimitry Andric printf("name = \"%s\"\n", ar_name.GetCString());
60*5f757f3fSDimitry Andric printf("mtime = 0x%8.8" PRIx32 "\n", modification_time);
61*5f757f3fSDimitry Andric printf("size = 0x%8.8" PRIx32 " (%" PRIu32 ")\n", size, size);
62*5f757f3fSDimitry Andric printf("file_offset = 0x%16.16" PRIx64 " (%" PRIu64 ")\n", file_offset,
63*5f757f3fSDimitry Andric file_offset);
64*5f757f3fSDimitry Andric printf("file_size = 0x%16.16" PRIx64 " (%" PRIu64 ")\n\n", file_size,
65*5f757f3fSDimitry Andric file_size);
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric
Archive(const lldb_private::ArchSpec & arch,const llvm::sys::TimePoint<> & time,lldb::offset_t file_offset,lldb_private::DataExtractor & data,ArchiveType archive_type)680b57cec5SDimitry Andric ObjectContainerBSDArchive::Archive::Archive(const lldb_private::ArchSpec &arch,
690b57cec5SDimitry Andric const llvm::sys::TimePoint<> &time,
700b57cec5SDimitry Andric lldb::offset_t file_offset,
71753f127fSDimitry Andric lldb_private::DataExtractor &data,
72753f127fSDimitry Andric ArchiveType archive_type)
730b57cec5SDimitry Andric : m_arch(arch), m_modification_time(time), m_file_offset(file_offset),
74753f127fSDimitry Andric m_objects(), m_data(data), m_archive_type(archive_type) {}
750b57cec5SDimitry Andric
76*5f757f3fSDimitry Andric Log *l = GetLog(LLDBLog::Object);
77fe6060f1SDimitry Andric ObjectContainerBSDArchive::Archive::~Archive() = default;
780b57cec5SDimitry Andric
ParseObjects()790b57cec5SDimitry Andric size_t ObjectContainerBSDArchive::Archive::ParseObjects() {
800b57cec5SDimitry Andric DataExtractor &data = m_data;
810b57cec5SDimitry Andric
82*5f757f3fSDimitry Andric std::unique_ptr<llvm::MemoryBuffer> mem_buffer =
83*5f757f3fSDimitry Andric llvm::MemoryBuffer::getMemBuffer(
84*5f757f3fSDimitry Andric llvm::StringRef((const char *)data.GetDataStart(),
85*5f757f3fSDimitry Andric data.GetByteSize()),
86*5f757f3fSDimitry Andric llvm::StringRef(),
87*5f757f3fSDimitry Andric /*RequiresNullTerminator=*/false);
88753f127fSDimitry Andric
89*5f757f3fSDimitry Andric auto exp_ar = llvm::object::Archive::create(mem_buffer->getMemBufferRef());
90*5f757f3fSDimitry Andric if (!exp_ar) {
91*5f757f3fSDimitry Andric LLDB_LOG_ERROR(l, exp_ar.takeError(), "failed to create archive: {0}");
92*5f757f3fSDimitry Andric return 0;
930b57cec5SDimitry Andric }
94*5f757f3fSDimitry Andric auto llvm_archive = std::move(exp_ar.get());
95*5f757f3fSDimitry Andric
96*5f757f3fSDimitry Andric llvm::Error iter_err = llvm::Error::success();
97*5f757f3fSDimitry Andric Object obj;
98*5f757f3fSDimitry Andric for (const auto &child: llvm_archive->children(iter_err)) {
99*5f757f3fSDimitry Andric obj.Clear();
100*5f757f3fSDimitry Andric auto exp_name = child.getName();
101*5f757f3fSDimitry Andric if (exp_name) {
102*5f757f3fSDimitry Andric obj.ar_name = ConstString(exp_name.get());
103*5f757f3fSDimitry Andric } else {
104*5f757f3fSDimitry Andric LLDB_LOG_ERROR(l, exp_name.takeError(),
105*5f757f3fSDimitry Andric "failed to get archive object name: {0}");
106*5f757f3fSDimitry Andric continue;
107*5f757f3fSDimitry Andric }
108*5f757f3fSDimitry Andric
109*5f757f3fSDimitry Andric auto exp_mtime = child.getLastModified();
110*5f757f3fSDimitry Andric if (exp_mtime) {
111*5f757f3fSDimitry Andric obj.modification_time =
112*5f757f3fSDimitry Andric std::chrono::duration_cast<std::chrono::seconds>(
113*5f757f3fSDimitry Andric std::chrono::time_point_cast<std::chrono::seconds>(
114*5f757f3fSDimitry Andric exp_mtime.get()).time_since_epoch()).count();
115*5f757f3fSDimitry Andric } else {
116*5f757f3fSDimitry Andric LLDB_LOG_ERROR(l, exp_mtime.takeError(),
117*5f757f3fSDimitry Andric "failed to get archive object time: {0}");
118*5f757f3fSDimitry Andric continue;
119*5f757f3fSDimitry Andric }
120*5f757f3fSDimitry Andric
121*5f757f3fSDimitry Andric auto exp_size = child.getRawSize();
122*5f757f3fSDimitry Andric if (exp_size) {
123*5f757f3fSDimitry Andric obj.size = exp_size.get();
124*5f757f3fSDimitry Andric } else {
125*5f757f3fSDimitry Andric LLDB_LOG_ERROR(l, exp_size.takeError(),
126*5f757f3fSDimitry Andric "failed to get archive object size: {0}");
127*5f757f3fSDimitry Andric continue;
128*5f757f3fSDimitry Andric }
129*5f757f3fSDimitry Andric
130*5f757f3fSDimitry Andric obj.file_offset = child.getDataOffset();
131*5f757f3fSDimitry Andric
132*5f757f3fSDimitry Andric auto exp_file_size = child.getSize();
133*5f757f3fSDimitry Andric if (exp_file_size) {
134*5f757f3fSDimitry Andric obj.file_size = exp_file_size.get();
135*5f757f3fSDimitry Andric } else {
136*5f757f3fSDimitry Andric LLDB_LOG_ERROR(l, exp_file_size.takeError(),
137*5f757f3fSDimitry Andric "failed to get archive object file size: {0}");
138*5f757f3fSDimitry Andric continue;
139*5f757f3fSDimitry Andric }
140*5f757f3fSDimitry Andric m_object_name_to_index_map.Append(obj.ar_name, m_objects.size());
141*5f757f3fSDimitry Andric m_objects.push_back(obj);
142*5f757f3fSDimitry Andric }
143*5f757f3fSDimitry Andric if (iter_err) {
144*5f757f3fSDimitry Andric LLDB_LOG_ERROR(l, std::move(iter_err),
145*5f757f3fSDimitry Andric "failed to iterate over archive objects: {0}");
146*5f757f3fSDimitry Andric }
147*5f757f3fSDimitry Andric // Now sort all of the object name pointers
148*5f757f3fSDimitry Andric m_object_name_to_index_map.Sort();
1490b57cec5SDimitry Andric return m_objects.size();
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric
1520b57cec5SDimitry Andric ObjectContainerBSDArchive::Object *
FindObject(ConstString object_name,const llvm::sys::TimePoint<> & object_mod_time)1530b57cec5SDimitry Andric ObjectContainerBSDArchive::Archive::FindObject(
1540b57cec5SDimitry Andric ConstString object_name, const llvm::sys::TimePoint<> &object_mod_time) {
1550b57cec5SDimitry Andric const ObjectNameToIndexMap::Entry *match =
1560b57cec5SDimitry Andric m_object_name_to_index_map.FindFirstValueForName(object_name);
1570b57cec5SDimitry Andric if (!match)
1580b57cec5SDimitry Andric return nullptr;
1590b57cec5SDimitry Andric if (object_mod_time == llvm::sys::TimePoint<>())
1600b57cec5SDimitry Andric return &m_objects[match->value];
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric const uint64_t object_modification_date = llvm::sys::toTimeT(object_mod_time);
1630b57cec5SDimitry Andric if (m_objects[match->value].modification_time == object_modification_date)
1640b57cec5SDimitry Andric return &m_objects[match->value];
1650b57cec5SDimitry Andric
1660b57cec5SDimitry Andric const ObjectNameToIndexMap::Entry *next_match =
1670b57cec5SDimitry Andric m_object_name_to_index_map.FindNextValueForName(match);
1680b57cec5SDimitry Andric while (next_match) {
1690b57cec5SDimitry Andric if (m_objects[next_match->value].modification_time ==
1700b57cec5SDimitry Andric object_modification_date)
1710b57cec5SDimitry Andric return &m_objects[next_match->value];
1720b57cec5SDimitry Andric next_match = m_object_name_to_index_map.FindNextValueForName(next_match);
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric return nullptr;
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric ObjectContainerBSDArchive::Archive::shared_ptr
FindCachedArchive(const FileSpec & file,const ArchSpec & arch,const llvm::sys::TimePoint<> & time,lldb::offset_t file_offset)1790b57cec5SDimitry Andric ObjectContainerBSDArchive::Archive::FindCachedArchive(
1800b57cec5SDimitry Andric const FileSpec &file, const ArchSpec &arch,
1810b57cec5SDimitry Andric const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset) {
1820b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> guard(Archive::GetArchiveCacheMutex());
1830b57cec5SDimitry Andric shared_ptr archive_sp;
1840b57cec5SDimitry Andric Archive::Map &archive_map = Archive::GetArchiveCache();
1850b57cec5SDimitry Andric Archive::Map::iterator pos = archive_map.find(file);
1860b57cec5SDimitry Andric // Don't cache a value for "archive_map.end()" below since we might delete an
1870b57cec5SDimitry Andric // archive entry...
1880b57cec5SDimitry Andric while (pos != archive_map.end() && pos->first == file) {
1890b57cec5SDimitry Andric bool match = true;
1900b57cec5SDimitry Andric if (arch.IsValid() &&
1910b57cec5SDimitry Andric !pos->second->GetArchitecture().IsCompatibleMatch(arch))
1920b57cec5SDimitry Andric match = false;
1930b57cec5SDimitry Andric else if (file_offset != LLDB_INVALID_OFFSET &&
1940b57cec5SDimitry Andric pos->second->GetFileOffset() != file_offset)
1950b57cec5SDimitry Andric match = false;
1960b57cec5SDimitry Andric if (match) {
1970b57cec5SDimitry Andric if (pos->second->GetModificationTime() == time) {
1980b57cec5SDimitry Andric return pos->second;
1990b57cec5SDimitry Andric } else {
2000b57cec5SDimitry Andric // We have a file at the same path with the same architecture whose
2010b57cec5SDimitry Andric // modification time doesn't match. It doesn't make sense for us to
2020b57cec5SDimitry Andric // continue to use this BSD archive since we cache only the object info
2030b57cec5SDimitry Andric // which consists of file time info and also the file offset and file
2040b57cec5SDimitry Andric // size of any contained objects. Since this information is now out of
2050b57cec5SDimitry Andric // date, we won't get the correct information if we go and extract the
2060b57cec5SDimitry Andric // file data, so we should remove the old and outdated entry.
2070b57cec5SDimitry Andric archive_map.erase(pos);
2080b57cec5SDimitry Andric pos = archive_map.find(file);
2090b57cec5SDimitry Andric continue; // Continue to next iteration so we don't increment pos
2100b57cec5SDimitry Andric // below...
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric ++pos;
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric return archive_sp;
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric ObjectContainerBSDArchive::Archive::shared_ptr
ParseAndCacheArchiveForFile(const FileSpec & file,const ArchSpec & arch,const llvm::sys::TimePoint<> & time,lldb::offset_t file_offset,DataExtractor & data,ArchiveType archive_type)2190b57cec5SDimitry Andric ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile(
2200b57cec5SDimitry Andric const FileSpec &file, const ArchSpec &arch,
2210b57cec5SDimitry Andric const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset,
222753f127fSDimitry Andric DataExtractor &data, ArchiveType archive_type) {
223753f127fSDimitry Andric shared_ptr archive_sp(
224753f127fSDimitry Andric new Archive(arch, time, file_offset, data, archive_type));
2250b57cec5SDimitry Andric if (archive_sp) {
2260b57cec5SDimitry Andric const size_t num_objects = archive_sp->ParseObjects();
2270b57cec5SDimitry Andric if (num_objects > 0) {
2280b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> guard(
2290b57cec5SDimitry Andric Archive::GetArchiveCacheMutex());
2300b57cec5SDimitry Andric Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp));
2310b57cec5SDimitry Andric } else {
2320b57cec5SDimitry Andric archive_sp.reset();
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric return archive_sp;
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric ObjectContainerBSDArchive::Archive::Map &
GetArchiveCache()2390b57cec5SDimitry Andric ObjectContainerBSDArchive::Archive::GetArchiveCache() {
2400b57cec5SDimitry Andric static Archive::Map g_archive_map;
2410b57cec5SDimitry Andric return g_archive_map;
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric
2440b57cec5SDimitry Andric std::recursive_mutex &
GetArchiveCacheMutex()2450b57cec5SDimitry Andric ObjectContainerBSDArchive::Archive::GetArchiveCacheMutex() {
2460b57cec5SDimitry Andric static std::recursive_mutex g_archive_map_mutex;
2470b57cec5SDimitry Andric return g_archive_map_mutex;
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric
Initialize()2500b57cec5SDimitry Andric void ObjectContainerBSDArchive::Initialize() {
2510b57cec5SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(),
2520b57cec5SDimitry Andric GetPluginDescriptionStatic(), CreateInstance,
2530b57cec5SDimitry Andric GetModuleSpecifications);
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric
Terminate()2560b57cec5SDimitry Andric void ObjectContainerBSDArchive::Terminate() {
2570b57cec5SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric
CreateInstance(const lldb::ModuleSP & module_sp,DataBufferSP & data_sp,lldb::offset_t data_offset,const FileSpec * file,lldb::offset_t file_offset,lldb::offset_t length)2600b57cec5SDimitry Andric ObjectContainer *ObjectContainerBSDArchive::CreateInstance(
2610b57cec5SDimitry Andric const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
2620b57cec5SDimitry Andric lldb::offset_t data_offset, const FileSpec *file,
2630b57cec5SDimitry Andric lldb::offset_t file_offset, lldb::offset_t length) {
2640b57cec5SDimitry Andric ConstString object_name(module_sp->GetObjectName());
2650b57cec5SDimitry Andric if (!object_name)
2660b57cec5SDimitry Andric return nullptr;
2670b57cec5SDimitry Andric
2680b57cec5SDimitry Andric if (data_sp) {
2690b57cec5SDimitry Andric // We have data, which means this is the first 512 bytes of the file Check
2700b57cec5SDimitry Andric // to see if the magic bytes match and if they do, read the entire table of
2710b57cec5SDimitry Andric // contents for the archive and cache it
2720b57cec5SDimitry Andric DataExtractor data;
2730b57cec5SDimitry Andric data.SetData(data_sp, data_offset, length);
274753f127fSDimitry Andric ArchiveType archive_type = ObjectContainerBSDArchive::MagicBytesMatch(data);
275753f127fSDimitry Andric if (file && data_sp && archive_type != ArchiveType::Invalid) {
276e8d8bef9SDimitry Andric LLDB_SCOPED_TIMERF(
2770b57cec5SDimitry Andric "ObjectContainerBSDArchive::CreateInstance (module = %s, file = "
2780b57cec5SDimitry Andric "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
2790b57cec5SDimitry Andric module_sp->GetFileSpec().GetPath().c_str(),
2800b57cec5SDimitry Andric static_cast<const void *>(file), static_cast<uint64_t>(file_offset),
2810b57cec5SDimitry Andric static_cast<uint64_t>(length));
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric // Map the entire .a file to be sure that we don't lose any data if the
2840b57cec5SDimitry Andric // file gets updated by a new build while this .a file is being used for
2850b57cec5SDimitry Andric // debugging
2860b57cec5SDimitry Andric DataBufferSP archive_data_sp =
2870b57cec5SDimitry Andric FileSystem::Instance().CreateDataBuffer(*file, length, file_offset);
2880b57cec5SDimitry Andric if (!archive_data_sp)
2890b57cec5SDimitry Andric return nullptr;
2900b57cec5SDimitry Andric
2910b57cec5SDimitry Andric lldb::offset_t archive_data_offset = 0;
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andric Archive::shared_ptr archive_sp(Archive::FindCachedArchive(
2940b57cec5SDimitry Andric *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(),
2950b57cec5SDimitry Andric file_offset));
2960b57cec5SDimitry Andric std::unique_ptr<ObjectContainerBSDArchive> container_up(
2970b57cec5SDimitry Andric new ObjectContainerBSDArchive(module_sp, archive_data_sp,
2980b57cec5SDimitry Andric archive_data_offset, file, file_offset,
299753f127fSDimitry Andric length, archive_type));
3000b57cec5SDimitry Andric
3010b57cec5SDimitry Andric if (container_up) {
3020b57cec5SDimitry Andric if (archive_sp) {
3030b57cec5SDimitry Andric // We already have this archive in our cache, use it
3040b57cec5SDimitry Andric container_up->SetArchive(archive_sp);
3050b57cec5SDimitry Andric return container_up.release();
3060b57cec5SDimitry Andric } else if (container_up->ParseHeader())
3070b57cec5SDimitry Andric return container_up.release();
3080b57cec5SDimitry Andric }
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric } else {
3110b57cec5SDimitry Andric // No data, just check for a cached archive
3120b57cec5SDimitry Andric Archive::shared_ptr archive_sp(Archive::FindCachedArchive(
3130b57cec5SDimitry Andric *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(),
3140b57cec5SDimitry Andric file_offset));
3150b57cec5SDimitry Andric if (archive_sp) {
3160b57cec5SDimitry Andric std::unique_ptr<ObjectContainerBSDArchive> container_up(
3170b57cec5SDimitry Andric new ObjectContainerBSDArchive(module_sp, data_sp, data_offset, file,
318753f127fSDimitry Andric file_offset, length,
319753f127fSDimitry Andric archive_sp->GetArchiveType()));
3200b57cec5SDimitry Andric
3210b57cec5SDimitry Andric if (container_up) {
3220b57cec5SDimitry Andric // We already have this archive in our cache, use it
3230b57cec5SDimitry Andric container_up->SetArchive(archive_sp);
3240b57cec5SDimitry Andric return container_up.release();
3250b57cec5SDimitry Andric }
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric return nullptr;
3290b57cec5SDimitry Andric }
3300b57cec5SDimitry Andric
331753f127fSDimitry Andric ArchiveType
MagicBytesMatch(const DataExtractor & data)332753f127fSDimitry Andric ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) {
3330b57cec5SDimitry Andric uint32_t offset = 0;
334*5f757f3fSDimitry Andric const char *armag = (const char *)data.PeekData(offset,
335*5f757f3fSDimitry Andric sizeof(ar_hdr) + SARMAG);
336753f127fSDimitry Andric if (armag == nullptr)
337753f127fSDimitry Andric return ArchiveType::Invalid;
338*5f757f3fSDimitry Andric ArchiveType result = ArchiveType::Invalid;
339*5f757f3fSDimitry Andric if (strncmp(armag, ArchiveMagic, SARMAG) == 0)
340*5f757f3fSDimitry Andric result = ArchiveType::Archive;
341*5f757f3fSDimitry Andric else if (strncmp(armag, ThinArchiveMagic, SARMAG) == 0)
342*5f757f3fSDimitry Andric result = ArchiveType::ThinArchive;
343*5f757f3fSDimitry Andric else
344*5f757f3fSDimitry Andric return ArchiveType::Invalid;
345*5f757f3fSDimitry Andric
3460b57cec5SDimitry Andric armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG;
3470b57cec5SDimitry Andric if (strncmp(armag, ARFMAG, 2) == 0)
348*5f757f3fSDimitry Andric return result;
349753f127fSDimitry Andric return ArchiveType::Invalid;
3500b57cec5SDimitry Andric }
3510b57cec5SDimitry Andric
ObjectContainerBSDArchive(const lldb::ModuleSP & module_sp,DataBufferSP & data_sp,lldb::offset_t data_offset,const lldb_private::FileSpec * file,lldb::offset_t file_offset,lldb::offset_t size,ArchiveType archive_type)3520b57cec5SDimitry Andric ObjectContainerBSDArchive::ObjectContainerBSDArchive(
3530b57cec5SDimitry Andric const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
3540b57cec5SDimitry Andric lldb::offset_t data_offset, const lldb_private::FileSpec *file,
355753f127fSDimitry Andric lldb::offset_t file_offset, lldb::offset_t size, ArchiveType archive_type)
3560b57cec5SDimitry Andric : ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset),
357753f127fSDimitry Andric m_archive_sp() {
358753f127fSDimitry Andric m_archive_type = archive_type;
359753f127fSDimitry Andric }
360753f127fSDimitry Andric
SetArchive(Archive::shared_ptr & archive_sp)3610b57cec5SDimitry Andric void ObjectContainerBSDArchive::SetArchive(Archive::shared_ptr &archive_sp) {
3620b57cec5SDimitry Andric m_archive_sp = archive_sp;
3630b57cec5SDimitry Andric }
3640b57cec5SDimitry Andric
365fe6060f1SDimitry Andric ObjectContainerBSDArchive::~ObjectContainerBSDArchive() = default;
3660b57cec5SDimitry Andric
ParseHeader()3670b57cec5SDimitry Andric bool ObjectContainerBSDArchive::ParseHeader() {
3680b57cec5SDimitry Andric if (m_archive_sp.get() == nullptr) {
3690b57cec5SDimitry Andric if (m_data.GetByteSize() > 0) {
3700b57cec5SDimitry Andric ModuleSP module_sp(GetModule());
3710b57cec5SDimitry Andric if (module_sp) {
3720b57cec5SDimitry Andric m_archive_sp = Archive::ParseAndCacheArchiveForFile(
3730b57cec5SDimitry Andric m_file, module_sp->GetArchitecture(),
374753f127fSDimitry Andric module_sp->GetModificationTime(), m_offset, m_data, m_archive_type);
3750b57cec5SDimitry Andric }
3760b57cec5SDimitry Andric // Clear the m_data that contains the entire archive data and let our
3770b57cec5SDimitry Andric // m_archive_sp hold onto the data.
3780b57cec5SDimitry Andric m_data.Clear();
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric }
3810b57cec5SDimitry Andric return m_archive_sp.get() != nullptr;
3820b57cec5SDimitry Andric }
3830b57cec5SDimitry Andric
GetChildFileSpecificationsFromThin(llvm::StringRef childPath,const FileSpec & parentFileSpec)384753f127fSDimitry Andric FileSpec GetChildFileSpecificationsFromThin(llvm::StringRef childPath,
385753f127fSDimitry Andric const FileSpec &parentFileSpec) {
386753f127fSDimitry Andric llvm::SmallString<128> FullPath;
387753f127fSDimitry Andric if (llvm::sys::path::is_absolute(childPath)) {
388753f127fSDimitry Andric FullPath = childPath;
389753f127fSDimitry Andric } else {
390753f127fSDimitry Andric FullPath = parentFileSpec.GetDirectory().GetStringRef();
391753f127fSDimitry Andric llvm::sys::path::append(FullPath, childPath);
392753f127fSDimitry Andric }
393753f127fSDimitry Andric FileSpec child = FileSpec(FullPath.str(), llvm::sys::path::Style::posix);
394753f127fSDimitry Andric return child;
395753f127fSDimitry Andric }
396753f127fSDimitry Andric
GetObjectFile(const FileSpec * file)3970b57cec5SDimitry Andric ObjectFileSP ObjectContainerBSDArchive::GetObjectFile(const FileSpec *file) {
3980b57cec5SDimitry Andric ModuleSP module_sp(GetModule());
3990b57cec5SDimitry Andric if (module_sp) {
4000b57cec5SDimitry Andric if (module_sp->GetObjectName() && m_archive_sp) {
4010b57cec5SDimitry Andric Object *object = m_archive_sp->FindObject(
4020b57cec5SDimitry Andric module_sp->GetObjectName(), module_sp->GetObjectModificationTime());
4030b57cec5SDimitry Andric if (object) {
404753f127fSDimitry Andric if (m_archive_type == ArchiveType::ThinArchive) {
405753f127fSDimitry Andric // Set file to child object file
406753f127fSDimitry Andric FileSpec child = GetChildFileSpecificationsFromThin(
407753f127fSDimitry Andric object->ar_name.GetStringRef(), m_file);
408753f127fSDimitry Andric lldb::offset_t file_offset = 0;
409753f127fSDimitry Andric lldb::offset_t file_size = object->size;
410753f127fSDimitry Andric std::shared_ptr<DataBuffer> child_data_sp =
411753f127fSDimitry Andric FileSystem::Instance().CreateDataBuffer(child, file_size,
412753f127fSDimitry Andric file_offset);
413*5f757f3fSDimitry Andric if (!child_data_sp ||
414*5f757f3fSDimitry Andric child_data_sp->GetByteSize() != object->file_size)
415753f127fSDimitry Andric return ObjectFileSP();
416753f127fSDimitry Andric lldb::offset_t data_offset = 0;
417753f127fSDimitry Andric return ObjectFile::FindPlugin(
418753f127fSDimitry Andric module_sp, &child, m_offset + object->file_offset,
419753f127fSDimitry Andric object->file_size, child_data_sp, data_offset);
420753f127fSDimitry Andric }
4210b57cec5SDimitry Andric lldb::offset_t data_offset = object->file_offset;
4220b57cec5SDimitry Andric return ObjectFile::FindPlugin(
4230b57cec5SDimitry Andric module_sp, file, m_offset + object->file_offset, object->file_size,
4240b57cec5SDimitry Andric m_archive_sp->GetData().GetSharedDataBuffer(), data_offset);
4250b57cec5SDimitry Andric }
4260b57cec5SDimitry Andric }
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric return ObjectFileSP();
4290b57cec5SDimitry Andric }
4300b57cec5SDimitry Andric
GetModuleSpecifications(const lldb_private::FileSpec & file,lldb::DataBufferSP & data_sp,lldb::offset_t data_offset,lldb::offset_t file_offset,lldb::offset_t file_size,lldb_private::ModuleSpecList & specs)4310b57cec5SDimitry Andric size_t ObjectContainerBSDArchive::GetModuleSpecifications(
4320b57cec5SDimitry Andric const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
4330b57cec5SDimitry Andric lldb::offset_t data_offset, lldb::offset_t file_offset,
4340b57cec5SDimitry Andric lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) {
4350b57cec5SDimitry Andric
4360b57cec5SDimitry Andric // We have data, which means this is the first 512 bytes of the file Check to
4370b57cec5SDimitry Andric // see if the magic bytes match and if they do, read the entire table of
4380b57cec5SDimitry Andric // contents for the archive and cache it
4390b57cec5SDimitry Andric DataExtractor data;
4400b57cec5SDimitry Andric data.SetData(data_sp, data_offset, data_sp->GetByteSize());
441753f127fSDimitry Andric ArchiveType archive_type = ObjectContainerBSDArchive::MagicBytesMatch(data);
442753f127fSDimitry Andric if (!file || !data_sp || archive_type == ArchiveType::Invalid)
4430b57cec5SDimitry Andric return 0;
4440b57cec5SDimitry Andric
4450b57cec5SDimitry Andric const size_t initial_count = specs.GetSize();
4460b57cec5SDimitry Andric llvm::sys::TimePoint<> file_mod_time = FileSystem::Instance().GetModificationTime(file);
4470b57cec5SDimitry Andric Archive::shared_ptr archive_sp(
4480b57cec5SDimitry Andric Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset));
4490b57cec5SDimitry Andric bool set_archive_arch = false;
4500b57cec5SDimitry Andric if (!archive_sp) {
4510b57cec5SDimitry Andric set_archive_arch = true;
4520b57cec5SDimitry Andric data_sp =
4530b57cec5SDimitry Andric FileSystem::Instance().CreateDataBuffer(file, file_size, file_offset);
4540b57cec5SDimitry Andric if (data_sp) {
4550b57cec5SDimitry Andric data.SetData(data_sp, 0, data_sp->GetByteSize());
4560b57cec5SDimitry Andric archive_sp = Archive::ParseAndCacheArchiveForFile(
457753f127fSDimitry Andric file, ArchSpec(), file_mod_time, file_offset, data, archive_type);
4580b57cec5SDimitry Andric }
4590b57cec5SDimitry Andric }
4600b57cec5SDimitry Andric
4610b57cec5SDimitry Andric if (archive_sp) {
4620b57cec5SDimitry Andric const size_t num_objects = archive_sp->GetNumObjects();
4630b57cec5SDimitry Andric for (size_t idx = 0; idx < num_objects; ++idx) {
4640b57cec5SDimitry Andric const Object *object = archive_sp->GetObjectAtIndex(idx);
4650b57cec5SDimitry Andric if (object) {
466753f127fSDimitry Andric if (archive_sp->GetArchiveType() == ArchiveType::ThinArchive) {
467753f127fSDimitry Andric if (object->ar_name.IsEmpty())
468753f127fSDimitry Andric continue;
469753f127fSDimitry Andric FileSpec child = GetChildFileSpecificationsFromThin(
470753f127fSDimitry Andric object->ar_name.GetStringRef(), file);
471753f127fSDimitry Andric if (ObjectFile::GetModuleSpecifications(child, 0, object->file_size,
472753f127fSDimitry Andric specs)) {
473753f127fSDimitry Andric ModuleSpec &spec =
474753f127fSDimitry Andric specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1);
475753f127fSDimitry Andric llvm::sys::TimePoint<> object_mod_time(
476753f127fSDimitry Andric std::chrono::seconds(object->modification_time));
477753f127fSDimitry Andric spec.GetObjectName() = object->ar_name;
478753f127fSDimitry Andric spec.SetObjectOffset(0);
479753f127fSDimitry Andric spec.SetObjectSize(object->file_size);
480753f127fSDimitry Andric spec.GetObjectModificationTime() = object_mod_time;
481753f127fSDimitry Andric }
482753f127fSDimitry Andric continue;
483753f127fSDimitry Andric }
4840b57cec5SDimitry Andric const lldb::offset_t object_file_offset =
4850b57cec5SDimitry Andric file_offset + object->file_offset;
4860b57cec5SDimitry Andric if (object->file_offset < file_size && file_size > object_file_offset) {
4870b57cec5SDimitry Andric if (ObjectFile::GetModuleSpecifications(
4880b57cec5SDimitry Andric file, object_file_offset, file_size - object_file_offset,
4890b57cec5SDimitry Andric specs)) {
4900b57cec5SDimitry Andric ModuleSpec &spec =
4910b57cec5SDimitry Andric specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1);
4920b57cec5SDimitry Andric llvm::sys::TimePoint<> object_mod_time(
4930b57cec5SDimitry Andric std::chrono::seconds(object->modification_time));
4940b57cec5SDimitry Andric spec.GetObjectName() = object->ar_name;
4950b57cec5SDimitry Andric spec.SetObjectOffset(object_file_offset);
496*5f757f3fSDimitry Andric spec.SetObjectSize(object->file_size);
4970b57cec5SDimitry Andric spec.GetObjectModificationTime() = object_mod_time;
4980b57cec5SDimitry Andric }
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric }
5020b57cec5SDimitry Andric }
5030b57cec5SDimitry Andric const size_t end_count = specs.GetSize();
5040b57cec5SDimitry Andric size_t num_specs_added = end_count - initial_count;
5050b57cec5SDimitry Andric if (set_archive_arch && num_specs_added > 0) {
5060b57cec5SDimitry Andric // The archive was created but we didn't have an architecture so we need to
5070b57cec5SDimitry Andric // set it
5080b57cec5SDimitry Andric for (size_t i = initial_count; i < end_count; ++i) {
5090b57cec5SDimitry Andric ModuleSpec module_spec;
5100b57cec5SDimitry Andric if (specs.GetModuleSpecAtIndex(i, module_spec)) {
5110b57cec5SDimitry Andric if (module_spec.GetArchitecture().IsValid()) {
5120b57cec5SDimitry Andric archive_sp->SetArchitecture(module_spec.GetArchitecture());
5130b57cec5SDimitry Andric break;
5140b57cec5SDimitry Andric }
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric }
5170b57cec5SDimitry Andric }
5180b57cec5SDimitry Andric return num_specs_added;
5190b57cec5SDimitry Andric }
520