diff options
author | Ian Rogers <irogers@google.com> | 2014-08-15 23:27:29 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-08-15 18:44:51 +0000 |
commit | aa1ed01d119ee6d93e6254789c79246e91fcec32 (patch) | |
tree | 90a1afdaa989959e788a2f596fd4278629cdc579 /compiler | |
parent | c28d8a6f0fbfbec8993854b1a9be08af7d506e7b (diff) | |
parent | e3ea83811d47152c00abea24a9b420651a33b496 (diff) | |
download | android_art-aa1ed01d119ee6d93e6254789c79246e91fcec32.tar.gz android_art-aa1ed01d119ee6d93e6254789c79246e91fcec32.tar.bz2 android_art-aa1ed01d119ee6d93e6254789c79246e91fcec32.zip |
Merge "ART source line debug info in OAT files"
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/compiled_method.cc | 28 | ||||
-rw-r--r-- | compiler/compiled_method.h | 100 | ||||
-rw-r--r-- | compiler/dex/quick/codegen_util.cc | 15 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 2 | ||||
-rwxr-xr-x | compiler/dex/quick/x86/target_x86.cc | 6 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 5 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 18 | ||||
-rw-r--r-- | compiler/elf_fixup.cc | 28 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 906 | ||||
-rw-r--r-- | compiler/elf_writer_quick.h | 27 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 8 | ||||
-rw-r--r-- | compiler/oat_writer.h | 8 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.cc | 10 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 6 | ||||
-rw-r--r-- | compiler/utils/dwarf_cfi.cc | 82 | ||||
-rw-r--r-- | compiler/utils/dwarf_cfi.h | 10 | ||||
-rw-r--r-- | compiler/utils/x86/assembler_x86.cc | 6 | ||||
-rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.cc | 6 |
19 files changed, 931 insertions, 344 deletions
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc index f2a8d84731..f9a78be6e8 100644 --- a/compiler/compiled_method.cc +++ b/compiler/compiled_method.cc @@ -148,16 +148,18 @@ CompiledMethod::CompiledMethod(CompilerDriver* driver, const size_t frame_size_in_bytes, const uint32_t core_spill_mask, const uint32_t fp_spill_mask, + SrcMap* src_mapping_table, const std::vector<uint8_t>& mapping_table, const std::vector<uint8_t>& vmap_table, const std::vector<uint8_t>& native_gc_map, const std::vector<uint8_t>* cfi_info) : CompiledCode(driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes), core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask), - mapping_table_(driver->DeduplicateMappingTable(mapping_table)), - vmap_table_(driver->DeduplicateVMapTable(vmap_table)), - gc_map_(driver->DeduplicateGCMap(native_gc_map)), - cfi_info_(driver->DeduplicateCFIInfo(cfi_info)) { + src_mapping_table_(driver->DeduplicateSrcMappingTable(src_mapping_table->Arrange())), + mapping_table_(driver->DeduplicateMappingTable(mapping_table)), + vmap_table_(driver->DeduplicateVMapTable(vmap_table)), + gc_map_(driver->DeduplicateGCMap(native_gc_map)), + cfi_info_(driver->DeduplicateCFIInfo(cfi_info)) { } CompiledMethod::CompiledMethod(CompilerDriver* driver, @@ -170,6 +172,7 @@ CompiledMethod::CompiledMethod(CompilerDriver* driver, : CompiledCode(driver, instruction_set, code), frame_size_in_bytes_(frame_size_in_bytes), core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask), + src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())), mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())), vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())), gc_map_(driver->DeduplicateGCMap(std::vector<uint8_t>())), @@ -182,19 +185,22 @@ CompiledMethod::CompiledMethod(CompilerDriver* driver, InstructionSet instructio const std::string& symbol) : CompiledCode(driver, instruction_set, code, symbol), frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0), - fp_spill_mask_(0), gc_map_(driver->DeduplicateGCMap(gc_map)) { - mapping_table_ = driver->DeduplicateMappingTable(std::vector<uint8_t>()); - vmap_table_ = driver->DeduplicateVMapTable(std::vector<uint8_t>()); + fp_spill_mask_(0), + src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())), + mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())), + vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())), + gc_map_(driver->DeduplicateGCMap(gc_map)) { } CompiledMethod::CompiledMethod(CompilerDriver* driver, InstructionSet instruction_set, const std::string& code, const std::string& symbol) : CompiledCode(driver, instruction_set, code, symbol), frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0), - fp_spill_mask_(0) { - mapping_table_ = driver->DeduplicateMappingTable(std::vector<uint8_t>()); - vmap_table_ = driver->DeduplicateVMapTable(std::vector<uint8_t>()); - gc_map_ = driver->DeduplicateGCMap(std::vector<uint8_t>()); + fp_spill_mask_(0), + src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())), + mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())), + vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())), + gc_map_(driver->DeduplicateGCMap(std::vector<uint8_t>())) { } } // namespace art diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index c98d06a01d..d02cbff7fc 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -100,7 +100,97 @@ class CompiledCode { std::vector<uint32_t> oatdata_offsets_to_compiled_code_offset_; }; -class CompiledMethod : public CompiledCode { +class SrcMapElem { + public: + uint32_t from_; + int32_t to_; + + bool operator<(const SrcMapElem& sme) const { + uint64_t lhs = (static_cast<uint64_t>(from_) << 32) + to_; + uint64_t rhs = (static_cast<uint64_t>(sme.from_) << 32) + sme.to_; + return lhs < rhs; + } + + operator uint8_t() const { + return static_cast<uint8_t>(from_ + to_); + } +}; + +class SrcMap FINAL : public std::vector<SrcMapElem> { + public: + struct CompareByTo { + bool operator()(const SrcMapElem& lhs, const SrcMapElem& rhs) { + return lhs.to_ < rhs.to_; + } + }; + + struct CompareByFrom { + bool operator()(const SrcMapElem& lhs, const SrcMapElem& rhs) { + return lhs.from_ < rhs.from_; + } + }; + + void SortByTo() { + std::sort(begin(), end(), CompareByTo()); + } + + void SortByFrom() { + std::sort(begin(), end(), CompareByFrom()); + } + + const_iterator FindByTo(int32_t to) const { + return std::lower_bound(begin(), end(), SrcMapElem({0, to}), CompareByTo()); + } + + SrcMap& Arrange() { + SortByTo(); + + // Remove duplicate pairs. + if (!empty()) { + SrcMap tmp; + tmp.swap(*this); + iterator it = tmp.begin(); + iterator prev = it; + it++; + push_back(*prev); + for (; it != tmp.end(); it++) { + if (prev->from_ != it->from_ || prev->to_ != it->to_) { + push_back(*(prev = it)); + } + } + } + return *this; + } + + void DeltaFormat(const SrcMapElem& start, uint32_t highest_pc) { + // Convert from abs values to deltas. + if (!empty()) { + SortByFrom(); + + // TODO: one PC can be mapped to several Java src lines. + // do we want such a one-to-many correspondence? + + // get rid of the highest values + size_t i = size() - 1; + for (; i > 0 ; i--) { + if ((*this)[i].from_ >= highest_pc) { + break; + } + } + this->resize(i + 1); + + for (size_t i = size(); --i >= 1; ) { + (*this)[i].from_ -= (*this)[i-1].from_; + (*this)[i].to_ -= (*this)[i-1].to_; + } + DCHECK((*this)[0].from_ >= start.from_); + (*this)[0].from_ -= start.from_; + (*this)[0].to_ -= start.to_; + } + } +}; + +class CompiledMethod FINAL : public CompiledCode { public: // Constructs a CompiledMethod for the non-LLVM compilers. CompiledMethod(CompilerDriver* driver, @@ -109,6 +199,7 @@ class CompiledMethod : public CompiledCode { const size_t frame_size_in_bytes, const uint32_t core_spill_mask, const uint32_t fp_spill_mask, + SrcMap* src_mapping_table, const std::vector<uint8_t>& mapping_table, const std::vector<uint8_t>& vmap_table, const std::vector<uint8_t>& native_gc_map, @@ -145,6 +236,11 @@ class CompiledMethod : public CompiledCode { return fp_spill_mask_; } + const SrcMap& GetSrcMappingTable() const { + DCHECK(src_mapping_table_ != nullptr); + return *src_mapping_table_; + } + const std::vector<uint8_t>& GetMappingTable() const { DCHECK(mapping_table_ != nullptr); return *mapping_table_; @@ -171,6 +267,8 @@ class CompiledMethod : public CompiledCode { const uint32_t core_spill_mask_; // For quick code, a bit mask describing spilled FPR callee-save registers. const uint32_t fp_spill_mask_; + // For quick code, a set of pairs (PC, Line) mapping from native PC offset to Java line + SrcMap* src_mapping_table_; // For quick code, a uleb128 encoded map from native PC offset to dex PC aswell as dex PC to // native PC offset. Size prefixed. std::vector<uint8_t>* mapping_table_; diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index be79b63931..ebebe70462 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -15,6 +15,7 @@ */ #include "dex/compiler_internals.h" +#include "driver/compiler_options.h" #include "dex_file-inl.h" #include "gc_map.h" #include "gc_map_builder.h" @@ -648,15 +649,19 @@ bool Mir2Lir::VerifyCatchEntries() { void Mir2Lir::CreateMappingTables() { + bool generate_src_map = cu_->compiler_driver->GetCompilerOptions().GetIncludeDebugSymbols(); + uint32_t pc2dex_data_size = 0u; uint32_t pc2dex_entries = 0u; uint32_t pc2dex_offset = 0u; uint32_t pc2dex_dalvik_offset = 0u; + uint32_t pc2dex_src_entries = 0u; uint32_t dex2pc_data_size = 0u; uint32_t dex2pc_entries = 0u; uint32_t dex2pc_offset = 0u; uint32_t dex2pc_dalvik_offset = 0u; for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) { + pc2dex_src_entries++; if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) { pc2dex_entries += 1; DCHECK(pc2dex_offset <= tgt_lir->offset); @@ -677,6 +682,10 @@ void Mir2Lir::CreateMappingTables() { } } + if (generate_src_map) { + src_mapping_table_.reserve(pc2dex_src_entries); + } + uint32_t total_entries = pc2dex_entries + dex2pc_entries; uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries); uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size; @@ -692,6 +701,10 @@ void Mir2Lir::CreateMappingTables() { dex2pc_offset = 0u; dex2pc_dalvik_offset = 0u; for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) { + if (generate_src_map && !tgt_lir->flags.is_nop) { + src_mapping_table_.push_back(SrcMapElem({tgt_lir->offset, + static_cast<int32_t>(tgt_lir->dalvik_offset)})); + } if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) { DCHECK(pc2dex_offset <= tgt_lir->offset); write_pos = EncodeUnsignedLeb128(write_pos, tgt_lir->offset - pc2dex_offset); @@ -1088,7 +1101,7 @@ CompiledMethod* Mir2Lir::GetCompiledMethod() { std::unique_ptr<std::vector<uint8_t>> cfi_info(ReturnFrameDescriptionEntry()); CompiledMethod* result = new CompiledMethod(cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_, - core_spill_mask_, fp_spill_mask_, encoded_mapping_table_, + core_spill_mask_, fp_spill_mask_, &src_mapping_table_, encoded_mapping_table_, vmap_encoder.GetData(), native_gc_map_, cfi_info.get()); return result; } diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 4b8f794e1e..573bd9143d 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -1715,6 +1715,8 @@ class Mir2Lir : public Backend { */ int live_sreg_; CodeBuffer code_buffer_; + // The source mapping table data (pc -> dex). More entries than in encoded_mapping_table_ + SrcMap src_mapping_table_; // The encoding mapping table data (dex -> pc offset and pc offset -> dex) with a size prefix. std::vector<uint8_t> encoded_mapping_table_; ArenaVector<uint32_t> core_vmap_table_; diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 089495ee37..f4bb40cc10 100755 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -1436,8 +1436,8 @@ std::vector<uint8_t>* X86Mir2Lir::ReturnFrameDescriptionEntry() { // Generate the FDE for the method. DCHECK_NE(data_offset_, 0U); - WriteFDEHeader(cfi_info); - WriteFDEAddressRange(cfi_info, data_offset_); + WriteFDEHeader(cfi_info, cu_->target64); + WriteFDEAddressRange(cfi_info, data_offset_, cu_->target64); // The instructions in the FDE. if (stack_decrement_ != nullptr) { @@ -1497,7 +1497,7 @@ std::vector<uint8_t>* X86Mir2Lir::ReturnFrameDescriptionEntry() { } PadCFI(cfi_info); - WriteCFILength(cfi_info); + WriteCFILength(cfi_info, cu_->target64); return cfi_info; } diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 645fc1c155..49aa4b75bf 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -354,6 +354,7 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, compiler_get_method_code_addr_(NULL), support_boot_image_fixup_(instruction_set != kMips), dedupe_code_("dedupe code"), + dedupe_src_mapping_table_("dedupe source mapping table"), dedupe_mapping_table_("dedupe mapping table"), dedupe_vmap_table_("dedupe vmap table"), dedupe_gc_map_("dedupe gc map"), @@ -390,6 +391,10 @@ std::vector<uint8_t>* CompilerDriver::DeduplicateCode(const std::vector<uint8_t> return dedupe_code_.Add(Thread::Current(), code); } +SrcMap* CompilerDriver::DeduplicateSrcMappingTable(const SrcMap& src_map) { + return dedupe_src_mapping_table_.Add(Thread::Current(), src_map); +} + std::vector<uint8_t>* CompilerDriver::DeduplicateMappingTable(const std::vector<uint8_t>& code) { return dedupe_mapping_table_.Add(Thread::Current(), code); } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 233c4f887b..d8f318ba97 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -601,6 +601,7 @@ class CompilerDriver { LOCKS_EXCLUDED(compiled_classes_lock_); std::vector<uint8_t>* DeduplicateCode(const std::vector<uint8_t>& code); + SrcMap* DeduplicateSrcMappingTable(const SrcMap& src_map); std::vector<uint8_t>* DeduplicateMappingTable(const std::vector<uint8_t>& code); std::vector<uint8_t>* DeduplicateVMapTable(const std::vector<uint8_t>& code); std::vector<uint8_t>* DeduplicateGCMap(const std::vector<uint8_t>& code); @@ -770,14 +771,15 @@ class CompilerDriver { bool support_boot_image_fixup_; // DeDuplication data structures, these own the corresponding byte arrays. + template <typename ByteArray> class DedupeHashFunc { public: - size_t operator()(const std::vector<uint8_t>& array) const { + size_t operator()(const ByteArray& array) const { // For small arrays compute a hash using every byte. static const size_t kSmallArrayThreshold = 16; size_t hash = 0x811c9dc5; if (array.size() <= kSmallArrayThreshold) { - for (uint8_t b : array) { + for (auto b : array) { hash = (hash * 16777619) ^ b; } } else { @@ -803,11 +805,13 @@ class CompilerDriver { return hash; } }; - DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_code_; - DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_mapping_table_; - DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_vmap_table_; - DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_gc_map_; - DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_cfi_info_; + + DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_code_; + DedupeSet<SrcMap, size_t, DedupeHashFunc<SrcMap>, 4> dedupe_src_mapping_table_; + DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_mapping_table_; + DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_vmap_table_; + DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_gc_map_; + DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_cfi_info_; DISALLOW_COPY_AND_ASSIGN(CompilerDriver); }; diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc index 60f76efed0..bbfbc6ece0 100644 --- a/compiler/elf_fixup.cc +++ b/compiler/elf_fixup.cc @@ -38,28 +38,32 @@ bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) { Elf32_Off base_address = oat_data_begin - oatdata_address; if (!FixupDynamic(*elf_file.get(), base_address)) { - LOG(WARNING) << "Failed fo fixup .dynamic in " << file->GetPath(); - return false; + LOG(WARNING) << "Failed to fixup .dynamic in " << file->GetPath(); + return false; } if (!FixupSectionHeaders(*elf_file.get(), base_address)) { - LOG(WARNING) << "Failed fo fixup section headers in " << file->GetPath(); - return false; + LOG(WARNING) << "Failed to fixup section headers in " << file->GetPath(); + return false; } if (!FixupProgramHeaders(*elf_file.get(), base_address)) { - LOG(WARNING) << "Failed fo fixup program headers in " << file->GetPath(); - return false; + LOG(WARNING) << "Failed to fixup program headers in " << file->GetPath(); + return false; } if (!FixupSymbols(*elf_file.get(), base_address, true)) { - LOG(WARNING) << "Failed fo fixup .dynsym in " << file->GetPath(); - return false; + LOG(WARNING) << "Failed to fixup .dynsym in " << file->GetPath(); + return false; } if (!FixupSymbols(*elf_file.get(), base_address, false)) { - LOG(WARNING) << "Failed fo fixup .symtab in " << file->GetPath(); - return false; + LOG(WARNING) << "Failed to fixup .symtab in " << file->GetPath(); + return false; } if (!FixupRelocations(*elf_file.get(), base_address)) { - LOG(WARNING) << "Failed fo fixup .rel.dyn in " << file->GetPath(); - return false; + LOG(WARNING) << "Failed to fixup .rel.dyn in " << file->GetPath(); + return false; + } + if (!elf_file->FixupDebugSections(base_address)) { + LOG(WARNING) << "Failed to fixup debug sections in " << file->GetPath(); + return false; } return true; } diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index bb5f7e0f9d..e45eb61030 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -16,11 +16,14 @@ #include "elf_writer_quick.h" +#include <unordered_map> + #include "base/logging.h" #include "base/unix_file/fd_file.h" #include "buffered_output_stream.h" #include "driver/compiler_driver.h" #include "dwarf.h" +#include "elf_file.h" #include "elf_utils.h" #include "file_output_stream.h" #include "globals.h" @@ -39,6 +42,30 @@ static uint8_t MakeStInfo(uint8_t binding, uint8_t type) { return ((binding) << 4) + ((type) & 0xf); } +static void PushByte(std::vector<uint8_t>* buf, int data) { + buf->push_back(data & 0xff); +} + +static uint32_t PushStr(std::vector<uint8_t>* buf, const char* str, const char* def = nullptr) { + if (str == nullptr) { + str = def; + } + + uint32_t offset = buf->size(); + for (size_t i = 0; str[i] != '\0'; ++i) { + buf->push_back(str[i]); + } + buf->push_back('\0'); + return offset; +} + +static uint32_t PushStr(std::vector<uint8_t>* buf, const std::string &str) { + uint32_t offset = buf->size(); + buf->insert(buf->end(), str.begin(), str.end()); + buf->push_back('\0'); + return offset; +} + static void UpdateWord(std::vector<uint8_t>* buf, int offset, int data) { (*buf)[offset+0] = data; (*buf)[offset+1] = data >> 8; @@ -51,7 +78,7 @@ static void PushHalf(std::vector<uint8_t>* buf, int data) { buf->push_back((data >> 8) & 0xff); } -bool ElfWriterQuick::ElfBuilder::Write() { +bool ElfWriterQuick::ElfBuilder::Init() { // The basic layout of the elf file. Order may be different in final output. // +-------------------------+ // | Elf32_Ehdr | @@ -120,16 +147,19 @@ bool ElfWriterQuick::ElfBuilder::Write() { // | .debug_str\0 | (Optional) // | .debug_info\0 | (Optional) // | .eh_frame\0 | (Optional) + // | .debug_line\0 | (Optional) // | .debug_abbrev\0 | (Optional) // +-------------------------+ (Optional) - // | .debug_str | (Optional) - // +-------------------------+ (Optional) // | .debug_info | (Optional) // +-------------------------+ (Optional) + // | .debug_abbrev | (Optional) + // +-------------------------+ (Optional) // | .eh_frame | (Optional) // +-------------------------+ (Optional) - // | .debug_abbrev | (Optional) - // +-------------------------+ + // | .debug_line | (Optional) + // +-------------------------+ (Optional) + // | .debug_str | (Optional) + // +-------------------------+ (Optional) // | Elf32_Shdr NULL | // | Elf32_Shdr .dynsym | // | Elf32_Shdr .dynstr | @@ -138,173 +168,117 @@ bool ElfWriterQuick::ElfBuilder::Write() { // | Elf32_Shdr .rodata | // | Elf32_Shdr .dynamic | // | Elf32_Shdr .shstrtab | - // | Elf32_Shdr .debug_str | (Optional) // | Elf32_Shdr .debug_info | (Optional) - // | Elf32_Shdr .eh_frame | (Optional) // | Elf32_Shdr .debug_abbrev| (Optional) + // | Elf32_Shdr .eh_frame | (Optional) + // | Elf32_Shdr .debug_line | (Optional) + // | Elf32_Shdr .debug_str | (Optional) // +-------------------------+ - if (fatal_error_) { return false; } // Step 1. Figure out all the offsets. - // What phdr is. - uint32_t phdr_offset = sizeof(Elf32_Ehdr); - const uint8_t PH_PHDR = 0; - const uint8_t PH_LOAD_R__ = 1; - const uint8_t PH_LOAD_R_X = 2; - const uint8_t PH_LOAD_RW_ = 3; - const uint8_t PH_DYNAMIC = 4; - const uint8_t PH_NUM = 5; - uint32_t phdr_size = sizeof(Elf32_Phdr) * PH_NUM; if (debug_logging_) { - LOG(INFO) << "phdr_offset=" << phdr_offset << std::hex << " " << phdr_offset; - LOG(INFO) << "phdr_size=" << phdr_size << std::hex << " " << phdr_size; + LOG(INFO) << "phdr_offset=" << PHDR_OFFSET << std::hex << " " << PHDR_OFFSET; + LOG(INFO) << "phdr_size=" << PHDR_SIZE << std::hex << " " << PHDR_SIZE; } - Elf32_Phdr program_headers[PH_NUM]; - memset(&program_headers, 0, sizeof(program_headers)); - program_headers[PH_PHDR].p_type = PT_PHDR; - program_headers[PH_PHDR].p_offset = phdr_offset; - program_headers[PH_PHDR].p_vaddr = phdr_offset; - program_headers[PH_PHDR].p_paddr = phdr_offset; - program_headers[PH_PHDR].p_filesz = sizeof(program_headers); - program_headers[PH_PHDR].p_memsz = sizeof(program_headers); - program_headers[PH_PHDR].p_flags = PF_R; - program_headers[PH_PHDR].p_align = sizeof(Elf32_Word); - - program_headers[PH_LOAD_R__].p_type = PT_LOAD; - program_headers[PH_LOAD_R__].p_offset = 0; - program_headers[PH_LOAD_R__].p_vaddr = 0; - program_headers[PH_LOAD_R__].p_paddr = 0; - program_headers[PH_LOAD_R__].p_flags = PF_R; - - program_headers[PH_LOAD_R_X].p_type = PT_LOAD; - program_headers[PH_LOAD_R_X].p_flags = PF_R | PF_X; - - program_headers[PH_LOAD_RW_].p_type = PT_LOAD; - program_headers[PH_LOAD_RW_].p_flags = PF_R | PF_W; - - program_headers[PH_DYNAMIC].p_type = PT_DYNAMIC; - program_headers[PH_DYNAMIC].p_flags = PF_R | PF_W; + + memset(&program_headers_, 0, sizeof(program_headers_)); + program_headers_[PH_PHDR].p_type = PT_PHDR; + program_headers_[PH_PHDR].p_offset = PHDR_OFFSET; + program_headers_[PH_PHDR].p_vaddr = PHDR_OFFSET; + program_headers_[PH_PHDR].p_paddr = PHDR_OFFSET; + program_headers_[PH_PHDR].p_filesz = sizeof(program_headers_); + program_headers_[PH_PHDR].p_memsz = sizeof(program_headers_); + program_headers_[PH_PHDR].p_flags = PF_R; + program_headers_[PH_PHDR].p_align = sizeof(Elf32_Word); + + program_headers_[PH_LOAD_R__].p_type = PT_LOAD; + program_headers_[PH_LOAD_R__].p_offset = 0; + program_headers_[PH_LOAD_R__].p_vaddr = 0; + program_headers_[PH_LOAD_R__].p_paddr = 0; + program_headers_[PH_LOAD_R__].p_flags = PF_R; + + program_headers_[PH_LOAD_R_X].p_type = PT_LOAD; + program_headers_[PH_LOAD_R_X].p_flags = PF_R | PF_X; + + program_headers_[PH_LOAD_RW_].p_type = PT_LOAD; + program_headers_[PH_LOAD_RW_].p_flags = PF_R | PF_W; + + program_headers_[PH_DYNAMIC].p_type = PT_DYNAMIC; + program_headers_[PH_DYNAMIC].p_flags = PF_R | PF_W; // Get the dynstr string. - std::string dynstr(dynsym_builder_.GenerateStrtab()); + dynstr_ = dynsym_builder_.GenerateStrtab(); // Add the SONAME to the dynstr. - uint32_t dynstr_soname_offset = dynstr.size(); + dynstr_soname_offset_ = dynstr_.size(); std::string file_name(elf_file_->GetPath()); size_t directory_separator_pos = file_name.rfind('/'); if (directory_separator_pos != std::string::npos) { file_name = file_name.substr(directory_separator_pos + 1); } - dynstr += file_name; - dynstr += '\0'; + dynstr_ += file_name; + dynstr_ += '\0'; if (debug_logging_) { - LOG(INFO) << "dynstr size (bytes) =" << dynstr.size() - << std::hex << " " << dynstr.size(); + LOG(INFO) << "dynstr size (bytes) =" << dynstr_.size() + << std::hex << " " << dynstr_.size(); LOG(INFO) << "dynsym size (elements)=" << dynsym_builder_.GetSize() << std::hex << " " << dynsym_builder_.GetSize(); } - // get the strtab - std::string strtab; - if (IncludingDebugSymbols()) { - strtab = symtab_builder_.GenerateStrtab(); - if (debug_logging_) { - LOG(INFO) << "strtab size (bytes) =" << strtab.size() - << std::hex << " " << strtab.size(); - LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize() - << std::hex << " " << symtab_builder_.GetSize(); - } - } - // Get the section header string table. - std::vector<Elf32_Shdr*> section_ptrs; - std::string shstrtab; - shstrtab += '\0'; + shstrtab_ += '\0'; // Setup sym_undef - Elf32_Shdr null_hdr; - memset(&null_hdr, 0, sizeof(null_hdr)); - null_hdr.sh_type = SHT_NULL; - null_hdr.sh_link = SHN_UNDEF; - section_ptrs.push_back(&null_hdr); + memset(&null_hdr_, 0, sizeof(null_hdr_)); + null_hdr_.sh_type = SHT_NULL; + null_hdr_.sh_link = SHN_UNDEF; + section_ptrs_.push_back(&null_hdr_); - uint32_t section_index = 1; + section_index_ = 1; // setup .dynsym - section_ptrs.push_back(&dynsym_builder_.section_); - AssignSectionStr(&dynsym_builder_, &shstrtab); - dynsym_builder_.section_index_ = section_index++; + section_ptrs_.push_back(&dynsym_builder_.section_); + AssignSectionStr(&dynsym_builder_, &shstrtab_); + dynsym_builder_.section_index_ = section_index_++; // Setup .dynstr - section_ptrs.push_back(&dynsym_builder_.strtab_.section_); - AssignSectionStr(&dynsym_builder_.strtab_, &shstrtab); - dynsym_builder_.strtab_.section_index_ = section_index++; + section_ptrs_.push_back(&dynsym_builder_.strtab_.section_); + AssignSectionStr(&dynsym_builder_.strtab_, &shstrtab_); + dynsym_builder_.strtab_.section_index_ = section_index_++; // Setup .hash - section_ptrs.push_back(&hash_builder_.section_); - AssignSectionStr(&hash_builder_, &shstrtab); - hash_builder_.section_index_ = section_index++; + section_ptrs_.push_back(&hash_builder_.section_); + AssignSectionStr(&hash_builder_, &shstrtab_); + hash_builder_.section_index_ = section_index_++; // Setup .rodata - section_ptrs.push_back(&rodata_builder_.section_); - AssignSectionStr(&rodata_builder_, &shstrtab); - rodata_builder_.section_index_ = section_index++; + section_ptrs_.push_back(&rodata_builder_.section_); + AssignSectionStr(&rodata_builder_, &shstrtab_); + rodata_builder_.section_index_ = section_index_++; // Setup .text - section_ptrs.push_back(&text_builder_.section_); - AssignSectionStr(&text_builder_, &shstrtab); - text_builder_.section_index_ = section_index++; + section_ptrs_.push_back(&text_builder_.section_); + AssignSectionStr(&text_builder_, &shstrtab_); + text_builder_.section_index_ = section_index_++; // Setup .dynamic - section_ptrs.push_back(&dynamic_builder_.section_); - AssignSectionStr(&dynamic_builder_, &shstrtab); - dynamic_builder_.section_index_ = section_index++; - - if (IncludingDebugSymbols()) { - // Setup .symtab - section_ptrs.push_back(&symtab_builder_.section_); - AssignSectionStr(&symtab_builder_, &shstrtab); - symtab_builder_.section_index_ = section_index++; - - // Setup .strtab - section_ptrs.push_back(&symtab_builder_.strtab_.section_); - AssignSectionStr(&symtab_builder_.strtab_, &shstrtab); - symtab_builder_.strtab_.section_index_ = section_index++; - } - ElfRawSectionBuilder* it = other_builders_.data(); - for (uint32_t cnt = 0; cnt < other_builders_.size(); ++it, ++cnt) { - // Setup all the other sections. - section_ptrs.push_back(&it->section_); - AssignSectionStr(it, &shstrtab); - it->section_index_ = section_index++; - } - - // Setup shstrtab - section_ptrs.push_back(&shstrtab_builder_.section_); - AssignSectionStr(&shstrtab_builder_, &shstrtab); - shstrtab_builder_.section_index_ = section_index++; - - if (debug_logging_) { - LOG(INFO) << ".shstrtab size (bytes) =" << shstrtab.size() - << std::hex << " " << shstrtab.size(); - LOG(INFO) << "section list size (elements)=" << section_ptrs.size() - << std::hex << " " << section_ptrs.size(); - } + section_ptrs_.push_back(&dynamic_builder_.section_); + AssignSectionStr(&dynamic_builder_, &shstrtab_); + dynamic_builder_.section_index_ = section_index_++; // Fill in the hash section. - std::vector<Elf32_Word> hash = dynsym_builder_.GenerateHashContents(); + hash_ = dynsym_builder_.GenerateHashContents(); if (debug_logging_) { - LOG(INFO) << ".hash size (bytes)=" << hash.size() * sizeof(Elf32_Word) - << std::hex << " " << hash.size() * sizeof(Elf32_Word); + LOG(INFO) << ".hash size (bytes)=" << hash_.size() * sizeof(Elf32_Word) + << std::hex << " " << hash_.size() * sizeof(Elf32_Word); } - Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers); - std::vector<ElfFilePiece> pieces; + Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers_); // Get the layout in the sections. // @@ -318,14 +292,14 @@ bool ElfWriterQuick::ElfBuilder::Write() { dynsym_builder_.strtab_.section_.sh_offset = NextOffset(dynsym_builder_.strtab_.section_, dynsym_builder_.section_); dynsym_builder_.strtab_.section_.sh_addr = dynsym_builder_.strtab_.section_.sh_offset; - dynsym_builder_.strtab_.section_.sh_size = dynstr.size(); + dynsym_builder_.strtab_.section_.sh_size = dynstr_.size(); dynsym_builder_.strtab_.section_.sh_link = dynsym_builder_.strtab_.GetLink(); // Get the layout of the hash section hash_builder_.section_.sh_offset = NextOffset(hash_builder_.section_, dynsym_builder_.strtab_.section_); hash_builder_.section_.sh_addr = hash_builder_.section_.sh_offset; - hash_builder_.section_.sh_size = hash.size() * sizeof(Elf32_Word); + hash_builder_.section_.sh_size = hash_.size() * sizeof(Elf32_Word); hash_builder_.section_.sh_link = hash_builder_.GetLink(); // Get the layout of the rodata section. @@ -349,7 +323,70 @@ bool ElfWriterQuick::ElfBuilder::Write() { dynamic_builder_.section_.sh_size = dynamic_builder_.GetSize() * sizeof(Elf32_Dyn); dynamic_builder_.section_.sh_link = dynamic_builder_.GetLink(); + if (debug_logging_) { + LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset + << " dynsym size=" << dynsym_builder_.section_.sh_size; + LOG(INFO) << "dynstr off=" << dynsym_builder_.strtab_.section_.sh_offset + << " dynstr size=" << dynsym_builder_.strtab_.section_.sh_size; + LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset + << " hash size=" << hash_builder_.section_.sh_size; + LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset + << " rodata size=" << rodata_builder_.section_.sh_size; + LOG(INFO) << "text off=" << text_builder_.section_.sh_offset + << " text size=" << text_builder_.section_.sh_size; + LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset + << " dynamic size=" << dynamic_builder_.section_.sh_size; + } + + return true; +} + +bool ElfWriterQuick::ElfBuilder::Write() { + std::vector<ElfFilePiece> pieces; Elf32_Shdr prev = dynamic_builder_.section_; + std::string strtab; + + if (IncludingDebugSymbols()) { + // Setup .symtab + section_ptrs_.push_back(&symtab_builder_.section_); + AssignSectionStr(&symtab_builder_, &shstrtab_); + symtab_builder_.section_index_ = section_index_++; + + // Setup .strtab + section_ptrs_.push_back(&symtab_builder_.strtab_.section_); + AssignSectionStr(&symtab_builder_.strtab_, &shstrtab_); + symtab_builder_.strtab_.section_index_ = section_index_++; + + strtab = symtab_builder_.GenerateStrtab(); + if (debug_logging_) { + LOG(INFO) << "strtab size (bytes) =" << strtab.size() + << std::hex << " " << strtab.size(); + LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize() + << std::hex << " " << symtab_builder_.GetSize(); + } + } + + // Setup all the other sections. + for (ElfRawSectionBuilder *builder = other_builders_.data(), + *end = builder + other_builders_.size(); + builder != end; ++builder) { + section_ptrs_.push_back(&builder->section_); + AssignSectionStr(builder, &shstrtab_); + builder->section_index_ = section_index_++; + } + + // Setup shstrtab + section_ptrs_.push_back(&shstrtab_builder_.section_); + AssignSectionStr(&shstrtab_builder_, &shstrtab_); + shstrtab_builder_.section_index_ = section_index_++; + + if (debug_logging_) { + LOG(INFO) << ".shstrtab size (bytes) =" << shstrtab_.size() + << std::hex << " " << shstrtab_.size(); + LOG(INFO) << "section list size (elements)=" << section_ptrs_.size() + << std::hex << " " << section_ptrs_.size(); + } + if (IncludingDebugSymbols()) { // Get the layout of the symtab section. symtab_builder_.section_.sh_offset = NextOffset(symtab_builder_.section_, @@ -367,27 +404,14 @@ bool ElfWriterQuick::ElfBuilder::Write() { symtab_builder_.strtab_.section_.sh_link = symtab_builder_.strtab_.GetLink(); prev = symtab_builder_.strtab_.section_; - } - if (debug_logging_) { - LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset - << " dynsym size=" << dynsym_builder_.section_.sh_size; - LOG(INFO) << "dynstr off=" << dynsym_builder_.strtab_.section_.sh_offset - << " dynstr size=" << dynsym_builder_.strtab_.section_.sh_size; - LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset - << " hash size=" << hash_builder_.section_.sh_size; - LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset - << " rodata size=" << rodata_builder_.section_.sh_size; - LOG(INFO) << "text off=" << text_builder_.section_.sh_offset - << " text size=" << text_builder_.section_.sh_size; - LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset - << " dynamic size=" << dynamic_builder_.section_.sh_size; - if (IncludingDebugSymbols()) { + if (debug_logging_) { LOG(INFO) << "symtab off=" << symtab_builder_.section_.sh_offset << " symtab size=" << symtab_builder_.section_.sh_size; LOG(INFO) << "strtab off=" << symtab_builder_.strtab_.section_.sh_offset << " strtab size=" << symtab_builder_.strtab_.section_.sh_size; } } + // Get the layout of the extra sections. (This will deal with the debug // sections if they are there) for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) { @@ -403,10 +427,11 @@ bool ElfWriterQuick::ElfBuilder::Write() { << " " << it->name_ << " size=" << it->section_.sh_size; } } + // Get the layout of the shstrtab section shstrtab_builder_.section_.sh_offset = NextOffset(shstrtab_builder_.section_, prev); shstrtab_builder_.section_.sh_addr = 0; - shstrtab_builder_.section_.sh_size = shstrtab.size(); + shstrtab_builder_.section_.sh_size = shstrtab_.size(); shstrtab_builder_.section_.sh_link = shstrtab_builder_.GetLink(); if (debug_logging_) { LOG(INFO) << "shstrtab off=" << shstrtab_builder_.section_.sh_offset @@ -430,58 +455,58 @@ bool ElfWriterQuick::ElfBuilder::Write() { // Setup the dynamic section. // This will add the 2 values we cannot know until now time, namely the size // and the soname_offset. - std::vector<Elf32_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr.size(), - dynstr_soname_offset); + std::vector<Elf32_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr_.size(), + dynstr_soname_offset_); CHECK_EQ(dynamic.size() * sizeof(Elf32_Dyn), dynamic_builder_.section_.sh_size); // Finish setup of the program headers now that we know the layout of the // whole file. Elf32_Word load_r_size = rodata_builder_.section_.sh_offset + rodata_builder_.section_.sh_size; - program_headers[PH_LOAD_R__].p_filesz = load_r_size; - program_headers[PH_LOAD_R__].p_memsz = load_r_size; - program_headers[PH_LOAD_R__].p_align = rodata_builder_.section_.sh_addralign; + program_headers_[PH_LOAD_R__].p_filesz = load_r_size; + program_headers_[PH_LOAD_R__].p_memsz = load_r_size; + program_headers_[PH_LOAD_R__].p_align = rodata_builder_.section_.sh_addralign; Elf32_Word load_rx_size = text_builder_.section_.sh_size; - program_headers[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset; - program_headers[PH_LOAD_R_X].p_vaddr = text_builder_.section_.sh_offset; - program_headers[PH_LOAD_R_X].p_paddr = text_builder_.section_.sh_offset; - program_headers[PH_LOAD_R_X].p_filesz = load_rx_size; - program_headers[PH_LOAD_R_X].p_memsz = load_rx_size; - program_headers[PH_LOAD_R_X].p_align = text_builder_.section_.sh_addralign; - - program_headers[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset; - program_headers[PH_LOAD_RW_].p_vaddr = dynamic_builder_.section_.sh_offset; - program_headers[PH_LOAD_RW_].p_paddr = dynamic_builder_.section_.sh_offset; - program_headers[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size; - program_headers[PH_LOAD_RW_].p_memsz = dynamic_builder_.section_.sh_size; - program_headers[PH_LOAD_RW_].p_align = dynamic_builder_.section_.sh_addralign; - - program_headers[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset; - program_headers[PH_DYNAMIC].p_vaddr = dynamic_builder_.section_.sh_offset; - program_headers[PH_DYNAMIC].p_paddr = dynamic_builder_.section_.sh_offset; - program_headers[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size; - program_headers[PH_DYNAMIC].p_memsz = dynamic_builder_.section_.sh_size; - program_headers[PH_DYNAMIC].p_align = dynamic_builder_.section_.sh_addralign; + program_headers_[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset; + program_headers_[PH_LOAD_R_X].p_vaddr = text_builder_.section_.sh_offset; + program_headers_[PH_LOAD_R_X].p_paddr = text_builder_.section_.sh_offset; + program_headers_[PH_LOAD_R_X].p_filesz = load_rx_size; + program_headers_[PH_LOAD_R_X].p_memsz = load_rx_size; + program_headers_[PH_LOAD_R_X].p_align = text_builder_.section_.sh_addralign; + + program_headers_[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset; + program_headers_[PH_LOAD_RW_].p_vaddr = dynamic_builder_.section_.sh_offset; + program_headers_[PH_LOAD_RW_].p_paddr = dynamic_builder_.section_.sh_offset; + program_headers_[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size; + program_headers_[PH_LOAD_RW_].p_memsz = dynamic_builder_.section_.sh_size; + program_headers_[PH_LOAD_RW_].p_align = dynamic_builder_.section_.sh_addralign; + + program_headers_[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset; + program_headers_[PH_DYNAMIC].p_vaddr = dynamic_builder_.section_.sh_offset; + program_headers_[PH_DYNAMIC].p_paddr = dynamic_builder_.section_.sh_offset; + program_headers_[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size; + program_headers_[PH_DYNAMIC].p_memsz = dynamic_builder_.section_.sh_size; + program_headers_[PH_DYNAMIC].p_align = dynamic_builder_.section_.sh_addralign; // Finish setup of the Ehdr values. - elf_header_.e_phoff = phdr_offset; + elf_header_.e_phoff = PHDR_OFFSET; elf_header_.e_shoff = sections_offset; elf_header_.e_phnum = PH_NUM; - elf_header_.e_shnum = section_ptrs.size(); + elf_header_.e_shnum = section_ptrs_.size(); elf_header_.e_shstrndx = shstrtab_builder_.section_index_; // Add the rest of the pieces to the list. pieces.push_back(ElfFilePiece("Elf Header", 0, &elf_header_, sizeof(elf_header_))); - pieces.push_back(ElfFilePiece("Program headers", phdr_offset, - &program_headers, sizeof(program_headers))); + pieces.push_back(ElfFilePiece("Program headers", PHDR_OFFSET, + &program_headers_, sizeof(program_headers_))); pieces.push_back(ElfFilePiece(".dynamic", dynamic_builder_.section_.sh_offset, dynamic.data(), dynamic_builder_.section_.sh_size)); pieces.push_back(ElfFilePiece(".dynsym", dynsym_builder_.section_.sh_offset, dynsym.data(), dynsym.size() * sizeof(Elf32_Sym))); pieces.push_back(ElfFilePiece(".dynstr", dynsym_builder_.strtab_.section_.sh_offset, - dynstr.c_str(), dynstr.size())); + dynstr_.c_str(), dynstr_.size())); pieces.push_back(ElfFilePiece(".hash", hash_builder_.section_.sh_offset, - hash.data(), hash.size() * sizeof(Elf32_Word))); + hash_.data(), hash_.size() * sizeof(Elf32_Word))); pieces.push_back(ElfFilePiece(".rodata", rodata_builder_.section_.sh_offset, nullptr, rodata_builder_.section_.sh_size)); pieces.push_back(ElfFilePiece(".text", text_builder_.section_.sh_offset, @@ -493,13 +518,13 @@ bool ElfWriterQuick::ElfBuilder::Write() { strtab.c_str(), strtab.size())); } pieces.push_back(ElfFilePiece(".shstrtab", shstrtab_builder_.section_.sh_offset, - &shstrtab[0], shstrtab.size())); - for (uint32_t i = 0; i < section_ptrs.size(); ++i) { + &shstrtab_[0], shstrtab_.size())); + for (uint32_t i = 0; i < section_ptrs_.size(); ++i) { // Just add all the sections in induvidually since they are all over the // place on the heap/stack. Elf32_Word cur_off = sections_offset + i * sizeof(Elf32_Shdr); pieces.push_back(ElfFilePiece("section table piece", cur_off, - section_ptrs[i], sizeof(Elf32_Shdr))); + section_ptrs_[i], sizeof(Elf32_Shdr))); } if (!WriteOutFile(pieces)) { @@ -664,7 +689,7 @@ std::vector<Elf32_Word> ElfWriterQuick::ElfSymtabBuilder::GenerateHashContents() // Lets say the state is something like this. // +--------+ +--------+ +-----------+ // | symtab | | bucket | | chain | - // | nullptr | | 1 | | STN_UNDEF | + // | null | | 1 | | STN_UNDEF | // | <sym1> | | 4 | | 2 | // | <sym2> | | | | 5 | // | <sym3> | | | | STN_UNDEF | @@ -836,13 +861,24 @@ void ElfWriterQuick::ReservePatchSpace(std::vector<uint8_t>* buffer, bool debug) } std::vector<uint8_t>* ConstructCIEFrameX86(bool is_x86_64) { - std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>; + std::vector<uint8_t>* cfi_info = new std::vector<uint8_t>; // Length (will be filled in later in this routine). - PushWord(cfi_info, 0); + if (is_x86_64) { + PushWord(cfi_info, 0xffffffff); // Indicates 64bit + PushWord(cfi_info, 0); + PushWord(cfi_info, 0); + } else { + PushWord(cfi_info, 0); + } // CIE id: always 0. - PushWord(cfi_info, 0); + if (is_x86_64) { + PushWord(cfi_info, 0); + PushWord(cfi_info, 0); + } else { + PushWord(cfi_info, 0); + } // Version: always 1. cfi_info->push_back(0x01); @@ -874,8 +910,14 @@ std::vector<uint8_t>* ConstructCIEFrameX86(bool is_x86_64) { // Augmentation length: 1. cfi_info->push_back(1); - // Augmentation data: 0x03 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4). - cfi_info->push_back(0x03); + // Augmentation data. + if (is_x86_64) { + // 0x04 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8). + cfi_info->push_back(0x04); + } else { + // 0x03 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4). + cfi_info->push_back(0x03); + } // Initial instructions. if (is_x86_64) { @@ -905,11 +947,13 @@ std::vector<uint8_t>* ConstructCIEFrameX86(bool is_x86_64) { } // Set the length of the CIE inside the generated bytes. - uint32_t length = cfi_info->size() - 4; - (*cfi_info)[0] = length; - (*cfi_info)[1] = length >> 8; - (*cfi_info)[2] = length >> 16; - (*cfi_info)[3] = length >> 24; + if (is_x86_64) { + uint32_t length = cfi_info->size() - 12; + UpdateWord(cfi_info, 4, length); + } else { + uint32_t length = cfi_info->size() - 4; + UpdateWord(cfi_info, 0, length); + } return cfi_info; } @@ -940,8 +984,12 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols(), debug); + if (!builder.Init()) { + return false; + } + if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) { - WriteDebugSymbols(builder, oat_writer); + WriteDebugSymbols(&builder, oat_writer); } if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) { @@ -954,15 +1002,17 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, return builder.Write(); } -void ElfWriterQuick::WriteDebugSymbols(ElfBuilder& builder, OatWriter* oat_writer) { +void ElfWriterQuick::WriteDebugSymbols(ElfBuilder* builder, OatWriter* oat_writer) { std::unique_ptr<std::vector<uint8_t>> cfi_info( ConstructCIEFrame(compiler_driver_->GetInstructionSet())); + Elf32_Addr text_section_address = builder->text_builder_.section_.sh_addr; + // Iterate over the compiled methods. const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo(); - ElfSymtabBuilder* symtab = &builder.symtab_builder_; + ElfSymtabBuilder* symtab = &builder->symtab_builder_; for (auto it = method_info.begin(); it != method_info.end(); ++it) { - symtab->AddSymbol(it->method_name_, &builder.text_builder_, it->low_pc_, true, + symtab->AddSymbol(it->method_name_, &builder->text_builder_, it->low_pc_, true, it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC); // Include CFI for compiled method, if possible. @@ -976,96 +1026,314 @@ void ElfWriterQuick::WriteDebugSymbols(ElfBuilder& builder, OatWriter* oat_write int cur_offset = cfi_info->size(); cfi_info->insert(cfi_info->end(), fde->begin(), fde->end()); - // Set the 'CIE_pointer' field to cur_offset+4. - uint32_t CIE_pointer = cur_offset + 4; - uint32_t offset_to_update = cur_offset + sizeof(uint32_t); - (*cfi_info)[offset_to_update+0] = CIE_pointer; - (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8; - (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16; - (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24; - - // Set the 'initial_location' field to address the start of the method. - offset_to_update = cur_offset + 2*sizeof(uint32_t); - const uint32_t quick_code_start = it->low_pc_; - (*cfi_info)[offset_to_update+0] = quick_code_start; - (*cfi_info)[offset_to_update+1] = quick_code_start >> 8; - (*cfi_info)[offset_to_update+2] = quick_code_start >> 16; - (*cfi_info)[offset_to_update+3] = quick_code_start >> 24; + bool is_64bit = *(reinterpret_cast<const uint32_t*>(fde->data())) == 0xffffffff; + + // Set the 'CIE_pointer' field. + uint64_t CIE_pointer = cur_offset + (is_64bit ? 12 : 4); + uint64_t offset_to_update = CIE_pointer; + if (is_64bit) { + (*cfi_info)[offset_to_update+0] = CIE_pointer; + (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8; + (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16; + (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24; + (*cfi_info)[offset_to_update+4] = CIE_pointer >> 32; + (*cfi_info)[offset_to_update+5] = CIE_pointer >> 40; + (*cfi_info)[offset_to_update+6] = CIE_pointer >> 48; + (*cfi_info)[offset_to_update+7] = CIE_pointer >> 56; + } else { + (*cfi_info)[offset_to_update+0] = CIE_pointer; + (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8; + (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16; + (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24; + } + + // Set the 'initial_location' field. + offset_to_update += is_64bit ? 8 : 4; + if (is_64bit) { + const uint64_t quick_code_start = it->low_pc_ + text_section_address; + (*cfi_info)[offset_to_update+0] = quick_code_start; + (*cfi_info)[offset_to_update+1] = quick_code_start >> 8; + (*cfi_info)[offset_to_update+2] = quick_code_start >> 16; + (*cfi_info)[offset_to_update+3] = quick_code_start >> 24; + (*cfi_info)[offset_to_update+4] = quick_code_start >> 32; + (*cfi_info)[offset_to_update+5] = quick_code_start >> 40; + (*cfi_info)[offset_to_update+6] = quick_code_start >> 48; + (*cfi_info)[offset_to_update+7] = quick_code_start >> 56; + } else { + const uint32_t quick_code_start = it->low_pc_ + text_section_address; + (*cfi_info)[offset_to_update+0] = quick_code_start; + (*cfi_info)[offset_to_update+1] = quick_code_start >> 8; + (*cfi_info)[offset_to_update+2] = quick_code_start >> 16; + (*cfi_info)[offset_to_update+3] = quick_code_start >> 24; + } } } } - if (cfi_info.get() != nullptr) { - // Now lay down the Elf sections. - ElfRawSectionBuilder debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + bool hasCFI = (cfi_info.get() != nullptr); + bool hasLineInfo = false; + for (auto& dbg_info : oat_writer->GetCFIMethodInfo()) { + if (dbg_info.dbgstream_ != nullptr && + !dbg_info.compiled_method_->GetSrcMappingTable().empty()) { + hasLineInfo = true; + break; + } + } + + if (hasLineInfo || hasCFI) { + ElfRawSectionBuilder debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0); ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0); - ElfRawSectionBuilder debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0); - ElfRawSectionBuilder eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0); - eh_frame.SetBuffer(std::move(*cfi_info.get())); - - FillInCFIInformation(oat_writer, debug_info.GetBuffer(), debug_abbrev.GetBuffer(), - debug_str.GetBuffer()); - builder.RegisterRawSection(debug_info); - builder.RegisterRawSection(debug_abbrev); - builder.RegisterRawSection(eh_frame); - builder.RegisterRawSection(debug_str); + ElfRawSectionBuilder debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + ElfRawSectionBuilder debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0); + + FillInCFIInformation(oat_writer, debug_info.GetBuffer(), + debug_abbrev.GetBuffer(), debug_str.GetBuffer(), + hasLineInfo ? debug_line.GetBuffer() : nullptr, + text_section_address); + + builder->RegisterRawSection(debug_info); + builder->RegisterRawSection(debug_abbrev); + + if (hasCFI) { + ElfRawSectionBuilder eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0); + eh_frame.SetBuffer(std::move(*cfi_info.get())); + builder->RegisterRawSection(eh_frame); + } + + if (hasLineInfo) { + builder->RegisterRawSection(debug_line); + } + + builder->RegisterRawSection(debug_str); + } +} + +class LineTableGenerator FINAL : public Leb128Encoder { + public: + LineTableGenerator(int line_base, int line_range, int opcode_base, + std::vector<uint8_t>* data, uintptr_t current_address, + size_t current_line) + : Leb128Encoder(data), line_base_(line_base), line_range_(line_range), + opcode_base_(opcode_base), current_address_(current_address), + current_line_(current_line) {} + + void PutDelta(unsigned delta_addr, int delta_line) { + current_line_ += delta_line; + current_address_ += delta_addr; + + if (delta_line >= line_base_ && delta_line < line_base_ + line_range_) { + unsigned special_opcode = (delta_line - line_base_) + + (line_range_ * delta_addr) + opcode_base_; + if (special_opcode <= 255) { + PushByte(data_, special_opcode); + return; + } + } + + // generate standart opcode for address advance + if (delta_addr != 0) { + PushByte(data_, DW_LNS_advance_pc); + PushBackUnsigned(delta_addr); + } + + // generate standart opcode for line delta + if (delta_line != 0) { + PushByte(data_, DW_LNS_advance_line); + PushBackSigned(delta_line); + } + + // generate standart opcode for new LTN entry + PushByte(data_, DW_LNS_copy); + } + + void SetAddr(uintptr_t addr) { + if (current_address_ == addr) { + return; + } + + current_address_ = addr; + + PushByte(data_, 0); // extended opcode: + PushByte(data_, 1 + 4); // length: opcode_size + address_size + PushByte(data_, DW_LNE_set_address); + PushWord(data_, addr); + } + + void SetLine(unsigned line) { + int delta_line = line - current_line_; + if (delta_line) { + current_line_ = line; + PushByte(data_, DW_LNS_advance_line); + PushBackSigned(delta_line); + } + } + + void SetFile(unsigned file_index) { + PushByte(data_, DW_LNS_set_file); + PushBackUnsigned(file_index); + } + + void EndSequence() { + // End of Line Table Program + // 0(=ext), 1(len), DW_LNE_end_sequence + PushByte(data_, 0); + PushByte(data_, 1); + PushByte(data_, DW_LNE_end_sequence); + } + + private: + const int line_base_; + const int line_range_; + const int opcode_base_; + uintptr_t current_address_; + size_t current_line_; + + DISALLOW_COPY_AND_ASSIGN(LineTableGenerator); +}; + +// TODO: rewriting it using DexFile::DecodeDebugInfo needs unneeded stuff. +static void GetLineInfoForJava(const uint8_t* dbgstream, const SrcMap& pc2dex, + SrcMap* result, uint32_t start_pc = 0) { + if (dbgstream == nullptr) { + return; + } + + int adjopcode; + uint32_t dex_offset = 0; + uint32_t java_line = DecodeUnsignedLeb128(&dbgstream); + + // skip parameters + for (uint32_t param_count = DecodeUnsignedLeb128(&dbgstream); param_count != 0; --param_count) { + DecodeUnsignedLeb128(&dbgstream); + } + + for (bool is_end = false; is_end == false; ) { + uint8_t opcode = *dbgstream; + dbgstream++; + switch (opcode) { + case DexFile::DBG_END_SEQUENCE: + is_end = true; + break; + + case DexFile::DBG_ADVANCE_PC: + dex_offset += DecodeUnsignedLeb128(&dbgstream); + break; + + case DexFile::DBG_ADVANCE_LINE: + java_line += DecodeSignedLeb128(&dbgstream); + break; + + case DexFile::DBG_START_LOCAL: + case DexFile::DBG_START_LOCAL_EXTENDED: + DecodeUnsignedLeb128(&dbgstream); + DecodeUnsignedLeb128(&dbgstream); + DecodeUnsignedLeb128(&dbgstream); + + if (opcode == DexFile::DBG_START_LOCAL_EXTENDED) { + DecodeUnsignedLeb128(&dbgstream); + } + break; + + case DexFile::DBG_END_LOCAL: + case DexFile::DBG_RESTART_LOCAL: + DecodeUnsignedLeb128(&dbgstream); + break; + + case DexFile::DBG_SET_PROLOGUE_END: + case DexFile::DBG_SET_EPILOGUE_BEGIN: + case DexFile::DBG_SET_FILE: + break; + + default: + adjopcode = opcode - DexFile::DBG_FIRST_SPECIAL; + dex_offset += adjopcode / DexFile::DBG_LINE_RANGE; + java_line += DexFile::DBG_LINE_BASE + (adjopcode % DexFile::DBG_LINE_RANGE); + + for (SrcMap::const_iterator found = pc2dex.FindByTo(dex_offset); + found != pc2dex.end() && found->to_ == static_cast<int32_t>(dex_offset); + found++) { + result->push_back({found->from_ + start_pc, static_cast<int32_t>(java_line)}); + } + break; + } } } void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_info, std::vector<uint8_t>* dbg_abbrev, - std::vector<uint8_t>* dbg_str) { + std::vector<uint8_t>* dbg_str, + std::vector<uint8_t>* dbg_line, + uint32_t text_section_offset) { + const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo(); + + uint32_t producer_str_offset = PushStr(dbg_str, "Android dex2oat"); + // Create the debug_abbrev section with boilerplate information. // We only care about low_pc and high_pc right now for the compilation // unit and methods. // Tag 1: Compilation unit: DW_TAG_compile_unit. - dbg_abbrev->push_back(1); - dbg_abbrev->push_back(DW_TAG_compile_unit); + PushByte(dbg_abbrev, 1); + PushByte(dbg_abbrev, DW_TAG_compile_unit); // There are children (the methods). - dbg_abbrev->push_back(DW_CHILDREN_yes); + PushByte(dbg_abbrev, DW_CHILDREN_yes); + + // DW_AT_producer DW_FORM_data1. + // REVIEW: we can get rid of dbg_str section if + // DW_FORM_string (immediate string) was used everywhere instead of + // DW_FORM_strp (ref to string from .debug_str section). + // DW_FORM_strp makes sense only if we reuse the strings. + PushByte(dbg_abbrev, DW_AT_producer); + PushByte(dbg_abbrev, DW_FORM_strp); // DW_LANG_Java DW_FORM_data1. - dbg_abbrev->push_back(DW_AT_language); - dbg_abbrev->push_back(DW_FORM_data1); + PushByte(dbg_abbrev, DW_AT_language); + PushByte(dbg_abbrev, DW_FORM_data1); // DW_AT_low_pc DW_FORM_addr. - dbg_abbrev->push_back(DW_AT_low_pc); - dbg_abbrev->push_back(DW_FORM_addr); + PushByte(dbg_abbrev, DW_AT_low_pc); + PushByte(dbg_abbrev, DW_FORM_addr); // DW_AT_high_pc DW_FORM_addr. - dbg_abbrev->push_back(DW_AT_high_pc); - dbg_abbrev->push_back(DW_FORM_addr); + PushByte(dbg_abbrev, DW_AT_high_pc); + PushByte(dbg_abbrev, DW_FORM_addr); + + if (dbg_line != nullptr) { + // DW_AT_stmt_list DW_FORM_sec_offset. + PushByte(dbg_abbrev, DW_AT_stmt_list); + PushByte(dbg_abbrev, DW_FORM_sec_offset); + } // End of DW_TAG_compile_unit. PushHalf(dbg_abbrev, 0); // Tag 2: Compilation unit: DW_TAG_subprogram. - dbg_abbrev->push_back(2); - dbg_abbrev->push_back(DW_TAG_subprogram); + PushByte(dbg_abbrev, 2); + PushByte(dbg_abbrev, DW_TAG_subprogram); // There are no children. - dbg_abbrev->push_back(DW_CHILDREN_no); + PushByte(dbg_abbrev, DW_CHILDREN_no); // Name of the method. - dbg_abbrev->push_back(DW_AT_name); - dbg_abbrev->push_back(DW_FORM_strp); + PushByte(dbg_abbrev, DW_AT_name); + PushByte(dbg_abbrev, DW_FORM_strp); // DW_AT_low_pc DW_FORM_addr. - dbg_abbrev->push_back(DW_AT_low_pc); - dbg_abbrev->push_back(DW_FORM_addr); + PushByte(dbg_abbrev, DW_AT_low_pc); + PushByte(dbg_abbrev, DW_FORM_addr); // DW_AT_high_pc DW_FORM_addr. - dbg_abbrev->push_back(DW_AT_high_pc); - dbg_abbrev->push_back(DW_FORM_addr); + PushByte(dbg_abbrev, DW_AT_high_pc); + PushByte(dbg_abbrev, DW_FORM_addr); // End of DW_TAG_subprogram. PushHalf(dbg_abbrev, 0); // Start the debug_info section with the header information // 'unit_length' will be filled in later. + int cunit_length = dbg_info->size(); PushWord(dbg_info, 0); // 'version' - 3. @@ -1075,55 +1343,153 @@ void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer, PushWord(dbg_info, 0); // Address size: 4. - dbg_info->push_back(4); + PushByte(dbg_info, 4); // Start the description for the compilation unit. // This uses tag 1. - dbg_info->push_back(1); + PushByte(dbg_info, 1); + + // The producer is Android dex2oat. + PushWord(dbg_info, producer_str_offset); // The language is Java. - dbg_info->push_back(DW_LANG_Java); + PushByte(dbg_info, DW_LANG_Java); - // Leave space for low_pc and high_pc. - int low_pc_offset = dbg_info->size(); + // low_pc and high_pc. + uint32_t cunit_low_pc = 0 - 1; + uint32_t cunit_high_pc = 0; + int cunit_low_pc_pos = dbg_info->size(); PushWord(dbg_info, 0); PushWord(dbg_info, 0); - // Walk through the information in the method table, and enter into dbg_info. - const std::vector<OatWriter::DebugInfo>& dbg = oat_writer->GetCFIMethodInfo(); - uint32_t low_pc = 0xFFFFFFFFU; - uint32_t high_pc = 0; + if (dbg_line == nullptr) { + for (size_t i = 0; i < method_info.size(); ++i) { + const OatWriter::DebugInfo &dbg = method_info[i]; + + cunit_low_pc = std::min(cunit_low_pc, dbg.low_pc_); + cunit_high_pc = std::max(cunit_high_pc, dbg.high_pc_); + + // Start a new TAG: subroutine (2). + PushByte(dbg_info, 2); - for (uint32_t i = 0; i < dbg.size(); i++) { - const OatWriter::DebugInfo& info = dbg[i]; - if (info.low_pc_ < low_pc) { - low_pc = info.low_pc_; + // Enter name, low_pc, high_pc. + PushWord(dbg_info, PushStr(dbg_str, dbg.method_name_)); + PushWord(dbg_info, dbg.low_pc_ + text_section_offset); + PushWord(dbg_info, dbg.high_pc_ + text_section_offset); } - if (info.high_pc_ > high_pc) { - high_pc = info.high_pc_; + } else { + // TODO: in gdb info functions <regexp> - reports Java functions, but + // source file is <unknown> because .debug_line is formed as one + // compilation unit. To fix this it is possible to generate + // a separate compilation unit for every distinct Java source. + // Each of the these compilation units can have several non-adjacent + // method ranges. + + // Line number table offset + PushWord(dbg_info, dbg_line->size()); + + size_t lnt_length = dbg_line->size(); + PushWord(dbg_line, 0); + + PushHalf(dbg_line, 4); // LNT Version DWARF v4 => 4 + + size_t lnt_hdr_length = dbg_line->size(); + PushWord(dbg_line, 0); // TODO: 64-bit uses 8-byte here + + PushByte(dbg_line, 1); // minimum_instruction_length (ubyte) + PushByte(dbg_line, 1); // maximum_operations_per_instruction (ubyte) = always 1 + PushByte(dbg_line, 1); // default_is_stmt (ubyte) + + const int8_t LINE_BASE = -5; + PushByte(dbg_line, LINE_BASE); // line_base (sbyte) + + const uint8_t LINE_RANGE = 14; + PushByte(dbg_line, LINE_RANGE); // line_range (ubyte) + + const uint8_t OPCODE_BASE = 13; + PushByte(dbg_line, OPCODE_BASE); // opcode_base (ubyte) + + // Standard_opcode_lengths (array of ubyte). + PushByte(dbg_line, 0); PushByte(dbg_line, 1); PushByte(dbg_line, 1); + PushByte(dbg_line, 1); PushByte(dbg_line, 1); PushByte(dbg_line, 0); + PushByte(dbg_line, 0); PushByte(dbg_line, 0); PushByte(dbg_line, 1); + PushByte(dbg_line, 0); PushByte(dbg_line, 0); PushByte(dbg_line, 1); + + PushByte(dbg_line, 0); // include_directories (sequence of path names) = EMPTY + + // File_names (sequence of file entries). + std::unordered_map<const char*, size_t> files; + for (size_t i = 0; i < method_info.size(); ++i) { + const OatWriter::DebugInfo &dbg = method_info[i]; + // TODO: add package directory to the file name + const char* file_name = dbg.src_file_name_ == nullptr ? "null" : dbg.src_file_name_; + auto found = files.find(file_name); + if (found == files.end()) { + size_t file_index = 1 + files.size(); + files[file_name] = file_index; + PushStr(dbg_line, file_name); + PushByte(dbg_line, 0); // include directory index = LEB128(0) - no directory + PushByte(dbg_line, 0); // modification time = LEB128(0) - NA + PushByte(dbg_line, 0); // file length = LEB128(0) - NA + } + } + PushByte(dbg_line, 0); // End of file_names. + + // Set lnt header length. + UpdateWord(dbg_line, lnt_hdr_length, dbg_line->size() - lnt_hdr_length - 4); + + // Generate Line Number Program code, one long program for all methods. + LineTableGenerator line_table_generator(LINE_BASE, LINE_RANGE, OPCODE_BASE, + dbg_line, 0, 1); + + SrcMap pc2java_map; + for (size_t i = 0; i < method_info.size(); ++i) { + const OatWriter::DebugInfo &dbg = method_info[i]; + const char* file_name = (dbg.src_file_name_ == nullptr) ? "null" : dbg.src_file_name_; + size_t file_index = files[file_name]; + DCHECK_NE(file_index, 0U) << file_name; + + cunit_low_pc = std::min(cunit_low_pc, dbg.low_pc_); + cunit_high_pc = std::max(cunit_high_pc, dbg.high_pc_); + + // Start a new TAG: subroutine (2). + PushByte(dbg_info, 2); + + // Enter name, low_pc, high_pc. + PushWord(dbg_info, PushStr(dbg_str, dbg.method_name_)); + PushWord(dbg_info, dbg.low_pc_ + text_section_offset); + PushWord(dbg_info, dbg.high_pc_ + text_section_offset); + + pc2java_map.clear(); + GetLineInfoForJava(dbg.dbgstream_, dbg.compiled_method_->GetSrcMappingTable(), + &pc2java_map, dbg.low_pc_); + pc2java_map.DeltaFormat({dbg.low_pc_, 1}, dbg.high_pc_); + + line_table_generator.SetFile(file_index); + line_table_generator.SetAddr(dbg.low_pc_ + text_section_offset); + line_table_generator.SetLine(1); + for (auto& src_map_elem : pc2java_map) { + line_table_generator.PutDelta(src_map_elem.from_, src_map_elem.to_); + } } - // Start a new TAG: subroutine (2). - dbg_info->push_back(2); - - // Enter the name into the string table (and NUL terminate). - uint32_t str_offset = dbg_str->size(); - dbg_str->insert(dbg_str->end(), info.method_name_.begin(), info.method_name_.end()); - dbg_str->push_back('\0'); + // End Sequence should have the highest address set. + line_table_generator.SetAddr(cunit_high_pc + text_section_offset); + line_table_generator.EndSequence(); - // Enter name, low_pc, high_pc. - PushWord(dbg_info, str_offset); - PushWord(dbg_info, info.low_pc_); - PushWord(dbg_info, info.high_pc_); + // set lnt length + UpdateWord(dbg_line, lnt_length, dbg_line->size() - lnt_length - 4); } // One byte terminator - dbg_info->push_back(0); + PushByte(dbg_info, 0); + + // Fill in cunit's low_pc and high_pc. + UpdateWord(dbg_info, cunit_low_pc_pos, cunit_low_pc + text_section_offset); + UpdateWord(dbg_info, cunit_low_pc_pos + 4, cunit_high_pc + text_section_offset); - // We have now walked all the methods. Fill in lengths and low/high PCs. - UpdateWord(dbg_info, 0, dbg_info->size() - 4); - UpdateWord(dbg_info, low_pc_offset, low_pc); - UpdateWord(dbg_info, low_pc_offset + 4, high_pc); + // We have now walked all the methods. Fill in lengths. + UpdateWord(dbg_info, cunit_length, dbg_info->size() - cunit_length - 4); } } // namespace art diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h index 8cfe550495..c7ef872174 100644 --- a/compiler/elf_writer_quick.h +++ b/compiler/elf_writer_quick.h @@ -48,7 +48,7 @@ class ElfWriterQuick FINAL : public ElfWriter { ~ElfWriterQuick() {} class ElfBuilder; - void WriteDebugSymbols(ElfBuilder& builder, OatWriter* oat_writer); + void WriteDebugSymbols(ElfBuilder* builder, OatWriter* oat_writer); void ReservePatchSpace(std::vector<uint8_t>* buffer, bool debug); class ElfSectionBuilder { @@ -237,6 +237,7 @@ class ElfWriterQuick FINAL : public ElfWriter { } ~ElfBuilder() {} + bool Init(); bool Write(); // Adds the given raw section to the builder. This will copy it. The caller @@ -253,8 +254,29 @@ class ElfWriterQuick FINAL : public ElfWriter { bool fatal_error_ = false; + // What phdr is. + static const uint32_t PHDR_OFFSET = sizeof(Elf32_Ehdr); + enum : uint8_t { + PH_PHDR = 0, + PH_LOAD_R__ = 1, + PH_LOAD_R_X = 2, + PH_LOAD_RW_ = 3, + PH_DYNAMIC = 4, + PH_NUM = 5, + }; + static const uint32_t PHDR_SIZE = sizeof(Elf32_Phdr) * PH_NUM; + Elf32_Phdr program_headers_[PH_NUM]; + Elf32_Ehdr elf_header_; + Elf32_Shdr null_hdr_; + std::string shstrtab_; + uint32_t section_index_; + std::string dynstr_; + uint32_t dynstr_soname_offset_; + std::vector<Elf32_Shdr*> section_ptrs_; + std::vector<Elf32_Word> hash_; + public: ElfOatSectionBuilder text_builder_; ElfOatSectionBuilder rodata_builder_; @@ -316,7 +338,8 @@ class ElfWriterQuick FINAL : public ElfWriter { * @param dbg_str Debug strings. */ void FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_info, - std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str); + std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str, + std::vector<uint8_t>* dbg_line, uint32_t text_section_offset); DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick); }; diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 1ba5d3218e..0fb1575475 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -411,10 +411,12 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { const uint32_t quick_code_start = quick_code_offset - writer_->oat_header_->GetExecutableOffset(); + const DexFile::CodeItem *code_item = it.GetMethodCodeItem(); writer_->method_info_.push_back(DebugInfo(name, - quick_code_start, - quick_code_start + code_size, - compiled_method)); + dex_file_->GetSourceFile(dex_file_->GetClassDef(class_def_index_)), + quick_code_start, quick_code_start + code_size, + code_item == nullptr ? nullptr : dex_file_->GetDebugInfoStream(code_item), + compiled_method)); } } diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index ef5fd6b1c2..11f8bffd11 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -98,14 +98,18 @@ class OatWriter { ~OatWriter(); struct DebugInfo { - DebugInfo(const std::string& method_name, uint32_t low_pc, uint32_t high_pc, + DebugInfo(const std::string& method_name, const char* src_file_name, + uint32_t low_pc, uint32_t high_pc, const uint8_t* dbgstream, CompiledMethod* compiled_method) - : method_name_(method_name), low_pc_(low_pc), high_pc_(high_pc), + : method_name_(method_name), src_file_name_(src_file_name), + low_pc_(low_pc), high_pc_(high_pc), dbgstream_(dbgstream), compiled_method_(compiled_method) { } std::string method_name_; // Note: this name is a pretty-printed name. + const char* src_file_name_; uint32_t low_pc_; uint32_t high_pc_; + const uint8_t* dbgstream_; CompiledMethod* compiled_method_; }; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index bd8c27ec3e..7269fff62c 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -19,6 +19,7 @@ #include "code_generator_arm.h" #include "code_generator_x86.h" #include "code_generator_x86_64.h" +#include "compiled_method.h" #include "dex/verified_method.h" #include "driver/dex_compilation_unit.h" #include "gc_map_builder.h" @@ -297,7 +298,7 @@ void CodeGenerator::BuildNativeGCMap( } } -void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data) const { +void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_map) const { uint32_t pc2dex_data_size = 0u; uint32_t pc2dex_entries = pc_infos_.Size(); uint32_t pc2dex_offset = 0u; @@ -305,6 +306,10 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data) const { uint32_t dex2pc_data_size = 0u; uint32_t dex2pc_entries = 0u; + if (src_map != nullptr) { + src_map->reserve(pc2dex_entries); + } + // We currently only have pc2dex entries. for (size_t i = 0; i < pc2dex_entries; i++) { struct PcInfo pc_info = pc_infos_.Get(i); @@ -312,6 +317,9 @@ void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data) const { pc2dex_data_size += SignedLeb128Size(pc_info.dex_pc - pc2dex_dalvik_offset); pc2dex_offset = pc_info.native_pc; pc2dex_dalvik_offset = pc_info.dex_pc; + if (src_map != nullptr) { + src_map->push_back(SrcMapElem({pc2dex_offset, pc2dex_dalvik_offset})); + } } uint32_t total_entries = pc2dex_entries + dex2pc_entries; diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index b31c3a3e83..24e02773d8 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -32,6 +32,7 @@ static size_t constexpr kUninitializedFrameSize = 0; class CodeGenerator; class DexCompilationUnit; +class SrcMap; class CodeAllocator { public: @@ -126,7 +127,7 @@ class CodeGenerator : public ArenaObject { void GenerateSlowPaths(); - void BuildMappingTable(std::vector<uint8_t>* vector) const; + void BuildMappingTable(std::vector<uint8_t>* vector, SrcMap* src_map) const; void BuildVMapTable(std::vector<uint8_t>* vector) const; void BuildNativeGCMap( std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const; @@ -142,6 +143,7 @@ class CodeGenerator : public ArenaObject { protected: CodeGenerator(HGraph* graph, size_t number_of_registers) : frame_size_(kUninitializedFrameSize), + core_spill_mask_(-1), graph_(graph), block_labels_(graph->GetArena(), 0), pc_infos_(graph->GetArena(), 32), diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 8a5077b962..fce6ab0a33 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -161,7 +161,10 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite } std::vector<uint8_t> mapping_table; - codegen->BuildMappingTable(&mapping_table); + SrcMap src_mapping_table; + codegen->BuildMappingTable(&mapping_table, + GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ? + &src_mapping_table : nullptr); std::vector<uint8_t> vmap_table; codegen->BuildVMapTable(&vmap_table); std::vector<uint8_t> gc_map; @@ -173,6 +176,7 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite codegen->GetFrameSize(), codegen->GetCoreSpillMask(), 0, /* FPR spill mask, unused */ + &src_mapping_table, mapping_table, vmap_table, gc_map, diff --git a/compiler/utils/dwarf_cfi.cc b/compiler/utils/dwarf_cfi.cc index b3d1a47b80..83e5f5ad39 100644 --- a/compiler/utils/dwarf_cfi.cc +++ b/compiler/utils/dwarf_cfi.cc @@ -65,44 +65,86 @@ void DW_CFA_restore_state(std::vector<uint8_t>* buf) { buf->push_back(0x0b); } -void WriteFDEHeader(std::vector<uint8_t>* buf) { +void WriteFDEHeader(std::vector<uint8_t>* buf, bool is_64bit) { // 'length' (filled in by other functions). - PushWord(buf, 0); + if (is_64bit) { + PushWord(buf, 0xffffffff); // Indicates 64bit + PushWord(buf, 0); + PushWord(buf, 0); + } else { + PushWord(buf, 0); + } // 'CIE_pointer' (filled in by linker). - PushWord(buf, 0); + if (is_64bit) { + PushWord(buf, 0); + PushWord(buf, 0); + } else { + PushWord(buf, 0); + } // 'initial_location' (filled in by linker). - PushWord(buf, 0); + if (is_64bit) { + PushWord(buf, 0); + PushWord(buf, 0); + } else { + PushWord(buf, 0); + } // 'address_range' (filled in by other functions). - PushWord(buf, 0); + if (is_64bit) { + PushWord(buf, 0); + PushWord(buf, 0); + } else { + PushWord(buf, 0); + } // Augmentation length: 0 buf->push_back(0); } -void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint32_t data) { - const int kOffsetOfAddressRange = 12; - CHECK(buf->size() >= kOffsetOfAddressRange + sizeof(uint32_t)); +void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint64_t data, bool is_64bit) { + const size_t kOffsetOfAddressRange = is_64bit? 28 : 12; + CHECK(buf->size() >= kOffsetOfAddressRange + (is_64bit? 8 : 4)); uint8_t *p = buf->data() + kOffsetOfAddressRange; - p[0] = data; - p[1] = data >> 8; - p[2] = data >> 16; - p[3] = data >> 24; + if (is_64bit) { + p[0] = data; + p[1] = data >> 8; + p[2] = data >> 16; + p[3] = data >> 24; + p[4] = data >> 32; + p[5] = data >> 40; + p[6] = data >> 48; + p[7] = data >> 56; + } else { + p[0] = data; + p[1] = data >> 8; + p[2] = data >> 16; + p[3] = data >> 24; + } } -void WriteCFILength(std::vector<uint8_t>* buf) { - uint32_t length = buf->size() - 4; +void WriteCFILength(std::vector<uint8_t>* buf, bool is_64bit) { + uint64_t length = is_64bit ? buf->size() - 12 : buf->size() - 4; DCHECK_EQ((length & 0x3), 0U); - DCHECK_GT(length, 4U); - uint8_t *p = buf->data(); - p[0] = length; - p[1] = length >> 8; - p[2] = length >> 16; - p[3] = length >> 24; + uint8_t *p = is_64bit? buf->data() + 4 : buf->data(); + if (is_64bit) { + p[0] = length; + p[1] = length >> 8; + p[2] = length >> 16; + p[3] = length >> 24; + p[4] = length >> 32; + p[5] = length >> 40; + p[6] = length >> 48; + p[7] = length >> 56; + } else { + p[0] = length; + p[1] = length >> 8; + p[2] = length >> 16; + p[3] = length >> 24; + } } void PadCFI(std::vector<uint8_t>* buf) { diff --git a/compiler/utils/dwarf_cfi.h b/compiler/utils/dwarf_cfi.h index e5acc0eb3a..0c8b1516dd 100644 --- a/compiler/utils/dwarf_cfi.h +++ b/compiler/utils/dwarf_cfi.h @@ -66,20 +66,24 @@ void DW_CFA_restore_state(std::vector<uint8_t>* buf); /** * @brief Write FDE header into an FDE buffer * @param buf FDE buffer. + * @param is_64bit If FDE is for 64bit application. */ -void WriteFDEHeader(std::vector<uint8_t>* buf); +void WriteFDEHeader(std::vector<uint8_t>* buf, bool is_64bit); /** * @brief Set 'address_range' field of an FDE buffer * @param buf FDE buffer. + * @param data Data value. + * @param is_64bit If FDE is for 64bit application. */ -void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint32_t data); +void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint64_t data, bool is_64bit); /** * @brief Set 'length' field of an FDE buffer * @param buf FDE buffer. + * @param is_64bit If FDE is for 64bit application. */ -void WriteCFILength(std::vector<uint8_t>* buf); +void WriteCFILength(std::vector<uint8_t>* buf, bool is_64bit); /** * @brief Pad an FDE buffer with 0 until its size is a multiple of 4 diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 48edb157f6..2c9bc28923 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -1409,13 +1409,13 @@ void X86Assembler::EmitGenericShift(int reg_or_opcode, } void X86Assembler::InitializeFrameDescriptionEntry() { - WriteFDEHeader(&cfi_info_); + WriteFDEHeader(&cfi_info_, false /* is_64bit */); } void X86Assembler::FinalizeFrameDescriptionEntry() { - WriteFDEAddressRange(&cfi_info_, buffer_.Size()); + WriteFDEAddressRange(&cfi_info_, buffer_.Size(), false /* is_64bit */); PadCFI(&cfi_info_); - WriteCFILength(&cfi_info_); + WriteCFILength(&cfi_info_, false /* is_64bit */); } constexpr size_t kFramePointerSize = 4; diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index 62b72c234a..1e2884a88c 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -1716,13 +1716,13 @@ void X86_64Assembler::EmitOptionalByteRegNormalizingRex32(CpuRegister dst, const } void X86_64Assembler::InitializeFrameDescriptionEntry() { - WriteFDEHeader(&cfi_info_); + WriteFDEHeader(&cfi_info_, true /* is_64bit */); } void X86_64Assembler::FinalizeFrameDescriptionEntry() { - WriteFDEAddressRange(&cfi_info_, buffer_.Size()); + WriteFDEAddressRange(&cfi_info_, buffer_.Size(), true /* is_64bit */); PadCFI(&cfi_info_); - WriteCFILength(&cfi_info_); + WriteCFILength(&cfi_info_, true /* is_64bit */); } constexpr size_t kFramePointerSize = 8; |