/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "elf_debug_writer.h" #include <vector> #include "base/array_ref.h" #include "debug/dwarf/dwarf_constants.h" #include "debug/elf_compilation_unit.h" #include "debug/elf_debug_frame_writer.h" #include "debug/elf_debug_info_writer.h" #include "debug/elf_debug_line_writer.h" #include "debug/elf_debug_loc_writer.h" #include "debug/elf_gnu_debugdata_writer.h" #include "debug/elf_symtab_writer.h" #include "debug/method_debug_info.h" #include "elf_builder.h" #include "linker/vector_output_stream.h" namespace art { namespace debug { template <typename ElfTypes> void WriteDebugInfo(ElfBuilder<ElfTypes>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, dwarf::CFIFormat cfi_format, bool write_oat_patches) { // Write .strtab and .symtab. WriteDebugSymbols(builder, method_infos, true /* with_signature */); // Write .debug_frame. WriteCFISection(builder, method_infos, cfi_format, 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) { 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; } } // Write .debug_line section. if (!compilation_units.empty()) { ElfDebugLineWriter<ElfTypes> line_writer(builder); line_writer.Start(); for (auto& compilation_unit : compilation_units) { line_writer.WriteCompilationUnit(compilation_unit); } line_writer.End(write_oat_patches); } // Write .debug_info section. if (!compilation_units.empty()) { ElfDebugInfoWriter<ElfTypes> info_writer(builder); info_writer.Start(); for (const auto& compilation_unit : compilation_units) { ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer); cu_writer.Write(compilation_unit); } info_writer.End(write_oat_patches); } } std::vector<uint8_t> MakeMiniDebugInfo( InstructionSet isa, const InstructionSetFeatures* features, size_t rodata_size, size_t text_size, const ArrayRef<const MethodDebugInfo>& method_infos) { if (Is64BitInstructionSet(isa)) { return MakeMiniDebugInfoInternal<ElfTypes64>(isa, features, rodata_size, text_size, method_infos); } else { return MakeMiniDebugInfoInternal<ElfTypes32>(isa, features, rodata_size, text_size, method_infos); } } template <typename ElfTypes> static std::vector<uint8_t> WriteDebugElfFileForMethodsInternal( InstructionSet isa, const InstructionSetFeatures* features, const ArrayRef<const MethodDebugInfo>& method_infos) { std::vector<uint8_t> buffer; buffer.reserve(KB); VectorOutputStream out("Debug ELF file", &buffer); std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out)); // No program headers since the ELF file is not linked and has no allocated sections. builder->Start(false /* write_program_headers */); WriteDebugInfo(builder.get(), method_infos, dwarf::DW_DEBUG_FRAME_FORMAT, false /* write_oat_patches */); builder->End(); CHECK(builder->Good()); return buffer; } std::vector<uint8_t> WriteDebugElfFileForMethods( InstructionSet isa, const InstructionSetFeatures* features, const ArrayRef<const MethodDebugInfo>& method_infos) { if (Is64BitInstructionSet(isa)) { return WriteDebugElfFileForMethodsInternal<ElfTypes64>(isa, features, method_infos); } else { return WriteDebugElfFileForMethodsInternal<ElfTypes32>(isa, features, method_infos); } } template <typename ElfTypes> static std::vector<uint8_t> WriteDebugElfFileForClassesInternal( InstructionSet isa, const InstructionSetFeatures* features, const ArrayRef<mirror::Class*>& types) REQUIRES_SHARED(Locks::mutator_lock_) { std::vector<uint8_t> buffer; buffer.reserve(KB); VectorOutputStream out("Debug ELF file", &buffer); std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out)); // No program headers since the ELF file is not linked and has no allocated sections. builder->Start(false /* write_program_headers */); ElfDebugInfoWriter<ElfTypes> info_writer(builder.get()); info_writer.Start(); ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer); cu_writer.Write(types); info_writer.End(false /* write_oat_patches */); builder->End(); CHECK(builder->Good()); return buffer; } std::vector<uint8_t> WriteDebugElfFileForClasses(InstructionSet isa, const InstructionSetFeatures* features, const ArrayRef<mirror::Class*>& types) { if (Is64BitInstructionSet(isa)) { return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, features, types); } else { return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, features, types); } } 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, const ArrayRef<const MethodDebugInfo>& method_infos, dwarf::CFIFormat cfi_format, bool write_oat_patches); template void WriteDebugInfo<ElfTypes64>( ElfBuilder<ElfTypes64>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, dwarf::CFIFormat cfi_format, bool write_oat_patches); } // namespace debug } // namespace art