Merge "Fix the x86 textrel and remove -Wl,--no-fatal-warnings."
diff --git a/Android.mk b/Android.mk
index 7d31382..14cd0f3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -364,9 +364,9 @@
 # "m art-host" for just building the files needed to run the art script
 .PHONY: art-host
 ifeq ($(HOST_PREFER_32_BIT),true)
-art-host:   $(HOST_OUT_EXECUTABLES)/art $(HOST_OUT)/bin/dalvikvm32 $(HOST_OUT)/lib/libart.so $(HOST_OUT)/bin/dex2oat $(HOST_CORE_IMG_OUT) $(HOST_OUT)/lib/libjavacore.so
+art-host:   $(HOST_OUT_EXECUTABLES)/art $(HOST_OUT)/bin/dalvikvm32 $(HOST_OUT)/lib/libart.so $(HOST_OUT)/bin/dex2oat $(HOST_CORE_IMG_OUT) $(HOST_OUT)/lib/libjavacore.so $(HOST_OUT)/bin/dalvikvm
 else
-art-host:   $(HOST_OUT_EXECUTABLES)/art $(HOST_OUT)/bin/dalvikvm64 $(HOST_OUT)/bin/dalvikvm32 $(HOST_OUT)/lib/libart.so $(HOST_OUT)/bin/dex2oat $(HOST_CORE_IMG_OUT) $(HOST_OUT)/lib/libjavacore.so
+art-host:   $(HOST_OUT_EXECUTABLES)/art $(HOST_OUT)/bin/dalvikvm64 $(HOST_OUT)/bin/dalvikvm32 $(HOST_OUT)/lib/libart.so $(HOST_OUT)/bin/dex2oat $(HOST_CORE_IMG_OUT) $(HOST_OUT)/lib/libjavacore.so $(HOST_OUT)/bin/dalvikvm
 endif
 
 .PHONY: art-host-debug
@@ -400,7 +400,7 @@
 use-art-full:
 	adb root && sleep 3
 	adb shell stop
-	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
+	adb shell rm -rf $(ART_TARGET_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags ""
 	adb shell setprop dalvik.vm.image-dex2oat-flags ""
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
@@ -410,7 +410,7 @@
 use-artd-full:
 	adb root && sleep 3
 	adb shell stop
-	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
+	adb shell rm -rf $(ART_TARGET_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags ""
 	adb shell setprop dalvik.vm.image-dex2oat-flags ""
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libartd.so
@@ -420,7 +420,7 @@
 use-art-smart:
 	adb root && sleep 3
 	adb shell stop
-	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
+	adb shell rm -rf $(ART_TARGET_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags "--compiler-filter=interpret-only"
 	adb shell setprop dalvik.vm.image-dex2oat-flags ""
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
@@ -430,7 +430,7 @@
 use-art-interpret-only:
 	adb root && sleep 3
 	adb shell stop
-	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
+	adb shell rm -rf $(ART_TARGET_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags "--compiler-filter=interpret-only"
 	adb shell setprop dalvik.vm.image-dex2oat-flags "--compiler-filter=interpret-only"
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
@@ -440,7 +440,7 @@
 use-art-verify-none:
 	adb root && sleep 3
 	adb shell stop
-	adb shell rm -rf $(ART_DALVIK_CACHE_DIR)/*
+	adb shell rm -rf $(ART_TARGET_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-flags "--compiler-filter=verify-none"
 	adb shell setprop dalvik.vm.image-dex2oat-flags "--compiler-filter=verify-none"
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index ac5f33b..b0865f1 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -136,23 +136,23 @@
   A64_REGISTER_CODE_LIST(A64_DEFINE_REGISTERS)
 #undef A64_DEFINE_REGISTERS
 
-  rwzr = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 0x3f,
   rxzr = RegStorage::k64BitSolo | RegStorage::kCoreRegister | 0x3f,
-  rwsp = rw31,
+  rwzr = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 0x3f,
   rsp = rx31,
-  rA64_SUSPEND = rx19,
-  rA64_SELF = rx18,
-  rA64_SP = rx31,
-  rA64_LR = rx30,
+  rwsp = rw31,
+
+  // Aliases which are not defined in "ARM Architecture Reference, register names".
+  rxSUSPEND = rx19,
+  rxSELF = rx18,
+  rxLR = rx30,
   /*
    * FIXME: It's a bit awkward to define both 32 and 64-bit views of these - we'll only ever use
    * the 64-bit view. However, for now we'll define a 32-bit view to keep these from being
    * allocated as 32-bit temp registers.
    */
-  rA32_SUSPEND = rw19,
-  rA32_SELF = rw18,
-  rA32_SP = rw31,
-  rA32_LR = rw30
+  rwSUSPEND = rw19,
+  rwSELF = rw18,
+  rwLR = rw30,
 };
 
 #define A64_DEFINE_REGSTORAGES(nr) \
@@ -163,17 +163,18 @@
 A64_REGISTER_CODE_LIST(A64_DEFINE_REGSTORAGES)
 #undef A64_DEFINE_REGSTORAGES
 
-constexpr RegStorage rs_wzr(RegStorage::kValid | rwzr);
 constexpr RegStorage rs_xzr(RegStorage::kValid | rxzr);
-constexpr RegStorage rs_rA64_SUSPEND(RegStorage::kValid | rA64_SUSPEND);
-constexpr RegStorage rs_rA64_SELF(RegStorage::kValid | rA64_SELF);
-constexpr RegStorage rs_rA64_SP(RegStorage::kValid | rA64_SP);
-constexpr RegStorage rs_rA64_LR(RegStorage::kValid | rA64_LR);
+constexpr RegStorage rs_wzr(RegStorage::kValid | rwzr);
+// Reserved registers.
+constexpr RegStorage rs_xSUSPEND(RegStorage::kValid | rxSUSPEND);
+constexpr RegStorage rs_xSELF(RegStorage::kValid | rxSELF);
+constexpr RegStorage rs_sp(RegStorage::kValid | rsp);
+constexpr RegStorage rs_xLR(RegStorage::kValid | rxLR);
 // TODO: eliminate the need for these.
-constexpr RegStorage rs_rA32_SUSPEND(RegStorage::kValid | rA32_SUSPEND);
-constexpr RegStorage rs_rA32_SELF(RegStorage::kValid | rA32_SELF);
-constexpr RegStorage rs_rA32_SP(RegStorage::kValid | rA32_SP);
-constexpr RegStorage rs_rA32_LR(RegStorage::kValid | rA32_LR);
+constexpr RegStorage rs_wSUSPEND(RegStorage::kValid | rwSUSPEND);
+constexpr RegStorage rs_wSELF(RegStorage::kValid | rwSELF);
+constexpr RegStorage rs_wsp(RegStorage::kValid | rwsp);
+constexpr RegStorage rs_wLR(RegStorage::kValid | rwLR);
 
 // RegisterLocation templates return values (following the hard-float calling convention).
 const RegLocation arm_loc_c_return =
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index cb126f2..cfdf926 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -174,12 +174,12 @@
   // Making a call - use explicit registers
   FlushAllRegs();   /* Everything to home location */
   LoadValueDirectFixed(rl_src, rs_x0);
-  LoadWordDisp(rs_rA64_SELF, QUICK_ENTRYPOINT_OFFSET(8, pHandleFillArrayData).Int32Value(),
-               rs_rA64_LR);
+  LoadWordDisp(rs_xSELF, QUICK_ENTRYPOINT_OFFSET(8, pHandleFillArrayData).Int32Value(),
+               rs_xLR);
   // Materialize a pointer to the fill data image
   NewLIR3(kA64Adr2xd, rx1, 0, WrapPointer(tab_rec));
   ClobberCallerSave();
-  LIR* call_inst = OpReg(kOpBlx, rs_rA64_LR);
+  LIR* call_inst = OpReg(kOpBlx, rs_xLR);
   MarkSafepointPC(call_inst);
 }
 
@@ -206,7 +206,7 @@
       null_check_branch = OpCmpImmBranch(kCondEq, rs_x0, 0, NULL);
     }
   }
-  Load32Disp(rs_rA64_SELF, Thread::ThinLockIdOffset<8>().Int32Value(), rs_w1);
+  Load32Disp(rs_xSELF, Thread::ThinLockIdOffset<8>().Int32Value(), rs_w1);
   OpRegRegImm(kOpAdd, rs_x2, rs_x0, mirror::Object::MonitorOffset().Int32Value());
   NewLIR2(kA64Ldxr2rX, rw3, rx2);
   MarkPossibleNullPointerException(opt_flags);
@@ -221,9 +221,9 @@
   }
   // TODO: move to a slow path.
   // Go expensive route - artLockObjectFromCode(obj);
-  LoadWordDisp(rs_rA64_SELF, QUICK_ENTRYPOINT_OFFSET(8, pLockObject).Int32Value(), rs_rA64_LR);
+  LoadWordDisp(rs_xSELF, QUICK_ENTRYPOINT_OFFSET(8, pLockObject).Int32Value(), rs_xLR);
   ClobberCallerSave();
-  LIR* call_inst = OpReg(kOpBlx, rs_rA64_LR);
+  LIR* call_inst = OpReg(kOpBlx, rs_xLR);
   MarkSafepointPC(call_inst);
 
   LIR* success_target = NewLIR0(kPseudoTargetLabel);
@@ -254,7 +254,7 @@
       null_check_branch = OpCmpImmBranch(kCondEq, rs_x0, 0, NULL);
     }
   }
-  Load32Disp(rs_rA64_SELF, Thread::ThinLockIdOffset<8>().Int32Value(), rs_w1);
+  Load32Disp(rs_xSELF, Thread::ThinLockIdOffset<8>().Int32Value(), rs_w1);
   Load32Disp(rs_x0, mirror::Object::MonitorOffset().Int32Value(), rs_w2);
   MarkPossibleNullPointerException(opt_flags);
   LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_w1, rs_w2, NULL);
@@ -269,9 +269,9 @@
   }
   // TODO: move to a slow path.
   // Go expensive route - artUnlockObjectFromCode(obj);
-  LoadWordDisp(rs_rA64_SELF, QUICK_ENTRYPOINT_OFFSET(8, pUnlockObject).Int32Value(), rs_rA64_LR);
+  LoadWordDisp(rs_xSELF, QUICK_ENTRYPOINT_OFFSET(8, pUnlockObject).Int32Value(), rs_xLR);
   ClobberCallerSave();
-  LIR* call_inst = OpReg(kOpBlx, rs_rA64_LR);
+  LIR* call_inst = OpReg(kOpBlx, rs_xLR);
   MarkSafepointPC(call_inst);
 
   LIR* success_target = NewLIR0(kPseudoTargetLabel);
@@ -281,8 +281,8 @@
 void Arm64Mir2Lir::GenMoveException(RegLocation rl_dest) {
   int ex_offset = Thread::ExceptionOffset<8>().Int32Value();
   RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
-  LoadRefDisp(rs_rA64_SELF, ex_offset, rl_result.reg, kNotVolatile);
-  StoreRefDisp(rs_rA64_SELF, ex_offset, rs_xzr, kNotVolatile);
+  LoadRefDisp(rs_xSELF, ex_offset, rl_result.reg, kNotVolatile);
+  StoreRefDisp(rs_xSELF, ex_offset, rs_xzr, kNotVolatile);
   StoreValue(rl_dest, rl_result);
 }
 
@@ -293,7 +293,7 @@
   RegStorage reg_card_base = AllocTempWide();
   RegStorage reg_card_no = AllocTemp();
   LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
-  LoadWordDisp(rs_rA64_SELF, Thread::CardTableOffset<8>().Int32Value(), reg_card_base);
+  LoadWordDisp(rs_xSELF, Thread::CardTableOffset<8>().Int32Value(), reg_card_base);
   OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   // TODO(Arm64): generate "strb wB, [xB, wC, uxtw]" rather than "strb wB, [xB, xC]"?
   StoreBaseIndexed(reg_card_base, As64BitReg(reg_card_no), As32BitReg(reg_card_base),
@@ -341,33 +341,33 @@
     if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
       if (!large_frame) {
         // Load stack limit
-        LoadWordDisp(rs_rA64_SELF, Thread::StackEndOffset<8>().Int32Value(), rs_x9);
+        LoadWordDisp(rs_xSELF, Thread::StackEndOffset<8>().Int32Value(), rs_x9);
       }
     } else {
       // TODO(Arm64) Implement implicit checks.
       // Implicit stack overflow check.
       // Generate a load from [sp, #-framesize].  If this is in the stack
       // redzone we will get a segmentation fault.
-      // Load32Disp(rs_rA64_SP, -Thread::kStackOverflowReservedBytes, rs_wzr);
+      // Load32Disp(rs_wSP, -Thread::kStackOverflowReservedBytes, rs_wzr);
       // MarkPossibleStackOverflowException();
       LOG(FATAL) << "Implicit stack overflow checks not implemented.";
     }
   }
 
   if (frame_size_ > 0) {
-    OpRegImm64(kOpSub, rs_rA64_SP, spill_size);
+    OpRegImm64(kOpSub, rs_sp, spill_size);
   }
 
   /* Need to spill any FP regs? */
   if (fp_spill_mask_) {
     int spill_offset = spill_size - kArm64PointerSize*(num_fp_spills_ + num_core_spills_);
-    SpillFPRegs(rs_rA64_SP, spill_offset, fp_spill_mask_);
+    SpillFPRegs(rs_sp, spill_offset, fp_spill_mask_);
   }
 
   /* Spill core callee saves. */
   if (core_spill_mask_) {
     int spill_offset = spill_size - kArm64PointerSize*num_core_spills_;
-    SpillCoreRegs(rs_rA64_SP, spill_offset, core_spill_mask_);
+    SpillCoreRegs(rs_sp, spill_offset, core_spill_mask_);
   }
 
   if (!skip_overflow_check) {
@@ -383,11 +383,11 @@
           m2l_->ResetDefTracking();
           GenerateTargetLabel(kPseudoThrowTarget);
           // Unwinds stack.
-          m2l_->OpRegImm(kOpAdd, rs_rA64_SP, sp_displace_);
+          m2l_->OpRegImm(kOpAdd, rs_sp, sp_displace_);
           m2l_->ClobberCallerSave();
           ThreadOffset<8> func_offset = QUICK_ENTRYPOINT_OFFSET(8, pThrowStackOverflow);
           m2l_->LockTemp(rs_x8);
-          m2l_->LoadWordDisp(rs_rA64_SELF, func_offset.Int32Value(), rs_x8);
+          m2l_->LoadWordDisp(rs_xSELF, func_offset.Int32Value(), rs_x8);
           m2l_->NewLIR1(kA64Br1x, rs_x8.GetReg());
           m2l_->FreeTemp(rs_x8);
         }
