Add debug info for link-time generated thunks.

Add debug info for method call thunks (currently unused) and
Baker read barrier thunks. Refactor debug info generation
for trampolines and record their sizes; change their names
to start with upper-case letters, so that they can be easily
generated as `#fn_name`.

This improved debug info must be generated by `dex2oat -g`,
the debug info generated by `oatdump --symbolize` remains
the same as before, except for the renamed trampolines and
an adjustment for "code delta", i.e. the Thumb mode bit.

Cortex-A53 erratum 843419 workaround thunks are not covered
by this CL.

Test: Manual; run-test --gdb -Xcompiler-option -g 160, pull
      symbols for gdbclient, break in the introspection
      entrypoint, check that gdb knows the new symbols
      (and disassembles them) and `backtrace` works when
      setting $pc to an address in the thunk.
Bug: 36141117
Change-Id: Id224b72cfa7a0628799c7db65e66e24c8517aabf
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc
index 4ca5afe..6e63bf8 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.cc
+++ b/compiler/linker/arm/relative_patcher_arm_base.cc
@@ -18,6 +18,7 @@
 
 #include "base/stl_util.h"
 #include "compiled_method.h"
+#include "debug/method_debug_info.h"
 #include "linker/output_stream.h"
 #include "oat.h"
 #include "oat_quick_method_header.h"
@@ -119,6 +120,25 @@
     return offsets_[pending_offset_ - 1u];
   }
 
+  size_t IndexOfFirstThunkAtOrAfter(uint32_t offset) const {
+    size_t number_of_thunks = NumberOfThunks();
+    for (size_t i = 0; i != number_of_thunks; ++i) {
+      if (GetThunkOffset(i) >= offset) {
+        return i;
+      }
+    }
+    return number_of_thunks;
+  }
+
+  size_t NumberOfThunks() const {
+    return offsets_.size();
+  }
+
+  uint32_t GetThunkOffset(size_t index) const {
+    DCHECK_LT(index, NumberOfThunks());
+    return offsets_[index];
+  }
+
  private:
   std::vector<uint8_t> code_;       // The code of the thunk.
   std::vector<uint32_t> offsets_;   // Offsets at which the thunk needs to be written.
@@ -203,6 +223,48 @@
   return offset;
 }
 
+std::vector<debug::MethodDebugInfo> ArmBaseRelativePatcher::GenerateThunkDebugInfo(
+    uint32_t executable_offset) {
+  // For multi-oat compilation (boot image), `thunks_` records thunks for all oat files.
+  // To return debug info for the current oat file, we must ignore thunks before the
+  // `executable_offset` as they are in the previous oat files and this function must be
+  // called before reserving thunk positions for subsequent oat files.
+  size_t number_of_thunks = 0u;
+  for (auto&& entry : thunks_) {
+    const ThunkData& data = entry.second;
+    number_of_thunks += data.NumberOfThunks() - data.IndexOfFirstThunkAtOrAfter(executable_offset);
+  }
+  std::vector<debug::MethodDebugInfo> result;
+  result.reserve(number_of_thunks);
+  for (auto&& entry : thunks_) {
+    const ThunkKey& key = entry.first;
+    const ThunkData& data = entry.second;
+    size_t start = data.IndexOfFirstThunkAtOrAfter(executable_offset);
+    if (start == data.NumberOfThunks()) {
+      continue;
+    }
+    // Get the base name to use for the first occurrence of the thunk.
+    std::string base_name = GetThunkDebugName(key);
+    for (size_t i = start, num = data.NumberOfThunks(); i != num; ++i) {
+      debug::MethodDebugInfo info = {};
+      if (i == 0u) {
+        info.trampoline_name = base_name;
+      } else {
+        // Add a disambiguating tag for subsequent identical thunks. Since the `thunks_`
+        // keeps records also for thunks in previous oat files, names based on the thunk
+        // index shall be unique across the whole multi-oat output.
+        info.trampoline_name = base_name + "_" + std::to_string(i);
+      }
+      info.isa = instruction_set_;
+      info.is_code_address_text_relative = true;
+      info.code_address = data.GetThunkOffset(i) - executable_offset;
+      info.code_size = data.CodeSize();
+      result.push_back(std::move(info));
+    }
+  }
+  return result;
+}
+
 ArmBaseRelativePatcher::ArmBaseRelativePatcher(RelativePatcherTargetProvider* provider,
                                                InstructionSet instruction_set)
     : provider_(provider),
diff --git a/compiler/linker/arm/relative_patcher_arm_base.h b/compiler/linker/arm/relative_patcher_arm_base.h
index 5197ce2..4c2be1e 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.h
+++ b/compiler/linker/arm/relative_patcher_arm_base.h
@@ -34,6 +34,7 @@
                         MethodReference method_ref) OVERRIDE;
   uint32_t ReserveSpaceEnd(uint32_t offset) OVERRIDE;
   uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE;
