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 #include <unordered_map>
21 
22 #include "base/array_ref.h"
23 #include "debug/dwarf/dwarf_constants.h"
24 #include "debug/elf_compilation_unit.h"
25 #include "debug/elf_debug_frame_writer.h"
26 #include "debug/elf_debug_info_writer.h"
27 #include "debug/elf_debug_line_writer.h"
28 #include "debug/elf_debug_loc_writer.h"
29 #include "debug/elf_gnu_debugdata_writer.h"
30 #include "debug/elf_symtab_writer.h"
31 #include "debug/method_debug_info.h"
32 #include "linker/elf_builder.h"
33 #include "linker/vector_output_stream.h"
34 #include "oat.h"
35 
36 namespace art {
37 namespace debug {
38 
39 template <typename ElfTypes>
WriteDebugInfo(linker::ElfBuilder<ElfTypes> * builder,const DebugInfo & debug_info,dwarf::CFIFormat cfi_format,bool write_oat_patches)40 void WriteDebugInfo(linker::ElfBuilder<ElfTypes>* builder,
41                     const DebugInfo& debug_info,
42                     dwarf::CFIFormat cfi_format,
43                     bool write_oat_patches) {
44   // Write .strtab and .symtab.
45   WriteDebugSymbols(builder, false /* mini-debug-info */, debug_info);
46 
47   // Write .debug_frame.
48   WriteCFISection(builder, debug_info.compiled_methods, cfi_format, write_oat_patches);
49 
50   // Group the methods into compilation units based on class.
51   std::unordered_map<const DexFile::ClassDef*, ElfCompilationUnit> class_to_compilation_unit;
52   for (const MethodDebugInfo& mi : debug_info.compiled_methods) {
53     if (mi.dex_file != nullptr) {
54       auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
55       ElfCompilationUnit& cu = class_to_compilation_unit[&dex_class_def];
56       cu.methods.push_back(&mi);
57       // All methods must have the same addressing mode otherwise the min/max below does not work.
58       DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
59       cu.is_code_address_text_relative = mi.is_code_address_text_relative;
60       cu.code_address = std::min(cu.code_address, mi.code_address);
61       cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
62     }
63   }
64 
65   // Sort compilation units to make the compiler output deterministic.
66   std::vector<ElfCompilationUnit> compilation_units;
67   compilation_units.reserve(class_to_compilation_unit.size());
68   for (auto& it : class_to_compilation_unit) {
69     // The .debug_line section requires the methods to be sorted by code address.
70     std::stable_sort(it.second.methods.begin(),
71                      it.second.methods.end(),
72                      [](const MethodDebugInfo* a, const MethodDebugInfo* b) {
73                          return a->code_address < b->code_address;
74                      });
75     compilation_units.push_back(std::move(it.second));
76   }
77   std::sort(compilation_units.begin(),
78             compilation_units.end(),
79             [](ElfCompilationUnit& a, ElfCompilationUnit& b) {
80                 // Sort by index of the first method within the method_infos array.
81                 // This assumes that the order of method_infos is deterministic.
82                 // Code address is not good for sorting due to possible duplicates.
83                 return a.methods.front() < b.methods.front();
84             });
85 
86   // Write .debug_line section.
87   if (!compilation_units.empty()) {
88     ElfDebugLineWriter<ElfTypes> line_writer(builder);
89     line_writer.Start();
90     for (auto& compilation_unit : compilation_units) {
91       line_writer.WriteCompilationUnit(compilation_unit);
92     }
93     line_writer.End(write_oat_patches);
94   }
95 
96   // Write .debug_info section.
97   if (!compilation_units.empty()) {
98     ElfDebugInfoWriter<ElfTypes> info_writer(builder);
99     info_writer.Start();
100     for (const auto& compilation_unit : compilation_units) {
101       ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
102       cu_writer.Write(compilation_unit);
103     }
104     info_writer.End(write_oat_patches);
105   }
106 }
107 
MakeMiniDebugInfo(InstructionSet isa,const InstructionSetFeatures * features,uint64_t text_section_address,size_t text_section_size,uint64_t dex_section_address,size_t dex_section_size,const DebugInfo & debug_info)108 std::vector<uint8_t> MakeMiniDebugInfo(
109     InstructionSet isa,
110     const InstructionSetFeatures* features,
111     uint64_t text_section_address,
112     size_t text_section_size,
113     uint64_t dex_section_address,
114     size_t dex_section_size,
115     const DebugInfo& debug_info) {
116   if (Is64BitInstructionSet(isa)) {
117     return MakeMiniDebugInfoInternal<ElfTypes64>(isa,
118                                                  features,
119                                                  text_section_address,
120                                                  text_section_size,
121                                                  dex_section_address,
122                                                  dex_section_size,
123                                                  debug_info);
124   } else {
125     return MakeMiniDebugInfoInternal<ElfTypes32>(isa,
126                                                  features,
127                                                  text_section_address,
128                                                  text_section_size,
129                                                  dex_section_address,
130                                                  dex_section_size,
131                                                  debug_info);
132   }
133 }
134 
135 template <typename ElfTypes>
MakeElfFileForJITInternal(InstructionSet isa,const InstructionSetFeatures * features,bool mini_debug_info,ArrayRef<const MethodDebugInfo> method_infos)136 static std::vector<uint8_t> MakeElfFileForJITInternal(
137     InstructionSet isa,
138     const InstructionSetFeatures* features,
139     bool mini_debug_info,
140     ArrayRef<const MethodDebugInfo> method_infos) {
141   CHECK_GT(method_infos.size(), 0u);
142   uint64_t min_address = std::numeric_limits<uint64_t>::max();
143   uint64_t max_address = 0;
144   for (const MethodDebugInfo& mi : method_infos) {
145     CHECK_EQ(mi.is_code_address_text_relative, false);
146     min_address = std::min(min_address, mi.code_address);
147     max_address = std::max(max_address, mi.code_address + mi.code_size);
148   }
149   DebugInfo debug_info{};
150   debug_info.compiled_methods = method_infos;
151   std::vector<uint8_t> buffer;
152   buffer.reserve(KB);
153   linker::VectorOutputStream out("Debug ELF file", &buffer);
154   std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
155       new linker::ElfBuilder<ElfTypes>(isa, features, &out));
156   // No program headers since the ELF file is not linked and has no allocated sections.
157   builder->Start(false /* write_program_headers */);
158   if (mini_debug_info) {
159     if (method_infos.size() > 1) {
160       std::vector<uint8_t> mdi = MakeMiniDebugInfo(isa,
161                                                    features,
162                                                    min_address,
163                                                    max_address - min_address,
164                                                    /* dex_section_address */ 0,
165                                                    /* dex_section_size */ 0,
166                                                    debug_info);
167       builder->WriteSection(".gnu_debugdata", &mdi);
168     } else {
169       // The compression is great help for multiple methods but it is not worth it for a
170       // single method due to the overheads so skip the compression here for performance.
171       builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address);
172       WriteDebugSymbols(builder.get(), true /* mini-debug-info */, debug_info);
173       WriteCFISection(builder.get(),
174                       debug_info.compiled_methods,
175                       dwarf::DW_DEBUG_FRAME_FORMAT,
176                       false /* write_oat_paches */);
177     }
178   } else {
179     builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address);
180     WriteDebugInfo(builder.get(),
181                    debug_info,
182                    dwarf::DW_DEBUG_FRAME_FORMAT,
183                    false /* write_oat_patches */);
184   }
185   builder->End();
186   CHECK(builder->Good());
187   return buffer;
188 }
189 
MakeElfFileForJIT(InstructionSet isa,const InstructionSetFeatures * features,bool mini_debug_info,ArrayRef<const MethodDebugInfo> method_infos)190 std::vector<uint8_t> MakeElfFileForJIT(
191     InstructionSet isa,
192     const InstructionSetFeatures* features,
193     bool mini_debug_info,
194     ArrayRef<const MethodDebugInfo> method_infos) {
195   if (Is64BitInstructionSet(isa)) {
196     return MakeElfFileForJITInternal<ElfTypes64>(isa, features, mini_debug_info, method_infos);
197   } else {
198     return MakeElfFileForJITInternal<ElfTypes32>(isa, features, mini_debug_info, method_infos);
199   }
200 }
201 
202 template <typename ElfTypes>
WriteDebugElfFileForClassesInternal(InstructionSet isa,const InstructionSetFeatures * features,const ArrayRef<mirror::Class * > & types)203 static std::vector<uint8_t> WriteDebugElfFileForClassesInternal(
204     InstructionSet isa,
205     const InstructionSetFeatures* features,
206     const ArrayRef<mirror::Class*>& types)
207     REQUIRES_SHARED(Locks::mutator_lock_) {
208   std::vector<uint8_t> buffer;
209   buffer.reserve(KB);
210   linker::VectorOutputStream out("Debug ELF file", &buffer);
211   std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
212       new linker::ElfBuilder<ElfTypes>(isa, features, &out));
213   // No program headers since the ELF file is not linked and has no allocated sections.
214   builder->Start(false /* write_program_headers */);
215   ElfDebugInfoWriter<ElfTypes> info_writer(builder.get());
216   info_writer.Start();
217   ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
218   cu_writer.Write(types);
219   info_writer.End(false /* write_oat_patches */);
220 
221   builder->End();
222   CHECK(builder->Good());
223   return buffer;
224 }
225 
WriteDebugElfFileForClasses(InstructionSet isa,const InstructionSetFeatures * features,const ArrayRef<mirror::Class * > & types)226 std::vector<uint8_t> WriteDebugElfFileForClasses(InstructionSet isa,
227                                                  const InstructionSetFeatures* features,
228                                                  const ArrayRef<mirror::Class*>& types) {
229   if (Is64BitInstructionSet(isa)) {
230     return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, features, types);
231   } else {
232     return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, features, types);
233   }
234 }
235 
236 // Explicit instantiations
237 template void WriteDebugInfo<ElfTypes32>(
238     linker::ElfBuilder<ElfTypes32>* builder,
239     const DebugInfo& debug_info,
240     dwarf::CFIFormat cfi_format,
241     bool write_oat_patches);
242 template void WriteDebugInfo<ElfTypes64>(
243     linker::ElfBuilder<ElfTypes64>* builder,
244     const DebugInfo& debug_info,
245     dwarf::CFIFormat cfi_format,
246     bool write_oat_patches);
247 
248 }  // namespace debug
249 }  // namespace art
250