[Lldb-commits] [lldb] 12dee9d - [lldb][Android] Support zip .so file
Kazuki Sakamoto via lldb-commits
lldb-commits at lists.llvm.org
Tue Jun 20 15:41:37 PDT 2023
Author: Kazuki Sakamoto
Date: 2023-06-20T15:21:46-07:00
New Revision: 12dee9d3cd762d9754e2adadffa13c1cce85cf07
URL: https://github.com/llvm/llvm-project/commit/12dee9d3cd762d9754e2adadffa13c1cce85cf07
DIFF: https://github.com/llvm/llvm-project/commit/12dee9d3cd762d9754e2adadffa13c1cce85cf07.diff
LOG: [lldb][Android] Support zip .so file
In Android API level 23 and above, dynamic loader is able to load .so file
directly from APK, which is zip file.
https://android.googlesource.com/platform/bionic/+/master/
android-changes-for-ndk-developers.md#
opening-shared-libraries-directly-from-an-apk
The .so file is page aligned and uncompressed, so
ObjectFileELF::GetModuleSpecifications works with .so file offset and size
directly from zip file without extracting it. (D152757)
GDBRemoteCommunicationServerCommon::GetModuleInfo returns a module spec to LLDB
with "zip_path!/so_path" file spec, which is passed through from Android
dynamic loader, and the .so file offset and size.
PlatformAndroid::DownloadModuleSlice uses 'shell dd' to download the .so file
slice from the zip file with the .so file offset and size.
Differential Revision: https://reviews.llvm.org/D152759
Added:
lldb/include/lldb/Host/common/ZipFileResolver.h
lldb/include/lldb/Utility/ZipFile.h
lldb/source/Host/common/ZipFileResolver.cpp
lldb/source/Utility/ZipFile.cpp
lldb/unittests/Host/common/CMakeLists.txt
lldb/unittests/Host/common/Inputs/zip-test.zip
lldb/unittests/Host/common/ZipFileResolverTest.cpp
Modified:
lldb/source/Host/CMakeLists.txt
lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
lldb/source/Utility/CMakeLists.txt
lldb/unittests/Host/CMakeLists.txt
Removed:
################################################################################
diff --git a/lldb/include/lldb/Host/common/ZipFileResolver.h b/lldb/include/lldb/Host/common/ZipFileResolver.h
new file mode 100644
index 0000000000000..ec7151f3e57c9
--- /dev/null
+++ b/lldb/include/lldb/Host/common/ZipFileResolver.h
@@ -0,0 +1,40 @@
+//===-- ZipFileResolver.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_HOST_ZIPFILERESOLVER_H
+#define LLDB_HOST_ZIPFILERESOLVER_H
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+/// In Android API level 23 and above, bionic dynamic linker is able to load
+/// .so file directly from APK or .zip file. This is a utility class to resolve
+/// the file spec in order to get the zip path and the .so file offset and size
+/// if the file spec contains "zip_path!/so_path".
+/// https://android.googlesource.com/platform/bionic/+/master/
+/// android-changes-for-ndk-developers.md#
+/// opening-shared-libraries-directly-from-an-apk
+class ZipFileResolver {
+public:
+ enum FileKind {
+ eFileKindInvalid = 0,
+ eFileKindNormal,
+ eFileKindZip,
+ };
+
+ static bool ResolveSharedLibraryPath(const FileSpec &file_spec,
+ FileKind &file_kind,
+ std::string &file_path,
+ lldb::offset_t &so_file_offset,
+ lldb::offset_t &so_file_size);
+};
+
+} // end of namespace lldb_private
+
+#endif // LLDB_HOST_ZIPFILERESOLVER_H
diff --git a/lldb/include/lldb/Utility/ZipFile.h b/lldb/include/lldb/Utility/ZipFile.h
new file mode 100644
index 0000000000000..cddd6c44ca638
--- /dev/null
+++ b/lldb/include/lldb/Utility/ZipFile.h
@@ -0,0 +1,30 @@
+//===-- ZipFile.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_ZIPFILE_H
+#define LLDB_UTILITY_ZIPFILE_H
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+/// In Android API level 23 and above, bionic dynamic linker is able to load
+/// .so file directly from APK or .zip file. This is a utility class to find
+/// .so file offset and size from zip file.
+/// https://android.googlesource.com/platform/bionic/+/master/
+/// android-changes-for-ndk-developers.md#
+/// opening-shared-libraries-directly-from-an-apk
+class ZipFile {
+public:
+ static bool Find(lldb::DataBufferSP zip_data, const llvm::StringRef file_path,
+ lldb::offset_t &file_offset, lldb::offset_t &file_size);
+};
+
+} // end of namespace lldb_private
+
+#endif // LLDB_UTILITY_ZIPFILE_H
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index 91f353e50b190..5451c2bcf776e 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -42,6 +42,7 @@ add_host_subdirectory(common
common/ThreadLauncher.cpp
common/UDPSocket.cpp
common/XML.cpp
+ common/ZipFileResolver.cpp
)
if (LLDB_ENABLE_LIBEDIT)
diff --git a/lldb/source/Host/common/ZipFileResolver.cpp b/lldb/source/Host/common/ZipFileResolver.cpp
new file mode 100644
index 0000000000000..abb914cb9ae42
--- /dev/null
+++ b/lldb/source/Host/common/ZipFileResolver.cpp
@@ -0,0 +1,57 @@
+//===-- ZipFileResolver.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/ZipFileResolver.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/ZipFile.h"
+
+using namespace lldb_private;
+using namespace llvm::support;
+
+bool ZipFileResolver::ResolveSharedLibraryPath(const FileSpec &file_spec,
+ FileKind &file_kind,
+ std::string &file_path,
+ lldb::offset_t &so_file_offset,
+ lldb::offset_t &so_file_size) {
+ // When bionic loads .so file from APK or zip file, this file_spec will be
+ // "zip_path!/so_path". Otherwise it is just a normal file path.
+ static constexpr llvm::StringLiteral k_zip_separator("!/");
+ std::string path(file_spec.GetPath());
+ size_t pos = path.find(k_zip_separator);
+ if (pos == std::string::npos) {
+ // This file_spec does not contain the zip separator.
+ // Treat this file_spec as a normal file.
+ // so_file_offset and so_file_size should be 0.
+ file_kind = FileKind::eFileKindNormal;
+ file_path = path;
+ so_file_offset = 0;
+ so_file_size = 0;
+ return true;
+ }
+
+ // This file_spec is a zip .so path. Extract the zip path and the .so path.
+ std::string zip_path(path.substr(0, pos));
+ std::string so_path(path.substr(pos + k_zip_separator.size()));
+
+ // Try to find the .so file from the zip file.
+ FileSpec zip_file_spec(zip_path);
+ uint64_t zip_file_size = FileSystem::Instance().GetByteSize(zip_file_spec);
+ lldb::DataBufferSP zip_data =
+ FileSystem::Instance().CreateDataBuffer(zip_file_spec, zip_file_size);
+ if (ZipFile::Find(zip_data, so_path, so_file_offset, so_file_size)) {
+ // Found the .so file from the zip file and got the file offset and size.
+ // Return the zip path. so_file_offset and so_file_size are already set.
+ file_kind = FileKind::eFileKindZip;
+ file_path = zip_path;
+ return true;
+ }
+
+ return false;
+}
diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
index 64c1d1e48a9ef..4b09e8b253412 100644
--- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
+++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
@@ -234,10 +234,32 @@ Status PlatformAndroid::DownloadModuleSlice(const FileSpec &src_file_spec,
const uint64_t src_offset,
const uint64_t src_size,
const FileSpec &dst_file_spec) {
- if (src_offset != 0)
- return Status("Invalid offset - %" PRIu64, src_offset);
+ // In Android API level 23 and above, dynamic loader is able to load .so
+ // file directly from APK. In that case, src_offset will be an non-zero.
+ if (src_offset == 0) // Use GetFile for a normal file.
+ return GetFile(src_file_spec, dst_file_spec);
- return GetFile(src_file_spec, dst_file_spec);
+ std::string source_file = src_file_spec.GetPath(false);
+ if (source_file.find('\'') != std::string::npos)
+ return Status("Doesn't support single-quotes in filenames");
+
+ // For zip .so file, src_file_spec will be "zip_path!/so_path".
+ // Extract "zip_path" from the source_file.
+ static constexpr llvm::StringLiteral k_zip_separator("!/");
+ size_t pos = source_file.find(k_zip_separator);
+ if (pos != std::string::npos)
+ source_file = source_file.substr(0, pos);
+
+ AdbClient adb(m_device_id);
+
+ // Use 'shell dd' to download the file slice with the offset and size.
+ char cmd[PATH_MAX];
+ snprintf(cmd, sizeof(cmd),
+ "dd if='%s' iflag=skip_bytes,count_bytes "
+ "skip=%" PRIu64 " count=%" PRIu64 " status=none",
+ source_file.c_str(), src_offset, src_size);
+
+ return adb.ShellToFile(cmd, minutes(1), dst_file_spec);
}
Status PlatformAndroid::DisconnectRemote() {
@@ -310,15 +332,16 @@ Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
// Create file remover for the temporary directory created on the device
std::unique_ptr<std::string, std::function<void(std::string *)>>
- tmpdir_remover(&tmpdir, [&adb](std::string *s) {
- StreamString command;
- command.Printf("rm -rf %s", s->c_str());
- Status error = adb.Shell(command.GetData(), seconds(5), nullptr);
+ tmpdir_remover(&tmpdir, [&adb](std::string *s) {
+ StreamString command;
+ command.Printf("rm -rf %s", s->c_str());
+ Status error = adb.Shell(command.GetData(), seconds(5), nullptr);
- Log *log = GetLog(LLDBLog::Platform);
- if (log && error.Fail())
- LLDB_LOGF(log, "Failed to remove temp directory: %s", error.AsCString());
- });
+ Log *log = GetLog(LLDBLog::Platform);
+ if (log && error.Fail())
+ LLDB_LOGF(log, "Failed to remove temp directory: %s",
+ error.AsCString());
+ });
FileSpec symfile_platform_filespec(tmpdir);
symfile_platform_filespec.AppendPathComponent("symbolized.oat");
@@ -344,15 +367,15 @@ bool PlatformAndroid::GetRemoteOSVersion() {
llvm::StringRef
PlatformAndroid::GetLibdlFunctionDeclarations(lldb_private::Process *process) {
SymbolContextList matching_symbols;
- std::vector<const char *> dl_open_names = { "__dl_dlopen", "dlopen" };
+ std::vector<const char *> dl_open_names = {"__dl_dlopen", "dlopen"};
const char *dl_open_name = nullptr;
Target &target = process->GetTarget();
- for (auto name: dl_open_names) {
+ for (auto name : dl_open_names) {
target.GetImages().FindFunctionSymbols(
ConstString(name), eFunctionNameTypeFull, matching_symbols);
if (matching_symbols.GetSize()) {
- dl_open_name = name;
- break;
+ dl_open_name = name;
+ break;
}
}
// Older platform versions have the dl function symbols mangled
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index 9e90e98b1f2ab..b4fb5b68dd41f 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -44,9 +44,9 @@
#ifdef __ANDROID__
#include "lldb/Host/android/HostInfoAndroid.h"
+#include "lldb/Host/common/ZipFileResolver.h"
#endif
-
using namespace lldb;
using namespace lldb_private::process_gdb_remote;
using namespace lldb_private;
@@ -1138,7 +1138,7 @@ GDBRemoteCommunicationServerCommon::Handle_qModuleInfo(
response.PutCString("file_path:");
response.PutStringAsRawHex8(
- matched_module_spec.GetFileSpec().GetPath().c_str());
+ matched_module_spec.GetFileSpec().GetPath().c_str());
response.PutChar(';');
response.PutCString("file_offset:");
response.PutHex64(file_offset);
@@ -1326,17 +1326,50 @@ GDBRemoteCommunicationServerCommon::GetModuleInfo(llvm::StringRef module_path,
const FileSpec module_path_spec =
FindModuleFile(req_module_path_spec.GetPath(), arch);
- const ModuleSpec module_spec(module_path_spec, arch);
+
+ lldb::offset_t file_offset = 0;
+ lldb::offset_t file_size = 0;
+#ifdef __ANDROID__
+ // In Android API level 23 and above, dynamic loader is able to load .so file
+ // directly from zip file. In that case, module_path will be
+ // "zip_path!/so_path". Resolve the zip file path, .so file offset and size.
+ ZipFileResolver::FileKind file_kind = ZipFileResolver::eFileKindInvalid;
+ std::string file_path;
+ if (!ZipFileResolver::ResolveSharedLibraryPath(
+ module_path_spec, file_kind, file_path, file_offset, file_size)) {
+ return ModuleSpec();
+ }
+ lldbassert(file_kind != ZipFileResolver::eFileKindInvalid);
+ // For zip .so file, this file_path will contain only the actual zip file
+ // path for the object file processing. Otherwise it is the same as
+ // module_path.
+ const FileSpec actual_module_path_spec(file_path);
+#else
+ // It is just module_path_spec reference for other platforms.
+ const FileSpec &actual_module_path_spec = module_path_spec;
+#endif
+
+ const ModuleSpec module_spec(actual_module_path_spec, arch);
ModuleSpecList module_specs;
- if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0,
- module_specs))
+ if (!ObjectFile::GetModuleSpecifications(actual_module_path_spec, file_offset,
+ file_size, module_specs))
return ModuleSpec();
ModuleSpec matched_module_spec;
if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
return ModuleSpec();
+#ifdef __ANDROID__
+ if (file_kind == ZipFileResolver::eFileKindZip) {
+ // For zip .so file, matched_module_spec contains only the actual zip file
+ // path for the object file processing. Overwrite the matched_module_spec
+ // file spec with the original module_path_spec to pass "zip_path!/so_path"
+ // through to PlatformAndroid::DownloadModuleSlice.
+ *matched_module_spec.GetFileSpecPtr() = module_path_spec;
+ }
+#endif
+
return matched_module_spec;
}
diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt
index d8c18b189f6c7..b376ace0ebe3d 100644
--- a/lldb/source/Utility/CMakeLists.txt
+++ b/lldb/source/Utility/CMakeLists.txt
@@ -74,6 +74,7 @@ add_lldb_library(lldbUtility NO_INTERNAL_DEPENDENCIES
VASprintf.cpp
VMRange.cpp
XcodeSDK.cpp
+ ZipFile.cpp
LINK_LIBS
${LLDB_SYSTEM_LIBS}
diff --git a/lldb/source/Utility/ZipFile.cpp b/lldb/source/Utility/ZipFile.cpp
new file mode 100644
index 0000000000000..b8ed956cbfcb2
--- /dev/null
+++ b/lldb/source/Utility/ZipFile.cpp
@@ -0,0 +1,180 @@
+//===-- ZipFile.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/ZipFile.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/FileSpec.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lldb_private;
+using namespace llvm::support;
+
+namespace {
+
+// Zip headers.
+// https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
+
+// The end of central directory record.
+struct EocdRecord {
+ static constexpr char kSignature[] = {0x50, 0x4b, 0x05, 0x06};
+ char signature[sizeof(kSignature)];
+ unaligned_uint16_t disks;
+ unaligned_uint16_t cd_start_disk;
+ unaligned_uint16_t cds_on_this_disk;
+ unaligned_uint16_t cd_records;
+ unaligned_uint32_t cd_size;
+ unaligned_uint32_t cd_offset;
+ unaligned_uint16_t comment_length;
+};
+
+// Logical find limit for the end of central directory record.
+const size_t kEocdRecordFindLimit =
+ sizeof(EocdRecord) +
+ std::numeric_limits<decltype(EocdRecord::comment_length)>::max();
+
+// Central directory record.
+struct CdRecord {
+ static constexpr char kSignature[] = {0x50, 0x4b, 0x01, 0x02};
+ char signature[sizeof(kSignature)];
+ unaligned_uint16_t version_made_by;
+ unaligned_uint16_t version_needed_to_extract;
+ unaligned_uint16_t general_purpose_bit_flag;
+ unaligned_uint16_t compression_method;
+ unaligned_uint16_t last_modification_time;
+ unaligned_uint16_t last_modification_date;
+ unaligned_uint32_t crc32;
+ unaligned_uint32_t compressed_size;
+ unaligned_uint32_t uncompressed_size;
+ unaligned_uint16_t file_name_length;
+ unaligned_uint16_t extra_field_length;
+ unaligned_uint16_t comment_length;
+ unaligned_uint16_t file_start_disk;
+ unaligned_uint16_t internal_file_attributes;
+ unaligned_uint32_t external_file_attributes;
+ unaligned_uint32_t local_file_header_offset;
+};
+// Immediately after CdRecord,
+// - file name (file_name_length)
+// - extra field (extra_field_length)
+// - comment (comment_length)
+
+// Local file header.
+struct LocalFileHeader {
+ static constexpr char kSignature[] = {0x50, 0x4b, 0x03, 0x04};
+ char signature[sizeof(kSignature)];
+ unaligned_uint16_t version_needed_to_extract;
+ unaligned_uint16_t general_purpose_bit_flag;
+ unaligned_uint16_t compression_method;
+ unaligned_uint16_t last_modification_time;
+ unaligned_uint16_t last_modification_date;
+ unaligned_uint32_t crc32;
+ unaligned_uint32_t compressed_size;
+ unaligned_uint32_t uncompressed_size;
+ unaligned_uint16_t file_name_length;
+ unaligned_uint16_t extra_field_length;
+};
+// Immediately after LocalFileHeader,
+// - file name (file_name_length)
+// - extra field (extra_field_length)
+// - file data (should be compressed_size == uncompressed_size, page aligned)
+
+const EocdRecord *FindEocdRecord(lldb::DataBufferSP zip_data) {
+ // Find backward the end of central directory record from the end of the zip
+ // file to the find limit.
+ const uint8_t *zip_data_end = zip_data->GetBytes() + zip_data->GetByteSize();
+ const uint8_t *find_limit = zip_data_end - kEocdRecordFindLimit;
+ const uint8_t *p = zip_data_end - sizeof(EocdRecord);
+ for (; p >= zip_data->GetBytes() && p >= find_limit; p--) {
+ auto eocd = reinterpret_cast<const EocdRecord *>(p);
+ if (::memcmp(eocd->signature, EocdRecord::kSignature,
+ sizeof(EocdRecord::kSignature)) == 0) {
+ // Found the end of central directory. Sanity check the values.
+ if (eocd->cd_records * sizeof(CdRecord) > eocd->cd_size ||
+ zip_data->GetBytes() + eocd->cd_offset + eocd->cd_size > p)
+ return nullptr;
+
+ // This is a valid end of central directory record.
+ return eocd;
+ }
+ }
+ return nullptr;
+}
+
+bool GetFile(lldb::DataBufferSP zip_data, uint32_t local_file_header_offset,
+ lldb::offset_t &file_offset, lldb::offset_t &file_size) {
+ auto local_file_header = reinterpret_cast<const LocalFileHeader *>(
+ zip_data->GetBytes() + local_file_header_offset);
+ // The signature should match.
+ if (::memcmp(local_file_header->signature, LocalFileHeader::kSignature,
+ sizeof(LocalFileHeader::kSignature)) != 0)
+ return false;
+
+ auto file_data = reinterpret_cast<const uint8_t *>(local_file_header + 1) +
+ local_file_header->file_name_length +
+ local_file_header->extra_field_length;
+ // File should be uncompressed.
+ if (local_file_header->compressed_size !=
+ local_file_header->uncompressed_size)
+ return false;
+
+ // This file is valid. Return the file offset and size.
+ file_offset = file_data - zip_data->GetBytes();
+ file_size = local_file_header->uncompressed_size;
+ return true;
+}
+
+bool FindFile(lldb::DataBufferSP zip_data, const EocdRecord *eocd,
+ const llvm::StringRef file_path, lldb::offset_t &file_offset,
+ lldb::offset_t &file_size) {
+ // Find the file from the central directory records.
+ auto cd = reinterpret_cast<const CdRecord *>(zip_data->GetBytes() +
+ eocd->cd_offset);
+ size_t cd_records = eocd->cd_records;
+ for (size_t i = 0; i < cd_records; i++) {
+ // The signature should match.
+ if (::memcmp(cd->signature, CdRecord::kSignature,
+ sizeof(CdRecord::kSignature)) != 0)
+ return false;
+
+ // Sanity check the file name values.
+ auto file_name = reinterpret_cast<const char *>(cd + 1);
+ size_t file_name_length = cd->file_name_length;
+ if (file_name + file_name_length >= reinterpret_cast<const char *>(eocd) ||
+ file_name_length == 0)
+ return false;
+
+ // Compare the file name.
+ if (file_path == llvm::StringRef(file_name, file_name_length)) {
+ // Found the file.
+ return GetFile(zip_data, cd->local_file_header_offset, file_offset,
+ file_size);
+ } else {
+ // Skip to the next central directory record.
+ cd = reinterpret_cast<const CdRecord *>(
+ reinterpret_cast<const char *>(cd) + sizeof(CdRecord) +
+ cd->file_name_length + cd->extra_field_length + cd->comment_length);
+ // Sanity check the pointer.
+ if (reinterpret_cast<const char *>(cd) >=
+ reinterpret_cast<const char *>(eocd))
+ return false;
+ }
+ }
+
+ return false;
+}
+
+} // end anonymous namespace
+
+bool ZipFile::Find(lldb::DataBufferSP zip_data, const llvm::StringRef file_path,
+ lldb::offset_t &file_offset, lldb::offset_t &file_size) {
+ const EocdRecord *eocd = FindEocdRecord(zip_data);
+ if (!eocd)
+ return false;
+
+ return FindFile(zip_data, eocd, file_path, file_offset, file_size);
+}
diff --git a/lldb/unittests/Host/CMakeLists.txt b/lldb/unittests/Host/CMakeLists.txt
index 68bf50d0a7312..c959478970d18 100644
--- a/lldb/unittests/Host/CMakeLists.txt
+++ b/lldb/unittests/Host/CMakeLists.txt
@@ -38,3 +38,5 @@ add_lldb_unittest(HostTests
LLVMTestingSupport
LLVMTargetParser
)
+
+add_subdirectory(common)
diff --git a/lldb/unittests/Host/common/CMakeLists.txt b/lldb/unittests/Host/common/CMakeLists.txt
new file mode 100644
index 0000000000000..2934e6f0b4315
--- /dev/null
+++ b/lldb/unittests/Host/common/CMakeLists.txt
@@ -0,0 +1,15 @@
+set (FILES
+ ZipFileResolverTest.cpp
+)
+
+add_lldb_unittest(HostCommonTests
+ ${FILES}
+ LINK_LIBS
+ lldbHost
+ lldbUtilityHelpers
+ )
+
+set(test_inputs
+ zip-test.zip
+ )
+add_unittest_inputs(HostCommonTests "${test_inputs}")
diff --git a/lldb/unittests/Host/common/Inputs/zip-test.zip b/lldb/unittests/Host/common/Inputs/zip-test.zip
new file mode 100644
index 0000000000000..a077b53d5b843
Binary files /dev/null and b/lldb/unittests/Host/common/Inputs/zip-test.zip
diff er
diff --git a/lldb/unittests/Host/common/ZipFileResolverTest.cpp b/lldb/unittests/Host/common/ZipFileResolverTest.cpp
new file mode 100644
index 0000000000000..12aba31411305
--- /dev/null
+++ b/lldb/unittests/Host/common/ZipFileResolverTest.cpp
@@ -0,0 +1,72 @@
+//===-- ZipFileResolverTest.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/ZipFileResolver.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/TestUtilities.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace llvm;
+
+namespace {
+class ZipFileResolverTest : public ::testing::Test {
+ SubsystemRAII<FileSystem> subsystems;
+};
+
+std::string TestZipPath() {
+ FileSpec zip_spec(GetInputFilePath("zip-test.zip"));
+ FileSystem::Instance().Resolve(zip_spec);
+ return zip_spec.GetPath();
+}
+} // namespace
+
+TEST_F(ZipFileResolverTest, ResolveSharedLibraryPathWithNormalFile) {
+ const FileSpec file_spec("/system/lib64/libtest.so");
+
+ ZipFileResolver::FileKind file_kind;
+ std::string file_path;
+ lldb::offset_t file_offset;
+ lldb::offset_t file_size;
+ ASSERT_TRUE(ZipFileResolver::ResolveSharedLibraryPath(
+ file_spec, file_kind, file_path, file_offset, file_size));
+
+ EXPECT_EQ(file_kind, ZipFileResolver::FileKind::eFileKindNormal);
+ EXPECT_EQ(file_path, file_spec.GetPath());
+ EXPECT_EQ(file_offset, 0UL);
+ EXPECT_EQ(file_size, 0UL);
+}
+
+TEST_F(ZipFileResolverTest, ResolveSharedLibraryPathWithZipMissing) {
+ const std::string zip_path = TestZipPath();
+ const FileSpec file_spec(zip_path + "!/lib/arm64-v8a/libmissing.so");
+
+ ZipFileResolver::FileKind file_kind;
+ std::string file_path;
+ lldb::offset_t file_offset;
+ lldb::offset_t file_size;
+ ASSERT_FALSE(ZipFileResolver::ResolveSharedLibraryPath(
+ file_spec, file_kind, file_path, file_offset, file_size));
+}
+
+TEST_F(ZipFileResolverTest, ResolveSharedLibraryPathWithZipExisting) {
+ const std::string zip_path = TestZipPath();
+ const FileSpec file_spec(zip_path + "!/lib/arm64-v8a/libzip-test.so");
+
+ ZipFileResolver::FileKind file_kind;
+ std::string file_path;
+ lldb::offset_t file_offset;
+ lldb::offset_t file_size;
+ ASSERT_TRUE(ZipFileResolver::ResolveSharedLibraryPath(
+ file_spec, file_kind, file_path, file_offset, file_size));
+
+ EXPECT_EQ(file_kind, ZipFileResolver::FileKind::eFileKindZip);
+ EXPECT_EQ(file_path, zip_path);
+ EXPECT_EQ(file_offset, 4096UL);
+ EXPECT_EQ(file_size, 3600UL);
+}
More information about the lldb-commits
mailing list