Merge "Add implicit min-sdk if a test uses a main-dex list."
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 5208d64..c73b988 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -74,7 +74,8 @@
 TARGET_CORE_IMG_LOCATION := $(ART_TARGET_TEST_OUT)/core.art
 
 # Modules to compile for core.art.
-CORE_IMG_JARS := core-oj core-libart core-simple okhttp bouncycastle apache-xml
+# TODO: Move conscrypt from CORE_IMG_JARS to TEST_CORE_JARS and adjust scripts to fix Golem.
+CORE_IMG_JARS := core-oj core-libart core-simple okhttp bouncycastle apache-xml conscrypt
 HOST_CORE_IMG_JARS   := $(addsuffix -hostdex,$(CORE_IMG_JARS))
 TARGET_CORE_IMG_JARS := $(addsuffix -testdex,$(CORE_IMG_JARS))
 HOST_CORE_IMG_DEX_LOCATIONS   := $(foreach jar,$(HOST_CORE_IMG_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
@@ -87,7 +88,7 @@
 TARGET_CORE_IMG_DEX_FILES := $(foreach jar,$(TARGET_CORE_IMG_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar)
 
 # Jar files for the boot class path for testing. Must start with CORE_IMG_JARS.
-TEST_CORE_JARS := $(CORE_IMG_JARS) conscrypt
+TEST_CORE_JARS := $(CORE_IMG_JARS)
 HOST_TEST_CORE_JARS   := $(addsuffix -hostdex,$(TEST_CORE_JARS))
 TARGET_TEST_CORE_JARS := $(addsuffix -testdex,$(TEST_CORE_JARS))
 HOST_CORE_DEX_LOCATIONS   := $(foreach jar,$(HOST_TEST_CORE_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
diff --git a/cmdline/cmdline_parser.h b/cmdline/cmdline_parser.h
index 82c04e7..952be44 100644
--- a/cmdline/cmdline_parser.h
+++ b/cmdline/cmdline_parser.h
@@ -206,7 +206,7 @@
       };
       load_value_ = []() -> TArg& {
         assert(false && "Should not be appending values to ignored arguments");
-        return *reinterpret_cast<TArg*>(0);  // Blow up.
+        __builtin_trap();  // Blow up.
       };
 
       save_value_specified_ = true;
@@ -270,7 +270,7 @@
 
       load_value_ = []() -> TArg& {
         assert(false && "No load value function defined");
-        return *reinterpret_cast<TArg*>(0);  // Blow up.
+        __builtin_trap();  // Blow up.
       };
     }
 
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 23bc7a2..3b57b07 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -95,7 +95,8 @@
       weak_ref_access_enabled_(true),
       copied_live_bytes_ratio_sum_(0.f),
       gc_count_(0),
-      inter_region_bitmap_(nullptr),
+      region_space_inter_region_bitmap_(nullptr),
+      non_moving_space_inter_region_bitmap_(nullptr),
       reclaimed_bytes_ratio_sum_(0.f),
       young_gen_(young_gen),
       skipped_blocks_lock_("concurrent copying bytes blocks lock", kMarkSweepMarkStackLock),
@@ -286,12 +287,32 @@
   gc_barrier_->Increment(self, barrier_count);
 }
 
+void ConcurrentCopying::CreateInterRegionRefBitmaps() {
+  DCHECK(kEnableGenerationalConcurrentCopyingCollection);
+  DCHECK(region_space_inter_region_bitmap_ == nullptr);
+  DCHECK(non_moving_space_inter_region_bitmap_ == nullptr);
+  DCHECK(region_space_ != nullptr);
+  DCHECK(heap_->non_moving_space_ != nullptr);
+  // Region-space
+  region_space_inter_region_bitmap_.reset(accounting::ContinuousSpaceBitmap::Create(
+      "region-space inter region ref bitmap",
+      reinterpret_cast<uint8_t*>(region_space_->Begin()),
+      region_space_->Limit() - region_space_->Begin()));
+  CHECK(region_space_inter_region_bitmap_ != nullptr)
+      << "Couldn't allocate region-space inter region ref bitmap";
+
+  // non-moving-space
+  non_moving_space_inter_region_bitmap_.reset(accounting::ContinuousSpaceBitmap::Create(
+      "non-moving-space inter region ref bitmap",
+      reinterpret_cast<uint8_t*>(heap_->non_moving_space_->Begin()),
+      heap_->non_moving_space_->Limit() - heap_->non_moving_space_->Begin()));
+  CHECK(non_moving_space_inter_region_bitmap_ != nullptr)
+      << "Couldn't allocate non-moving-space inter region ref bitmap";
+}
+
 void ConcurrentCopying::BindBitmaps() {
   Thread* self = Thread::Current();
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-  uintptr_t continuous_spaces_begin = UINTPTR_MAX;
-  uintptr_t continuous_spaces_limit = 0;
-  DCHECK(inter_region_bitmap_ == nullptr);
   // Mark all of the spaces we never collect as immune.
   for (const auto& space : heap_->GetContinuousSpaces()) {
     if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyNeverCollect ||
@@ -301,6 +322,7 @@
     } else {
       CHECK(!space->IsZygoteSpace());
       CHECK(!space->IsImageSpace());
+      CHECK(space == region_space_ || space == heap_->non_moving_space_);
       if (kEnableGenerationalConcurrentCopyingCollection) {
         if (space == region_space_) {
           region_space_bitmap_ = region_space_->GetMarkBitmap();
@@ -323,11 +345,6 @@
           // be captured after the thread-flip of this GC cycle, as that is when
           // the young-gen for the next GC cycle starts getting populated.
           heap_->GetCardTable()->ClearCardRange(space->Begin(), space->Limit());
-
-          continuous_spaces_begin =
-              std::min(continuous_spaces_begin, reinterpret_cast<uintptr_t>(space->Begin()));
-          continuous_spaces_limit =
-              std::max(continuous_spaces_limit, reinterpret_cast<uintptr_t>(space->Limit()));
         }
       } else {
         if (space == region_space_) {
@@ -339,18 +356,10 @@
       }
     }
   }
-  if (kEnableGenerationalConcurrentCopyingCollection) {
-    if (young_gen_) {
-      for (const auto& space : GetHeap()->GetDiscontinuousSpaces()) {
-        CHECK(space->IsLargeObjectSpace());
-        space->AsLargeObjectSpace()->CopyLiveToMarked();
-      }
-    } else {
-      inter_region_bitmap_.reset(accounting::ContinuousSpaceBitmap::Create(
-          "inter region ref bitmap",
-          reinterpret_cast<uint8_t*>(continuous_spaces_begin),
-          continuous_spaces_limit - continuous_spaces_begin));
-      CHECK(inter_region_bitmap_ != nullptr) << "Couldn't allocate inter region ref bitmap";
+  if (kEnableGenerationalConcurrentCopyingCollection && young_gen_) {
+    for (const auto& space : GetHeap()->GetDiscontinuousSpaces()) {
+      CHECK(space->IsLargeObjectSpace());
+      space->AsLargeObjectSpace()->CopyLiveToMarked();
     }
   }
 }
@@ -717,7 +726,7 @@
 // Switch threads that from from-space to to-space refs. Forward/mark the thread roots.
 void ConcurrentCopying::FlipThreadRoots() {
   TimingLogger::ScopedTiming split("FlipThreadRoots", GetTimings());
-  if (kVerboseMode) {
+  if (kVerboseMode || heap_->dump_region_info_before_gc_) {
     LOG(INFO) << "time=" << region_space_->Time();
     region_space_->DumpNonFreeRegions(LOG_STREAM(INFO));
   }
@@ -1112,12 +1121,22 @@
   }
   ComputeLiveBytesAndMarkRefFieldsVisitor</*kHandleInterRegionRefs*/ true>
       visitor(this, obj_region_idx);
-  ref->VisitReferences</*kVisitNativeRoots=*/true, kDefaultVerifyFlags, kWithoutReadBarrier>(
+  ref->VisitReferences</*kVisitNativeRoots=*/ true, kDefaultVerifyFlags, kWithoutReadBarrier>(
       visitor, visitor);
   // Mark the corresponding card dirty if the object contains any
   // inter-region reference.
   if (visitor.ContainsInterRegionRefs()) {
-    inter_region_bitmap_->Set(ref);
+    if (obj_region_idx == static_cast<size_t>(-1)) {
+      // If an inter-region ref has been found in a non-region-space, then it
+      // must be non-moving-space. This is because this function cannot be
+      // called on a immune-space object, and a large-object-space object has
+      // only class object reference, which is either in some immune-space, or
+      // in non-moving-space.
+      DCHECK(heap_->non_moving_space_->HasAddress(ref));
+      non_moving_space_inter_region_bitmap_->Set(ref);
+    } else {
+      region_space_inter_region_bitmap_->Set(ref);
+    }
   }
 }
 
@@ -1427,11 +1446,15 @@
                 }
               }
               ScanDirtyObject</*kNoUnEvac*/ true>(obj);
-            } else if (space != region_space_ || region_space_->IsInUnevacFromSpace(obj)) {
+            } else if (space != region_space_) {
+              DCHECK(space == heap_->non_moving_space_);
               // We need to process un-evac references as they may be unprocessed,
               // if they skipped the marking phase due to heap mutation.
               ScanDirtyObject</*kNoUnEvac*/ false>(obj);
-              inter_region_bitmap_->Clear(obj);
+              non_moving_space_inter_region_bitmap_->Clear(obj);
+            } else if (region_space_->IsInUnevacFromSpace(obj)) {
+              ScanDirtyObject</*kNoUnEvac*/ false>(obj);
+              region_space_inter_region_bitmap_->Clear(obj);
             }
           },
           accounting::CardTable::kCardAged);
