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