Add stack locations to DWARF parameters.

Translate StackMap to DWARF location attributes so that the
debugger knows where to read the run-time value from.

Change-Id: I8b2baf23f37e6e7ff6f76e18077d880f0c1cf57d
diff --git a/compiler/dwarf/debug_info_entry_writer.h b/compiler/dwarf/debug_info_entry_writer.h
index aa31036..a551e4b 100644
--- a/compiler/dwarf/debug_info_entry_writer.h
+++ b/compiler/dwarf/debug_info_entry_writer.h
@@ -112,6 +112,12 @@
     this->PushData(ptr, num_bytes);
   }
 
+  void WriteExprLoc(Attribute attrib, const void* ptr, size_t num_bytes) {
+    AddAbbrevAttribute(attrib, DW_FORM_exprloc);
+    this->PushUleb128(dchecked_integral_cast<uint32_t>(num_bytes));
+    this->PushData(ptr, num_bytes);
+  }
+
   void WriteData1(Attribute attrib, uint8_t value) {
     AddAbbrevAttribute(attrib, DW_FORM_data1);
     this->PushUint8(value);
@@ -132,6 +138,11 @@
     this->PushUint64(value);
   }
 
+  void WriteSecOffset(Attribute attrib, uint32_t offset) {
+    AddAbbrevAttribute(attrib, DW_FORM_sec_offset);
+    this->PushUint32(offset);
+  }
+
   void WriteSdata(Attribute attrib, int value) {
     AddAbbrevAttribute(attrib, DW_FORM_sdata);
     this->PushSleb128(value);
diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h
index c75aeac..f76f76f 100644
--- a/compiler/dwarf/headers.h
+++ b/compiler/dwarf/headers.h
@@ -134,7 +134,7 @@
   Writer<> writer(debug_info);
   size_t start = writer.data()->size();
   writer.PushUint32(0);  // Length placeholder.
-  writer.PushUint16(3);  // Version.
+  writer.PushUint16(4);  // Version.
   writer.PushUint32(debug_abbrev_offset);
   writer.PushUint8(entries.Is64bit() ? 8 : 4);
   size_t entries_offset = writer.data()->size();
@@ -167,10 +167,7 @@
   Writer<> writer(debug_line);
   size_t header_start = writer.data()->size();
   writer.PushUint32(0);  // Section-length placeholder.
-  // Claim DWARF-2 version even though we use some DWARF-3 features.
-  // DWARF-2 consumers will ignore the unknown opcodes.
-  // This is what clang currently does.
-  writer.PushUint16(2);  // .debug_line version.
+  writer.PushUint16(3);  // .debug_line version.
   size_t header_length_pos = writer.data()->size();
   writer.PushUint32(0);  // Header-length placeholder.
   writer.PushUint8(1 << opcodes.GetCodeFactorBits());
diff --git a/compiler/dwarf/register.h b/compiler/dwarf/register.h
index 7045237..b67e8dd 100644
--- a/compiler/dwarf/register.h
+++ b/compiler/dwarf/register.h
@@ -35,9 +35,10 @@
   //   Arm64 mapping is correct since we already do this there.
   //   libunwind might struggle with the new mapping as well.
 
-  static Reg ArmCore(int num) { return Reg(num); }
+  static Reg ArmCore(int num) { return Reg(num); }  // R0-R15.
   static Reg ArmFp(int num) { return Reg(64 + num); }  // S0–S31.
-  static Reg Arm64Core(int num) { return Reg(num); }
+  static Reg ArmDp(int num) { return Reg(256 + num); }  // D0–D31.
+  static Reg Arm64Core(int num) { return Reg(num); }  // X0-X31.
   static Reg Arm64Fp(int num) { return Reg(64 + num); }  // V0-V31.
   static Reg MipsCore(int num) { return Reg(num); }
   static Reg Mips64Core(int num) { return Reg(num); }
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 5e2a8bf..ee557fc 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -29,10 +29,49 @@
 #include "elf_builder.h"
 #include "oat_writer.h"
 #include "utils.h"
+#include "stack_map.h"
 
 namespace art {
 namespace dwarf {
 
+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);
+    default:
+      LOG(FATAL) << "Unknown instruction set: " << isa;
+      UNREACHABLE();
+  }
+}
+
 static void WriteCIE(InstructionSet isa,
                      CFIFormat format,
                      std::vector<uint8_t>* buffer) {
@@ -280,8 +319,8 @@
       info_.WriteStrp(DW_AT_producer, owner_->WriteString("Android dex2oat"));
       info_.WriteData1(DW_AT_language, DW_LANG_Java);
       info_.WriteAddr(DW_AT_low_pc, text_address + compilation_unit.low_pc_);
-      info_.WriteAddr(DW_AT_high_pc, text_address + compilation_unit.high_pc_);
-      info_.WriteData4(DW_AT_stmt_list, compilation_unit.debug_line_offset_);
+      info_.WriteUdata(DW_AT_high_pc, compilation_unit.high_pc_ - compilation_unit.low_pc_);
+      info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset_);
 
       const char* last_dex_class_desc = nullptr;
       for (auto mi : compilation_unit.methods_) {
@@ -321,18 +360,41 @@
         info_.StartTag(DW_TAG_subprogram);
         WriteName(dex->GetMethodName(dex_method));
         info_.WriteAddr(DW_AT_low_pc, text_address + mi->low_pc_);
-        info_.WriteAddr(DW_AT_high_pc, text_address + mi->high_pc_);
+        info_.WriteUdata(DW_AT_high_pc, mi->high_pc_ - mi->low_pc_);
+        uint8_t frame_base[] = { DW_OP_call_frame_cfa };
+        info_.WriteExprLoc(DW_AT_frame_base, &frame_base, sizeof(frame_base));
         WriteLazyType(dex->GetReturnTypeDescriptor(dex_proto));
         if (dex_params != nullptr) {
+          uint32_t vreg = mi->code_item_ == nullptr ? 0 :
+              mi->code_item_->registers_size_ - mi->code_item_->ins_size_;
+          if ((mi->access_flags_ & kAccStatic) == 0) {
+            info_.StartTag(DW_TAG_formal_parameter);
+            WriteName("this");
+            info_.WriteFlag(DW_AT_artificial, true);
+            WriteLazyType(dex_class_desc);
+            const bool is64bitValue = false;
+            WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_);
+            vreg++;
+            info_.EndTag();
+          }
           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() && param_names[i] != nullptr) {
               WriteName(param_names[i]);
             }