@@ -399,26 +399,26 @@
       if (large_frame) {
         // Compare Expected SP against bottom of stack.
         // Branch to throw target if there is not enough room.
-        OpRegRegImm(kOpSub, rs_x9, rs_rA64_SP, frame_size_without_spills);
-        LoadWordDisp(rs_rA64_SELF, Thread::StackEndOffset<8>().Int32Value(), rs_x8);
+        OpRegRegImm(kOpSub, rs_x9, rs_sp, frame_size_without_spills);
+        LoadWordDisp(rs_xSELF, Thread::StackEndOffset<8>().Int32Value(), rs_x8);
         LIR* branch = OpCmpBranch(kCondUlt, rs_x9, rs_x8, nullptr);
         AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, spill_size));
-        OpRegCopy(rs_rA64_SP, rs_x9);  // Establish stack after checks.
+        OpRegCopy(rs_sp, rs_x9);  // Establish stack after checks.
       } else {
         /*
          * If the frame is small enough we are guaranteed to have enough space that remains to
          * handle signals on the user stack.
          * Establishes stack before checks.
          */
-        OpRegRegImm(kOpSub, rs_rA64_SP, rs_rA64_SP, frame_size_without_spills);
-        LIR* branch = OpCmpBranch(kCondUlt, rs_rA64_SP, rs_x9, nullptr);
+        OpRegRegImm(kOpSub, rs_sp, rs_sp, frame_size_without_spills);
+        LIR* branch = OpCmpBranch(kCondUlt, rs_sp, rs_x9, nullptr);
         AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, frame_size_));
       }
     } else {
-      OpRegImm(kOpSub, rs_rA64_SP, frame_size_without_spills);
+      OpRegImm(kOpSub, rs_sp, frame_size_without_spills);
     }
   } else {
-    OpRegImm(kOpSub, rs_rA64_SP, frame_size_without_spills);
+    OpRegImm(kOpSub, rs_sp, frame_size_without_spills);
   }
 
   FlushIns(ArgLocs, rl_method);
@@ -448,14 +448,14 @@
   /* Need to restore any FP callee saves? */
   if (fp_spill_mask_) {
     int spill_offset = frame_size_ - kArm64PointerSize*(num_fp_spills_ + num_core_spills_);
-    UnSpillFPRegs(rs_rA64_SP, spill_offset, fp_spill_mask_);
+    UnSpillFPRegs(rs_sp, spill_offset, fp_spill_mask_);
   }
   if (core_spill_mask_) {
     int spill_offset = frame_size_ - kArm64PointerSize*num_core_spills_;
-    UnSpillCoreRegs(rs_rA64_SP, spill_offset, core_spill_mask_);
+    UnSpillCoreRegs(rs_sp, spill_offset, core_spill_mask_);
   }
 
-  OpRegImm64(kOpAdd, rs_rA64_SP, frame_size_);
+  OpRegImm64(kOpAdd, rs_sp, frame_size_);
   NewLIR0(kA64Ret);
 }
 
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index ac32f6e..56fb2dd 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -599,9 +599,7 @@
 
 // Test suspend flag, return target of taken suspend branch
 LIR* Arm64Mir2Lir::OpTestSuspend(LIR* target) {
-  // FIXME: Define rA64_SUSPEND as w19, when we do not need two copies of reserved register.
-  // Note: The opcode is not set as wide, so actually we are using the 32-bit version register.
-  NewLIR3(kA64Subs3rRd, rA64_SUSPEND, rA64_SUSPEND, 1);
+  NewLIR3(kA64Subs3rRd, rwSUSPEND, rwSUSPEND, 1);
   return OpCondBranch((target == NULL) ? kCondEq : kCondNe, target);
 }
 
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index 0ebcefb..6105837 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -48,9 +48,9 @@
      rs_d16, rs_d17, rs_d18, rs_d19, rs_d20, rs_d21, rs_d22, rs_d23,
      rs_d24, rs_d25, rs_d26, rs_d27, rs_d28, rs_d29, rs_d30, rs_d31};
 static constexpr RegStorage reserved_regs_arr[] =
-    {rs_rA32_SUSPEND, rs_rA32_SELF, rs_rA32_SP, rs_rA32_LR, rs_wzr};
+    {rs_wSUSPEND, rs_wSELF, rs_wsp, rs_wLR, rs_wzr};
 static constexpr RegStorage reserved64_regs_arr[] =
-    {rs_rA64_SUSPEND, rs_rA64_SELF, rs_rA64_SP, rs_rA64_LR, rs_xzr};
+    {rs_xSUSPEND, rs_xSELF, rs_sp, rs_xLR, rs_xzr};
 // TUNING: Are there too many temp registers and too less promote target?
 // This definition need to be matched with runtime.cc, quick entry assembly and JNI compiler
 // Note: we are not able to call to C function directly if it un-match C ABI.
