backtrace: use Java stack to help decode native
Before change:
native: usb_host_run+16 [0x400a43f9] (/libusbhost.so)
native: android::Vector<int>::do_move_forward(void*, void const*, unsigned int) const+54 [0x501b1c5b] (/libandroid_servers.so)
native: ??? [0x624de480] (/system@framework@boot.oat)
at com.android.server.usb.UsbHostManager.monitorUsbHostBus(Native method)
at com.android.server.usb.UsbHostManager.access$000(UsbHostManager.java:38)
After change:
native: usb_host_run+16 [0x400933f9] (libusbhost.so)
native: android::Vector<int>::do_move_forward(void*, void const*, unsigned int) const+54 [0x4e984c5b] (libandroid_servers.so)
native: Java_com_android_server_usb_UsbHostManager_monitorUsbHostBus__+92 [0x624de480] (system@framework@boot.oat)
at com.android.server.usb.UsbHostManager.monitorUsbHostBus(Native method)
at com.android.server.usb.UsbHostManager.access$000(UsbHostManager.java:38)
Change-Id: Iea550a251a12e9ba7df9582fd454093bfa4e90e0
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 0ad0190..1c42020 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -864,7 +864,8 @@
// If we're currently in native code, dump that stack before dumping the managed stack.
if (dump_for_abort || ShouldShowNativeStack(this)) {
DumpKernelStack(os, GetTid(), " kernel: ", false);
- DumpNativeStack(os, GetTid(), " native: ", false);
+ SirtRef<mirror::ArtMethod> method_ref(Thread::Current(), GetCurrentMethod(nullptr));
+ DumpNativeStack(os, GetTid(), " native: ", false, method_ref.get());
}
UniquePtr<Context> context(Context::Create());
StackDumpVisitor dumper(os, const_cast<Thread*>(this), context.get(), !throwing_OutOfMemoryError_);
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 237d217..d2d23e8 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -38,6 +38,7 @@
#include "mirror/string.h"
#include "object_utils.h"
#include "os.h"
+#include "scoped_thread_state_change.h"
#include "utf-inl.h"
#if !defined(HAVE_POSIX_CLOCKS)
@@ -1052,7 +1053,12 @@
return map->name.substr(last_slash + 1);
}
-void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, bool include_count) {
+void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, bool include_count,
+ mirror::ArtMethod* current_method) {
+ // We may be called from contexts where current_method is not null, so we must assert this.
+ if (current_method != nullptr) {
+ Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+ }
UniquePtr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid));
if (!backtrace->Unwind(0)) {
os << prefix << "(backtrace::Unwind failed for thread " << tid << ")\n";
@@ -1073,7 +1079,11 @@
if (!it->func_name.empty()) {
os << it->func_name;
} else {
- os << "???";
+ if (current_method != nullptr && current_method->IsWithinQuickCode(it->pc)) {
+ os << JniLongName(current_method) << "+" << (it->pc - current_method->GetQuickOatCodeOffset());
+ } else {
+ os << "???";
+ }
}
if (it->func_offset != 0) {
os << "+" << it->func_offset;
diff --git a/runtime/utils.h b/runtime/utils.h
index bcbeb0e..dbc3ab7 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -373,7 +373,9 @@
void SetThreadName(const char* thread_name);
// Dumps the native stack for thread 'tid' to 'os'.
-void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix = "", bool include_count = true);
+void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix = "",
+ bool include_count = true, mirror::ArtMethod* current_method = nullptr)
+ NO_THREAD_SAFETY_ANALYSIS;
// Dumps the kernel stack for thread 'tid' to 'os'. Note that this is only available on linux-x86.
void DumpKernelStack(std::ostream& os, pid_t tid, const char* prefix = "", bool include_count = true);