1*06c3fb27SDimitry Andric //===-- ZipFileResolver.cpp -----------------------------------------------===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric
9*06c3fb27SDimitry Andric #include "lldb/Host/common/ZipFileResolver.h"
10*06c3fb27SDimitry Andric #include "lldb/Host/FileSystem.h"
11*06c3fb27SDimitry Andric #include "lldb/Utility/DataBuffer.h"
12*06c3fb27SDimitry Andric #include "lldb/Utility/FileSpec.h"
13*06c3fb27SDimitry Andric #include "lldb/Utility/ZipFile.h"
14*06c3fb27SDimitry Andric
15*06c3fb27SDimitry Andric using namespace lldb_private;
16*06c3fb27SDimitry Andric using namespace llvm::support;
17*06c3fb27SDimitry 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)18*06c3fb27SDimitry Andric bool ZipFileResolver::ResolveSharedLibraryPath(const FileSpec &file_spec,
19*06c3fb27SDimitry Andric FileKind &file_kind,
20*06c3fb27SDimitry Andric std::string &file_path,
21*06c3fb27SDimitry Andric lldb::offset_t &so_file_offset,
22*06c3fb27SDimitry Andric lldb::offset_t &so_file_size) {
23*06c3fb27SDimitry Andric // When bionic loads .so file from APK or zip file, this file_spec will be
24*06c3fb27SDimitry Andric // "zip_path!/so_path". Otherwise it is just a normal file path.
25*06c3fb27SDimitry Andric static constexpr llvm::StringLiteral k_zip_separator("!/");
26*06c3fb27SDimitry Andric std::string path(file_spec.GetPath());
27*06c3fb27SDimitry Andric size_t pos = path.find(k_zip_separator);
28*06c3fb27SDimitry Andric
29*06c3fb27SDimitry Andric #if defined(_WIN32)
30*06c3fb27SDimitry Andric // When the file_spec is resolved as a Windows path, the zip .so path will be
31*06c3fb27SDimitry Andric // "zip_path!\so_path". Support both patterns on Windows.
32*06c3fb27SDimitry Andric static constexpr llvm::StringLiteral k_zip_separator_win("!\\");
33*06c3fb27SDimitry Andric if (pos == std::string::npos)
34*06c3fb27SDimitry Andric pos = path.find(k_zip_separator_win);
35*06c3fb27SDimitry Andric #endif
36*06c3fb27SDimitry Andric
37*06c3fb27SDimitry Andric if (pos == std::string::npos) {
38*06c3fb27SDimitry Andric // This file_spec does not contain the zip separator.
39*06c3fb27SDimitry Andric // Treat this file_spec as a normal file.
40*06c3fb27SDimitry Andric // so_file_offset and so_file_size should be 0.
41*06c3fb27SDimitry Andric file_kind = FileKind::eFileKindNormal;
42*06c3fb27SDimitry Andric file_path = path;
43*06c3fb27SDimitry Andric so_file_offset = 0;
44*06c3fb27SDimitry Andric so_file_size = 0;
45*06c3fb27SDimitry Andric return true;
46*06c3fb27SDimitry Andric }
47*06c3fb27SDimitry Andric
48*06c3fb27SDimitry Andric // This file_spec is a zip .so path. Extract the zip path and the .so path.
49*06c3fb27SDimitry Andric std::string zip_path(path.substr(0, pos));
50*06c3fb27SDimitry Andric std::string so_path(path.substr(pos + k_zip_separator.size()));
51*06c3fb27SDimitry Andric
52*06c3fb27SDimitry Andric #if defined(_WIN32)
53*06c3fb27SDimitry Andric // Replace the .so path to use POSIX file separator for file searching inside
54*06c3fb27SDimitry Andric // the zip file.
55*06c3fb27SDimitry Andric std::replace(so_path.begin(), so_path.end(), '\\', '/');
56*06c3fb27SDimitry Andric #endif
57*06c3fb27SDimitry Andric
58*06c3fb27SDimitry Andric // Try to find the .so file from the zip file.
59*06c3fb27SDimitry Andric FileSpec zip_file_spec(zip_path);
60*06c3fb27SDimitry Andric uint64_t zip_file_size = FileSystem::Instance().GetByteSize(zip_file_spec);
61*06c3fb27SDimitry Andric lldb::DataBufferSP zip_data =
62*06c3fb27SDimitry Andric FileSystem::Instance().CreateDataBuffer(zip_file_spec, zip_file_size);
63*06c3fb27SDimitry Andric if (ZipFile::Find(zip_data, so_path, so_file_offset, so_file_size)) {
64*06c3fb27SDimitry Andric // Found the .so file from the zip file and got the file offset and size.
65*06c3fb27SDimitry Andric // Return the zip path. so_file_offset and so_file_size are already set.
66*06c3fb27SDimitry Andric file_kind = FileKind::eFileKindZip;
67*06c3fb27SDimitry Andric file_path = zip_path;
68*06c3fb27SDimitry Andric return true;
69*06c3fb27SDimitry Andric }
70*06c3fb27SDimitry Andric
71*06c3fb27SDimitry Andric return false;
72*06c3fb27SDimitry Andric }
73