Improvements to the ARM64 disassembler.

This contains three changes:
- Use register aliases in the disassembly.
- When loading from a literal pool, show what is being loaded.
- Disassemble using absolute addresses on ARM64.
  This ensures that addresses disassembled are coherent with instruction
  location addresses shown.

Examples of disassembled instructions before and after the changes:

Before:
  movz w17, #0x471f
  ldr d9, pc+736 (addr 0x72690d50)

After:
  movz wip1, #0x471f
  ldr d9, pc+736 (addr 0x72690d50) (-745.133)

Change-Id: I72fdc160fac26f74126921834f17a581c26fd5d8
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 487f433..1d827ba 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -34,8 +34,14 @@
   // Base addess for calculating relative code offsets when absolute_addresses_ is false.
   const uint8_t* const base_address_;
 
-  DisassemblerOptions(bool absolute_addresses, const uint8_t* base_address)
-      : absolute_addresses_(absolute_addresses), base_address_(base_address) {}
+  // If set, the disassembler is allowed to look at load targets in literal
+  // pools.
+  const bool can_read_literals_;
+
+  DisassemblerOptions(bool absolute_addresses, const uint8_t* base_address,
+                      bool can_read_literals)
+      : absolute_addresses_(absolute_addresses), base_address_(base_address),
+        can_read_literals_(can_read_literals) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DisassemblerOptions);
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index 229ac97..fe50421 100644
--- a/disassembler/disassembler_arm64.cc
+++ b/disassembler/disassembler_arm64.cc
@@ -27,10 +27,88 @@
 namespace art {
 namespace arm64 {
 
+void CustomDisassembler::AppendRegisterNameToOutput(
+    const vixl::Instruction* instr,
+    const vixl::CPURegister& reg) {
+  USE(instr);
+  if (reg.IsRegister()) {
+    // This enumeration should mirror the declarations in
+    // runtime/arch/arm64/registers_arm64.h. We do not include that file to
+    // avoid a dependency on libart.
+    enum {
+      TR  = 18,
+      ETR = 21,
+      IP0 = 16,
+      IP1 = 17,
+      FP  = 29,
+      LR  = 30
+    };
+    switch (reg.code()) {
+      case IP0: AppendToOutput(reg.Is64Bits() ? "ip0" : "wip0"); return;
+      case IP1: AppendToOutput(reg.Is64Bits() ? "ip1" : "wip1"); return;
+      case TR:  AppendToOutput(reg.Is64Bits() ? "tr"  :  "w18"); return;
+      case ETR: AppendToOutput(reg.Is64Bits() ? "etr" :  "w21"); return;
+      case FP:  AppendToOutput(reg.Is64Bits() ? "fp"  :  "w29"); return;
+      case LR:  AppendToOutput(reg.Is64Bits() ? "lr"  :  "w30"); return;
+      default:
+        // Fall through.
+        break;
+    }
+  }
+  // Print other register names as usual.
+  Disassembler::AppendRegisterNameToOutput(instr, reg);
+}
+
+void CustomDisassembler::VisitLoadLiteral(const vixl::Instruction* instr) {
+  Disassembler::VisitLoadLiteral(instr);
+
+  if (!read_literals_) {
+    return;
+  }
+
+  char* buffer = buffer_;
+  char* buffer_end = buffer_ + buffer_size_;
+
+  // Find the end position in the buffer.
+  while ((*buffer != 0) && (buffer < buffer_end)) {
+    ++buffer;
+  }
+
+  void* data_address = instr->LiteralAddress();
+  ptrdiff_t buf_size_remaining = buffer_end - buffer;
+  vixl::Instr op = instr->Mask(vixl::LoadLiteralMask);
+
+  switch (op) {
+    case vixl::LDR_w_lit:
+    case vixl::LDR_x_lit:
+    case vixl::LDRSW_x_lit: {
+      int64_t data = op == vixl::LDR_x_lit ? *reinterpret_cast<int64_t*>(data_address)
+                                           : *reinterpret_cast<int32_t*>(data_address);
+      snprintf(buffer, buf_size_remaining, " (0x%" PRIx64 " / %" PRId64 ")", data, data);
+      break;
+    }
+    case vixl::LDR_s_lit:
+    case vixl::LDR_d_lit: {
+      double data = (op == vixl::LDR_s_lit) ? *reinterpret_cast<float*>(data_address)
+                                            : *reinterpret_cast<double*>(data_address);
+      snprintf(buffer, buf_size_remaining, " (%g)", data);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
 size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) {
   const vixl::Instruction* instr = reinterpret_cast<const vixl::Instruction*>(begin);
   decoder.Decode(instr);
-  os << FormatInstructionPointer(begin)
+  // TODO: Use FormatInstructionPointer() once VIXL provides the appropriate
+  // features.
+  // VIXL does not yet allow remapping addresses disassembled. Using
+  // FormatInstructionPointer() would show incoherences between the instruction
+  // location addresses and the target addresses disassembled by VIXL (eg. for
+  // branch instructions).
+  os << StringPrintf("%p", instr)
      << StringPrintf(": %08x\t%s\n", instr->InstructionBits(), disasm.GetOutput());
   return vixl::kInstructionSize;
 }
diff --git a/disassembler/disassembler_arm64.h b/disassembler/disassembler_arm64.h
index ad20c70..96a4dd0 100644
--- a/disassembler/disassembler_arm64.h
+++ b/disassembler/disassembler_arm64.h
@@ -25,9 +25,35 @@
 namespace art {
 namespace arm64 {
 
+class CustomDisassembler FINAL : public vixl::Disassembler {
+ public:
+  explicit CustomDisassembler(bool read_literals) :
+      vixl::Disassembler(), read_literals_(read_literals) {}
+
+  // Use register aliases in the disassembly.
+  virtual void AppendRegisterNameToOutput(const vixl::Instruction* instr,
+                                          const vixl::CPURegister& reg) OVERRIDE;
+
+  // Improve the disassembly of literal load instructions.
+  virtual void VisitLoadLiteral(const vixl::Instruction* instr) OVERRIDE;
+
+ private:
+  // 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:
+  // read_literals_ | disassembly
+  //           true | 0x72681558: 1c000acb  ldr s11, pc+344 (addr 0x726816b0)
+  //          false | 0x72681558: 1c000acb  ldr s11, pc+344 (addr 0x726816b0) (3.40282e+38)
+  const bool read_literals_;
+};
+
 class DisassemblerArm64 FINAL : public Disassembler {
  public:
-  explicit DisassemblerArm64(DisassemblerOptions* options) : Disassembler(options) {
+  // TODO: Update this code once VIXL provides the ability to map code addresses
+  // to disassemble as a different address (the way FormatInstructionPointer()
+  // does).
+  explicit DisassemblerArm64(DisassemblerOptions* options) :
+      Disassembler(options), disasm(options->can_read_literals_) {
     decoder.AppendVisitor(&disasm);
   }
 
@@ -36,7 +62,7 @@
 
  private:
   vixl::Decoder decoder;
-  vixl::Disassembler disasm;
+  CustomDisassembler disasm;
 
   DISALLOW_COPY_AND_ASSIGN(DisassemblerArm64);
 };
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index f565277..ece9f7d 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -374,7 +374,8 @@
       options_(options),
       disassembler_(Disassembler::Create(oat_file_.GetOatHeader().GetInstructionSet(),
                                          new DisassemblerOptions(options_->absolute_addresses_,
-                                                                 oat_file.Begin()))) {
+                                                                 oat_file.Begin(),
+                                                                 true /* can_read_litals_ */))) {
     CHECK(options_->class_loader_ != nullptr);
     AddAllOffsets();
   }