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