diff options
author | 2019-02-12 16:34:55 +0000 | |
---|---|---|
committer | 2019-02-18 14:06:22 +0000 | |
commit | 53eb07f0858795b7487eddc23b95ac38336696a7 (patch) | |
tree | 8b5710abea53fdf95aac2c582d58b465e9fd46e7 | |
parent | e39765cd311f31653137a2efede6c0eb7903e434 (diff) |
Refactor ElfDebugReader.
Make the code more flexible, which I will need for
future mini-debug-info work.
Bug: 110133331
Test: ./art/test.py -b -r -t 137
Change-Id: I8b0fe3c43537f546f2ff103bff3c63a59a0f940a
-rw-r--r-- | compiler/debug/dwarf/headers.h | 24 | ||||
-rw-r--r-- | compiler/debug/elf_debug_reader.h | 171 | ||||
-rw-r--r-- | compiler/debug/elf_debug_writer.cc | 96 | ||||
-rw-r--r-- | compiler/debug/elf_debug_writer.h | 2 | ||||
-rw-r--r-- | runtime/jit/debugger_interface.cc | 5 | ||||
-rw-r--r-- | runtime/jit/debugger_interface.h | 3 |
6 files changed, 177 insertions, 124 deletions
diff --git a/compiler/debug/dwarf/headers.h b/compiler/debug/dwarf/headers.h index 869a2c256e..3cc8ad8290 100644 --- a/compiler/debug/dwarf/headers.h +++ b/compiler/debug/dwarf/headers.h @@ -90,30 +90,6 @@ void WriteFDE(bool is64bit, writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4); } -// Read singe FDE entry from 'data' (which is advanced). -template<typename Addr> -bool ReadFDE(const uint8_t** data, Addr* addr, Addr* size, ArrayRef<const uint8_t>* opcodes) { - struct Header { - uint32_t length; - int32_t cie_pointer; - Addr addr; - Addr size; - uint8_t augmentaion; - uint8_t opcodes[]; - } PACKED(1); - const Header* header = reinterpret_cast<const Header*>(*data); - const size_t length = 4 + header->length; - *data += length; - if (header->cie_pointer == -1) { - return false; // Not an FDE entry. - } - DCHECK_EQ(header->cie_pointer, 0); // Expects single CIE. Assumes DW_DEBUG_FRAME_FORMAT. - *addr = header->addr; - *size = header->size; - *opcodes = ArrayRef<const uint8_t>(header->opcodes, length - offsetof(Header, opcodes)); - return true; -} - // Write compilation unit (CU) to .debug_info section. template<typename Vector> void WriteDebugInfoCU(uint32_t debug_abbrev_offset, diff --git a/compiler/debug/elf_debug_reader.h b/compiler/debug/elf_debug_reader.h index 91b1b3ea81..1820e7cdc7 100644 --- a/compiler/debug/elf_debug_reader.h +++ b/compiler/debug/elf_debug_reader.h @@ -22,6 +22,9 @@ #include "elf.h" #include "xz_utils.h" +#include <map> +#include <string_view> + namespace art { namespace debug { @@ -29,75 +32,141 @@ namespace debug { // // It is the bare minimum needed to read mini-debug-info symbols for unwinding. // We use it to merge JIT mini-debug-infos together or to prune them after GC. -// The consumed ELF file comes from ART JIT. -template <typename ElfTypes, typename VisitSym, typename VisitFde> -static void ReadElfSymbols(const uint8_t* elf, VisitSym visit_sym, VisitFde visit_fde) { +template <typename ElfTypes> +class ElfDebugReader { + public: // Note that the input buffer might be misaligned. typedef typename ElfTypes::Ehdr ALIGNED(1) Elf_Ehdr; typedef typename ElfTypes::Shdr ALIGNED(1) Elf_Shdr; typedef typename ElfTypes::Sym ALIGNED(1) Elf_Sym; typedef typename ElfTypes::Addr ALIGNED(1) Elf_Addr; - // Read and check the elf header. - const Elf_Ehdr* header = reinterpret_cast<const Elf_Ehdr*>(elf); - CHECK(header->checkMagic()); - - // Find sections that we are interested in. - const Elf_Shdr* sections = reinterpret_cast<const Elf_Shdr*>(elf + header->e_shoff); - const Elf_Shdr* strtab = nullptr; - const Elf_Shdr* symtab = nullptr; - const Elf_Shdr* debug_frame = nullptr; - const Elf_Shdr* gnu_debugdata = nullptr; - for (size_t i = 1 /* skip null section */; i < header->e_shnum; i++) { - const Elf_Shdr* section = sections + i; - const char* name = reinterpret_cast<const char*>( - elf + sections[header->e_shstrndx].sh_offset + section->sh_name); - if (strcmp(name, ".strtab") == 0) { - strtab = section; - } else if (strcmp(name, ".symtab") == 0) { - symtab = section; - } else if (strcmp(name, ".debug_frame") == 0) { - debug_frame = section; - } else if (strcmp(name, ".gnu_debugdata") == 0) { - gnu_debugdata = section; + // Call Frame Information. + struct CFI { + uint32_t length; // Length excluding the size of this field. + int32_t cie_pointer; // Offset in the section or -1 for CIE. + + const uint8_t* data() const { return reinterpret_cast<const uint8_t*>(this); } + size_t size() const { return sizeof(uint32_t) + length; } + } PACKED(1); + + // Common Information Entry. + struct CIE : public CFI { + } PACKED(1); + + // Frame Description Entry. + struct FDE : public CFI { + Elf_Addr sym_addr; + Elf_Addr sym_size; + } PACKED(1); + + explicit ElfDebugReader(ArrayRef<const uint8_t> file) : file_(file) { + header_ = Read<Elf_Ehdr>(/*offset=*/ 0); + CHECK(header_->checkMagic()); + CHECK_EQ(header_->e_ehsize, sizeof(Elf_Ehdr)); + CHECK_EQ(header_->e_shentsize, sizeof(Elf_Shdr)); + + // Find all ELF sections. + sections_ = Read<Elf_Shdr>(header_->e_shoff, header_->e_shnum); + for (const Elf_Shdr& section : sections_) { + const char* name = Read<char>(sections_[header_->e_shstrndx].sh_offset + section.sh_name); + section_map_[std::string_view(name)] = §ion; } + + // Decompressed embedded debug symbols, if any. + const Elf_Shdr* gnu_debugdata = section_map_[".gnu_debugdata"]; + if (gnu_debugdata != nullptr) { + auto compressed = Read<uint8_t>(gnu_debugdata->sh_offset, gnu_debugdata->sh_size); + XzDecompress(compressed, &decompressed_gnu_debugdata_); + gnu_debugdata_reader_.reset(new ElfDebugReader(decompressed_gnu_debugdata_)); + } + } + + explicit ElfDebugReader(std::vector<uint8_t>& file) + : ElfDebugReader(ArrayRef<const uint8_t>(file)) { } - // Visit symbols. - if (symtab != nullptr && strtab != nullptr) { - const Elf_Sym* symbols = reinterpret_cast<const Elf_Sym*>(elf + symtab->sh_offset); - DCHECK_EQ(symtab->sh_entsize, sizeof(Elf_Sym)); - size_t count = symtab->sh_size / sizeof(Elf_Sym); - for (size_t i = 1 /* skip null symbol */; i < count; i++) { - Elf_Sym symbol = symbols[i]; - if (symbol.getBinding() != STB_LOCAL) { // Ignore local symbols (e.g. "$t"). - const uint8_t* name = elf + strtab->sh_offset + symbol.st_name; - visit_sym(symbol, reinterpret_cast<const char*>(name)); + const Elf_Ehdr* GetHeader() { return header_; } + + ArrayRef<Elf_Shdr> GetSections() { return sections_; } + + const Elf_Shdr* GetSection(const char* name) { return section_map_[name]; } + + template <typename VisitSym> + void VisitFunctionSymbols(VisitSym visit_sym) { + const Elf_Shdr* symtab = GetSection(".symtab"); + const Elf_Shdr* strtab = GetSection(".strtab"); + const Elf_Shdr* text = GetSection(".text"); + if (symtab != nullptr && strtab != nullptr) { + CHECK_EQ(symtab->sh_entsize, sizeof(Elf_Sym)); + size_t count = symtab->sh_size / sizeof(Elf_Sym); + for (const Elf_Sym& symbol : Read<Elf_Sym>(symtab->sh_offset, count)) { + if (symbol.getType() == STT_FUNC && §ions_[symbol.st_shndx] == text) { + visit_sym(symbol, Read<char>(strtab->sh_offset + symbol.st_name)); + } } } + if (gnu_debugdata_reader_ != nullptr) { + gnu_debugdata_reader_->VisitFunctionSymbols(visit_sym); + } } - // Visit CFI (unwind) data. - if (debug_frame != nullptr) { - const uint8_t* data = elf + debug_frame->sh_offset; - const uint8_t* end = data + debug_frame->sh_size; - while (data < end) { - Elf_Addr addr, size; - ArrayRef<const uint8_t> opcodes; - if (dwarf::ReadFDE<Elf_Addr>(&data, &addr, &size, &opcodes)) { - visit_fde(addr, size, opcodes); + template <typename VisitSym> + void VisitDynamicSymbols(VisitSym visit_sym) { + const Elf_Shdr* dynsym = GetSection(".dynsym"); + const Elf_Shdr* dynstr = GetSection(".dynstr"); + if (dynsym != nullptr && dynstr != nullptr) { + CHECK_EQ(dynsym->sh_entsize, sizeof(Elf_Sym)); + size_t count = dynsym->sh_size / sizeof(Elf_Sym); + for (const Elf_Sym& symbol : Read<Elf_Sym>(dynsym->sh_offset, count)) { + visit_sym(symbol, Read<char>(dynstr->sh_offset + symbol.st_name)); } } } - // Process embedded compressed ELF file. - if (gnu_debugdata != nullptr) { - ArrayRef<const uint8_t> compressed(elf + gnu_debugdata->sh_offset, gnu_debugdata->sh_size); - std::vector<uint8_t> decompressed; - XzDecompress(compressed, &decompressed); - ReadElfSymbols<ElfTypes>(decompressed.data(), visit_sym, visit_fde); + template <typename VisitCIE, typename VisitFDE> + void VisitDebugFrame(VisitCIE visit_cie, VisitFDE visit_fde) { + const Elf_Shdr* debug_frame = GetSection(".debug_frame"); + if (debug_frame != nullptr) { + for (size_t offset = 0; offset < debug_frame->sh_size;) { + const CFI* entry = Read<CFI>(debug_frame->sh_offset + offset); + DCHECK_LE(entry->size(), debug_frame->sh_size - offset); + if (entry->cie_pointer == -1) { + visit_cie(Read<CIE>(debug_frame->sh_offset + offset)); + } else { + const FDE* fde = Read<FDE>(debug_frame->sh_offset + offset); + visit_fde(fde, Read<CIE>(debug_frame->sh_offset + fde->cie_pointer)); + } + offset += entry->size(); + } + } + if (gnu_debugdata_reader_ != nullptr) { + gnu_debugdata_reader_->VisitDebugFrame(visit_cie, visit_fde); + } } -} + + private: + template<typename T> + const T* Read(size_t offset) { + DCHECK_LE(offset + sizeof(T), file_.size()); + return reinterpret_cast<const T*>(file_.data() + offset); + } + + template<typename T> + ArrayRef<const T> Read(size_t offset, size_t count) { + DCHECK_LE(offset + count * sizeof(T), file_.size()); + return ArrayRef<const T>(Read<T>(offset), count); + } + + ArrayRef<const uint8_t> const file_; + const Elf_Ehdr* header_; + ArrayRef<const Elf_Shdr> sections_; + std::unordered_map<std::string_view, const Elf_Shdr*> section_map_; + std::vector<uint8_t> decompressed_gnu_debugdata_; + std::unique_ptr<ElfDebugReader> gnu_debugdata_reader_; + + DISALLOW_COPY_AND_ASSIGN(ElfDebugReader); +}; } // namespace debug } // namespace art diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc index fd638b7be0..3b7363be6a 100644 --- a/compiler/debug/elf_debug_writer.cc +++ b/compiler/debug/elf_debug_writer.cc @@ -203,25 +203,26 @@ std::vector<uint8_t> MakeElfFileForJIT( // Verify the ELF file by reading it back using the trivial reader. if (kIsDebugBuild) { using Elf_Sym = typename ElfTypes::Sym; - using Elf_Addr = typename ElfTypes::Addr; size_t num_syms = 0; - size_t num_cfis = 0; - ReadElfSymbols<ElfTypes>( - buffer.data(), - [&](Elf_Sym sym, const char*) { - DCHECK_EQ(sym.st_value, method_info.code_address + CompiledMethod::CodeDelta(isa)); - DCHECK_EQ(sym.st_size, method_info.code_size); - num_syms++; - }, - [&](Elf_Addr addr, Elf_Addr size, ArrayRef<const uint8_t> opcodes) { - DCHECK_EQ(addr, method_info.code_address); - DCHECK_EQ(size, method_info.code_size); - DCHECK_GE(opcodes.size(), method_info.cfi.size()); - DCHECK_EQ(memcmp(opcodes.data(), method_info.cfi.data(), method_info.cfi.size()), 0); - num_cfis++; - }); + size_t num_cies = 0; + size_t num_fdes = 0; + using Reader = ElfDebugReader<ElfTypes>; + Reader reader(buffer); + reader.VisitFunctionSymbols([&](Elf_Sym sym, const char*) { + DCHECK_EQ(sym.st_value, method_info.code_address + CompiledMethod::CodeDelta(isa)); + DCHECK_EQ(sym.st_size, method_info.code_size); + num_syms++; + }); + reader.VisitDebugFrame([&](const Reader::CIE* cie ATTRIBUTE_UNUSED) { + num_cies++; + }, [&](const Reader::FDE* fde, const Reader::CIE* cie ATTRIBUTE_UNUSED) { + DCHECK_EQ(fde->sym_addr, method_info.code_address); + DCHECK_EQ(fde->sym_size, method_info.code_size); + num_fdes++; + }); DCHECK_EQ(num_syms, 1u); - DCHECK_EQ(num_cfis, 1u); + DCHECK_LE(num_cies, 1u); + DCHECK_LE(num_fdes, 1u); } return buffer; } @@ -230,14 +231,13 @@ std::vector<uint8_t> MakeElfFileForJIT( std::vector<uint8_t> PackElfFileForJIT( InstructionSet isa, const InstructionSetFeatures* features, - std::vector<const uint8_t*>& added_elf_files, + std::vector<ArrayRef<const uint8_t>>& added_elf_files, std::vector<const void*>& removed_symbols, /*out*/ size_t* num_symbols) { using ElfTypes = ElfRuntimeTypes; using Elf_Addr = typename ElfTypes::Addr; using Elf_Sym = typename ElfTypes::Sym; CHECK_EQ(sizeof(Elf_Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa))); - const bool is64bit = Is64BitInstructionSet(isa); auto is_removed_symbol = [&removed_symbols](Elf_Addr addr) { const void* code_ptr = reinterpret_cast<const void*>(addr); return std::binary_search(removed_symbols.begin(), removed_symbols.end(), code_ptr); @@ -259,35 +259,26 @@ std::vector<uint8_t> PackElfFileForJIT( auto* symtab = builder->GetSymTab(); auto* debug_frame = builder->GetDebugFrame(); std::deque<Elf_Sym> symbols; - std::vector<uint8_t> debug_frame_buffer; - WriteCIE(isa, &debug_frame_buffer); + + using Reader = ElfDebugReader<ElfTypes>; + std::deque<Reader> readers; + for (ArrayRef<const uint8_t> added_elf_file : added_elf_files) { + readers.emplace_back(added_elf_file); + } // Write symbols names. All other data is buffered. strtab->Start(); strtab->Write(""); // strtab should start with empty string. - for (const uint8_t* added_elf_file : added_elf_files) { - ReadElfSymbols<ElfTypes>( - added_elf_file, - [&](Elf_Sym sym, const char* name) { - if (is_removed_symbol(sym.st_value)) { - return; - } - sym.st_name = strtab->Write(name); - symbols.push_back(sym); - min_address = std::min<uint64_t>(min_address, sym.st_value); - max_address = std::max<uint64_t>(max_address, sym.st_value + sym.st_size); - }, - [&](Elf_Addr addr, Elf_Addr size, ArrayRef<const uint8_t> opcodes) { - if (is_removed_symbol(addr)) { - return; - } - dwarf::WriteFDE(is64bit, - /* cie_pointer= */ 0, - addr, - size, - opcodes, - &debug_frame_buffer); - }); + for (Reader& reader : readers) { + reader.VisitFunctionSymbols([&](Elf_Sym sym, const char* name) { + if (is_removed_symbol(sym.st_value)) { + return; + } + sym.st_name = strtab->Write(name); + symbols.push_back(sym); + min_address = std::min<uint64_t>(min_address, sym.st_value); + max_address = std::max<uint64_t>(max_address, sym.st_value + sym.st_size); + }); } strtab->End(); @@ -305,7 +296,22 @@ std::vector<uint8_t> PackElfFileForJIT( // Add the CFI/unwind section. debug_frame->Start(); - debug_frame->WriteFully(debug_frame_buffer.data(), debug_frame_buffer.size()); + // ART always produces the same CIE, so we copy the first one and ignore the rest. + bool copied_cie = false; + for (Reader& reader : readers) { + reader.VisitDebugFrame([&](const Reader::CIE* cie) { + if (!copied_cie) { + debug_frame->WriteFully(cie->data(), cie->size()); + copied_cie = true; + } + }, [&](const Reader::FDE* fde, const Reader::CIE* cie ATTRIBUTE_UNUSED) { + DCHECK(copied_cie); + DCHECK_EQ(fde->cie_pointer, 0); + if (!is_removed_symbol(fde->sym_addr)) { + debug_frame->WriteFully(fde->data(), fde->size()); + } + }); + } debug_frame->End(); builder->End(); diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h index 3cc38a2757..90580b4676 100644 --- a/compiler/debug/elf_debug_writer.h +++ b/compiler/debug/elf_debug_writer.h @@ -57,7 +57,7 @@ std::vector<uint8_t> MakeElfFileForJIT( std::vector<uint8_t> PackElfFileForJIT( InstructionSet isa, const InstructionSetFeatures* features, - std::vector<const uint8_t*>& added_elf_files, + std::vector<ArrayRef<const uint8_t>>& added_elf_files, std::vector<const void*>& removed_symbols, /*out*/ size_t* num_symbols); diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc index 99f9387c9e..a69429f94c 100644 --- a/runtime/jit/debugger_interface.cc +++ b/runtime/jit/debugger_interface.cc @@ -301,7 +301,7 @@ static void MaybePackJitMiniDebugInfo(PackElfFileForJITFunction pack, return; // Nothing to do. } - std::vector<const uint8_t*> added_elf_files; + std::vector<ArrayRef<const uint8_t>> added_elf_files; std::vector<const void*> removed_symbols; auto added_it = g_jit_debug_entries.begin(); auto removed_it = removed_entries.begin(); @@ -312,7 +312,8 @@ static void MaybePackJitMiniDebugInfo(PackElfFileForJITFunction pack, auto added_begin = added_it; while (added_it != g_jit_debug_entries.end() && AlignDown(added_it->first, kGroupSize) == group_ptr) { - added_elf_files.push_back((added_it++)->second->symfile_addr_); + JITCodeEntry* entry = (added_it++)->second; + added_elf_files.emplace_back(entry->symfile_addr_, entry->symfile_size_); } removed_symbols.clear(); while (removed_it != removed_entries.end() && diff --git a/runtime/jit/debugger_interface.h b/runtime/jit/debugger_interface.h index 17beb4baca..51b7041675 100644 --- a/runtime/jit/debugger_interface.h +++ b/runtime/jit/debugger_interface.h @@ -21,6 +21,7 @@ #include <vector> #include "arch/instruction_set_features.h" +#include "base/array_ref.h" #include "base/locks.h" namespace art { @@ -33,7 +34,7 @@ class Thread; typedef std::vector<uint8_t> PackElfFileForJITFunction( InstructionSet isa, const InstructionSetFeatures* features, - std::vector<const uint8_t*>& added_elf_files, + std::vector<ArrayRef<const uint8_t>>& added_elf_files, std::vector<const void*>& removed_symbols, /*out*/ size_t* num_symbols); |