@@ -1443,16 +1466,20 @@
                          ScanDirtyObject</*kNoUnEvac*/ true>(obj);
                        };
         if (space == region_space_) {
-          region_space_->ScanUnevacFromSpace(inter_region_bitmap_.get(), visitor);
+          region_space_->ScanUnevacFromSpace(region_space_inter_region_bitmap_.get(), visitor);
         } else {
-          inter_region_bitmap_->VisitMarkedRange(reinterpret_cast<uintptr_t>(space->Begin()),
-                                                 reinterpret_cast<uintptr_t>(space->End()),
-                                                 visitor);
+          DCHECK(space == heap_->non_moving_space_);
+          non_moving_space_inter_region_bitmap_->VisitMarkedRange(
+              reinterpret_cast<uintptr_t>(space->Begin()),
+              reinterpret_cast<uintptr_t>(space->End()),
+              visitor);
         }
       }
     }
     // Done scanning unevac space.
     done_scanning_.store(true, std::memory_order_release);
+    // NOTE: inter-region-ref bitmaps can be cleared here to release memory, if needed.
+    // Currently we do it in ReclaimPhase().
     if (kVerboseMode) {
       LOG(INFO) << "GC end of ScanCardsForSpace";
     }
@@ -2592,6 +2619,11 @@
 
   CheckEmptyMarkStack();
 