-            WriteLazyType(dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_));
+            // Write the type.
+            const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_);
+            WriteLazyType(type_desc);
+            // Write the stack location of the parameter.
+            const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J';
+            WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_);
+            vreg += is64bitValue ? 2 : 1;
             info_.EndTag();
           }
+          if (mi->code_item_ != nullptr) {
+            CHECK_EQ(vreg, mi->code_item_->registers_size_);
+          }
         }
         info_.EndTag();
         CHECK_EQ(info_.Depth(), start_depth);  // Balanced start/end.
@@ -352,6 +414,154 @@
       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 OatWriter::DebugInfo* method_info, uint16_t vreg,
+                          bool is64bitValue, uint32_t compilation_unit_low_pc) {
+      using Kind = DexRegisterLocation::Kind;
+      bool is_optimizing = 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;
+      if (!is_optimizing) {
+        return;
+      }
+
+      Writer<> writer(&owner_->debug_loc_);
+      info_.WriteSecOffset(DW_AT_location, writer.size());
+
+      const InstructionSet isa = owner_->builder_->GetIsa();
+      const bool is64bit = Is64BitInstructionSet(isa);
+      const CodeInfo code_info(method_info->compiled_method_->GetVmapTable().data());
+      const StackMapEncoding encoding = code_info.ExtractEncoding();
+      DexRegisterLocation last_reg_lo = DexRegisterLocation::None();
+      DexRegisterLocation last_reg_hi = DexRegisterLocation::None();
+      size_t offset_of_last_end_address = 0;
+      for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
+        StackMap stack_map = code_info.GetStackMapAt(s, encoding);
+        DCHECK(stack_map.IsValid());
+
+        // 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);
+          }
+        }
+        if ((reg_lo == last_reg_lo && reg_hi == last_reg_hi) ||
+            reg_lo.GetKind() == Kind::kNone) {
+          // Skip identical or undefined locations.
+          continue;
+        }
+        last_reg_lo = reg_lo;
+        last_reg_hi = reg_hi;
+
+        // 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)
+        uint8_t buffer[64];
+        uint8_t* pos = buffer;
+        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();
+            *(pos++) = DW_OP_fbreg;
+            // The stack offset is relative to SP. Make it relative to CFA.
+            pos = EncodeSignedLeb128(pos, 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) {
+            pos = WriteOpReg(pos, 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).
+              pos = WriteOpReg(pos, Reg::ArmDp(value / 2).num());
+              break;
+            }
+            pos = WriteOpReg(pos, 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) {
+            *(pos++) = DW_OP_consts;
+            pos = EncodeSignedLeb128(pos, value);
+            *(pos++) = DW_OP_stack_value;
+          } 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.
+            *(pos++) = DW_OP_piece;
+            pos = EncodeUnsignedLeb128(pos, 4);
+          }
+        }
+
+        // Write end address for previous entry.
+        const uint32_t pc = method_info->low_pc_ + stack_map.GetNativePcOffset(encoding);
+        if (offset_of_last_end_address != 0) {
+          if (is64bit) {
+            writer.UpdateUint64(offset_of_last_end_address, pc - compilation_unit_low_pc);
+          } else {
+            writer.UpdateUint32(offset_of_last_end_address, pc - compilation_unit_low_pc);
+          }
+        }
+        offset_of_last_end_address = 0;
+
+        DCHECK_LE(static_cast<size_t>(pos - buffer), sizeof(buffer));
+        if (pos > buffer) {
+          // Write start/end address.
+          if (is64bit) {
+            writer.PushUint64(pc - compilation_unit_low_pc);
+            offset_of_last_end_address = writer.size();
+            writer.PushUint64(method_info->high_pc_ - compilation_unit_low_pc);
+          } else {
+            writer.PushUint32(pc - compilation_unit_low_pc);
+            offset_of_last_end_address = writer.size();
+            writer.PushUint32(method_info->high_pc_ - compilation_unit_low_pc);
+          }
+          // Write the expression.
+          writer.PushUint16(pos - buffer);
+          writer.PushData(buffer, pos - buffer);
+        } else {
+          // Otherwise leave the address range undefined.
+        }
+      }
+      // Write end-of-list entry.
+      if (is64bit) {
+        writer.PushUint64(0);
+        writer.PushUint64(0);
+      } else {
+        writer.PushUint32(0);
+        writer.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.
@@ -375,6 +585,17 @@
       info_.WriteStrp(DW_AT_name, owner_->WriteString(name));
     }
 
