diff options
author | 2016-03-11 17:11:44 +0000 | |
---|---|---|
committer | 2016-03-11 17:35:19 +0000 | |
commit | 09c2a6be63337ee060e2d54bd01cf18be7301d29 (patch) | |
tree | c623c5352bc908410f03b20b772c3dad47df207c | |
parent | fdaa583e785383cca68df63c7ef53fcaf667b8e2 (diff) |
Add trampoline symbols to native debug info.
The debugger needs them to unwind through the trampolines and to
understand what is happening in the call stack.
Change-Id: Ia554058c3796788adcd7336d620a7734eb366905
-rw-r--r-- | compiler/debug/elf_debug_info_writer.h | 2 | ||||
-rw-r--r-- | compiler/debug/elf_debug_line_writer.h | 1 | ||||
-rw-r--r-- | compiler/debug/elf_debug_writer.cc | 63 | ||||
-rw-r--r-- | compiler/debug/elf_debug_writer.h | 5 | ||||
-rw-r--r-- | compiler/debug/elf_symtab_writer.h | 27 | ||||
-rw-r--r-- | compiler/debug/method_debug_info.h | 5 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 3 | ||||
-rw-r--r-- | compiler/oat_writer.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 3 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 3 |
10 files changed, 80 insertions, 36 deletions
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h index af74d4c5b5..a6e6f8b5da 100644 --- a/compiler/debug/elf_debug_info_writer.h +++ b/compiler/debug/elf_debug_info_writer.h @@ -46,6 +46,7 @@ static void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) { static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) { std::vector<const char*> names; if (mi->code_item != nullptr) { + DCHECK(mi->dex_file != nullptr); const uint8_t* stream = mi->dex_file->GetDebugInfoStream(mi->code_item); if (stream != nullptr) { DecodeUnsignedLeb128(&stream); // line. @@ -133,6 +134,7 @@ class ElfCompilationUnitWriter { const char* last_dex_class_desc = nullptr; for (auto mi : compilation_unit.methods) { + DCHECK(mi->dex_file != nullptr); const DexFile* dex = mi->dex_file; const DexFile::CodeItem* dex_code = mi->code_item; const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index); diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h index ed26d96603..9875c71080 100644 --- a/compiler/debug/elf_debug_line_writer.h +++ b/compiler/debug/elf_debug_line_writer.h @@ -117,6 +117,7 @@ class ElfDebugLineWriter { Elf_Addr method_address = base_address + mi->code_address; PositionInfos dex2line_map; + DCHECK(mi->dex_file != nullptr); const DexFile* dex = mi->dex_file; if (!dex->DecodeDebugPositionInfo(mi->code_item, PositionInfoCallback, &dex2line_map)) { continue; diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc index 0ca7370f98..4dd802495c 100644 --- a/compiler/debug/elf_debug_writer.cc +++ b/compiler/debug/elf_debug_writer.cc @@ -39,35 +39,31 @@ void WriteDebugInfo(ElfBuilder<ElfTypes>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, dwarf::CFIFormat cfi_format, bool write_oat_patches) { - // Add methods to .symtab. + // Write .strtab and .symtab. WriteDebugSymbols(builder, method_infos, true /* with_signature */); - // Generate CFI (stack unwinding information). + + // Write .debug_frame. WriteCFISection(builder, method_infos, cfi_format, write_oat_patches); - // Write DWARF .debug_* sections. - WriteDebugSections(builder, method_infos, write_oat_patches); -} -template<typename ElfTypes> -static void WriteDebugSections(ElfBuilder<ElfTypes>* builder, - const ArrayRef<const MethodDebugInfo>& method_infos, - bool write_oat_patches) { // Group the methods into compilation units based on source file. std::vector<ElfCompilationUnit> compilation_units; const char* last_source_file = nullptr; for (const MethodDebugInfo& mi : method_infos) { - auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index); - const char* source_file = mi.dex_file->GetSourceFile(dex_class_def); - if (compilation_units.empty() || source_file != last_source_file) { - compilation_units.push_back(ElfCompilationUnit()); + if (mi.dex_file != nullptr) { + auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index); + const char* source_file = mi.dex_file->GetSourceFile(dex_class_def); + if (compilation_units.empty() || source_file != last_source_file) { + compilation_units.push_back(ElfCompilationUnit()); + } + ElfCompilationUnit& cu = compilation_units.back(); + cu.methods.push_back(&mi); + // All methods must have the same addressing mode otherwise the min/max below does not work. + DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative); + cu.is_code_address_text_relative = mi.is_code_address_text_relative; + cu.code_address = std::min(cu.code_address, mi.code_address); + cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size); + last_source_file = source_file; } - ElfCompilationUnit& cu = compilation_units.back(); - cu.methods.push_back(&mi); - // All methods must have the same addressing mode otherwise the min/max below does not work. - DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative); - cu.is_code_address_text_relative = mi.is_code_address_text_relative; - cu.code_address = std::min(cu.code_address, mi.code_address); - cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size); - last_source_file = source_file; } // Write .debug_line section. @@ -185,6 +181,31 @@ ArrayRef<const uint8_t> WriteDebugElfFileForClasses(InstructionSet isa, } } +std::vector<MethodDebugInfo> MakeTrampolineInfos(const OatHeader& header) { + std::map<const char*, uint32_t> trampolines = { + { "interpreterToInterpreterBridge", header.GetInterpreterToInterpreterBridgeOffset() }, + { "interpreterToCompiledCodeBridge", header.GetInterpreterToCompiledCodeBridgeOffset() }, + { "jniDlsymLookup", header.GetJniDlsymLookupOffset() }, + { "quickGenericJniTrampoline", header.GetQuickGenericJniTrampolineOffset() }, + { "quickImtConflictTrampoline", header.GetQuickImtConflictTrampolineOffset() }, + { "quickResolutionTrampoline", header.GetQuickResolutionTrampolineOffset() }, + { "quickToInterpreterBridge", header.GetQuickToInterpreterBridgeOffset() }, + }; + std::vector<MethodDebugInfo> result; + for (const auto& it : trampolines) { + if (it.second != 0) { + MethodDebugInfo info = MethodDebugInfo(); + info.trampoline_name = it.first; + info.isa = header.GetInstructionSet(); + info.is_code_address_text_relative = true; + info.code_address = it.second - header.GetExecutableOffset(); + info.code_size = 0; // The symbol lasts until the next symbol. + result.push_back(std::move(info)); + } + } + return result; +} + // Explicit instantiations template void WriteDebugInfo<ElfTypes32>( ElfBuilder<ElfTypes32>* builder, diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h index 7f5d24d06e..736370e2d3 100644 --- a/compiler/debug/elf_debug_writer.h +++ b/compiler/debug/elf_debug_writer.h @@ -17,6 +17,8 @@ #ifndef ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_ #define ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_ +#include <vector> + #include "base/macros.h" #include "base/mutex.h" #include "debug/dwarf/dwarf_constants.h" @@ -24,6 +26,7 @@ #include "utils/array_ref.h" namespace art { +class OatHeader; namespace mirror { class Class; } @@ -55,6 +58,8 @@ ArrayRef<const uint8_t> WriteDebugElfFileForClasses( const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_); +std::vector<MethodDebugInfo> MakeTrampolineInfos(const OatHeader& oat_header); + } // namespace debug } // namespace art diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h index 0a199dac35..045edddd77 100644 --- a/compiler/debug/elf_symtab_writer.h +++ b/compiler/debug/elf_symtab_writer.h @@ -39,7 +39,7 @@ template <typename ElfTypes> static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, bool with_signature) { - bool generated_mapping_symbol = false; + uint64_t mapping_symbol_address = std::numeric_limits<uint64_t>::max(); auto* strtab = builder->GetStrTab(); auto* symtab = builder->GetSymTab(); @@ -64,12 +64,20 @@ static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, if (info.deduped) { continue; // Add symbol only for the first instance. } - std::string name = PrettyMethod(info.dex_method_index, *info.dex_file, with_signature); - if (deduped_addresses.find(info.code_address) != deduped_addresses.end()) { - name += " [DEDUPED]"; + size_t name_offset; + if (info.trampoline_name != nullptr) { + name_offset = strtab->Write(info.trampoline_name); + } else { + DCHECK(info.dex_file != nullptr); + std::string name = PrettyMethod(info.dex_method_index, *info.dex_file, with_signature); + if (deduped_addresses.find(info.code_address) != deduped_addresses.end()) { + name += " [DEDUPED]"; + } + // If we write method names without signature, we might see the same name multiple times. + name_offset = (name == last_name ? last_name_offset : strtab->Write(name)); + last_name = std::move(name); + last_name_offset = name_offset; } - // If we write method names without signature, we might see the same name multiple times. - size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name)); const auto* text = info.is_code_address_text_relative ? builder->GetText() : nullptr; uint64_t address = info.code_address + (text != nullptr ? text->GetAddress() : 0); @@ -82,14 +90,11 @@ static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, // Note that even if we generate just a single mapping symbol, ARM's Streamline // requires it to match function symbol. Just address 0 does not work. if (info.isa == kThumb2) { - if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) { + if (address < mapping_symbol_address || !kGenerateSingleArmMappingSymbol) { symtab->Add(strtab->Write("$t"), text, address & ~1, 0, STB_LOCAL, STT_NOTYPE); - generated_mapping_symbol = true; + mapping_symbol_address = address; } } - - last_name = std::move(name); - last_name_offset = name_offset; } strtab->End(); diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h index 1ccc705ff9..ed1da2c26e 100644 --- a/compiler/debug/method_debug_info.h +++ b/compiler/debug/method_debug_info.h @@ -24,7 +24,8 @@ namespace art { namespace debug { struct MethodDebugInfo { - const DexFile* dex_file; + const char* trampoline_name; + const DexFile* dex_file; // Native methods (trampolines) do not reference dex file. size_t class_def_index; uint32_t dex_method_index; uint32_t access_flags; @@ -37,7 +38,7 @@ struct MethodDebugInfo { uint64_t code_address; uint32_t code_size; uint32_t frame_size_in_bytes; - const uint8_t* code_info; + const void* code_info; ArrayRef<const uint8_t> cfi; }; diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 2b511fc082..c2f19c9d61 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -811,7 +811,8 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) { bool has_code_info = method_header->IsOptimized(); // Record debug information for this function if we are doing that. - debug::MethodDebugInfo info; + debug::MethodDebugInfo info = debug::MethodDebugInfo(); + info.trampoline_name = nullptr; info.dex_file = dex_file_; info.class_def_index = class_def_index_; info.dex_method_index = it.GetMemberIndex(); diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 74aab4efd0..5e7a4a37d1 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -202,6 +202,10 @@ class OatWriter { ~OatWriter(); + void AddMethodDebugInfos(const std::vector<debug::MethodDebugInfo>& infos) { + method_info_.insert(method_info_.end(), infos.begin(), infos.end()); + } + ArrayRef<const debug::MethodDebugInfo> GetMethodDebugInfo() const { return ArrayRef<const debug::MethodDebugInfo>(method_info_); } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index cc1a8064b1..7a82063bba 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -919,7 +919,8 @@ bool OptimizingCompiler::JitCompile(Thread* self, if (compiler_options.GetGenerateDebugInfo()) { const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code); const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode()); - debug::MethodDebugInfo info; + debug::MethodDebugInfo info = debug::MethodDebugInfo(); + info.trampoline_name = nullptr; info.dex_file = dex_file; info.class_def_index = class_def_idx; info.dex_method_index = method_idx; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 44e7fc9017..a14a295f25 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -46,6 +46,7 @@ #include "class_linker.h" #include "compiler.h" #include "compiler_callbacks.h" +#include "debug/elf_debug_writer.h" #include "debug/method_debug_info.h" #include "dex/pass_manager.h" #include "dex/quick/dex_file_to_method_inliner_map.h" @@ -1687,6 +1688,8 @@ class Dex2Oat FINAL { std::unique_ptr<ElfWriter>& elf_writer = elf_writers_[i]; std::unique_ptr<OatWriter>& oat_writer = oat_writers_[i]; + oat_writer->AddMethodDebugInfos(debug::MakeTrampolineInfos(oat_writer->GetOatHeader())); + // We need to mirror the layout of the ELF file in the compressed debug-info. // Therefore PrepareDebugInfo() relies on the SetLoadedSectionSizes() call further above. elf_writer->PrepareDebugInfo(oat_writer->GetMethodDebugInfo()); |