Include held locks in SIGQUIT thread dumps.

Handy if you have an ANR that's locking related. Quick tour:

   at org.apache.harmony.dalvik.NativeTestTarget.emptyJniStaticSynchronizedMethod0(Native method)
   - locked <0x60135aa8> (a java.lang.Class<org.apache.harmony.dalvik.NativeTestTarget>)
   at java.lang.reflect.Method.invoke(Native method)
   at C.whileTrue(Main.java:63)
   at C.synchronizedOnClassString(Main.java:56)
   - locked <0x60002a70> (a java.lang.Class<java.lang.String>)
   at C.nestedSynchronizationWithTryCatch(Main.java:44)
   - locked <0x61336b90> (a java.lang.String)
   - locked <0x61336bd0> (a java.lang.String)
   at C.nestedSynchronization(Main.java:35)
   - locked <0x61336b18> (a java.lang.String)
   - locked <0x61336b50> (a java.lang.String)
   at C.synchronizedOnClassC(Main.java:30)
   - locked <0x613366f8> (a java.lang.Class<C>)
   at C.noLocks(Main.java:27)
   at C.<clinit>(Main.java:24)
   - locked <0x613366f8> (a java.lang.Class<C>)
   at Main.main(Main.java:19)

A non-static synchronized native method works too:

   at org.apache.harmony.dalvik.NativeTestTarget.emptyJniSynchronizedMethod0(Native method)
   - locked <0x613371a8> (a org.apache.harmony.dalvik.NativeTestTarget)
   ...

Note that most stack traces don't look any different; the above is a
pathological example that exercises different kinds of locking. Testing
with system_server shows most threads don't hold any locks.

Future work (marked by TODO) is that explicit JNI MonitorEnter calls in
native code aren't shown.

Change-Id: I2747f5cddb4ef64b1935736f084a68fe8e4005e9
diff --git a/src/stack.cc b/src/stack.cc
index e7c632c..c419530 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -27,7 +27,7 @@
 class StackGetter {
  public:
   StackGetter(const ScopedJniThreadState& ts, Thread* thread)
-    : ts_(ts), thread_(thread), trace_(NULL) {
+      : ts_(ts), thread_(thread), trace_(NULL) {
   }
 
   static void Callback(void* arg) {
@@ -106,6 +106,7 @@
 }
 
 uint32_t StackVisitor::GetVReg(Method* m, int vreg) const {
+  DCHECK(context_ != NULL); // You can't reliably read registers without a context.
   DCHECK(m == GetMethod());
   uint32_t core_spills = m->GetCoreSpillMask();
   const VmapTable vmap_table(m->GetVmapTableRaw());
@@ -135,6 +136,7 @@
 }
 
 void StackVisitor::SetVReg(Method* m, int vreg, uint32_t new_value) {
+  DCHECK(context_ != NULL); // You can't reliably write registers without a context.
   DCHECK(m == GetMethod());
   const VmapTable vmap_table(m->GetVmapTableRaw());
   uint32_t vmap_offset;
@@ -174,12 +176,13 @@
   struct NumFramesVisitor : public StackVisitor {
     explicit NumFramesVisitor(const ManagedStack* stack,
                               const std::vector<TraceStackFrame>* trace_stack)
-        : StackVisitor(stack, trace_stack), frames(0) {}
+        : StackVisitor(stack, trace_stack, NULL), frames(0) {}
 
     virtual bool VisitFrame() {
       frames++;
       return true;
     }
+
     size_t frames;
   };