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());
}
}