From: Kazuki Sakamoto Date: Mon, 12 Jun 2023 16:07:53 +0000 (-0700) Subject: [lldb][ObjectFileELF] Set ModuleSpec file offset and size X-Git-Tag: upstream/17.0.6~4409 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b0b9605a544dbf26940a48777af401a419f4e4f1;p=platform%2Fupstream%2Fllvm.git [lldb][ObjectFileELF] Set ModuleSpec file offset and size In Android API level 23 and above, dynamic loader is able to load .so file directly from APK. https://android.googlesource.com/platform/bionic/+/master/ android-changes-for-ndk-developers.md# opening-shared-libraries-directly-from-an-apk ObjectFileELF::GetModuleSpecifications will load a .so file, which is page aligned and uncompressed, directly from a zip file. However it does not set the .so file offset and size to the ModuleSpec. Also crc32 calculation uses more data than the .so file size. Set the .so file offset and size to the ModuleSpec, and set the size to MapFileData length argument. For normal file, file_offset should be zero, and length should be the size of the file. Differential Revision: https://reviews.llvm.org/D152757 --- diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 82171de..727c1fa 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -555,6 +555,14 @@ size_t ObjectFileELF::GetModuleSpecifications( if (header.Parse(data, &header_offset)) { if (data_sp) { ModuleSpec spec(file); + // In Android API level 23 and above, bionic dynamic linker is able to + // load .so file directly from zip file. In that case, .so file is + // page aligned and uncompressed, and this module spec should retain the + // .so file offset and file size to pass through the information from + // lldb-server to LLDB. For normal file, file_offset should be 0, + // length should be the size of the file. + spec.SetObjectOffset(file_offset); + spec.SetObjectSize(length); const uint32_t sub_type = subTypeFromElfHeader(header); spec.GetArchitecture().SetArchitecture( @@ -586,8 +594,12 @@ size_t ObjectFileELF::GetModuleSpecifications( __FUNCTION__, file.GetPath().c_str()); } + // When ELF file does not contain GNU build ID, the later code will + // calculate CRC32 with this data_sp file_offset and length. It is + // important for Android zip .so file, which is a slice of a file, + // to not access the outside of the file slice range. if (data_sp->GetByteSize() < length) - data_sp = MapFileData(file, -1, file_offset); + data_sp = MapFileData(file, length, file_offset); if (data_sp) data.SetData(data_sp); // In case there is header extension in the section #0, the header we diff --git a/lldb/unittests/ObjectFile/ELF/CMakeLists.txt b/lldb/unittests/ObjectFile/ELF/CMakeLists.txt index 4c59ca1..68a78ba 100644 --- a/lldb/unittests/ObjectFile/ELF/CMakeLists.txt +++ b/lldb/unittests/ObjectFile/ELF/CMakeLists.txt @@ -11,5 +11,7 @@ add_lldb_unittest(ObjectFileELFTests set(test_inputs early-section-headers.so + liboffset-test.so + offset-test.bin ) add_unittest_inputs(ObjectFileELFTests "${test_inputs}") diff --git a/lldb/unittests/ObjectFile/ELF/Inputs/liboffset-test.so b/lldb/unittests/ObjectFile/ELF/Inputs/liboffset-test.so new file mode 100644 index 0000000..3aa98db Binary files /dev/null and b/lldb/unittests/ObjectFile/ELF/Inputs/liboffset-test.so differ diff --git a/lldb/unittests/ObjectFile/ELF/Inputs/offset-test.bin b/lldb/unittests/ObjectFile/ELF/Inputs/offset-test.bin new file mode 100644 index 0000000..7de9ecf Binary files /dev/null and b/lldb/unittests/ObjectFile/ELF/Inputs/offset-test.bin differ diff --git a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp b/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp index 0381870..80abc5b 100644 --- a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp +++ b/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp @@ -156,6 +156,39 @@ TEST_F(ObjectFileELFTest, GetModuleSpecifications_EarlySectionHeaders) { EXPECT_EQ(Spec.GetUUID(), Uuid); } +TEST_F(ObjectFileELFTest, GetModuleSpecifications_OffsetSizeWithNormalFile) { + std::string SO = GetInputFilePath("liboffset-test.so"); + ModuleSpecList Specs; + ASSERT_EQ(1u, ObjectFile::GetModuleSpecifications(FileSpec(SO), 0, 0, Specs)); + ModuleSpec Spec; + ASSERT_TRUE(Specs.GetModuleSpecAtIndex(0, Spec)) ; + UUID Uuid; + Uuid.SetFromStringRef("7D6E4738"); + EXPECT_EQ(Spec.GetUUID(), Uuid); + EXPECT_EQ(Spec.GetObjectOffset(), 0UL); + EXPECT_EQ(Spec.GetObjectSize(), 3600UL); + EXPECT_EQ(FileSystem::Instance().GetByteSize(FileSpec(SO)), 3600UL); +} + +TEST_F(ObjectFileELFTest, GetModuleSpecifications_OffsetSizeWithOffsetFile) { + // The contents of offset-test.bin are + // - 0-1023: \0 + // - 1024-4623: liboffset-test.so (offset: 1024, size: 3600, CRC32: 7D6E4738) + // - 4624-4639: \0 + std::string SO = GetInputFilePath("offset-test.bin"); + ModuleSpecList Specs; + ASSERT_EQ( + 1u, ObjectFile::GetModuleSpecifications(FileSpec(SO), 1024, 3600, Specs)); + ModuleSpec Spec; + ASSERT_TRUE(Specs.GetModuleSpecAtIndex(0, Spec)) ; + UUID Uuid; + Uuid.SetFromStringRef("7D6E4738"); + EXPECT_EQ(Spec.GetUUID(), Uuid); + EXPECT_EQ(Spec.GetObjectOffset(), 1024UL); + EXPECT_EQ(Spec.GetObjectSize(), 3600UL); + EXPECT_EQ(FileSystem::Instance().GetByteSize(FileSpec(SO)), 4640UL); +} + TEST_F(ObjectFileELFTest, GetSymtab_NoSymEntryPointArmThumbAddressClass) { /* // nosym-entrypoint-arm-thumb.s