@@ -107,11 +107,11 @@
 RegStorage Arm64Mir2Lir::TargetReg(SpecialTargetRegister reg) {
   RegStorage res_reg = RegStorage::InvalidReg();
   switch (reg) {
-    case kSelf: res_reg = rs_rA64_SELF; break;
-    case kSuspend: res_reg = rs_rA64_SUSPEND; break;
-    case kLr: res_reg =  rs_rA64_LR; break;
+    case kSelf: res_reg = rs_xSELF; break;
+    case kSuspend: res_reg = rs_xSUSPEND; break;
+    case kLr: res_reg =  rs_xLR; break;
     case kPc: res_reg = RegStorage::InvalidReg(); break;
-    case kSp: res_reg =  rs_rA64_SP; break;
+    case kSp: res_reg =  rs_sp; break;
     case kArg0: res_reg = rs_x0; break;
     case kArg1: res_reg = rs_x1; break;
     case kArg2: res_reg = rs_x2; break;
@@ -130,7 +130,7 @@
     case kFArg7: res_reg = rs_f7; break;
     case kRet0: res_reg = rs_x0; break;
     case kRet1: res_reg = rs_x1; break;
-    case kInvokeTgt: res_reg = rs_rA64_LR; break;
+    case kInvokeTgt: res_reg = rs_xLR; break;
     case kHiddenArg: res_reg = rs_x12; break;
     case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
     case kCount: res_reg = RegStorage::InvalidReg(); break;
@@ -644,7 +644,7 @@
  */
 
 void Arm64Mir2Lir::AdjustSpillMask() {
-  core_spill_mask_ |= (1 << rs_rA64_LR.GetRegNum());
+  core_spill_mask_ |= (1 << rs_xLR.GetRegNum());
   num_core_spills_++;
 }
 
@@ -789,13 +789,13 @@
 RegStorage Arm64Mir2Lir::LoadHelper(ThreadOffset<8> offset) {
   // TODO(Arm64): use LoadWordDisp instead.
   //   e.g. LoadWordDisp(rs_rA64_SELF, offset.Int32Value(), rs_rA64_LR);
-  LoadBaseDisp(rs_rA64_SELF, offset.Int32Value(), rs_rA64_LR, k64, kNotVolatile);
-  return rs_rA64_LR;
+  LoadBaseDisp(rs_xSELF, offset.Int32Value(), rs_xLR, k64, kNotVolatile);
+  return rs_xLR;
 }
 
 LIR* Arm64Mir2Lir::CheckSuspendUsingLoad() {
   RegStorage tmp = rs_x0;
-  LoadWordDisp(rs_rA64_SELF, Thread::ThreadSuspendTriggerOffset<8>().Int32Value(), tmp);
+  LoadWordDisp(rs_xSELF, Thread::ThreadSuspendTriggerOffset<8>().Int32Value(), tmp);
   LIR* load2 = LoadWordDisp(tmp, 0, tmp);
   return load2;
 }
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index c8d45c6..e248410 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -554,7 +554,7 @@
   /* RegReg operations with SP in first parameter need extended register instruction form.
    * Only CMN and CMP instructions are implemented.
    */
-  if (r_dest_src1 == rs_rA64_SP) {
+  if (r_dest_src1 == rs_sp) {
     return OpRegRegExtend(op, r_dest_src1, r_src2, ENCODE_NO_EXTEND);
   } else {
     return OpRegRegShift(op, r_dest_src1, r_src2, ENCODE_NO_SHIFT);
@@ -1110,7 +1110,7 @@
 
   // TODO: in future may need to differentiate Dalvik accesses w/ spills
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-    DCHECK(r_base == rs_rA64_SP);
+    DCHECK(r_base == rs_sp);
     AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit());
   }
   return load;
@@ -1203,7 +1203,7 @@
 
   // TODO: In future, may need to differentiate Dalvik & spill accesses.
   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
-    DCHECK(r_base == rs_rA64_SP);
+    DCHECK(r_base == rs_sp);
     AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
   }
   return store;
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index fd20a81..481b00c 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1006,8 +1006,9 @@
 
       RegStorage new_index = index_;
       // Move index out of kArg1, either directly to kArg0, or to kArg2.
-      if (index_.GetReg() == m2l_->TargetReg(kArg1).GetReg()) {
-        if (array_base_.GetReg() == m2l_->TargetReg(kArg0).GetReg()) {
+      // TODO: clean-up to check not a number but with type
+      if (index_.GetRegNum() == m2l_->TargetReg(kArg1).GetRegNum()) {
+        if (array_base_.GetRegNum() == m2l_->TargetReg(kArg0).GetRegNum()) {
           m2l_->OpRegCopy(m2l_->TargetReg(kArg2), index_);
           new_index = m2l_->TargetReg(kArg2);
         } else {
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index 4c093c7..55ee18e 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -43,7 +43,7 @@
                                      size_t& oat_data_offset) {
   std::string error_msg;
   std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, false, false, &error_msg));
-  CHECK(elf_file.get() != NULL) << error_msg;
+  CHECK(elf_file.get() != nullptr) << error_msg;
 
   oat_loaded_size = elf_file->GetLoadedSize();
   CHECK_NE(0U, oat_loaded_size);
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 78757ec..e4dcaa7 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -20,6 +20,7 @@
 #include "base/unix_file/fd_file.h"
 #include "buffered_output_stream.h"
 #include "driver/compiler_driver.h"
+#include "dwarf.h"
 #include "elf_utils.h"
 #include "file_output_stream.h"
 #include "globals.h"
@@ -469,9 +470,9 @@
   pieces.push_back(ElfFilePiece(".hash", hash_builder_.section_.sh_offset,
                                 hash.data(), hash.size() * sizeof(Elf32_Word)));
   pieces.push_back(ElfFilePiece(".rodata", rodata_builder_.section_.sh_offset,
-                                NULL, rodata_builder_.section_.sh_size));
+                                nullptr, rodata_builder_.section_.sh_size));
   pieces.push_back(ElfFilePiece(".text", text_builder_.section_.sh_offset,
-                                NULL, text_builder_.section_.sh_size));
+                                nullptr, text_builder_.section_.sh_size));
   if (IncludingDebugSymbols()) {
     pieces.push_back(ElfFilePiece(".symtab", symtab_builder_.section_.sh_offset,
                                   symtab.data(), symtab.size() * sizeof(Elf32_Sym)));
@@ -547,7 +548,7 @@
   if (tag == DT_NULL) {
     return;
   }
-  dynamics_.push_back({NULL, tag, d_un});
+  dynamics_.push_back({nullptr, tag, d_un});
 }
 
 void ElfWriterQuick::ElfDynamicBuilder::AddDynamicTag(Elf32_Sword tag, Elf32_Word d_un,
@@ -650,7 +651,7 @@
   // Lets say the state is something like this.
   // +--------+       +--------+      +-----------+
   // | symtab |       | bucket |      |   chain   |
-  // |  NULL  |       | 1      |      | STN_UNDEF |
+  // |  nullptr  |       | 1      |      | STN_UNDEF |
   // | <sym1> |       | 4      |      | 2         |
   // | <sym2> |       |        |      | 5         |
   // | <sym3> |       |        |      | STN_UNDEF |
@@ -821,10 +822,10 @@
 
   bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr;
   if (generateDebugInformation) {
-    ElfRawSectionBuilder debug_info(".debug_info",   SHT_PROGBITS, 0, NULL, 0, 1, 0);
-    ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, NULL, 0, 1, 0);
-    ElfRawSectionBuilder debug_str(".debug_str",    SHT_PROGBITS, 0, NULL, 0, 1, 0);
-    ElfRawSectionBuilder debug_frame(".debug_frame",  SHT_PROGBITS, 0, NULL, 0, 4, 0);
+    ElfRawSectionBuilder debug_info(".debug_info",   SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    ElfRawSectionBuilder debug_str(".debug_str",    SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+    ElfRawSectionBuilder debug_frame(".debug_frame",  SHT_PROGBITS, 0, nullptr, 0, 4, 0);
     debug_frame.SetBuffer(*compiler_driver_->GetCallFrameInformation());
 
     FillInCFIInformation(oat_writer, debug_info.GetBuffer(),
@@ -866,31 +867,6 @@
   buf->push_back((data >> 8) & 0xff);
 }
 
-// DWARF constants needed to generate CFI information.
-enum {
-  // Tag encodings.
-  DW_TAG_compile_unit = 0x11,
-  DW_TAG_subprogram = 0X2e,
-
-  // Attribute encodings.
-  DW_AT_name = 0x03,
-  DW_AT_low_pc = 0x11,
-  DW_AT_high_pc = 0x12,
-  DW_AT_language = 0x13,
-
-  // Constant encoding.
-  DW_CHILDREN_no = 0x00,
-  DW_CHILDREN_yes = 0x01,
-
-  // Attribute form encodings.
-  DW_FORM_addr = 0x01,
-  DW_FORM_data1 = 0x0b,
-  DW_FORM_strp = 0x0e,
-
-  // Language encoding.
-  DW_LANG_Java = 0x000b
-};
-
 void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer,
                                           std::vector<uint8_t>* dbg_info,
                                           std::vector<uint8_t>* dbg_abbrev,
diff --git a/dalvikvm/Android.mk b/dalvikvm/Android.mk
index 5d838c0..a06b5c5 100644
--- a/dalvikvm/Android.mk
+++ b/dalvikvm/Android.mk
@@ -16,6 +16,8 @@
 
 LOCAL_PATH := $(call my-dir)
 
+include art/build/Android.common.mk
+
 dalvikvm_cflags := -Wall -Werror -Wextra -std=gnu++11
 
 include $(CLEAR_VARS)
@@ -27,6 +29,7 @@
 LOCAL_C_INCLUDES := art/runtime
 LOCAL_SHARED_LIBRARIES := libdl libnativehelper
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := dalvikvm32
 LOCAL_MODULE_STEM_64 := dalvikvm64
@@ -37,6 +40,10 @@
 include  $(BUILD_SYSTEM)/executable_prefer_symlink.mk
 
 ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)
+ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(ART_PHONY_TEST_TARGET_SUFFIX)
+ifdef 2ND_ART_PHONY_TEST_TARGET_SUFFIX
+  ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+endif
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := dalvikvm
@@ -48,7 +55,8 @@
 LOCAL_C_INCLUDES := art/runtime
 LOCAL_SHARED_LIBRARIES := libnativehelper
 LOCAL_LDFLAGS := -ldl -lpthread
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk
 LOCAL_IS_HOST_MODULE := true
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := dalvikvm32
@@ -56,7 +64,11 @@
 include external/libcxx/libcxx.mk
 include $(BUILD_HOST_EXECUTABLE)
 
-ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)32
-ifneq ($(HOST_PREFER_32_BIT),true)
-  ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)64
-endif
\ No newline at end of file
+# Create symlink for the primary version target.
+include  $(BUILD_SYSTEM)/executable_prefer_symlink.mk
+
+ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)
+ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(ART_PHONY_TEST_HOST_SUFFIX)
+ifdef 2ND_ART_PHONY_TEST_HOST_SUFFIX
+  ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+endif
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index bf04a54..280f6d0 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -875,6 +875,8 @@
       watch_dog_enabled = false;
     } else if (option == "--gen-gdb-info") {
       generate_gdb_information = true;
+      // Debug symbols are needed for gdb information.
+      include_debug_symbols = true;
     } else if (option == "--no-gen-gdb-info") {
       generate_gdb_information = false;
     } else if (option.starts_with("-j")) {
diff --git a/runtime/dwarf.h b/runtime/dwarf.h
new file mode 100644
index 0000000..370ad95
--- /dev/null
+++ b/runtime/dwarf.h
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DWARF_H_
+#define ART_RUNTIME_DWARF_H_
+
+namespace art {
+
+// Based on the Dwarf 4 specification at dwarfstd.com and issues marked
+// for inclusion in Dwarf 5 on same. Values not specified in the Dwarf 4
+// standard might change or be removed in the future and may be different
+// than the values used currently by other implementations for the same trait,
+// use at your own risk.
+
+enum Tag {
+  DW_TAG_array_type = 0x01,
+  DW_TAG_class_type = 0x02,
+  DW_TAG_entry_point = 0x03,
+  DW_TAG_enumeration_type = 0x04,
+  DW_TAG_formal_parameter = 0x05,
+  DW_TAG_imported_declaration = 0x08,
+  DW_TAG_label = 0x0a,
+  DW_TAG_lexical_block = 0x0b,
+  DW_TAG_member = 0x0d,
+  DW_TAG_pointer_type = 0x0f,
+  DW_TAG_reference_type = 0x10,
+  DW_TAG_compile_unit = 0x11,
+  DW_TAG_string_type = 0x12,
+  DW_TAG_structure_type = 0x13,
+  DW_TAG_subroutine_type = 0x15,
+  DW_TAG_typedef = 0x16,
+  DW_TAG_union_type = 0x17,
+  DW_TAG_unspecified_parameters = 0x18,
+  DW_TAG_variant = 0x19,
+  DW_TAG_common_block = 0x1a,
+  DW_TAG_common_inclusion = 0x1b,
+  DW_TAG_inheritance = 0x1c,
+  DW_TAG_inlined_subroutine = 0x1d,
+  DW_TAG_module = 0x1e,
+  DW_TAG_ptr_to_member_type = 0x1f,
+  DW_TAG_set_type = 0x20,
+  DW_TAG_subrange_type = 0x21,
+  DW_TAG_with_stmt = 0x22,
+  DW_TAG_access_declaration = 0x23,
+  DW_TAG_base_type = 0x24,
+  DW_TAG_catch_block = 0x25,
+  DW_TAG_const_type = 0x26,
+  DW_TAG_constant = 0x27,
+  DW_TAG_enumerator = 0x28,
+  DW_TAG_file_type = 0x29,
+  DW_TAG_friend = 0x2a,
+  DW_TAG_namelist = 0x2b,
+  DW_TAG_namelist_item = 0x2c,
+  DW_TAG_packed_type = 0x2d,
+  DW_TAG_subprogram = 0x2e,
+  DW_TAG_template_type_parameter = 0x2f,
+  DW_TAG_template_value_parameter = 0x30,
+  DW_TAG_thrown_type = 0x31,
+  DW_TAG_try_block = 0x32,
+  DW_TAG_variant_part = 0x33,
+  DW_TAG_variable = 0x34,
+  DW_TAG_volatile_type = 0x35,
+  DW_TAG_dwarf_procedure = 0x36,
+  DW_TAG_restrict_type = 0x37,
+  DW_TAG_interface_type = 0x38,
+  DW_TAG_namespace = 0x39,
+  DW_TAG_imported_module = 0x3a,
+  DW_TAG_unspecified_type = 0x3b,
+  DW_TAG_partial_unit = 0x3c,
+  DW_TAG_imported_unit = 0x3d,
+  DW_TAG_condition = 0x3f,
+  DW_TAG_shared_type = 0x40,
+  DW_TAG_type_unit = 0x41,
+  DW_TAG_rvalue_reference_type = 0x42,
+  DW_TAG_template_alias = 0x43,
+#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_TAG_coarray_type = 0x44,
+  DW_TAG_call_site = 0x45,
+  DW_TAG_call_site_parameter = 0x46,
+  DW_TAG_generic_subrange = 0x47,
+  DW_TAG_atomic_type = 0x48,
+  DW_TAG_dynamic_type = 0x49,
+  DW_TAG_aligned_type = 0x50,
+#endif
+  DW_TAG_lo_user = 0x4080,
+  DW_TAG_hi_user = 0xffff
+};
+
+enum Children : uint8_t {
+  DW_CHILDREN_no = 0x00,
+  DW_CHILDREN_yes = 0x01
+};
+
+enum Attribute {
+  DW_AT_sibling = 0x01,
+  DW_AT_location = 0x02,
+  DW_AT_name = 0x03,
+  DW_AT_ordering = 0x09,
+  DW_AT_byte_size = 0x0b,
+  DW_AT_bit_offset = 0x0c,
+  DW_AT_bit_size = 0x0d,
+  DW_AT_stmt_list = 0x10,
+  DW_AT_low_pc = 0x11,
+  DW_AT_high_pc = 0x12,
+  DW_AT_language = 0x13,
+  DW_AT_discr = 0x15,
+  DW_AT_discr_value = 0x16,
+  DW_AT_visibility = 0x17,
+  DW_AT_import = 0x18,
+  DW_AT_string_length = 0x19,
+  DW_AT_common_reference = 0x1a,
+  DW_AT_comp_dir = 0x1b,
+  DW_AT_const_value = 0x1c,
+  DW_AT_containing_type = 0x1d,
+  DW_AT_default_value = 0x1e,
+  DW_AT_inline = 0x20,
+  DW_AT_is_optional = 0x21,
+  DW_AT_lower_bound = 0x22,
+  DW_AT_producer = 0x25,
+  DW_AT_prototyped = 0x27,
+  DW_AT_return_addr = 0x2a,
+  DW_AT_start_scope = 0x2c,
+  DW_AT_bit_stride = 0x2e,
+  DW_AT_upper_bound = 0x2f,
+  DW_AT_abstract_origin = 0x31,
+  DW_AT_accessibility = 0x32,
+  DW_AT_address_class = 0x33,
+  DW_AT_artificial = 0x34,
+  DW_AT_base_types = 0x35,
+  DW_AT_calling_convention = 0x36,
+  DW_AT_count = 0x37,
+  DW_AT_data_member_location = 0x38,
+  DW_AT_decl_column = 0x39,
+  DW_AT_decl_file = 0x3a,
+  DW_AT_decl_line = 0x3b,
+  DW_AT_declaration = 0x3c,
+  DW_AT_discr_list = 0x3d,
+  DW_AT_encoding = 0x3e,
+  DW_AT_external = 0x3f,
+  DW_AT_frame_base = 0x40,
+  DW_AT_friend = 0x41,
+  DW_AT_identifier_case = 0x42,
+  DW_AT_macro_info = 0x43,
+  DW_AT_namelist_item = 0x44,
+  DW_AT_priority = 0x45,
+  DW_AT_segment = 0x46,
+  DW_AT_specification = 0x47,
+  DW_AT_static_link = 0x48,
+  DW_AT_type = 0x49,
+  DW_AT_use_location = 0x4a,
+  DW_AT_variable_parameter = 0x4b,
+  DW_AT_virtuality = 0x4c,
+  DW_AT_vtable_elem_location = 0x4d,
+  DW_AT_allocated = 0x4e,
+  DW_AT_associated = 0x4f,
+  DW_AT_data_location = 0x50,
+  DW_AT_byte_stride = 0x51,
+  DW_AT_entry_pc = 0x52,
+  DW_AT_use_UTF8 = 0x53,
+  DW_AT_extension = 0x54,
+  DW_AT_ranges = 0x55,
+  DW_AT_trampoline = 0x56,
+  DW_AT_call_column = 0x57,
+  DW_AT_call_file = 0x58,
+  DW_AT_call_line = 0x59,
+  DW_AT_description = 0x5a,
+  DW_AT_binary_scale = 0x5b,
+  DW_AT_decimal_scale = 0x5c,
+  DW_AT_small = 0x5d,
+  DW_AT_decimal_sign = 0x5e,
+  DW_AT_digit_count = 0x5f,
+  DW_AT_picture_string = 0x60,
+  DW_AT_mutable = 0x61,
+  DW_AT_threads_scaled = 0x62,
+  DW_AT_explicit = 0x63,
+  DW_AT_object_pointer = 0x64,
+  DW_AT_endianity = 0x65,
+  DW_AT_elemental = 0x66,
+  DW_AT_pure = 0x67,
+  DW_AT_recursive = 0x68,
+  DW_AT_signature = 0x69,
+  DW_AT_main_subprogram = 0x6a,
+  DW_AT_data_bit_offset = 0x6b,
+  DW_AT_const_expr = 0x6c,
+  DW_AT_enum_class = 0x6d,
+#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,
+  DW_AT_call_site_target_clobbered = 0x72,
+  DW_AT_tail_call = 0x73,
+  DW_AT_all_tail_call_sites = 0x74,
+  DW_AT_all_call_sites = 0x75,
+  DW_AT_all_source_call_sites = 0x76,
+  DW_AT_call_site_parameter = 0x77,
+  DW_AT_tail_call = 0x78,
+  DW_AT_all_tail_call_sites = 0x79,
+  DW_AT_all_call_sites = 0x7a,
+  DW_AT_all_source_call_sites = 0x7b,
+  DW_AT_rank = 0x7c,
+  DW_AT_string_bitsize = 0x7d,
+  DW_AT_string_byte_size = 0x7e,
+  DW_AT_reference = 0x7f,
+  DW_AT_rvalue_reference = 0x80,
+  DW_AT_noreturn = 0x81,
+  DW_AT_alignment = 0x82,
+#endif
+  DW_AT_lo_user = 0x2000,
+  DW_AT_hi_user = 0xffff
+};
+
+enum Form : uint8_t {
+  DW_FORM_addr = 0x01,
+  DW_FORM_block2 = 0x03,
+  DW_FORM_block4 = 0x04,
+  DW_FORM_data2 = 0x05,
+  DW_FORM_data4 = 0x06,
+  DW_FORM_data8 = 0x07,
+  DW_FORM_string = 0x08,
+  DW_FORM_block = 0x09,
+  DW_FORM_block1 = 0x0a,
+  DW_FORM_data1 = 0x0b,
+  DW_FORM_flag = 0x0c,
+  DW_FORM_sdata = 0x0d,
+  DW_FORM_strp = 0x0e,
+  DW_FORM_udata = 0x0f,
+  DW_FORM_ref_addr = 0x10,
+  DW_FORM_ref1 = 0x11,
+  DW_FORM_ref2 = 0x12,
+  DW_FORM_ref4 = 0x13,
+  DW_FORM_ref8 = 0x14,
+  DW_FORM_ref_udata = 0x15,
+  DW_FORM_indirect = 0x16,
+  DW_FORM_sec_offset = 0x17,
+  DW_FORM_exprloc = 0x18,
+  DW_FORM_flag_present = 0x19,
+  DW_FORM_ref_sig8 = 0x20
+};
+
+enum Operation : uint16_t {
+  DW_OP_addr = 0x03,
+  DW_OP_deref = 0x06,
+  DW_OP_const1u = 0x08,
+  DW_OP_const1s = 0x09,
+  DW_OP_const2u = 0x0a,
+  DW_OP_const2s = 0x0b,
+  DW_OP_const4u = 0x0c,
+  DW_OP_const4s = 0x0d,
+  DW_OP_const8u = 0x0e,
+  DW_OP_const8s = 0x0f,
+  DW_OP_constu = 0x10,
+  DW_OP_consts = 0x11,
+  DW_OP_dup = 0x12,
+  DW_OP_drop = 0x13,
+  DW_OP_over = 0x14,
+  DW_OP_pick = 0x15,
+  DW_OP_swap = 0x16,
+  DW_OP_rot = 0x17,
+  DW_OP_xderef = 0x18,
+  DW_OP_abs = 0x19,
+  DW_OP_and = 0x1a,
+  DW_OP_div = 0x1b,
+  DW_OP_minus = 0x1c,
+  DW_OP_mod = 0x1d,
+  DW_OP_mul = 0x1e,
+  DW_OP_neg = 0x1f,
+  DW_OP_not = 0x20,
+  DW_OP_or = 0x21,
+  DW_OP_plus = 0x22,
+  DW_OP_plus_uconst = 0x23,
+  DW_OP_shl = 0x24,
+  DW_OP_shr = 0x25,
+  DW_OP_shra = 0x26,
+  DW_OP_xor = 0x27,
+  DW_OP_skip = 0x2f,
+  DW_OP_bra = 0x28,
+  DW_OP_eq = 0x29,
+  DW_OP_ge = 0x2a,
+  DW_OP_gt = 0x2b,
+  DW_OP_le = 0x2c,
+  DW_OP_lt = 0x2d,
+  DW_OP_ne = 0x2e,
+  DW_OP_lit0 = 0x30,
+  DW_OP_lit1 = 0x31,
+  DW_OP_lit2 = 0x32,
+  DW_OP_lit3 = 0x33,
+  DW_OP_lit4 = 0x34,
+  DW_OP_lit5 = 0x35,
+  DW_OP_lit6 = 0x36,
+  DW_OP_lit7 = 0x37,
+  DW_OP_lit8 = 0x38,
+  DW_OP_lit9 = 0x39,
+  DW_OP_lit10 = 0x3a,
+  DW_OP_lit11 = 0x3b,
+  DW_OP_lit12 = 0x3c,
+  DW_OP_lit13 = 0x3d,
+  DW_OP_lit14 = 0x3e,
+  DW_OP_lit15 = 0x3f,
+  DW_OP_lit16 = 0x40,
+  DW_OP_lit17 = 0x41,
+  DW_OP_lit18 = 0x42,
+  DW_OP_lit19 = 0x43,
+  DW_OP_lit20 = 0x44,
+  DW_OP_lit21 = 0x45,
+  DW_OP_lit22 = 0x46,
+  DW_OP_lit23 = 0x47,
+  DW_OP_lit24 = 0x48,
+  DW_OP_lit25 = 0x49,
+  DW_OP_lit26 = 0x4a,
+  DW_OP_lit27 = 0x4b,
+  DW_OP_lit28 = 0x4c,
+  DW_OP_lit29 = 0x4d,
+  DW_OP_lit30 = 0x4e,
+  DW_OP_lit31 = 0x4f,
+  DW_OP_reg0 = 0x50,
+  DW_OP_reg1 = 0x51,
+  DW_OP_reg2 = 0x52,
+  DW_OP_reg3 = 0x53,
+  DW_OP_reg4 = 0x54,
+  DW_OP_reg5 = 0x55,
+  DW_OP_reg6 = 0x56,
+  DW_OP_reg7 = 0x57,
+  DW_OP_reg8 = 0x58,
+  DW_OP_reg9 = 0x59,
+  DW_OP_reg10 = 0x5a,
+  DW_OP_reg11 = 0x5b,
+  DW_OP_reg12 = 0x5c,
+  DW_OP_reg13 = 0x5d,
+  DW_OP_reg14 = 0x5e,
+  DW_OP_reg15 = 0x5f,
+  DW_OP_reg16 = 0x60,
+  DW_OP_reg17 = 0x61,
+  DW_OP_reg18 = 0x62,
+  DW_OP_reg19 = 0x63,
+  DW_OP_reg20 = 0x64,
+  DW_OP_reg21 = 0x65,
+  DW_OP_reg22 = 0x66,
+  DW_OP_reg23 = 0x67,
+  DW_OP_reg24 = 0x68,
+  DW_OP_reg25 = 0x69,
+  DW_OP_reg26 = 0x6a,
+  DW_OP_reg27 = 0x6b,
+  DW_OP_reg28 = 0x6c,
+  DW_OP_reg29 = 0x6d,
+  DW_OP_reg30 = 0x6e,
+  DW_OP_reg31 = 0x6f,
+  DW_OP_breg0 = 0x50,
+  DW_OP_breg1 = 0x51,
+  DW_OP_breg2 = 0x52,
+  DW_OP_breg3 = 0x53,
+  DW_OP_breg4 = 0x54,
+  DW_OP_breg5 = 0x55,
+  DW_OP_breg6 = 0x56,
+  DW_OP_breg7 = 0x57,
+  DW_OP_breg8 = 0x58,
+  DW_OP_breg9 = 0x59,
+  DW_OP_breg10 = 0x5a,
+  DW_OP_breg11 = 0x5b,
+  DW_OP_breg12 = 0x5c,
+  DW_OP_breg13 = 0x5d,
+  DW_OP_breg14 = 0x5e,
+  DW_OP_breg15 = 0x5f,
+  DW_OP_breg16 = 0x60,
+  DW_OP_breg17 = 0x61,
+  DW_OP_breg18 = 0x62,
+  DW_OP_breg19 = 0x63,
+  DW_OP_breg20 = 0x64,
+  DW_OP_breg21 = 0x65,
+  DW_OP_breg22 = 0x66,
+  DW_OP_breg23 = 0x67,
+  DW_OP_breg24 = 0x68,
+  DW_OP_breg25 = 0x69,
+  DW_OP_breg26 = 0x6a,
+  DW_OP_breg27 = 0x6b,
+  DW_OP_breg28 = 0x6c,
+  DW_OP_breg29 = 0x6d,
+  DW_OP_breg30 = 0x6e,
+  DW_OP_breg31 = 0x6f,
+  DW_OP_regx = 0x90,
+  DW_OP_fbreg = 0x91,
+  DW_OP_bregx = 0x92,
+  DW_OP_piece = 0x93,
+  DW_OP_deref_size = 0x94,
+  DW_OP_xderef_size = 0x95,
+  DW_OP_nop = 0x96,
+  DW_OP_push_object_address = 0x97,
+  DW_OP_call2 = 0x98,
+  DW_OP_call4 = 0x99,
+  DW_OP_call_ref = 0x9a,
+  DW_OP_form_tls_address = 0x9b,
+  DW_OP_call_frame_cfa = 0x9c,
+  DW_OP_bit_piece = 0x9d,
+  DW_OP_implicit_value = 0x9e,
+  DW_OP_stack_value = 0x9f,
+#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_OP_entry_value = 0xa0,
+  DW_OP_const_type = 0xa1,
+  DW_OP_regval_type = 0xa2,
+  DW_OP_deref_type = 0xa3,
+  DW_OP_xderef_type = 0xa4,
+  DW_OP_convert = 0xa5,
+  DW_OP_reinterpret = 0xa6,
+#endif
+  DW_OP_lo_user = 0xe0,
+  DW_OP_hi_user = 0xff
+};
+
+enum BaseTypeEncoding : uint8_t {
+  DW_ATE_address = 0x01,
+  DW_ATE_boolean = 0x02,
+  DW_ATE_complex_float = 0x03,
+  DW_ATE_float = 0x04,
+  DW_ATE_signed = 0x05,
+  DW_ATE_signed_char = 0x06,
+  DW_ATE_unsigned = 0x07,
+  DW_ATE_unsigned_char = 0x08,
+  DW_ATE_imaginary_float = 0x09,
+  DW_ATE_packed_decimal = 0x0a,
+  DW_ATE_numeric_string = 0x0b,
+  DW_ATE_edited = 0x0c,
+  DW_ATE_signed_fixed = 0x0d,
+  DW_ATE_unsigned_fixed = 0x0e,
+  DW_ATE_decimal_float = 0x0f,
+  DW_ATE_UTF = 0x10,
+  DW_ATE_lo_user = 0x80,
+  DW_ATE_hi_user = 0xff
+};
+
+enum DecimalSign : uint8_t {
+  DW_DS_unsigned = 0x01,
+  DW_DS_leading_overpunch = 0x02,
+  DW_DS_trailing_overpunch = 0x03,
+  DW_DS_leading_separate = 0x04,
+  DW_DS_trailing_separate = 0x05
+};
+
+enum Endianity : uint8_t {
+  DW_END_default = 0x00,
+  DW_END_big = 0x01,
+  DW_END_little = 0x02,
+  DW_END_lo_user = 0x40,
+  DW_END_hi_user = 0xff
+};
+
+enum Accessibility : uint8_t {
+  DW_ACCESS_public = 0x01,
+  DW_ACCESS_protected = 0x02,
+  DW_ACCESS_private = 0x03
+};
+
+enum Visibility : uint8_t {
+  DW_VIS_local = 0x01,
+  DW_VIS_exported = 0x02,
+  DW_VIS_qualified = 0x03
+};
+
+enum Virtuality : uint8_t {
+  DW_VIRTUALITY_none = 0x00,
+  DW_VIRTUALITY_virtual = 0x01,
+  DW_VIRTUALITY_pure_virtual = 0x02
+};
+
+enum Language {
+  DW_LANG_C89 = 0x01,
+  DW_LANG_C = 0x02,
+  DW_LANG_Ada83 = 0x03,
+  DW_LANG_C_plus_plus = 0x04,
+  DW_LANG_Cobol74 = 0x05,
+  DW_LANG_Cobol85 = 0x06,
+  DW_LANG_Fortran77 = 0x07,
+  DW_LANG_Fortran90 = 0x08,
+  DW_LANG_Pascal83 = 0x09,
+  DW_LANG_Modula2 = 0x0a,
+  DW_LANG_Java = 0x0b,
+  DW_LANG_C99 = 0x0c,
+  DW_LANG_Ada95 = 0x0d,
+  DW_LANG_Fortran95 = 0x0e,
+  DW_LANG_PLI = 0x0f,
+  DW_LANG_ObjC = 0x10,
+  DW_LANG_ObjC_plus_plus = 0x11,
+  DW_LANG_UPC = 0x12,
+  DW_LANG_D = 0x13,
+  DW_LANG_Python = 0x14,
+#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_LANG_OpenCL = 0x15,
+  DW_LANG_Go = 0x16,
+  DW_LANG_Modula3 = 0x17,
+  DW_LANG_Haskell = 0x18,
+  DW_LANG_C_plus_plus_03 = 0x19,
+  DW_LANG_C_plus_plus_11 = 0x1a,
+  DW_LANG_OCaml = 0x1b,
+  DW_LANG_Rust = 0x1c,
+  DW_LANG_C11 = 0x1d,
+  DW_LANG_Swift = 0x1e,
+  DW_LANG_Julia = 0x1f,
+#endif
+  DW_LANG_lo_user = 0x8000,
+  DW_LANG_hi_user = 0xffff
+};
+
+enum Identifier : uint8_t {
+  DW_ID_case_sensitive = 0x00,
+  DW_ID_up_case = 0x01,
+  DW_ID_down_case = 0x02,
+  DW_ID_case_insensitive = 0x03
+};
+
+enum CallingConvention : uint8_t {
+  DW_CC_normal = 0x01,
+  DW_CC_program = 0x02,
+  DW_CC_nocall = 0x03,
+  DW_CC_lo_user = 0x40,
+  DW_CC_hi_user = 0xff
+};
+
+enum Inline : uint8_t {
+  DW_INL_not_inlined = 0x00,
+  DW_INL_inlined = 0x01,
+  DW_INL_declared_not_inlined = 0x02,
+  DW_INL_declared_inlined = 0x03
+};
+
+enum ArrayOrdering : uint8_t {
+  DW_ORD_row_major = 0x00,
+  DW_ORD_col_major = 0x01
+};
+
+enum DiscriminantList : uint8_t {
+  DW_DSC_label = 0x00,
+  DW_DSC_range = 0x01
+};
+
+enum LineNumberOpcode : uint8_t {
+  DW_LNS_copy = 0x01,
+  DW_LNS_advance_pc = 0x02,
+  DW_LNS_advance_line = 0x03,
+  DW_LNS_set_file = 0x04,
+  DW_LNS_set_column = 0x05,
+  DW_LNS_negate_stmt = 0x06,
+  DW_LNS_set_basic_block = 0x07,
+  DW_LNS_const_add_pc = 0x08,
+  DW_LNS_fixed_advance_pc = 0x09,
+  DW_LNS_set_prologue_end = 0x0a,
+  DW_LNS_set_epilogue_begin = 0x0b,
+  DW_LNS_set_isa = 0x0c
+};
+
+enum LineNumberExtendedOpcode : uint8_t {
+  DW_LNE_end_sequence = 0x01,
+  DW_LNE_set_address = 0x02,
+  DW_LNE_define_file = 0x03,
+  DW_LNE_set_discriminator = 0x04,
+  DW_LNE_lo_user = 0x80,
+  DW_LNE_hi_user = 0xff
+};
+
+#ifdef INCLUDE_DWARF5_VALUES
+enum LineNumberFormat : uint8_t {
+  // 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_LNF_path = 0x1,
+  DW_LNF_include_index = 0x2,
+  DW_LNF_timestamp = 0x3,
+  DW_LNF_size = 0x4,
+  DW_LNF_MD5 = 0x5,
+  DW_LNF_lo_user = 0x2000,
+  DW_LNF_hi_user = 0x3fff
+};
+#endif
+
+enum MacroInfo : uint8_t {
+  DW_MACINFO_define = 0x01,
+  DW_MACINFO_undef = 0x02,
+  DW_MACINFO_start_file = 0x03,
+  DW_MACINFO_end_file = 0x04,
+  DW_MACINFO_vendor_ext = 0xff
+};
+
+#ifdef INCLUDE_DWARF5_VALUES
+enum Macro : uint8_t {
+  // 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_MACRO_define = 0x01,
+  DW_MACRO_undef = 0x02,
+  DW_MACRO_start_file = 0x03,
+  DW_MACRO_end_file = 0x04,
+  DW_MACRO_define_indirect = 0x05,
+  DW_MACRO_undef_indirect = 0x06,
+  DW_MACRO_transparent_include = 0x07,
+  DW_MACRO_define_indirectx = 0x0b,
+  DW_MACRO_undef_indirectx = 0x0c,
+  DW_MACRO_lo_user = 0xe0,
+  DW_MACRO_hi_user = 0xff
+};
+#endif
+
+const uint32_t CIE_ID_32 = 0xffffffff;
+const uint64_t CIE_ID_64 = 0xffffffffffffffff;
+
+enum CallFrameInstruction : uint8_t {
+  DW_CFA_advance_loc = 0x40,
+  DW_CFA_offset = 0x80,
+  DW_CFA_restore = 0xc0,
+  DW_CFA_nop = 0x00,
+  DW_CFA_set_loc = 0x01,
+  DW_CFA_advance_loc1 = 0x02,
+  DW_CFA_advance_loc2 = 0x03,
+  DW_CFA_advance_loc4 = 0x04,
+  DW_CFA_offset_extended = 0x05,
+  DW_CFA_restore_extended = 0x06,
+  DW_CFA_undefined = 0x07,
+  DW_CFA_same_value = 0x08,
+  DW_CFA_register = 0x09,
+  DW_CFA_remember_state = 0x0a,
+  DW_CFA_restore_state = 0x0b,
+  DW_CFA_def_cfa = 0x0c,
+  DW_CFA_def_cfa_register = 0x0d,
+  DW_CFA_def_cfa_offset = 0x0e,
+  DW_CFA_def_cfa_expression = 0x0f,
+  DW_CFA_expression = 0x10,
+  DW_CFA_offset_extended_sf = 0x11,
+  DW_CFA_def_cfa_sf = 0x12,
+  DW_CFA_def_cfa_offset_sf = 0x13,
+  DW_CFA_val_offset = 0x14,
+  DW_CFA_val_offset_sf = 0x15,
+  DW_CFA_val_expression = 0x16,
+  DW_CFA_lo_user = 0x1c,
+  DW_CFA_hi_user = 0x3f
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DWARF_H_
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 0df8211..bb33978 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -22,6 +22,8 @@
 #include "base/logging.h"
 #include "base/stringprintf.h"
 #include "base/stl_util.h"
+#include "dwarf.h"
+#include "leb128.h"
 #include "utils.h"
 #include "instruction_set.h"
 
@@ -108,43 +110,51 @@
   : file_(file),
     writable_(writable),
     program_header_only_(program_header_only),
-    header_(NULL),
-    base_address_(NULL),
-    program_headers_start_(NULL),
-    section_headers_start_(NULL),
-    dynamic_program_header_(NULL),
-    dynamic_section_start_(NULL),
-    symtab_section_start_(NULL),
-    dynsym_section_start_(NULL),
-    strtab_section_start_(NULL),
-    dynstr_section_start_(NULL),
-    hash_section_start_(NULL),
-    symtab_symbol_table_(NULL),
-    dynsym_symbol_table_(NULL),
-    jit_elf_image_(NULL),
-    jit_gdb_entry_(NULL) {
-  CHECK(file != NULL);
+    header_(nullptr),
+    base_address_(nullptr),
+    program_headers_start_(nullptr),
+    section_headers_start_(nullptr),
+    dynamic_program_header_(nullptr),
+    dynamic_section_start_(nullptr),
+    symtab_section_start_(nullptr),
+    dynsym_section_start_(nullptr),
+    strtab_section_start_(nullptr),
+    dynstr_section_start_(nullptr),
+    hash_section_start_(nullptr),
+    symtab_symbol_table_(nullptr),
+    dynsym_symbol_table_(nullptr),
+    jit_elf_image_(nullptr),
+    jit_gdb_entry_(nullptr) {
+  CHECK(file != nullptr);
 }
 
 ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only,
                        std::string* error_msg) {
   std::unique_ptr<ElfFile> elf_file(new ElfFile(file, writable, program_header_only));
-  if (!elf_file->Setup(error_msg)) {
-    return nullptr;
-  }
-  return elf_file.release();
-}
-
-bool ElfFile::Setup(std::string* error_msg) {
   int prot;
   int flags;
-  if (writable_) {
+  if (writable) {
     prot = PROT_READ | PROT_WRITE;
     flags = MAP_SHARED;
   } else {
     prot = PROT_READ;
     flags = MAP_PRIVATE;
   }
+  if (!elf_file->Setup(prot, flags, error_msg)) {
+    return nullptr;
+  }
+  return elf_file.release();
+}
+
+ElfFile* ElfFile::Open(File* file, int prot, int flags, std::string* error_msg) {
+  std::unique_ptr<ElfFile> elf_file(new ElfFile(file, (prot & PROT_WRITE) == PROT_WRITE, false));
+  if (!elf_file->Setup(prot, flags, error_msg)) {
+    return nullptr;
+  }
+  return elf_file.release();
+}
+
+bool ElfFile::Setup(int prot, int flags, std::string* error_msg) {
   int64_t temp_file_length = file_->GetLength();
   if (temp_file_length < 0) {
     errno = -temp_file_length;
@@ -201,7 +211,7 @@
 
     // Find .dynamic section info from program header
     dynamic_program_header_ = FindProgamHeaderByType(PT_DYNAMIC);
-    if (dynamic_program_header_ == NULL) {
+    if (dynamic_program_header_ == nullptr) {
       *error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'",
                                 file_->GetPath().c_str());
       return false;
@@ -263,14 +273,14 @@
 }
 
 bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
-  if (map == NULL) {
+  if (map == nullptr) {
     // MemMap::Open should have already set an error.
     DCHECK(!error_msg->empty());
     return false;
   }
   map_.reset(map);
-  CHECK(map_.get() != NULL) << file_->GetPath();
-  CHECK(map_->Begin() != NULL) << file_->GetPath();
+  CHECK(map_.get() != nullptr) << file_->GetPath();
+  CHECK(map_->Begin() != nullptr) << file_->GetPath();
 
   header_ = reinterpret_cast<Elf32_Ehdr*>(map_->Begin());
   if ((ELFMAG0 != header_->e_ident[EI_MAG0])
@@ -397,27 +407,27 @@
 
 
 Elf32_Ehdr& ElfFile::GetHeader() const {
-  CHECK(header_ != NULL);
+  CHECK(header_ != nullptr);
   return *header_;
 }
 
 byte* ElfFile::GetProgramHeadersStart() const {
-  CHECK(program_headers_start_ != NULL);
+  CHECK(program_headers_start_ != nullptr);
   return program_headers_start_;
 }
 
 byte* ElfFile::GetSectionHeadersStart() const {
-  CHECK(section_headers_start_ != NULL);
+  CHECK(section_headers_start_ != nullptr);
   return section_headers_start_;
 }
 
 Elf32_Phdr& ElfFile::GetDynamicProgramHeader() const {
-  CHECK(dynamic_program_header_ != NULL);
+  CHECK(dynamic_program_header_ != nullptr);
   return *dynamic_program_header_;
 }
 
 Elf32_Dyn* ElfFile::GetDynamicSectionStart() const {
-  CHECK(dynamic_section_start_ != NULL);
+  CHECK(dynamic_section_start_ != nullptr);
   return dynamic_section_start_;
 }
 
@@ -435,10 +445,10 @@
     }
     default: {
       LOG(FATAL) << section_type;
-      symbol_section_start = NULL;
+      symbol_section_start = nullptr;
     }
   }
-  CHECK(symbol_section_start != NULL);
+  CHECK(symbol_section_start != nullptr);
   return symbol_section_start;
 }
 
@@ -456,17 +466,17 @@
     }
     default: {
       LOG(FATAL) << section_type;
-      string_section_start = NULL;
+      string_section_start = nullptr;
     }
   }
-  CHECK(string_section_start != NULL);
+  CHECK(string_section_start != nullptr);
   return string_section_start;
 }
 
 const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
   if (i == 0) {
-    return NULL;
+    return nullptr;
   }
   const char* string_section_start = GetStringSectionStart(section_type);
   const char* string = string_section_start + i;
@@ -474,7 +484,7 @@
 }
 
 Elf32_Word* ElfFile::GetHashSectionStart() const {
-  CHECK(hash_section_start_ != NULL);
+  CHECK(hash_section_start_ != nullptr);
   return hash_section_start_;
 }
 
@@ -516,7 +526,7 @@
       return &program_header;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 Elf32_Word ElfFile::GetSectionHeaderNum() const {
@@ -543,7 +553,7 @@
       return &section_header;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 // from bionic
@@ -565,6 +575,15 @@
 }
 
 const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
+  const Elf32_Sym* sym = FindDynamicSymbol(symbol_name);
+  if (sym != nullptr) {
+    return base_address_ + sym->st_value;
+  } else {
+    return nullptr;
+  }
+}
+
+const Elf32_Sym* ElfFile::FindDynamicSymbol(const std::string& symbol_name) const {
   Elf32_Word hash = elfhash(symbol_name.c_str());
   Elf32_Word bucket_index = hash % GetHashBucketNum();
   Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index);
