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