+  if (heap_->dump_region_info_after_gc_) {
+    LOG(INFO) << "time=" << region_space_->Time();
+    region_space_->DumpNonFreeRegions(LOG_STREAM(INFO));
+  }
+
   if (kVerboseMode) {
     LOG(INFO) << "GC end of ReclaimPhase";
   }
@@ -3522,7 +3554,8 @@
     // We do not currently use the region space cards at all, madvise them away to save ram.
     heap_->GetCardTable()->ClearCardRange(region_space_->Begin(), region_space_->Limit());
   } else if (kEnableGenerationalConcurrentCopyingCollection && !young_gen_) {
-    inter_region_bitmap_.reset();
+    region_space_inter_region_bitmap_->Clear();
+    non_moving_space_inter_region_bitmap_->Clear();
   }
   {
     MutexLock mu(self, skipped_blocks_lock_);
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index aabfc8e..a2d4837 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -98,6 +98,9 @@
     return kCollectorTypeCC;
   }
   void RevokeAllThreadLocalBuffers() override;
+  // Creates inter-region ref bitmaps for region-space and non-moving-space.
+  // Gets called in Heap construction after the two spaces are created.
+  void CreateInterRegionRefBitmaps();
   void SetRegionSpace(space::RegionSpace* region_space) {
     DCHECK(region_space != nullptr);
     region_space_ = region_space;
@@ -391,7 +394,8 @@
   size_t gc_count_;
   // Bit is set if the corresponding object has inter-region references that
   // were found during the marking phase of two-phase full-heap GC cycle.
-  std::unique_ptr<accounting::ContinuousSpaceBitmap> inter_region_bitmap_;
+  std::unique_ptr<accounting::ContinuousSpaceBitmap> region_space_inter_region_bitmap_;
+  std::unique_ptr<accounting::ContinuousSpaceBitmap> non_moving_space_inter_region_bitmap_;
 
   // reclaimed_bytes_ratio = reclaimed_bytes/num_allocated_bytes per GC cycle
   float reclaimed_bytes_ratio_sum_;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d47aca9..bf8aaae 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -201,7 +201,9 @@
            bool gc_stress_mode,
            bool measure_gc_performance,
            bool use_homogeneous_space_compaction_for_oom,
-           uint64_t min_interval_homogeneous_space_compaction_by_oom)
+           uint64_t min_interval_homogeneous_space_compaction_by_oom,
+           bool dump_region_info_before_gc,
+           bool dump_region_info_after_gc)
     : non_moving_space_(nullptr),
       rosalloc_space_(nullptr),
       dlmalloc_space_(nullptr),