+  std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) OVERRIDE;
 
  protected:
   ArmBaseRelativePatcher(RelativePatcherTargetProvider* provider,
@@ -94,6 +95,7 @@
                                            uint32_t target_offset);
 
   virtual std::vector<uint8_t> CompileThunk(const ThunkKey& key) = 0;
+  virtual std::string GetThunkDebugName(const ThunkKey& key) = 0;
   virtual uint32_t MaxPositiveDisplacement(const ThunkKey& key) = 0;
   virtual uint32_t MaxNegativeDisplacement(const ThunkKey& key) = 0;
 
diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc
index 2ac2a1d..704feeb 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2.cc
@@ -281,7 +281,7 @@
       Register base_reg(BakerReadBarrierFirstRegField::Decode(encoded_data));
       CheckValidReg(base_reg.GetCode());
       DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data));
-      DCHECK(BakerReadBarrierWidth::kWide == BakerReadBarrierWidthField::Decode(encoded_data));
+      DCHECK(BakerReadBarrierWidthField::Decode(encoded_data) == BakerReadBarrierWidth::kWide);
       UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
       temps.Exclude(ip);
       vixl::aarch32::Label slow_path;
@@ -379,6 +379,44 @@
   return thunk_code;
 }
 
+std::string Thumb2RelativePatcher::GetThunkDebugName(const ThunkKey& key) {
+  switch (key.GetType()) {
+    case ThunkType::kMethodCall:
+      return "MethodCallThunk";
+
+    case ThunkType::kBakerReadBarrier: {
+      uint32_t encoded_data = key.GetCustomValue1();
+      BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data);
+      std::ostringstream oss;
+      oss << "BakerReadBarrierThunk";
+      switch (kind) {
+        case BakerReadBarrierKind::kField:
+          oss << "Field";
+          if (BakerReadBarrierWidthField::Decode(encoded_data) == BakerReadBarrierWidth::kWide) {
+            oss << "Wide";
+          }
+          oss << "_r" << BakerReadBarrierFirstRegField::Decode(encoded_data)
+              << "_r" << BakerReadBarrierSecondRegField::Decode(encoded_data);
+          break;
+        case BakerReadBarrierKind::kArray:
+          oss << "Array_r" << BakerReadBarrierFirstRegField::Decode(encoded_data);
+          DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data));
+          DCHECK(BakerReadBarrierWidthField::Decode(encoded_data) == BakerReadBarrierWidth::kWide);
+          break;
+        case BakerReadBarrierKind::kGcRoot:
+          oss << "GcRoot";
+          if (BakerReadBarrierWidthField::Decode(encoded_data) == BakerReadBarrierWidth::kWide) {
+            oss << "Wide";
+          }
+          oss << "_r" << BakerReadBarrierFirstRegField::Decode(encoded_data);
+          DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data));
+          break;
+      }
+      return oss.str();
+    }
+  }
+}
+
 #undef __
 
 uint32_t Thumb2RelativePatcher::MaxPositiveDisplacement(const ThunkKey& key) {
diff --git a/compiler/linker/arm/relative_patcher_thumb2.h b/compiler/linker/arm/relative_patcher_thumb2.h
index 183e5e6..68386c0 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.h
+++ b/compiler/linker/arm/relative_patcher_thumb2.h
@@ -84,6 +84,7 @@
 
  protected:
   std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE;
+  std::string GetThunkDebugName(const ThunkKey& key) OVERRIDE;
   uint32_t MaxPositiveDisplacement(const ThunkKey& key) OVERRIDE;
   uint32_t MaxNegativeDisplacement(const ThunkKey& key) OVERRIDE;
 
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 4960f4d..270ba3c 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -535,6 +535,35 @@
   return thunk_code;
 }
 