@@ -572,11 +591,11 @@
     Elf32_Sym& symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
     const char* name = GetString(SHT_DYNSYM, symbol.st_name);
     if (symbol_name == name) {
-      return base_address_ + symbol.st_value;
+      return &symbol;
     }
     symbol_and_chain_index = GetHashChain(symbol_and_chain_index);
   }
-  return NULL;
+  return nullptr;
 }
 
 bool ElfFile::IsSymbolSectionType(Elf32_Word section_type) {
@@ -606,7 +625,7 @@
     }
     default: {
       LOG(FATAL) << section_type;
-      return NULL;
+      return nullptr;
     }
   }
 }
@@ -618,12 +637,12 @@
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
 
   SymbolTable** symbol_table = GetSymbolTable(section_type);
-  if (*symbol_table != NULL || build_map) {
-    if (*symbol_table == NULL) {
+  if (*symbol_table != nullptr || build_map) {
+    if (*symbol_table == nullptr) {
       DCHECK(build_map);
       *symbol_table = new SymbolTable;
       Elf32_Shdr* symbol_section = FindSectionByType(section_type);
-      CHECK(symbol_section != NULL) << file_->GetPath();
+      CHECK(symbol_section != nullptr) << file_->GetPath();
       Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
       for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
         Elf32_Sym& symbol = GetSymbol(section_type, i);
@@ -632,7 +651,7 @@
           continue;
         }
         const char* name = GetString(string_section, symbol.st_name);
-        if (name == NULL) {
+        if (name == nullptr) {
           continue;
         }
         std::pair<SymbolTable::iterator, bool> result =
@@ -647,36 +666,36 @@
         }
       }
     }
-    CHECK(*symbol_table != NULL);
+    CHECK(*symbol_table != nullptr);
     SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name);
     if (it == (*symbol_table)->end()) {
-      return NULL;
+      return nullptr;
     }
     return it->second;
   }
 
   // Fall back to linear search
   Elf32_Shdr* symbol_section = FindSectionByType(section_type);