@@ -300,7 +302,9 @@
       backtrace_lock_(nullptr),
       seen_backtrace_count_(0u),
       unique_backtrace_count_(0u),
-      gc_disabled_for_shutdown_(false) {
+      gc_disabled_for_shutdown_(false),
+      dump_region_info_before_gc_(dump_region_info_before_gc),
+      dump_region_info_after_gc_(dump_region_info_after_gc) {
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     LOG(INFO) << "Heap() entering";
   }
@@ -662,6 +666,9 @@
       concurrent_copying_collector_->SetRegionSpace(region_space_);
       if (kEnableGenerationalConcurrentCopyingCollection) {
         young_concurrent_copying_collector_->SetRegionSpace(region_space_);
+        // At this point, non-moving space should be created.
+        DCHECK(non_moving_space_ != nullptr);
+        concurrent_copying_collector_->CreateInterRegionRefBitmaps();
       }
       garbage_collectors_.push_back(concurrent_copying_collector_);
       if (kEnableGenerationalConcurrentCopyingCollection) {
@@ -2732,7 +2739,7 @@
           // active_concurrent_copying_collector_. So we should not concurrency here.
           active_concurrent_copying_collector_ = (gc_type == collector::kGcTypeSticky) ?
               young_concurrent_copying_collector_ : concurrent_copying_collector_;
-          active_concurrent_copying_collector_->SetRegionSpace(region_space_);
+          DCHECK(active_concurrent_copying_collector_->RegionSpace() == region_space_);
         }
         collector = active_concurrent_copying_collector_;
         break;
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index de65f023..aa09cbe 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -207,7 +207,9 @@
        bool gc_stress_mode,
        bool measure_gc_performance,
        bool use_homogeneous_space_compaction,
-       uint64_t min_interval_homogeneous_space_compaction_by_oom);
+       uint64_t min_interval_homogeneous_space_compaction_by_oom,
+       bool dump_region_info_before_gc,
+       bool dump_region_info_after_gc);
 
   ~Heap();
 
@@ -1506,6 +1508,11 @@
   // allocating.
   bool gc_disabled_for_shutdown_ GUARDED_BY(gc_complete_lock_);
 
+  // Turned on by -XX:DumpRegionInfoBeforeGC and -XX:DumpRegionInfoAfterGC to
+  // emit region info before and after each GC cycle.
+  bool dump_region_info_before_gc_;
+  bool dump_region_info_after_gc_;
+
   // Boot image spaces.
   std::vector<space::ImageSpace*> boot_image_spaces_;
 
diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc
index 98b140e..07783ba 100644
--- a/runtime/gc/space/region_space.cc
+++ b/runtime/gc/space/region_space.cc
@@ -835,8 +835,14 @@
      << " type=" << type_
      << " objects_allocated=" << objects_allocated_
      << " alloc_time=" << alloc_time_
-     << " live_bytes=" << live_bytes_
-     << " is_newly_allocated=" << std::boolalpha << is_newly_allocated_ << std::noboolalpha
+     << " live_bytes=" << live_bytes_;
+
+  if (live_bytes_ != static_cast<size_t>(-1)) {
+    os << " ratio over allocated bytes="
+       << (static_cast<float>(live_bytes_) / RoundUp(BytesAllocated(), kRegionSize));
+  }
+
+  os << " is_newly_allocated=" << std::boolalpha << is_newly_allocated_ << std::noboolalpha
      << " is_a_tlab=" << std::boolalpha << is_a_tlab_ << std::noboolalpha
      << " thread=" << thread_ << '\n';
 }
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 17ff3a2..4a04259 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -151,6 +151,10 @@
           .IntoKey(M::LongGCLogThreshold)
       .Define("-XX:DumpGCPerformanceOnShutdown")
           .IntoKey(M::DumpGCPerformanceOnShutdown)
+      .Define("-XX:DumpRegionInfoBeforeGC")
+          .IntoKey(M::DumpRegionInfoBeforeGC)
+      .Define("-XX:DumpRegionInfoAfterGC")
+          .IntoKey(M::DumpRegionInfoAfterGC)
       .Define("-XX:DumpJITInfoOnShutdown")
           .IntoKey(M::DumpJITInfoOnShutdown)
       .Define("-XX:IgnoreMaxFootprint")
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 55bc2ec..7eac3d9 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1249,7 +1249,9 @@
                        xgc_option.gcstress_,
                        xgc_option.measure_,
                        runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
-                       runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));
+                       runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs),
+                       runtime_options.Exists(Opt::DumpRegionInfoBeforeGC),
+                       runtime_options.Exists(Opt::DumpRegionInfoAfterGC));
 
   if (!heap_->HasBootImageSpace() && !allow_dex_file_fallback_) {
     LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 2b2919e..222c821 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -64,6 +64,8 @@
 RUNTIME_OPTIONS_KEY (MillisecondsToNanoseconds, \
                                           ThreadSuspendTimeout,           ThreadList::kDefaultThreadSuspendTimeout)
 RUNTIME_OPTIONS_KEY (Unit,                DumpGCPerformanceOnShutdown)
+RUNTIME_OPTIONS_KEY (Unit,                DumpRegionInfoBeforeGC)
+RUNTIME_OPTIONS_KEY (Unit,                DumpRegionInfoAfterGC)
 RUNTIME_OPTIONS_KEY (Unit,                DumpJITInfoOnShutdown)
 RUNTIME_OPTIONS_KEY (Unit,                IgnoreMaxFootprint)
 RUNTIME_OPTIONS_KEY (Unit,                LowMemoryMode)
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 8bec2d9..f459f9c 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -160,6 +160,7 @@
 }
 
 void Thread::InitTlsEntryPoints() {
+  ScopedTrace trace("InitTlsEntryPoints");
   // Insert a placeholder so we can easily tell if we call an unimplemented entry point.
   uintptr_t* begin = reinterpret_cast<uintptr_t*>(&tlsPtr_.jni_entrypoints);
   uintptr_t* end = reinterpret_cast<uintptr_t*>(
@@ -903,6 +904,8 @@
   tlsPtr_.pthread_self = pthread_self();
   CHECK(is_started_);
 
+  ScopedTrace trace("Thread::Init");
+
   SetUpAlternateSignalStack();
   if (!InitStackHwm()) {
     return false;
@@ -912,7 +915,10 @@
   RemoveSuspendTrigger();
   InitCardTable();
   InitTid();
-  interpreter::InitInterpreterTls(this);
+  {
+    ScopedTrace trace2("InitInterpreterTls");
+    interpreter::InitInterpreterTls(this);
+  }
 
 #ifdef ART_TARGET_ANDROID
   __get_tls()[TLS_SLOT_ART_THREAD_SELF] = this;
@@ -936,6 +942,7 @@
     }
   }
 
+  ScopedTrace trace3("ThreadList::Register");
   thread_list->Register(this);
   return true;
 }