+std::string Arm64RelativePatcher::GetThunkDebugName(const ThunkKey& key) {
+  switch (key.GetType()) {
+    case ThunkType::kMethodCall:
+      return "MethodCallThunk";
+
+    case ThunkType::kBakerReadBarrier: {
+      uint32_t encoded_data = key.GetCustomValue1();
+      BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data);
+      std::ostringstream oss;
+      oss << "BakerReadBarrierThunk";
+      switch (kind) {
+        case BakerReadBarrierKind::kField:
+          oss << "Field_r" << BakerReadBarrierFirstRegField::Decode(encoded_data)
+              << "_r" << BakerReadBarrierSecondRegField::Decode(encoded_data);
+          break;
+        case BakerReadBarrierKind::kArray:
+          oss << "Array_r" << BakerReadBarrierFirstRegField::Decode(encoded_data);
+          DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data));
+          break;
+        case BakerReadBarrierKind::kGcRoot:
+          oss << "GcRoot_r" << BakerReadBarrierFirstRegField::Decode(encoded_data);
+          DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data));
+          break;
+      }
+      return oss.str();
+    }
+  }
+}
+
 #undef __
 
 uint32_t Arm64RelativePatcher::MaxPositiveDisplacement(const ThunkKey& key) {
diff --git a/compiler/linker/arm64/relative_patcher_arm64.h b/compiler/linker/arm64/relative_patcher_arm64.h
index b00dd08..8ba5997 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.h
+++ b/compiler/linker/arm64/relative_patcher_arm64.h
@@ -76,6 +76,7 @@
 
  protected:
   std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE;
+  std::string GetThunkDebugName(const ThunkKey& key) OVERRIDE;
   uint32_t MaxPositiveDisplacement(const ThunkKey& key) OVERRIDE;
   uint32_t MaxNegativeDisplacement(const ThunkKey& key) OVERRIDE;
 
diff --git a/compiler/linker/mips/relative_patcher_mips.cc b/compiler/linker/mips/relative_patcher_mips.cc
index 6c974c3..408ac22 100644
--- a/compiler/linker/mips/relative_patcher_mips.cc
+++ b/compiler/linker/mips/relative_patcher_mips.cc
@@ -17,6 +17,7 @@
 #include "linker/mips/relative_patcher_mips.h"
 
 #include "compiled_method.h"
+#include "debug/method_debug_info.h"
 
 namespace art {
 namespace linker {
@@ -90,5 +91,10 @@
   LOG(FATAL) << "UNIMPLEMENTED";
 }
 
+std::vector<debug::MethodDebugInfo> MipsRelativePatcher::GenerateThunkDebugInfo(
+    uint32_t executable_offset ATTRIBUTE_UNUSED) {
+  return std::vector<debug::MethodDebugInfo>();  // No thunks added.
+}
+
 }  // namespace linker
 }  // namespace art
diff --git a/compiler/linker/mips/relative_patcher_mips.h b/compiler/linker/mips/relative_patcher_mips.h
index d6eda34..5714a7d 100644
--- a/compiler/linker/mips/relative_patcher_mips.h
+++ b/compiler/linker/mips/relative_patcher_mips.h
@@ -44,6 +44,7 @@
   void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
                                    const LinkerPatch& patch,
                                    uint32_t patch_offset) OVERRIDE;
+  std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) OVERRIDE;
 
  private:
   bool is_r6;
diff --git a/compiler/linker/mips64/relative_patcher_mips64.cc b/compiler/linker/mips64/relative_patcher_mips64.cc
index d9f4758..2bcd98a 100644
--- a/compiler/linker/mips64/relative_patcher_mips64.cc
+++ b/compiler/linker/mips64/relative_patcher_mips64.cc
@@ -17,6 +17,7 @@
 #include "linker/mips64/relative_patcher_mips64.h"
 
 #include "compiled_method.h"
+#include "debug/method_debug_info.h"
 
 namespace art {
 namespace linker {
@@ -88,5 +89,10 @@
   LOG(FATAL) << "UNIMPLEMENTED";
 }
 
+std::vector<debug::MethodDebugInfo> Mips64RelativePatcher::GenerateThunkDebugInfo(
+    uint32_t executable_offset ATTRIBUTE_UNUSED) {
+  return std::vector<debug::MethodDebugInfo>();  // No thunks added.
+}
+
 }  // namespace linker
 }  // namespace art
diff --git a/compiler/linker/mips64/relative_patcher_mips64.h b/compiler/linker/mips64/relative_patcher_mips64.h
index f478d7f..6d7c638 100644
--- a/compiler/linker/mips64/relative_patcher_mips64.h
+++ b/compiler/linker/mips64/relative_patcher_mips64.h
@@ -42,6 +42,7 @@
   void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
                                    const LinkerPatch& patch,
                                    uint32_t patch_offset) OVERRIDE;
+  std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) OVERRIDE;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Mips64RelativePatcher);
diff --git a/compiler/linker/multi_oat_relative_patcher.h b/compiler/linker/multi_oat_relative_patcher.h
index bdc1ee1..1c5c8a0 100644
--- a/compiler/linker/multi_oat_relative_patcher.h
+++ b/compiler/linker/multi_oat_relative_patcher.h
@@ -18,6 +18,7 @@
 #define ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_
 
 #include "arch/instruction_set.h"
+#include "debug/method_debug_info.h"
 #include "method_reference.h"
 #include "relative_patcher.h"
 #include "safe_map.h"
@@ -119,6 +120,11 @@
     relative_patcher_->PatchBakerReadBarrierBranch(code, patch, patch_offset);
   }
 
