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