changeset 4242:143973ced9ab

Merge
author coleenp
date Thu, 28 Feb 2013 18:37:41 -0500
parents a506ac816f14 a140cd925462
children 3e83d69c19db
files
diffstat 15 files changed, 120 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/os/linux/LinuxDebuggerLocal.c	Wed Feb 27 07:35:32 2013 -0500
+++ b/agent/src/os/linux/LinuxDebuggerLocal.c	Thu Feb 28 18:37:41 2013 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,13 @@
 #include <jni.h>
 #include "libproc.h"
 
+#include <elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <limits.h>
+
 #if defined(x86_64) && !defined(amd64)
 #define amd64 1
 #endif
@@ -154,6 +161,39 @@
   }
 }
 
+
+/*
+ * Verify that a named ELF binary file (core or executable) has the same
+ * bitness as ourselves.
+ * Throw an exception if there is a mismatch or other problem.
+ *
+ * If we proceed using a mismatched debugger/debuggee, the best to hope
+ * for is a missing symbol, the worst is a crash searching for debug symbols.
+ */
+void verifyBitness(JNIEnv *env, const char *binaryName) {
+  int fd = open(binaryName, O_RDONLY);
+  if (fd < 0) {
+    THROW_NEW_DEBUGGER_EXCEPTION("cannot open binary file");
+  }
+  unsigned char elf_ident[EI_NIDENT];
+  int i = read(fd, &elf_ident, sizeof(elf_ident));
+  close(fd);
+
+  if (i < 0) {
+    THROW_NEW_DEBUGGER_EXCEPTION("cannot read binary file");
+  }
+#ifndef _LP64
+  if (elf_ident[EI_CLASS] == ELFCLASS64) {
+    THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use 64-bit java for debugger");
+  }
+#else
+  if (elf_ident[EI_CLASS] != ELFCLASS64) {
+    THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger");
+  }
+#endif
+}
+
+
 /*
  * Class:     sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal
  * Method:    attach0
@@ -162,6 +202,12 @@
 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_attach0__I
   (JNIEnv *env, jobject this_obj, jint jpid) {
 
+  // For bitness checking, locate binary at /proc/jpid/exe
+  char buf[PATH_MAX];
+  snprintf((char *) &buf, PATH_MAX, "/proc/%d/exe", jpid);
+  verifyBitness(env, (char *) &buf);
+  CHECK_EXCEPTION;
+
   struct ps_prochandle* ph;
   if ( (ph = Pgrab(jpid)) == NULL) {
     THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
@@ -187,6 +233,9 @@
   coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy);
   CHECK_EXCEPTION;
 
+  verifyBitness(env, execName_cstr);
+  CHECK_EXCEPTION;
+
   if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {
     (*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
     (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java	Wed Feb 27 07:35:32 2013 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java	Thu Feb 28 18:37:41 2013 -0500
@@ -60,8 +60,13 @@
         return null;
       }
 
+      // Check alignment of rbp
+      if ( dbg.getAddressValue(rbp) % ADDRESS_SIZE != 0) {
+        return null;
+      }
+
       Address nextRBP = rbp.getAddressAt( 0 * ADDRESS_SIZE);
-      if (nextRBP == null) {
+      if (nextRBP == null || nextRBP.lessThanOrEqual(rbp)) {
         return null;
       }
       Address nextPC  = rbp.getAddressAt( 1 * ADDRESS_SIZE);
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java	Wed Feb 27 07:35:32 2013 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java	Thu Feb 28 18:37:41 2013 -0500
@@ -61,8 +61,13 @@
         return null;
       }
 
+      // Check alignment of ebp
+      if ( dbg.getAddressValue(ebp) % ADDRESS_SIZE != 0) {
+        return null;
+      }
+
       Address nextEBP = ebp.getAddressAt( 0 * ADDRESS_SIZE);
-      if (nextEBP == null) {
+      if (nextEBP == null || nextEBP.lessThanOrEqual(ebp)) {
         return null;
       }
       Address nextPC  = ebp.getAddressAt( 1 * ADDRESS_SIZE);
--- a/src/share/vm/c1/c1_FrameMap.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/c1/c1_FrameMap.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -308,27 +308,6 @@
   return sp_offset_for_monitor_base(index) + in_ByteSize(BasicObjectLock::obj_offset_in_bytes());
 }
 
-void FrameMap::print_frame_layout() const {
-  int svar;
-  tty->print_cr("#####################################");
-  tty->print_cr("Frame size in words %d", framesize());
-
-  if( _num_monitors > 0) {
-    tty->print_cr("monitor [0]:%d | [%2d]:%d",
-                  in_bytes(sp_offset_for_monitor_base(0)),
-                  in_bytes(sp_offset_for_monitor_base(_num_monitors)));
-  }
-  if( _num_spills > 0) {
-    svar = _num_spills - 1;
-    if(svar == 0)
-      tty->print_cr("spill   [0]:%d", in_bytes(sp_offset_for_spill(0)));
-    else
-      tty->print_cr("spill   [0]:%d | [%2d]:%d", in_bytes(sp_offset_for_spill(0)),
-                    svar,
-                    in_bytes(sp_offset_for_spill(svar)));
-  }
-}
-
 
 // For OopMaps, map a local variable or spill index to an VMReg.
 // This is the offset from sp() in the frame of the slot for the index,
--- a/src/share/vm/c1/c1_FrameMap.hpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/c1/c1_FrameMap.hpp	Thu Feb 28 18:37:41 2013 -0500
@@ -226,8 +226,6 @@
     return make_new_address(sp_offset_for_monitor_object(monitor_index));
   }
 
-  void print_frame_layout() const;
-
   // Creates Location describing desired slot and returns it via pointer
   // to Location object. Returns true if the stack frame offset was legal
   // (as defined by Location::legal_offset_in_bytes()), false otherwise.
--- a/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -373,6 +373,8 @@
                          " does not exceed used.end() = " PTR_FORMAT ","
                          " yet last_chunk_index_to_check " INTPTR_FORMAT
                          " exceeds last_chunk_index " INTPTR_FORMAT,
+                         last_block, last_block + last_block_size,
+                         used.end(),
                          last_chunk_index_to_check, last_chunk_index));
           assert(sp->used_region().end() > used.end(),
                  err_msg("Expansion did not happen: "
--- a/src/share/vm/memory/cardTableModRefBS.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/memory/cardTableModRefBS.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -694,7 +694,7 @@
     if (failed) {
       if (!failures) {
         tty->cr();
-        tty->print_cr("== CT verification failed: ["PTR_FORMAT","PTR_FORMAT"]");
+        tty->print_cr("== CT verification failed: ["PTR_FORMAT","PTR_FORMAT"]", start, end);
         tty->print_cr("==   %sexpecting value: %d",
                       (val_equals) ? "" : "not ", val);
         failures = true;
--- a/src/share/vm/memory/cardTableRS.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/memory/cardTableRS.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -353,7 +353,7 @@
     assert(jp >= _begin && jp < _end,
            err_msg("Error: jp " PTR_FORMAT " should be within "
                    "[_begin, _end) = [" PTR_FORMAT "," PTR_FORMAT ")",
-                   _begin, _end));
+                   jp, _begin, _end));
     oop obj = oopDesc::load_decode_heap_oop(p);
     guarantee(obj == NULL || (HeapWord*)obj >= _boundary,
               err_msg("pointer " PTR_FORMAT " at " PTR_FORMAT " on "
--- a/src/share/vm/prims/jvmtiEnter.xsl	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/prims/jvmtiEnter.xsl	Thu Feb 28 18:37:41 2013 -0500
@@ -773,7 +773,7 @@
 </xsl:text>
     <xsl:apply-templates select=".." mode="traceError">     
       <xsl:with-param name="err">JVMTI_ERROR_INVALID_THREAD</xsl:with-param>
-      <xsl:with-param name="comment"> - jthread resolved to NULL - jthread = %0x%x</xsl:with-param>
+      <xsl:with-param name="comment"> - jthread resolved to NULL - jthread = 0x%x</xsl:with-param>
       <xsl:with-param name="extraValue">, <xsl:value-of select="$name"/></xsl:with-param>
     </xsl:apply-templates>
     <xsl:text>
@@ -782,7 +782,7 @@
 </xsl:text>
     <xsl:apply-templates select=".." mode="traceError">     
       <xsl:with-param name="err">JVMTI_ERROR_INVALID_THREAD</xsl:with-param>
-      <xsl:with-param name="comment"> - oop is not a thread - jthread = %0x%x</xsl:with-param>
+      <xsl:with-param name="comment"> - oop is not a thread - jthread = 0x%x</xsl:with-param>
       <xsl:with-param name="extraValue">, <xsl:value-of select="$name"/></xsl:with-param>
     </xsl:apply-templates>
     <xsl:text>
@@ -794,7 +794,7 @@
       <xsl:with-param name="err">
         <xsl:text>JVMTI_ERROR_THREAD_NOT_ALIVE</xsl:text>
       </xsl:with-param>
-      <xsl:with-param name="comment"> - not a Java thread - jthread = %0x%x</xsl:with-param>
+      <xsl:with-param name="comment"> - not a Java thread - jthread = 0x%x</xsl:with-param>
       <xsl:with-param name="extraValue">, <xsl:value-of select="$name"/></xsl:with-param>
     </xsl:apply-templates>
     <xsl:text>
@@ -838,7 +838,7 @@
 </xsl:text>
     <xsl:apply-templates select=".." mode="traceError">     
       <xsl:with-param name="err">JVMTI_ERROR_ILLEGAL_ARGUMENT</xsl:with-param>
-      <xsl:with-param name="comment"> - negative depth - jthread = %0x%x</xsl:with-param>
+      <xsl:with-param name="comment"> - negative depth - jthread = 0x%x</xsl:with-param>
       <xsl:with-param name="extraValue">, <xsl:value-of select="$name"/></xsl:with-param>
     </xsl:apply-templates>
     <xsl:text>
--- a/src/share/vm/prims/jvmtiEnvBase.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/prims/jvmtiEnvBase.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -997,13 +997,19 @@
       // move our object at this point. However, our owner value is safe
       // since it is either the Lock word on a stack or a JavaThread *.
       owning_thread = Threads::owning_thread_from_monitor_owner(owner, !at_safepoint);
-      assert(owning_thread != NULL, "sanity check");
-      if (owning_thread != NULL) {  // robustness
+      // Cannot assume (owning_thread != NULL) here because this function
+      // may not have been called at a safepoint and the owning_thread
+      // might not be suspended.
+      if (owning_thread != NULL) {
         // The monitor's owner either has to be the current thread, at safepoint
         // or it has to be suspended. Any of these conditions will prevent both
         // contending and waiting threads from modifying the state of
         // the monitor.
         if (!at_safepoint && !JvmtiEnv::is_thread_fully_suspended(owning_thread, true, &debug_bits)) {
+          // Don't worry! This return of JVMTI_ERROR_THREAD_NOT_SUSPENDED
+          // will not make it back to the JVM/TI agent. The error code will
+          // get intercepted in JvmtiEnv::GetObjectMonitorUsage() which
+          // will retry the call via a VM_GetObjectMonitorUsage VM op.
           return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
         }
         HandleMark hm;
--- a/src/share/vm/runtime/synchronizer.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/runtime/synchronizer.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -813,6 +813,7 @@
   }
 
   if (owner != NULL) {
+    // owning_thread_from_monitor_owner() may also return NULL here
     return Threads::owning_thread_from_monitor_owner(owner, doLock);
   }
 
--- a/src/share/vm/runtime/thread.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/runtime/thread.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -4285,7 +4285,9 @@
       if (owner == (address)p) return p;
     }
   }
-  assert(UseHeavyMonitors == false, "Did not find owning Java thread with UseHeavyMonitors enabled");
+  // Cannot assert on lack of success here since this function may be
+  // used by code that is trying to report useful problem information
+  // like deadlock detection.
   if (UseHeavyMonitors) return NULL;
 
   //
@@ -4303,7 +4305,7 @@
       }
     }
   }
-  assert(the_owner != NULL, "Did not find owning Java thread for lock word address");
+  // cannot assert on lack of success here; see above comment
   return the_owner;
 }
 
--- a/src/share/vm/services/memReporter.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/services/memReporter.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -419,7 +419,7 @@
       _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset);
       _output->print("%28s", " ");
     } else {
-      _output->print("[" PTR_FORMAT "]%18s", " ");
+      _output->print("[" PTR_FORMAT "]%18s", pc, " ");
     }
 
     _output->print_cr("(mmap: reserved=%d%s, committed=%d%s)",
@@ -596,7 +596,7 @@
         _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset);
         _output->print("%28s", " ");
       } else {
-        _output->print("[" PTR_FORMAT "]%18s", " ");
+        _output->print("[" PTR_FORMAT "]%18s", pc, " ");
       }
     }
 
--- a/src/share/vm/services/threadService.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/services/threadService.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -327,8 +327,28 @@
     while (waitingToLockMonitor != NULL || waitingToLockBlocker != NULL) {
       cycle->add_thread(currentThread);
       if (waitingToLockMonitor != NULL) {
-        currentThread = Threads::owning_thread_from_monitor_owner((address)waitingToLockMonitor->owner(),
-                                                                  false /* no locking needed */);
+        currentThread = Threads::owning_thread_from_monitor_owner(
+                          (address)waitingToLockMonitor->owner(),
+                          false /* no locking needed */);
+        if (currentThread == NULL) {
+          // This function is called at a safepoint so the JavaThread
+          // that owns waitingToLockMonitor should be findable, but
+          // if it is not findable, then the previous currentThread is
+          // blocked permanently. We record this as a deadlock.
+          num_deadlocks++;
+
+          cycle->set_deadlock(true);
+
+          // add this cycle to the deadlocks list
+          if (deadlocks == NULL) {
+            deadlocks = cycle;
+          } else {
+            last->set_next(cycle);
+          }
+          last = cycle;
+          cycle = new DeadlockCycle();
+          break;
+        }
       } else {
         if (concurrent_locks) {
           if (waitingToLockBlocker->is_a(SystemDictionary::abstract_ownable_synchronizer_klass())) {
@@ -841,7 +861,17 @@
         owner_desc = " (JVMTI raw monitor),\n  which is held by";
       }
       currentThread = Threads::owning_thread_from_monitor_owner(
-        (address)waitingToLockMonitor->owner(), false /* no locking needed */);
+                        (address)waitingToLockMonitor->owner(),
+                        false /* no locking needed */);
+      if (currentThread == NULL) {
+        // The deadlock was detected at a safepoint so the JavaThread
+        // that owns waitingToLockMonitor should be findable, but
+        // if it is not findable, then the previous currentThread is
+        // blocked permanently.
+        st->print("%s UNKNOWN_owner_addr=" PTR_FORMAT, owner_desc,
+                  (address)waitingToLockMonitor->owner());
+        continue;
+      }
     } else {
       st->print("  waiting for ownable synchronizer " INTPTR_FORMAT ", (a %s)",
                 (address)waitingToLockBlocker,
--- a/src/share/vm/utilities/numberSeq.cpp	Wed Feb 27 07:35:32 2013 -0500
+++ b/src/share/vm/utilities/numberSeq.cpp	Thu Feb 28 18:37:41 2013 -0500
@@ -245,7 +245,7 @@
 
 void NumberSeq::dump_on(outputStream* s) {
   AbsSeq::dump_on(s);
-  s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f");
+  s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f", _last, _maximum);
 }
 
 void TruncatedSeq::dump_on(outputStream* s) {