From a2cee18799d7e61adb037a4219adb23fef7d022b Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 16 Apr 2014 19:13:59 -0700 Subject: [PATCH] Modify unwind to comply with stack parser tools. Bug: 14081592 Change-Id: I6906b2575c74d64f1c3ba7602779b3a789de1c69 --- runtime/runtime_linux.cc | 2 +- runtime/thread.cc | 2 +- runtime/thread_list.cc | 4 ++-- runtime/utils.cc | 48 +++++++++++++++++++++--------------------------- runtime/utils.h | 2 +- 5 files changed, 26 insertions(+), 32 deletions(-) diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc index da1b2cac1..960d3324d 100644 --- a/runtime/runtime_linux.cc +++ b/runtime/runtime_linux.cc @@ -33,7 +33,7 @@ static constexpr bool kDumpHeapObjectOnSigsevg = false; struct Backtrace { void Dump(std::ostream& os) { - DumpNativeStack(os, GetTid(), "\t", true); + DumpNativeStack(os, GetTid(), "\t"); } }; diff --git a/runtime/thread.cc b/runtime/thread.cc index 8691dec3b..3408dd31c 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -939,7 +939,7 @@ void Thread::DumpStack(std::ostream& os) const { if (dump_for_abort || ShouldShowNativeStack(this)) { DumpKernelStack(os, GetTid(), " kernel: ", false); SirtRef method_ref(Thread::Current(), GetCurrentMethod(nullptr)); - DumpNativeStack(os, GetTid(), " native: ", false, method_ref.get()); + DumpNativeStack(os, GetTid(), " native: ", method_ref.get()); } DumpJavaStack(os); } else { diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index 270deb0a9..6f93566a5 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -78,7 +78,7 @@ void ThreadList::DumpNativeStacks(std::ostream& os) { MutexLock mu(Thread::Current(), *Locks::thread_list_lock_); for (const auto& thread : list_) { os << "DUMPING THREAD " << thread->GetTid() << "\n"; - DumpNativeStack(os, thread->GetTid(), "\t", true); + DumpNativeStack(os, thread->GetTid(), "\t"); os << "\n"; } } @@ -99,7 +99,7 @@ static void DumpUnattachedThread(std::ostream& os, pid_t tid) NO_THREAD_SAFETY_A // TODO: Reenable this when the native code in system_server can handle it. // Currently "adb shell kill -3 `pid system_server`" will cause it to exit. if (false) { - DumpNativeStack(os, tid, " native: ", false); + DumpNativeStack(os, tid, " native: "); } os << "\n"; } diff --git a/runtime/utils.cc b/runtime/utils.cc index afbcbb758..c4d1a7864 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -1041,20 +1041,7 @@ std::string GetSchedulerGroupName(pid_t tid) { return ""; } -static std::string CleanMapName(const backtrace_map_t* map) { - if (map == NULL || map->name.empty()) { - return "???"; - } - // Turn "/usr/local/google/home/enh/clean-dalvik-dev/out/host/linux-x86/lib/libartd.so" - // into "libartd.so". - size_t last_slash = map->name.rfind('/'); - if (last_slash == std::string::npos) { - return map->name; - } - 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, 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) { @@ -1072,27 +1059,34 @@ void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, bool inclu for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) { // We produce output like this: - // ] #00 unwind_backtrace_thread+536 [0x55d75bb8] (libbacktrace.so) - os << prefix; - if (include_count) { - os << StringPrintf("#%02zu ", it->num); - } - if (!it->func_name.empty()) { - os << it->func_name; + // ] #00 pc 000075bb8 /system/lib/libc.so (unwind_backtrace_thread+536) + // In order for parsing tools to continue to function, the stack dump + // format must at least adhere to this format: + // #XX pc ... + // The parsers require a single space before and after pc, and two spaces + // after the . There can be any prefix data before the + // #XX. has to be a hex number but with no 0x prefix. + os << prefix << StringPrintf("#%02zu pc ", it->num); + if (!it->map) { + os << StringPrintf("%08" PRIxPTR " ???", it->pc); } else { - if (current_method != nullptr && current_method->IsWithinQuickCode(it->pc)) { + os << StringPrintf("%08" PRIxPTR " ", it->pc - it->map->start) + << it->map->name << " ("; + if (!it->func_name.empty()) { + os << it->func_name; + if (it->func_offset != 0) { + os << "+" << it->func_offset; + } + } else if (current_method != nullptr && current_method->IsWithinQuickCode(it->pc)) { const void* start_of_code = current_method->GetEntryPointFromQuickCompiledCode(); os << JniLongName(current_method) << "+" << (it->pc - reinterpret_cast(start_of_code)); } else { os << "???"; } + os << ")"; } - if (it->func_offset != 0) { - os << "+" << it->func_offset; - } - os << StringPrintf(" [%p]", reinterpret_cast(it->pc)); - os << " (" << CleanMapName(it->map) << ")\n"; + os << "\n"; } } diff --git a/runtime/utils.h b/runtime/utils.h index 5def66b56..6ab10137b 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -382,7 +382,7 @@ 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, mirror::ArtMethod* current_method = nullptr) + 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. -- 2.11.0