@@ -943,6 +950,7 @@
 template <typename PeerAction>
 Thread* Thread::Attach(const char* thread_name, bool as_daemon, PeerAction peer_action) {
   Runtime* runtime = Runtime::Current();
+  ScopedTrace trace("Thread::Attach");
   if (runtime == nullptr) {
     LOG(ERROR) << "Thread attaching to non-existent runtime: " <<
         ((thread_name != nullptr) ? thread_name : "(Unnamed)");
@@ -950,6 +958,7 @@
   }
   Thread* self;
   {
+    ScopedTrace trace2("Thread birth");
     MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
     if (runtime->IsShuttingDownLocked()) {
       LOG(WARNING) << "Thread attaching while runtime is shutting down: " <<
@@ -1251,6 +1260,7 @@
 }
 
 bool Thread::InitStackHwm() {
+  ScopedTrace trace("InitStackHwm");
   void* read_stack_base;
   size_t read_stack_size;
   size_t read_guard_size;
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 5bcd1c0..879f2fd 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1161,5 +1161,11 @@
         "tests": ["454-get-vreg", "457-regs"],
         "variant": "baseline",
         "description": ["Tests are expected to fail with baseline."]
+    },
+    {
+        "tests": ["708-jit-cache-churn"],
+        "variant": "jit-on-first-use",
+        "bug": "b/120112467",
+        "description": [ "Fails on Android Build hosts with uncaught std::bad_alloc." ]
     }
 ]
diff --git a/tools/timeout_dumper/timeout_dumper.cc b/tools/timeout_dumper/timeout_dumper.cc
index 96d165c..e04aefb 100644
--- a/tools/timeout_dumper/timeout_dumper.cc
+++ b/tools/timeout_dumper/timeout_dumper.cc
@@ -29,6 +29,7 @@
 #include <thread>
 #include <memory>
 #include <set>
+#include <string>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -103,9 +104,22 @@
     }
   }
 
-  std::string path = std::string(".") + kAddr2linePath;
-  if (access(path.c_str(), X_OK) == 0) {
-    return std::make_unique<std::string>(path);
+  {
+    std::string path = std::string(".") + kAddr2linePath;
+    if (access(path.c_str(), X_OK) == 0) {
+      return std::make_unique<std::string>(path);
+    }
+  }
+
+  {
+    using android::base::Dirname;
+
+    std::string exec_dir = android::base::GetExecutableDirectory();
+    std::string derived_top = Dirname(Dirname(Dirname(Dirname(exec_dir))));
+    std::string path = derived_top + kAddr2linePath;
+    if (access(path.c_str(), X_OK) == 0) {
+      return std::make_unique<std::string>(path);
+    }
   }
 
   constexpr const char* kHostAddr2line = "/usr/bin/addr2line";
@@ -356,6 +370,91 @@
   return ret;
 }
 
