changeset 4611:be693a09e7f5

8006423: SA: NullPointerException in sun.jvm.hotspot.debugger.bsd.BsdThread.getContext(BsdThread.java:67) Summary: Do not rely on mach thread port names to identify threads from SA Reviewed-by: dholmes, minqi, rbackman
author sla
date Fri, 08 Feb 2013 12:48:24 +0100
parents 78538cd4794c
children 9dccaeb8e966 04f81958a8e2
files agent/src/os/bsd/MacosxDebuggerLocal.m agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java src/os/bsd/vm/osThread_bsd.hpp src/os/bsd/vm/os_bsd.cpp src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp
diffstat 8 files changed, 149 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/os/bsd/MacosxDebuggerLocal.m	Wed Apr 17 13:16:25 2013 +0200
+++ b/agent/src/os/bsd/MacosxDebuggerLocal.m	Fri Feb 08 12:48:24 2013 +0100
@@ -90,7 +90,8 @@
  * Method:    init0
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {
+JNIEXPORT void JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {
   symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");
   taskID = (*env)->GetFieldID(env, cls, "task", "J");
   CHECK_EXCEPTION;
@@ -101,7 +102,11 @@
  * Method:    lookupByName0
  * Signature: (Ljava/lang/String;Ljava/lang/String;)J
  */
-JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
+JNIEXPORT jlong JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(
+  JNIEnv *env, jobject this_obj, 
+  jstring objectName, jstring symbolName) 
+{
   jlong address = 0;
 
 JNF_COCOA_ENTER(env);
@@ -130,7 +135,11 @@
  * Method:    readBytesFromProcess0
  * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
  */
-JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) {
+JNIEXPORT jbyteArray JNICALL
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
+  JNIEnv *env, jobject this_obj, 
+  jlong addr, jlong numBytes) 
+{
   if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);
 
   // must allocate storage instead of using former parameter buf
@@ -202,12 +211,74 @@
   return array;
 }
 
+
 /*
- * Class:     sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal
+ * Lookup the thread_t that corresponds to the given thread_id.
+ * The thread_id should be the result from calling thread_info() with THREAD_IDENTIFIER_INFO
+ * and reading the m_ident_info.thread_id returned.
+ * The returned thread_t is the mach send right to the kernel port for the corresponding thread.
+ *
+ * We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self()
+ * in the VM, but that thread port is not valid for a remote debugger to access the thread.
+ */
+thread_t
+lookupThreadFromThreadId(task_t task, jlong thread_id) {
+  if (debug) {
+    printf("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id);
+  }
+  
+  thread_array_t thread_list = NULL;
+  mach_msg_type_number_t thread_list_count = 0;
+  thread_t result_thread = 0;
+  int i;
+  
+  // get the list of all the send rights
+  kern_return_t result = task_threads(task, &thread_list, &thread_list_count);
+  if (result != KERN_SUCCESS) {
+    if (debug) {
+      printf("task_threads returned 0x%x\n", result);
+    }
+    return 0;
+  }
+  
+  for(i = 0 ; i < thread_list_count; i++) {
+    thread_identifier_info_data_t m_ident_info;
+    mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
+
+    // get the THREAD_IDENTIFIER_INFO for the send right
+    result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
+    if (result != KERN_SUCCESS) {
+      if (debug) {
+        printf("thread_info returned 0x%x\n", result);
+      }
+      break;
+    }
+    
+    // if this is the one we're looking for, return the send right
+    if (thread_id == m_ident_info.thread_id)
+    {
+      result_thread = thread_list[i];
+      break;
+    }
+  }
+  
+  vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t));
+  vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count);
+  
+  return result_thread;
+}
+
+
+/*
+ * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
  * Method:    getThreadIntegerRegisterSet0
- * Signature: (I)[J
+ * Signature: (J)[J
  */
-JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(JNIEnv *env, jobject this_obj, jint lwp_id) {
+JNIEXPORT jlongArray JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(
+  JNIEnv *env, jobject this_obj, 
+  jlong thread_id) 
+{
   if (debug)
     printf("getThreadRegisterSet0 called\n");
 
@@ -219,8 +290,9 @@
   int i;
   jlongArray registerArray;
   jlong *primitiveArray;
+  task_t gTask = getTask(env, this_obj);
 
-  tid = lwp_id;
+  tid = lookupThreadFromThreadId(gTask, thread_id);
 
   result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);
 
@@ -321,19 +393,21 @@
 }
 
 /*
- * Class:     sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal
+ * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
  * Method:    translateTID0
  * Signature: (I)I
  */
 JNIEXPORT jint JNICALL
-Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(JNIEnv *env, jobject this_obj, jint tid) {
+Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(
+  JNIEnv *env, jobject this_obj, jint tid) 
+{
   if (debug)
     printf("translateTID0 called on tid = 0x%x\n", (int)tid);
 
   kern_return_t result;
   thread_t foreign_tid, usable_tid;
   mach_msg_type_name_t type;
-    
+  
   foreign_tid = tid;
     
   task_t gTask = getTask(env, this_obj);
@@ -421,7 +495,10 @@
  * Method:    attach0
  * Signature: (I)V
  */
-JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(JNIEnv *env, jobject this_obj, jint jpid) {
+JNIEXPORT void JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
+  JNIEnv *env, jobject this_obj, jint jpid) 
+{
 JNF_COCOA_ENTER(env);
   if (getenv("JAVA_SAPROC_DEBUG") != NULL)
     debug = JNI_TRUE;
@@ -469,7 +546,10 @@
  * Method:    detach0
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(JNIEnv *env, jobject this_obj) {
+JNIEXPORT void JNICALL 
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
+  JNIEnv *env, jobject this_obj) 
+{
 JNF_COCOA_ENTER(env);
   if (debug) printf("detach0 called\n");
 
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java	Wed Apr 17 13:16:25 2013 +0200
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java	Fri Feb 08 12:48:24 2013 +0100
@@ -48,7 +48,7 @@
   public BsdAddress readCompOopAddress(long address) throws DebuggerException;
   public BsdOopHandle readOopHandle(long address) throws DebuggerException;
   public BsdOopHandle readCompOopHandle(long address) throws DebuggerException;
-  public long[]       getThreadIntegerRegisterSet(int lwp_id) throws DebuggerException;
+  public long[]       getThreadIntegerRegisterSet(long unique_thread_id) throws DebuggerException;
   public long         getAddressValue(Address addr) throws DebuggerException;
   public Address      newAddress(long value) throws DebuggerException;
 
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Wed Apr 17 13:16:25 2013 +0200
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Fri Feb 08 12:48:24 2013 +0100
@@ -90,7 +90,7 @@
                                 throws DebuggerException;
     private native ClosestSymbol lookupByAddress0(long address)
                                 throws DebuggerException;
-    private native long[] getThreadIntegerRegisterSet0(int lwp_id)
+    private native long[] getThreadIntegerRegisterSet0(long unique_thread_id)
                                 throws DebuggerException;
     private native byte[] readBytesFromProcess0(long address, long numBytes)
                                 throws DebuggerException;
@@ -400,10 +400,15 @@
     //
 
     /** From the ThreadAccess interface via Debugger and JVMDebugger */
+    public ThreadProxy getThreadForIdentifierAddress(Address threadIdAddr, Address uniqueThreadIdAddr) {
+        return new BsdThread(this, threadIdAddr, uniqueThreadIdAddr);
+    }
+    @Override
     public ThreadProxy getThreadForIdentifierAddress(Address addr) {
-        return new BsdThread(this, addr);
+        throw new RuntimeException("unimplemented");
     }
 
+
     /** From the ThreadAccess interface via Debugger and JVMDebugger */
     public ThreadProxy getThreadForThreadId(long id) {
         return new BsdThread(this, id);
@@ -449,22 +454,22 @@
     // Thread context access
     //
 
-    public synchronized long[] getThreadIntegerRegisterSet(int lwp_id)
+    public synchronized long[] getThreadIntegerRegisterSet(long unique_thread_id)
                                             throws DebuggerException {
         requireAttach();
         if (isCore) {
-            return getThreadIntegerRegisterSet0(lwp_id);
+            return getThreadIntegerRegisterSet0(unique_thread_id);
         } else {
             class GetThreadIntegerRegisterSetTask implements WorkerThreadTask {
-                int lwp_id;
+                long unique_thread_id;
                 long[] result;
                 public void doit(BsdDebuggerLocal debugger) {
-                    result = debugger.getThreadIntegerRegisterSet0(lwp_id);
+                    result = debugger.getThreadIntegerRegisterSet0(unique_thread_id);
                 }
             }
 
             GetThreadIntegerRegisterSetTask task = new GetThreadIntegerRegisterSetTask();
-            task.lwp_id = lwp_id;
+            task.unique_thread_id = unique_thread_id;
             workerThread.execute(task);
             return task.result;
         }
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java	Wed Apr 17 13:16:25 2013 +0200
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java	Fri Feb 08 12:48:24 2013 +0100
@@ -28,21 +28,23 @@
 
 class BsdThread implements ThreadProxy {
     private BsdDebugger debugger;
-    private int           lwp_id;
+    private int         thread_id;
+    private long        unique_thread_id;
 
     /** The address argument must be the address of the _thread_id in the
         OSThread. It's value is result ::gettid() call. */
-    BsdThread(BsdDebugger debugger, Address addr) {
+    BsdThread(BsdDebugger debugger, Address threadIdAddr, Address uniqueThreadIdAddr) {
         this.debugger = debugger;
         // FIXME: size of data fetched here should be configurable.
         // However, making it so would produce a dependency on the "types"
         // package from the debugger package, which is not desired.
-        this.lwp_id = (int) addr.getCIntegerAt(0, 4, true);
+        this.thread_id = (int) threadIdAddr.getCIntegerAt(0, 4, true);
+        this.unique_thread_id = uniqueThreadIdAddr.getCIntegerAt(0, 8, true);
     }
 
     BsdThread(BsdDebugger debugger, long id) {
         this.debugger = debugger;
-        this.lwp_id = (int) id;
+        this.thread_id = (int) id;
     }
 
     public boolean equals(Object obj) {
@@ -50,19 +52,19 @@
             return false;
         }
 
-        return (((BsdThread) obj).lwp_id == lwp_id);
+        return (((BsdThread) obj).thread_id == thread_id);
     }
 
     public int hashCode() {
-        return lwp_id;
+        return thread_id;
     }
 
     public String toString() {
-        return Integer.toString(lwp_id);
+        return Integer.toString(thread_id);
     }
 
     public ThreadContext getContext() throws IllegalThreadStateException {
-        long[] data = debugger.getThreadIntegerRegisterSet(lwp_id);
+        long[] data = debugger.getThreadIntegerRegisterSet(unique_thread_id);
         ThreadContext context = BsdThreadContextFactory.createThreadContext(debugger);
         for (int i = 0; i < data.length; i++) {
             context.setRegister(i, data[i]);
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java	Wed Apr 17 13:16:25 2013 +0200
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java	Fri Feb 08 12:48:24 2013 +0100
@@ -28,6 +28,8 @@
 import java.util.*;
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.debugger.bsd.BsdDebugger;
+import sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.runtime.amd64.*;
 import sun.jvm.hotspot.runtime.x86.*;
@@ -38,8 +40,9 @@
   private static AddressField  lastJavaFPField;
   private static AddressField  osThreadField;
 
-  // Field from OSThread
+  // Fields from OSThread
   private static CIntegerField osThreadThreadIDField;
+  private static CIntegerField osThreadUniqueThreadIDField;
 
   // This is currently unneeded but is being kept in case we change
   // the currentFrameGuess algorithm
@@ -61,7 +64,8 @@
     lastJavaFPField         = anchorType.getAddressField("_last_Java_fp");
 
     Type osThreadType = db.lookupType("OSThread");
-    osThreadThreadIDField   = osThreadType.getCIntegerField("_thread_id");
+    osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id");
+    osThreadUniqueThreadIDField = osThreadType.getCIntegerField("_unique_thread_id");
   }
 
   public    Address getLastJavaFP(Address addr) {
@@ -125,8 +129,9 @@
     Address osThreadAddr = osThreadField.getValue(addr);
     // Get the address of the _thread_id from the OSThread
     Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset());
+    Address uniqueThreadIdAddr = osThreadAddr.addOffsetTo(osThreadUniqueThreadIDField.getOffset());
 
-    JVMDebugger debugger = VM.getVM().getDebugger();
-    return debugger.getThreadForIdentifierAddress(threadIdAddr);
+    BsdDebuggerLocal debugger = (BsdDebuggerLocal) VM.getVM().getDebugger();
+    return debugger.getThreadForIdentifierAddress(threadIdAddr, uniqueThreadIdAddr);
   }
 }
--- a/src/os/bsd/vm/osThread_bsd.hpp	Wed Apr 17 13:16:25 2013 +0200
+++ b/src/os/bsd/vm/osThread_bsd.hpp	Fri Feb 08 12:48:24 2013 +0100
@@ -55,6 +55,11 @@
   // (e.g. pthread_kill).
   pthread_t _pthread_id;
 
+  // This is the "thread_id" from struct thread_identifier_info. According to a
+  // comment in thread_info.h, this is a "system-wide unique 64-bit thread id".
+  // The value is used by SA to correlate threads.
+  uint64_t _unique_thread_id;
+
   sigset_t _caller_sigmask; // Caller's signal mask
 
  public:
@@ -83,6 +88,10 @@
     _pthread_id = tid;
   }
 
+  void set_unique_thread_id(uint64_t id) {
+    _unique_thread_id = id;
+  }
+
   // ***************************************************************
   // suspension support.
   // ***************************************************************
--- a/src/os/bsd/vm/os_bsd.cpp	Wed Apr 17 13:16:25 2013 +0200
+++ b/src/os/bsd/vm/os_bsd.cpp	Fri Feb 08 12:48:24 2013 +0100
@@ -970,6 +970,18 @@
 objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFunction = NULL;
 #endif
 
+#ifdef __APPLE__
+static uint64_t locate_unique_thread_id() {
+  // Additional thread_id used to correlate threads in SA
+  thread_identifier_info_data_t     m_ident_info;
+  mach_msg_type_number_t            count = THREAD_IDENTIFIER_INFO_COUNT;
+
+  thread_info(::mach_thread_self(), THREAD_IDENTIFIER_INFO,
+              (thread_info_t) &m_ident_info, &count);
+  return m_ident_info.thread_id;
+}
+#endif
+
 // Thread start routine for all newly created threads
 static void *java_start(Thread *thread) {
   // Try to randomize the cache line index of hot stack frames.
@@ -999,6 +1011,7 @@
 #ifdef __APPLE__
   // thread_id is mach thread on macos
   osthread->set_thread_id(::mach_thread_self());
+  osthread->set_unique_thread_id(locate_unique_thread_id());
 #else
   // thread_id is pthread_id on BSD
   osthread->set_thread_id(::pthread_self());
@@ -1195,6 +1208,7 @@
 #ifdef _ALLBSD_SOURCE
 #ifdef __APPLE__
   osthread->set_thread_id(::mach_thread_self());
+  osthread->set_unique_thread_id(locate_unique_thread_id());
 #else
   osthread->set_thread_id(::pthread_self());
 #endif
--- a/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp	Wed Apr 17 13:16:25 2013 +0200
+++ b/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp	Fri Feb 08 12:48:24 2013 +0100
@@ -35,7 +35,7 @@
   /* Threads (NOTE: incomplete) */                                                                                                   \
   /******************************/                                                                                                   \
   nonstatic_field(OSThread,                      _thread_id,                                      OSThread::thread_id_t)             \
-  nonstatic_field(OSThread,                      _pthread_id,                                     pthread_t)                         \
+  nonstatic_field(OSThread,                      _unique_thread_id,                               uint64_t)                          \
   /* This must be the last entry, and must be present */                                                                             \
   last_entry()
 
@@ -43,11 +43,10 @@
 #define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
                                                                           \
   /**********************/                                                \
-  /* Posix Thread IDs   */                                                \
+  /* Thread IDs         */                                                \
   /**********************/                                                \
                                                                           \
   declare_unsigned_integer_type(OSThread::thread_id_t)                    \
-  declare_unsigned_integer_type(pthread_t)                                \
                                                                           \
   /* This must be the last entry, and must be present */                  \
   last_entry()