Include kernel stacks on non-ARM hardware.

Also explicitly say when we have no managed frames (so their absence
is clearly deliberate in those rare cases where it happens).

Change-Id: I5cd60235faad9297dcbeaa2aea62a101b8e20e89
diff --git a/src/thread.cc b/src/thread.cc
index bbbe6e5..43c1e2d 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -564,6 +564,9 @@
   }
 
   virtual ~StackDumpVisitor() {
+    if (frame_count == 0) {
+      os << "  (no managed stack frames)\n";
+    }
   }
 
   bool VisitFrame(const Frame& frame, uintptr_t pc) {
@@ -620,12 +623,32 @@
 void Thread::DumpStack(std::ostream& os) const {
   // If we're currently in native code, dump that stack before dumping the managed stack.
   if (GetState() == kNative || GetState() == kVmWait) {
+    DumpKernelStack(os);
     DumpNativeStack(os);
   }
   StackDumpVisitor dumper(os, this);
   WalkStack(&dumper);
 }
 
+void Thread::DumpKernelStack(std::ostream& os) const {
+#if !defined(__APPLE__)
+  std::string kernel_stack_filename(StringPrintf("/proc/self/task/%d/stack", GetTid()));
+  std::string kernel_stack;
+  if (!ReadFileToString(kernel_stack_filename, &kernel_stack)) {
+    os << "  (couldn't read " << kernel_stack_filename << ")";
+  }
+
+  std::vector<std::string> kernel_stack_frames;
+  Split(kernel_stack, '\n', kernel_stack_frames);
+  // We skip the last stack frame because it's always equivalent to "[<ffffffff>] 0xffffffff",
+  // which looking at the source appears to be the kernel's way of saying "that's all, folks!".
+  kernel_stack_frames.pop_back();
+  for (size_t i = 0; i < kernel_stack_frames.size(); ++i) {
+    os << "  kernel: " << kernel_stack_frames[i] << "\n";
+  }
+#endif
+}
+
 void Thread::SetStateWithoutSuspendCheck(ThreadState new_state) {
   volatile void* raw = reinterpret_cast<volatile void*>(&state_);
   volatile int32_t* addr = reinterpret_cast<volatile int32_t*>(raw);
diff --git a/src/thread.h b/src/thread.h
index c5695cf..8ff9dfb 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -484,6 +484,7 @@
 
   void DumpState(std::ostream& os) const;
   void DumpStack(std::ostream& os) const;
+  void DumpKernelStack(std::ostream& os) const;
   void DumpNativeStack(std::ostream& os) const;
 
   // Out-of-line conveniences for debugging in gdb.
diff --git a/src/thread_android.cc b/src/thread_android.cc
index d26f446..4d982b1 100644
--- a/src/thread_android.cc
+++ b/src/thread_android.cc
@@ -97,6 +97,7 @@
     os << "  (unwind_backtrace_thread failed for thread " << GetTid() << ".)";
     return;
   } else if (frame_count == 0) {
+    os << "  (no native stack frames)";
     return;
   }