17fa27ce4SDimitry Andric //===-- ZipFileResolver.cpp -----------------------------------------------===//
27fa27ce4SDimitry Andric //
37fa27ce4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47fa27ce4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
57fa27ce4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67fa27ce4SDimitry Andric //
77fa27ce4SDimitry Andric //===----------------------------------------------------------------------===//
87fa27ce4SDimitry Andric
97fa27ce4SDimitry Andric #include "lldb/Host/common/ZipFileResolver.h"
107fa27ce4SDimitry Andric #include "lldb/Host/FileSystem.h"
117fa27ce4SDimitry Andric #include "lldb/Utility/DataBuffer.h"
127fa27ce4SDimitry Andric #include "lldb/Utility/FileSpec.h"
137fa27ce4SDimitry Andric #include "lldb/Utility/ZipFile.h"
147fa27ce4SDimitry Andric
157fa27ce4SDimitry Andric using namespace lldb_private;
167fa27ce4SDimitry Andric using namespace llvm::support;
177fa27ce4SDimitry Andric
ResolveSharedLibraryPath(const FileSpec & file_spec,FileKind & file_kind,std::string & file_path,lldb::offset_t & so_file_offset,lldb::offset_t & so_file_size)187fa27ce4SDimitry Andric bool ZipFileResolver::ResolveSharedLibraryPath(const FileSpec &file_spec,
197fa27ce4SDimitry Andric FileKind &file_kind,
207fa27ce4SDimitry Andric std::string &file_path,
217fa27ce4SDimitry Andric lldb::offset_t &so_file_offset,
227fa27ce4SDimitry Andric lldb::offset_t &so_file_size) {
237fa27ce4SDimitry Andric // When bionic loads .so file from APK or zip file, this file_spec will be
247fa27ce4SDimitry Andric // "zip_path!/so_path". Otherwise it is just a normal file path.
257fa27ce4SDimitry Andric static constexpr llvm::StringLiteral k_zip_separator("!/");
267fa27ce4SDimitry Andric std::string path(file_spec.GetPath());
277fa27ce4SDimitry Andric size_t pos = path.find(k_zip_separator);
287fa27ce4SDimitry Andric
297fa27ce4SDimitry Andric #if defined(_WIN32)
307fa27ce4SDimitry Andric // When the file_spec is resolved as a Windows path, the zip .so path will be
317fa27ce4SDimitry Andric // "zip_path!\so_path". Support both patterns on Windows.
327fa27ce4SDimitry Andric static constexpr llvm::StringLiteral k_zip_separator_win("!\\");
337fa27ce4SDimitry Andric if (pos == std::string::npos)
347fa27ce4SDimitry Andric pos = path.find(k_zip_separator_win);
357fa27ce4SDimitry Andric #endif
367fa27ce4SDimitry Andric
377fa27ce4SDimitry Andric if (pos == std::string::npos) {
387fa27ce4SDimitry Andric // This file_spec does not contain the zip separator.
397fa27ce4SDimitry Andric // Treat this file_spec as a normal file.
407fa27ce4SDimitry Andric // so_file_offset and so_file_size should be 0.
417fa27ce4SDimitry Andric file_kind = FileKind::eFileKindNormal;
427fa27ce4SDimitry Andric file_path = path;
437fa27ce4SDimitry Andric so_file_offset = 0;
447fa27ce4SDimitry Andric so_file_size = 0;
457fa27ce4SDimitry Andric return true;
467fa27ce4SDimitry Andric }
477fa27ce4SDimitry Andric
487fa27ce4SDimitry Andric // This file_spec is a zip .so path. Extract the zip path and the .so path.
497fa27ce4SDimitry Andric std::string zip_path(path.substr(0, pos));
507fa27ce4SDimitry Andric std::string so_path(path.substr(pos + k_zip_separator.size()));
517fa27ce4SDimitry Andric
527fa27ce4SDimitry Andric #if defined(_WIN32)
537fa27ce4SDimitry Andric // Replace the .so path to use POSIX file separator for file searching inside
547fa27ce4SDimitry Andric // the zip file.
557fa27ce4SDimitry Andric std::replace(so_path.begin(), so_path.end(), '\\', '/');
567fa27ce4SDimitry Andric #endif
577fa27ce4SDimitry Andric
587fa27ce4SDimitry Andric // Try to find the .so file from the zip file.
597fa27ce4SDimitry Andric FileSpec zip_file_spec(zip_path);
607fa27ce4SDimitry Andric uint64_t zip_file_size = FileSystem::Instance().GetByteSize(zip_file_spec);
617fa27ce4SDimitry Andric lldb::DataBufferSP zip_data =
627fa27ce4SDimitry Andric FileSystem::Instance().CreateDataBuffer(zip_file_spec, zip_file_size);
637fa27ce4SDimitry Andric if (ZipFile::Find(zip_data, so_path, so_file_offset, so_file_size)) {
647fa27ce4SDimitry Andric // Found the .so file from the zip file and got the file offset and size.
657fa27ce4SDimitry Andric // Return the zip path. so_file_offset and so_file_size are already set.
667fa27ce4SDimitry Andric file_kind = FileKind::eFileKindZip;
677fa27ce4SDimitry Andric file_path = zip_path;
687fa27ce4SDimitry Andric return true;
697fa27ce4SDimitry Andric }
707fa27ce4SDimitry Andric
717fa27ce4SDimitry Andric return false;
727fa27ce4SDimitry Andric }
73