summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Neill <richard.neill@arm.com>2024-04-22 16:21:56 +0100
committerSteven Moreland <smoreland@google.com>2024-05-06 16:28:01 +0000
commita463b165408222e3ef6a2052ef31b1560b3afea6 (patch)
tree8b2bfb8f19a1385ae5c272333c67dd36ac69dec1
parent53da12c60f200d64b08d9c079593da2cff8f43d2 (diff)
downloadart-a463b165408222e3ef6a2052ef31b1560b3afea6.tar.gz
Add ELF alignment mismatch test
When executing 'standalone' tests that run against an on-device deployed ART APEX (see test/README.atest.md), the test ART configuration and the existing deployed ART configuration must be compatible for the testing to be meaningful. One source of incompatibility is ELF segment alignment, where the value of the constexpr kElfSegmentAlignment in the test build must match the ELF files that are compiled on-device. Many tests are expected to fail if there is a mismatch, but the runtime errors could be difficult to debug. This patch adds an ELF alignment mismatch test to clearly identify when this incompatibility occurs, to ease debugging in the future. The test determines the value of kElfSegmentAlignment used by the on-device ART APEX by reading the alignment of the boot.oat file. Bug: 333480073 As the ELF segment alignment is controlled by enabling page-agnostic mode (kPageSizeAgnostic), tests were run on Oriole running page-agnostic 4K and 16K as well legacy constexpr 4K. Test failures were confirmed when page-agnostic standalone tests were run against a constexpr 4K ART APEX, and vice versa. Test: art/tools/run-gtests.sh Test: atest ArtGtestsTargetChroot Test: atest art_standalone_* -- --abi arm64-v8a Test: atest art_standalone_runtime_tests -- --abi arm64-v8a Change-Id: I1deac98167443766686c7a2c5b6f6c33166c9530
-rw-r--r--runtime/oat/elf_file.cc18
-rw-r--r--runtime/oat/elf_file.h2
-rw-r--r--runtime/oat/elf_file_impl.h3
-rw-r--r--runtime/runtime_test.cc34
4 files changed, 57 insertions, 0 deletions
diff --git a/runtime/oat/elf_file.cc b/runtime/oat/elf_file.cc
index 30e0197470..91af410471 100644
--- a/runtime/oat/elf_file.cc
+++ b/runtime/oat/elf_file.cc
@@ -1025,6 +1025,20 @@ bool ElfFileImpl<ElfTypes>::GetLoadedSize(size_t* size, std::string* error_msg)
return GetLoadedAddressRange(&vaddr_begin, size, error_msg);
}
+template <typename ElfTypes>
+size_t ElfFileImpl<ElfTypes>::GetElfSegmentAlignmentFromFile() const {
+ // Return the alignment of the first loadable program segment.
+ for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
+ Elf_Phdr* program_header = GetProgramHeader(i);
+ if (program_header->p_type != PT_LOAD) {
+ continue;
+ }
+ return program_header->p_align;
+ }
+ LOG(ERROR) << "No loadable segment found in ELF file " << file_path_;
+ return 0;
+}
+
// Base on bionic phdr_table_get_load_size
template <typename ElfTypes>
bool ElfFileImpl<ElfTypes>::GetLoadedAddressRange(/*out*/uint8_t** vaddr_begin,
@@ -1671,6 +1685,10 @@ bool ElfFile::GetLoadedSize(size_t* size, std::string* error_msg) const {
DELEGATE_TO_IMPL(GetLoadedSize, size, error_msg);
}
+size_t ElfFile::GetElfSegmentAlignmentFromFile() const {
+ DELEGATE_TO_IMPL(GetElfSegmentAlignmentFromFile);
+}
+
bool ElfFile::Strip(File* file, std::string* error_msg) {
std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, /*low_4gb=*/false, error_msg));
if (elf_file.get() == nullptr) {
diff --git a/runtime/oat/elf_file.h b/runtime/oat/elf_file.h
index a9218106de..125b4441f1 100644
--- a/runtime/oat/elf_file.h
+++ b/runtime/oat/elf_file.h
@@ -82,6 +82,8 @@ class ElfFile {
bool GetLoadedSize(size_t* size, std::string* error_msg) const;
+ size_t GetElfSegmentAlignmentFromFile() const;
+
// Strip an ELF file of unneeded debugging information.
// Returns true on success, false on failure.
static bool Strip(File* file, std::string* error_msg);
diff --git a/runtime/oat/elf_file_impl.h b/runtime/oat/elf_file_impl.h
index ffc6a2c081..67c60e906c 100644
--- a/runtime/oat/elf_file_impl.h
+++ b/runtime/oat/elf_file_impl.h
@@ -116,6 +116,9 @@ class ElfFileImpl {
// Retrieves the expected size when the file is loaded at runtime. Returns true if successful.
bool GetLoadedSize(size_t* size, std::string* error_msg) const;
+ // Get the alignment of the first loadable program segment. Return 0 if no loadable segment found.
+ size_t GetElfSegmentAlignmentFromFile() const;
+
// Load segments into memory based on PT_LOAD program headers.
// executable is true at run time, false at compile time.
bool Load(File* file,
diff --git a/runtime/runtime_test.cc b/runtime/runtime_test.cc
index 210ad7d711..cd0c862d82 100644
--- a/runtime/runtime_test.cc
+++ b/runtime/runtime_test.cc
@@ -21,9 +21,14 @@
#include "android-base/logging.h"
#include "base/locks.h"
#include "base/mutex.h"
+#include "oat/elf_file.h"
#include "runtime.h"
#include "thread-current-inl.h"
+#ifdef ART_TARGET_ANDROID
+#include "android-base/properties.h"
+#endif
+
namespace art HIDDEN {
class RuntimeTest : public CommonRuntimeTest {};
@@ -75,4 +80,33 @@ TEST_F(RuntimeTest, AbortFromUnattachedThread) {
}, ::testing::KilledBySignal(SIGABRT), kDeathRegex);
}
+// It is possible to run tests that validate an existing deployed on-device ART APEX ('standalone'
+// tests). If these tests expect to load ELF files with a particular alignment, but those ELF files
+// were created with a different alignment, there will be many difficult-to-debug failures. This
+// test aims to identify this mismatch, related to whether or not the runtimes were built to be
+// page-size agnostic.
+TEST_F(RuntimeTest, ElfAlignmentMismatch) {
+#ifdef ART_TARGET_ANDROID
+ bool platform_pga = android::base::GetBoolProperty("ro.product.build.no_bionic_page_size_macro",
+ false);
+ if (kPageSizeAgnostic != platform_pga) {
+ LOG(WARNING) << "Test configured with kPageSizeAgnostic=" << kPageSizeAgnostic << ", but "
+ << "platform ro.product.build.no_bionic_page_size_macro=" << platform_pga << ".";
+ }
+#endif
+ // Determine the alignment of the ART APEX by reading the alignment of boot.oat.
+ std::string core_oat_location = GetSystemImageFilename(GetCoreOatLocation().c_str(), kRuntimeISA);
+ std::unique_ptr<File> core_oat_file(OS::OpenFileForReading(core_oat_location.c_str()));
+ ASSERT_TRUE(core_oat_file.get() != nullptr) << core_oat_location;
+
+ std::string error_msg;
+ std::unique_ptr<ElfFile> elf_file(ElfFile::Open(core_oat_file.get(),
+ /*writable=*/false,
+ /*program_header_only=*/true,
+ /*low_4gb=*/false,
+ &error_msg));
+ ASSERT_TRUE(elf_file != nullptr) << error_msg;
+ EXPECT_EQ(kElfSegmentAlignment, elf_file->GetElfSegmentAlignmentFromFile());
+}
+
} // namespace art