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/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 178c2a9..9082172 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -328,12 +328,35 @@
       class_loader_(class_loader),
       class_def_idx_(class_def_idx),
       code_item_(code_item),
+      interesting_dex_pc_(-1),
+      monitor_enter_dex_pcs_(NULL),
       have_pending_hard_failure_(false),
       have_pending_rewrite_failure_(false),
       new_instance_count_(0),
       monitor_enter_count_(0) {
 }
 
+void MethodVerifier::FindLocksAtDexPc(Method* m, uint32_t dex_pc, std::vector<uint32_t>& monitor_enter_dex_pcs) {
+  MethodHelper mh(m);
+  MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(),
+                          mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(),
+                          m, m->GetAccessFlags());
+  verifier.interesting_dex_pc_ = dex_pc;
+  verifier.monitor_enter_dex_pcs_ = &monitor_enter_dex_pcs;
+  verifier.FindLocksAtDexPc();
+}
+
+void MethodVerifier::FindLocksAtDexPc() {
+  CHECK(monitor_enter_dex_pcs_ != NULL);
+  CHECK(code_item_ != NULL); // This only makes sense for methods with code.
+
+  // Strictly speaking, we ought to be able to get away with doing a subset of the full method
+  // verification. In practice, the phase we want relies on data structures set up by all the
+  // earlier passes, so we just run the full method verification and bail out early when we've
+  // got what we wanted.
+  Verify();
+}
+
 bool MethodVerifier::Verify() {
   // If there aren't any instructions, make sure that's expected, then exit successfully.
   if (code_item_ == NULL) {
@@ -1276,6 +1299,16 @@
   }
 #endif
 
+  // If we're doing FindLocksAtDexPc, check whether we're at the dex pc we care about.
+  // We want the state _before_ the instruction, for the case where the dex pc we're
+  // interested in is itself a monitor-enter instruction (which is a likely place
+  // for a thread to be suspended).
+  if (monitor_enter_dex_pcs_ != NULL && work_insn_idx_ == interesting_dex_pc_) {
+    for (size_t i = 0; i < work_line_->GetMonitorEnterCount(); ++i) {
+      monitor_enter_dex_pcs_->push_back(work_line_->GetMonitorEnterDexPc(i));
+    }
+  }
+
   /*
    * Once we finish decoding the instruction, we need to figure out where
    * we can go from here. There are three possible ways to transfer