+void DumpABI(pid_t forked_pid) {
+  enum class ABI { kArm, kArm64, kMips, kMips64, kX86, kX86_64 };
+#if defined(__arm__)
+  constexpr ABI kDumperABI = ABI::kArm;
+#elif defined(__aarch64__)
+  constexpr ABI kDumperABI = ABI::kArm64;
+#elif defined(__mips__) && !defined(__LP64__)
+  constexpr ABI kDumperABI = ABI::kMips;
+#elif defined(__mips__) && defined(__LP64__)
+  constexpr ABI kDumperABI = ABI::kMips64;
+#elif defined(__i386__)
+  constexpr ABI kDumperABI = ABI::kX86;
+#elif defined(__x86_64__)
+  constexpr ABI kDumperABI = ABI::kX86_64;
+#else
+#error Unsupported architecture
+#endif
+
+  char data[1024];  // Should be more than enough.
+  struct iovec io_vec;
+  io_vec.iov_base = &data;
+  io_vec.iov_len = 1024;
+  ABI to_print;
+  if (0 != ::ptrace(PTRACE_GETREGSET, forked_pid, /* NT_PRSTATUS */ 1, &io_vec)) {
+    LOG(ERROR) << "Could not get registers to determine abi.";
+    // Use 64-bit as default.
+    switch (kDumperABI) {
+      case ABI::kArm:
+      case ABI::kArm64:
+        to_print = ABI::kArm64;
+        break;
+      case ABI::kMips:
+      case ABI::kMips64:
+        to_print = ABI::kMips64;
+        break;
+      case ABI::kX86:
+      case ABI::kX86_64:
+        to_print = ABI::kX86_64;
+        break;
+      default:
+        __builtin_unreachable();
+    }
+  } else {
+    // Check the length of the data. Assume that it's the same arch as the tool.
+    switch (kDumperABI) {
+      case ABI::kArm:
+      case ABI::kArm64:
+        to_print = io_vec.iov_len == 18 * sizeof(uint32_t) ? ABI::kArm : ABI::kArm64;
+        break;
+      case ABI::kMips:
+      case ABI::kMips64:
+        to_print = ABI::kMips64;  // TODO Figure out how this should work.
+        break;
+      case ABI::kX86:
+      case ABI::kX86_64:
+        to_print = io_vec.iov_len == 17 * sizeof(uint32_t) ? ABI::kX86 : ABI::kX86_64;
+        break;
+      default:
+        __builtin_unreachable();
+    }
+  }
+  std::string abi_str;
+  switch (to_print) {
+    case ABI::kArm:
+      abi_str = "arm";
+      break;
+    case ABI::kArm64:
+      abi_str = "arm64";
+      break;
+    case ABI::kMips:
+      abi_str = "mips";
+      break;
+    case ABI::kMips64:
+      abi_str = "mips64";
+      break;
+    case ABI::kX86:
+      abi_str = "x86";
+      break;
+    case ABI::kX86_64:
+      abi_str = "x86_64";
+      break;
+  }
+  std::cerr << "ABI: '" << abi_str << "'" << std::endl;
+}
+
 }  // namespace ptrace
 
 template <typename T>
@@ -495,19 +594,22 @@
 }
 
 void DumpProcess(pid_t forked_pid, const std::atomic<bool>& saw_wif_stopped_for_main) {
+  LOG(ERROR) << "Timeout for process " << forked_pid;
+
   CHECK_EQ(0, ::ptrace(PTRACE_ATTACH, forked_pid, 0, 0));
   std::set<pid_t> tids = ptrace::PtraceSiblings(forked_pid);
   tids.insert(forked_pid);
 
+  ptrace::DumpABI(forked_pid);
+
   // Check whether we have and should use addr2line.
-  std::unique_ptr<std::string> addr2line_path = addr2line::FindAddr2line();
-  if (addr2line_path != nullptr) {
-    LOG(ERROR) << "Found addr2line at " << *addr2line_path;
-  } else {
-    LOG(ERROR) << "Did not find usable addr2line";
+  std::unique_ptr<std::string> addr2line_path;
+  if (kUseAddr2line) {
+    addr2line_path = addr2line::FindAddr2line();
+    if (addr2line_path == nullptr) {
+      LOG(ERROR) << "Did not find usable addr2line";
+    }
   }
-  bool use_addr2line = kUseAddr2line && addr2line_path != nullptr;
-  LOG(ERROR) << (use_addr2line ? "U" : "Not u") << "sing addr2line";
 
   if (!WaitForMainSigStop(saw_wif_stopped_for_main)) {
     LOG(ERROR) << "Did not receive SIGSTOP for pid " << forked_pid;
@@ -520,11 +622,7 @@
   }
 
   for (pid_t tid : tids) {
-    DumpThread(forked_pid,
-               tid,
-               use_addr2line ? addr2line_path.get() : nullptr,
-               "  ",
-               backtrace_map.get());
+    DumpThread(forked_pid, tid, addr2line_path.get(), "  ", backtrace_map.get());
   }
 }