diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/Android.bp | 8 | ||||
-rw-r--r-- | compiler/driver/compiler_options.cc | 6 | ||||
-rw-r--r-- | compiler/driver/compiler_options.h | 5 | ||||
-rw-r--r-- | compiler/elf_builder.h | 62 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 33 | ||||
-rw-r--r-- | compiler/elf_writer_test.cc | 19 |
6 files changed, 132 insertions, 1 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp index 2556178ddf..d9ed0671a3 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -190,6 +190,14 @@ art_cc_defaults { ], include_dirs: ["art/disassembler"], export_include_dirs: ["."], + + // For SHA-1 checksumming of build ID + static: { + whole_static_libs: ["libcrypto"], + }, + shared: { + shared_libs: ["libcrypto"], + }, } gensrcs { diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index cbcc169f41..c222f90043 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -37,6 +37,7 @@ CompilerOptions::CompilerOptions() debuggable_(false), generate_debug_info_(kDefaultGenerateDebugInfo), generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo), + generate_build_id_(false), implicit_null_checks_(true), implicit_so_checks_(true), implicit_suspend_checks_(false), @@ -97,6 +98,7 @@ CompilerOptions::CompilerOptions(CompilerFilter::Filter compiler_filter, debuggable_(debuggable), generate_debug_info_(generate_debug_info), generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo), + generate_build_id_(false), implicit_null_checks_(implicit_null_checks), implicit_so_checks_(implicit_so_checks), implicit_suspend_checks_(implicit_suspend_checks), @@ -196,6 +198,10 @@ bool CompilerOptions::ParseCompilerOption(const StringPiece& option, UsageFn Usa generate_mini_debug_info_ = true; } else if (option == "--no-generate-mini-debug-info") { generate_mini_debug_info_ = false; + } else if (option == "--generate-build-id") { + generate_build_id_ = true; + } else if (option == "--no-generate-build-id") { + generate_build_id_ = false; } else if (option == "--debuggable") { debuggable_ = true; } else if (option.starts_with("--top-k-profile-threshold=")) { diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index 8e4a775558..3c920d9601 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -187,6 +187,10 @@ class CompilerOptions FINAL { return generate_mini_debug_info_; } + bool GetGenerateBuildId() const { + return generate_build_id_; + } + bool GetImplicitNullChecks() const { return implicit_null_checks_; } @@ -297,6 +301,7 @@ class CompilerOptions FINAL { bool debuggable_; bool generate_debug_info_; bool generate_mini_debug_info_; + bool generate_build_id_; bool implicit_null_checks_; bool implicit_so_checks_; bool implicit_suspend_checks_; diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index 73240bed03..31a75294bc 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -36,6 +36,7 @@ namespace art { // The basic layout of the elf file: // Elf_Ehdr - The ELF header. // Elf_Phdr[] - Program headers for the linker. +// .note.gnu.build-id - Optional build ID section (SHA-1 digest). // .rodata - DEX files and oat metadata. // .text - Compiled code. // .bss - Zero-initialized writeable section. @@ -75,6 +76,10 @@ template <typename ElfTypes> class ElfBuilder FINAL { public: static constexpr size_t kMaxProgramHeaders = 16; + // SHA-1 digest. Not using SHA_DIGEST_LENGTH from openssl/sha.h to avoid + // spreading this header dependency for just this single constant. + static constexpr size_t kBuildIdLen = 20; + using Elf_Addr = typename ElfTypes::Addr; using Elf_Off = typename ElfTypes::Off; using Elf_Word = typename ElfTypes::Word; @@ -458,6 +463,49 @@ class ElfBuilder FINAL { } abiflags_; }; + class BuildIdSection FINAL : public Section { + public: + BuildIdSection(ElfBuilder<ElfTypes>* owner, + const std::string& name, + Elf_Word type, + Elf_Word flags, + const Section* link, + Elf_Word info, + Elf_Word align, + Elf_Word entsize) + : Section(owner, name, type, flags, link, info, align, entsize), + digest_start_(-1) { + } + + void Write() { + // The size fields are 32-bit on both 32-bit and 64-bit systems, confirmed + // with the 64-bit linker and libbfd code. The size of name and desc must + // be a multiple of 4 and it currently is. + this->WriteUint32(4); // namesz. + this->WriteUint32(kBuildIdLen); // descsz. + this->WriteUint32(3); // type = NT_GNU_BUILD_ID. + this->WriteFully("GNU", 4); // name. + digest_start_ = this->Seek(0, kSeekCurrent); + static_assert(kBuildIdLen % 4 == 0, "expecting a mutliple of 4 for build ID length"); + this->WriteFully(std::string(kBuildIdLen, '\0').c_str(), kBuildIdLen); // desc. + } + + off_t GetDigestStart() { + CHECK_GT(digest_start_, 0); + return digest_start_; + } + + private: + bool WriteUint32(uint32_t v) { + return this->WriteFully(&v, sizeof(v)); + } + + // File offset where the build ID digest starts. + // Populated with zeros first, then updated with the actual value as the + // very last thing in the output file creation. + off_t digest_start_; + }; + ElfBuilder(InstructionSet isa, const InstructionSetFeatures* features, OutputStream* output) : isa_(isa), features_(features), @@ -479,6 +527,7 @@ class ElfBuilder FINAL { shstrtab_(this, ".shstrtab", 0, 1), abiflags_(this, ".MIPS.abiflags", SHT_MIPS_ABIFLAGS, SHF_ALLOC, nullptr, 0, kPageSize, 0, isa, features), + build_id_(this, ".note.gnu.build-id", SHT_NOTE, SHF_ALLOC, nullptr, 0, 4, 0), started_(false), write_program_headers_(false), loaded_size_(0u), @@ -489,6 +538,7 @@ class ElfBuilder FINAL { dynamic_.phdr_type_ = PT_DYNAMIC; eh_frame_hdr_.phdr_type_ = PT_GNU_EH_FRAME; abiflags_.phdr_type_ = PT_MIPS_ABIFLAGS; + build_id_.phdr_type_ = PT_NOTE; } ~ElfBuilder() {} @@ -741,6 +791,17 @@ class ElfBuilder FINAL { abiflags_.End(); } + void WriteBuildIdSection() { + build_id_.Start(); + build_id_.Write(); + build_id_.End(); + } + + void WriteBuildId(uint8_t build_id[kBuildIdLen]) { + stream_.Seek(build_id_.GetDigestStart(), kSeekSet); + stream_.WriteFully(build_id, kBuildIdLen); + } + // Returns true if all writes and seeks on the output stream succeeded. bool Good() { return stream_.Good(); @@ -932,6 +993,7 @@ class ElfBuilder FINAL { Section debug_line_; StringSection shstrtab_; AbiflagsSection abiflags_; + BuildIdSection build_id_; std::vector<std::unique_ptr<Section>> other_sections_; // List of used section in the order in which they were written. diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 36cd2327c4..0d6575cffd 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -16,6 +16,7 @@ #include "elf_writer_quick.h" +#include <openssl/sha.h> #include <unordered_map> #include <unordered_set> @@ -126,6 +127,8 @@ class ElfWriterQuick FINAL : public ElfWriter { std::unique_ptr<DebugInfoTask> debug_info_task_; std::unique_ptr<ThreadPool> debug_info_thread_pool_; + void ComputeFileBuildId(uint8_t (*build_id)[ElfBuilder<ElfTypes>::kBuildIdLen]); + DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick); }; @@ -167,6 +170,9 @@ ElfWriterQuick<ElfTypes>::~ElfWriterQuick() {} template <typename ElfTypes> void ElfWriterQuick<ElfTypes>::Start() { builder_->Start(); + if (compiler_options_->GetGenerateBuildId()) { + builder_->WriteBuildIdSection(); + } } template <typename ElfTypes> @@ -275,11 +281,36 @@ void ElfWriterQuick<ElfTypes>::WritePatchLocations( template <typename ElfTypes> bool ElfWriterQuick<ElfTypes>::End() { builder_->End(); - + if (compiler_options_->GetGenerateBuildId()) { + uint8_t build_id[ElfBuilder<ElfTypes>::kBuildIdLen]; + ComputeFileBuildId(&build_id); + builder_->WriteBuildId(build_id); + } return builder_->Good(); } template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::ComputeFileBuildId( + uint8_t (*build_id)[ElfBuilder<ElfTypes>::kBuildIdLen]) { + constexpr int kBufSize = 8192; + std::vector<char> buffer(kBufSize); + int64_t offset = 0; + SHA_CTX ctx; + SHA1_Init(&ctx); + while (true) { + int64_t bytes_read = elf_file_->Read(buffer.data(), kBufSize, offset); + CHECK_GE(bytes_read, 0); + if (bytes_read == 0) { + // End of file. + break; + } + SHA1_Update(&ctx, buffer.data(), bytes_read); + offset += bytes_read; + } + SHA1_Final(*build_id, &ctx); +} + +template <typename ElfTypes> OutputStream* ElfWriterQuick<ElfTypes>::GetStream() { return builder_->GetStream(); } diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc index d5f16637be..b58004976e 100644 --- a/compiler/elf_writer_test.cc +++ b/compiler/elf_writer_test.cc @@ -101,6 +101,25 @@ TEST_F(ElfWriterTest, dlsym) { } } +TEST_F(ElfWriterTest, CheckBuildIdPresent) { + std::string elf_location = GetCoreOatLocation(); + std::string elf_filename = GetSystemImageFilename(elf_location.c_str(), kRuntimeISA); + LOG(INFO) << "elf_filename=" << elf_filename; + + std::unique_ptr<File> file(OS::OpenFileForReading(elf_filename.c_str())); + ASSERT_TRUE(file.get() != nullptr); + { + std::string error_msg; + std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), + false, + false, + /*low_4gb*/false, + &error_msg)); + CHECK(ef.get() != nullptr) << error_msg; + EXPECT_TRUE(ef->HasSection(".note.gnu.build-id")); + } +} + TEST_F(ElfWriterTest, EncodeDecodeOatPatches) { const std::vector<std::vector<uintptr_t>> test_data { { 0, 4, 8, 15, 128, 200 }, |