-  CHECK(symbol_section != NULL) << file_->GetPath();
+  CHECK(symbol_section != nullptr) << file_->GetPath();
   Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
   for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
     Elf32_Sym& symbol = GetSymbol(section_type, i);
     const char* name = GetString(string_section, symbol.st_name);
-    if (name == NULL) {
+    if (name == nullptr) {
       continue;
     }
     if (symbol_name == name) {
       return &symbol;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 Elf32_Addr ElfFile::FindSymbolAddress(Elf32_Word section_type,
                                       const std::string& symbol_name,
                                       bool build_map) {
   Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map);
-  if (symbol == NULL) {
+  if (symbol == nullptr) {
     return 0;
   }
   return symbol->st_value;
@@ -688,7 +707,7 @@
   CHECK_EQ(static_cast<Elf32_Word>(SHT_STRTAB), string_section.sh_type) << file_->GetPath();
   CHECK_LT(i, string_section.sh_size) << file_->GetPath();
   if (i == 0) {
-    return NULL;
+    return nullptr;
   }
   byte* strings = Begin() + string_section.sh_offset;
   byte* string = strings + i;
@@ -846,7 +865,7 @@
       std::string reservation_name("ElfFile reservation for ");
       reservation_name += file_->GetPath();
       std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(),
-                                                     NULL, GetLoadedSize(), PROT_NONE, false,
+                                                     nullptr, GetLoadedSize(), PROT_NONE, false,
                                                      error_msg));
       if (reserve.get() == nullptr) {
         *error_msg = StringPrintf("Failed to allocate %s: %s",
@@ -970,29 +989,323 @@
   return false;
 }
 
-static bool check_section_name(ElfFile& file, int section_num, const char *name) {
-  Elf32_Shdr& section_header = file.GetSectionHeader(section_num);
-  const char *section_name = file.GetString(SHT_SYMTAB, section_header.sh_name);
-  return strcmp(name, section_name) == 0;
+
+Elf32_Shdr* ElfFile::FindSectionByName(const std::string& name) const {
+  CHECK(!program_header_only_);
+  Elf32_Shdr& shstrtab_sec = GetSectionNameStringSection();
+  for (uint32_t i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf32_Shdr& shdr = GetSectionHeader(i);
+    const char* sec_name = GetString(shstrtab_sec, shdr.sh_name);
+    if (sec_name == nullptr) {
+      continue;
+    }
+    if (name == sec_name) {
+      return &shdr;
+    }
+  }
+  return nullptr;
 }
 
-static void IncrementUint32(byte *p, uint32_t increment) {
-  uint32_t *u = reinterpret_cast<uint32_t *>(p);
-  *u += increment;
+struct PACKED(1) FDE {
+  uint32_t raw_length_;
+  uint32_t GetLength() {
+    return raw_length_ + sizeof(raw_length_);
+  }
+  uint32_t CIE_pointer;
+  uint32_t initial_location;
+  uint32_t address_range;
+  uint8_t instructions[0];
+};
+
+static FDE* NextFDE(FDE* frame) {
+  byte* fde_bytes = reinterpret_cast<byte*>(frame);
+  fde_bytes += frame->GetLength();
+  return reinterpret_cast<FDE*>(fde_bytes);
 }
 
-static void RoundAndClear(byte *image, uint32_t& offset, int pwr2) {
-  uint32_t mask = pwr2 - 1;
-  while (offset & mask) {
-    image[offset++] = 0;
+static bool IsFDE(FDE* frame) {
+  // TODO This seems to be the constant everyone uses (for the .debug_frame
+  // section at least), however we should investigate this further.
+  const uint32_t kDwarfCIE_id = 0xffffffff;
+  const uint32_t kReservedLengths[] = {0xffffffff, 0xfffffff0};
+  return frame->CIE_pointer != kDwarfCIE_id &&
+      frame->raw_length_ != kReservedLengths[0] && frame->raw_length_ != kReservedLengths[1];
+}
+
+// TODO This only works for 32-bit Elf Files.
+static bool FixupDebugFrame(uintptr_t text_start, byte* dbg_frame, size_t dbg_frame_size) {
+  FDE* last_frame = reinterpret_cast<FDE*>(dbg_frame + dbg_frame_size);
+  FDE* frame = NextFDE(reinterpret_cast<FDE*>(dbg_frame));
+  for (; frame < last_frame; frame = NextFDE(frame)) {
+    if (!IsFDE(frame)) {
+      return false;
+    }
+    frame->initial_location += text_start;
+  }
+  return true;
+}
+
+struct PACKED(1) DebugInfoHeader {
+  uint32_t unit_length;  // TODO 32-bit specific size
+  uint16_t version;
+  uint32_t debug_abbrev_offset;  // TODO 32-bit specific size
+  uint8_t  address_size;
+};
+
+// Returns -1 if it is variable length, which we will just disallow for now.
+static int32_t FormLength(uint32_t att) {
+  switch (att) {
+    case DW_FORM_data1:
+    case DW_FORM_flag:
+    case DW_FORM_flag_present:
+    case DW_FORM_ref1:
+      return 1;
+
+    case DW_FORM_data2:
+    case DW_FORM_ref2:
+      return 2;
+
+    case DW_FORM_addr:        // TODO 32-bit only
+    case DW_FORM_ref_addr:    // TODO 32-bit only
+    case DW_FORM_sec_offset:  // TODO 32-bit only
+    case DW_FORM_strp:        // TODO 32-bit only
+    case DW_FORM_data4:
+    case DW_FORM_ref4:
+      return 4;
+
+    case DW_FORM_data8:
+    case DW_FORM_ref8:
+    case DW_FORM_ref_sig8:
+      return 8;
+
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+    case DW_FORM_exprloc:
+    case DW_FORM_indirect:
+    case DW_FORM_ref_udata:
+    case DW_FORM_sdata:
+    case DW_FORM_string:
+    case DW_FORM_udata:
+    default:
+      return -1;
   }
 }
 
-// Simple macro to bump a point to a section header to the next one.
-#define BUMP_SHENT(sp) \
-  sp = reinterpret_cast<Elf32_Shdr *> (\
-      reinterpret_cast<byte*>(sp) + elf_hdr.e_shentsize);\
-  offset += elf_hdr.e_shentsize
+class DebugTag {
+ public:
+  const uint32_t index_;
+  ~DebugTag() {}
+  // Creates a new tag and moves data pointer up to the start of the next one.
+  // nullptr means error.
+  static DebugTag* Create(const byte** data_pointer) {
+    const byte* data = *data_pointer;
+    uint32_t index = DecodeUnsignedLeb128(&data);
+    std::unique_ptr<DebugTag> tag(new DebugTag(index));
+    tag->size_ = static_cast<uint32_t>(
+        reinterpret_cast<uintptr_t>(data) - reinterpret_cast<uintptr_t>(*data_pointer));
+    // skip the abbrev
+    tag->tag_ = DecodeUnsignedLeb128(&data);
+    tag->has_child_ = (*data == 0);
+    data++;
+    while (true) {
+      uint32_t attr = DecodeUnsignedLeb128(&data);
+      uint32_t form = DecodeUnsignedLeb128(&data);
+      if (attr == 0 && form == 0) {
+        break;
+      } else if (attr == 0 || form == 0) {
+        // Bad abbrev.
+        return nullptr;
+      }
+      int32_t size = FormLength(form);
+      if (size == -1) {
+        return nullptr;
+      }
+      tag->AddAttribute(attr, static_cast<uint32_t>(size));
+    }
+    *data_pointer = data;
+    return tag.release();
+  }
+
+  uint32_t GetSize() const {
+    return size_;
+  }
+
+  bool HasChild() {
+    return has_child_;
+  }
+
+  uint32_t GetTagNumber() {
+    return tag_;
+  }
+
+  // Gets the offset of a particular attribute in this tag structure.
+  // Interpretation of the data is left to the consumer. 0 is returned if the
+  // tag does not contain the attribute.
+  uint32_t GetOffsetOf(uint32_t dwarf_attribute) const {
+    auto it = off_map_.find(dwarf_attribute);
+    if (it == off_map_.end()) {
+      return 0;
+    } else {
+      return it->second;
+    }
+  }
+
+  // Gets the size of attribute
+  uint32_t GetAttrSize(uint32_t dwarf_attribute) const {
+    auto it = size_map_.find(dwarf_attribute);
+    if (it == size_map_.end()) {
+      return 0;
+    } else {
+      return it->second;
+    }
+  }
+
+ private:
+  explicit DebugTag(uint32_t index) : index_(index) {}
+  void AddAttribute(uint32_t type, uint32_t attr_size) {
+    off_map_.insert(std::pair<uint32_t, uint32_t>(type, size_));
+    size_map_.insert(std::pair<uint32_t, uint32_t>(type, attr_size));
+    size_ += attr_size;
+  }
+  std::map<uint32_t, uint32_t> off_map_;
+  std::map<uint32_t, uint32_t> size_map_;
+  uint32_t size_;
+  uint32_t tag_;
+  bool has_child_;
+};
+
+class DebugAbbrev {
+ public:
+  ~DebugAbbrev() {}
+  static DebugAbbrev* Create(const byte* dbg_abbrev, size_t dbg_abbrev_size) {
+    std::unique_ptr<DebugAbbrev> abbrev(new DebugAbbrev);
+    const byte* last = dbg_abbrev + dbg_abbrev_size;
+    while (dbg_abbrev < last) {
+      std::unique_ptr<DebugTag> tag(DebugTag::Create(&dbg_abbrev));
+      if (tag.get() == nullptr) {
+        return nullptr;
+      } else {
+        abbrev->tags_.insert(std::pair<uint32_t, uint32_t>(tag->index_, abbrev->tag_list_.size()));
+        abbrev->tag_list_.push_back(std::move(tag));
+      }
+    }
+    return abbrev.release();
+  }
+
+  DebugTag* ReadTag(const byte* entry) {
+    uint32_t tag_num = DecodeUnsignedLeb128(&entry);
+    auto it = tags_.find(tag_num);
+    if (it == tags_.end()) {
+      return nullptr;
+    } else {
+      CHECK_GT(tag_list_.size(), it->second);
+      return tag_list_.at(it->second).get();
+    }
+  }
+
+ private:
+  DebugAbbrev() {}
+  std::map<uint32_t, uint32_t> tags_;
+  std::vector<std::unique_ptr<DebugTag>> tag_list_;
+};
+
+class DebugInfoIterator {
+ public:
+  static DebugInfoIterator* Create(DebugInfoHeader* header, size_t frame_size,
+                                   DebugAbbrev* abbrev) {
+    std::unique_ptr<DebugInfoIterator> iter(new DebugInfoIterator(header, frame_size, abbrev));
+    if (iter->GetCurrentTag() == nullptr) {
+      return nullptr;
+    } else {
+      return iter.release();
+    }
+  }
+  ~DebugInfoIterator() {}
+
+  // Moves to the next DIE. Returns false if at last entry.
+  // TODO Handle variable length attributes.
+  bool next() {
+    if (current_entry_ == nullptr || current_tag_ == nullptr) {
+      return false;
+    }
+    current_entry_ += current_tag_->GetSize();
+    if (current_entry_ >= last_entry_) {
+      current_entry_ = nullptr;
+      return false;
+    }
+    current_tag_ = abbrev_->ReadTag(current_entry_);
+    if (current_tag_ == nullptr) {
+      current_entry_ = nullptr;
+      return false;
+    } else {
+      return true;
+    }
+  }
+
+  const DebugTag* GetCurrentTag() {
+    return const_cast<DebugTag*>(current_tag_);
+  }
+  byte* GetPointerToField(uint8_t dwarf_field) {
+    if (current_tag_ == nullptr || current_entry_ == nullptr || current_entry_ >= last_entry_) {
+      return nullptr;
+    }
+    uint32_t off = current_tag_->GetOffsetOf(dwarf_field);
+    if (off == 0) {
+      // tag does not have that field.
+      return nullptr;
+    } else {
+      DCHECK_LT(off, current_tag_->GetSize());
+      return current_entry_ + off;
+    }
+  }
+
+ private:
+  DebugInfoIterator(DebugInfoHeader* header, size_t frame_size, DebugAbbrev* abbrev)
+      : abbrev_(abbrev),
+        last_entry_(reinterpret_cast<byte*>(header) + frame_size),
+        current_entry_(reinterpret_cast<byte*>(header) + sizeof(DebugInfoHeader)),
+        current_tag_(abbrev_->ReadTag(current_entry_)) {}
+  DebugAbbrev* abbrev_;
+  byte* last_entry_;
+  byte* current_entry_;
+  DebugTag* current_tag_;
+};
+
+static bool FixupDebugInfo(uint32_t text_start, DebugInfoIterator* iter) {
+  do {
+    if (iter->GetCurrentTag()->GetAttrSize(DW_AT_low_pc) != sizeof(int32_t) ||
+        iter->GetCurrentTag()->GetAttrSize(DW_AT_high_pc) != sizeof(int32_t)) {
+      return false;
+    }
+    uint32_t* PC_low = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_low_pc));
+    uint32_t* PC_high = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_high_pc));
+    if (PC_low != nullptr && PC_high != nullptr) {
+      *PC_low  += text_start;
+      *PC_high += text_start;
+    }
+  } while (iter->next());
+  return true;
+}
+
+static bool FixupDebugSections(const byte* dbg_abbrev, size_t dbg_abbrev_size,
+                               uintptr_t text_start,
+                               byte* dbg_info, size_t dbg_info_size,
+                               byte* dbg_frame, size_t dbg_frame_size) {
+  std::unique_ptr<DebugAbbrev> abbrev(DebugAbbrev::Create(dbg_abbrev, dbg_abbrev_size));
+  if (abbrev.get() == nullptr) {
+    return false;
+  }
+  std::unique_ptr<DebugInfoIterator> iter(
+      DebugInfoIterator::Create(reinterpret_cast<DebugInfoHeader*>(dbg_info),
+                                dbg_info_size, abbrev.get()));
+  if (iter.get() == nullptr) {
+    return false;
+  }
+  return FixupDebugInfo(text_start, iter.get())
+      && FixupDebugFrame(text_start, dbg_frame, dbg_frame_size);
+}
 
 void ElfFile::GdbJITSupport() {
   // We only get here if we only are mapping the program header.
@@ -1000,18 +1313,25 @@
 
   // Well, we need the whole file to do this.
   std::string error_msg;
-  std::unique_ptr<ElfFile> ptr(Open(const_cast<File*>(file_), false, false, &error_msg));
-  ElfFile& all = *ptr;
-
-  // Do we have interesting sections?
-  // Is this an OAT file with interesting sections?
-  if (all.GetSectionHeaderNum() != kExpectedSectionsInOATFile) {
+  // Make it MAP_PRIVATE so we can just give it to gdb if all the necessary
+  // sections are there.
+  std::unique_ptr<ElfFile> all_ptr(Open(const_cast<File*>(file_), PROT_READ | PROT_WRITE,
+                                        MAP_PRIVATE, &error_msg));
+  if (all_ptr.get() == nullptr) {
     return;
   }
-  if (!check_section_name(all, 8, ".debug_info") ||
-      !check_section_name(all, 9, ".debug_abbrev") ||
-      !check_section_name(all, 10, ".debug_frame") ||
-      !check_section_name(all, 11, ".debug_str")) {
+  ElfFile& all = *all_ptr;
+
+  // Do we have interesting sections?
+  const Elf32_Shdr* debug_info = all.FindSectionByName(".debug_info");
+  const Elf32_Shdr* debug_abbrev = all.FindSectionByName(".debug_abbrev");
+  const Elf32_Shdr* debug_frame = all.FindSectionByName(".debug_frame");
+  const Elf32_Shdr* debug_str = all.FindSectionByName(".debug_str");
+  const Elf32_Shdr* strtab_sec = all.FindSectionByName(".strtab");
+  const Elf32_Shdr* symtab_sec = all.FindSectionByName(".symtab");
+  Elf32_Shdr* text_sec = all.FindSectionByName(".text");
+  if (debug_info == nullptr || debug_abbrev == nullptr || debug_frame == nullptr ||
+      debug_str == nullptr || text_sec == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
     return;
   }
 #ifdef __LP64__
@@ -1019,227 +1339,29 @@
     return;  // No ELF debug support in 64bit.
   }
 #endif
-  // This is not needed if we have no .text segment.
-  uint32_t text_start_addr = 0;
-  for (uint32_t i = 0; i < segments_.size(); i++) {
-    if (segments_[i]->GetProtect() & PROT_EXEC) {
-      // We found the .text section.
-      text_start_addr = PointerToLowMemUInt32(segments_[i]->Begin());
-      break;
-    }
-  }
-  if (text_start_addr == 0U) {
-    return;
-  }
-
-  // Okay, we are good enough.  Fake up an ELF image and tell GDB about it.
-  // We need some extra space for the debug and string sections, the ELF header, and the
-  // section header.
-  uint32_t needed_size = KB;
-
-  for (Elf32_Word i = 1; i < all.GetSectionHeaderNum(); i++) {
-    Elf32_Shdr& section_header = all.GetSectionHeader(i);
-    if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
-      // Debug section: we need it.
-      needed_size += section_header.sh_size;
-    } else if (section_header.sh_type == SHT_STRTAB &&
-                strcmp(".shstrtab",
-                       all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
-      // We also need the shared string table.
-      needed_size += section_header.sh_size;
-
-      // We also need the extra strings .symtab\0.strtab\0
-      needed_size += 16;
-    }
-  }
-
-  // Start creating our image.
-  jit_elf_image_ = new byte[needed_size];
-
-  // Create the Elf Header by copying the old one
-  Elf32_Ehdr& elf_hdr =
-    *reinterpret_cast<Elf32_Ehdr*>(jit_elf_image_);
-
-  elf_hdr = all.GetHeader();
+  // We need to add in a strtab and symtab to the image.
+  // all is MAP_PRIVATE so it can be written to freely.
+  // We also already have strtab and symtab so we are fine there.
+  Elf32_Ehdr& elf_hdr = all.GetHeader();
   elf_hdr.e_entry = 0;
   elf_hdr.e_phoff = 0;
   elf_hdr.e_phnum = 0;
   elf_hdr.e_phentsize = 0;
   elf_hdr.e_type = ET_EXEC;
 
-  uint32_t offset = sizeof(Elf32_Ehdr);
+  text_sec->sh_type = SHT_NOBITS;
+  text_sec->sh_offset = 0;
 
-  // Copy the debug sections and string table.
-  uint32_t debug_offsets[kExpectedSectionsInOATFile];
-  memset(debug_offsets, '\0', sizeof debug_offsets);
-  Elf32_Shdr *text_header = nullptr;
-  int extra_shstrtab_entries = -1;
-  int text_section_index = -1;
-  int section_index = 1;
-  for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
-    Elf32_Shdr& section_header = all.GetSectionHeader(i);
-    // Round up to multiple of 4, ensuring zero fill.
-    RoundAndClear(jit_elf_image_, offset, 4);
-    if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
-      // Debug section: we need it.  Unfortunately, it wasn't mapped in.
-      debug_offsets[i] = offset;
-      // Read it from the file.
-      lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
-      read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
-      offset += section_header.sh_size;
-      section_index++;
-      offset += 16;
-    } else if (section_header.sh_type == SHT_STRTAB &&
-                strcmp(".shstrtab",
-                       all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
-      // We also need the shared string table.
-      debug_offsets[i] = offset;
-      // Read it from the file.
-      lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
-      read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
-      offset += section_header.sh_size;
-      // We also need the extra strings .symtab\0.strtab\0
-      extra_shstrtab_entries = section_header.sh_size;
-      memcpy(jit_elf_image_+offset, ".symtab\0.strtab\0", 16);
-      offset += 16;
-      section_index++;
-    } else if (section_header.sh_flags & SHF_EXECINSTR) {
-      DCHECK(strcmp(".text", all.GetString(SHT_SYMTAB,
-                                           section_header.sh_name)) == 0);
-      text_header = &section_header;
-      text_section_index = section_index++;
-    }
-  }
-  DCHECK(text_header != nullptr);
-  DCHECK_NE(extra_shstrtab_entries, -1);
-
-  // We now need to update the addresses for debug_info and debug_frame to get to the
-  // correct offset within the .text section.
-  byte *p = jit_elf_image_+debug_offsets[8];
-  byte *end = p + all.GetSectionHeader(8).sh_size;
-
-  // For debug_info; patch compilation using low_pc @ offset 13, high_pc at offset 17.
-  IncrementUint32(p + 13, text_start_addr);
-  IncrementUint32(p + 17, text_start_addr);
-
-  // Now fix the low_pc, high_pc for each method address.
-  // First method starts at offset 0x15, each subsequent method is 1+3*4 bytes further.
-  for (p += 0x15; p < end; p += 1 /* attr# */ + 3 * sizeof(uint32_t) /* addresses */) {
-    IncrementUint32(p + 1 + sizeof(uint32_t), text_start_addr);
-    IncrementUint32(p + 1 + 2 * sizeof(uint32_t), text_start_addr);
+  if (!FixupDebugSections(
+        all.Begin() + debug_abbrev->sh_offset, debug_abbrev->sh_size, text_sec->sh_addr,
+        all.Begin() + debug_info->sh_offset, debug_info->sh_size,
+        all.Begin() + debug_frame->sh_offset, debug_frame->sh_size)) {
+    LOG(ERROR) << "Failed to load GDB data";
+    return;
   }
 
-  // Now we have to handle the debug_frame method start addresses
-  p = jit_elf_image_+debug_offsets[10];
-  end = p + all.GetSectionHeader(10).sh_size;
-
-  // Skip past the CIE.
-  p += *reinterpret_cast<uint32_t *>(p) + 4;
-
-  // And walk the FDEs.
-  for (; p < end; p += *reinterpret_cast<uint32_t *>(p) + sizeof(uint32_t)) {
-    IncrementUint32(p + 2 * sizeof(uint32_t), text_start_addr);
-  }
-
-  // Create the data for the symbol table.
-  const int kSymbtabAlignment = 16;
-  RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
-  uint32_t symtab_offset = offset;
-
-  // First entry is empty.
-  memset(jit_elf_image_+offset, 0, sizeof(Elf32_Sym));
-  offset += sizeof(Elf32_Sym);
-
-  // Symbol 1 is the real .text section.
-  Elf32_Sym& sym_ent = *reinterpret_cast<Elf32_Sym*>(jit_elf_image_+offset);
-  sym_ent.st_name = 1; /* .text */
-  sym_ent.st_value = text_start_addr;
-  sym_ent.st_size = text_header->sh_size;
-  SetBindingAndType(&sym_ent, STB_LOCAL, STT_SECTION);
-  sym_ent.st_other = 0;
-  sym_ent.st_shndx = text_section_index;
-  offset += sizeof(Elf32_Sym);
-
-  // Create the data for the string table.
-  RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
-  const int kTextStringSize = 7;
-  uint32_t strtab_offset = offset;
-  memcpy(jit_elf_image_+offset, "\0.text", kTextStringSize);
-  offset += kTextStringSize;
-
-  // Create the section header table.
-  // Round up to multiple of kSymbtabAlignment, ensuring zero fill.
-  RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
-  elf_hdr.e_shoff = offset;
-  Elf32_Shdr *sp =
-    reinterpret_cast<Elf32_Shdr *>(jit_elf_image_ + offset);
-
-  // Copy the first empty index.
-  *sp = all.GetSectionHeader(0);
-  BUMP_SHENT(sp);
-
-  elf_hdr.e_shnum = 1;
-  for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
-    Elf32_Shdr& section_header = all.GetSectionHeader(i);
-    if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
-      // Debug section: we need it.
-      *sp = section_header;
-      sp->sh_offset = debug_offsets[i];
-      sp->sh_addr = 0;
-      elf_hdr.e_shnum++;
-      BUMP_SHENT(sp);
-    } else if (section_header.sh_type == SHT_STRTAB &&
-                strcmp(".shstrtab",
-                       all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
-      // We also need the shared string table.
-      *sp = section_header;
-      sp->sh_offset = debug_offsets[i];
-      sp->sh_size += 16; /* sizeof ".symtab\0.strtab\0" */
-      sp->sh_addr = 0;
-      elf_hdr.e_shstrndx = elf_hdr.e_shnum;
-      elf_hdr.e_shnum++;
-      BUMP_SHENT(sp);
-    }
-  }
-
-  // Add a .text section for the matching code section.
-  *sp = *text_header;
-  sp->sh_type = SHT_NOBITS;
-  sp->sh_offset = 0;
-  sp->sh_addr = text_start_addr;
-  elf_hdr.e_shnum++;
-  BUMP_SHENT(sp);
-
-  // .symtab section:  Need an empty index and the .text entry
-  sp->sh_name = extra_shstrtab_entries;
-  sp->sh_type = SHT_SYMTAB;
-  sp->sh_flags = 0;
-  sp->sh_addr = 0;
-  sp->sh_offset = symtab_offset;
-  sp->sh_size = 2 * sizeof(Elf32_Sym);
-  sp->sh_link = elf_hdr.e_shnum + 1;  // Link to .strtab section.
-  sp->sh_info = 0;
-  sp->sh_addralign = 16;
-  sp->sh_entsize = sizeof(Elf32_Sym);
-  elf_hdr.e_shnum++;
-  BUMP_SHENT(sp);
-
-  // .strtab section:  Enough for .text\0.
-  sp->sh_name = extra_shstrtab_entries + 8;
-  sp->sh_type = SHT_STRTAB;
-  sp->sh_flags = 0;
-  sp->sh_addr = 0;
-  sp->sh_offset = strtab_offset;
-  sp->sh_size = kTextStringSize;
-  sp->sh_link = 0;
-  sp->sh_info = 0;
-  sp->sh_addralign = 16;
-  sp->sh_entsize = 0;
-  elf_hdr.e_shnum++;
-  BUMP_SHENT(sp);
-
-  // We now have enough information to tell GDB about our file.
-  jit_gdb_entry_ = CreateCodeEntry(jit_elf_image_, offset);
+  jit_gdb_entry_ = CreateCodeEntry(all.Begin(), all.Size());
+  gdb_file_mapping_.reset(all_ptr.release());
 }
 
 }  // namespace art
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 6650acd..496690b 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -41,6 +41,9 @@
 class ElfFile {
  public:
   static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg);
+  // Open with specific mmap flags, Always maps in the whole file, not just the
+  // program header sections.
+  static ElfFile* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg);
   ~ElfFile();
 
   // Load segments into memory based on PT_LOAD program headers
