diff options
-rw-r--r-- | runtime/backtrace_helper.cc | 35 | ||||
-rw-r--r-- | runtime/backtrace_helper.h | 4 | ||||
-rw-r--r-- | runtime/deoptimization_kind.h | 2 | ||||
-rw-r--r-- | runtime/entrypoints/runtime_asm_entrypoints.h | 4 |
4 files changed, 41 insertions, 4 deletions
diff --git a/runtime/backtrace_helper.cc b/runtime/backtrace_helper.cc index 98280c779f..2d39270b53 100644 --- a/runtime/backtrace_helper.cc +++ b/runtime/backtrace_helper.cc @@ -26,6 +26,8 @@ #include "unwindstack/Memory.h" #include "unwindstack/Unwinder.h" +#include "base/bit_utils.h" +#include "entrypoints/runtime_asm_entrypoints.h" #include "thread-inl.h" #else @@ -56,6 +58,9 @@ struct UnwindHelper : public TLSData { unwindstack::Elf::SetCachingEnabled(true); } + // Reparse process mmaps to detect newly loaded libraries. + bool Reparse() { return maps_.Reparse(); } + static UnwindHelper* Get(Thread* self, size_t max_depth) { UnwindHelper* tls = reinterpret_cast<UnwindHelper*>(self->GetCustomTLS(kTlsKey)); if (tls == nullptr) { @@ -68,7 +73,7 @@ struct UnwindHelper : public TLSData { unwindstack::Unwinder* Unwinder() { return &unwinder_; } private: - unwindstack::LocalMaps maps_; + unwindstack::LocalUpdatableMaps maps_; std::shared_ptr<unwindstack::Memory> memory_; unwindstack::JitDebug jit_; unwindstack::DexFiles dex_; @@ -76,19 +81,41 @@ struct UnwindHelper : public TLSData { }; void BacktraceCollector::Collect() { + if (!CollectImpl()) { + // Reparse process mmaps to detect newly loaded libraries and retry. + UnwindHelper::Get(Thread::Current(), max_depth_)->Reparse(); + if (!CollectImpl()) { + // Failed to unwind stack. Ignore for now. + } + } +} + +bool BacktraceCollector::CollectImpl() { unwindstack::Unwinder* unwinder = UnwindHelper::Get(Thread::Current(), max_depth_)->Unwinder(); std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal()); RegsGetLocal(regs.get()); unwinder->SetRegs(regs.get()); unwinder->Unwind(); + num_frames_ = 0; if (unwinder->NumFrames() > skip_count_) { - for (auto it = unwinder->frames().begin() + skip_count_; - max_depth_ > num_frames_ && it != unwinder->frames().end(); - ++it) { + for (auto it = unwinder->frames().begin() + skip_count_; it != unwinder->frames().end(); ++it) { + CHECK_LT(num_frames_, max_depth_); out_frames_[num_frames_++] = static_cast<uintptr_t>(it->pc); + + // Expected early end: Instrumentation breaks unwinding (b/138296821). + size_t align = GetInstructionSetAlignment(kRuntimeISA); + if (RoundUp(it->pc, align) == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) { + return true; + } } } + + if (unwinder->LastErrorCode() == unwindstack::ERROR_INVALID_MAP) { + return false; + } + + return true; } #else diff --git a/runtime/backtrace_helper.h b/runtime/backtrace_helper.h index 8eda3fa0a1..2fee62c23d 100644 --- a/runtime/backtrace_helper.h +++ b/runtime/backtrace_helper.h @@ -36,6 +36,10 @@ class BacktraceCollector { void Collect(); private: + // Try to collect backtrace. Returns false on failure. + // It is used to retry backtrace on temporary failure. + bool CollectImpl(); + uintptr_t* const out_frames_ = nullptr; size_t num_frames_ = 0u; const size_t max_depth_ = 0u; diff --git a/runtime/deoptimization_kind.h b/runtime/deoptimization_kind.h index 14e189c5d1..5be6f3dab1 100644 --- a/runtime/deoptimization_kind.h +++ b/runtime/deoptimization_kind.h @@ -17,6 +17,8 @@ #ifndef ART_RUNTIME_DEOPTIMIZATION_KIND_H_ #define ART_RUNTIME_DEOPTIMIZATION_KIND_H_ +#include "base/logging.h" + namespace art { enum class DeoptimizationKind { diff --git a/runtime/entrypoints/runtime_asm_entrypoints.h b/runtime/entrypoints/runtime_asm_entrypoints.h index 3f4e91ed91..f350ce458d 100644 --- a/runtime/entrypoints/runtime_asm_entrypoints.h +++ b/runtime/entrypoints/runtime_asm_entrypoints.h @@ -19,8 +19,12 @@ #include "deoptimization_kind.h" +#include "jni.h" + namespace art { +class ArtMethod; + #ifndef BUILDING_LIBART #error "File and symbols only for use within libart." #endif |