+  std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(size_t executable_offset) {
+    executable_offset += adjustment_;
+    return relative_patcher_->GenerateThunkDebugInfo(executable_offset);
+  }
+
   // Wrappers around RelativePatcher for statistics retrieval.
   uint32_t CodeAlignmentSize() const;
   uint32_t RelativeCallThunksSize() const;
diff --git a/compiler/linker/multi_oat_relative_patcher_test.cc b/compiler/linker/multi_oat_relative_patcher_test.cc
index e967901..f89fba6 100644
--- a/compiler/linker/multi_oat_relative_patcher_test.cc
+++ b/compiler/linker/multi_oat_relative_patcher_test.cc
@@ -17,6 +17,7 @@
 #include "multi_oat_relative_patcher.h"
 
 #include "compiled_method.h"
+#include "debug/method_debug_info.h"
 #include "gtest/gtest.h"
 #include "vector_output_stream.h"
 
@@ -102,6 +103,12 @@
       LOG(FATAL) << "UNIMPLEMENTED";
     }
 
+    std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(
+        uint32_t executable_offset ATTRIBUTE_UNUSED) {
+      LOG(FATAL) << "UNIMPLEMENTED";
+      UNREACHABLE();
+    }
+
     uint32_t last_reserve_offset_ = 0u;
     MethodReference last_reserve_method_ = kNullMethodRef;
     uint32_t next_reserve_adjustment_ = 0u;
diff --git a/compiler/linker/relative_patcher.cc b/compiler/linker/relative_patcher.cc
index ee49453..dc15bb0 100644
--- a/compiler/linker/relative_patcher.cc
+++ b/compiler/linker/relative_patcher.cc
@@ -16,6 +16,7 @@
 
 #include "linker/relative_patcher.h"
 
+#include "debug/method_debug_info.h"
 #ifdef ART_ENABLE_CODEGEN_arm
 #include "linker/arm/relative_patcher_thumb2.h"
 #endif
@@ -81,6 +82,11 @@
       LOG(FATAL) << "Unexpected baker read barrier branch patch.";
     }
 
+    std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(
+        uint32_t executable_offset ATTRIBUTE_UNUSED) OVERRIDE {
+      return std::vector<debug::MethodDebugInfo>();  // No thunks added.
+    }
+
    private:
     DISALLOW_COPY_AND_ASSIGN(RelativePatcherNone);
   };
diff --git a/compiler/linker/relative_patcher.h b/compiler/linker/relative_patcher.h
index 38c8228..53a0966 100644
--- a/compiler/linker/relative_patcher.h
+++ b/compiler/linker/relative_patcher.h
@@ -31,6 +31,10 @@
 class LinkerPatch;
 class OutputStream;
 
+namespace debug {
+struct MethodDebugInfo;
+}  // namespace debug
+
 namespace linker {
 
 /**
@@ -114,6 +118,9 @@
                                            const LinkerPatch& patch,
                                            uint32_t patch_offset) = 0;
 
+  virtual std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(
+      uint32_t executable_offset) = 0;
+
  protected:
   RelativePatcher()
       : size_code_alignment_(0u),
diff --git a/compiler/linker/x86/relative_patcher_x86_base.cc b/compiler/linker/x86/relative_patcher_x86_base.cc
index bf3a648..6a9690d 100644
--- a/compiler/linker/x86/relative_patcher_x86_base.cc
+++ b/compiler/linker/x86/relative_patcher_x86_base.cc
@@ -16,6 +16,8 @@
 
 #include "linker/x86/relative_patcher_x86_base.h"
 
+#include "debug/method_debug_info.h"
+
 namespace art {
 namespace linker {
 
@@ -34,6 +36,11 @@
   return offset;  // No thunks added; no limit on relative call distance.
 }
 
+std::vector<debug::MethodDebugInfo> X86BaseRelativePatcher::GenerateThunkDebugInfo(
+    uint32_t executable_offset ATTRIBUTE_UNUSED) {
+  return std::vector<debug::MethodDebugInfo>();  // No thunks added.
+}
+
 void X86BaseRelativePatcher::PatchCall(std::vector<uint8_t>* code,
                                        uint32_t literal_offset,
                                        uint32_t patch_offset,
diff --git a/compiler/linker/x86/relative_patcher_x86_base.h b/compiler/linker/x86/relative_patcher_x86_base.h
index ca83a72..6097345 100644
--- a/compiler/linker/x86/relative_patcher_x86_base.h
+++ b/compiler/linker/x86/relative_patcher_x86_base.h
@@ -33,6 +33,7 @@
                  uint32_t literal_offset,
                  uint32_t patch_offset,
                  uint32_t target_offset) OVERRIDE;
+  std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) OVERRIDE;
 
  protected:
   X86BaseRelativePatcher() { }