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 <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>
     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 
     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>
    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 
    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>
    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 
    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 
    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