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
34 namespace art {
35 namespace debug {
36
37 template <typename ElfTypes>
WriteDebugInfo(ElfBuilder<ElfTypes> * builder,const ArrayRef<const MethodDebugInfo> & method_infos,dwarf::CFIFormat cfi_format,bool write_oat_patches)38 void 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
MakeMiniDebugInfo(InstructionSet isa,const InstructionSetFeatures * features,size_t rodata_size,size_t text_size,const ArrayRef<const MethodDebugInfo> & method_infos)91 std::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
112 template <typename ElfTypes>
WriteDebugElfFileForMethodsInternal(InstructionSet isa,const InstructionSetFeatures * features,const ArrayRef<const MethodDebugInfo> & method_infos)113 static 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
WriteDebugElfFileForMethods(InstructionSet isa,const InstructionSetFeatures * features,const ArrayRef<const MethodDebugInfo> & method_infos)132 std::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
143 template <typename ElfTypes>
WriteDebugElfFileForClassesInternal(InstructionSet isa,const InstructionSetFeatures * features,const ArrayRef<mirror::Class * > & types)144 static std::vector<uint8_t> WriteDebugElfFileForClassesInternal(
145 InstructionSet isa,
146 const InstructionSetFeatures* features,
147 const ArrayRef<mirror::Class*>& types)
148 REQUIRES_SHARED(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
WriteDebugElfFileForClasses(InstructionSet isa,const InstructionSetFeatures * features,const ArrayRef<mirror::Class * > & types)166 std::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
MakeTrampolineInfos(const OatHeader & header)176 std::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
202 template void WriteDebugInfo<ElfTypes32>(
203 ElfBuilder<ElfTypes32>* builder,
204 const ArrayRef<const MethodDebugInfo>& method_infos,
205 dwarf::CFIFormat cfi_format,
206 bool write_oat_patches);
207 template 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