Generate unique ID for each type during native debugging.
This allows the native debugger to find dynamic types of variables.
Change-Id: I901022b7db7d3c1db9f4b678ebafcb4eefed4ba7
diff --git a/compiler/dwarf/dwarf_constants.h b/compiler/dwarf/dwarf_constants.h
index 3b570e5..0d7951b 100644
--- a/compiler/dwarf/dwarf_constants.h
+++ b/compiler/dwarf/dwarf_constants.h
@@ -200,11 +200,11 @@
DW_AT_data_bit_offset = 0x6b,
DW_AT_const_expr = 0x6c,
DW_AT_enum_class = 0x6d,
+ DW_AT_linkage_name = 0x6e,
#ifdef INCLUDE_DWARF5_VALUES
// Values to be added in Dwarf 5. Final value not yet specified. Values listed
// may be different than other implementations. Use with caution.
// TODO Update these values when Dwarf 5 is released.
- DW_AT_linkage_name = 0x6e,
DW_AT_call_site_value = 0x6f,
DW_AT_call_site_data_value = 0x70,
DW_AT_call_site_target = 0x71,
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index f3baf67..a64c9f1 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -18,9 +18,11 @@
#include <unordered_set>
#include <vector>
+#include <cstdio>
#include "base/casts.h"
#include "base/stl_util.h"
+#include "linear_alloc.h"
#include "compiled_method.h"
#include "dex_file-inl.h"
#include "driver/compiler_driver.h"
@@ -591,7 +593,7 @@
info_.WriteStrp(DW_AT_producer, owner_->WriteString("Android dex2oat"));
info_.WriteData1(DW_AT_language, DW_LANG_Java);
- std::vector<uint8_t> count_expr_buffer;
+ 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.
@@ -607,16 +609,33 @@
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(&count_expr_buffer);
+ 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 {
+ // Declare base class. We can not use the standard WriteLazyType
+ // since we want to avoid the DW_TAG_reference_tag wrapping.
+ mirror::Class* base_class = type->GetSuperClass();
+ size_t base_class_declaration_offset = 0;
+ if (base_class != nullptr) {
+ std::string tmp_storage;
+ const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
+ base_class_declaration_offset = StartClassTag(base_class_desc);
+ info_.WriteFlag(DW_AT_declaration, true);
+ WriteLinkageName(base_class);
+ EndClassTag(base_class_desc);
+ }
+
std::string descriptor_string;
const char* desc = type->GetDescriptor(&descriptor_string);
StartClassTag(desc);
@@ -625,11 +644,40 @@
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_.WriteFlag(DW_AT_artificial, true);
+ // 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);
- WriteLazyType(base_class->GetDescriptor(&descriptor_string));
+ info_.WriteRef4(DW_AT_type, base_class_declaration_offset);
info_.WriteUdata(DW_AT_data_member_location, 0);
info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
info_.EndTag(); // DW_TAG_inheritance.
@@ -684,6 +732,24 @@
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.
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 3a06b82..6b5ed91 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -706,6 +706,10 @@
ALWAYS_INLINE LengthPrefixedArray<ArtMethod>* GetMethodsPtr()
SHARED_REQUIRES(Locks::mutator_lock_);
+ static MemberOffset MethodsOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(Class, methods_));
+ }
+
ALWAYS_INLINE IterationRange<StrideIterator<ArtMethod>> GetMethods(size_t pointer_size)
SHARED_REQUIRES(Locks::mutator_lock_);
@@ -1357,6 +1361,8 @@
// The slice methods_ [copied_methods_offset_, |methods_|) are the methods that are copied from
// interfaces such as miranda or default methods. These are copied for resolution purposes as this
// class is where they are (logically) declared as far as the virtual dispatch is concerned.
+ //
+ // Note that this field is used by the native debugger as the unique identifier for the type.
uint64_t methods_;
// Static fields length-prefixed array.