diff options
author | 2016-01-28 20:01:28 +0000 | |
---|---|---|
committer | 2016-02-04 13:16:21 +0000 | |
commit | 579942fc26f8a0b0ff1d909d19086fca6d2396a3 (patch) | |
tree | 840504b5904cf81540cf802c4cea1527e12debe9 | |
parent | cbe3b55ac3c34c9f6f3b7f0ddd86f9b88243547d (diff) |
Reduce the size of native debug info generated by JIT.
Remove some ELF file overheads:
- Do not produce program headers.
- Do not page align strtab.
- Do not write oat_patches sections.
This more than halves the size of JIT native debug info.
Since we generate many small entries, the overheads added up.
Change-Id: I27d95548c61e2e38c3683d6f5eb870a2db6e812d
-rw-r--r-- | compiler/elf_builder.h | 75 | ||||
-rw-r--r-- | compiler/elf_writer_debug.cc | 56 | ||||
-rw-r--r-- | compiler/elf_writer_debug.h | 3 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 2 |
4 files changed, 94 insertions, 42 deletions
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index 3d24d19919..bc7c83ed7d 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -110,18 +110,27 @@ class ElfBuilder FINAL { CHECK(sections.empty() || sections.back()->finished_); // The first ELF section index is 1. Index 0 is reserved for NULL. section_index_ = sections.size() + 1; - // Push this section on the list of written sections. - sections.push_back(this); + // Page-align if we switch between allocated and non-allocated sections, + // or if we change the type of allocation (e.g. executable vs non-executable). + if (!sections.empty()) { + if (header_.sh_flags != sections.back()->header_.sh_flags) { + header_.sh_addralign = kPageSize; + } + } // Align file position. if (header_.sh_type != SHT_NOBITS) { - header_.sh_offset = RoundUp(owner_->stream_.Seek(0, kSeekCurrent), header_.sh_addralign); - owner_->stream_.Seek(header_.sh_offset, kSeekSet); + header_.sh_offset = owner_->AlignFileOffset(header_.sh_addralign); + } else { + header_.sh_offset = 0; } // Align virtual memory address. if ((header_.sh_flags & SHF_ALLOC) != 0) { - header_.sh_addr = RoundUp(owner_->virtual_address_, header_.sh_addralign); - owner_->virtual_address_ = header_.sh_addr; + header_.sh_addr = owner_->AlignVirtualAddress(header_.sh_addralign); + } else { + header_.sh_addr = 0; } + // Push this section on the list of written sections. + sections.push_back(this); } // Finish writing of this section. @@ -170,8 +179,8 @@ class ElfBuilder FINAL { // and it will be zero-initialized when the ELF file is loaded in the running program. void WriteNoBitsSection(Elf_Word size) { DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u); - Start(); header_.sh_type = SHT_NOBITS; + Start(); header_.sh_size = size; End(); } @@ -293,12 +302,13 @@ class ElfBuilder FINAL { dynamic_(this, ".dynamic", SHT_DYNAMIC, SHF_ALLOC, &dynstr_, 0, kPageSize, sizeof(Elf_Dyn)), eh_frame_(this, ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), eh_frame_hdr_(this, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0), - strtab_(this, ".strtab", 0, kPageSize), + strtab_(this, ".strtab", 0, 1), symtab_(this, ".symtab", SHT_SYMTAB, 0, &strtab_), debug_frame_(this, ".debug_frame", SHT_PROGBITS, 0, nullptr, 0, sizeof(Elf_Addr), 0), debug_info_(this, ".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0), debug_line_(this, ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0), shstrtab_(this, ".shstrtab", 0, 1), + started_(false), virtual_address_(0) { text_.phdr_flags_ = PF_R | PF_X; bss_.phdr_flags_ = PF_R | PF_W; @@ -357,16 +367,25 @@ class ElfBuilder FINAL { virtual_address_ = address; } - void Start() { - // Reserve space for ELF header and program headers. - // We do not know the number of headers until later, so - // it is easiest to just reserve a fixed amount of space. - int size = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * kMaxProgramHeaders; + // Reserve space for ELF header and program headers. + // We do not know the number of headers until later, so + // it is easiest to just reserve a fixed amount of space. + // Program headers are required for loading by the linker. + // It is possible to omit them for ELF files used for debugging. + void Start(bool write_program_headers = true) { + int size = sizeof(Elf_Ehdr); + if (write_program_headers) { + size += sizeof(Elf_Phdr) * kMaxProgramHeaders; + } stream_.Seek(size, kSeekSet); + started_ = true; virtual_address_ += size; + write_program_headers_ = write_program_headers; } void End() { + DCHECK(started_); + // Write section names and finish the section headers. shstrtab_.Start(); shstrtab_.Write(""); @@ -386,8 +405,7 @@ class ElfBuilder FINAL { shdrs.push_back(section->header_); } Elf_Off section_headers_offset; - section_headers_offset = RoundUp(stream_.Seek(0, kSeekCurrent), sizeof(Elf_Off)); - stream_.Seek(section_headers_offset, kSeekSet); + section_headers_offset = AlignFileOffset(sizeof(Elf_Off)); stream_.WriteFully(shdrs.data(), shdrs.size() * sizeof(shdrs[0])); // Flush everything else before writing the program headers. This should prevent @@ -395,14 +413,21 @@ class ElfBuilder FINAL { // and partially written data if we suddenly lose power, for example. stream_.Flush(); - // Write the initial file headers. - std::vector<Elf_Phdr> phdrs = MakeProgramHeaders(); + // The main ELF header. Elf_Ehdr elf_header = MakeElfHeader(isa_); - elf_header.e_phoff = sizeof(Elf_Ehdr); elf_header.e_shoff = section_headers_offset; - elf_header.e_phnum = phdrs.size(); elf_header.e_shnum = shdrs.size(); elf_header.e_shstrndx = shstrtab_.GetSectionIndex(); + + // Program headers (i.e. mmap instructions). + std::vector<Elf_Phdr> phdrs; + if (write_program_headers_) { + phdrs = MakeProgramHeaders(); + CHECK_LE(phdrs.size(), kMaxProgramHeaders); + elf_header.e_phoff = sizeof(Elf_Ehdr); + elf_header.e_phnum = phdrs.size(); + } + stream_.Seek(0, kSeekSet); stream_.WriteFully(&elf_header, sizeof(elf_header)); stream_.WriteFully(phdrs.data(), phdrs.size() * sizeof(phdrs[0])); @@ -492,6 +517,14 @@ class ElfBuilder FINAL { return &stream_; } + off_t AlignFileOffset(size_t alignment) { + return stream_.Seek(RoundUp(stream_.Seek(0, kSeekCurrent), alignment), kSeekSet); + } + + Elf_Addr AlignVirtualAddress(size_t alignment) { + return virtual_address_ = RoundUp(virtual_address_, alignment); + } + private: static Elf_Ehdr MakeElfHeader(InstructionSet isa) { Elf_Ehdr elf_header = Elf_Ehdr(); @@ -666,9 +699,13 @@ class ElfBuilder FINAL { // List of used section in the order in which they were written. std::vector<Section*> sections_; + bool started_; + // Used for allocation of virtual address space. Elf_Addr virtual_address_; + size_t write_program_headers_; + DISALLOW_COPY_AND_ASSIGN(ElfBuilder); }; diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc index d1f50073a0..ca8cd68b33 100644 --- a/compiler/elf_writer_debug.cc +++ b/compiler/elf_writer_debug.cc @@ -1148,13 +1148,19 @@ class DebugInfoWriter { writer.Write(types); } - void End() { + void End(bool write_oat_patches) { builder_->GetDebugInfo()->End(); - builder_->WritePatches(".debug_info.oat_patches", - ArrayRef<const uintptr_t>(debug_info_patches_)); + if (write_oat_patches) { + builder_->WritePatches(".debug_info.oat_patches", + ArrayRef<const uintptr_t>(debug_info_patches_)); + } builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_); - builder_->WriteSection(".debug_loc", &debug_loc_); - builder_->WriteSection(".debug_ranges", &debug_ranges_); + if (!debug_loc_.empty()) { + builder_->WriteSection(".debug_loc", &debug_loc_); + } + if (!debug_ranges_.empty()) { + builder_->WriteSection(".debug_ranges", &debug_ranges_); + } } private: @@ -1357,10 +1363,12 @@ class DebugLineWriter { return buffer.size(); } - void End() { + void End(bool write_oat_patches) { builder_->GetDebugLine()->End(); - builder_->WritePatches(".debug_line.oat_patches", - ArrayRef<const uintptr_t>(debug_line_patches)); + if (write_oat_patches) { + builder_->WritePatches(".debug_line.oat_patches", + ArrayRef<const uintptr_t>(debug_line_patches)); + } } private: @@ -1370,7 +1378,8 @@ class DebugLineWriter { template<typename ElfTypes> static void WriteDebugSections(ElfBuilder<ElfTypes>* builder, - const ArrayRef<const MethodDebugInfo>& method_infos) { + const ArrayRef<const MethodDebugInfo>& method_infos, + bool write_oat_patches) { // Group the methods into compilation units based on source file. std::vector<CompilationUnit> compilation_units; const char* last_source_file = nullptr; @@ -1394,7 +1403,7 @@ static void WriteDebugSections(ElfBuilder<ElfTypes>* builder, for (auto& compilation_unit : compilation_units) { line_writer.WriteCompilationUnit(compilation_unit); } - line_writer.End(); + line_writer.End(write_oat_patches); } // Write .debug_info section. @@ -1404,7 +1413,7 @@ static void WriteDebugSections(ElfBuilder<ElfTypes>* builder, for (const auto& compilation_unit : compilation_units) { info_writer.WriteCompilationUnit(compilation_unit); } - info_writer.End(); + info_writer.End(write_oat_patches); } } @@ -1484,13 +1493,14 @@ static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, template <typename ElfTypes> void WriteDebugInfo(ElfBuilder<ElfTypes>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, - CFIFormat cfi_format) { + CFIFormat cfi_format, + bool write_oat_patches) { // Add methods to .symtab. WriteDebugSymbols(builder, method_infos, true /* with_signature */); // Generate CFI (stack unwinding information). - WriteCFISection(builder, method_infos, cfi_format, true /* write_oat_patches */); + WriteCFISection(builder, method_infos, cfi_format, write_oat_patches); // Write DWARF .debug_* sections. - WriteDebugSections(builder, method_infos); + WriteDebugSections(builder, method_infos, write_oat_patches); } static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* dst) { @@ -1571,10 +1581,12 @@ static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal( buffer.reserve(KB); VectorOutputStream out("Debug ELF file", &buffer); std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); - builder->Start(); + // No program headers since the ELF file is not linked and has no allocated sections. + builder->Start(false /* write_program_headers */); WriteDebugInfo(builder.get(), ArrayRef<const MethodDebugInfo>(&method_info, 1), - DW_DEBUG_FRAME_FORMAT); + DW_DEBUG_FRAME_FORMAT, + false /* write_oat_patches */); builder->End(); CHECK(builder->Good()); // Make a copy of the buffer. We want to shrink it anyway. @@ -1601,12 +1613,12 @@ static ArrayRef<const uint8_t> WriteDebugElfFileForClassesInternal( buffer.reserve(KB); VectorOutputStream out("Debug ELF file", &buffer); std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); - builder->Start(); - + // No program headers since the ELF file is not linked and has no allocated sections. + builder->Start(false /* write_program_headers */); DebugInfoWriter<ElfTypes> info_writer(builder.get()); info_writer.Start(); info_writer.WriteTypes(types); - info_writer.End(); + info_writer.End(false /* write_oat_patches */); builder->End(); CHECK(builder->Good()); @@ -1630,11 +1642,13 @@ ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa, template void WriteDebugInfo<ElfTypes32>( ElfBuilder<ElfTypes32>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, - CFIFormat cfi_format); + CFIFormat cfi_format, + bool write_oat_patches); template void WriteDebugInfo<ElfTypes64>( ElfBuilder<ElfTypes64>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, - CFIFormat cfi_format); + CFIFormat cfi_format, + bool write_oat_patches); template void WriteMiniDebugInfo<ElfTypes32>( ElfBuilder<ElfTypes32>* builder, const ArrayRef<const MethodDebugInfo>& method_infos); diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h index e19da088da..8e8472f678 100644 --- a/compiler/elf_writer_debug.h +++ b/compiler/elf_writer_debug.h @@ -33,7 +33,8 @@ struct MethodDebugInfo; template <typename ElfTypes> void WriteDebugInfo(ElfBuilder<ElfTypes>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, - CFIFormat cfi_format); + CFIFormat cfi_format, + bool write_oat_patches); template <typename ElfTypes> void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* builder, diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 6bf080a083..f2a95f2396 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -151,7 +151,7 @@ void ElfWriterQuick<ElfTypes>::WriteDebugInfo( const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) { if (compiler_options_->GetGenerateDebugInfo()) { // Generate all the debug information we can. - dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat); + dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat, true /* write_oat_patches */); } if (compiler_options_->GetGenerateMiniDebugInfo()) { // Generate only some information and compress it. |