@@ -70,17 +73,19 @@
   Elf32_Word GetSectionHeaderNum() const;
   Elf32_Shdr& GetSectionHeader(Elf32_Word) const;
   Elf32_Shdr* FindSectionByType(Elf32_Word type) const;
+  Elf32_Shdr* FindSectionByName(const std::string& name) const;
 
   Elf32_Shdr& GetSectionNameStringSection() const;
 
   // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress.
   const byte* FindDynamicSymbolAddress(const std::string& symbol_name) const;
+  const Elf32_Sym* FindDynamicSymbol(const std::string& symbol_name) const;
 
   static bool IsSymbolSectionType(Elf32_Word section_type);
   Elf32_Word GetSymbolNum(Elf32_Shdr&) const;
   Elf32_Sym& GetSymbol(Elf32_Word section_type, Elf32_Word i) const;
 
-  // Find symbol in specified table, returning NULL if it is not found.
+  // Find symbol in specified table, returning nullptr if it is not found.
   //
   // If build_map is true, builds a map to speed repeated access. The
   // map does not included untyped symbol values (aka STT_NOTYPE)
@@ -98,11 +103,11 @@
                                const std::string& symbol_name,
                                bool build_map);
 
-  // Lookup a string given string section and offset. Returns NULL for
+  // Lookup a string given string section and offset. Returns nullptr for
   // special 0 offset.
   const char* GetString(Elf32_Shdr&, Elf32_Word) const;
 
