diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/Android.mk | 2 | ||||
| -rw-r--r-- | compiler/debug/elf_compilation_unit.h | 38 | ||||
| -rw-r--r-- | compiler/debug/elf_debug_frame_writer.h | 290 | ||||
| -rw-r--r-- | compiler/debug/elf_debug_info_writer.h | 649 | ||||
| -rw-r--r-- | compiler/debug/elf_debug_line_writer.h | 247 | ||||
| -rw-r--r-- | compiler/debug/elf_debug_loc_writer.h | 298 | ||||
| -rw-r--r-- | compiler/debug/elf_debug_writer.cc | 183 | ||||
| -rw-r--r-- | compiler/debug/elf_debug_writer.h (renamed from compiler/debug/elf_writer_debug.h) | 16 | ||||
| -rw-r--r-- | compiler/debug/elf_gnu_debugdata_writer.h | 111 | ||||
| -rw-r--r-- | compiler/debug/elf_symtab_writer.h | 115 | ||||
| -rw-r--r-- | compiler/debug/elf_writer_debug.cc | 1666 | ||||
| -rw-r--r-- | compiler/debug/method_debug_info.h | 31 | ||||
| -rw-r--r-- | compiler/elf_writer.h | 8 | ||||
| -rw-r--r-- | compiler/elf_writer_quick.cc | 18 | ||||
| -rw-r--r-- | compiler/jit/jit_compiler.cc | 4 | ||||
| -rw-r--r-- | compiler/oat_writer.cc | 2 | ||||
| -rw-r--r-- | compiler/oat_writer.h | 10 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 6 | 
18 files changed, 1983 insertions, 1711 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 414f667e5a..b16494248f 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -20,7 +20,7 @@ include art/build/Android.common_build.mk  LIBART_COMPILER_SRC_FILES := \  	compiled_method.cc \ -	debug/elf_writer_debug.cc \ +	debug/elf_debug_writer.cc \  	dex/global_value_numbering.cc \  	dex/gvn_dead_code_elimination.cc \  	dex/local_value_numbering.cc \ diff --git a/compiler/debug/elf_compilation_unit.h b/compiler/debug/elf_compilation_unit.h new file mode 100644 index 0000000000..f725f45e15 --- /dev/null +++ b/compiler/debug/elf_compilation_unit.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_DEBUG_ELF_COMPILATION_UNIT_H_ +#define ART_COMPILER_DEBUG_ELF_COMPILATION_UNIT_H_ + +#include <vector> + +#include "debug/method_debug_info.h" + +namespace art { +namespace debug { + +struct ElfCompilationUnit { +  std::vector<const MethodDebugInfo*> methods; +  size_t debug_line_offset = 0; +  uintptr_t low_pc = std::numeric_limits<uintptr_t>::max(); +  uintptr_t high_pc = 0; +}; + +}  // namespace debug +}  // namespace art + +#endif  // ART_COMPILER_DEBUG_ELF_COMPILATION_UNIT_H_ + diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h new file mode 100644 index 0000000000..f6d9b169c4 --- /dev/null +++ b/compiler/debug/elf_debug_frame_writer.h @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_ +#define ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_ + +#include <vector> + +#include "arch/instruction_set.h" +#include "debug/dwarf/debug_frame_opcode_writer.h" +#include "debug/dwarf/dwarf_constants.h" +#include "debug/dwarf/headers.h" +#include "debug/method_debug_info.h" +#include "elf_builder.h" + +namespace art { +namespace debug { + +static void WriteCIE(InstructionSet isa, +                     dwarf::CFIFormat format, +                     std::vector<uint8_t>* buffer) { +  using Reg = dwarf::Reg; +  // Scratch registers should be marked as undefined.  This tells the +  // debugger that its value in the previous frame is not recoverable. +  bool is64bit = Is64BitInstructionSet(isa); +  switch (isa) { +    case kArm: +    case kThumb2: { +      dwarf::DebugFrameOpCodeWriter<> opcodes; +      opcodes.DefCFA(Reg::ArmCore(13), 0);  // R13(SP). +      // core registers. +      for (int reg = 0; reg < 13; reg++) { +        if (reg < 4 || reg == 12) { +          opcodes.Undefined(Reg::ArmCore(reg)); +        } else { +          opcodes.SameValue(Reg::ArmCore(reg)); +        } +      } +      // fp registers. +      for (int reg = 0; reg < 32; reg++) { +        if (reg < 16) { +          opcodes.Undefined(Reg::ArmFp(reg)); +        } else { +          opcodes.SameValue(Reg::ArmFp(reg)); +        } +      } +      auto return_reg = Reg::ArmCore(14);  // R14(LR). +      WriteCIE(is64bit, return_reg, opcodes, format, buffer); +      return; +    } +    case kArm64: { +      dwarf::DebugFrameOpCodeWriter<> opcodes; +      opcodes.DefCFA(Reg::Arm64Core(31), 0);  // R31(SP). +      // core registers. +      for (int reg = 0; reg < 30; reg++) { +        if (reg < 8 || reg == 16 || reg == 17) { +          opcodes.Undefined(Reg::Arm64Core(reg)); +        } else { +          opcodes.SameValue(Reg::Arm64Core(reg)); +        } +      } +      // fp registers. +      for (int reg = 0; reg < 32; reg++) { +        if (reg < 8 || reg >= 16) { +          opcodes.Undefined(Reg::Arm64Fp(reg)); +        } else { +          opcodes.SameValue(Reg::Arm64Fp(reg)); +        } +      } +      auto return_reg = Reg::Arm64Core(30);  // R30(LR). +      WriteCIE(is64bit, return_reg, opcodes, format, buffer); +      return; +    } +    case kMips: +    case kMips64: { +      dwarf::DebugFrameOpCodeWriter<> opcodes; +      opcodes.DefCFA(Reg::MipsCore(29), 0);  // R29(SP). +      // core registers. +      for (int reg = 1; reg < 26; reg++) { +        if (reg < 16 || reg == 24 || reg == 25) {  // AT, V*, A*, T*. +          opcodes.Undefined(Reg::MipsCore(reg)); +        } else { +          opcodes.SameValue(Reg::MipsCore(reg)); +        } +      } +      // fp registers. +      for (int reg = 0; reg < 32; reg++) { +        if (reg < 24) { +          opcodes.Undefined(Reg::Mips64Fp(reg)); +        } else { +          opcodes.SameValue(Reg::Mips64Fp(reg)); +        } +      } +      auto return_reg = Reg::MipsCore(31);  // R31(RA). +      WriteCIE(is64bit, return_reg, opcodes, format, buffer); +      return; +    } +    case kX86: { +      // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296 +      constexpr bool generate_opcodes_for_x86_fp = false; +      dwarf::DebugFrameOpCodeWriter<> opcodes; +      opcodes.DefCFA(Reg::X86Core(4), 4);   // R4(ESP). +      opcodes.Offset(Reg::X86Core(8), -4);  // R8(EIP). +      // core registers. +      for (int reg = 0; reg < 8; reg++) { +        if (reg <= 3) { +          opcodes.Undefined(Reg::X86Core(reg)); +        } else if (reg == 4) { +          // Stack pointer. +        } else { +          opcodes.SameValue(Reg::X86Core(reg)); +        } +      } +      // fp registers. +      if (generate_opcodes_for_x86_fp) { +        for (int reg = 0; reg < 8; reg++) { +          opcodes.Undefined(Reg::X86Fp(reg)); +        } +      } +      auto return_reg = Reg::X86Core(8);  // R8(EIP). +      WriteCIE(is64bit, return_reg, opcodes, format, buffer); +      return; +    } +    case kX86_64: { +      dwarf::DebugFrameOpCodeWriter<> opcodes; +      opcodes.DefCFA(Reg::X86_64Core(4), 8);  // R4(RSP). +      opcodes.Offset(Reg::X86_64Core(16), -8);  // R16(RIP). +      // core registers. +      for (int reg = 0; reg < 16; reg++) { +        if (reg == 4) { +          // Stack pointer. +        } else if (reg < 12 && reg != 3 && reg != 5) {  // except EBX and EBP. +          opcodes.Undefined(Reg::X86_64Core(reg)); +        } else { +          opcodes.SameValue(Reg::X86_64Core(reg)); +        } +      } +      // fp registers. +      for (int reg = 0; reg < 16; reg++) { +        if (reg < 12) { +          opcodes.Undefined(Reg::X86_64Fp(reg)); +        } else { +          opcodes.SameValue(Reg::X86_64Fp(reg)); +        } +      } +      auto return_reg = Reg::X86_64Core(16);  // R16(RIP). +      WriteCIE(is64bit, return_reg, opcodes, format, buffer); +      return; +    } +    case kNone: +      break; +  } +  LOG(FATAL) << "Cannot write CIE frame for ISA " << isa; +  UNREACHABLE(); +} + +template<typename ElfTypes> +void WriteCFISection(ElfBuilder<ElfTypes>* builder, +                     const ArrayRef<const MethodDebugInfo>& method_infos, +                     dwarf::CFIFormat format, +                     bool write_oat_patches) { +  CHECK(format == dwarf::DW_DEBUG_FRAME_FORMAT || format == dwarf::DW_EH_FRAME_FORMAT); +  typedef typename ElfTypes::Addr Elf_Addr; + +  if (method_infos.empty()) { +    return; +  } + +  std::vector<uint32_t> binary_search_table; +  std::vector<uintptr_t> patch_locations; +  if (format == dwarf::DW_EH_FRAME_FORMAT) { +    binary_search_table.reserve(2 * method_infos.size()); +  } else { +    patch_locations.reserve(method_infos.size()); +  } + +  // The methods can be written in any order. +  // Let's therefore sort them in the lexicographical order of the opcodes. +  // This has no effect on its own. However, if the final .debug_frame section is +  // compressed it reduces the size since similar opcodes sequences are grouped. +  std::vector<const MethodDebugInfo*> sorted_method_infos; +  sorted_method_infos.reserve(method_infos.size()); +  for (size_t i = 0; i < method_infos.size(); i++) { +    sorted_method_infos.push_back(&method_infos[i]); +  } +  std::sort( +      sorted_method_infos.begin(), +      sorted_method_infos.end(), +      [](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) { +        ArrayRef<const uint8_t> l = lhs->compiled_method->GetCFIInfo(); +        ArrayRef<const uint8_t> r = rhs->compiled_method->GetCFIInfo(); +        return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); +      }); + +  // Write .eh_frame/.debug_frame section. +  auto* cfi_section = (format == dwarf::DW_DEBUG_FRAME_FORMAT +                       ? builder->GetDebugFrame() +                       : builder->GetEhFrame()); +  { +    cfi_section->Start(); +    const bool is64bit = Is64BitInstructionSet(builder->GetIsa()); +    const Elf_Addr text_address = builder->GetText()->Exists() +        ? builder->GetText()->GetAddress() +        : 0; +    const Elf_Addr cfi_address = cfi_section->GetAddress(); +    const Elf_Addr cie_address = cfi_address; +    Elf_Addr buffer_address = cfi_address; +    std::vector<uint8_t> buffer;  // Small temporary buffer. +    WriteCIE(builder->GetIsa(), format, &buffer); +    cfi_section->WriteFully(buffer.data(), buffer.size()); +    buffer_address += buffer.size(); +    buffer.clear(); +    for (const MethodDebugInfo* mi : sorted_method_infos) { +      if (!mi->deduped) {  // Only one FDE per unique address. +        ArrayRef<const uint8_t> opcodes = mi->compiled_method->GetCFIInfo(); +        if (!opcodes.empty()) { +          const Elf_Addr code_address = text_address + mi->low_pc; +          if (format == dwarf::DW_EH_FRAME_FORMAT) { +            binary_search_table.push_back( +                dchecked_integral_cast<uint32_t>(code_address)); +            binary_search_table.push_back( +                dchecked_integral_cast<uint32_t>(buffer_address)); +          } +          WriteFDE(is64bit, cfi_address, cie_address, +                   code_address, mi->high_pc - mi->low_pc, +                   opcodes, format, buffer_address, &buffer, +                   &patch_locations); +          cfi_section->WriteFully(buffer.data(), buffer.size()); +          buffer_address += buffer.size(); +          buffer.clear(); +        } +      } +    } +    cfi_section->End(); +  } + +  if (format == dwarf::DW_EH_FRAME_FORMAT) { +    auto* header_section = builder->GetEhFrameHdr(); +    header_section->Start(); +    uint32_t header_address = dchecked_integral_cast<int32_t>(header_section->GetAddress()); +    // Write .eh_frame_hdr section. +    std::vector<uint8_t> buffer; +    dwarf::Writer<> header(&buffer); +    header.PushUint8(1);  // Version. +    // Encoding of .eh_frame pointer - libunwind does not honor datarel here, +    // so we have to use pcrel which means relative to the pointer's location. +    header.PushUint8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4); +    // Encoding of binary search table size. +    header.PushUint8(dwarf::DW_EH_PE_udata4); +    // Encoding of binary search table addresses - libunwind supports only this +    // specific combination, which means relative to the start of .eh_frame_hdr. +    header.PushUint8(dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4); +    // .eh_frame pointer +    header.PushInt32(cfi_section->GetAddress() - (header_address + 4u)); +    // Binary search table size (number of entries). +    header.PushUint32(dchecked_integral_cast<uint32_t>(binary_search_table.size()/2)); +    header_section->WriteFully(buffer.data(), buffer.size()); +    // Binary search table. +    for (size_t i = 0; i < binary_search_table.size(); i++) { +      // Make addresses section-relative since we know the header address now. +      binary_search_table[i] -= header_address; +    } +    header_section->WriteFully(binary_search_table.data(), binary_search_table.size()); +    header_section->End(); +  } else { +    if (write_oat_patches) { +      builder->WritePatches(".debug_frame.oat_patches", +                            ArrayRef<const uintptr_t>(patch_locations)); +    } +  } +} + +}  // namespace debug +}  // namespace art + +#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_ + diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h new file mode 100644 index 0000000000..eed032f88d --- /dev/null +++ b/compiler/debug/elf_debug_info_writer.h @@ -0,0 +1,649 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_INFO_WRITER_H_ +#define ART_COMPILER_DEBUG_ELF_DEBUG_INFO_WRITER_H_ + +#include <map> +#include <unordered_set> +#include <vector> + +#include "debug/dwarf/debug_abbrev_writer.h" +#include "debug/dwarf/debug_info_entry_writer.h" +#include "debug/elf_compilation_unit.h" +#include "debug/elf_debug_loc_writer.h" +#include "debug/method_debug_info.h" +#include "dex_file-inl.h" +#include "dex_file.h" +#include "elf_builder.h" +#include "linear_alloc.h" +#include "mirror/array.h" +#include "mirror/class-inl.h" +#include "mirror/class.h" + +namespace art { +namespace debug { + +typedef std::vector<DexFile::LocalInfo> LocalInfos; + +static void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) { +  static_cast<LocalInfos*>(ctx)->push_back(entry); +} + +static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) { +  std::vector<const char*> names; +  if (mi->code_item != nullptr) { +    const uint8_t* stream = mi->dex_file->GetDebugInfoStream(mi->code_item); +    if (stream != nullptr) { +      DecodeUnsignedLeb128(&stream);  // line. +      uint32_t parameters_size = DecodeUnsignedLeb128(&stream); +      for (uint32_t i = 0; i < parameters_size; ++i) { +        uint32_t id = DecodeUnsignedLeb128P1(&stream); +        names.push_back(mi->dex_file->StringDataByIdx(id)); +      } +    } +  } +  return names; +} + +// Helper class to write .debug_info and its supporting sections. +template<typename ElfTypes> +class ElfDebugInfoWriter { +  using Elf_Addr = typename ElfTypes::Addr; + + public: +  explicit ElfDebugInfoWriter(ElfBuilder<ElfTypes>* builder) +      : builder_(builder), +        debug_abbrev_(&debug_abbrev_buffer_) { +  } + +  void Start() { +    builder_->GetDebugInfo()->Start(); +  } + +  void End(bool write_oat_patches) { +    builder_->GetDebugInfo()->End(); +    if (write_oat_patches) { +      builder_->WritePatches(".debug_info.oat_patches", +                             ArrayRef<const uintptr_t>(debug_info_patches_)); +    } +    builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_); +    if (!debug_loc_.empty()) { +      builder_->WriteSection(".debug_loc", &debug_loc_); +    } +    if (!debug_ranges_.empty()) { +      builder_->WriteSection(".debug_ranges", &debug_ranges_); +    } +  } + + private: +  ElfBuilder<ElfTypes>* builder_; +  std::vector<uintptr_t> debug_info_patches_; +  std::vector<uint8_t> debug_abbrev_buffer_; +  dwarf::DebugAbbrevWriter<> debug_abbrev_; +  std::vector<uint8_t> debug_loc_; +  std::vector<uint8_t> debug_ranges_; + +  std::unordered_set<const char*> defined_dex_classes_;  // For CHECKs only. + +  template<typename ElfTypes2> +  friend class ElfCompilationUnitWriter; +}; + +// Helper class to write one compilation unit. +// It holds helper methods and temporary state. +template<typename ElfTypes> +class ElfCompilationUnitWriter { +  using Elf_Addr = typename ElfTypes::Addr; + + public: +  explicit ElfCompilationUnitWriter(ElfDebugInfoWriter<ElfTypes>* owner) +    : owner_(owner), +      info_(Is64BitInstructionSet(owner_->builder_->GetIsa()), &owner->debug_abbrev_) { +  } + +  void Write(const ElfCompilationUnit& compilation_unit) { +    CHECK(!compilation_unit.methods.empty()); +    const Elf_Addr text_address = owner_->builder_->GetText()->Exists() +        ? owner_->builder_->GetText()->GetAddress() +        : 0; +    const uintptr_t cu_size = compilation_unit.high_pc - compilation_unit.low_pc; +    using namespace dwarf;  // NOLINT. For easy access to DWARF constants. + +    info_.StartTag(DW_TAG_compile_unit); +    info_.WriteString(DW_AT_producer, "Android dex2oat"); +    info_.WriteData1(DW_AT_language, DW_LANG_Java); +    info_.WriteString(DW_AT_comp_dir, "$JAVA_SRC_ROOT"); +    info_.WriteAddr(DW_AT_low_pc, text_address + compilation_unit.low_pc); +    info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size)); +    info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset); + +    const char* last_dex_class_desc = nullptr; +    for (auto mi : compilation_unit.methods) { +      const DexFile* dex = mi->dex_file; +      const DexFile::CodeItem* dex_code = mi->code_item; +      const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index); +      const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method); +      const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto); +      const char* dex_class_desc = dex->GetMethodDeclaringClassDescriptor(dex_method); +      const bool is_static = (mi->access_flags & kAccStatic) != 0; + +      // Enclose the method in correct class definition. +      if (last_dex_class_desc != dex_class_desc) { +        if (last_dex_class_desc != nullptr) { +          EndClassTag(); +        } +        // Write reference tag for the class we are about to declare. +        size_t reference_tag_offset = info_.StartTag(DW_TAG_reference_type); +        type_cache_.emplace(std::string(dex_class_desc), reference_tag_offset); +        size_t type_attrib_offset = info_.size(); +        info_.WriteRef4(DW_AT_type, 0); +        info_.EndTag(); +        // Declare the class that owns this method. +        size_t class_offset = StartClassTag(dex_class_desc); +        info_.UpdateUint32(type_attrib_offset, class_offset); +        info_.WriteFlagPresent(DW_AT_declaration); +        // Check that each class is defined only once. +        bool unique = owner_->defined_dex_classes_.insert(dex_class_desc).second; +        CHECK(unique) << "Redefinition of " << dex_class_desc; +        last_dex_class_desc = dex_class_desc; +      } + +      int start_depth = info_.Depth(); +      info_.StartTag(DW_TAG_subprogram); +      WriteName(dex->GetMethodName(dex_method)); +      info_.WriteAddr(DW_AT_low_pc, text_address + mi->low_pc); +      info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(mi->high_pc-mi->low_pc)); +      std::vector<uint8_t> expr_buffer; +      Expression expr(&expr_buffer); +      expr.WriteOpCallFrameCfa(); +      info_.WriteExprLoc(DW_AT_frame_base, expr); +      WriteLazyType(dex->GetReturnTypeDescriptor(dex_proto)); + +      // Write parameters. DecodeDebugLocalInfo returns them as well, but it does not +      // guarantee order or uniqueness so it is safer to iterate over them manually. +      // DecodeDebugLocalInfo might not also be available if there is no debug info. +      std::vector<const char*> param_names = GetParamNames(mi); +      uint32_t arg_reg = 0; +      if (!is_static) { +        info_.StartTag(DW_TAG_formal_parameter); +        WriteName("this"); +        info_.WriteFlagPresent(DW_AT_artificial); +        WriteLazyType(dex_class_desc); +        if (dex_code != nullptr) { +          // Write the stack location of the parameter. +          const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg; +          const bool is64bitValue = false; +          WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc); +        } +        arg_reg++; +        info_.EndTag(); +      } +      if (dex_params != nullptr) { +        for (uint32_t i = 0; i < dex_params->Size(); ++i) { +          info_.StartTag(DW_TAG_formal_parameter); +          // Parameter names may not be always available. +          if (i < param_names.size()) { +            WriteName(param_names[i]); +          } +          // Write the type. +          const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_); +          WriteLazyType(type_desc); +          const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J'; +          if (dex_code != nullptr) { +            // Write the stack location of the parameter. +            const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg; +            WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc); +          } +          arg_reg += is64bitValue ? 2 : 1; +          info_.EndTag(); +        } +        if (dex_code != nullptr) { +          DCHECK_EQ(arg_reg, dex_code->ins_size_); +        } +      } + +      // Write local variables. +      LocalInfos local_infos; +      if (dex->DecodeDebugLocalInfo(dex_code, +                                    is_static, +                                    mi->dex_method_index, +                                    LocalInfoCallback, +                                    &local_infos)) { +        for (const DexFile::LocalInfo& var : local_infos) { +          if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) { +            info_.StartTag(DW_TAG_variable); +            WriteName(var.name_); +            WriteLazyType(var.descriptor_); +            bool is64bitValue = var.descriptor_[0] == 'D' || var.descriptor_[0] == 'J'; +            WriteRegLocation(mi, var.reg_, is64bitValue, compilation_unit.low_pc, +                             var.start_address_, var.end_address_); +            info_.EndTag(); +          } +        } +      } + +      info_.EndTag(); +      CHECK_EQ(info_.Depth(), start_depth);  // Balanced start/end. +    } +    if (last_dex_class_desc != nullptr) { +      EndClassTag(); +    } +    FinishLazyTypes(); +    CloseNamespacesAboveDepth(0); +    info_.EndTag();  // DW_TAG_compile_unit +    CHECK_EQ(info_.Depth(), 0); +    std::vector<uint8_t> buffer; +    buffer.reserve(info_.data()->size() + KB); +    const size_t offset = owner_->builder_->GetDebugInfo()->GetSize(); +    // All compilation units share single table which is at the start of .debug_abbrev. +    const size_t debug_abbrev_offset = 0; +    WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_); +    owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size()); +  } + +  void Write(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) { +    using namespace dwarf;  // NOLINT. For easy access to DWARF constants. + +    info_.StartTag(DW_TAG_compile_unit); +    info_.WriteString(DW_AT_producer, "Android dex2oat"); +    info_.WriteData1(DW_AT_language, DW_LANG_Java); + +    // Base class references to be patched at the end. +    std::map<size_t, mirror::Class*> base_class_references; + +    // Already written declarations or definitions. +    std::map<mirror::Class*, size_t> class_declarations; + +    std::vector<uint8_t> expr_buffer; +    for (mirror::Class* type : types) { +      if (type->IsPrimitive()) { +        // For primitive types the definition and the declaration is the same. +        if (type->GetPrimitiveType() != Primitive::kPrimVoid) { +          WriteTypeDeclaration(type->GetDescriptor(nullptr)); +        } +      } else if (type->IsArrayClass()) { +        mirror::Class* element_type = type->GetComponentType(); +        uint32_t component_size = type->GetComponentSize(); +        uint32_t data_offset = mirror::Array::DataOffset(component_size).Uint32Value(); +        uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value(); + +        CloseNamespacesAboveDepth(0);  // Declare in root namespace. +        info_.StartTag(DW_TAG_array_type); +        std::string descriptor_string; +        WriteLazyType(element_type->GetDescriptor(&descriptor_string)); +        WriteLinkageName(type); +        info_.WriteUdata(DW_AT_data_member_location, data_offset); +        info_.StartTag(DW_TAG_subrange_type); +        Expression count_expr(&expr_buffer); +        count_expr.WriteOpPushObjectAddress(); +        count_expr.WriteOpPlusUconst(length_offset); +        count_expr.WriteOpDerefSize(4);  // Array length is always 32-bit wide. +        info_.WriteExprLoc(DW_AT_count, count_expr); +        info_.EndTag();  // DW_TAG_subrange_type. +        info_.EndTag();  // DW_TAG_array_type. +      } else if (type->IsInterface()) { +        // Skip.  Variables cannot have an interface as a dynamic type. +        // We do not expose the interface information to the debugger in any way. +      } else { +        std::string descriptor_string; +        const char* desc = type->GetDescriptor(&descriptor_string); +        size_t class_offset = StartClassTag(desc); +        class_declarations.emplace(type, class_offset); + +        if (!type->IsVariableSize()) { +          info_.WriteUdata(DW_AT_byte_size, type->GetObjectSize()); +        } + +        WriteLinkageName(type); + +        if (type->IsObjectClass()) { +          // Generate artificial member which is used to get the dynamic type of variable. +          // The run-time value of this field will correspond to linkage name of some type. +          // We need to do it only once in j.l.Object since all other types inherit it. +          info_.StartTag(DW_TAG_member); +          WriteName(".dynamic_type"); +          WriteLazyType(sizeof(uintptr_t) == 8 ? "J" : "I"); +          info_.WriteFlagPresent(DW_AT_artificial); +          // Create DWARF expression to get the value of the methods_ field. +          Expression expr(&expr_buffer); +          // The address of the object has been implicitly pushed on the stack. +          // Dereference the klass_ field of Object (32-bit; possibly poisoned). +          DCHECK_EQ(type->ClassOffset().Uint32Value(), 0u); +          DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Class>), 4u); +          expr.WriteOpDerefSize(4); +          if (kPoisonHeapReferences) { +            expr.WriteOpNeg(); +            // DWARF stack is pointer sized. Ensure that the high bits are clear. +            expr.WriteOpConstu(0xFFFFFFFF); +            expr.WriteOpAnd(); +          } +          // Add offset to the methods_ field. +          expr.WriteOpPlusUconst(mirror::Class::MethodsOffset().Uint32Value()); +          // Top of stack holds the location of the field now. +          info_.WriteExprLoc(DW_AT_data_member_location, expr); +          info_.EndTag();  // DW_TAG_member. +        } + +        // Base class. +        mirror::Class* base_class = type->GetSuperClass(); +        if (base_class != nullptr) { +          info_.StartTag(DW_TAG_inheritance); +          base_class_references.emplace(info_.size(), base_class); +          info_.WriteRef4(DW_AT_type, 0); +          info_.WriteUdata(DW_AT_data_member_location, 0); +          info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public); +          info_.EndTag();  // DW_TAG_inheritance. +        } + +        // Member variables. +        for (uint32_t i = 0, count = type->NumInstanceFields(); i < count; ++i) { +          ArtField* field = type->GetInstanceField(i); +          info_.StartTag(DW_TAG_member); +          WriteName(field->GetName()); +          WriteLazyType(field->GetTypeDescriptor()); +          info_.WriteUdata(DW_AT_data_member_location, field->GetOffset().Uint32Value()); +          uint32_t access_flags = field->GetAccessFlags(); +          if (access_flags & kAccPublic) { +            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public); +          } else if (access_flags & kAccProtected) { +            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_protected); +          } else if (access_flags & kAccPrivate) { +            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private); +          } +          info_.EndTag();  // DW_TAG_member. +        } + +        if (type->IsStringClass()) { +          // Emit debug info about an artifical class member for java.lang.String which represents +          // the first element of the data stored in a string instance. Consumers of the debug +          // info will be able to read the content of java.lang.String based on the count (real +          // field) and based on the location of this data member. +          info_.StartTag(DW_TAG_member); +          WriteName("value"); +          // We don't support fields with C like array types so we just say its type is java char. +          WriteLazyType("C");  // char. +          info_.WriteUdata(DW_AT_data_member_location, +                           mirror::String::ValueOffset().Uint32Value()); +          info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private); +          info_.EndTag();  // DW_TAG_member. +        } + +        EndClassTag(); +      } +    } + +    // Write base class declarations. +    for (const auto& base_class_reference : base_class_references) { +      size_t reference_offset = base_class_reference.first; +      mirror::Class* base_class = base_class_reference.second; +      const auto& it = class_declarations.find(base_class); +      if (it != class_declarations.end()) { +        info_.UpdateUint32(reference_offset, it->second); +      } else { +        // Declare base class.  We can not use the standard WriteLazyType +        // since we want to avoid the DW_TAG_reference_tag wrapping. +        std::string tmp_storage; +        const char* base_class_desc = base_class->GetDescriptor(&tmp_storage); +        size_t base_class_declaration_offset = StartClassTag(base_class_desc); +        info_.WriteFlagPresent(DW_AT_declaration); +        WriteLinkageName(base_class); +        EndClassTag(); +        class_declarations.emplace(base_class, base_class_declaration_offset); +        info_.UpdateUint32(reference_offset, base_class_declaration_offset); +      } +    } + +    FinishLazyTypes(); +    CloseNamespacesAboveDepth(0); +    info_.EndTag();  // DW_TAG_compile_unit. +    CHECK_EQ(info_.Depth(), 0); +    std::vector<uint8_t> buffer; +    buffer.reserve(info_.data()->size() + KB); +    const size_t offset = owner_->builder_->GetDebugInfo()->GetSize(); +    // All compilation units share single table which is at the start of .debug_abbrev. +    const size_t debug_abbrev_offset = 0; +    WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_); +    owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size()); +  } + +  // Write table into .debug_loc which describes location of dex register. +  // The dex register might be valid only at some points and it might +  // move between machine registers and stack. +  void WriteRegLocation(const MethodDebugInfo* method_info, +                        uint16_t vreg, +                        bool is64bitValue, +                        uint32_t compilation_unit_low_pc, +                        uint32_t dex_pc_low = 0, +                        uint32_t dex_pc_high = 0xFFFFFFFF) { +    WriteDebugLocEntry(method_info, +                       vreg, +                       is64bitValue, +                       compilation_unit_low_pc, +                       dex_pc_low, +                       dex_pc_high, +                       owner_->builder_->GetIsa(), +                       &info_, +                       &owner_->debug_loc_, +                       &owner_->debug_ranges_); +  } + +  // Linkage name uniquely identifies type. +  // It is used to determine the dynamic type of objects. +  // We use the methods_ field of class since it is unique and it is not moved by the GC. +  void WriteLinkageName(mirror::Class* type) SHARED_REQUIRES(Locks::mutator_lock_) { +    auto* methods_ptr = type->GetMethodsPtr(); +    if (methods_ptr == nullptr) { +      // Some types might have no methods.  Allocate empty array instead. +      LinearAlloc* allocator = Runtime::Current()->GetLinearAlloc(); +      void* storage = allocator->Alloc(Thread::Current(), sizeof(LengthPrefixedArray<ArtMethod>)); +      methods_ptr = new (storage) LengthPrefixedArray<ArtMethod>(0); +      type->SetMethodsPtr(methods_ptr, 0, 0); +      DCHECK(type->GetMethodsPtr() != nullptr); +    } +    char name[32]; +    snprintf(name, sizeof(name), "0x%" PRIXPTR, reinterpret_cast<uintptr_t>(methods_ptr)); +    info_.WriteString(dwarf::DW_AT_linkage_name, name); +  } + +  // Some types are difficult to define as we go since they need +  // to be enclosed in the right set of namespaces. Therefore we +  // just define all types lazily at the end of compilation unit. +  void WriteLazyType(const char* type_descriptor) { +    if (type_descriptor != nullptr && type_descriptor[0] != 'V') { +      lazy_types_.emplace(std::string(type_descriptor), info_.size()); +      info_.WriteRef4(dwarf::DW_AT_type, 0); +    } +  } + +  void FinishLazyTypes() { +    for (const auto& lazy_type : lazy_types_) { +      info_.UpdateUint32(lazy_type.second, WriteTypeDeclaration(lazy_type.first)); +    } +    lazy_types_.clear(); +  } + + private: +  void WriteName(const char* name) { +    if (name != nullptr) { +      info_.WriteString(dwarf::DW_AT_name, name); +    } +  } + +  // Convert dex type descriptor to DWARF. +  // Returns offset in the compilation unit. +  size_t WriteTypeDeclaration(const std::string& desc) { +    using namespace dwarf;  // NOLINT. For easy access to DWARF constants. + +    DCHECK(!desc.empty()); +    const auto& it = type_cache_.find(desc); +    if (it != type_cache_.end()) { +      return it->second; +    } + +    size_t offset; +    if (desc[0] == 'L') { +      // Class type. For example: Lpackage/name; +      size_t class_offset = StartClassTag(desc.c_str()); +      info_.WriteFlagPresent(DW_AT_declaration); +      EndClassTag(); +      // Reference to the class type. +      offset = info_.StartTag(DW_TAG_reference_type); +      info_.WriteRef(DW_AT_type, class_offset); +      info_.EndTag(); +    } else if (desc[0] == '[') { +      // Array type. +      size_t element_type = WriteTypeDeclaration(desc.substr(1)); +      CloseNamespacesAboveDepth(0);  // Declare in root namespace. +      size_t array_type = info_.StartTag(DW_TAG_array_type); +      info_.WriteFlagPresent(DW_AT_declaration); +      info_.WriteRef(DW_AT_type, element_type); +      info_.EndTag(); +      offset = info_.StartTag(DW_TAG_reference_type); +      info_.WriteRef4(DW_AT_type, array_type); +      info_.EndTag(); +    } else { +      // Primitive types. +      DCHECK_EQ(desc.size(), 1u); + +      const char* name; +      uint32_t encoding; +      uint32_t byte_size; +      switch (desc[0]) { +      case 'B': +        name = "byte"; +        encoding = DW_ATE_signed; +        byte_size = 1; +        break; +      case 'C': +        name = "char"; +        encoding = DW_ATE_UTF; +        byte_size = 2; +        break; +      case 'D': +        name = "double"; +        encoding = DW_ATE_float; +        byte_size = 8; +        break; +      case 'F': +        name = "float"; +        encoding = DW_ATE_float; +        byte_size = 4; +        break; +      case 'I': +        name = "int"; +        encoding = DW_ATE_signed; +        byte_size = 4; +        break; +      case 'J': +        name = "long"; +        encoding = DW_ATE_signed; +        byte_size = 8; +        break; +      case 'S': +        name = "short"; +        encoding = DW_ATE_signed; +        byte_size = 2; +        break; +      case 'Z': +        name = "boolean"; +        encoding = DW_ATE_boolean; +        byte_size = 1; +        break; +      case 'V': +        LOG(FATAL) << "Void type should not be encoded"; +        UNREACHABLE(); +      default: +        LOG(FATAL) << "Unknown dex type descriptor: \"" << desc << "\""; +        UNREACHABLE(); +      } +      CloseNamespacesAboveDepth(0);  // Declare in root namespace. +      offset = info_.StartTag(DW_TAG_base_type); +      WriteName(name); +      info_.WriteData1(DW_AT_encoding, encoding); +      info_.WriteData1(DW_AT_byte_size, byte_size); +      info_.EndTag(); +    } + +    type_cache_.emplace(desc, offset); +    return offset; +  } + +  // Start DW_TAG_class_type tag nested in DW_TAG_namespace tags. +  // Returns offset of the class tag in the compilation unit. +  size_t StartClassTag(const char* desc) { +    std::string name = SetNamespaceForClass(desc); +    size_t offset = info_.StartTag(dwarf::DW_TAG_class_type); +    WriteName(name.c_str()); +    return offset; +  } + +  void EndClassTag() { +    info_.EndTag(); +  } + +  // Set the current namespace nesting to one required by the given class. +  // Returns the class name with namespaces, 'L', and ';' stripped. +  std::string SetNamespaceForClass(const char* desc) { +    DCHECK(desc != nullptr && desc[0] == 'L'); +    desc++;  // Skip the initial 'L'. +    size_t depth = 0; +    for (const char* end; (end = strchr(desc, '/')) != nullptr; desc = end + 1, ++depth) { +      // Check whether the name at this depth is already what we need. +      if (depth < current_namespace_.size()) { +        const std::string& name = current_namespace_[depth]; +        if (name.compare(0, name.size(), desc, end - desc) == 0) { +          continue; +        } +      } +      // Otherwise we need to open a new namespace tag at this depth. +      CloseNamespacesAboveDepth(depth); +      info_.StartTag(dwarf::DW_TAG_namespace); +      std::string name(desc, end - desc); +      WriteName(name.c_str()); +      current_namespace_.push_back(std::move(name)); +    } +    CloseNamespacesAboveDepth(depth); +    return std::string(desc, strchr(desc, ';') - desc); +  } + +  // Close namespace tags to reach the given nesting depth. +  void CloseNamespacesAboveDepth(size_t depth) { +    DCHECK_LE(depth, current_namespace_.size()); +    while (current_namespace_.size() > depth) { +      info_.EndTag(); +      current_namespace_.pop_back(); +    } +  } + +  // For access to the ELF sections. +  ElfDebugInfoWriter<ElfTypes>* owner_; +  // Temporary buffer to create and store the entries. +  dwarf::DebugInfoEntryWriter<> info_; +  // Cache of already translated type descriptors. +  std::map<std::string, size_t> type_cache_;  // type_desc -> definition_offset. +  // 32-bit references which need to be resolved to a type later. +  // Given type may be used multiple times.  Therefore we need a multimap. +  std::multimap<std::string, size_t> lazy_types_;  // type_desc -> patch_offset. +  // The current set of open namespace tags which are active and not closed yet. +  std::vector<std::string> current_namespace_; +}; + +}  // namespace debug +}  // namespace art + +#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_INFO_WRITER_H_ + diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h new file mode 100644 index 0000000000..ac0f4ca21d --- /dev/null +++ b/compiler/debug/elf_debug_line_writer.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_LINE_WRITER_H_ +#define ART_COMPILER_DEBUG_ELF_DEBUG_LINE_WRITER_H_ + +#include <vector> + +#include "compiled_method.h" +#include "debug/dwarf/debug_line_opcode_writer.h" +#include "debug/dwarf/headers.h" +#include "debug/elf_compilation_unit.h" +#include "dex_file-inl.h" +#include "dex_file.h" +#include "elf_builder.h" +#include "stack_map.h" + +namespace art { +namespace debug { + +typedef std::vector<DexFile::PositionInfo> PositionInfos; + +static bool PositionInfoCallback(void* ctx, const DexFile::PositionInfo& entry) { +  static_cast<PositionInfos*>(ctx)->push_back(entry); +  return false; +} + +template<typename ElfTypes> +class ElfDebugLineWriter { +  using Elf_Addr = typename ElfTypes::Addr; + + public: +  explicit ElfDebugLineWriter(ElfBuilder<ElfTypes>* builder) : builder_(builder) { +  } + +  void Start() { +    builder_->GetDebugLine()->Start(); +  } + +  // Write line table for given set of methods. +  // Returns the number of bytes written. +  size_t WriteCompilationUnit(ElfCompilationUnit& compilation_unit) { +    const bool is64bit = Is64BitInstructionSet(builder_->GetIsa()); +    const Elf_Addr text_address = builder_->GetText()->Exists() +        ? builder_->GetText()->GetAddress() +        : 0; + +    compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetSize(); + +    std::vector<dwarf::FileEntry> files; +    std::unordered_map<std::string, size_t> files_map; +    std::vector<std::string> directories; +    std::unordered_map<std::string, size_t> directories_map; +    int code_factor_bits_ = 0; +    int dwarf_isa = -1; +    switch (builder_->GetIsa()) { +      case kArm:  // arm actually means thumb2. +      case kThumb2: +        code_factor_bits_ = 1;  // 16-bit instuctions +        dwarf_isa = 1;  // DW_ISA_ARM_thumb. +        break; +      case kArm64: +      case kMips: +      case kMips64: +        code_factor_bits_ = 2;  // 32-bit instructions +        break; +      case kNone: +      case kX86: +      case kX86_64: +        break; +    } +    dwarf::DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits_); +    for (const MethodDebugInfo* mi : compilation_unit.methods) { +      // Ignore function if we have already generated line table for the same address. +      // It would confuse the debugger and the DWARF specification forbids it. +      if (mi->deduped) { +        continue; +      } + +      ArrayRef<const SrcMapElem> src_mapping_table; +      std::vector<SrcMapElem> src_mapping_table_from_stack_maps; +      if (mi->IsFromOptimizingCompiler()) { +        // Use stack maps to create mapping table from pc to dex. +        const CodeInfo code_info(mi->compiled_method->GetVmapTable().data()); +        const StackMapEncoding encoding = code_info.ExtractEncoding(); +        for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) { +          StackMap stack_map = code_info.GetStackMapAt(s, encoding); +          DCHECK(stack_map.IsValid()); +          // Emit only locations where we have local-variable information. +          // In particular, skip mappings inside the prologue. +          if (stack_map.HasDexRegisterMap(encoding)) { +            const uint32_t pc = stack_map.GetNativePcOffset(encoding); +            const int32_t dex = stack_map.GetDexPc(encoding); +            src_mapping_table_from_stack_maps.push_back({pc, dex}); +          } +        } +        std::sort(src_mapping_table_from_stack_maps.begin(), +                  src_mapping_table_from_stack_maps.end()); +        src_mapping_table = ArrayRef<const SrcMapElem>(src_mapping_table_from_stack_maps); +      } else { +        // Use the mapping table provided by the quick compiler. +        src_mapping_table = mi->compiled_method->GetSrcMappingTable(); +      } + +      if (src_mapping_table.empty()) { +        continue; +      } + +      Elf_Addr method_address = text_address + mi->low_pc; + +      PositionInfos position_infos; +      const DexFile* dex = mi->dex_file; +      if (!dex->DecodeDebugPositionInfo(mi->code_item, PositionInfoCallback, &position_infos)) { +        continue; +      } + +      if (position_infos.empty()) { +        continue; +      } + +      opcodes.SetAddress(method_address); +      if (dwarf_isa != -1) { +        opcodes.SetISA(dwarf_isa); +      } + +      // Get and deduplicate directory and filename. +      int file_index = 0;  // 0 - primary source file of the compilation. +      auto& dex_class_def = dex->GetClassDef(mi->class_def_index); +      const char* source_file = dex->GetSourceFile(dex_class_def); +      if (source_file != nullptr) { +        std::string file_name(source_file); +        size_t file_name_slash = file_name.find_last_of('/'); +        std::string class_name(dex->GetClassDescriptor(dex_class_def)); +        size_t class_name_slash = class_name.find_last_of('/'); +        std::string full_path(file_name); + +        // Guess directory from package name. +        int directory_index = 0;  // 0 - current directory of the compilation. +        if (file_name_slash == std::string::npos &&  // Just filename. +            class_name.front() == 'L' &&  // Type descriptor for a class. +            class_name_slash != std::string::npos) {  // Has package name. +          std::string package_name = class_name.substr(1, class_name_slash - 1); +          auto it = directories_map.find(package_name); +          if (it == directories_map.end()) { +            directory_index = 1 + directories.size(); +            directories_map.emplace(package_name, directory_index); +            directories.push_back(package_name); +          } else { +            directory_index = it->second; +          } +          full_path = package_name + "/" + file_name; +        } + +        // Add file entry. +        auto it2 = files_map.find(full_path); +        if (it2 == files_map.end()) { +          file_index = 1 + files.size(); +          files_map.emplace(full_path, file_index); +          files.push_back(dwarf::FileEntry { +            file_name, +            directory_index, +            0,  // Modification time - NA. +            0,  // File size - NA. +          }); +        } else { +          file_index = it2->second; +        } +      } +      opcodes.SetFile(file_index); + +      // Generate mapping opcodes from PC to Java lines. +      if (file_index != 0) { +        bool first = true; +        for (SrcMapElem pc2dex : src_mapping_table) { +          uint32_t pc = pc2dex.from_; +          int dex_pc = pc2dex.to_; +          // Find mapping with address with is greater than our dex pc; then go back one step. +          auto ub = std::upper_bound(position_infos.begin(), position_infos.end(), dex_pc, +              [](uint32_t address, const DexFile::PositionInfo& entry) { +                  return address < entry.address_; +              }); +          if (ub != position_infos.begin()) { +            int line = (--ub)->line_; +            if (first) { +              first = false; +              if (pc > 0) { +                // Assume that any preceding code is prologue. +                int first_line = position_infos.front().line_; +                // Prologue is not a sensible place for a breakpoint. +                opcodes.NegateStmt(); +                opcodes.AddRow(method_address, first_line); +                opcodes.NegateStmt(); +                opcodes.SetPrologueEnd(); +              } +              opcodes.AddRow(method_address + pc, line); +            } else if (line != opcodes.CurrentLine()) { +              opcodes.AddRow(method_address + pc, line); +            } +          } +        } +      } else { +        // line 0 - instruction cannot be attributed to any source line. +        opcodes.AddRow(method_address, 0); +      } + +      opcodes.AdvancePC(text_address + mi->high_pc); +      opcodes.EndSequence(); +    } +    std::vector<uint8_t> buffer; +    buffer.reserve(opcodes.data()->size() + KB); +    size_t offset = builder_->GetDebugLine()->GetSize(); +    WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches_); +    builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size()); +    return buffer.size(); +  } + +  void End(bool write_oat_patches) { +    builder_->GetDebugLine()->End(); +    if (write_oat_patches) { +      builder_->WritePatches(".debug_line.oat_patches", +                             ArrayRef<const uintptr_t>(debug_line_patches_)); +    } +  } + + private: +  ElfBuilder<ElfTypes>* builder_; +  std::vector<uintptr_t> debug_line_patches_; +}; + +}  // namespace debug +}  // namespace art + +#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_LINE_WRITER_H_ + diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h new file mode 100644 index 0000000000..fd7f949c5d --- /dev/null +++ b/compiler/debug/elf_debug_loc_writer.h @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_ +#define ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_ + +#include <map> + +#include "arch/instruction_set.h" +#include "compiled_method.h" +#include "debug/dwarf/debug_info_entry_writer.h" +#include "debug/dwarf/register.h" +#include "debug/method_debug_info.h" +#include "stack_map.h" + +namespace art { +namespace debug { +using Reg = dwarf::Reg; + +static Reg GetDwarfCoreReg(InstructionSet isa, int machine_reg) { +  switch (isa) { +    case kArm: +    case kThumb2: +      return Reg::ArmCore(machine_reg); +    case kArm64: +      return Reg::Arm64Core(machine_reg); +    case kX86: +      return Reg::X86Core(machine_reg); +    case kX86_64: +      return Reg::X86_64Core(machine_reg); +    case kMips: +      return Reg::MipsCore(machine_reg); +    case kMips64: +      return Reg::Mips64Core(machine_reg); +    case kNone: +      LOG(FATAL) << "No instruction set"; +  } +  UNREACHABLE(); +} + +static Reg GetDwarfFpReg(InstructionSet isa, int machine_reg) { +  switch (isa) { +    case kArm: +    case kThumb2: +      return Reg::ArmFp(machine_reg); +    case kArm64: +      return Reg::Arm64Fp(machine_reg); +    case kX86: +      return Reg::X86Fp(machine_reg); +    case kX86_64: +      return Reg::X86_64Fp(machine_reg); +    case kMips: +      return Reg::MipsFp(machine_reg); +    case kMips64: +      return Reg::Mips64Fp(machine_reg); +    case kNone: +      LOG(FATAL) << "No instruction set"; +  } +  UNREACHABLE(); +} + +struct VariableLocation { +  uint32_t low_pc; +  uint32_t high_pc; +  DexRegisterLocation reg_lo;  // May be None if the location is unknown. +  DexRegisterLocation reg_hi;  // Most significant bits of 64-bit value. +}; + +// Get the location of given dex register (e.g. stack or machine register). +// Note that the location might be different based on the current pc. +// The result will cover all ranges where the variable is in scope. +std::vector<VariableLocation> GetVariableLocations(const MethodDebugInfo* method_info, +                                                   uint16_t vreg, +                                                   bool is64bitValue, +                                                   uint32_t dex_pc_low, +                                                   uint32_t dex_pc_high) { +  std::vector<VariableLocation> variable_locations; + +  // Get stack maps sorted by pc (they might not be sorted internally). +  const CodeInfo code_info(method_info->compiled_method->GetVmapTable().data()); +  const StackMapEncoding encoding = code_info.ExtractEncoding(); +  std::map<uint32_t, StackMap> stack_maps; +  for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) { +    StackMap stack_map = code_info.GetStackMapAt(s, encoding); +    DCHECK(stack_map.IsValid()); +    const uint32_t low_pc = method_info->low_pc + stack_map.GetNativePcOffset(encoding); +    DCHECK_LE(low_pc, method_info->high_pc); +    stack_maps.emplace(low_pc, stack_map); +  } + +  // Create entries for the requested register based on stack map data. +  for (auto it = stack_maps.begin(); it != stack_maps.end(); it++) { +    const StackMap& stack_map = it->second; +    const uint32_t low_pc = it->first; +    auto next_it = it; +    next_it++; +    const uint32_t high_pc = next_it != stack_maps.end() ? next_it->first +                                                         : method_info->high_pc; +    DCHECK_LE(low_pc, high_pc); +    if (low_pc == high_pc) { +      continue;  // Ignore if the address range is empty. +    } + +    // Check that the stack map is in the requested range. +    uint32_t dex_pc = stack_map.GetDexPc(encoding); +    if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) { +      continue; +    } + +    // Find the location of the dex register. +    DexRegisterLocation reg_lo = DexRegisterLocation::None(); +    DexRegisterLocation reg_hi = DexRegisterLocation::None(); +    if (stack_map.HasDexRegisterMap(encoding)) { +      DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf( +          stack_map, encoding, method_info->code_item->registers_size_); +      reg_lo = dex_register_map.GetDexRegisterLocation( +          vreg, method_info->code_item->registers_size_, code_info, encoding); +      if (is64bitValue) { +        reg_hi = dex_register_map.GetDexRegisterLocation( +            vreg + 1, method_info->code_item->registers_size_, code_info, encoding); +      } +    } + +    // Add location entry for this address range. +    if (!variable_locations.empty() && +        variable_locations.back().reg_lo == reg_lo && +        variable_locations.back().reg_hi == reg_hi && +        variable_locations.back().high_pc == low_pc) { +      // Merge with the previous entry (extend its range). +      variable_locations.back().high_pc = high_pc; +    } else { +      variable_locations.push_back({low_pc, high_pc, reg_lo, reg_hi}); +    } +  } + +  return variable_locations; +} + +// Write table into .debug_loc which describes location of dex register. +// The dex register might be valid only at some points and it might +// move between machine registers and stack. +static void WriteDebugLocEntry(const MethodDebugInfo* method_info, +                               uint16_t vreg, +                               bool is64bitValue, +                               uint32_t compilation_unit_low_pc, +                               uint32_t dex_pc_low, +                               uint32_t dex_pc_high, +                               InstructionSet isa, +                               dwarf::DebugInfoEntryWriter<>* debug_info, +                               std::vector<uint8_t>* debug_loc_buffer, +                               std::vector<uint8_t>* debug_ranges_buffer) { +  using Kind = DexRegisterLocation::Kind; +  if (!method_info->IsFromOptimizingCompiler()) { +    return; +  } + +  dwarf::Writer<> debug_loc(debug_loc_buffer); +  dwarf::Writer<> debug_ranges(debug_ranges_buffer); +  debug_info->WriteSecOffset(dwarf::DW_AT_location, debug_loc.size()); +  debug_info->WriteSecOffset(dwarf::DW_AT_start_scope, debug_ranges.size()); + +  std::vector<VariableLocation> variable_locations = GetVariableLocations( +      method_info, +      vreg, +      is64bitValue, +      dex_pc_low, +      dex_pc_high); + +  // Write .debug_loc entries. +  const bool is64bit = Is64BitInstructionSet(isa); +  std::vector<uint8_t> expr_buffer; +  for (const VariableLocation& variable_location : variable_locations) { +    // Translate dex register location to DWARF expression. +    // Note that 64-bit value might be split to two distinct locations. +    // (for example, two 32-bit machine registers, or even stack and register) +    dwarf::Expression expr(&expr_buffer); +    DexRegisterLocation reg_lo = variable_location.reg_lo; +    DexRegisterLocation reg_hi = variable_location.reg_hi; +    for (int piece = 0; piece < (is64bitValue ? 2 : 1); piece++) { +      DexRegisterLocation reg_loc = (piece == 0 ? reg_lo : reg_hi); +      const Kind kind = reg_loc.GetKind(); +      const int32_t value = reg_loc.GetValue(); +      if (kind == Kind::kInStack) { +        const size_t frame_size = method_info->compiled_method->GetFrameSizeInBytes(); +        // The stack offset is relative to SP. Make it relative to CFA. +        expr.WriteOpFbreg(value - frame_size); +        if (piece == 0 && reg_hi.GetKind() == Kind::kInStack && +            reg_hi.GetValue() == value + 4) { +          break;  // the high word is correctly implied by the low word. +        } +      } else if (kind == Kind::kInRegister) { +        expr.WriteOpReg(GetDwarfCoreReg(isa, value).num()); +        if (piece == 0 && reg_hi.GetKind() == Kind::kInRegisterHigh && +            reg_hi.GetValue() == value) { +          break;  // the high word is correctly implied by the low word. +        } +      } else if (kind == Kind::kInFpuRegister) { +        if ((isa == kArm || isa == kThumb2) && +            piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegister && +            reg_hi.GetValue() == value + 1 && value % 2 == 0) { +          // Translate S register pair to D register (e.g. S4+S5 to D2). +          expr.WriteOpReg(Reg::ArmDp(value / 2).num()); +          break; +        } +        expr.WriteOpReg(GetDwarfFpReg(isa, value).num()); +        if (piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegisterHigh && +            reg_hi.GetValue() == reg_lo.GetValue()) { +          break;  // the high word is correctly implied by the low word. +        } +      } else if (kind == Kind::kConstant) { +        expr.WriteOpConsts(value); +        expr.WriteOpStackValue(); +      } else if (kind == Kind::kNone) { +        break; +      } else { +        // kInStackLargeOffset and kConstantLargeValue are hidden by GetKind(). +        // kInRegisterHigh and kInFpuRegisterHigh should be handled by +        // the special cases above and they should not occur alone. +        LOG(ERROR) << "Unexpected register location kind: " +                   << DexRegisterLocation::PrettyDescriptor(kind); +        break; +      } +      if (is64bitValue) { +        // Write the marker which is needed by split 64-bit values. +        // This code is skipped by the special cases. +        expr.WriteOpPiece(4); +      } +    } + +    if (expr.size() > 0) { +      if (is64bit) { +        debug_loc.PushUint64(variable_location.low_pc - compilation_unit_low_pc); +        debug_loc.PushUint64(variable_location.high_pc - compilation_unit_low_pc); +      } else { +        debug_loc.PushUint32(variable_location.low_pc - compilation_unit_low_pc); +        debug_loc.PushUint32(variable_location.high_pc - compilation_unit_low_pc); +      } +      // Write the expression. +      debug_loc.PushUint16(expr.size()); +      debug_loc.PushData(expr.data()); +    } else { +      // Do not generate .debug_loc if the location is not known. +    } +  } +  // Write end-of-list entry. +  if (is64bit) { +    debug_loc.PushUint64(0); +    debug_loc.PushUint64(0); +  } else { +    debug_loc.PushUint32(0); +    debug_loc.PushUint32(0); +  } + +  // Write .debug_ranges entries. +  // This includes ranges where the variable is in scope but the location is not known. +  for (size_t i = 0; i < variable_locations.size(); i++) { +    uint32_t low_pc = variable_locations[i].low_pc; +    uint32_t high_pc = variable_locations[i].high_pc; +    while (i + 1 < variable_locations.size() && variable_locations[i+1].low_pc == high_pc) { +      // Merge address range with the next entry. +      high_pc = variable_locations[++i].high_pc; +    } +    if (is64bit) { +      debug_ranges.PushUint64(low_pc - compilation_unit_low_pc); +      debug_ranges.PushUint64(high_pc - compilation_unit_low_pc); +    } else { +      debug_ranges.PushUint32(low_pc - compilation_unit_low_pc); +      debug_ranges.PushUint32(high_pc - compilation_unit_low_pc); +    } +  } +  // Write end-of-list entry. +  if (is64bit) { +    debug_ranges.PushUint64(0); +    debug_ranges.PushUint64(0); +  } else { +    debug_ranges.PushUint32(0); +    debug_ranges.PushUint32(0); +  } +} + +}  // namespace debug +}  // namespace art + +#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_ + diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc new file mode 100644 index 0000000000..01bd6797c9 --- /dev/null +++ b/compiler/debug/elf_debug_writer.cc @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "elf_debug_writer.h" + +#include <vector> + +#include "debug/dwarf/dwarf_constants.h" +#include "debug/elf_compilation_unit.h" +#include "debug/elf_debug_frame_writer.h" +#include "debug/elf_debug_info_writer.h" +#include "debug/elf_debug_line_writer.h" +#include "debug/elf_debug_loc_writer.h" +#include "debug/elf_gnu_debugdata_writer.h" +#include "debug/elf_symtab_writer.h" +#include "debug/method_debug_info.h" +#include "elf_builder.h" +#include "linker/vector_output_stream.h" +#include "utils/array_ref.h" + +namespace art { +namespace debug { + +template <typename ElfTypes> +void WriteDebugInfo(ElfBuilder<ElfTypes>* builder, +                    const ArrayRef<const MethodDebugInfo>& method_infos, +                    dwarf::CFIFormat cfi_format, +                    bool write_oat_patches) { +  // Add methods to .symtab. +  WriteDebugSymbols(builder, method_infos, true /* with_signature */); +  // Generate CFI (stack unwinding information). +  WriteCFISection(builder, method_infos, cfi_format, write_oat_patches); +  // Write DWARF .debug_* sections. +  WriteDebugSections(builder, method_infos, write_oat_patches); +} + +template<typename ElfTypes> +static void WriteDebugSections(ElfBuilder<ElfTypes>* builder, +                               const ArrayRef<const MethodDebugInfo>& method_infos, +                               bool write_oat_patches) { +  // Group the methods into compilation units based on source file. +  std::vector<ElfCompilationUnit> compilation_units; +  const char* last_source_file = nullptr; +  for (const MethodDebugInfo& mi : method_infos) { +    auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index); +    const char* source_file = mi.dex_file->GetSourceFile(dex_class_def); +    if (compilation_units.empty() || source_file != last_source_file) { +      compilation_units.push_back(ElfCompilationUnit()); +    } +    ElfCompilationUnit& cu = compilation_units.back(); +    cu.methods.push_back(&mi); +    cu.low_pc = std::min(cu.low_pc, mi.low_pc); +    cu.high_pc = std::max(cu.high_pc, mi.high_pc); +    last_source_file = source_file; +  } + +  // Write .debug_line section. +  if (!compilation_units.empty()) { +    ElfDebugLineWriter<ElfTypes> line_writer(builder); +    line_writer.Start(); +    for (auto& compilation_unit : compilation_units) { +      line_writer.WriteCompilationUnit(compilation_unit); +    } +    line_writer.End(write_oat_patches); +  } + +  // Write .debug_info section. +  if (!compilation_units.empty()) { +    ElfDebugInfoWriter<ElfTypes> info_writer(builder); +    info_writer.Start(); +    for (const auto& compilation_unit : compilation_units) { +      ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer); +      cu_writer.Write(compilation_unit); +    } +    info_writer.End(write_oat_patches); +  } +} + +std::vector<uint8_t> MakeMiniDebugInfo( +    InstructionSet isa, +    size_t rodata_size, +    size_t text_size, +    const ArrayRef<const MethodDebugInfo>& method_infos) { +  if (Is64BitInstructionSet(isa)) { +    return MakeMiniDebugInfoInternal<ElfTypes64>(isa, rodata_size, text_size, method_infos); +  } else { +    return MakeMiniDebugInfoInternal<ElfTypes32>(isa, rodata_size, text_size, method_infos); +  } +} + +template <typename ElfTypes> +static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal( +    const MethodDebugInfo& method_info) { +  const InstructionSet isa = method_info.compiled_method->GetInstructionSet(); +  std::vector<uint8_t> buffer; +  buffer.reserve(KB); +  VectorOutputStream out("Debug ELF file", &buffer); +  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); +  // No program headers since the ELF file is not linked and has no allocated sections. +  builder->Start(false /* write_program_headers */); +  WriteDebugInfo(builder.get(), +                 ArrayRef<const MethodDebugInfo>(&method_info, 1), +                 dwarf::DW_DEBUG_FRAME_FORMAT, +                 false /* write_oat_patches */); +  builder->End(); +  CHECK(builder->Good()); +  // Make a copy of the buffer.  We want to shrink it anyway. +  uint8_t* result = new uint8_t[buffer.size()]; +  CHECK(result != nullptr); +  memcpy(result, buffer.data(), buffer.size()); +  return ArrayRef<const uint8_t>(result, buffer.size()); +} + +ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const MethodDebugInfo& method_info) { +  const InstructionSet isa = method_info.compiled_method->GetInstructionSet(); +  if (Is64BitInstructionSet(isa)) { +    return WriteDebugElfFileForMethodInternal<ElfTypes64>(method_info); +  } else { +    return WriteDebugElfFileForMethodInternal<ElfTypes32>(method_info); +  } +} + +template <typename ElfTypes> +static ArrayRef<const uint8_t> WriteDebugElfFileForClassesInternal( +    const InstructionSet isa, const ArrayRef<mirror::Class*>& types) +    SHARED_REQUIRES(Locks::mutator_lock_) { +  std::vector<uint8_t> buffer; +  buffer.reserve(KB); +  VectorOutputStream out("Debug ELF file", &buffer); +  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); +  // No program headers since the ELF file is not linked and has no allocated sections. +  builder->Start(false /* write_program_headers */); +  ElfDebugInfoWriter<ElfTypes> info_writer(builder.get()); +  info_writer.Start(); +  ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer); +  cu_writer.Write(types); +  info_writer.End(false /* write_oat_patches */); + +  builder->End(); +  CHECK(builder->Good()); +  // Make a copy of the buffer.  We want to shrink it anyway. +  uint8_t* result = new uint8_t[buffer.size()]; +  CHECK(result != nullptr); +  memcpy(result, buffer.data(), buffer.size()); +  return ArrayRef<const uint8_t>(result, buffer.size()); +} + +ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa, +                                                    const ArrayRef<mirror::Class*>& types) { +  if (Is64BitInstructionSet(isa)) { +    return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, types); +  } else { +    return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, types); +  } +} + +// Explicit instantiations +template void WriteDebugInfo<ElfTypes32>( +    ElfBuilder<ElfTypes32>* builder, +    const ArrayRef<const MethodDebugInfo>& method_infos, +    dwarf::CFIFormat cfi_format, +    bool write_oat_patches); +template void WriteDebugInfo<ElfTypes64>( +    ElfBuilder<ElfTypes64>* builder, +    const ArrayRef<const MethodDebugInfo>& method_infos, +    dwarf::CFIFormat cfi_format, +    bool write_oat_patches); + +}  // namespace debug +}  // namespace art diff --git a/compiler/debug/elf_writer_debug.h b/compiler/debug/elf_debug_writer.h index c5bf609217..103b501489 100644 --- a/compiler/debug/elf_writer_debug.h +++ b/compiler/debug/elf_debug_writer.h @@ -1,5 +1,5 @@  /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2016 The Android Open Source Project   *   * Licensed under the Apache License, Version 2.0 (the "License");   * you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@   * limitations under the License.   */ -#ifndef ART_COMPILER_DEBUG_ELF_WRITER_DEBUG_H_ -#define ART_COMPILER_DEBUG_ELF_WRITER_DEBUG_H_ +#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_ +#define ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_  #include "base/macros.h"  #include "base/mutex.h" @@ -27,13 +27,13 @@ namespace art {  namespace mirror {  class Class;  } -namespace dwarf { +namespace debug {  struct MethodDebugInfo;  template <typename ElfTypes>  void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,                      const ArrayRef<const MethodDebugInfo>& method_infos, -                    CFIFormat cfi_format, +                    dwarf::CFIFormat cfi_format,                      bool write_oat_patches);  std::vector<uint8_t> MakeMiniDebugInfo(InstructionSet isa, @@ -41,13 +41,13 @@ std::vector<uint8_t> MakeMiniDebugInfo(InstructionSet isa,                                         size_t text_section_size,                                         const ArrayRef<const MethodDebugInfo>& method_infos); -ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info); +ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const MethodDebugInfo& method_info);  ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,                                                      const ArrayRef<mirror::Class*>& types)      SHARED_REQUIRES(Locks::mutator_lock_); -}  // namespace dwarf +}  // namespace debug  }  // namespace art -#endif  // ART_COMPILER_DEBUG_ELF_WRITER_DEBUG_H_ +#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_ diff --git a/compiler/debug/elf_gnu_debugdata_writer.h b/compiler/debug/elf_gnu_debugdata_writer.h new file mode 100644 index 0000000000..5c7d1c72a4 --- /dev/null +++ b/compiler/debug/elf_gnu_debugdata_writer.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_ +#define ART_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_ + +#include <vector> + +#include "arch/instruction_set.h" +#include "elf_builder.h" +#include "linker/vector_output_stream.h" + +// liblzma. +#include "7zCrc.h" +#include "XzCrc64.h" +#include "XzEnc.h" + +namespace art { +namespace debug { + +static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* dst) { +  // Configure the compression library. +  CrcGenerateTable(); +  Crc64GenerateTable(); +  CLzma2EncProps lzma2Props; +  Lzma2EncProps_Init(&lzma2Props); +  lzma2Props.lzmaProps.level = 1;  // Fast compression. +  Lzma2EncProps_Normalize(&lzma2Props); +  CXzProps props; +  XzProps_Init(&props); +  props.lzma2Props = &lzma2Props; +  // Implement the required interface for communication (written in C so no virtual methods). +  struct XzCallbacks : public ISeqInStream, public ISeqOutStream, public ICompressProgress { +    static SRes ReadImpl(void* p, void* buf, size_t* size) { +      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqInStream*>(p)); +      *size = std::min(*size, ctx->src_->size() - ctx->src_pos_); +      memcpy(buf, ctx->src_->data() + ctx->src_pos_, *size); +      ctx->src_pos_ += *size; +      return SZ_OK; +    } +    static size_t WriteImpl(void* p, const void* buf, size_t size) { +      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqOutStream*>(p)); +      const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buf); +      ctx->dst_->insert(ctx->dst_->end(), buffer, buffer + size); +      return size; +    } +    static SRes ProgressImpl(void* , UInt64, UInt64) { +      return SZ_OK; +    } +    size_t src_pos_; +    const std::vector<uint8_t>* src_; +    std::vector<uint8_t>* dst_; +  }; +  XzCallbacks callbacks; +  callbacks.Read = XzCallbacks::ReadImpl; +  callbacks.Write = XzCallbacks::WriteImpl; +  callbacks.Progress = XzCallbacks::ProgressImpl; +  callbacks.src_pos_ = 0; +  callbacks.src_ = src; +  callbacks.dst_ = dst; +  // Compress. +  SRes res = Xz_Encode(&callbacks, &callbacks, &props, &callbacks); +  CHECK_EQ(res, SZ_OK); +} + +template <typename ElfTypes> +static std::vector<uint8_t> MakeMiniDebugInfoInternal( +    InstructionSet isa, +    size_t rodata_section_size, +    size_t text_section_size, +    const ArrayRef<const MethodDebugInfo>& method_infos) { +  std::vector<uint8_t> buffer; +  buffer.reserve(KB); +  VectorOutputStream out("Mini-debug-info ELF file", &buffer); +  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); +  builder->Start(); +  // Mirror .rodata and .text as NOBITS sections. +  // It is needed to detected relocations after compression. +  builder->GetRoData()->WriteNoBitsSection(rodata_section_size); +  builder->GetText()->WriteNoBitsSection(text_section_size); +  WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */); +  WriteCFISection(builder.get(), +                  method_infos, +                  dwarf::DW_DEBUG_FRAME_FORMAT, +                  false /* write_oat_paches */); +  builder->End(); +  CHECK(builder->Good()); +  std::vector<uint8_t> compressed_buffer; +  compressed_buffer.reserve(buffer.size() / 4); +  XzCompress(&buffer, &compressed_buffer); +  return compressed_buffer; +} + +}  // namespace debug +}  // namespace art + +#endif  // ART_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_ + diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h new file mode 100644 index 0000000000..41508f44b4 --- /dev/null +++ b/compiler/debug/elf_symtab_writer.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_ +#define ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_ + +#include <unordered_set> + +#include "debug/method_debug_info.h" +#include "elf_builder.h" +#include "utils.h" + +namespace art { +namespace debug { + +// The ARM specification defines three special mapping symbols +// $a, $t and $d which mark ARM, Thumb and data ranges respectively. +// These symbols can be used by tools, for example, to pretty +// print instructions correctly.  Objdump will use them if they +// exist, but it will still work well without them. +// However, these extra symbols take space, so let's just generate +// one symbol which marks the whole .text section as code. +constexpr bool kGenerateSingleArmMappingSymbol = true; + +template <typename ElfTypes> +static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, +                              const ArrayRef<const MethodDebugInfo>& method_infos, +                              bool with_signature) { +  bool generated_mapping_symbol = false; +  auto* strtab = builder->GetStrTab(); +  auto* symtab = builder->GetSymTab(); + +  if (method_infos.empty()) { +    return; +  } + +  // Find all addresses (low_pc) which contain deduped methods. +  // The first instance of method is not marked deduped_, but the rest is. +  std::unordered_set<uint32_t> deduped_addresses; +  for (const MethodDebugInfo& info : method_infos) { +    if (info.deduped) { +      deduped_addresses.insert(info.low_pc); +    } +  } + +  strtab->Start(); +  strtab->Write("");  // strtab should start with empty string. +  std::string last_name; +  size_t last_name_offset = 0; +  for (const MethodDebugInfo& info : method_infos) { +    if (info.deduped) { +      continue;  // Add symbol only for the first instance. +    } +    std::string name = PrettyMethod(info.dex_method_index, *info.dex_file, with_signature); +    if (deduped_addresses.find(info.low_pc) != deduped_addresses.end()) { +      name += " [DEDUPED]"; +    } +    // If we write method names without signature, we might see the same name multiple times. +    size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name)); + +    const auto* text = builder->GetText()->Exists() ? builder->GetText() : nullptr; +    const bool is_relative = (text != nullptr); +    uint32_t low_pc = info.low_pc; +    // Add in code delta, e.g., thumb bit 0 for Thumb2 code. +    low_pc += info.compiled_method->CodeDelta(); +    symtab->Add(name_offset, +                text, +                low_pc, +                is_relative, +                info.high_pc - info.low_pc, +                STB_GLOBAL, +                STT_FUNC); + +    // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2 +    // instructions, so that disassembler tools can correctly disassemble. +    // Note that even if we generate just a single mapping symbol, ARM's Streamline +    // requires it to match function symbol.  Just address 0 does not work. +    if (info.compiled_method->GetInstructionSet() == kThumb2) { +      if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) { +        symtab->Add(strtab->Write("$t"), text, info.low_pc & ~1, +                    is_relative, 0, STB_LOCAL, STT_NOTYPE); +        generated_mapping_symbol = true; +      } +    } + +    last_name = std::move(name); +    last_name_offset = name_offset; +  } +  strtab->End(); + +  // Symbols are buffered and written after names (because they are smaller). +  // We could also do two passes in this function to avoid the buffering. +  symtab->Start(); +  symtab->Write(); +  symtab->End(); +} + +}  // namespace debug +}  // namespace art + +#endif  // ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_ + diff --git a/compiler/debug/elf_writer_debug.cc b/compiler/debug/elf_writer_debug.cc deleted file mode 100644 index 07d16d22e7..0000000000 --- a/compiler/debug/elf_writer_debug.cc +++ /dev/null @@ -1,1666 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "elf_writer_debug.h" - -#include <algorithm> -#include <unordered_set> -#include <vector> -#include <cstdio> - -#include "base/casts.h" -#include "base/stl_util.h" -#include "compiled_method.h" -#include "debug/dwarf/expression.h" -#include "debug/dwarf/headers.h" -#include "debug/dwarf/register.h" -#include "debug/method_debug_info.h" -#include "dex_file-inl.h" -#include "driver/compiler_driver.h" -#include "elf_builder.h" -#include "linear_alloc.h" -#include "linker/vector_output_stream.h" -#include "mirror/array.h" -#include "mirror/class-inl.h" -#include "mirror/class.h" -#include "oat_writer.h" -#include "stack_map.h" -#include "utils.h" - -// liblzma. -#include "XzEnc.h" -#include "7zCrc.h" -#include "XzCrc64.h" - -namespace art { -namespace dwarf { - -// The ARM specification defines three special mapping symbols -// $a, $t and $d which mark ARM, Thumb and data ranges respectively. -// These symbols can be used by tools, for example, to pretty -// print instructions correctly.  Objdump will use them if they -// exist, but it will still work well without them. -// However, these extra symbols take space, so let's just generate -// one symbol which marks the whole .text section as code. -constexpr bool kGenerateSingleArmMappingSymbol = true; - -static Reg GetDwarfCoreReg(InstructionSet isa, int machine_reg) { -  switch (isa) { -    case kArm: -    case kThumb2: -      return Reg::ArmCore(machine_reg); -    case kArm64: -      return Reg::Arm64Core(machine_reg); -    case kX86: -      return Reg::X86Core(machine_reg); -    case kX86_64: -      return Reg::X86_64Core(machine_reg); -    case kMips: -      return Reg::MipsCore(machine_reg); -    case kMips64: -      return Reg::Mips64Core(machine_reg); -    default: -      LOG(FATAL) << "Unknown instruction set: " << isa; -      UNREACHABLE(); -  } -} - -static Reg GetDwarfFpReg(InstructionSet isa, int machine_reg) { -  switch (isa) { -    case kArm: -    case kThumb2: -      return Reg::ArmFp(machine_reg); -    case kArm64: -      return Reg::Arm64Fp(machine_reg); -    case kX86: -      return Reg::X86Fp(machine_reg); -    case kX86_64: -      return Reg::X86_64Fp(machine_reg); -    case kMips: -      return Reg::MipsFp(machine_reg); -    case kMips64: -      return Reg::Mips64Fp(machine_reg); -    default: -      LOG(FATAL) << "Unknown instruction set: " << isa; -      UNREACHABLE(); -  } -} - -static void WriteCIE(InstructionSet isa, -                     CFIFormat format, -                     std::vector<uint8_t>* buffer) { -  // Scratch registers should be marked as undefined.  This tells the -  // debugger that its value in the previous frame is not recoverable. -  bool is64bit = Is64BitInstructionSet(isa); -  switch (isa) { -    case kArm: -    case kThumb2: { -      DebugFrameOpCodeWriter<> opcodes; -      opcodes.DefCFA(Reg::ArmCore(13), 0);  // R13(SP). -      // core registers. -      for (int reg = 0; reg < 13; reg++) { -        if (reg < 4 || reg == 12) { -          opcodes.Undefined(Reg::ArmCore(reg)); -        } else { -          opcodes.SameValue(Reg::ArmCore(reg)); -        } -      } -      // fp registers. -      for (int reg = 0; reg < 32; reg++) { -        if (reg < 16) { -          opcodes.Undefined(Reg::ArmFp(reg)); -        } else { -          opcodes.SameValue(Reg::ArmFp(reg)); -        } -      } -      auto return_reg = Reg::ArmCore(14);  // R14(LR). -      WriteCIE(is64bit, return_reg, opcodes, format, buffer); -      return; -    } -    case kArm64: { -      DebugFrameOpCodeWriter<> opcodes; -      opcodes.DefCFA(Reg::Arm64Core(31), 0);  // R31(SP). -      // core registers. -      for (int reg = 0; reg < 30; reg++) { -        if (reg < 8 || reg == 16 || reg == 17) { -          opcodes.Undefined(Reg::Arm64Core(reg)); -        } else { -          opcodes.SameValue(Reg::Arm64Core(reg)); -        } -      } -      // fp registers. -      for (int reg = 0; reg < 32; reg++) { -        if (reg < 8 || reg >= 16) { -          opcodes.Undefined(Reg::Arm64Fp(reg)); -        } else { -          opcodes.SameValue(Reg::Arm64Fp(reg)); -        } -      } -      auto return_reg = Reg::Arm64Core(30);  // R30(LR). -      WriteCIE(is64bit, return_reg, opcodes, format, buffer); -      return; -    } -    case kMips: -    case kMips64: { -      DebugFrameOpCodeWriter<> opcodes; -      opcodes.DefCFA(Reg::MipsCore(29), 0);  // R29(SP). -      // core registers. -      for (int reg = 1; reg < 26; reg++) { -        if (reg < 16 || reg == 24 || reg == 25) {  // AT, V*, A*, T*. -          opcodes.Undefined(Reg::MipsCore(reg)); -        } else { -          opcodes.SameValue(Reg::MipsCore(reg)); -        } -      } -      // fp registers. -      for (int reg = 0; reg < 32; reg++) { -        if (reg < 24) { -          opcodes.Undefined(Reg::Mips64Fp(reg)); -        } else { -          opcodes.SameValue(Reg::Mips64Fp(reg)); -        } -      } -      auto return_reg = Reg::MipsCore(31);  // R31(RA). -      WriteCIE(is64bit, return_reg, opcodes, format, buffer); -      return; -    } -    case kX86: { -      // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296 -      constexpr bool generate_opcodes_for_x86_fp = false; -      DebugFrameOpCodeWriter<> opcodes; -      opcodes.DefCFA(Reg::X86Core(4), 4);   // R4(ESP). -      opcodes.Offset(Reg::X86Core(8), -4);  // R8(EIP). -      // core registers. -      for (int reg = 0; reg < 8; reg++) { -        if (reg <= 3) { -          opcodes.Undefined(Reg::X86Core(reg)); -        } else if (reg == 4) { -          // Stack pointer. -        } else { -          opcodes.SameValue(Reg::X86Core(reg)); -        } -      } -      // fp registers. -      if (generate_opcodes_for_x86_fp) { -        for (int reg = 0; reg < 8; reg++) { -          opcodes.Undefined(Reg::X86Fp(reg)); -        } -      } -      auto return_reg = Reg::X86Core(8);  // R8(EIP). -      WriteCIE(is64bit, return_reg, opcodes, format, buffer); -      return; -    } -    case kX86_64: { -      DebugFrameOpCodeWriter<> opcodes; -      opcodes.DefCFA(Reg::X86_64Core(4), 8);  // R4(RSP). -      opcodes.Offset(Reg::X86_64Core(16), -8);  // R16(RIP). -      // core registers. -      for (int reg = 0; reg < 16; reg++) { -        if (reg == 4) { -          // Stack pointer. -        } else if (reg < 12 && reg != 3 && reg != 5) {  // except EBX and EBP. -          opcodes.Undefined(Reg::X86_64Core(reg)); -        } else { -          opcodes.SameValue(Reg::X86_64Core(reg)); -        } -      } -      // fp registers. -      for (int reg = 0; reg < 16; reg++) { -        if (reg < 12) { -          opcodes.Undefined(Reg::X86_64Fp(reg)); -        } else { -          opcodes.SameValue(Reg::X86_64Fp(reg)); -        } -      } -      auto return_reg = Reg::X86_64Core(16);  // R16(RIP). -      WriteCIE(is64bit, return_reg, opcodes, format, buffer); -      return; -    } -    case kNone: -      break; -  } -  LOG(FATAL) << "Cannot write CIE frame for ISA " << isa; -  UNREACHABLE(); -} - -template<typename ElfTypes> -void WriteCFISection(ElfBuilder<ElfTypes>* builder, -                     const ArrayRef<const MethodDebugInfo>& method_infos, -                     CFIFormat format, -                     bool write_oat_patches) { -  CHECK(format == DW_DEBUG_FRAME_FORMAT || format == DW_EH_FRAME_FORMAT); -  typedef typename ElfTypes::Addr Elf_Addr; - -  if (method_infos.empty()) { -    return; -  } - -  std::vector<uint32_t> binary_search_table; -  std::vector<uintptr_t> patch_locations; -  if (format == DW_EH_FRAME_FORMAT) { -    binary_search_table.reserve(2 * method_infos.size()); -  } else { -    patch_locations.reserve(method_infos.size()); -  } - -  // The methods can be written any order. -  // Let's therefore sort them in the lexicographical order of the opcodes. -  // This has no effect on its own. However, if the final .debug_frame section is -  // compressed it reduces the size since similar opcodes sequences are grouped. -  std::vector<const MethodDebugInfo*> sorted_method_infos; -  sorted_method_infos.reserve(method_infos.size()); -  for (size_t i = 0; i < method_infos.size(); i++) { -    sorted_method_infos.push_back(&method_infos[i]); -  } -  std::sort( -      sorted_method_infos.begin(), -      sorted_method_infos.end(), -      [](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) { -        ArrayRef<const uint8_t> l = lhs->compiled_method_->GetCFIInfo(); -        ArrayRef<const uint8_t> r = rhs->compiled_method_->GetCFIInfo(); -        return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); -      }); - -  // Write .eh_frame/.debug_frame section. -  auto* cfi_section = (format == DW_DEBUG_FRAME_FORMAT -                       ? builder->GetDebugFrame() -                       : builder->GetEhFrame()); -  { -    cfi_section->Start(); -    const bool is64bit = Is64BitInstructionSet(builder->GetIsa()); -    const Elf_Addr text_address = builder->GetText()->Exists() -        ? builder->GetText()->GetAddress() -        : 0; -    const Elf_Addr cfi_address = cfi_section->GetAddress(); -    const Elf_Addr cie_address = cfi_address; -    Elf_Addr buffer_address = cfi_address; -    std::vector<uint8_t> buffer;  // Small temporary buffer. -    WriteCIE(builder->GetIsa(), format, &buffer); -    cfi_section->WriteFully(buffer.data(), buffer.size()); -    buffer_address += buffer.size(); -    buffer.clear(); -    for (const MethodDebugInfo* mi : sorted_method_infos) { -      if (!mi->deduped_) {  // Only one FDE per unique address. -        ArrayRef<const uint8_t> opcodes = mi->compiled_method_->GetCFIInfo(); -        if (!opcodes.empty()) { -          const Elf_Addr code_address = text_address + mi->low_pc_; -          if (format == DW_EH_FRAME_FORMAT) { -            binary_search_table.push_back( -                dchecked_integral_cast<uint32_t>(code_address)); -            binary_search_table.push_back( -                dchecked_integral_cast<uint32_t>(buffer_address)); -          } -          WriteFDE(is64bit, cfi_address, cie_address, -                   code_address, mi->high_pc_ - mi->low_pc_, -                   opcodes, format, buffer_address, &buffer, -                   &patch_locations); -          cfi_section->WriteFully(buffer.data(), buffer.size()); -          buffer_address += buffer.size(); -          buffer.clear(); -        } -      } -    } -    cfi_section->End(); -  } - -  if (format == DW_EH_FRAME_FORMAT) { -    auto* header_section = builder->GetEhFrameHdr(); -    header_section->Start(); -    uint32_t header_address = dchecked_integral_cast<int32_t>(header_section->GetAddress()); -    // Write .eh_frame_hdr section. -    std::vector<uint8_t> buffer; -    Writer<> header(&buffer); -    header.PushUint8(1);  // Version. -    // Encoding of .eh_frame pointer - libunwind does not honor datarel here, -    // so we have to use pcrel which means relative to the pointer's location. -    header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); -    // Encoding of binary search table size. -    header.PushUint8(DW_EH_PE_udata4); -    // Encoding of binary search table addresses - libunwind supports only this -    // specific combination, which means relative to the start of .eh_frame_hdr. -    header.PushUint8(DW_EH_PE_datarel | DW_EH_PE_sdata4); -    // .eh_frame pointer -    header.PushInt32(cfi_section->GetAddress() - (header_address + 4u)); -    // Binary search table size (number of entries). -    header.PushUint32(dchecked_integral_cast<uint32_t>(binary_search_table.size()/2)); -    header_section->WriteFully(buffer.data(), buffer.size()); -    // Binary search table. -    for (size_t i = 0; i < binary_search_table.size(); i++) { -      // Make addresses section-relative since we know the header address now. -      binary_search_table[i] -= header_address; -    } -    header_section->WriteFully(binary_search_table.data(), binary_search_table.size()); -    header_section->End(); -  } else { -    if (write_oat_patches) { -      builder->WritePatches(".debug_frame.oat_patches", -                            ArrayRef<const uintptr_t>(patch_locations)); -    } -  } -} - -namespace { -  struct CompilationUnit { -    std::vector<const MethodDebugInfo*> methods_; -    size_t debug_line_offset_ = 0; -    uintptr_t low_pc_ = std::numeric_limits<uintptr_t>::max(); -    uintptr_t high_pc_ = 0; -  }; - -  typedef std::vector<DexFile::LocalInfo> LocalInfos; - -  void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) { -    static_cast<LocalInfos*>(ctx)->push_back(entry); -  } - -  typedef std::vector<DexFile::PositionInfo> PositionInfos; - -  bool PositionInfoCallback(void* ctx, const DexFile::PositionInfo& entry) { -    static_cast<PositionInfos*>(ctx)->push_back(entry); -    return false; -  } - -  std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) { -    std::vector<const char*> names; -    if (mi->code_item_ != nullptr) { -      const uint8_t* stream = mi->dex_file_->GetDebugInfoStream(mi->code_item_); -      if (stream != nullptr) { -        DecodeUnsignedLeb128(&stream);  // line. -        uint32_t parameters_size = DecodeUnsignedLeb128(&stream); -        for (uint32_t i = 0; i < parameters_size; ++i) { -          uint32_t id = DecodeUnsignedLeb128P1(&stream); -          names.push_back(mi->dex_file_->StringDataByIdx(id)); -        } -      } -    } -    return names; -  } - -  struct VariableLocation { -    uint32_t low_pc; -    uint32_t high_pc; -    DexRegisterLocation reg_lo;  // May be None if the location is unknown. -    DexRegisterLocation reg_hi;  // Most significant bits of 64-bit value. -  }; - -  // Get the location of given dex register (e.g. stack or machine register). -  // Note that the location might be different based on the current pc. -  // The result will cover all ranges where the variable is in scope. -  std::vector<VariableLocation> GetVariableLocations(const MethodDebugInfo* method_info, -                                                     uint16_t vreg, -                                                     bool is64bitValue, -                                                     uint32_t dex_pc_low, -                                                     uint32_t dex_pc_high) { -    std::vector<VariableLocation> variable_locations; - -    // Get stack maps sorted by pc (they might not be sorted internally). -    const CodeInfo code_info(method_info->compiled_method_->GetVmapTable().data()); -    const StackMapEncoding encoding = code_info.ExtractEncoding(); -    std::map<uint32_t, StackMap> stack_maps; -    for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) { -      StackMap stack_map = code_info.GetStackMapAt(s, encoding); -      DCHECK(stack_map.IsValid()); -      const uint32_t low_pc = method_info->low_pc_ + stack_map.GetNativePcOffset(encoding); -      DCHECK_LE(low_pc, method_info->high_pc_); -      stack_maps.emplace(low_pc, stack_map); -    } - -    // Create entries for the requested register based on stack map data. -    for (auto it = stack_maps.begin(); it != stack_maps.end(); it++) { -      const StackMap& stack_map = it->second; -      const uint32_t low_pc = it->first; -      auto next_it = it; -      next_it++; -      const uint32_t high_pc = next_it != stack_maps.end() ? next_it->first -                                                           : method_info->high_pc_; -      DCHECK_LE(low_pc, high_pc); -      if (low_pc == high_pc) { -        continue;  // Ignore if the address range is empty. -      } - -      // Check that the stack map is in the requested range. -      uint32_t dex_pc = stack_map.GetDexPc(encoding); -      if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) { -        continue; -      } - -      // Find the location of the dex register. -      DexRegisterLocation reg_lo = DexRegisterLocation::None(); -      DexRegisterLocation reg_hi = DexRegisterLocation::None(); -      if (stack_map.HasDexRegisterMap(encoding)) { -        DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf( -            stack_map, encoding, method_info->code_item_->registers_size_); -        reg_lo = dex_register_map.GetDexRegisterLocation( -            vreg, method_info->code_item_->registers_size_, code_info, encoding); -        if (is64bitValue) { -          reg_hi = dex_register_map.GetDexRegisterLocation( -              vreg + 1, method_info->code_item_->registers_size_, code_info, encoding); -        } -      } - -      // Add location entry for this address range. -      if (!variable_locations.empty() && -          variable_locations.back().reg_lo == reg_lo && -          variable_locations.back().reg_hi == reg_hi && -          variable_locations.back().high_pc == low_pc) { -        // Merge with the previous entry (extend its range). -        variable_locations.back().high_pc = high_pc; -      } else { -        variable_locations.push_back({low_pc, high_pc, reg_lo, reg_hi}); -      } -    } - -    return variable_locations; -  } - -  bool IsFromOptimizingCompiler(const MethodDebugInfo* method_info) { -    return method_info->compiled_method_->GetQuickCode().size() > 0 && -           method_info->compiled_method_->GetVmapTable().size() > 0 && -           method_info->compiled_method_->GetGcMap().size() == 0 && -           method_info->code_item_ != nullptr; -  } -}  // namespace - -// Helper class to write .debug_info and its supporting sections. -template<typename ElfTypes> -class DebugInfoWriter { -  typedef typename ElfTypes::Addr Elf_Addr; - -  // Helper class to write one compilation unit. -  // It holds helper methods and temporary state. -  class CompilationUnitWriter { -   public: -    explicit CompilationUnitWriter(DebugInfoWriter* owner) -      : owner_(owner), -        info_(Is64BitInstructionSet(owner_->builder_->GetIsa()), &owner->debug_abbrev_) { -    } - -    void Write(const CompilationUnit& compilation_unit) { -      CHECK(!compilation_unit.methods_.empty()); -      const Elf_Addr text_address = owner_->builder_->GetText()->Exists() -          ? owner_->builder_->GetText()->GetAddress() -          : 0; -      const uintptr_t cu_size = compilation_unit.high_pc_ - compilation_unit.low_pc_; - -      info_.StartTag(DW_TAG_compile_unit); -      info_.WriteString(DW_AT_producer, "Android dex2oat"); -      info_.WriteData1(DW_AT_language, DW_LANG_Java); -      info_.WriteString(DW_AT_comp_dir, "$JAVA_SRC_ROOT"); -      info_.WriteAddr(DW_AT_low_pc, text_address + compilation_unit.low_pc_); -      info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size)); -      info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset_); - -      const char* last_dex_class_desc = nullptr; -      for (auto mi : compilation_unit.methods_) { -        const DexFile* dex = mi->dex_file_; -        const DexFile::CodeItem* dex_code = mi->code_item_; -        const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index_); -        const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method); -        const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto); -        const char* dex_class_desc = dex->GetMethodDeclaringClassDescriptor(dex_method); -        const bool is_static = (mi->access_flags_ & kAccStatic) != 0; - -        // Enclose the method in correct class definition. -        if (last_dex_class_desc != dex_class_desc) { -          if (last_dex_class_desc != nullptr) { -            EndClassTag(); -          } -          // Write reference tag for the class we are about to declare. -          size_t reference_tag_offset = info_.StartTag(DW_TAG_reference_type); -          type_cache_.emplace(std::string(dex_class_desc), reference_tag_offset); -          size_t type_attrib_offset = info_.size(); -          info_.WriteRef4(DW_AT_type, 0); -          info_.EndTag(); -          // Declare the class that owns this method. -          size_t class_offset = StartClassTag(dex_class_desc); -          info_.UpdateUint32(type_attrib_offset, class_offset); -          info_.WriteFlagPresent(DW_AT_declaration); -          // Check that each class is defined only once. -          bool unique = owner_->defined_dex_classes_.insert(dex_class_desc).second; -          CHECK(unique) << "Redefinition of " << dex_class_desc; -          last_dex_class_desc = dex_class_desc; -        } - -        int start_depth = info_.Depth(); -        info_.StartTag(DW_TAG_subprogram); -        WriteName(dex->GetMethodName(dex_method)); -        info_.WriteAddr(DW_AT_low_pc, text_address + mi->low_pc_); -        info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(mi->high_pc_-mi->low_pc_)); -        std::vector<uint8_t> expr_buffer; -        Expression expr(&expr_buffer); -        expr.WriteOpCallFrameCfa(); -        info_.WriteExprLoc(DW_AT_frame_base, expr); -        WriteLazyType(dex->GetReturnTypeDescriptor(dex_proto)); - -        // Write parameters. DecodeDebugLocalInfo returns them as well, but it does not -        // guarantee order or uniqueness so it is safer to iterate over them manually. -        // DecodeDebugLocalInfo might not also be available if there is no debug info. -        std::vector<const char*> param_names = GetParamNames(mi); -        uint32_t arg_reg = 0; -        if (!is_static) { -          info_.StartTag(DW_TAG_formal_parameter); -          WriteName("this"); -          info_.WriteFlagPresent(DW_AT_artificial); -          WriteLazyType(dex_class_desc); -          if (dex_code != nullptr) { -            // Write the stack location of the parameter. -            const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg; -            const bool is64bitValue = false; -            WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_); -          } -          arg_reg++; -          info_.EndTag(); -        } -        if (dex_params != nullptr) { -          for (uint32_t i = 0; i < dex_params->Size(); ++i) { -            info_.StartTag(DW_TAG_formal_parameter); -            // Parameter names may not be always available. -            if (i < param_names.size()) { -              WriteName(param_names[i]); -            } -            // Write the type. -            const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_); -            WriteLazyType(type_desc); -            const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J'; -            if (dex_code != nullptr) { -              // Write the stack location of the parameter. -              const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg; -              WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_); -            } -            arg_reg += is64bitValue ? 2 : 1; -            info_.EndTag(); -          } -          if (dex_code != nullptr) { -            DCHECK_EQ(arg_reg, dex_code->ins_size_); -          } -        } - -        // Write local variables. -        LocalInfos local_infos; -        if (dex->DecodeDebugLocalInfo(dex_code, -                                      is_static, -                                      mi->dex_method_index_, -                                      LocalInfoCallback, -                                      &local_infos)) { -          for (const DexFile::LocalInfo& var : local_infos) { -            if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) { -              info_.StartTag(DW_TAG_variable); -              WriteName(var.name_); -              WriteLazyType(var.descriptor_); -              bool is64bitValue = var.descriptor_[0] == 'D' || var.descriptor_[0] == 'J'; -              WriteRegLocation(mi, var.reg_, is64bitValue, compilation_unit.low_pc_, -                               var.start_address_, var.end_address_); -              info_.EndTag(); -            } -          } -        } - -        info_.EndTag(); -        CHECK_EQ(info_.Depth(), start_depth);  // Balanced start/end. -      } -      if (last_dex_class_desc != nullptr) { -        EndClassTag(); -      } -      FinishLazyTypes(); -      CloseNamespacesAboveDepth(0); -      info_.EndTag();  // DW_TAG_compile_unit -      CHECK_EQ(info_.Depth(), 0); -      std::vector<uint8_t> buffer; -      buffer.reserve(info_.data()->size() + KB); -      const size_t offset = owner_->builder_->GetDebugInfo()->GetSize(); -      // All compilation units share single table which is at the start of .debug_abbrev. -      const size_t debug_abbrev_offset = 0; -      WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_); -      owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size()); -    } - -    void Write(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) { -      info_.StartTag(DW_TAG_compile_unit); -      info_.WriteString(DW_AT_producer, "Android dex2oat"); -      info_.WriteData1(DW_AT_language, DW_LANG_Java); - -      // Base class references to be patched at the end. -      std::map<size_t, mirror::Class*> base_class_references; - -      // Already written declarations or definitions. -      std::map<mirror::Class*, size_t> class_declarations; - -      std::vector<uint8_t> expr_buffer; -      for (mirror::Class* type : types) { -        if (type->IsPrimitive()) { -          // For primitive types the definition and the declaration is the same. -          if (type->GetPrimitiveType() != Primitive::kPrimVoid) { -            WriteTypeDeclaration(type->GetDescriptor(nullptr)); -          } -        } else if (type->IsArrayClass()) { -          mirror::Class* element_type = type->GetComponentType(); -          uint32_t component_size = type->GetComponentSize(); -          uint32_t data_offset = mirror::Array::DataOffset(component_size).Uint32Value(); -          uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value(); - -          CloseNamespacesAboveDepth(0);  // Declare in root namespace. -          info_.StartTag(DW_TAG_array_type); -          std::string descriptor_string; -          WriteLazyType(element_type->GetDescriptor(&descriptor_string)); -          WriteLinkageName(type); -          info_.WriteUdata(DW_AT_data_member_location, data_offset); -          info_.StartTag(DW_TAG_subrange_type); -          Expression count_expr(&expr_buffer); -          count_expr.WriteOpPushObjectAddress(); -          count_expr.WriteOpPlusUconst(length_offset); -          count_expr.WriteOpDerefSize(4);  // Array length is always 32-bit wide. -          info_.WriteExprLoc(DW_AT_count, count_expr); -          info_.EndTag();  // DW_TAG_subrange_type. -          info_.EndTag();  // DW_TAG_array_type. -        } else if (type->IsInterface()) { -          // Skip.  Variables cannot have an interface as a dynamic type. -          // We do not expose the interface information to the debugger in any way. -        } else { -          std::string descriptor_string; -          const char* desc = type->GetDescriptor(&descriptor_string); -          size_t class_offset = StartClassTag(desc); -          class_declarations.emplace(type, class_offset); - -          if (!type->IsVariableSize()) { -            info_.WriteUdata(DW_AT_byte_size, type->GetObjectSize()); -          } - -          WriteLinkageName(type); - -          if (type->IsObjectClass()) { -            // Generate artificial member which is used to get the dynamic type of variable. -            // The run-time value of this field will correspond to linkage name of some type. -            // We need to do it only once in j.l.Object since all other types inherit it. -            info_.StartTag(DW_TAG_member); -            WriteName(".dynamic_type"); -            WriteLazyType(sizeof(uintptr_t) == 8 ? "J" : "I"); -            info_.WriteFlagPresent(DW_AT_artificial); -            // Create DWARF expression to get the value of the methods_ field. -            Expression expr(&expr_buffer); -            // The address of the object has been implicitly pushed on the stack. -            // Dereference the klass_ field of Object (32-bit; possibly poisoned). -            DCHECK_EQ(type->ClassOffset().Uint32Value(), 0u); -            DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Class>), 4u); -            expr.WriteOpDerefSize(4); -            if (kPoisonHeapReferences) { -              expr.WriteOpNeg(); -              // DWARF stack is pointer sized. Ensure that the high bits are clear. -              expr.WriteOpConstu(0xFFFFFFFF); -              expr.WriteOpAnd(); -            } -            // Add offset to the methods_ field. -            expr.WriteOpPlusUconst(mirror::Class::MethodsOffset().Uint32Value()); -            // Top of stack holds the location of the field now. -            info_.WriteExprLoc(DW_AT_data_member_location, expr); -            info_.EndTag();  // DW_TAG_member. -          } - -          // Base class. -          mirror::Class* base_class = type->GetSuperClass(); -          if (base_class != nullptr) { -            info_.StartTag(DW_TAG_inheritance); -            base_class_references.emplace(info_.size(), base_class); -            info_.WriteRef4(DW_AT_type, 0); -            info_.WriteUdata(DW_AT_data_member_location, 0); -            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public); -            info_.EndTag();  // DW_TAG_inheritance. -          } - -          // Member variables. -          for (uint32_t i = 0, count = type->NumInstanceFields(); i < count; ++i) { -            ArtField* field = type->GetInstanceField(i); -            info_.StartTag(DW_TAG_member); -            WriteName(field->GetName()); -            WriteLazyType(field->GetTypeDescriptor()); -            info_.WriteUdata(DW_AT_data_member_location, field->GetOffset().Uint32Value()); -            uint32_t access_flags = field->GetAccessFlags(); -            if (access_flags & kAccPublic) { -              info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public); -            } else if (access_flags & kAccProtected) { -              info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_protected); -            } else if (access_flags & kAccPrivate) { -              info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private); -            } -            info_.EndTag();  // DW_TAG_member. -          } - -          if (type->IsStringClass()) { -            // Emit debug info about an artifical class member for java.lang.String which represents -            // the first element of the data stored in a string instance. Consumers of the debug -            // info will be able to read the content of java.lang.String based on the count (real -            // field) and based on the location of this data member. -            info_.StartTag(DW_TAG_member); -            WriteName("value"); -            // We don't support fields with C like array types so we just say its type is java char. -            WriteLazyType("C");  // char. -            info_.WriteUdata(DW_AT_data_member_location, -                             mirror::String::ValueOffset().Uint32Value()); -            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private); -            info_.EndTag();  // DW_TAG_member. -          } - -          EndClassTag(); -        } -      } - -      // Write base class declarations. -      for (const auto& base_class_reference : base_class_references) { -        size_t reference_offset = base_class_reference.first; -        mirror::Class* base_class = base_class_reference.second; -        const auto& it = class_declarations.find(base_class); -        if (it != class_declarations.end()) { -          info_.UpdateUint32(reference_offset, it->second); -        } else { -          // Declare base class.  We can not use the standard WriteLazyType -          // since we want to avoid the DW_TAG_reference_tag wrapping. -          std::string tmp_storage; -          const char* base_class_desc = base_class->GetDescriptor(&tmp_storage); -          size_t base_class_declaration_offset = StartClassTag(base_class_desc); -          info_.WriteFlagPresent(DW_AT_declaration); -          WriteLinkageName(base_class); -          EndClassTag(); -          class_declarations.emplace(base_class, base_class_declaration_offset); -          info_.UpdateUint32(reference_offset, base_class_declaration_offset); -        } -      } - -      FinishLazyTypes(); -      CloseNamespacesAboveDepth(0); -      info_.EndTag();  // DW_TAG_compile_unit. -      CHECK_EQ(info_.Depth(), 0); -      std::vector<uint8_t> buffer; -      buffer.reserve(info_.data()->size() + KB); -      const size_t offset = owner_->builder_->GetDebugInfo()->GetSize(); -      // All compilation units share single table which is at the start of .debug_abbrev. -      const size_t debug_abbrev_offset = 0; -      WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_); -      owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size()); -    } - -    // Linkage name uniquely identifies type. -    // It is used to determine the dynamic type of objects. -    // We use the methods_ field of class since it is unique and it is not moved by the GC. -    void WriteLinkageName(mirror::Class* type) SHARED_REQUIRES(Locks::mutator_lock_) { -      auto* methods_ptr = type->GetMethodsPtr(); -      if (methods_ptr == nullptr) { -        // Some types might have no methods.  Allocate empty array instead. -        LinearAlloc* allocator = Runtime::Current()->GetLinearAlloc(); -        void* storage = allocator->Alloc(Thread::Current(), sizeof(LengthPrefixedArray<ArtMethod>)); -        methods_ptr = new (storage) LengthPrefixedArray<ArtMethod>(0); -        type->SetMethodsPtr(methods_ptr, 0, 0); -        DCHECK(type->GetMethodsPtr() != nullptr); -      } -      char name[32]; -      snprintf(name, sizeof(name), "0x%" PRIXPTR, reinterpret_cast<uintptr_t>(methods_ptr)); -      info_.WriteString(DW_AT_linkage_name, name); -    } - -    // Write table into .debug_loc which describes location of dex register. -    // The dex register might be valid only at some points and it might -    // move between machine registers and stack. -    void WriteRegLocation(const MethodDebugInfo* method_info, -                          uint16_t vreg, -                          bool is64bitValue, -                          uint32_t compilation_unit_low_pc, -                          uint32_t dex_pc_low = 0, -                          uint32_t dex_pc_high = 0xFFFFFFFF) { -      using Kind = DexRegisterLocation::Kind; -      if (!IsFromOptimizingCompiler(method_info)) { -        return; -      } - -      Writer<> debug_loc(&owner_->debug_loc_); -      Writer<> debug_ranges(&owner_->debug_ranges_); -      info_.WriteSecOffset(DW_AT_location, debug_loc.size()); -      info_.WriteSecOffset(DW_AT_start_scope, debug_ranges.size()); - -      std::vector<VariableLocation> variable_locations = GetVariableLocations( -          method_info, -          vreg, -          is64bitValue, -          dex_pc_low, -          dex_pc_high); - -      // Write .debug_loc entries. -      const InstructionSet isa = owner_->builder_->GetIsa(); -      const bool is64bit = Is64BitInstructionSet(isa); -      std::vector<uint8_t> expr_buffer; -      for (const VariableLocation& variable_location : variable_locations) { -        // Translate dex register location to DWARF expression. -        // Note that 64-bit value might be split to two distinct locations. -        // (for example, two 32-bit machine registers, or even stack and register) -        Expression expr(&expr_buffer); -        DexRegisterLocation reg_lo = variable_location.reg_lo; -        DexRegisterLocation reg_hi = variable_location.reg_hi; -        for (int piece = 0; piece < (is64bitValue ? 2 : 1); piece++) { -          DexRegisterLocation reg_loc = (piece == 0 ? reg_lo : reg_hi); -          const Kind kind = reg_loc.GetKind(); -          const int32_t value = reg_loc.GetValue(); -          if (kind == Kind::kInStack) { -            const size_t frame_size = method_info->compiled_method_->GetFrameSizeInBytes(); -            // The stack offset is relative to SP. Make it relative to CFA. -            expr.WriteOpFbreg(value - frame_size); -            if (piece == 0 && reg_hi.GetKind() == Kind::kInStack && -                reg_hi.GetValue() == value + 4) { -              break;  // the high word is correctly implied by the low word. -            } -          } else if (kind == Kind::kInRegister) { -            expr.WriteOpReg(GetDwarfCoreReg(isa, value).num()); -            if (piece == 0 && reg_hi.GetKind() == Kind::kInRegisterHigh && -                reg_hi.GetValue() == value) { -              break;  // the high word is correctly implied by the low word. -            } -          } else if (kind == Kind::kInFpuRegister) { -            if ((isa == kArm || isa == kThumb2) && -                piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegister && -                reg_hi.GetValue() == value + 1 && value % 2 == 0) { -              // Translate S register pair to D register (e.g. S4+S5 to D2). -              expr.WriteOpReg(Reg::ArmDp(value / 2).num()); -              break; -            } -            expr.WriteOpReg(GetDwarfFpReg(isa, value).num()); -            if (piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegisterHigh && -                reg_hi.GetValue() == reg_lo.GetValue()) { -              break;  // the high word is correctly implied by the low word. -            } -          } else if (kind == Kind::kConstant) { -            expr.WriteOpConsts(value); -            expr.WriteOpStackValue(); -          } else if (kind == Kind::kNone) { -            break; -          } else { -            // kInStackLargeOffset and kConstantLargeValue are hidden by GetKind(). -            // kInRegisterHigh and kInFpuRegisterHigh should be handled by -            // the special cases above and they should not occur alone. -            LOG(ERROR) << "Unexpected register location kind: " -                       << DexRegisterLocation::PrettyDescriptor(kind); -            break; -          } -          if (is64bitValue) { -            // Write the marker which is needed by split 64-bit values. -            // This code is skipped by the special cases. -            expr.WriteOpPiece(4); -          } -        } - -        if (expr.size() > 0) { -          if (is64bit) { -            debug_loc.PushUint64(variable_location.low_pc - compilation_unit_low_pc); -            debug_loc.PushUint64(variable_location.high_pc - compilation_unit_low_pc); -          } else { -            debug_loc.PushUint32(variable_location.low_pc - compilation_unit_low_pc); -            debug_loc.PushUint32(variable_location.high_pc - compilation_unit_low_pc); -          } -          // Write the expression. -          debug_loc.PushUint16(expr.size()); -          debug_loc.PushData(expr.data()); -        } else { -          // Do not generate .debug_loc if the location is not known. -        } -      } -      // Write end-of-list entry. -      if (is64bit) { -        debug_loc.PushUint64(0); -        debug_loc.PushUint64(0); -      } else { -        debug_loc.PushUint32(0); -        debug_loc.PushUint32(0); -      } - -      // Write .debug_ranges entries. -      // This includes ranges where the variable is in scope but the location is not known. -      for (size_t i = 0; i < variable_locations.size(); i++) { -        uint32_t low_pc = variable_locations[i].low_pc; -        uint32_t high_pc = variable_locations[i].high_pc; -        while (i + 1 < variable_locations.size() && variable_locations[i+1].low_pc == high_pc) { -          // Merge address range with the next entry. -          high_pc = variable_locations[++i].high_pc; -        } -        if (is64bit) { -          debug_ranges.PushUint64(low_pc - compilation_unit_low_pc); -          debug_ranges.PushUint64(high_pc - compilation_unit_low_pc); -        } else { -          debug_ranges.PushUint32(low_pc - compilation_unit_low_pc); -          debug_ranges.PushUint32(high_pc - compilation_unit_low_pc); -        } -      } -      // Write end-of-list entry. -      if (is64bit) { -        debug_ranges.PushUint64(0); -        debug_ranges.PushUint64(0); -      } else { -        debug_ranges.PushUint32(0); -        debug_ranges.PushUint32(0); -      } -    } - -    // Some types are difficult to define as we go since they need -    // to be enclosed in the right set of namespaces. Therefore we -    // just define all types lazily at the end of compilation unit. -    void WriteLazyType(const char* type_descriptor) { -      if (type_descriptor != nullptr && type_descriptor[0] != 'V') { -        lazy_types_.emplace(std::string(type_descriptor), info_.size()); -        info_.WriteRef4(DW_AT_type, 0); -      } -    } - -    void FinishLazyTypes() { -      for (const auto& lazy_type : lazy_types_) { -        info_.UpdateUint32(lazy_type.second, WriteTypeDeclaration(lazy_type.first)); -      } -      lazy_types_.clear(); -    } - -   private: -    void WriteName(const char* name) { -      if (name != nullptr) { -        info_.WriteString(DW_AT_name, name); -      } -    } - -    // Convert dex type descriptor to DWARF. -    // Returns offset in the compilation unit. -    size_t WriteTypeDeclaration(const std::string& desc) { -      DCHECK(!desc.empty()); -      const auto& it = type_cache_.find(desc); -      if (it != type_cache_.end()) { -        return it->second; -      } - -      size_t offset; -      if (desc[0] == 'L') { -        // Class type. For example: Lpackage/name; -        size_t class_offset = StartClassTag(desc.c_str()); -        info_.WriteFlagPresent(DW_AT_declaration); -        EndClassTag(); -        // Reference to the class type. -        offset = info_.StartTag(DW_TAG_reference_type); -        info_.WriteRef(DW_AT_type, class_offset); -        info_.EndTag(); -      } else if (desc[0] == '[') { -        // Array type. -        size_t element_type = WriteTypeDeclaration(desc.substr(1)); -        CloseNamespacesAboveDepth(0);  // Declare in root namespace. -        size_t array_type = info_.StartTag(DW_TAG_array_type); -        info_.WriteFlagPresent(DW_AT_declaration); -        info_.WriteRef(DW_AT_type, element_type); -        info_.EndTag(); -        offset = info_.StartTag(DW_TAG_reference_type); -        info_.WriteRef4(DW_AT_type, array_type); -        info_.EndTag(); -      } else { -        // Primitive types. -        DCHECK_EQ(desc.size(), 1u); - -        const char* name; -        uint32_t encoding; -        uint32_t byte_size; -        switch (desc[0]) { -        case 'B': -          name = "byte"; -          encoding = DW_ATE_signed; -          byte_size = 1; -          break; -        case 'C': -          name = "char"; -          encoding = DW_ATE_UTF; -          byte_size = 2; -          break; -        case 'D': -          name = "double"; -          encoding = DW_ATE_float; -          byte_size = 8; -          break; -        case 'F': -          name = "float"; -          encoding = DW_ATE_float; -          byte_size = 4; -          break; -        case 'I': -          name = "int"; -          encoding = DW_ATE_signed; -          byte_size = 4; -          break; -        case 'J': -          name = "long"; -          encoding = DW_ATE_signed; -          byte_size = 8; -          break; -        case 'S': -          name = "short"; -          encoding = DW_ATE_signed; -          byte_size = 2; -          break; -        case 'Z': -          name = "boolean"; -          encoding = DW_ATE_boolean; -          byte_size = 1; -          break; -        case 'V': -          LOG(FATAL) << "Void type should not be encoded"; -          UNREACHABLE(); -        default: -          LOG(FATAL) << "Unknown dex type descriptor: \"" << desc << "\""; -          UNREACHABLE(); -        } -        CloseNamespacesAboveDepth(0);  // Declare in root namespace. -        offset = info_.StartTag(DW_TAG_base_type); -        WriteName(name); -        info_.WriteData1(DW_AT_encoding, encoding); -        info_.WriteData1(DW_AT_byte_size, byte_size); -        info_.EndTag(); -      } - -      type_cache_.emplace(desc, offset); -      return offset; -    } - -    // Start DW_TAG_class_type tag nested in DW_TAG_namespace tags. -    // Returns offset of the class tag in the compilation unit. -    size_t StartClassTag(const char* desc) { -      std::string name = SetNamespaceForClass(desc); -      size_t offset = info_.StartTag(DW_TAG_class_type); -      WriteName(name.c_str()); -      return offset; -    } - -    void EndClassTag() { -      info_.EndTag(); -    } - -    // Set the current namespace nesting to one required by the given class. -    // Returns the class name with namespaces, 'L', and ';' stripped. -    std::string SetNamespaceForClass(const char* desc) { -      DCHECK(desc != nullptr && desc[0] == 'L'); -      desc++;  // Skip the initial 'L'. -      size_t depth = 0; -      for (const char* end; (end = strchr(desc, '/')) != nullptr; desc = end + 1, ++depth) { -        // Check whether the name at this depth is already what we need. -        if (depth < current_namespace_.size()) { -          const std::string& name = current_namespace_[depth]; -          if (name.compare(0, name.size(), desc, end - desc) == 0) { -            continue; -          } -        } -        // Otherwise we need to open a new namespace tag at this depth. -        CloseNamespacesAboveDepth(depth); -        info_.StartTag(DW_TAG_namespace); -        std::string name(desc, end - desc); -        WriteName(name.c_str()); -        current_namespace_.push_back(std::move(name)); -      } -      CloseNamespacesAboveDepth(depth); -      return std::string(desc, strchr(desc, ';') - desc); -    } - -    // Close namespace tags to reach the given nesting depth. -    void CloseNamespacesAboveDepth(size_t depth) { -      DCHECK_LE(depth, current_namespace_.size()); -      while (current_namespace_.size() > depth) { -        info_.EndTag(); -        current_namespace_.pop_back(); -      } -    } - -    // For access to the ELF sections. -    DebugInfoWriter<ElfTypes>* owner_; -    // Temporary buffer to create and store the entries. -    DebugInfoEntryWriter<> info_; -    // Cache of already translated type descriptors. -    std::map<std::string, size_t> type_cache_;  // type_desc -> definition_offset. -    // 32-bit references which need to be resolved to a type later. -    // Given type may be used multiple times.  Therefore we need a multimap. -    std::multimap<std::string, size_t> lazy_types_;  // type_desc -> patch_offset. -    // The current set of open namespace tags which are active and not closed yet. -    std::vector<std::string> current_namespace_; -  }; - - public: -  explicit DebugInfoWriter(ElfBuilder<ElfTypes>* builder) -      : builder_(builder), -        debug_abbrev_(&debug_abbrev_buffer_) { -  } - -  void Start() { -    builder_->GetDebugInfo()->Start(); -  } - -  void WriteCompilationUnit(const CompilationUnit& compilation_unit) { -    CompilationUnitWriter writer(this); -    writer.Write(compilation_unit); -  } - -  void WriteTypes(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) { -    CompilationUnitWriter writer(this); -    writer.Write(types); -  } - -  void End(bool write_oat_patches) { -    builder_->GetDebugInfo()->End(); -    if (write_oat_patches) { -      builder_->WritePatches(".debug_info.oat_patches", -                             ArrayRef<const uintptr_t>(debug_info_patches_)); -    } -    builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_); -    if (!debug_loc_.empty()) { -      builder_->WriteSection(".debug_loc", &debug_loc_); -    } -    if (!debug_ranges_.empty()) { -      builder_->WriteSection(".debug_ranges", &debug_ranges_); -    } -  } - - private: -  ElfBuilder<ElfTypes>* builder_; -  std::vector<uintptr_t> debug_info_patches_; -  std::vector<uint8_t> debug_abbrev_buffer_; -  DebugAbbrevWriter<> debug_abbrev_; -  std::vector<uint8_t> debug_loc_; -  std::vector<uint8_t> debug_ranges_; - -  std::unordered_set<const char*> defined_dex_classes_;  // For CHECKs only. -}; - -template<typename ElfTypes> -class DebugLineWriter { -  typedef typename ElfTypes::Addr Elf_Addr; - - public: -  explicit DebugLineWriter(ElfBuilder<ElfTypes>* builder) : builder_(builder) { -  } - -  void Start() { -    builder_->GetDebugLine()->Start(); -  } - -  // Write line table for given set of methods. -  // Returns the number of bytes written. -  size_t WriteCompilationUnit(CompilationUnit& compilation_unit) { -    const bool is64bit = Is64BitInstructionSet(builder_->GetIsa()); -    const Elf_Addr text_address = builder_->GetText()->Exists() -        ? builder_->GetText()->GetAddress() -        : 0; - -    compilation_unit.debug_line_offset_ = builder_->GetDebugLine()->GetSize(); - -    std::vector<FileEntry> files; -    std::unordered_map<std::string, size_t> files_map; -    std::vector<std::string> directories; -    std::unordered_map<std::string, size_t> directories_map; -    int code_factor_bits_ = 0; -    int dwarf_isa = -1; -    switch (builder_->GetIsa()) { -      case kArm:  // arm actually means thumb2. -      case kThumb2: -        code_factor_bits_ = 1;  // 16-bit instuctions -        dwarf_isa = 1;  // DW_ISA_ARM_thumb. -        break; -      case kArm64: -      case kMips: -      case kMips64: -        code_factor_bits_ = 2;  // 32-bit instructions -        break; -      case kNone: -      case kX86: -      case kX86_64: -        break; -    } -    DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits_); -    for (const MethodDebugInfo* mi : compilation_unit.methods_) { -      // Ignore function if we have already generated line table for the same address. -      // It would confuse the debugger and the DWARF specification forbids it. -      if (mi->deduped_) { -        continue; -      } - -      ArrayRef<const SrcMapElem> src_mapping_table; -      std::vector<SrcMapElem> src_mapping_table_from_stack_maps; -      if (IsFromOptimizingCompiler(mi)) { -        // Use stack maps to create mapping table from pc to dex. -        const CodeInfo code_info(mi->compiled_method_->GetVmapTable().data()); -        const StackMapEncoding encoding = code_info.ExtractEncoding(); -        for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) { -          StackMap stack_map = code_info.GetStackMapAt(s, encoding); -          DCHECK(stack_map.IsValid()); -          // Emit only locations where we have local-variable information. -          // In particular, skip mappings inside the prologue. -          if (stack_map.HasDexRegisterMap(encoding)) { -            const uint32_t pc = stack_map.GetNativePcOffset(encoding); -            const int32_t dex = stack_map.GetDexPc(encoding); -            src_mapping_table_from_stack_maps.push_back({pc, dex}); -          } -        } -        std::sort(src_mapping_table_from_stack_maps.begin(), -                  src_mapping_table_from_stack_maps.end()); -        src_mapping_table = ArrayRef<const SrcMapElem>(src_mapping_table_from_stack_maps); -      } else { -        // Use the mapping table provided by the quick compiler. -        src_mapping_table = mi->compiled_method_->GetSrcMappingTable(); -      } - -      if (src_mapping_table.empty()) { -        continue; -      } - -      Elf_Addr method_address = text_address + mi->low_pc_; - -      PositionInfos position_infos; -      const DexFile* dex = mi->dex_file_; -      if (!dex->DecodeDebugPositionInfo(mi->code_item_, PositionInfoCallback, &position_infos)) { -        continue; -      } - -      if (position_infos.empty()) { -        continue; -      } - -      opcodes.SetAddress(method_address); -      if (dwarf_isa != -1) { -        opcodes.SetISA(dwarf_isa); -      } - -      // Get and deduplicate directory and filename. -      int file_index = 0;  // 0 - primary source file of the compilation. -      auto& dex_class_def = dex->GetClassDef(mi->class_def_index_); -      const char* source_file = dex->GetSourceFile(dex_class_def); -      if (source_file != nullptr) { -        std::string file_name(source_file); -        size_t file_name_slash = file_name.find_last_of('/'); -        std::string class_name(dex->GetClassDescriptor(dex_class_def)); -        size_t class_name_slash = class_name.find_last_of('/'); -        std::string full_path(file_name); - -        // Guess directory from package name. -        int directory_index = 0;  // 0 - current directory of the compilation. -        if (file_name_slash == std::string::npos &&  // Just filename. -            class_name.front() == 'L' &&  // Type descriptor for a class. -            class_name_slash != std::string::npos) {  // Has package name. -          std::string package_name = class_name.substr(1, class_name_slash - 1); -          auto it = directories_map.find(package_name); -          if (it == directories_map.end()) { -            directory_index = 1 + directories.size(); -            directories_map.emplace(package_name, directory_index); -            directories.push_back(package_name); -          } else { -            directory_index = it->second; -          } -          full_path = package_name + "/" + file_name; -        } - -        // Add file entry. -        auto it2 = files_map.find(full_path); -        if (it2 == files_map.end()) { -          file_index = 1 + files.size(); -          files_map.emplace(full_path, file_index); -          files.push_back(FileEntry { -            file_name, -            directory_index, -            0,  // Modification time - NA. -            0,  // File size - NA. -          }); -        } else { -          file_index = it2->second; -        } -      } -      opcodes.SetFile(file_index); - -      // Generate mapping opcodes from PC to Java lines. -      if (file_index != 0) { -        bool first = true; -        for (SrcMapElem pc2dex : src_mapping_table) { -          uint32_t pc = pc2dex.from_; -          int dex_pc = pc2dex.to_; -          // Find mapping with address with is greater than our dex pc; then go back one step. -          auto ub = std::upper_bound(position_infos.begin(), position_infos.end(), dex_pc, -              [](uint32_t address, const DexFile::PositionInfo& entry) { -                  return address < entry.address_; -              }); -          if (ub != position_infos.begin()) { -            int line = (--ub)->line_; -            if (first) { -              first = false; -              if (pc > 0) { -                // Assume that any preceding code is prologue. -                int first_line = position_infos.front().line_; -                // Prologue is not a sensible place for a breakpoint. -                opcodes.NegateStmt(); -                opcodes.AddRow(method_address, first_line); -                opcodes.NegateStmt(); -                opcodes.SetPrologueEnd(); -              } -              opcodes.AddRow(method_address + pc, line); -            } else if (line != opcodes.CurrentLine()) { -              opcodes.AddRow(method_address + pc, line); -            } -          } -        } -      } else { -        // line 0 - instruction cannot be attributed to any source line. -        opcodes.AddRow(method_address, 0); -      } - -      opcodes.AdvancePC(text_address + mi->high_pc_); -      opcodes.EndSequence(); -    } -    std::vector<uint8_t> buffer; -    buffer.reserve(opcodes.data()->size() + KB); -    size_t offset = builder_->GetDebugLine()->GetSize(); -    WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches); -    builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size()); -    return buffer.size(); -  } - -  void End(bool write_oat_patches) { -    builder_->GetDebugLine()->End(); -    if (write_oat_patches) { -      builder_->WritePatches(".debug_line.oat_patches", -                             ArrayRef<const uintptr_t>(debug_line_patches)); -    } -  } - - private: -  ElfBuilder<ElfTypes>* builder_; -  std::vector<uintptr_t> debug_line_patches; -}; - -template<typename ElfTypes> -static void WriteDebugSections(ElfBuilder<ElfTypes>* builder, -                               const ArrayRef<const MethodDebugInfo>& method_infos, -                               bool write_oat_patches) { -  // Group the methods into compilation units based on source file. -  std::vector<CompilationUnit> compilation_units; -  const char* last_source_file = nullptr; -  for (const MethodDebugInfo& mi : method_infos) { -    auto& dex_class_def = mi.dex_file_->GetClassDef(mi.class_def_index_); -    const char* source_file = mi.dex_file_->GetSourceFile(dex_class_def); -    if (compilation_units.empty() || source_file != last_source_file) { -      compilation_units.push_back(CompilationUnit()); -    } -    CompilationUnit& cu = compilation_units.back(); -    cu.methods_.push_back(&mi); -    cu.low_pc_ = std::min(cu.low_pc_, mi.low_pc_); -    cu.high_pc_ = std::max(cu.high_pc_, mi.high_pc_); -    last_source_file = source_file; -  } - -  // Write .debug_line section. -  if (!compilation_units.empty()) { -    DebugLineWriter<ElfTypes> line_writer(builder); -    line_writer.Start(); -    for (auto& compilation_unit : compilation_units) { -      line_writer.WriteCompilationUnit(compilation_unit); -    } -    line_writer.End(write_oat_patches); -  } - -  // Write .debug_info section. -  if (!compilation_units.empty()) { -    DebugInfoWriter<ElfTypes> info_writer(builder); -    info_writer.Start(); -    for (const auto& compilation_unit : compilation_units) { -      info_writer.WriteCompilationUnit(compilation_unit); -    } -    info_writer.End(write_oat_patches); -  } -} - -template <typename ElfTypes> -static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, -                              const ArrayRef<const MethodDebugInfo>& method_infos, -                              bool with_signature) { -  bool generated_mapping_symbol = false; -  auto* strtab = builder->GetStrTab(); -  auto* symtab = builder->GetSymTab(); - -  if (method_infos.empty()) { -    return; -  } - -  // Find all addresses (low_pc) which contain deduped methods. -  // The first instance of method is not marked deduped_, but the rest is. -  std::unordered_set<uint32_t> deduped_addresses; -  for (const MethodDebugInfo& info : method_infos) { -    if (info.deduped_) { -      deduped_addresses.insert(info.low_pc_); -    } -  } - -  strtab->Start(); -  strtab->Write("");  // strtab should start with empty string. -  std::string last_name; -  size_t last_name_offset = 0; -  for (const MethodDebugInfo& info : method_infos) { -    if (info.deduped_) { -      continue;  // Add symbol only for the first instance. -    } -    std::string name = PrettyMethod(info.dex_method_index_, *info.dex_file_, with_signature); -    if (deduped_addresses.find(info.low_pc_) != deduped_addresses.end()) { -      name += " [DEDUPED]"; -    } -    // If we write method names without signature, we might see the same name multiple times. -    size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name)); - -    const auto* text = builder->GetText()->Exists() ? builder->GetText() : nullptr; -    const bool is_relative = (text != nullptr); -    uint32_t low_pc = info.low_pc_; -    // Add in code delta, e.g., thumb bit 0 for Thumb2 code. -    low_pc += info.compiled_method_->CodeDelta(); -    symtab->Add(name_offset, -                text, -                low_pc, -                is_relative, -                info.high_pc_ - info.low_pc_, -                STB_GLOBAL, -                STT_FUNC); - -    // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2 -    // instructions, so that disassembler tools can correctly disassemble. -    // Note that even if we generate just a single mapping symbol, ARM's Streamline -    // requires it to match function symbol.  Just address 0 does not work. -    if (info.compiled_method_->GetInstructionSet() == kThumb2) { -      if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) { -        symtab->Add(strtab->Write("$t"), text, info.low_pc_ & ~1, -                    is_relative, 0, STB_LOCAL, STT_NOTYPE); -        generated_mapping_symbol = true; -      } -    } - -    last_name = std::move(name); -    last_name_offset = name_offset; -  } -  strtab->End(); - -  // Symbols are buffered and written after names (because they are smaller). -  // We could also do two passes in this function to avoid the buffering. -  symtab->Start(); -  symtab->Write(); -  symtab->End(); -} - -template <typename ElfTypes> -void WriteDebugInfo(ElfBuilder<ElfTypes>* builder, -                    const ArrayRef<const MethodDebugInfo>& method_infos, -                    CFIFormat cfi_format, -                    bool write_oat_patches) { -  // Add methods to .symtab. -  WriteDebugSymbols(builder, method_infos, true /* with_signature */); -  // Generate CFI (stack unwinding information). -  WriteCFISection(builder, method_infos, cfi_format, write_oat_patches); -  // Write DWARF .debug_* sections. -  WriteDebugSections(builder, method_infos, write_oat_patches); -} - -static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* dst) { -  // Configure the compression library. -  CrcGenerateTable(); -  Crc64GenerateTable(); -  CLzma2EncProps lzma2Props; -  Lzma2EncProps_Init(&lzma2Props); -  lzma2Props.lzmaProps.level = 1;  // Fast compression. -  Lzma2EncProps_Normalize(&lzma2Props); -  CXzProps props; -  XzProps_Init(&props); -  props.lzma2Props = &lzma2Props; -  // Implement the required interface for communication (written in C so no virtual methods). -  struct XzCallbacks : public ISeqInStream, public ISeqOutStream, public ICompressProgress { -    static SRes ReadImpl(void* p, void* buf, size_t* size) { -      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqInStream*>(p)); -      *size = std::min(*size, ctx->src_->size() - ctx->src_pos_); -      memcpy(buf, ctx->src_->data() + ctx->src_pos_, *size); -      ctx->src_pos_ += *size; -      return SZ_OK; -    } -    static size_t WriteImpl(void* p, const void* buf, size_t size) { -      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqOutStream*>(p)); -      const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buf); -      ctx->dst_->insert(ctx->dst_->end(), buffer, buffer + size); -      return size; -    } -    static SRes ProgressImpl(void* , UInt64, UInt64) { -      return SZ_OK; -    } -    size_t src_pos_; -    const std::vector<uint8_t>* src_; -    std::vector<uint8_t>* dst_; -  }; -  XzCallbacks callbacks; -  callbacks.Read = XzCallbacks::ReadImpl; -  callbacks.Write = XzCallbacks::WriteImpl; -  callbacks.Progress = XzCallbacks::ProgressImpl; -  callbacks.src_pos_ = 0; -  callbacks.src_ = src; -  callbacks.dst_ = dst; -  // Compress. -  SRes res = Xz_Encode(&callbacks, &callbacks, &props, &callbacks); -  CHECK_EQ(res, SZ_OK); -} - -template <typename ElfTypes> -std::vector<uint8_t> MakeMiniDebugInfoInternal( -    InstructionSet isa, -    size_t rodata_section_size, -    size_t text_section_size, -    const ArrayRef<const MethodDebugInfo>& method_infos) { -  std::vector<uint8_t> buffer; -  buffer.reserve(KB); -  VectorOutputStream out("Mini-debug-info ELF file", &buffer); -  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); -  builder->Start(); -  // Mirror .rodata and .text as NOBITS sections. -  // It is needed to detected relocations after compression. -  builder->GetRoData()->WriteNoBitsSection(rodata_section_size); -  builder->GetText()->WriteNoBitsSection(text_section_size); -  WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */); -  WriteCFISection(builder.get(), method_infos, DW_DEBUG_FRAME_FORMAT, false /* write_oat_paches */); -  builder->End(); -  CHECK(builder->Good()); -  std::vector<uint8_t> compressed_buffer; -  compressed_buffer.reserve(buffer.size() / 4); -  XzCompress(&buffer, &compressed_buffer); -  return compressed_buffer; -} - -std::vector<uint8_t> MakeMiniDebugInfo( -    InstructionSet isa, -    size_t rodata_size, -    size_t text_size, -    const ArrayRef<const MethodDebugInfo>& method_infos) { -  if (Is64BitInstructionSet(isa)) { -    return MakeMiniDebugInfoInternal<ElfTypes64>(isa, rodata_size, text_size, method_infos); -  } else { -    return MakeMiniDebugInfoInternal<ElfTypes32>(isa, rodata_size, text_size, method_infos); -  } -} - -template <typename ElfTypes> -static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal( -    const dwarf::MethodDebugInfo& method_info) { -  const InstructionSet isa = method_info.compiled_method_->GetInstructionSet(); -  std::vector<uint8_t> buffer; -  buffer.reserve(KB); -  VectorOutputStream out("Debug ELF file", &buffer); -  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); -  // No program headers since the ELF file is not linked and has no allocated sections. -  builder->Start(false /* write_program_headers */); -  WriteDebugInfo(builder.get(), -                 ArrayRef<const MethodDebugInfo>(&method_info, 1), -                 DW_DEBUG_FRAME_FORMAT, -                 false /* write_oat_patches */); -  builder->End(); -  CHECK(builder->Good()); -  // Make a copy of the buffer.  We want to shrink it anyway. -  uint8_t* result = new uint8_t[buffer.size()]; -  CHECK(result != nullptr); -  memcpy(result, buffer.data(), buffer.size()); -  return ArrayRef<const uint8_t>(result, buffer.size()); -} - -ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info) { -  const InstructionSet isa = method_info.compiled_method_->GetInstructionSet(); -  if (Is64BitInstructionSet(isa)) { -    return WriteDebugElfFileForMethodInternal<ElfTypes64>(method_info); -  } else { -    return WriteDebugElfFileForMethodInternal<ElfTypes32>(method_info); -  } -} - -template <typename ElfTypes> -static ArrayRef<const uint8_t> WriteDebugElfFileForClassesInternal( -    const InstructionSet isa, const ArrayRef<mirror::Class*>& types) -    SHARED_REQUIRES(Locks::mutator_lock_) { -  std::vector<uint8_t> buffer; -  buffer.reserve(KB); -  VectorOutputStream out("Debug ELF file", &buffer); -  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); -  // No program headers since the ELF file is not linked and has no allocated sections. -  builder->Start(false /* write_program_headers */); -  DebugInfoWriter<ElfTypes> info_writer(builder.get()); -  info_writer.Start(); -  info_writer.WriteTypes(types); -  info_writer.End(false /* write_oat_patches */); - -  builder->End(); -  CHECK(builder->Good()); -  // Make a copy of the buffer.  We want to shrink it anyway. -  uint8_t* result = new uint8_t[buffer.size()]; -  CHECK(result != nullptr); -  memcpy(result, buffer.data(), buffer.size()); -  return ArrayRef<const uint8_t>(result, buffer.size()); -} - -ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa, -                                                    const ArrayRef<mirror::Class*>& types) { -  if (Is64BitInstructionSet(isa)) { -    return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, types); -  } else { -    return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, types); -  } -} - -// Explicit instantiations -template void WriteDebugInfo<ElfTypes32>( -    ElfBuilder<ElfTypes32>* builder, -    const ArrayRef<const MethodDebugInfo>& method_infos, -    CFIFormat cfi_format, -    bool write_oat_patches); -template void WriteDebugInfo<ElfTypes64>( -    ElfBuilder<ElfTypes64>* builder, -    const ArrayRef<const MethodDebugInfo>& method_infos, -    CFIFormat cfi_format, -    bool write_oat_patches); - -}  // namespace dwarf -}  // namespace art diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h index 7da8fb7952..6b3dd8c528 100644 --- a/compiler/debug/method_debug_info.h +++ b/compiler/debug/method_debug_info.h @@ -17,25 +17,32 @@  #ifndef ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_  #define ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_ +#include "compiled_method.h"  #include "dex_file.h"  namespace art { -class CompiledMethod; -namespace dwarf { +namespace debug {  struct MethodDebugInfo { -  const DexFile* dex_file_; -  size_t class_def_index_; -  uint32_t dex_method_index_; -  uint32_t access_flags_; -  const DexFile::CodeItem* code_item_; -  bool deduped_; -  uintptr_t low_pc_; -  uintptr_t high_pc_; -  CompiledMethod* compiled_method_; +  const DexFile* dex_file; +  size_t class_def_index; +  uint32_t dex_method_index; +  uint32_t access_flags; +  const DexFile::CodeItem* code_item; +  bool deduped; +  uintptr_t low_pc; +  uintptr_t high_pc; +  CompiledMethod* compiled_method; + +  bool IsFromOptimizingCompiler() const { +    return compiled_method->GetQuickCode().size() > 0 && +           compiled_method->GetVmapTable().size() > 0 && +           compiled_method->GetGcMap().size() == 0 && +           code_item != nullptr; +  }  }; -}  // namespace dwarf +}  // namespace debug  }  // namespace art  #endif  // ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_ diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h index 5dbf7360f8..d50a08cb20 100644 --- a/compiler/elf_writer.h +++ b/compiler/elf_writer.h @@ -32,9 +32,9 @@ namespace art {  class ElfFile;  class OutputStream; -namespace dwarf { +namespace debug {  struct MethodDebugInfo; -}  // namespace dwarf +}  // namespace debug  class ElfWriter {   public: @@ -54,14 +54,14 @@ class ElfWriter {    virtual void Start() = 0;    virtual void PrepareDebugInfo(size_t rodata_section_size,                                  size_t text_section_size, -                                const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) = 0; +                                const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;    virtual OutputStream* StartRoData() = 0;    virtual void EndRoData(OutputStream* rodata) = 0;    virtual OutputStream* StartText() = 0;    virtual void EndText(OutputStream* text) = 0;    virtual void SetBssSize(size_t bss_size) = 0;    virtual void WriteDynamicSection() = 0; -  virtual void WriteDebugInfo(const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) = 0; +  virtual void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;    virtual void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) = 0;    virtual bool End() = 0; diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index e5dfe68ea6..1d71e572d7 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -23,7 +23,7 @@  #include "base/logging.h"  #include "base/stl_util.h"  #include "compiled_method.h" -#include "debug/elf_writer_debug.h" +#include "debug/elf_debug_writer.h"  #include "debug/method_debug_info.h"  #include "driver/compiler_options.h"  #include "elf.h" @@ -53,7 +53,7 @@ class DebugInfoTask : public Task {    DebugInfoTask(InstructionSet isa,                  size_t rodata_section_size,                  size_t text_section_size, -                const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) +                const ArrayRef<const debug::MethodDebugInfo>& method_infos)        : isa_(isa),          rodata_section_size_(rodata_section_size),          text_section_size_(text_section_size), @@ -61,7 +61,7 @@ class DebugInfoTask : public Task {    }    void Run(Thread*) { -    result_ = dwarf::MakeMiniDebugInfo(isa_, +    result_ = debug::MakeMiniDebugInfo(isa_,                                         rodata_section_size_,                                         text_section_size_,                                         method_infos_); @@ -75,7 +75,7 @@ class DebugInfoTask : public Task {    InstructionSet isa_;    size_t rodata_section_size_;    size_t text_section_size_; -  const ArrayRef<const dwarf::MethodDebugInfo>& method_infos_; +  const ArrayRef<const debug::MethodDebugInfo>& method_infos_;    std::vector<uint8_t> result_;  }; @@ -90,14 +90,14 @@ class ElfWriterQuick FINAL : public ElfWriter {    void Start() OVERRIDE;    void PrepareDebugInfo(size_t rodata_section_size,                          size_t text_section_size, -                        const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) OVERRIDE; +                        const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;    OutputStream* StartRoData() OVERRIDE;    void EndRoData(OutputStream* rodata) OVERRIDE;    OutputStream* StartText() OVERRIDE;    void EndText(OutputStream* text) OVERRIDE;    void SetBssSize(size_t bss_size) OVERRIDE;    void WriteDynamicSection() OVERRIDE; -  void WriteDebugInfo(const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) OVERRIDE; +  void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;    void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) OVERRIDE;    bool End() OVERRIDE; @@ -188,7 +188,7 @@ template <typename ElfTypes>  void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(      size_t rodata_section_size,      size_t text_section_size, -    const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) { +    const ArrayRef<const debug::MethodDebugInfo>& method_infos) {    if (!method_infos.empty() && compiler_options_->GetGenerateMiniDebugInfo()) {      // Prepare the mini-debug-info in background while we do other I/O.      Thread* self = Thread::Current(); @@ -206,11 +206,11 @@ void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(  template <typename ElfTypes>  void ElfWriterQuick<ElfTypes>::WriteDebugInfo( -    const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) { +    const ArrayRef<const debug::MethodDebugInfo>& method_infos) {    if (!method_infos.empty()) {      if (compiler_options_->GetGenerateDebugInfo()) {        // Generate all the debug information we can. -      dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat, true /* write_oat_patches */); +      debug::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat, true /* write_oat_patches */);      }      if (compiler_options_->GetGenerateMiniDebugInfo()) {        // Wait for the mini-debug-info generation to finish and write it to disk. diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 339ed7375f..d2bf6c07c8 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -24,7 +24,7 @@  #include "base/timing_logger.h"  #include "base/unix_file/fd_file.h"  #include "compiler_callbacks.h" -#include "debug/elf_writer_debug.h" +#include "debug/elf_debug_writer.h"  #include "dex/pass_manager.h"  #include "dex/quick_compiler_callbacks.h"  #include "driver/compiler_driver.h" @@ -74,7 +74,7 @@ extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t cou    DCHECK(jit_compiler != nullptr);    if (jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo()) {      const ArrayRef<mirror::Class*> types_array(types, count); -    ArrayRef<const uint8_t> elf_file = dwarf::WriteDebugElfFileForClasses(kRuntimeISA, types_array); +    ArrayRef<const uint8_t> elf_file = debug::WriteDebugElfFileForClasses(kRuntimeISA, types_array);      CreateJITCodeEntry(std::unique_ptr<const uint8_t[]>(elf_file.data()), elf_file.size());    }  } diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 590c0f8707..47dcfd56f8 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -811,7 +811,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {          // Record debug information for this function if we are doing that.          const uint32_t quick_code_start = quick_code_offset -              writer_->oat_header_->GetExecutableOffset() - thumb_offset; -        writer_->method_info_.push_back(dwarf::MethodDebugInfo { +        writer_->method_info_.push_back(debug::MethodDebugInfo {              dex_file_,              class_def_index_,              it.GetMemberIndex(), diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 14c6d5054a..5a55fc6c95 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -43,9 +43,9 @@ class TimingLogger;  class TypeLookupTable;  class ZipEntry; -namespace dwarf { +namespace debug {  struct MethodDebugInfo; -}  // namespace dwarf +}  // namespace debug  // OatHeader         variable length with count of D OatDexFiles  // @@ -193,8 +193,8 @@ class OatWriter {    ~OatWriter(); -  ArrayRef<const dwarf::MethodDebugInfo> GetMethodDebugInfo() const { -    return ArrayRef<const dwarf::MethodDebugInfo>(method_info_); +  ArrayRef<const debug::MethodDebugInfo> GetMethodDebugInfo() const { +    return ArrayRef<const debug::MethodDebugInfo>(method_info_);    }    const CompilerDriver* GetCompilerDriver() { @@ -289,7 +289,7 @@ class OatWriter {    // We need this because we keep plain pointers to the strings' c_str().    std::list<std::string> zipped_dex_file_locations_; -  dchecked_vector<dwarf::MethodDebugInfo> method_info_; +  dchecked_vector<debug::MethodDebugInfo> method_info_;    const CompilerDriver* compiler_driver_;    ImageWriter* image_writer_; diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index d9f993db61..dcd8e7d216 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -45,7 +45,7 @@  #include "compiler.h"  #include "constant_folding.h"  #include "dead_code_elimination.h" -#include "debug/elf_writer_debug.h" +#include "debug/elf_debug_writer.h"  #include "debug/method_debug_info.h"  #include "dex/quick/dex_file_to_method_inliner_map.h"  #include "dex/verification_results.h" @@ -932,7 +932,7 @@ bool OptimizingCompiler::JitCompile(Thread* self,          ArrayRef<const uint8_t>(),  // native_gc_map.          ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()),          ArrayRef<const LinkerPatch>()); -    dwarf::MethodDebugInfo method_debug_info { +    debug::MethodDebugInfo method_debug_info {          dex_file,          class_def_idx,          method_idx, @@ -943,7 +943,7 @@ bool OptimizingCompiler::JitCompile(Thread* self,          code_address + code_allocator.GetSize(),          &compiled_method      }; -    ArrayRef<const uint8_t> elf_file = dwarf::WriteDebugElfFileForMethod(method_debug_info); +    ArrayRef<const uint8_t> elf_file = debug::WriteDebugElfFileForMethod(method_debug_info);      CreateJITCodeEntryForAddress(code_address,                                   std::unique_ptr<const uint8_t[]>(elf_file.data()),                                   elf_file.size());  |