1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "elf_debug_writer.h" 18 19#include <vector> 20 21#include "debug/dwarf/dwarf_constants.h" 22#include "debug/elf_compilation_unit.h" 23#include "debug/elf_debug_frame_writer.h" 24#include "debug/elf_debug_info_writer.h" 25#include "debug/elf_debug_line_writer.h" 26#include "debug/elf_debug_loc_writer.h" 27#include "debug/elf_gnu_debugdata_writer.h" 28#include "debug/elf_symtab_writer.h" 29#include "debug/method_debug_info.h" 30#include "elf_builder.h" 31#include "linker/vector_output_stream.h" 32#include "utils/array_ref.h" 33 34namespace art { 35namespace debug { 36 37template <typename ElfTypes> 38void WriteDebugInfo(ElfBuilder<ElfTypes>* builder, 39 const ArrayRef<const MethodDebugInfo>& method_infos, 40 dwarf::CFIFormat cfi_format, 41 bool write_oat_patches) { 42 // Write .strtab and .symtab. 43 WriteDebugSymbols(builder, method_infos, true /* with_signature */); 44 45 // Write .debug_frame. 46 WriteCFISection(builder, method_infos, cfi_format, write_oat_patches); 47 48 // Group the methods into compilation units based on source file. 49 std::vector<ElfCompilationUnit> compilation_units; 50 const char* last_source_file = nullptr; 51 for (const MethodDebugInfo& mi : method_infos) { 52 if (mi.dex_file != nullptr) { 53 auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index); 54 const char* source_file = mi.dex_file->GetSourceFile(dex_class_def); 55 if (compilation_units.empty() || source_file != last_source_file) { 56 compilation_units.push_back(ElfCompilationUnit()); 57 } 58 ElfCompilationUnit& cu = compilation_units.back(); 59 cu.methods.push_back(&mi); 60 // All methods must have the same addressing mode otherwise the min/max below does not work. 61 DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative); 62 cu.is_code_address_text_relative = mi.is_code_address_text_relative; 63 cu.code_address = std::min(cu.code_address, mi.code_address); 64 cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size); 65 last_source_file = source_file; 66 } 67 } 68 69 // Write .debug_line section. 70 if (!compilation_units.empty()) { 71 ElfDebugLineWriter<ElfTypes> line_writer(builder); 72 line_writer.Start(); 73 for (auto& compilation_unit : compilation_units) { 74 line_writer.WriteCompilationUnit(compilation_unit); 75 } 76 line_writer.End(write_oat_patches); 77 } 78 79 // Write .debug_info section. 80 if (!compilation_units.empty()) { 81 ElfDebugInfoWriter<ElfTypes> info_writer(builder); 82 info_writer.Start(); 83 for (const auto& compilation_unit : compilation_units) { 84 ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer); 85 cu_writer.Write(compilation_unit); 86 } 87 info_writer.End(write_oat_patches); 88 } 89} 90 91std::vector<uint8_t> MakeMiniDebugInfo( 92 InstructionSet isa, 93 const InstructionSetFeatures* features, 94 size_t rodata_size, 95 size_t text_size, 96 const ArrayRef<const MethodDebugInfo>& method_infos) { 97 if (Is64BitInstructionSet(isa)) { 98 return MakeMiniDebugInfoInternal<ElfTypes64>(isa, 99 features, 100 rodata_size, 101 text_size, 102 method_infos); 103 } else { 104 return MakeMiniDebugInfoInternal<ElfTypes32>(isa, 105 features, 106 rodata_size, 107 text_size, 108 method_infos); 109 } 110} 111 112template <typename ElfTypes> 113static std::vector<uint8_t> WriteDebugElfFileForMethodsInternal( 114 InstructionSet isa, 115 const InstructionSetFeatures* features, 116 const ArrayRef<const MethodDebugInfo>& method_infos) { 117 std::vector<uint8_t> buffer; 118 buffer.reserve(KB); 119 VectorOutputStream out("Debug ELF file", &buffer); 120 std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out)); 121 // No program headers since the ELF file is not linked and has no allocated sections. 122 builder->Start(false /* write_program_headers */); 123 WriteDebugInfo(builder.get(), 124 method_infos, 125 dwarf::DW_DEBUG_FRAME_FORMAT, 126 false /* write_oat_patches */); 127 builder->End(); 128 CHECK(builder->Good()); 129 return buffer; 130} 131 132std::vector<uint8_t> WriteDebugElfFileForMethods( 133 InstructionSet isa, 134 const InstructionSetFeatures* features, 135 const ArrayRef<const MethodDebugInfo>& method_infos) { 136 if (Is64BitInstructionSet(isa)) { 137 return WriteDebugElfFileForMethodsInternal<ElfTypes64>(isa, features, method_infos); 138 } else { 139 return WriteDebugElfFileForMethodsInternal<ElfTypes32>(isa, features, method_infos); 140 } 141} 142 143template <typename ElfTypes> 144static std::vector<uint8_t> WriteDebugElfFileForClassesInternal( 145 InstructionSet isa, 146 const InstructionSetFeatures* features, 147 const ArrayRef<mirror::Class*>& types) 148 SHARED_REQUIRES(Locks::mutator_lock_) { 149 std::vector<uint8_t> buffer; 150 buffer.reserve(KB); 151 VectorOutputStream out("Debug ELF file", &buffer); 152 std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out)); 153 // No program headers since the ELF file is not linked and has no allocated sections. 154 builder->Start(false /* write_program_headers */); 155 ElfDebugInfoWriter<ElfTypes> info_writer(builder.get()); 156 info_writer.Start(); 157 ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer); 158 cu_writer.Write(types); 159 info_writer.End(false /* write_oat_patches */); 160 161 builder->End(); 162 CHECK(builder->Good()); 163 return buffer; 164} 165 166std::vector<uint8_t> WriteDebugElfFileForClasses(InstructionSet isa, 167 const InstructionSetFeatures* features, 168 const ArrayRef<mirror::Class*>& types) { 169 if (Is64BitInstructionSet(isa)) { 170 return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, features, types); 171 } else { 172 return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, features, types); 173 } 174} 175 176std::vector<MethodDebugInfo> MakeTrampolineInfos(const OatHeader& header) { 177 std::map<const char*, uint32_t> trampolines = { 178 { "interpreterToInterpreterBridge", header.GetInterpreterToInterpreterBridgeOffset() }, 179 { "interpreterToCompiledCodeBridge", header.GetInterpreterToCompiledCodeBridgeOffset() }, 180 { "jniDlsymLookup", header.GetJniDlsymLookupOffset() }, 181 { "quickGenericJniTrampoline", header.GetQuickGenericJniTrampolineOffset() }, 182 { "quickImtConflictTrampoline", header.GetQuickImtConflictTrampolineOffset() }, 183 { "quickResolutionTrampoline", header.GetQuickResolutionTrampolineOffset() }, 184 { "quickToInterpreterBridge", header.GetQuickToInterpreterBridgeOffset() }, 185 }; 186 std::vector<MethodDebugInfo> result; 187 for (const auto& it : trampolines) { 188 if (it.second != 0) { 189 MethodDebugInfo info = MethodDebugInfo(); 190 info.trampoline_name = it.first; 191 info.isa = header.GetInstructionSet(); 192 info.is_code_address_text_relative = true; 193 info.code_address = it.second - header.GetExecutableOffset(); 194 info.code_size = 0; // The symbol lasts until the next symbol. 195 result.push_back(std::move(info)); 196 } 197 } 198 return result; 199} 200 201// Explicit instantiations 202template void WriteDebugInfo<ElfTypes32>( 203 ElfBuilder<ElfTypes32>* builder, 204 const ArrayRef<const MethodDebugInfo>& method_infos, 205 dwarf::CFIFormat cfi_format, 206 bool write_oat_patches); 207template void WriteDebugInfo<ElfTypes64>( 208 ElfBuilder<ElfTypes64>* builder, 209 const ArrayRef<const MethodDebugInfo>& method_infos, 210 dwarf::CFIFormat cfi_format, 211 bool write_oat_patches); 212 213} // namespace debug 214} // namespace art 215