-  // Lookup a string by section type. Returns NULL for special 0 offset.
+  // Lookup a string by section type. Returns nullptr for special 0 offset.
   const char* GetString(Elf32_Word section_type, Elf32_Word) const;
 
   Elf32_Word GetDynamicNum() const;
@@ -125,7 +130,7 @@
  private:
   ElfFile(File* file, bool writable, bool program_header_only);
 
-  bool Setup(std::string* error_msg);
+  bool Setup(int prot, int flags, std::string* error_msg);
 
   bool SetMap(MemMap* map, std::string* error_msg);
 
@@ -181,9 +186,8 @@
   // Support for GDB JIT
   byte* jit_elf_image_;
   JITCodeEntry* jit_gdb_entry_;
+  std::unique_ptr<ElfFile> gdb_file_mapping_;
   void GdbJITSupport();
-  // Is this an OAT file with debug information in it?
-  static constexpr uint32_t kExpectedSectionsInOATFile = 12;
 };
 
 }  // namespace art
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 65799cd..43bdf49 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -168,8 +168,7 @@
 
 template<typename T>
 inline PrimitiveArray<T>* PrimitiveArray<T>::Alloc(Thread* self, size_t length) {
-  DCHECK(array_class_ != NULL);
-  Array* raw_array = Array::Alloc<true>(self, array_class_, length, sizeof(T),
+  Array* raw_array = Array::Alloc<true>(self, GetArrayClass(), length, sizeof(T),
                                         Runtime::Current()->GetHeap()->GetCurrentAllocator());
   return down_cast<PrimitiveArray<T>*>(raw_array);
 }
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 64e2317..25a4535 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -20,6 +20,7 @@
 #include "gc/allocator_type.h"
 #include "object.h"
 #include "object_callbacks.h"
+#include "read_barrier.h"
 
 namespace art {
 
@@ -160,9 +161,10 @@
     array_class_ = array_class;
   }
 
-  static Class* GetArrayClass() {
+  static Class* GetArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(array_class_ != nullptr);
-    return array_class_;
+    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
+        &array_class_);
   }
 
   static void ResetArrayClass() {
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index 4858613..502cec7 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -23,6 +23,7 @@
 #include "modifiers.h"
 #include "object.h"
 #include "object_callbacks.h"
+#include "read_barrier.h"
 
 namespace art {
 
@@ -121,9 +122,11 @@
   template<bool kTransactionActive>
   void SetObj(Object* object, Object* new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static Class* GetJavaLangReflectArtField() {
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+  static Class* GetJavaLangReflectArtField()  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(java_lang_reflect_ArtField_ != nullptr);
-    return java_lang_reflect_ArtField_;
+    return ReadBarrier::BarrierForRoot<mirror::Class, kReadBarrierOption>(
+        &java_lang_reflect_ArtField_);
   }
 
   static void SetClass(Class* java_lang_reflect_ArtField);
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 1c21b81..a55c48b 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -24,6 +24,7 @@
 #include "object.h"
 #include "object_callbacks.h"
 #include "quick/quick_method_frame_info.h"
+#include "read_barrier.h"
 
 namespace art {
 
@@ -409,9 +410,11 @@
 
   static void SetClass(Class* java_lang_reflect_ArtMethod);
 
-  static Class* GetJavaLangReflectArtMethod() {
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+  static Class* GetJavaLangReflectArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(java_lang_reflect_ArtMethod_ != nullptr);
-    return java_lang_reflect_ArtMethod_;
+    return ReadBarrier::BarrierForRoot<mirror::Class, kReadBarrierOption>(
+        &java_lang_reflect_ArtMethod_);
   }
 
   static void ResetClass();
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 6205f70..451235c 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -511,12 +511,14 @@
   VisitInstanceFieldsReferences<kVisitClass>(klass, visitor);
 }
 
+template<ReadBarrierOption kReadBarrierOption>
 inline bool Class::IsArtFieldClass() const {
-  return this == ArtField::GetJavaLangReflectArtField();
+  return this == ArtField::GetJavaLangReflectArtField<kReadBarrierOption>();
 }
 
+template<ReadBarrierOption kReadBarrierOption>
 inline bool Class::IsArtMethodClass() const {
-  return this == ArtMethod::GetJavaLangReflectArtMethod();
+  return this == ArtMethod::GetJavaLangReflectArtMethod<kReadBarrierOption>();
 }
 
 template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index c798180..c6472c6 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -40,7 +40,9 @@
 Class* Class::java_lang_Class_ = nullptr;
 
 void Class::SetClassClass(Class* java_lang_Class) {
-  CHECK(java_lang_Class_ == nullptr) << java_lang_Class_ << " " << java_lang_Class;
+  CHECK(java_lang_Class_ == nullptr)
+      << ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(&java_lang_Class_)
+      << " " << java_lang_Class;
   CHECK(java_lang_Class != nullptr);
   java_lang_Class_ = java_lang_Class;
 }
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index c83f411..e735c45 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -24,6 +24,7 @@
 #include "object.h"
 #include "object_callbacks.h"
 #include "primitive.h"
+#include "read_barrier.h"
 
 /*
  * A magic value for refOffsets. Ignore the bits and walk the super
@@ -376,8 +377,10 @@
 
   bool IsThrowableClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArtFieldClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArtMethodClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static MemberOffset ComponentTypeOffset() {
@@ -845,13 +848,14 @@
     SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx);
   }
 
-  static Class* GetJavaLangClass() {
+  static Class* GetJavaLangClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(java_lang_Class_ != NULL);
-    return java_lang_Class_;
+    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
+        &java_lang_Class_);
   }
 
   // Can't call this SetClass or else gets called instead of Object::SetClass in places.
-  static void SetClassClass(Class* java_lang_Class);
+  static void SetClassClass(Class* java_lang_Class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void ResetClass();
   static void VisitRoots(RootCallback* callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 15ecd3c..62c1162 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -218,7 +218,8 @@
 
 template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline bool Object::IsArtField() {
-  return GetClass<kVerifyFlags, kReadBarrierOption>()->IsArtFieldClass();
+  return GetClass<kVerifyFlags, kReadBarrierOption>()->
+      template IsArtFieldClass<kReadBarrierOption>();
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -229,7 +230,8 @@
 
 template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline bool Object::IsArtMethod() {
-  return GetClass<kVerifyFlags, kReadBarrierOption>()->IsArtMethodClass();
+  return GetClass<kVerifyFlags, kReadBarrierOption>()->
+      template IsArtMethodClass<kReadBarrierOption>();
 }
 
 template<VerifyObjectFlags kVerifyFlags>
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index e094e8b..abecbc5 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -19,6 +19,7 @@
 
 #include "object.h"
 #include "object_callbacks.h"
+#include "read_barrier.h"
 
 namespace art {
 
@@ -55,9 +56,10 @@
   static void ResetClass();
   static void VisitRoots(RootCallback* callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static Class* GetStackTraceElement() {
+  static Class* GetStackTraceElement() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(java_lang_StackTraceElement_ != NULL);
-    return java_lang_StackTraceElement_;
+    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
+        &java_lang_StackTraceElement_);
   }
 
  private:
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 6c3015f..b8acede 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -21,6 +21,7 @@
 
 #include "class.h"
 #include "object_callbacks.h"
+#include "read_barrier.h"
 
 namespace art {
 
@@ -102,9 +103,10 @@
 
   int32_t CompareTo(String* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static Class* GetJavaLangString() {
+  static Class* GetJavaLangString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(java_lang_String_ != NULL);
-    return java_lang_String_;
+    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
+        &java_lang_String_);
   }
 
   static void SetClass(Class* java_lang_String);
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index c4127e0..cf54ad6 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -19,6 +19,7 @@
 
 #include "object.h"
 #include "object_callbacks.h"
+#include "read_barrier.h"
 #include "string.h"
 
 namespace art {
@@ -45,9 +46,10 @@
   void SetStackState(Object* state) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsCheckedException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static Class* GetJavaLangThrowable() {
+  static Class* GetJavaLangThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(java_lang_Throwable_ != NULL);
-    return java_lang_Throwable_;
+    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
+        &java_lang_Throwable_);
   }
 
   static void SetClass(Class* java_lang_Throwable);
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index cecd86f..7a7a92a 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -752,9 +752,9 @@
     // Bad summary info.  It should be count/nullcount/bootcount
     return;
   }
-  previous_num_samples_ = atoi(summary_info[0].c_str());
-  previous_num_null_methods_ = atoi(summary_info[1].c_str());
-  previous_num_boot_methods_ = atoi(summary_info[2].c_str());
+  previous_num_samples_ = strtoul(summary_info[0].c_str(), nullptr, 10);
+  previous_num_null_methods_ = strtoul(summary_info[1].c_str(), nullptr, 10);
+  previous_num_boot_methods_ = strtoul(summary_info[2].c_str(), nullptr, 10);
 
   // Now read each line until the end of file.  Each line consists of 3 or 4 fields separated by /
   while (true) {
@@ -768,8 +768,8 @@
       break;
     }
     std::string methodname = info[0];
-    uint32_t total_count = atoi(info[1].c_str());
-    uint32_t size = atoi(info[2].c_str());
+    uint32_t total_count = strtoul(info[1].c_str(), nullptr, 10);
+    uint32_t size = strtoul(info[2].c_str(), nullptr, 10);
     PreviousContextMap* context_map = nullptr;
     if (type == kProfilerBoundedStack && info.size() == 4) {
       context_map = new PreviousContextMap();
@@ -781,13 +781,13 @@
         Split(context_count_pairs[i], ':', context_count);
         if (context_count.size() == 2) {
           // Handles the situtation when the profile file doesn't contain context information.
-          uint32_t dexpc = atoi(context_count[0].c_str());
-          uint32_t count = atoi(context_count[1].c_str());
+          uint32_t dexpc = strtoul(context_count[0].c_str(), nullptr, 10);
+          uint32_t count = strtoul(context_count[1].c_str(), nullptr, 10);
           (*context_map)[std::make_pair(dexpc, "")] = count;
         } else {
           // Handles the situtation when the profile file contains context information.
-          uint32_t dexpc = atoi(context_count[0].c_str());
-          uint32_t count = atoi(context_count[1].c_str());
+          uint32_t dexpc = strtoul(context_count[0].c_str(), nullptr, 10);
+          uint32_t count = strtoul(context_count[1].c_str(), nullptr, 10);
           std::string context = context_count[2];
           (*context_map)[std::make_pair(dexpc, context)] = count;
         }
@@ -830,7 +830,7 @@
     return false;
   }
   // This is the number of hits in all profiled methods (without nullptr or boot methods)
-  uint32_t total_count = atoi(summary_info[0].c_str());
+  uint32_t total_count = strtoul(summary_info[0].c_str(), nullptr, 10);
 
   // Now read each line until the end of file.  Each line consists of 3 fields separated by '/'.
   // Store the info in descending order given by the most used methods.
@@ -857,7 +857,7 @@
   for (ProfileSet::iterator it = countSet.begin(); it != end ; it++) {
     const std::string& methodname = it->second[0];
     uint32_t count = -it->first;
-    uint32_t size = atoi(it->second[2].c_str());
+    uint32_t size = strtoul(it->second[2].c_str(), nullptr, 10);
     double usedPercent = (count * 100.0) / total_count;
 
     curTotalCount += count;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 8aa7ea1..53ddcca 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -241,16 +241,22 @@
   }
 
   void DumpAllThreads(std::ostream& os, Thread* self) NO_THREAD_SAFETY_ANALYSIS {
-    bool tll_already_held = Locks::thread_list_lock_->IsExclusiveHeld(self);
-    bool ml_already_held = Locks::mutator_lock_->IsSharedHeld(self);
-    if (!tll_already_held || !ml_already_held) {
-      os << "Dumping all threads without appropriate locks held:"
-          << (!tll_already_held ? " thread list lock" : "")
-          << (!ml_already_held ? " mutator lock" : "")
-          << "\n";
+    Runtime* runtime = Runtime::Current();
+    if (runtime != nullptr) {
+      ThreadList* thread_list = runtime->GetThreadList();
+      if (thread_list != nullptr) {
+        bool tll_already_held = Locks::thread_list_lock_->IsExclusiveHeld(self);
+        bool ml_already_held = Locks::mutator_lock_->IsSharedHeld(self);
+        if (!tll_already_held || !ml_already_held) {
+          os << "Dumping all threads without appropriate locks held:"
+              << (!tll_already_held ? " thread list lock" : "")
+              << (!ml_already_held ? " mutator lock" : "")
+              << "\n";
+        }
+        os << "All threads:\n";
+        thread_list->DumpLocked(os);
+      }
     }
-    os << "All threads:\n";
-    Runtime::Current()->GetThreadList()->DumpLocked(os);
   }
 };