Improve disasembly of BL to thread entrypoint trampoline.

Test: Manual, search for "\bbl\b" in `m dump-oat` output and
      oatdump of an individual oat file for arm and arm64.
Change-Id: Idb6d8d1a21b2aa8c77e5b72f24faf7a4e655294c
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 94ea006..c2156ca 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -68,6 +68,22 @@
           PrintLiteral(type, offset);
           return *this;
         }
+        case kCodeLocation:
+          DisassemblerStream::operator<<(label);
+          // Improve the disassembly of branch to thunk jumping to pointer from thread entrypoint.
+          if (disasm_->GetIsT32() && GetCurrentInstructionType() == vixl::aarch32::kBl) {
+            const uintptr_t begin = reinterpret_cast<uintptr_t>(options_->base_address_);
+            const uintptr_t end = reinterpret_cast<uintptr_t>(options_->end_address_);
+            uintptr_t address = label.GetLocation() + (options_->absolute_addresses_ ? 0u : begin);
+            if ((address >= begin && address < end && end - address >= 4u) &&
+                reinterpret_cast<const uint16_t*>(address)[0] == 0xf8d9 &&  // LDR Rt, [tr, #imm12]
+                (reinterpret_cast<const uint16_t*>(address)[1] >> 12) == 0xf) {  // Rt == PC
+              uint32_t imm12 = reinterpret_cast<const uint16_t*>(address)[1] & 0xfffu;
+              os() << " ; ";
+              options_->thread_offset_name_function_(os(), imm12);
+            }
+          }
+          return *this;
         default:
           return DisassemblerStream::operator<<(label);
       }
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index 49b9623..0d51cfd 100644
--- a/disassembler/disassembler_arm64.cc
+++ b/disassembler/disassembler_arm64.cc
@@ -101,13 +101,35 @@
   Disassembler::VisitLoadStoreUnsignedOffset(instr);
 
   if (instr->GetRn() == TR) {
-    int64_t offset = instr->GetImmLSUnsigned() << instr->GetSizeLS();
-    std::ostringstream tmp_stream;
-    options_->thread_offset_name_function_(tmp_stream, static_cast<uint32_t>(offset));
-    AppendToOutput(" ; %s", tmp_stream.str().c_str());
+    AppendThreadOfsetName(instr);
   }
 }
 
+void CustomDisassembler::VisitUnconditionalBranch(const Instruction* instr) {
+  Disassembler::VisitUnconditionalBranch(instr);
+
+  if (instr->Mask(UnconditionalBranchMask) == BL) {
+    const Instruction* target = instr->GetImmPCOffsetTarget();
+    if (target >= base_address_ &&
+        target < end_address_ &&
+        target->Mask(LoadStoreMask) == LDR_x &&
+        target->GetRn() == TR &&
+        target->GetRt() == IP0 &&
+        target->GetNextInstruction() < end_address_ &&
+        target->GetNextInstruction()->Mask(UnconditionalBranchToRegisterMask) == BR &&
+        target->GetNextInstruction()->GetRn() == IP0) {
+      AppendThreadOfsetName(target);
+    }
+  }
+}
+
+void CustomDisassembler::AppendThreadOfsetName(const vixl::aarch64::Instruction* instr) {
+  int64_t offset = instr->GetImmLSUnsigned() << instr->GetSizeLS();
+  std::ostringstream tmp_stream;
+  options_->thread_offset_name_function_(tmp_stream, static_cast<uint32_t>(offset));
+  AppendToOutput(" ; %s", tmp_stream.str().c_str());
+}
+
 size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) {
   const Instruction* instr = reinterpret_cast<const Instruction*>(begin);
   decoder.Decode(instr);
diff --git a/disassembler/disassembler_arm64.h b/disassembler/disassembler_arm64.h
index 89beaa9..a895dfe 100644
--- a/disassembler/disassembler_arm64.h
+++ b/disassembler/disassembler_arm64.h
@@ -53,7 +53,12 @@
   // Improve the disassembly of thread offset.
   void VisitLoadStoreUnsignedOffset(const vixl::aarch64::Instruction* instr) override;
 
+  // Improve the disassembly of branch to thunk jumping to pointer from thread entrypoint.
+  void VisitUnconditionalBranch(const vixl::aarch64::Instruction* instr) override;
+
  private:
+  void AppendThreadOfsetName(const vixl::aarch64::Instruction* instr);
+
   // Indicate if the disassembler should read data loaded from literal pools.
   // This should only be enabled if reading the target of literal loads is safe.
   // Here are possible outputs when the option is on or off: