Use libunwindstack instead of libbacktrace.
Replace all instances of libbacktrace code with equivalent
libunwindstack code.
Test: Run 037-cfi test in optimized, interpreter, jit modes.
Test: Ran 004-ThreadStress in a loop for optimized, interpreter, jit modes.
Test: Forced an ANR and verified native stacks are correct, and that
Test: native stacks correctly stop before java stacks.
Change-Id: I642ffd61b731dae6a68a5ba9453485a79f608d28
diff --git a/runtime/Android.bp b/runtime/Android.bp
index d11f8fa..7390953 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -465,7 +465,6 @@
],
shared_libs: [
"libartpalette",
- "libbacktrace",
"libbase", // For common macros.
"liblog",
"liblz4",
@@ -495,7 +494,6 @@
name: "libart_static_base_defaults",
whole_static_libs: [
"libartpalette",
- "libbacktrace",
"libbase",
"liblog",
"liblz4",
@@ -847,7 +845,7 @@
"verifier/reg_type_test.cc",
],
shared_libs: [
- "libbacktrace",
+ "libunwindstack",
],
header_libs: [
"art_cmdlineparser_headers", // For parsed_options_test.
diff --git a/runtime/backtrace_helper.h b/runtime/backtrace_helper.h
index a74d0e0..9be2550 100644
--- a/runtime/backtrace_helper.h
+++ b/runtime/backtrace_helper.h
@@ -26,7 +26,7 @@
namespace art {
-// Using libbacktrace
+// Using libunwindstack
class BacktraceCollector {
public:
BacktraceCollector(uintptr_t* out_frames, size_t max_depth, size_t skip_count)
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index 31deda1..30b5ee6 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -24,8 +24,7 @@
#include "art_method.h"
// For DumpNativeStack.
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
+#include <unwindstack/AndroidUnwinder.h>
#if defined(__linux__)
@@ -324,27 +323,33 @@
void DumpNativeStack(std::ostream& os,
pid_t tid,
- BacktraceMap* existing_map,
+ const char* prefix,
+ ArtMethod* current_method,
+ void* ucontext_ptr,
+ bool skip_frames) {
+ unwindstack::AndroidLocalUnwinder unwinder;
+ DumpNativeStack(os, unwinder, tid, prefix, current_method, ucontext_ptr, skip_frames);
+}
+
+void DumpNativeStack(std::ostream& os,
+ unwindstack::AndroidLocalUnwinder& unwinder,
+ pid_t tid,
const char* prefix,
ArtMethod* current_method,
void* ucontext_ptr,
bool skip_frames) {
// Historical note: This was disabled when running under Valgrind (b/18119146).
- BacktraceMap* map = existing_map;
- std::unique_ptr<BacktraceMap> tmp_map;
- if (map == nullptr) {
- tmp_map.reset(BacktraceMap::Create(getpid()));
- map = tmp_map.get();
+ unwindstack::AndroidUnwinderData data(!skip_frames /*show_all_frames*/);
+ bool unwind_ret;
+ if (ucontext_ptr != nullptr) {
+ unwind_ret = unwinder.Unwind(ucontext_ptr, data);
+ } else {
+ unwind_ret = unwinder.Unwind(tid, data);
}
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid, map));
- backtrace->SetSkipFrames(skip_frames);
- if (!backtrace->Unwind(0, reinterpret_cast<ucontext*>(ucontext_ptr))) {
- os << prefix << "(backtrace::Unwind failed for thread " << tid
- << ": " << backtrace->GetErrorString(backtrace->GetError()) << ")" << std::endl;
- return;
- } else if (backtrace->NumFrames() == 0) {
- os << prefix << "(no native stack frames for thread " << tid << ")" << std::endl;
+ if (!unwind_ret) {
+ os << prefix << "(Unwind failed for thread " << tid << ": "
+ << data.GetErrorString() << ")" << std::endl;
return;
}
@@ -359,9 +364,8 @@
}
std::unique_ptr<Addr2linePipe> addr2line_state;
-
- for (Backtrace::const_iterator it = backtrace->begin();
- it != backtrace->end(); ++it) {
+ data.DemangleFunctionNames();
+ for (const unwindstack::FrameData& frame : data.frames) {
// We produce output like this:
// ] #00 pc 000075bb8 /system/lib/libc.so (unwind_backtrace_thread+536)
// In order for parsing tools to continue to function, the stack dump
@@ -370,53 +374,55 @@
// The parsers require a single space before and after pc, and two spaces
// after the <RELATIVE_ADDR>. There can be any prefix data before the
// #XX. <RELATIVE_ADDR> has to be a hex number but with no 0x prefix.
- os << prefix << StringPrintf("#%02zu pc ", it->num);
+ os << prefix << StringPrintf("#%02zu pc ", frame.num);
bool try_addr2line = false;
- if (!BacktraceMap::IsValid(it->map)) {
+ if (frame.map_info == nullptr) {
os << StringPrintf(Is64BitInstructionSet(kRuntimeISA) ? "%016" PRIx64 " ???"
: "%08" PRIx64 " ???",
- it->pc);
+ frame.pc);
} else {
os << StringPrintf(Is64BitInstructionSet(kRuntimeISA) ? "%016" PRIx64 " "
: "%08" PRIx64 " ",
- it->rel_pc);
- if (it->map.name.empty()) {
- os << StringPrintf("<anonymous:%" PRIx64 ">", it->map.start);
+ frame.rel_pc);
+ const std::shared_ptr<unwindstack::MapInfo>& map_info = frame.map_info;
+ if (map_info->name().empty()) {
+ os << StringPrintf("<anonymous:%" PRIx64 ">", map_info->start());
} else {
- os << it->map.name;
+ os << map_info->name().c_str();
}
- if (it->map.offset != 0) {
- os << StringPrintf(" (offset %" PRIx64 ")", it->map.offset);
+ if (map_info->elf_start_offset() != 0) {
+ os << StringPrintf(" (offset %" PRIx64 ")", map_info->elf_start_offset());
}
os << " (";
- if (!it->func_name.empty()) {
- os << it->func_name;
- if (it->func_offset != 0) {
- os << "+" << it->func_offset;
+ if (!frame.function_name.empty()) {
+ os << frame.function_name.c_str();
+ if (frame.function_offset != 0) {
+ os << "+" << frame.function_offset;
}
// Functions found using the gdb jit interface will be in an empty
// map that cannot be found using addr2line.
- if (!it->map.name.empty()) {
+ if (!map_info->name().empty()) {
try_addr2line = true;
}
} else if (current_method != nullptr &&
Locks::mutator_lock_->IsSharedHeld(Thread::Current()) &&
- PcIsWithinQuickCode(current_method, it->pc)) {
+ PcIsWithinQuickCode(current_method, frame.pc)) {
const void* start_of_code = current_method->GetEntryPointFromQuickCompiledCode();
os << current_method->JniLongName() << "+"
- << (it->pc - reinterpret_cast<uint64_t>(start_of_code));
+ << (frame.pc - reinterpret_cast<uint64_t>(start_of_code));
} else {
os << "???";
}
os << ")";
- std::string build_id = map->GetBuildId(it->pc);
+ std::string build_id = map_info->GetPrintableBuildID();
if (!build_id.empty()) {
os << " (BuildId: " << build_id << ")";
}
}
os << std::endl;
if (try_addr2line && use_addr2line) {
- Addr2line(it->map.name, it->rel_pc, os, prefix, &addr2line_state);
+ // Guaranteed that map_info is not nullptr and name is non-empty.
+ Addr2line(frame.map_info->name(), frame.rel_pc, os, prefix, &addr2line_state);
}
}
@@ -429,7 +435,15 @@
void DumpNativeStack(std::ostream& os ATTRIBUTE_UNUSED,
pid_t tid ATTRIBUTE_UNUSED,
- BacktraceMap* existing_map ATTRIBUTE_UNUSED,
+ const char* prefix ATTRIBUTE_UNUSED,
+ ArtMethod* current_method ATTRIBUTE_UNUSED,
+ void* ucontext_ptr ATTRIBUTE_UNUSED,
+ bool skip_frames ATTRIBUTE_UNUSED) {
+}
+
+void DumpNativeStack(std::ostream& os ATTRIBUTE_UNUSED,
+ unwindstack::AndroidLocalUnwinder& existing_map ATTRIBUTE_UNUSED,
+ pid_t tid ATTRIBUTE_UNUSED,
const char* prefix ATTRIBUTE_UNUSED,
ArtMethod* current_method ATTRIBUTE_UNUSED,
void* ucontext_ptr ATTRIBUTE_UNUSED,
diff --git a/runtime/native_stack_dump.h b/runtime/native_stack_dump.h
index 4d4b36b..99fb59c 100644
--- a/runtime/native_stack_dump.h
+++ b/runtime/native_stack_dump.h
@@ -23,7 +23,9 @@
#include "base/macros.h"
-class BacktraceMap;
+namespace unwindstack {
+class AndroidLocalUnwinder;
+} // namespace unwindstack
namespace art {
@@ -32,7 +34,15 @@
// Dumps the native stack for thread 'tid' to 'os'.
void DumpNativeStack(std::ostream& os,
pid_t tid,
- BacktraceMap* map = nullptr,
+ const char* prefix = "",
+ ArtMethod* current_method = nullptr,
+ void* ucontext = nullptr,
+ bool skip_frames = true)
+ NO_THREAD_SAFETY_ANALYSIS;
+
+void DumpNativeStack(std::ostream& os,
+ unwindstack::AndroidLocalUnwinder& unwinder,
+ pid_t tid,
const char* prefix = "",
ArtMethod* current_method = nullptr,
void* ucontext = nullptr,
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index e56d533..ebad371 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -543,7 +543,7 @@
os << "Runtime aborting...\n";
if (Runtime::Current() == nullptr) {
os << "(Runtime does not yet exist!)\n";
- DumpNativeStack(os, GetTid(), nullptr, " native: ", nullptr);
+ DumpNativeStack(os, GetTid(), " native: ", nullptr);
return;
}
Thread* self = Thread::Current();
@@ -555,7 +555,7 @@
if (self == nullptr) {
os << "(Aborting thread was not attached to runtime!)\n";
- DumpNativeStack(os, GetTid(), nullptr, " native: ", nullptr);
+ DumpNativeStack(os, GetTid(), " native: ", nullptr);
} else {
os << "Aborting thread:\n";
if (Locks::mutator_lock_->IsExclusiveHeld(self) || Locks::mutator_lock_->IsSharedHeld(self)) {
diff --git a/runtime/runtime_common.h b/runtime/runtime_common.h
index 925594e..ec08907 100644
--- a/runtime/runtime_common.h
+++ b/runtime/runtime_common.h
@@ -42,7 +42,7 @@
void Dump(std::ostream& os) const {
// This is a backtrace from a crash, do not skip any frames in case the
// crash is in the unwinder itself.
- DumpNativeStack(os, GetTid(), nullptr, "\t", nullptr, raw_context_, false);
+ DumpNativeStack(os, GetTid(), "\t", nullptr, raw_context_, false);
}
private:
// Stores the context of the signal that was unexpected and will terminate the runtime. The
diff --git a/runtime/thread.cc b/runtime/thread.cc
index e7c6bec..bc39d7f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -41,6 +41,8 @@
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
+#include "unwindstack/AndroidUnwinder.h"
+
#include "arch/context-inl.h"
#include "arch/context.h"
#include "art_field-inl.h"
@@ -1391,10 +1393,15 @@
tls32_.num_name_readers.fetch_sub(1 /* at least memory_order_release */);
}
-void Thread::Dump(std::ostream& os, bool dump_native_stack, BacktraceMap* backtrace_map,
- bool force_dump_stack) const {
+void Thread::Dump(std::ostream& os, bool dump_native_stack, bool force_dump_stack) const {
DumpState(os);
- DumpStack(os, dump_native_stack, backtrace_map, force_dump_stack);
+ DumpStack(os, dump_native_stack, force_dump_stack);
+}
+
+void Thread::Dump(std::ostream& os, unwindstack::AndroidLocalUnwinder& unwinder,
+ bool dump_native_stack, bool force_dump_stack) const {
+ DumpState(os);
+ DumpStack(os, unwinder, dump_native_stack, force_dump_stack);
}
ObjPtr<mirror::String> Thread::GetThreadName() const {
@@ -2280,7 +2287,14 @@
void Thread::DumpStack(std::ostream& os,
bool dump_native_stack,
- BacktraceMap* backtrace_map,
+ bool force_dump_stack) const {
+ unwindstack::AndroidLocalUnwinder unwinder;
+ DumpStack(os, unwinder, dump_native_stack, force_dump_stack);
+}
+
+void Thread::DumpStack(std::ostream& os,
+ unwindstack::AndroidLocalUnwinder& unwinder,
+ bool dump_native_stack,
bool force_dump_stack) const {
// TODO: we call this code when dying but may not have suspended the thread ourself. The
// IsSuspended check is therefore racy with the use for dumping (normally we inhibit
@@ -2299,7 +2313,7 @@
GetCurrentMethod(nullptr,
/*check_suspended=*/ !force_dump_stack,
/*abort_on_error=*/ !(dump_for_abort || force_dump_stack));
- DumpNativeStack(os, GetTid(), backtrace_map, " native: ", method);
+ DumpNativeStack(os, unwinder, GetTid(), " native: ", method);
}
DumpJavaStack(os,
/*check_suspended=*/ !force_dump_stack,
diff --git a/runtime/thread.h b/runtime/thread.h
index 7ac4007..51d1fdc 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -48,7 +48,9 @@
#include "runtime_stats.h"
#include "thread_state.h"
-class BacktraceMap;
+namespace unwindstack {
+class AndroidLocalUnwinder;
+} // namespace unwindstack
namespace art {
@@ -270,7 +272,11 @@
// Dumps the detailed thread state and the thread stack (used for SIGQUIT).
void Dump(std::ostream& os,
bool dump_native_stack = true,
- BacktraceMap* backtrace_map = nullptr,
+ bool force_dump_stack = false) const
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ void Dump(std::ostream& os,
+ unwindstack::AndroidLocalUnwinder& unwinder,
+ bool dump_native_stack = true,
bool force_dump_stack = false) const
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -1492,7 +1498,11 @@
void DumpState(std::ostream& os) const REQUIRES_SHARED(Locks::mutator_lock_);
void DumpStack(std::ostream& os,
bool dump_native_stack = true,
- BacktraceMap* backtrace_map = nullptr,
+ bool force_dump_stack = false) const
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ void DumpStack(std::ostream& os,
+ unwindstack::AndroidLocalUnwinder& unwinder,
+ bool dump_native_stack = true,
bool force_dump_stack = false) const
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index bfde711..ca179ef 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -24,9 +24,9 @@
#include <vector>
#include "android-base/stringprintf.h"
-#include "backtrace/BacktraceMap.h"
#include "nativehelper/scoped_local_ref.h"
#include "nativehelper/scoped_utf_chars.h"
+#include "unwindstack/AndroidUnwinder.h"
#include "base/aborting.h"
#include "base/histogram-inl.h"
@@ -124,10 +124,10 @@
void ThreadList::DumpNativeStacks(std::ostream& os) {
MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
+ unwindstack::AndroidLocalUnwinder unwinder;
for (const auto& thread : list_) {
os << "DUMPING THREAD " << thread->GetTid() << "\n";
- DumpNativeStack(os, thread->GetTid(), map.get(), "\t");
+ DumpNativeStack(os, unwinder, thread->GetTid(), "\t");
os << "\n";
}
}
@@ -153,7 +153,7 @@
// refactor DumpState to avoid skipping analysis.
Thread::DumpState(os, nullptr, tid);
if (dump_native_stack) {
- DumpNativeStack(os, tid, nullptr, " native: ");
+ DumpNativeStack(os, tid, " native: ");
}
os << std::endl;
}
@@ -195,11 +195,8 @@
// Avoid verifying count in case a thread doesn't end up passing through the barrier.
// This avoids a SIGABRT that would otherwise happen in the destructor.
barrier_(0, /*verify_count_on_shutdown=*/false),
- backtrace_map_(dump_native_stack ? BacktraceMap::Create(getpid()) : nullptr),
+ unwinder_(std::vector<std::string>{}, std::vector<std::string> {"oat", "odex"}),
dump_native_stack_(dump_native_stack) {
- if (backtrace_map_ != nullptr) {
- backtrace_map_->SetSuffixesToIgnore(std::vector<std::string> { "oat", "odex" });
- }
}
void Run(Thread* thread) override {
@@ -210,7 +207,7 @@
std::ostringstream local_os;
{
ScopedObjectAccess soa(self);
- thread->Dump(local_os, dump_native_stack_, backtrace_map_.get());
+ thread->Dump(local_os, unwinder_, dump_native_stack_);
}
{
// Use the logging lock to ensure serialization when writing to the common ostream.
@@ -237,7 +234,7 @@
// The barrier to be passed through and for the requestor to wait upon.
Barrier barrier_;
// A backtrace map, so that all threads use a shared info and don't reacquire/parse separately.
- std::unique_ptr<BacktraceMap> backtrace_map_;
+ unwindstack::AndroidLocalUnwinder unwinder_;
// Whether we should dump the native stack.
const bool dump_native_stack_;
};
@@ -486,7 +483,6 @@
// Assume it's stuck and safe to dump its stack.
thread->Dump(LOG_STREAM(FATAL_WITHOUT_ABORT),
/*dump_native_stack=*/ true,
- /*backtrace_map=*/ nullptr,
/*force_dump_stack=*/ true);
}
}
@@ -1324,7 +1320,7 @@
std::string thread_name;
self->GetThreadName(thread_name);
std::ostringstream os;
- DumpNativeStack(os, GetTid(), nullptr, " native: ", nullptr);
+ DumpNativeStack(os, GetTid(), " native: ", nullptr);
LOG(ERROR) << "Request to unregister unattached thread " << thread_name << "\n" << os.str();
break;
} else {