DWARF: Allow compilation units to contain methods out of order.
Test: m test-art-host
Change-Id: I463a413fea3a740d4a8912f138bdccdc09a3d1e4
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index de32351..6c6bd63 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -122,17 +122,39 @@
const Elf_Addr base_address = compilation_unit.is_code_address_text_relative
? owner_->builder_->GetText()->GetAddress()
: 0;
- const uint64_t cu_size = compilation_unit.code_end - compilation_unit.code_address;
+ const bool is64bit = Is64BitInstructionSet(owner_->builder_->GetIsa());
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");
+ // The low_pc acts as base address for several other addresses/ranges.
info_.WriteAddr(DW_AT_low_pc, base_address + compilation_unit.code_address);
- info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size));
info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset);
+ // Write .debug_ranges entries covering code ranges of the whole compilation unit.
+ dwarf::Writer<> debug_ranges(&owner_->debug_ranges_);
+ info_.WriteSecOffset(DW_AT_ranges, owner_->debug_ranges_.size());
+ for (auto mi : compilation_unit.methods) {
+ uint64_t low_pc = mi->code_address - compilation_unit.code_address;
+ uint64_t high_pc = low_pc + mi->code_size;
+ if (is64bit) {
+ debug_ranges.PushUint64(low_pc);
+ debug_ranges.PushUint64(high_pc);
+ } else {
+ debug_ranges.PushUint32(low_pc);
+ debug_ranges.PushUint32(high_pc);
+ }
+ }
+ if (is64bit) {
+ debug_ranges.PushUint64(0); // End of list.
+ debug_ranges.PushUint64(0);
+ } else {
+ debug_ranges.PushUint32(0); // End of list.
+ debug_ranges.PushUint32(0);
+ }
+
const char* last_dex_class_desc = nullptr;
for (auto mi : compilation_unit.methods) {
DCHECK(mi->dex_file != nullptr);
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 7fa6e14..e962d56 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -17,6 +17,7 @@
#include "elf_debug_writer.h"
#include <vector>
+#include <unordered_map>
#include "base/array_ref.h"
#include "debug/dwarf/dwarf_constants.h"
@@ -46,27 +47,42 @@
// Write .debug_frame.
WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
- // Group the methods into compilation units based on source file.
- std::vector<ElfCompilationUnit> compilation_units;
- const char* last_source_file = nullptr;
+ // Group the methods into compilation units based on class.
+ std::unordered_map<const DexFile::ClassDef*, ElfCompilationUnit> class_to_compilation_unit;
for (const MethodDebugInfo& mi : method_infos) {
if (mi.dex_file != nullptr) {
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();
+ ElfCompilationUnit& cu = class_to_compilation_unit[&dex_class_def];
cu.methods.push_back(&mi);
// All methods must have the same addressing mode otherwise the min/max below does not work.
DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
cu.is_code_address_text_relative = mi.is_code_address_text_relative;
cu.code_address = std::min(cu.code_address, mi.code_address);
cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
- last_source_file = source_file;
}
}
+ // Sort compilation units to make the compiler output deterministic.
+ std::vector<ElfCompilationUnit> compilation_units;
+ compilation_units.reserve(class_to_compilation_unit.size());
+ for (auto& it : class_to_compilation_unit) {
+ // The .debug_line section requires the methods to be sorted by code address.
+ std::stable_sort(it.second.methods.begin(),
+ it.second.methods.end(),
+ [](const MethodDebugInfo* a, const MethodDebugInfo* b) {
+ return a->code_address < b->code_address;
+ });
+ compilation_units.push_back(std::move(it.second));
+ }
+ std::sort(compilation_units.begin(),
+ compilation_units.end(),
+ [](ElfCompilationUnit& a, ElfCompilationUnit& b) {
+ // Sort by index of the first method within the method_infos array.
+ // This assumes that the order of method_infos is deterministic.
+ // Code address is not good for sorting due to possible duplicates.
+ return a.methods.front() < b.methods.front();
+ });
+
// Write .debug_line section.
if (!compilation_units.empty()) {
ElfDebugLineWriter<ElfTypes> line_writer(builder);