/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "elf_writer_quick.h" #include #include #include #include "base/casts.h" #include "base/globals.h" #include "base/leb128.h" #include "base/utils.h" #include "debug/elf_debug_writer.h" #include "debug/method_debug_info.h" #include "driver/compiler_options.h" #include "elf/elf_builder.h" #include "elf/elf_utils.h" #include "stream/buffered_output_stream.h" #include "stream/file_output_stream.h" #include "thread-current-inl.h" #include "thread_pool.h" namespace art { namespace linker { class DebugInfoTask : public Task { public: DebugInfoTask(InstructionSet isa, const InstructionSetFeatures* features, uint64_t text_section_address, size_t text_section_size, uint64_t dex_section_address, size_t dex_section_size, const debug::DebugInfo& debug_info) : isa_(isa), instruction_set_features_(features), text_section_address_(text_section_address), text_section_size_(text_section_size), dex_section_address_(dex_section_address), dex_section_size_(dex_section_size), debug_info_(debug_info) { } void Run(Thread*) override { result_ = debug::MakeMiniDebugInfo(isa_, instruction_set_features_, text_section_address_, text_section_size_, dex_section_address_, dex_section_size_, debug_info_); } std::vector* GetResult() { return &result_; } private: InstructionSet isa_; const InstructionSetFeatures* instruction_set_features_; uint64_t text_section_address_; size_t text_section_size_; uint64_t dex_section_address_; size_t dex_section_size_; const debug::DebugInfo& debug_info_; std::vector result_; }; template class ElfWriterQuick final : public ElfWriter { public: ElfWriterQuick(const CompilerOptions& compiler_options, File* elf_file); ~ElfWriterQuick(); void Start() override; void PrepareDynamicSection(size_t rodata_size, size_t text_size, size_t data_bimg_rel_ro_size, size_t bss_size, size_t bss_methods_offset, size_t bss_roots_offset, size_t dex_section_size) override; void PrepareDebugInfo(const debug::DebugInfo& debug_info) override; OutputStream* StartRoData() override; void EndRoData(OutputStream* rodata) override; OutputStream* StartText() override; void EndText(OutputStream* text) override; OutputStream* StartDataBimgRelRo() override; void EndDataBimgRelRo(OutputStream* data_bimg_rel_ro) override; void WriteDynamicSection() override; void WriteDebugInfo(const debug::DebugInfo& debug_info) override; bool StripDebugInfo() override; bool End() override; OutputStream* GetStream() override; size_t GetLoadedSize() override; static void EncodeOatPatches(const std::vector& locations, std::vector* buffer); private: const CompilerOptions& compiler_options_; File* const elf_file_; size_t rodata_size_; size_t text_size_; size_t data_bimg_rel_ro_size_; size_t bss_size_; size_t dex_section_size_; std::unique_ptr output_stream_; std::unique_ptr> builder_; std::unique_ptr debug_info_task_; std::unique_ptr debug_info_thread_pool_; void ComputeFileBuildId(uint8_t (*build_id)[ElfBuilder::kBuildIdLen]); DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick); }; std::unique_ptr CreateElfWriterQuick(const CompilerOptions& compiler_options, File* elf_file) { if (Is64BitInstructionSet(compiler_options.GetInstructionSet())) { return std::make_unique>(compiler_options, elf_file); } else { return std::make_unique>(compiler_options, elf_file); } } template ElfWriterQuick::ElfWriterQuick(const CompilerOptions& compiler_options, File* elf_file) : ElfWriter(), compiler_options_(compiler_options), elf_file_(elf_file), rodata_size_(0u), text_size_(0u), data_bimg_rel_ro_size_(0u), bss_size_(0u), dex_section_size_(0u), output_stream_( std::make_unique(std::make_unique(elf_file))), builder_(new ElfBuilder(compiler_options_.GetInstructionSet(), output_stream_.get())) {} template ElfWriterQuick::~ElfWriterQuick() {} template void ElfWriterQuick::Start() { builder_->Start(); if (compiler_options_.GetGenerateBuildId()) { builder_->GetBuildId()->AllocateVirtualMemory(builder_->GetBuildId()->GetSize()); builder_->WriteBuildIdSection(); } } template void ElfWriterQuick::PrepareDynamicSection(size_t rodata_size, size_t text_size, size_t data_bimg_rel_ro_size, size_t bss_size, size_t bss_methods_offset, size_t bss_roots_offset, size_t dex_section_size) { DCHECK_EQ(rodata_size_, 0u); rodata_size_ = rodata_size; DCHECK_EQ(text_size_, 0u); text_size_ = text_size; DCHECK_EQ(data_bimg_rel_ro_size_, 0u); data_bimg_rel_ro_size_ = data_bimg_rel_ro_size; DCHECK_EQ(bss_size_, 0u); bss_size_ = bss_size; DCHECK_EQ(dex_section_size_, 0u); dex_section_size_ = dex_section_size; builder_->PrepareDynamicSection(elf_file_->GetPath(), rodata_size_, text_size_, data_bimg_rel_ro_size_, bss_size_, bss_methods_offset, bss_roots_offset, dex_section_size); } template OutputStream* ElfWriterQuick::StartRoData() { auto* rodata = builder_->GetRoData(); rodata->Start(); return rodata; } template void ElfWriterQuick::EndRoData(OutputStream* rodata) { CHECK_EQ(builder_->GetRoData(), rodata); builder_->GetRoData()->End(); } template OutputStream* ElfWriterQuick::StartText() { auto* text = builder_->GetText(); text->Start(); return text; } template void ElfWriterQuick::EndText(OutputStream* text) { CHECK_EQ(builder_->GetText(), text); builder_->GetText()->End(); } template OutputStream* ElfWriterQuick::StartDataBimgRelRo() { auto* data_bimg_rel_ro = builder_->GetDataBimgRelRo(); data_bimg_rel_ro->Start(); return data_bimg_rel_ro; } template void ElfWriterQuick::EndDataBimgRelRo(OutputStream* data_bimg_rel_ro) { CHECK_EQ(builder_->GetDataBimgRelRo(), data_bimg_rel_ro); builder_->GetDataBimgRelRo()->End(); } template void ElfWriterQuick::WriteDynamicSection() { builder_->WriteDynamicSection(); } template void ElfWriterQuick::PrepareDebugInfo(const debug::DebugInfo& debug_info) { if (compiler_options_.GetGenerateMiniDebugInfo()) { // Prepare the mini-debug-info in background while we do other I/O. Thread* self = Thread::Current(); debug_info_task_ = std::make_unique( builder_->GetIsa(), compiler_options_.GetInstructionSetFeatures(), builder_->GetText()->GetAddress(), text_size_, builder_->GetDex()->Exists() ? builder_->GetDex()->GetAddress() : 0, dex_section_size_, debug_info); debug_info_thread_pool_ = std::make_unique("Mini-debug-info writer", 1); debug_info_thread_pool_->AddTask(self, debug_info_task_.get()); debug_info_thread_pool_->StartWorkers(self); } } template void ElfWriterQuick::WriteDebugInfo(const debug::DebugInfo& debug_info) { if (compiler_options_.GetGenerateMiniDebugInfo()) { // If mini-debug-info wasn't explicitly created so far, create it now (happens in tests). if (debug_info_task_ == nullptr) { PrepareDebugInfo(debug_info); } // Wait for the mini-debug-info generation to finish and write it to disk. Thread* self = Thread::Current(); DCHECK(debug_info_thread_pool_ != nullptr); debug_info_thread_pool_->Wait(self, true, false); builder_->WriteSection(".gnu_debugdata", debug_info_task_->GetResult()); } // The Strip method expects debug info to be last (mini-debug-info is not stripped). if (!debug_info.Empty() && compiler_options_.GetGenerateDebugInfo()) { // Generate all the debug information we can. debug::WriteDebugInfo(builder_.get(), debug_info); } } template bool ElfWriterQuick::StripDebugInfo() { off_t file_size = builder_->Strip(); return elf_file_->SetLength(file_size) == 0; } template bool ElfWriterQuick::End() { builder_->End(); if (compiler_options_.GetGenerateBuildId()) { uint8_t build_id[ElfBuilder::kBuildIdLen]; ComputeFileBuildId(&build_id); builder_->WriteBuildId(build_id); } return builder_->Good(); } template void ElfWriterQuick::ComputeFileBuildId( uint8_t (*build_id)[ElfBuilder::kBuildIdLen]) { constexpr int kBufSize = 8192; std::vector 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 OutputStream* ElfWriterQuick::GetStream() { return builder_->GetStream(); } template size_t ElfWriterQuick::GetLoadedSize() { return builder_->GetLoadedSize(); } // Explicit instantiations template class ElfWriterQuick; template class ElfWriterQuick; } // namespace linker } // namespace art