| 1 | //===-- ObjectContainerBSDArchive.cpp -------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "ObjectContainerBSDArchive.h" |
| 10 | |
| 11 | #if defined(_WIN32) || defined(_AIX) |
| 12 | // Defines from ar, missing on Windows |
| 13 | #define SARMAG 8 |
| 14 | #define ARFMAG "`\n" |
| 15 | |
| 16 | typedef struct ar_hdr { |
| 17 | char ar_name[16]; |
| 18 | char ar_date[12]; |
| 19 | char ar_uid[6], ar_gid[6]; |
| 20 | char ar_mode[8]; |
| 21 | char ar_size[10]; |
| 22 | char ar_fmag[2]; |
| 23 | } ar_hdr; |
| 24 | #else |
| 25 | #include <ar.h> |
| 26 | #endif |
| 27 | |
| 28 | #include "lldb/Core/Module.h" |
| 29 | #include "lldb/Core/ModuleSpec.h" |
| 30 | #include "lldb/Core/PluginManager.h" |
| 31 | #include "lldb/Host/FileSystem.h" |
| 32 | #include "lldb/Symbol/ObjectFile.h" |
| 33 | #include "lldb/Utility/ArchSpec.h" |
| 34 | #include "lldb/Utility/LLDBLog.h" |
| 35 | #include "lldb/Utility/Stream.h" |
| 36 | #include "lldb/Utility/Timer.h" |
| 37 | |
| 38 | #include "llvm/Object/Archive.h" |
| 39 | #include "llvm/Support/MemoryBuffer.h" |
| 40 | |
| 41 | using namespace lldb; |
| 42 | using namespace lldb_private; |
| 43 | |
| 44 | using namespace llvm::object; |
| 45 | |
| 46 | LLDB_PLUGIN_DEFINE(ObjectContainerBSDArchive) |
| 47 | |
| 48 | ObjectContainerBSDArchive::Object::Object() : ar_name() {} |
| 49 | |
| 50 | void ObjectContainerBSDArchive::Object::Clear() { |
| 51 | ar_name.Clear(); |
| 52 | modification_time = 0; |
| 53 | size = 0; |
| 54 | file_offset = 0; |
| 55 | file_size = 0; |
| 56 | } |
| 57 | |
| 58 | void ObjectContainerBSDArchive::Object::Dump() const { |
| 59 | printf(format: "name = \"%s\"\n" , ar_name.GetCString()); |
| 60 | printf(format: "mtime = 0x%8.8" PRIx32 "\n" , modification_time); |
| 61 | printf(format: "size = 0x%8.8" PRIx32 " (%" PRIu32 ")\n" , size, size); |
| 62 | printf(format: "file_offset = 0x%16.16" PRIx64 " (%" PRIu64 ")\n" , file_offset, |
| 63 | file_offset); |
| 64 | printf(format: "file_size = 0x%16.16" PRIx64 " (%" PRIu64 ")\n\n" , file_size, |
| 65 | file_size); |
| 66 | } |
| 67 | |
| 68 | ObjectContainerBSDArchive::Archive::Archive(const lldb_private::ArchSpec &arch, |
| 69 | const llvm::sys::TimePoint<> &time, |
| 70 | lldb::offset_t file_offset, |
| 71 | lldb_private::DataExtractor &data, |
| 72 | ArchiveType archive_type) |
| 73 | : m_arch(arch), m_modification_time(time), m_file_offset(file_offset), |
| 74 | m_objects(), m_data(data), m_archive_type(archive_type) {} |
| 75 | |
| 76 | Log *l = GetLog(mask: LLDBLog::Object); |
| 77 | ObjectContainerBSDArchive::Archive::~Archive() = default; |
| 78 | |
| 79 | size_t ObjectContainerBSDArchive::Archive::ParseObjects() { |
| 80 | DataExtractor &data = m_data; |
| 81 | |
| 82 | std::unique_ptr<llvm::MemoryBuffer> mem_buffer = |
| 83 | llvm::MemoryBuffer::getMemBuffer( |
| 84 | InputData: llvm::StringRef((const char *)data.GetDataStart(), |
| 85 | data.GetByteSize()), |
| 86 | BufferName: llvm::StringRef(), |
| 87 | /*RequiresNullTerminator=*/false); |
| 88 | |
| 89 | auto exp_ar = llvm::object::Archive::create(Source: mem_buffer->getMemBufferRef()); |
| 90 | if (!exp_ar) { |
| 91 | LLDB_LOG_ERROR(l, exp_ar.takeError(), "failed to create archive: {0}" ); |
| 92 | return 0; |
| 93 | } |
| 94 | auto llvm_archive = std::move(exp_ar.get()); |
| 95 | |
| 96 | llvm::Error iter_err = llvm::Error::success(); |
| 97 | Object obj; |
| 98 | for (const auto &child : llvm_archive->children(Err&: iter_err)) { |
| 99 | obj.Clear(); |
| 100 | auto exp_name = child.getName(); |
| 101 | if (exp_name) { |
| 102 | obj.ar_name = ConstString(exp_name.get()); |
| 103 | } else { |
| 104 | LLDB_LOG_ERROR(l, exp_name.takeError(), |
| 105 | "failed to get archive object name: {0}" ); |
| 106 | continue; |
| 107 | } |
| 108 | |
| 109 | auto exp_mtime = child.getLastModified(); |
| 110 | if (exp_mtime) { |
| 111 | obj.modification_time = |
| 112 | std::chrono::duration_cast<std::chrono::seconds>( |
| 113 | d: std::chrono::time_point_cast<std::chrono::seconds>( |
| 114 | t: exp_mtime.get()) |
| 115 | .time_since_epoch()) |
| 116 | .count(); |
| 117 | } else { |
| 118 | LLDB_LOG_ERROR(l, exp_mtime.takeError(), |
| 119 | "failed to get archive object time: {0}" ); |
| 120 | continue; |
| 121 | } |
| 122 | |
| 123 | auto exp_size = child.getRawSize(); |
| 124 | if (exp_size) { |
| 125 | obj.size = exp_size.get(); |
| 126 | } else { |
| 127 | LLDB_LOG_ERROR(l, exp_size.takeError(), |
| 128 | "failed to get archive object size: {0}" ); |
| 129 | continue; |
| 130 | } |
| 131 | |
| 132 | obj.file_offset = child.getDataOffset(); |
| 133 | |
| 134 | auto exp_file_size = child.getSize(); |
| 135 | if (exp_file_size) { |
| 136 | obj.file_size = exp_file_size.get(); |
| 137 | } else { |
| 138 | LLDB_LOG_ERROR(l, exp_file_size.takeError(), |
| 139 | "failed to get archive object file size: {0}" ); |
| 140 | continue; |
| 141 | } |
| 142 | m_object_name_to_index_map.Append(unique_cstr: obj.ar_name, value: m_objects.size()); |
| 143 | m_objects.push_back(x: obj); |
| 144 | } |
| 145 | if (iter_err) { |
| 146 | LLDB_LOG_ERROR(l, std::move(iter_err), |
| 147 | "failed to iterate over archive objects: {0}" ); |
| 148 | } |
| 149 | // Now sort all of the object name pointers |
| 150 | m_object_name_to_index_map.Sort(); |
| 151 | return m_objects.size(); |
| 152 | } |
| 153 | |
| 154 | ObjectContainerBSDArchive::Object * |
| 155 | ObjectContainerBSDArchive::Archive::FindObject( |
| 156 | ConstString object_name, const llvm::sys::TimePoint<> &object_mod_time) { |
| 157 | const ObjectNameToIndexMap::Entry *match = |
| 158 | m_object_name_to_index_map.FindFirstValueForName(unique_cstr: object_name); |
| 159 | if (!match) |
| 160 | return nullptr; |
| 161 | if (object_mod_time == llvm::sys::TimePoint<>()) |
| 162 | return &m_objects[match->value]; |
| 163 | |
| 164 | const uint64_t object_modification_date = llvm::sys::toTimeT(TP: object_mod_time); |
| 165 | if (m_objects[match->value].modification_time == object_modification_date) |
| 166 | return &m_objects[match->value]; |
| 167 | |
| 168 | const ObjectNameToIndexMap::Entry *next_match = |
| 169 | m_object_name_to_index_map.FindNextValueForName(entry_ptr: match); |
| 170 | while (next_match) { |
| 171 | if (m_objects[next_match->value].modification_time == |
| 172 | object_modification_date) |
| 173 | return &m_objects[next_match->value]; |
| 174 | next_match = m_object_name_to_index_map.FindNextValueForName(entry_ptr: next_match); |
| 175 | } |
| 176 | |
| 177 | return nullptr; |
| 178 | } |
| 179 | |
| 180 | ObjectContainerBSDArchive::Archive::shared_ptr |
| 181 | ObjectContainerBSDArchive::Archive::FindCachedArchive( |
| 182 | const FileSpec &file, const ArchSpec &arch, |
| 183 | const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset) { |
| 184 | std::lock_guard<std::recursive_mutex> guard(Archive::GetArchiveCacheMutex()); |
| 185 | shared_ptr archive_sp; |
| 186 | Archive::Map &archive_map = Archive::GetArchiveCache(); |
| 187 | Archive::Map::iterator pos = archive_map.find(x: file); |
| 188 | // Don't cache a value for "archive_map.end()" below since we might delete an |
| 189 | // archive entry... |
| 190 | while (pos != archive_map.end() && pos->first == file) { |
| 191 | bool match = true; |
| 192 | if (arch.IsValid() && |
| 193 | !pos->second->GetArchitecture().IsCompatibleMatch(rhs: arch)) |
| 194 | match = false; |
| 195 | else if (file_offset != LLDB_INVALID_OFFSET && |
| 196 | pos->second->GetFileOffset() != file_offset) |
| 197 | match = false; |
| 198 | if (match) { |
| 199 | if (pos->second->GetModificationTime() == time) { |
| 200 | return pos->second; |
| 201 | } else { |
| 202 | // We have a file at the same path with the same architecture whose |
| 203 | // modification time doesn't match. It doesn't make sense for us to |
| 204 | // continue to use this BSD archive since we cache only the object info |
| 205 | // which consists of file time info and also the file offset and file |
| 206 | // size of any contained objects. Since this information is now out of |
| 207 | // date, we won't get the correct information if we go and extract the |
| 208 | // file data, so we should remove the old and outdated entry. |
| 209 | archive_map.erase(position: pos); |
| 210 | pos = archive_map.find(x: file); |
| 211 | continue; // Continue to next iteration so we don't increment pos |
| 212 | // below... |
| 213 | } |
| 214 | } |
| 215 | ++pos; |
| 216 | } |
| 217 | return archive_sp; |
| 218 | } |
| 219 | |
| 220 | ObjectContainerBSDArchive::Archive::shared_ptr |
| 221 | ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile( |
| 222 | const FileSpec &file, const ArchSpec &arch, |
| 223 | const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset, |
| 224 | DataExtractor &data, ArchiveType archive_type) { |
| 225 | shared_ptr archive_sp( |
| 226 | new Archive(arch, time, file_offset, data, archive_type)); |
| 227 | if (archive_sp) { |
| 228 | const size_t num_objects = archive_sp->ParseObjects(); |
| 229 | if (num_objects > 0) { |
| 230 | std::lock_guard<std::recursive_mutex> guard( |
| 231 | Archive::GetArchiveCacheMutex()); |
| 232 | Archive::GetArchiveCache().insert(x: std::make_pair(x: file, y&: archive_sp)); |
| 233 | } else { |
| 234 | archive_sp.reset(); |
| 235 | } |
| 236 | } |
| 237 | return archive_sp; |
| 238 | } |
| 239 | |
| 240 | ObjectContainerBSDArchive::Archive::Map & |
| 241 | ObjectContainerBSDArchive::Archive::GetArchiveCache() { |
| 242 | static Archive::Map g_archive_map; |
| 243 | return g_archive_map; |
| 244 | } |
| 245 | |
| 246 | std::recursive_mutex & |
| 247 | ObjectContainerBSDArchive::Archive::GetArchiveCacheMutex() { |
| 248 | static std::recursive_mutex g_archive_map_mutex; |
| 249 | return g_archive_map_mutex; |
| 250 | } |
| 251 | |
| 252 | void ObjectContainerBSDArchive::Initialize() { |
| 253 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
| 254 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance, |
| 255 | get_module_specifications: GetModuleSpecifications); |
| 256 | } |
| 257 | |
| 258 | void ObjectContainerBSDArchive::Terminate() { |
| 259 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
| 260 | } |
| 261 | |
| 262 | ObjectContainer *ObjectContainerBSDArchive::CreateInstance( |
| 263 | const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, |
| 264 | lldb::offset_t data_offset, const FileSpec *file, |
| 265 | lldb::offset_t file_offset, lldb::offset_t length) { |
| 266 | ConstString object_name(module_sp->GetObjectName()); |
| 267 | if (!object_name) |
| 268 | return nullptr; |
| 269 | |
| 270 | if (data_sp) { |
| 271 | // We have data, which means this is the first 512 bytes of the file Check |
| 272 | // to see if the magic bytes match and if they do, read the entire table of |
| 273 | // contents for the archive and cache it |
| 274 | DataExtractor data; |
| 275 | data.SetData(data_sp, offset: data_offset, length); |
| 276 | ArchiveType archive_type = ObjectContainerBSDArchive::MagicBytesMatch(data); |
| 277 | if (file && data_sp && archive_type != ArchiveType::Invalid) { |
| 278 | LLDB_SCOPED_TIMERF( |
| 279 | "ObjectContainerBSDArchive::CreateInstance (module = %s, file = " |
| 280 | "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")" , |
| 281 | module_sp->GetFileSpec().GetPath().c_str(), |
| 282 | static_cast<const void *>(file), static_cast<uint64_t>(file_offset), |
| 283 | static_cast<uint64_t>(length)); |
| 284 | |
| 285 | // Map the entire .a file to be sure that we don't lose any data if the |
| 286 | // file gets updated by a new build while this .a file is being used for |
| 287 | // debugging |
| 288 | DataBufferSP archive_data_sp = |
| 289 | FileSystem::Instance().CreateDataBuffer(file_spec: *file, size: length, offset: file_offset); |
| 290 | if (!archive_data_sp) |
| 291 | return nullptr; |
| 292 | |
| 293 | lldb::offset_t archive_data_offset = 0; |
| 294 | |
| 295 | Archive::shared_ptr archive_sp(Archive::FindCachedArchive( |
| 296 | file: *file, arch: module_sp->GetArchitecture(), time: module_sp->GetModificationTime(), |
| 297 | file_offset)); |
| 298 | std::unique_ptr<ObjectContainerBSDArchive> container_up( |
| 299 | new ObjectContainerBSDArchive(module_sp, archive_data_sp, |
| 300 | archive_data_offset, file, file_offset, |
| 301 | length, archive_type)); |
| 302 | |
| 303 | if (container_up) { |
| 304 | if (archive_sp) { |
| 305 | // We already have this archive in our cache, use it |
| 306 | container_up->SetArchive(archive_sp); |
| 307 | return container_up.release(); |
| 308 | } else if (container_up->ParseHeader()) |
| 309 | return container_up.release(); |
| 310 | } |
| 311 | } |
| 312 | } else { |
| 313 | // No data, just check for a cached archive |
| 314 | Archive::shared_ptr archive_sp(Archive::FindCachedArchive( |
| 315 | file: *file, arch: module_sp->GetArchitecture(), time: module_sp->GetModificationTime(), |
| 316 | file_offset)); |
| 317 | if (archive_sp) { |
| 318 | std::unique_ptr<ObjectContainerBSDArchive> container_up( |
| 319 | new ObjectContainerBSDArchive(module_sp, data_sp, data_offset, file, |
| 320 | file_offset, length, |
| 321 | archive_sp->GetArchiveType())); |
| 322 | |
| 323 | if (container_up) { |
| 324 | // We already have this archive in our cache, use it |
| 325 | container_up->SetArchive(archive_sp); |
| 326 | return container_up.release(); |
| 327 | } |
| 328 | } |
| 329 | } |
| 330 | return nullptr; |
| 331 | } |
| 332 | |
| 333 | ArchiveType |
| 334 | ObjectContainerBSDArchive::(const DataExtractor &data) { |
| 335 | uint32_t offset = 0; |
| 336 | const char *armag = |
| 337 | (const char *)data.PeekData(offset, length: sizeof(ar_hdr) + SARMAG); |
| 338 | if (armag == nullptr) |
| 339 | return ArchiveType::Invalid; |
| 340 | ArchiveType result = ArchiveType::Invalid; |
| 341 | if (strncmp(s1: armag, s2: ArchiveMagic, SARMAG) == 0) |
| 342 | result = ArchiveType::Archive; |
| 343 | else if (strncmp(s1: armag, s2: ThinArchiveMagic, SARMAG) == 0) |
| 344 | result = ArchiveType::ThinArchive; |
| 345 | else |
| 346 | return ArchiveType::Invalid; |
| 347 | |
| 348 | armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; |
| 349 | if (strncmp(s1: armag, ARFMAG, n: 2) == 0) |
| 350 | return result; |
| 351 | return ArchiveType::Invalid; |
| 352 | } |
| 353 | |
| 354 | ObjectContainerBSDArchive::ObjectContainerBSDArchive( |
| 355 | const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, |
| 356 | lldb::offset_t data_offset, const lldb_private::FileSpec *file, |
| 357 | lldb::offset_t file_offset, lldb::offset_t size, ArchiveType archive_type) |
| 358 | : ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset), |
| 359 | m_archive_sp() { |
| 360 | m_archive_type = archive_type; |
| 361 | } |
| 362 | |
| 363 | void ObjectContainerBSDArchive::SetArchive(Archive::shared_ptr &archive_sp) { |
| 364 | m_archive_sp = archive_sp; |
| 365 | } |
| 366 | |
| 367 | ObjectContainerBSDArchive::~ObjectContainerBSDArchive() = default; |
| 368 | |
| 369 | bool ObjectContainerBSDArchive::() { |
| 370 | if (m_archive_sp.get() == nullptr) { |
| 371 | if (m_data.GetByteSize() > 0) { |
| 372 | ModuleSP module_sp(GetModule()); |
| 373 | if (module_sp) { |
| 374 | m_archive_sp = Archive::ParseAndCacheArchiveForFile( |
| 375 | file: m_file, arch: module_sp->GetArchitecture(), |
| 376 | time: module_sp->GetModificationTime(), file_offset: m_offset, data&: m_data, archive_type: m_archive_type); |
| 377 | } |
| 378 | // Clear the m_data that contains the entire archive data and let our |
| 379 | // m_archive_sp hold onto the data. |
| 380 | m_data.Clear(); |
| 381 | } |
| 382 | } |
| 383 | return m_archive_sp.get() != nullptr; |
| 384 | } |
| 385 | |
| 386 | FileSpec GetChildFileSpecificationsFromThin(llvm::StringRef childPath, |
| 387 | const FileSpec &parentFileSpec) { |
| 388 | llvm::SmallString<128> FullPath; |
| 389 | if (llvm::sys::path::is_absolute(path: childPath)) { |
| 390 | FullPath = childPath; |
| 391 | } else { |
| 392 | FullPath = parentFileSpec.GetDirectory().GetStringRef(); |
| 393 | llvm::sys::path::append(path&: FullPath, a: childPath); |
| 394 | } |
| 395 | FileSpec child = FileSpec(FullPath.str(), llvm::sys::path::Style::posix); |
| 396 | return child; |
| 397 | } |
| 398 | |
| 399 | ObjectFileSP ObjectContainerBSDArchive::GetObjectFile(const FileSpec *file) { |
| 400 | ModuleSP module_sp(GetModule()); |
| 401 | if (module_sp) { |
| 402 | if (module_sp->GetObjectName() && m_archive_sp) { |
| 403 | Object *object = m_archive_sp->FindObject( |
| 404 | object_name: module_sp->GetObjectName(), object_mod_time: module_sp->GetObjectModificationTime()); |
| 405 | if (object) { |
| 406 | if (m_archive_type == ArchiveType::ThinArchive) { |
| 407 | // Set file to child object file |
| 408 | FileSpec child = GetChildFileSpecificationsFromThin( |
| 409 | childPath: object->ar_name.GetStringRef(), parentFileSpec: m_file); |
| 410 | lldb::offset_t file_offset = 0; |
| 411 | lldb::offset_t file_size = object->size; |
| 412 | std::shared_ptr<DataBuffer> child_data_sp = |
| 413 | FileSystem::Instance().CreateDataBuffer(file_spec: child, size: file_size, |
| 414 | offset: file_offset); |
| 415 | if (!child_data_sp || |
| 416 | child_data_sp->GetByteSize() != object->file_size) |
| 417 | return ObjectFileSP(); |
| 418 | lldb::offset_t data_offset = 0; |
| 419 | return ObjectFile::FindPlugin( |
| 420 | module_sp, file_spec: &child, file_offset: m_offset + object->file_offset, |
| 421 | file_size: object->file_size, data_sp&: child_data_sp, data_offset); |
| 422 | } |
| 423 | lldb::offset_t data_offset = object->file_offset; |
| 424 | return ObjectFile::FindPlugin( |
| 425 | module_sp, file_spec: file, file_offset: m_offset + object->file_offset, file_size: object->file_size, |
| 426 | data_sp&: m_archive_sp->GetData().GetSharedDataBuffer(), data_offset); |
| 427 | } |
| 428 | } |
| 429 | } |
| 430 | return ObjectFileSP(); |
| 431 | } |
| 432 | |
| 433 | size_t ObjectContainerBSDArchive::GetModuleSpecifications( |
| 434 | const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, |
| 435 | lldb::offset_t data_offset, lldb::offset_t file_offset, |
| 436 | lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) { |
| 437 | |
| 438 | // We have data, which means this is the first 512 bytes of the file Check to |
| 439 | // see if the magic bytes match and if they do, read the entire table of |
| 440 | // contents for the archive and cache it |
| 441 | DataExtractor data; |
| 442 | data.SetData(data_sp, offset: data_offset, length: data_sp->GetByteSize()); |
| 443 | ArchiveType archive_type = ObjectContainerBSDArchive::MagicBytesMatch(data); |
| 444 | if (!file || !data_sp || archive_type == ArchiveType::Invalid) |
| 445 | return 0; |
| 446 | |
| 447 | const size_t initial_count = specs.GetSize(); |
| 448 | llvm::sys::TimePoint<> file_mod_time = |
| 449 | FileSystem::Instance().GetModificationTime(file_spec: file); |
| 450 | Archive::shared_ptr archive_sp( |
| 451 | Archive::FindCachedArchive(file, arch: ArchSpec(), time: file_mod_time, file_offset)); |
| 452 | bool set_archive_arch = false; |
| 453 | if (!archive_sp) { |
| 454 | set_archive_arch = true; |
| 455 | data_sp = |
| 456 | FileSystem::Instance().CreateDataBuffer(file_spec: file, size: file_size, offset: file_offset); |
| 457 | if (data_sp) { |
| 458 | data.SetData(data_sp, offset: 0, length: data_sp->GetByteSize()); |
| 459 | archive_sp = Archive::ParseAndCacheArchiveForFile( |
| 460 | file, arch: ArchSpec(), time: file_mod_time, file_offset, data, archive_type); |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | if (archive_sp) { |
| 465 | const size_t num_objects = archive_sp->GetNumObjects(); |
| 466 | for (size_t idx = 0; idx < num_objects; ++idx) { |
| 467 | const Object *object = archive_sp->GetObjectAtIndex(idx); |
| 468 | if (object) { |
| 469 | if (archive_sp->GetArchiveType() == ArchiveType::ThinArchive) { |
| 470 | if (object->ar_name.IsEmpty()) |
| 471 | continue; |
| 472 | FileSpec child = GetChildFileSpecificationsFromThin( |
| 473 | childPath: object->ar_name.GetStringRef(), parentFileSpec: file); |
| 474 | if (ObjectFile::GetModuleSpecifications(file: child, file_offset: 0, file_size: object->file_size, |
| 475 | specs)) { |
| 476 | ModuleSpec &spec = |
| 477 | specs.GetModuleSpecRefAtIndex(i: specs.GetSize() - 1); |
| 478 | llvm::sys::TimePoint<> object_mod_time( |
| 479 | std::chrono::seconds(object->modification_time)); |
| 480 | spec.GetObjectName() = object->ar_name; |
| 481 | spec.SetObjectOffset(0); |
| 482 | spec.SetObjectSize(object->file_size); |
| 483 | spec.GetObjectModificationTime() = object_mod_time; |
| 484 | } |
| 485 | continue; |
| 486 | } |
| 487 | const lldb::offset_t object_file_offset = |
| 488 | file_offset + object->file_offset; |
| 489 | if (object->file_offset < file_size && file_size > object_file_offset) { |
| 490 | if (ObjectFile::GetModuleSpecifications( |
| 491 | file, file_offset: object_file_offset, file_size: file_size - object_file_offset, |
| 492 | specs)) { |
| 493 | ModuleSpec &spec = |
| 494 | specs.GetModuleSpecRefAtIndex(i: specs.GetSize() - 1); |
| 495 | llvm::sys::TimePoint<> object_mod_time( |
| 496 | std::chrono::seconds(object->modification_time)); |
| 497 | spec.GetObjectName() = object->ar_name; |
| 498 | spec.SetObjectOffset(object_file_offset); |
| 499 | spec.SetObjectSize(object->file_size); |
| 500 | spec.GetObjectModificationTime() = object_mod_time; |
| 501 | } |
| 502 | } |
| 503 | } |
| 504 | } |
| 505 | } |
| 506 | const size_t end_count = specs.GetSize(); |
| 507 | size_t num_specs_added = end_count - initial_count; |
| 508 | if (set_archive_arch && num_specs_added > 0) { |
| 509 | // The archive was created but we didn't have an architecture so we need to |
| 510 | // set it |
| 511 | for (size_t i = initial_count; i < end_count; ++i) { |
| 512 | ModuleSpec module_spec; |
| 513 | if (specs.GetModuleSpecAtIndex(i, module_spec)) { |
| 514 | if (module_spec.GetArchitecture().IsValid()) { |
| 515 | archive_sp->SetArchitecture(module_spec.GetArchitecture()); |
| 516 | break; |
| 517 | } |
| 518 | } |
| 519 | } |
| 520 | } |
| 521 | return num_specs_added; |
| 522 | } |
| 523 | |