diff options
author | 2018-07-05 22:27:08 +0100 | |
---|---|---|
committer | 2018-07-17 17:17:00 +0100 | |
commit | de91fd4f92363c69bce2c21366fbb2a31c8c1e78 (patch) | |
tree | e7fd79f291caa7676c7d68ca537f1c62ce214f3e | |
parent | 2449d6d006dcb685d3b386edcf624e67ef37e12c (diff) |
Generate unstripped .oat files in the symbols directory.
Test: Check the generated files with readelf.
Bug: 70512966
Change-Id: Id31232f8b750281bdc170f356833a8d71e1b5796
-rw-r--r-- | compiler/linker/elf_builder.h | 52 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 61 | ||||
-rw-r--r-- | dex2oat/dex2oat_options.cc | 2 | ||||
-rw-r--r-- | dex2oat/dex2oat_options.def | 1 | ||||
-rw-r--r-- | dex2oat/linker/elf_writer.h | 1 | ||||
-rw-r--r-- | dex2oat/linker/elf_writer_quick.cc | 16 |
6 files changed, 97 insertions, 36 deletions
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h index 3da7a43762..974c590a65 100644 --- a/compiler/linker/elf_builder.h +++ b/compiler/linker/elf_builder.h @@ -308,9 +308,14 @@ class ElfBuilder FINAL { /* link */ nullptr, /* info */ 0, align, - /* entsize */ 0), - current_offset_(0), - last_offset_(0) { + /* entsize */ 0) { + Reset(); + } + + void Reset() { + current_offset_ = 0; + last_name_ = ""; + last_offset_ = 0; } Elf_Word Write(const std::string& name) { @@ -550,6 +555,7 @@ class ElfBuilder FINAL { build_id_(this, ".note.gnu.build-id", SHT_NOTE, SHF_ALLOC, nullptr, 0, 4, 0), current_section_(nullptr), started_(false), + finished_(false), write_program_headers_(false), loaded_size_(0u), virtual_address_(0) { @@ -627,8 +633,10 @@ class ElfBuilder FINAL { write_program_headers_ = write_program_headers; } - void End() { + off_t End() { DCHECK(started_); + DCHECK(!finished_); + finished_ = true; // Note: loaded_size_ == 0 for tests that don't write .rodata, .text, .bss, // .dynstr, dynsym, .hash and .dynamic. These tests should not read loaded_size_. @@ -662,6 +670,7 @@ class ElfBuilder FINAL { Elf_Off section_headers_offset; section_headers_offset = AlignFileOffset(sizeof(Elf_Off)); stream_.WriteFully(shdrs.data(), shdrs.size() * sizeof(shdrs[0])); + off_t file_size = stream_.Seek(0, kSeekCurrent); // Flush everything else before writing the program headers. This should prevent // the OS from reordering writes, so that we don't end up with valid headers @@ -687,6 +696,39 @@ class ElfBuilder FINAL { stream_.WriteFully(&elf_header, sizeof(elf_header)); stream_.WriteFully(phdrs.data(), phdrs.size() * sizeof(phdrs[0])); stream_.Flush(); + + return file_size; + } + + // This has the same effect as running the "strip" command line tool. + // It removes all debugging sections (but it keeps mini-debug-info). + // It returns the ELF file size (as the caller needs to truncate it). + off_t Strip() { + DCHECK(finished_); + finished_ = false; + Elf_Off end = 0; + std::vector<Section*> non_debug_sections; + for (Section* section : sections_) { + if (section == &shstrtab_ || // Section names will be recreated. + section == &symtab_ || + section == &strtab_ || + section->name_.find(".debug_") == 0) { + section->header_.sh_offset = 0; + section->header_.sh_size = 0; + section->section_index_ = 0; + } else { + if (section->header_.sh_type != SHT_NOBITS) { + DCHECK_LE(section->header_.sh_offset, end + kPageSize) << "Large gap between sections"; + end = std::max<off_t>(end, section->header_.sh_offset + section->header_.sh_size); + } + non_debug_sections.push_back(section); + } + } + shstrtab_.Reset(); + // Write the non-debug section headers, program headers, and ELF header again. + sections_ = std::move(non_debug_sections); + stream_.Seek(end, kSeekSet); + return End(); } // The running program does not have access to section headers @@ -861,6 +903,7 @@ class ElfBuilder FINAL { void WriteBuildId(uint8_t build_id[kBuildIdLen]) { stream_.Seek(build_id_.GetDigestStart(), kSeekSet); stream_.WriteFully(build_id, kBuildIdLen); + stream_.Flush(); } // Returns true if all writes and seeks on the output stream succeeded. @@ -1060,6 +1103,7 @@ class ElfBuilder FINAL { Section* current_section_; // The section which is currently being written. bool started_; + bool finished_; bool write_program_headers_; // The size of the memory taken by the ELF file when loaded. diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index cbc6424466..0b68620e6e 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -253,7 +253,14 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(" to the file descriptor specified by --oat-fd."); UsageError(" Example: --oat-location=/data/dalvik-cache/system@app@Calculator.apk.oat"); UsageError(""); - UsageError(" --oat-symbols=<file.oat>: specifies an oat output destination with full symbols."); + UsageError(" --oat-symbols=<file.oat>: specifies a destination where the oat file is copied."); + UsageError(" This is equivalent to file copy as build post-processing step."); + UsageError(" It is intended to be used with --strip and it happens before it."); + UsageError(" Example: --oat-symbols=/symbols/system/framework/boot.oat"); + UsageError(""); + UsageError(" --strip: remove all debugging sections at the end (but keep mini-debug-info)."); + UsageError(" This is equivalent to the \"strip\" command as build post-processing step."); + UsageError(" It is intended to be used with --oat-symbols and it happens after it."); UsageError(" Example: --oat-symbols=/symbols/system/framework/boot.oat"); UsageError(""); UsageError(" --image=<file.art>: specifies an output image filename."); @@ -1180,6 +1187,7 @@ class Dex2Oat FINAL { AssignIfExists(args, M::DexLocations, &dex_locations_); AssignIfExists(args, M::OatFiles, &oat_filenames_); AssignIfExists(args, M::OatSymbols, &parser_options->oat_symbols); + AssignTrueIfExists(args, M::Strip, &strip_); AssignIfExists(args, M::ImageFilenames, &image_filenames_); AssignIfExists(args, M::ZipFd, &zip_fd_); AssignIfExists(args, M::ZipLocation, &zip_location_); @@ -2175,7 +2183,7 @@ class Dex2Oat FINAL { VLOG(compiler) << "Oat file written successfully: " << oat_filenames_[i]; oat_writer.reset(); - elf_writer.reset(); + // We may still need the ELF writer later for stripping. } } @@ -2194,21 +2202,16 @@ class Dex2Oat FINAL { return true; } - // Create a copy from stripped to unstripped. - bool CopyStrippedToUnstripped() { + // Copy the full oat files to symbols directory and then strip the originals. + bool CopyOatFilesToSymbolsDirectoryAndStrip() { for (size_t i = 0; i < oat_unstripped_.size(); ++i) { // If we don't want to strip in place, copy from stripped location to unstripped location. // We need to strip after image creation because FixupElf needs to use .strtab. if (strcmp(oat_unstripped_[i], oat_filenames_[i]) != 0) { - // If the oat file is still open, flush it. - if (oat_files_[i].get() != nullptr && oat_files_[i]->IsOpened()) { - if (!FlushCloseOutputFile(&oat_files_[i])) { - return false; - } - } + DCHECK(oat_files_[i].get() != nullptr && oat_files_[i]->IsOpened()); TimingLogger::ScopedTiming t("dex2oat OatFile copy", timings_); - std::unique_ptr<File> in(OS::OpenFileForReading(oat_filenames_[i])); + std::unique_ptr<File>& in = oat_files_[i]; std::unique_ptr<File> out(OS::CreateEmptyFile(oat_unstripped_[i])); int64_t in_length = in->GetLength(); if (in_length < 0) { @@ -2224,6 +2227,14 @@ class Dex2Oat FINAL { return false; } VLOG(compiler) << "Oat file copied successfully (unstripped): " << oat_unstripped_[i]; + + if (strip_) { + TimingLogger::ScopedTiming t2("dex2oat OatFile strip", timings_); + if (!elf_writers_[i]->StripDebugInfo()) { + PLOG(ERROR) << "Failed strip oat file: " << in->GetPath(); + return false; + } + } } } return true; @@ -2239,11 +2250,10 @@ class Dex2Oat FINAL { return true; } - bool FlushCloseOutputFile(std::unique_ptr<File>* file) { - if (file->get() != nullptr) { - std::unique_ptr<File> tmp(file->release()); - if (tmp->FlushCloseOrErase() != 0) { - PLOG(ERROR) << "Failed to flush and close output file: " << tmp->GetPath(); + bool FlushCloseOutputFile(File* file) { + if (file != nullptr) { + if (file->FlushCloseOrErase() != 0) { + PLOG(ERROR) << "Failed to flush and close output file: " << file->GetPath(); return false; } } @@ -2266,7 +2276,7 @@ class Dex2Oat FINAL { bool result = true; for (auto& files : { &vdex_files_, &oat_files_ }) { for (size_t i = 0; i < files->size(); ++i) { - result &= FlushCloseOutputFile(&(*files)[i]); + result &= FlushCloseOutputFile((*files)[i].get()); } } return result; @@ -2825,6 +2835,7 @@ class Dex2Oat FINAL { std::string oat_location_; std::vector<const char*> oat_filenames_; std::vector<const char*> oat_unstripped_; + bool strip_; int oat_fd_; int input_vdex_fd_; int output_vdex_fd_; @@ -2947,15 +2958,9 @@ static dex2oat::ReturnCode CompileImage(Dex2Oat& dex2oat) { return dex2oat::ReturnCode::kOther; } - // Flush boot.oat. We always expect the output file by name, and it will be re-opened from the - // unstripped name. Do not close the file if we are compiling the image with an oat fd since the - // image writer will require this fd to generate the image. - if (dex2oat.ShouldKeepOatFileOpen()) { - if (!dex2oat.FlushOutputFiles()) { - dex2oat.EraseOutputFiles(); - return dex2oat::ReturnCode::kOther; - } - } else if (!dex2oat.FlushCloseOutputFiles()) { + // Flush boot.oat. Keep it open as we might still modify it later (strip it). + if (!dex2oat.FlushOutputFiles()) { + dex2oat.EraseOutputFiles(); return dex2oat::ReturnCode::kOther; } @@ -2974,7 +2979,7 @@ static dex2oat::ReturnCode CompileImage(Dex2Oat& dex2oat) { } // Copy stripped to unstripped location, if necessary. - if (!dex2oat.CopyStrippedToUnstripped()) { + if (!dex2oat.CopyOatFilesToSymbolsDirectoryAndStrip()) { return dex2oat::ReturnCode::kOther; } @@ -3012,7 +3017,7 @@ static dex2oat::ReturnCode CompileApp(Dex2Oat& dex2oat) { // Copy stripped to unstripped location, if necessary. This will implicitly flush & close the // stripped versions. If this is given, we expect to be able to open writable files by name. - if (!dex2oat.CopyStrippedToUnstripped()) { + if (!dex2oat.CopyOatFilesToSymbolsDirectoryAndStrip()) { return dex2oat::ReturnCode::kOther; } diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc index bf9edf7384..710f14c4c5 100644 --- a/dex2oat/dex2oat_options.cc +++ b/dex2oat/dex2oat_options.cc @@ -98,6 +98,8 @@ static void AddGeneratedArtifactMappings(Builder& builder) { .Define("--oat-symbols=_") .WithType<std::vector<std::string>>().AppendValues() .IntoKey(M::OatSymbols) + .Define("--strip") + .IntoKey(M::Strip) .Define("--oat-fd=_") .WithType<int>() .IntoKey(M::OatFd) diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def index fe5c4e69a7..c8cb7e7b72 100644 --- a/dex2oat/dex2oat_options.def +++ b/dex2oat/dex2oat_options.def @@ -47,6 +47,7 @@ DEX2OAT_OPTIONS_KEY (int, DmFd) DEX2OAT_OPTIONS_KEY (std::string, DmFile) DEX2OAT_OPTIONS_KEY (std::vector<std::string>, OatFiles) DEX2OAT_OPTIONS_KEY (std::vector<std::string>, OatSymbols) +DEX2OAT_OPTIONS_KEY (Unit, Strip) DEX2OAT_OPTIONS_KEY (int, OatFd) DEX2OAT_OPTIONS_KEY (std::string, OatLocation) DEX2OAT_OPTIONS_KEY (bool, Watchdog) diff --git a/dex2oat/linker/elf_writer.h b/dex2oat/linker/elf_writer.h index cd8cf4c54e..637330c835 100644 --- a/dex2oat/linker/elf_writer.h +++ b/dex2oat/linker/elf_writer.h @@ -77,6 +77,7 @@ class ElfWriter { virtual void EndDataBimgRelRo(OutputStream* data_bimg_rel_ro) = 0; virtual void WriteDynamicSection() = 0; virtual void WriteDebugInfo(const debug::DebugInfo& debug_info) = 0; + virtual bool StripDebugInfo() = 0; virtual bool End() = 0; // Get the ELF writer's stream. This stream can be used for writing data directly diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc index 8f6ff702cc..4e7d636dbf 100644 --- a/dex2oat/linker/elf_writer_quick.cc +++ b/dex2oat/linker/elf_writer_quick.cc @@ -117,6 +117,7 @@ class ElfWriterQuick FINAL : public ElfWriter { 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; virtual OutputStream* GetStream() OVERRIDE; @@ -280,10 +281,6 @@ void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(const debug::DebugInfo& debug_in template <typename ElfTypes> void ElfWriterQuick<ElfTypes>::WriteDebugInfo(const debug::DebugInfo& debug_info) { if (!debug_info.Empty()) { - if (compiler_options_.GetGenerateDebugInfo()) { - // Generate all the debug information we can. - debug::WriteDebugInfo(builder_.get(), debug_info, kCFIFormat, true /* write_oat_patches */); - } if (compiler_options_.GetGenerateMiniDebugInfo()) { // Wait for the mini-debug-info generation to finish and write it to disk. Thread* self = Thread::Current(); @@ -291,10 +288,21 @@ void ElfWriterQuick<ElfTypes>::WriteDebugInfo(const debug::DebugInfo& debug_info 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 (compiler_options_.GetGenerateDebugInfo()) { + // Generate all the debug information we can. + debug::WriteDebugInfo(builder_.get(), debug_info, kCFIFormat, true /* write_oat_patches */); + } } } template <typename ElfTypes> +bool ElfWriterQuick<ElfTypes>::StripDebugInfo() { + off_t file_size = builder_->Strip(); + return elf_file_->SetLength(file_size) == 0; +} + +template <typename ElfTypes> bool ElfWriterQuick<ElfTypes>::End() { builder_->End(); if (compiler_options_.GetGenerateBuildId()) { |