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