+    // Helper which writes DWARF expression referencing a register.
+    static uint8_t* WriteOpReg(uint8_t* buffer, uint32_t dwarf_reg_num) {
+      if (dwarf_reg_num < 32) {
+        *(buffer++) = DW_OP_reg0 + dwarf_reg_num;
+      } else {
+        *(buffer++) = DW_OP_regx;
+        buffer = EncodeUnsignedLeb128(buffer, dwarf_reg_num);
+      }
+      return buffer;
+    }
+
     // Convert dex type descriptor to DWARF.
     // Returns offset in the compilation unit.
     size_t WriteType(const char* desc) {
@@ -398,22 +619,60 @@
       } else {
         // Primitive types.
         const char* name;
+        uint32_t encoding;
+        uint32_t byte_size;
         switch (*desc) {
-        case 'B': name = "byte"; break;
-        case 'C': name = "char"; break;
-        case 'D': name = "double"; break;
-        case 'F': name = "float"; break;
-        case 'I': name = "int"; break;
-        case 'J': name = "long"; break;
-        case 'S': name = "short"; break;
-        case 'Z': name = "boolean"; break;
-        case 'V': name = "void"; break;
+        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();
         }
         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();
       }
 
@@ -480,6 +739,7 @@
     builder_->WritePatches(".debug_info.oat_patches", &debug_info_patches_);
     builder_->WriteSection(".debug_abbrev", &debug_abbrev_.Data());
     builder_->WriteSection(".debug_str", &debug_str_.Data());
+    builder_->WriteSection(".debug_loc", &debug_loc_);
   }
 
  private:
@@ -491,6 +751,7 @@
   std::vector<uintptr_t> debug_info_patches_;
   DedupVector debug_abbrev_;
   DedupVector debug_str_;
+  std::vector<uint8_t> debug_loc_;
 
   std::unordered_set<const char*> defined_dex_classes_;  // For CHECKs only.
 };