• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <type_traits>
20 #include <unordered_map>
21 #include <vector>
22 
23 #include "base/array_ref.h"
24 #include "base/stl_util.h"
25 #include "debug/elf_compilation_unit.h"
26 #include "debug/elf_debug_frame_writer.h"
27 #include "debug/elf_debug_info_writer.h"
28 #include "debug/elf_debug_line_writer.h"
29 #include "debug/elf_debug_loc_writer.h"
30 #include "debug/elf_symtab_writer.h"
31 #include "debug/method_debug_info.h"
32 #include "dwarf/dwarf_constants.h"
33 #include "elf/elf_builder.h"
34 #include "elf/elf_debug_reader.h"
35 #include "elf/elf_utils.h"
36 #include "elf/xz_utils.h"
37 #include "jit/debugger_interface.h"
38 #include "oat.h"
39 #include "stream/vector_output_stream.h"
40 
41 namespace art HIDDEN {
42 namespace debug {
43 
44 using ElfRuntimeTypes = std::conditional<sizeof(void*) == 4, ElfTypes32, ElfTypes64>::type;
45 
46 template <typename ElfTypes>
WriteDebugInfo(ElfBuilder<ElfTypes> * builder,const DebugInfo & debug_info)47 void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
48                     const DebugInfo& debug_info) {
49   // Write .strtab and .symtab.
50   WriteDebugSymbols(builder, /* mini-debug-info= */ false, debug_info);
51 
52   // Write .debug_frame.
53   WriteCFISection(builder, debug_info.compiled_methods);
54 
55   // Group the methods into compilation units based on class.
56   std::unordered_map<const dex::ClassDef*, ElfCompilationUnit> class_to_compilation_unit;
57   for (const MethodDebugInfo& mi : debug_info.compiled_methods) {
58     if (mi.dex_file != nullptr) {
59       auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
60       ElfCompilationUnit& cu = class_to_compilation_unit[&dex_class_def];
61       cu.methods.push_back(&mi);
62       // All methods must have the same addressing mode otherwise the min/max below does not work.
63       DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
64       cu.is_code_address_text_relative = mi.is_code_address_text_relative;
65       cu.code_address = std::min(cu.code_address, mi.code_address);
66       cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
67     }
68   }
69 
70   // Sort compilation units to make the compiler output deterministic.
71   std::vector<ElfCompilationUnit> compilation_units;
72   compilation_units.reserve(class_to_compilation_unit.size());
73   for (auto& it : class_to_compilation_unit) {
74     // The .debug_line section requires the methods to be sorted by code address.
75     std::stable_sort(it.second.methods.begin(),
76                      it.second.methods.end(),
77                      [](const MethodDebugInfo* a, const MethodDebugInfo* b) {
78                          return a->code_address < b->code_address;
79                      });
80     compilation_units.push_back(std::move(it.second));
81   }
82   std::sort(compilation_units.begin(),
83             compilation_units.end(),
84             [](ElfCompilationUnit& a, ElfCompilationUnit& b) {
85                 // Sort by index of the first method within the method_infos array.
86                 // This assumes that the order of method_infos is deterministic.
87                 // Code address is not good for sorting due to possible duplicates.
88                 return a.methods.front() < b.methods.front();
89             });
90 
91   // Write .debug_line section.
92   if (!compilation_units.empty()) {
93     ElfDebugLineWriter<ElfTypes> line_writer(builder);
94     line_writer.Start();
95     for (auto& compilation_unit : compilation_units) {
96       line_writer.WriteCompilationUnit(compilation_unit);
97     }
98     line_writer.End();
99   }
100 
101   // Write .debug_info section.
102   if (!compilation_units.empty()) {
103     ElfDebugInfoWriter<ElfTypes> info_writer(builder);
104     info_writer.Start();
105     for (const auto& compilation_unit : compilation_units) {
106       ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
107       cu_writer.Write(compilation_unit);
108     }
109     info_writer.End();
110   }
111 }
112 
113 template <typename ElfTypes>
MakeMiniDebugInfoInternal(InstructionSet isa,const InstructionSetFeatures * features ATTRIBUTE_UNUSED,typename ElfTypes::Addr text_section_address,size_t text_section_size,typename ElfTypes::Addr dex_section_address,size_t dex_section_size,const DebugInfo & debug_info)114 static std::vector<uint8_t> MakeMiniDebugInfoInternal(
115     InstructionSet isa,
116     const InstructionSetFeatures* features ATTRIBUTE_UNUSED,
117     typename ElfTypes::Addr text_section_address,
118     size_t text_section_size,
119     typename ElfTypes::Addr dex_section_address,
120     size_t dex_section_size,
121     const DebugInfo& debug_info) {
122   std::vector<uint8_t> buffer;
123   buffer.reserve(KB);
124   VectorOutputStream out("Mini-debug-info ELF file", &buffer);
125   std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
126   builder->Start(/* write_program_headers= */ false);
127   // Mirror ELF sections as NOBITS since the added symbols will reference them.
128   if (text_section_size != 0) {
129     builder->GetText()->AllocateVirtualMemory(text_section_address, text_section_size);
130   }
131   if (dex_section_size != 0) {
132     builder->GetDex()->AllocateVirtualMemory(dex_section_address, dex_section_size);
133   }
134   if (!debug_info.Empty()) {
135     WriteDebugSymbols(builder.get(), /* mini-debug-info= */ true, debug_info);
136   }
137   if (!debug_info.compiled_methods.empty()) {
138     WriteCFISection(builder.get(), debug_info.compiled_methods);
139   }
140   builder->End();
141   CHECK(builder->Good());
142   std::vector<uint8_t> compressed_buffer;
143   compressed_buffer.reserve(buffer.size() / 4);
144   XzCompress(ArrayRef<const uint8_t>(buffer), &compressed_buffer);
145   return compressed_buffer;
146 }
147 
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)148 std::vector<uint8_t> MakeMiniDebugInfo(
149     InstructionSet isa,
150     const InstructionSetFeatures* features,
151     uint64_t text_section_address,
152     size_t text_section_size,
153     uint64_t dex_section_address,
154     size_t dex_section_size,
155     const DebugInfo& debug_info) {
156   if (Is64BitInstructionSet(isa)) {
157     return MakeMiniDebugInfoInternal<ElfTypes64>(isa,
158                                                  features,
159                                                  text_section_address,
160                                                  text_section_size,
161                                                  dex_section_address,
162                                                  dex_section_size,
163                                                  debug_info);
164   } else {
165     return MakeMiniDebugInfoInternal<ElfTypes32>(isa,
166                                                  features,
167                                                  text_section_address,
168                                                  text_section_size,
169                                                  dex_section_address,
170                                                  dex_section_size,
171                                                  debug_info);
172   }
173 }
174 
MakeElfFileForJIT(InstructionSet isa,const InstructionSetFeatures * features ATTRIBUTE_UNUSED,bool mini_debug_info,const MethodDebugInfo & method_info)175 std::vector<uint8_t> MakeElfFileForJIT(
176     InstructionSet isa,
177     const InstructionSetFeatures* features ATTRIBUTE_UNUSED,
178     bool mini_debug_info,
179     const MethodDebugInfo& method_info) {
180   using ElfTypes = ElfRuntimeTypes;
181   CHECK_EQ(sizeof(ElfTypes::Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa)));
182   CHECK_EQ(method_info.is_code_address_text_relative, false);
183   DebugInfo debug_info{};
184   debug_info.compiled_methods = ArrayRef<const MethodDebugInfo>(&method_info, 1);
185   std::vector<uint8_t> buffer;
186   buffer.reserve(KB);
187   VectorOutputStream out("Debug ELF file", &buffer);
188   std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
189   // No program headers since the ELF file is not linked and has no allocated sections.
190   builder->Start(/* write_program_headers= */ false);
191   builder->GetText()->AllocateVirtualMemory(method_info.code_address, method_info.code_size);
192   if (mini_debug_info) {
193     // The compression is great help for multiple methods but it is not worth it for a
194     // single method due to the overheads so skip the compression here for performance.
195     WriteDebugSymbols(builder.get(), /* mini-debug-info= */ true, debug_info);
196     WriteCFISection(builder.get(), debug_info.compiled_methods);
197   } else {
198     WriteDebugInfo(builder.get(), debug_info);
199   }
200   builder->End();
201   CHECK(builder->Good());
202   // Verify the ELF file by reading it back using the trivial reader.
203   if (kIsDebugBuild) {
204     using Elf_Sym = typename ElfTypes::Sym;
205     size_t num_syms = 0;
206     size_t num_cies = 0;
207     size_t num_fdes = 0;
208     using Reader = ElfDebugReader<ElfTypes>;
209     Reader reader(buffer);
210     reader.VisitFunctionSymbols([&](Elf_Sym sym, const char*) {
211       DCHECK_EQ(sym.st_value,
212                 method_info.code_address + GetInstructionSetEntryPointAdjustment(isa));
213       DCHECK_EQ(sym.st_size, method_info.code_size);
214       num_syms++;
215     });
216     reader.VisitDebugFrame([&](const Reader::CIE* cie ATTRIBUTE_UNUSED) {
217       num_cies++;
218     }, [&](const Reader::FDE* fde, const Reader::CIE* cie ATTRIBUTE_UNUSED) {
219       DCHECK_EQ(fde->sym_addr, method_info.code_address);
220       DCHECK_EQ(fde->sym_size, method_info.code_size);
221       num_fdes++;
222     });
223     DCHECK_EQ(num_syms, 1u);
224     DCHECK_LE(num_cies, 1u);
225     DCHECK_LE(num_fdes, 1u);
226   }
227   return buffer;
228 }
229 
230 // Combine several mini-debug-info ELF files into one, while filtering some symbols.
PackElfFileForJIT(ArrayRef<const JITCodeEntry * > jit_entries,ArrayRef<const void * > removed_symbols,bool compress,size_t * num_symbols)231 std::vector<uint8_t> PackElfFileForJIT(
232     ArrayRef<const JITCodeEntry*> jit_entries,
233     ArrayRef<const void*> removed_symbols,
234     bool compress,
235     /*out*/ size_t* num_symbols) {
236   using ElfTypes = ElfRuntimeTypes;
237   using Elf_Addr = typename ElfTypes::Addr;
238   using Elf_Sym = typename ElfTypes::Sym;
239   const InstructionSet isa = kRuntimeISA;
240   CHECK_EQ(sizeof(Elf_Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa)));
241   const uint32_t kPcAlign = GetInstructionSetInstructionAlignment(isa);
242   auto is_pc_aligned = [](const void* pc) { return IsAligned<kPcAlign>(pc); };
243   DCHECK(std::all_of(removed_symbols.begin(), removed_symbols.end(), is_pc_aligned));
244   auto is_removed_symbol = [&removed_symbols](Elf_Addr addr) {
245     // Remove thumb-bit, if any (using the fact that address is instruction aligned).
246     const void* code_ptr = AlignDown(reinterpret_cast<const void*>(addr), kPcAlign);
247     return std::binary_search(removed_symbols.begin(), removed_symbols.end(), code_ptr);
248   };
249   uint64_t min_address = std::numeric_limits<uint64_t>::max();
250   uint64_t max_address = 0;
251 
252   // Produce the inner ELF file.
253   // It will contain the symbols (.symtab) and unwind information (.debug_frame).
254   std::vector<uint8_t> inner_elf_file;
255   {
256     inner_elf_file.reserve(1 * KB);  // Approximate size of ELF file with a single symbol.
257     VectorOutputStream out("Mini-debug-info ELF file for JIT", &inner_elf_file);
258     std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
259     builder->Start(/*write_program_headers=*/ false);
260     auto* text = builder->GetText();
261     auto* strtab = builder->GetStrTab();
262     auto* symtab = builder->GetSymTab();
263     auto* debug_frame = builder->GetDebugFrame();
264     std::deque<Elf_Sym> symbols;
265 
266     using Reader = ElfDebugReader<ElfTypes>;
267     std::deque<Reader> readers;
268     for (const JITCodeEntry* it : jit_entries) {
269       readers.emplace_back(GetJITCodeEntrySymFile(it));
270     }
271 
272     // Write symbols names. All other data is buffered.
273     strtab->Start();
274     strtab->Write("");  // strtab should start with empty string.
275     for (Reader& reader : readers) {
276       reader.VisitFunctionSymbols([&](Elf_Sym sym, const char* name) {
277           if (is_removed_symbol(sym.st_value)) {
278             return;
279           }
280           sym.st_name = strtab->Write(name);
281           symbols.push_back(sym);
282           min_address = std::min<uint64_t>(min_address, sym.st_value);
283           max_address = std::max<uint64_t>(max_address, sym.st_value + sym.st_size);
284       });
285     }
286     strtab->End();
287 
288     // Create .text covering the code range. Needed for gdb to find the symbols.
289     if (max_address > min_address) {
290       text->AllocateVirtualMemory(min_address, max_address - min_address);
291     }
292 
293     // Add the symbols.
294     *num_symbols = symbols.size();
295     for (; !symbols.empty(); symbols.pop_front()) {
296       symtab->Add(symbols.front(), text);
297     }
298     symtab->WriteCachedSection();
299 
300     // Add the CFI/unwind section.
301     debug_frame->Start();
302     // ART always produces the same CIE, so we copy the first one and ignore the rest.
303     bool copied_cie = false;
304     for (Reader& reader : readers) {
305       reader.VisitDebugFrame([&](const Reader::CIE* cie) {
306         if (!copied_cie) {
307           debug_frame->WriteFully(cie->data(), cie->size());
308           copied_cie = true;
309         }
310       }, [&](const Reader::FDE* fde, const Reader::CIE* cie ATTRIBUTE_UNUSED) {
311         DCHECK(copied_cie);
312         DCHECK_EQ(fde->cie_pointer, 0);
313         if (!is_removed_symbol(fde->sym_addr)) {
314           debug_frame->WriteFully(fde->data(), fde->size());
315         }
316       });
317     }
318     debug_frame->End();
319 
320     builder->End();
321     CHECK(builder->Good());
322   }
323 
324   // Produce the outer ELF file.
325   // It contains only the inner ELF file compressed as .gnu_debugdata section.
326   // This extra wrapping is not necessary but the compression saves space.
327   if (compress) {
328     std::vector<uint8_t> outer_elf_file;
329     std::vector<uint8_t> gnu_debugdata;
330     gnu_debugdata.reserve(inner_elf_file.size() / 4);
331     XzCompress(ArrayRef<const uint8_t>(inner_elf_file), &gnu_debugdata);
332 
333     outer_elf_file.reserve(KB + gnu_debugdata.size());
334     VectorOutputStream out("Mini-debug-info ELF file for JIT", &outer_elf_file);
335     std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
336     builder->Start(/*write_program_headers=*/ false);
337     if (max_address > min_address) {
338       builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address);
339     }
340     builder->WriteSection(".gnu_debugdata", &gnu_debugdata);
341     builder->End();
342     CHECK(builder->Good());
343     return outer_elf_file;
344   } else {
345     return inner_elf_file;
346   }
347 }
348 
WriteDebugElfFileForClasses(InstructionSet isa,const InstructionSetFeatures * features ATTRIBUTE_UNUSED,const ArrayRef<mirror::Class * > & types)349 std::vector<uint8_t> WriteDebugElfFileForClasses(
350     InstructionSet isa,
351     const InstructionSetFeatures* features ATTRIBUTE_UNUSED,
352     const ArrayRef<mirror::Class*>& types)
353     REQUIRES_SHARED(Locks::mutator_lock_) {
354   using ElfTypes = ElfRuntimeTypes;
355   CHECK_EQ(sizeof(ElfTypes::Addr), static_cast<size_t>(GetInstructionSetPointerSize(isa)));
356   std::vector<uint8_t> buffer;
357   buffer.reserve(KB);
358   VectorOutputStream out("Debug ELF file", &buffer);
359   std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
360   // No program headers since the ELF file is not linked and has no allocated sections.
361   builder->Start(/* write_program_headers= */ false);
362   ElfDebugInfoWriter<ElfTypes> info_writer(builder.get());
363   info_writer.Start();
364   ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
365   cu_writer.Write(types);
366   info_writer.End();
367 
368   builder->End();
369   CHECK(builder->Good());
370   return buffer;
371 }
372 
373 // Explicit instantiations
374 template void WriteDebugInfo<ElfTypes32>(
375     ElfBuilder<ElfTypes32>* builder,
376     const DebugInfo& debug_info);
377 template void WriteDebugInfo<ElfTypes64>(
378     ElfBuilder<ElfTypes64>* builder,
379     const DebugInfo& debug_info);
380 
381 }  // namespace debug
382 }  // namespace art
383