agent/src/os/solaris/proc/saproc.cpp

Mon, 02 May 2011 14:53:49 -0700

author
dcubed
date
Mon, 02 May 2011 14:53:49 -0700
changeset 2838
405c634f4aaa
parent 1907
c18cbe5936b8
child 4037
da91efe96a93
permissions
-rw-r--r--

7028172: 3/4 SA needs to adapt to Solaris libproc change made in 6748307
Summary: Support build and runtime configs of old and new interfaces as appropriate.
Reviewed-by: acorn, never

     1 /*
     2  * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 #include "salibproc.h"
    26 #include "sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal.h"
    27 #ifndef SOLARIS_11_B159_OR_LATER
    28 #include <sys/utsname.h>
    29 #endif
    30 #include <thread_db.h>
    31 #include <strings.h>
    32 #include <limits.h>
    33 #include <demangle.h>
    34 #include <stdarg.h>
    35 #include <stdlib.h>
    36 #include <errno.h>
    38 #define CHECK_EXCEPTION_(value) if(env->ExceptionOccurred()) { return value; }
    39 #define CHECK_EXCEPTION if(env->ExceptionOccurred()) { return;}
    40 #define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throwNewDebuggerException(env, str); return value; }
    41 #define THROW_NEW_DEBUGGER_EXCEPTION(str) { throwNewDebuggerException(env, str); return;}
    43 #define SYMBOL_BUF_SIZE  256
    44 #define ERR_MSG_SIZE     (PATH_MAX + 256)
    46 // debug modes
    47 static int _libsaproc_debug = 0;
    48 #ifndef SOLARIS_11_B159_OR_LATER
    49 static bool _Pstack_iter_debug = false;
    51 static void dprintf_2(const char* format,...) {
    52   if (_Pstack_iter_debug) {
    53     va_list alist;
    55     va_start(alist, format);
    56     fputs("Pstack_iter DEBUG: ", stderr);
    57     vfprintf(stderr, format, alist);
    58     va_end(alist);
    59   }
    60 }
    61 #endif // !SOLARIS_11_B159_OR_LATER
    63 static void print_debug(const char* format,...) {
    64   if (_libsaproc_debug) {
    65     va_list alist;
    67     va_start(alist, format);
    68     fputs("libsaproc DEBUG: ", stderr);
    69     vfprintf(stderr, format, alist);
    70     va_end(alist);
    71   }
    72 }
    74 struct Debugger {
    75     JNIEnv* env;
    76     jobject this_obj;
    77 };
    79 struct DebuggerWithObject : Debugger {
    80     jobject obj;
    81 };
    83 struct DebuggerWith2Objects : DebuggerWithObject {
    84     jobject obj2;
    85 };
    87 /*
    88 * Portions of user thread level detail gathering code is from pstack source
    89 * code. See pstack.c in Solaris 2.8 user commands source code.
    90 */
    92 static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) {
    93   env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
    94 }
    96 // JNI ids for some fields, methods
    98 // libproc handler pointer
    99 static jfieldID p_ps_prochandle_ID = 0;
   101 // libthread.so dlopen handle, thread agent ptr and function pointers
   102 static jfieldID libthread_db_handle_ID   = 0;
   103 static jfieldID p_td_thragent_t_ID       = 0;
   104 static jfieldID p_td_init_ID             = 0;
   105 static jfieldID p_td_ta_new_ID           = 0;
   106 static jfieldID p_td_ta_delete_ID        = 0;
   107 static jfieldID p_td_ta_thr_iter_ID      = 0;
   108 static jfieldID p_td_thr_get_info_ID     = 0;
   109 static jfieldID p_td_ta_map_id2thr_ID    = 0;
   110 static jfieldID p_td_thr_getgregs_ID     = 0;
   112 // reg index fields
   113 static jfieldID pcRegIndex_ID            = 0;
   114 static jfieldID fpRegIndex_ID            = 0;
   116 // part of the class sharing workaround
   117 static jfieldID classes_jsa_fd_ID        = 0;
   118 static jfieldID p_file_map_header_ID     = 0;
   120 // method ids
   122 static jmethodID getThreadForThreadId_ID = 0;
   123 static jmethodID createSenderFrame_ID    = 0;
   124 static jmethodID createLoadObject_ID     = 0;
   125 static jmethodID createClosestSymbol_ID  = 0;
   126 static jmethodID listAdd_ID              = 0;
   128 /*
   129  * Functions we need from libthread_db
   130  */
   131 typedef td_err_e
   132         (*p_td_init_t)(void);
   133 typedef td_err_e
   134         (*p_td_ta_new_t)(void *, td_thragent_t **);
   135 typedef td_err_e
   136         (*p_td_ta_delete_t)(td_thragent_t *);
   137 typedef td_err_e
   138         (*p_td_ta_thr_iter_t)(const td_thragent_t *, td_thr_iter_f *, void *,
   139                 td_thr_state_e, int, sigset_t *, unsigned);
   140 typedef td_err_e
   141         (*p_td_thr_get_info_t)(const td_thrhandle_t *, td_thrinfo_t *);
   142 typedef td_err_e
   143         (*p_td_ta_map_id2thr_t)(const td_thragent_t *, thread_t,  td_thrhandle_t *);
   144 typedef td_err_e
   145         (*p_td_thr_getgregs_t)(const td_thrhandle_t *, prgregset_t);
   147 static void
   148 clear_libthread_db_ptrs(JNIEnv* env, jobject this_obj) {
   149   // release libthread_db agent, if we had created
   150   p_td_ta_delete_t p_td_ta_delete = 0;
   151   p_td_ta_delete = (p_td_ta_delete_t) env->GetLongField(this_obj, p_td_ta_delete_ID);
   153   td_thragent_t *p_td_thragent_t = 0;
   154   p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
   155   if (p_td_thragent_t != 0 && p_td_ta_delete != 0) {
   156      p_td_ta_delete(p_td_thragent_t);
   157   }
   159   // dlclose libthread_db.so
   160   void* libthread_db_handle = (void*) env->GetLongField(this_obj, libthread_db_handle_ID);
   161   if (libthread_db_handle != 0) {
   162     dlclose(libthread_db_handle);
   163   }
   165   env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)0);
   166   env->SetLongField(this_obj, p_td_init_ID, (jlong)0);
   167   env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)0);
   168   env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)0);
   169   env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)0);
   170   env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)0);
   171   env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)0);
   172   env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)0);
   173 }
   176 static void detach_internal(JNIEnv* env, jobject this_obj) {
   177   // clear libthread_db stuff
   178   clear_libthread_db_ptrs(env, this_obj);
   180   // release ptr to ps_prochandle
   181   jlong p_ps_prochandle;
   182   p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
   183   if (p_ps_prochandle != 0L) {
   184     Prelease((struct ps_prochandle*) p_ps_prochandle, PRELEASE_CLEAR);
   185   }
   187   // part of the class sharing workaround
   188   int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);
   189   if (classes_jsa_fd != -1) {
   190     close(classes_jsa_fd);
   191     struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID);
   192     if (pheader != NULL) {
   193       free(pheader);
   194     }
   195   }
   196 }
   198 // Is it okay to ignore libthread_db failure? Set env var to ignore
   199 // libthread_db failure. You can still debug, but will miss threads
   200 // related functionality.
   201 static bool sa_ignore_threaddb = (getenv("SA_IGNORE_THREADDB") != 0);
   203 #define HANDLE_THREADDB_FAILURE(msg)          \
   204   if (sa_ignore_threaddb) {                   \
   205      printf("libsaproc WARNING: %s\n", msg);  \
   206      return;                                  \
   207   } else {                                    \
   208      THROW_NEW_DEBUGGER_EXCEPTION(msg);       \
   209   }
   211 #define HANDLE_THREADDB_FAILURE_(msg, ret)    \
   212   if (sa_ignore_threaddb) {                   \
   213      printf("libsaproc WARNING: %s\n", msg);  \
   214      return ret;                              \
   215   } else {                                    \
   216      THROW_NEW_DEBUGGER_EXCEPTION_(msg, ret); \
   217   }
   219 static const char * alt_root = NULL;
   220 static int alt_root_len = -1;
   222 #define SA_ALTROOT "SA_ALTROOT"
   224 static void init_alt_root() {
   225   if (alt_root_len == -1) {
   226     alt_root = getenv(SA_ALTROOT);
   227     if (alt_root)
   228       alt_root_len = strlen(alt_root);
   229     else
   230       alt_root_len = 0;
   231   }
   232 }
   234 // This function is a complete substitute for the open system call
   235 // since it's also used to override open calls from libproc to
   236 // implement as a pathmap style facility for the SA.  If libproc
   237 // starts using other interfaces then this might have to extended to
   238 // cover other calls.
   239 extern "C" int libsaproc_open(const char * name, int oflag, ...) {
   240   if (oflag == O_RDONLY) {
   241     init_alt_root();
   243     if (_libsaproc_debug) {
   244       printf("libsaproc DEBUG: libsaproc_open %s\n", name);
   245     }
   247     if (alt_root_len > 0) {
   248       int fd = -1;
   249       char alt_path[PATH_MAX+1];
   251       strcpy(alt_path, alt_root);
   252       strcat(alt_path, name);
   253       fd = open(alt_path, O_RDONLY);
   254       if (fd >= 0) {
   255         if (_libsaproc_debug) {
   256           printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path);
   257         }
   258         return fd;
   259       }
   261       if (strrchr(name, '/')) {
   262         strcpy(alt_path, alt_root);
   263         strcat(alt_path, strrchr(name, '/'));
   264         fd = open(alt_path, O_RDONLY);
   265         if (fd >= 0) {
   266           if (_libsaproc_debug) {
   267             printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path);
   268           }
   269           return fd;
   270         }
   271       }
   272     }
   273   }
   275   {
   276     mode_t mode;
   277     va_list ap;
   278     va_start(ap, oflag);
   279     mode = va_arg(ap, mode_t);
   280     va_end(ap);
   282     return open(name, oflag, mode);
   283   }
   284 }
   287 static void * pathmap_dlopen(const char * name, int mode) {
   288   init_alt_root();
   290   if (_libsaproc_debug) {
   291     printf("libsaproc DEBUG: pathmap_dlopen %s\n", name);
   292   }
   294   void * handle = NULL;
   295   if (alt_root_len > 0) {
   296     char alt_path[PATH_MAX+1];
   297     strcpy(alt_path, alt_root);
   298     strcat(alt_path, name);
   299     handle = dlopen(alt_path, mode);
   300     if (_libsaproc_debug && handle) {
   301       printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);
   302     }
   304     if (handle == NULL && strrchr(name, '/')) {
   305       strcpy(alt_path, alt_root);
   306       strcat(alt_path, strrchr(name, '/'));
   307       handle = dlopen(alt_path, mode);
   308       if (_libsaproc_debug && handle) {
   309         printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);
   310       }
   311     }
   312   }
   313   if (handle == NULL) {
   314     handle = dlopen(name, mode);
   315   }
   316   if (_libsaproc_debug) {
   317     printf("libsaproc DEBUG: pathmap_dlopen %s return 0x%x\n", name, handle);
   318   }
   319   return handle;
   320 }
   322 // libproc and libthread_db callback functions
   324 extern "C" {
   326 static int
   327 init_libthread_db_ptrs(void *cd, const prmap_t *pmp, const char *object_name) {
   328   Debugger* dbg = (Debugger*) cd;
   329   JNIEnv* env = dbg->env;
   330   jobject this_obj = dbg->this_obj;
   331   struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
   333   char *s1 = 0, *s2 = 0;
   334   char libthread_db[PATH_MAX];
   336   if (strstr(object_name, "/libthread.so.") == NULL)
   337      return (0);
   339   /*
   340    * We found a libthread.
   341    * dlopen() the matching libthread_db and get the thread agent handle.
   342    */
   343   if (Pstatus(ph)->pr_dmodel == PR_MODEL_NATIVE) {
   344      (void) strcpy(libthread_db, object_name);
   345      s1 = (char*) strstr(object_name, ".so.");
   346      s2 = (char*) strstr(libthread_db, ".so.");
   347      (void) strcpy(s2, "_db");
   348      s2 += 3;
   349      (void) strcpy(s2, s1);
   350   } else {
   351 #ifdef _LP64
   352      /*
   353       * The victim process is 32-bit, we are 64-bit.
   354       * We have to find the 64-bit version of libthread_db
   355       * that matches the victim's 32-bit version of libthread.
   356       */
   357      (void) strcpy(libthread_db, object_name);
   358      s1 = (char*) strstr(object_name, "/libthread.so.");
   359      s2 = (char*) strstr(libthread_db, "/libthread.so.");
   360      (void) strcpy(s2, "/64");
   361      s2 += 3;
   362      (void) strcpy(s2, s1);
   363      s1 = (char*) strstr(s1, ".so.");
   364      s2 = (char*) strstr(s2, ".so.");
   365      (void) strcpy(s2, "_db");
   366      s2 += 3;
   367      (void) strcpy(s2, s1);
   368 #else
   369      return (0);
   370 #endif  /* _LP64 */
   371   }
   373   void* libthread_db_handle = 0;
   374   if ((libthread_db_handle = pathmap_dlopen(libthread_db, RTLD_LAZY|RTLD_LOCAL)) == NULL) {
   375      char errMsg[PATH_MAX + 256];
   376      sprintf(errMsg, "Can't load %s!", libthread_db);
   377      HANDLE_THREADDB_FAILURE_(errMsg, 0);
   378   }
   379   env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)(uintptr_t)libthread_db_handle);
   381   void* tmpPtr = 0;
   382   tmpPtr = dlsym(libthread_db_handle, "td_init");
   383   if (tmpPtr == 0) {
   384      HANDLE_THREADDB_FAILURE_("dlsym failed on td_init!", 0);
   385   }
   386   env->SetLongField(this_obj, p_td_init_ID, (jlong)(uintptr_t) tmpPtr);
   388   tmpPtr =dlsym(libthread_db_handle, "td_ta_new");
   389   if (tmpPtr == 0) {
   390      HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_new!", 0);
   391   }
   392   env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)(uintptr_t) tmpPtr);
   394   tmpPtr = dlsym(libthread_db_handle, "td_ta_delete");
   395   if (tmpPtr == 0) {
   396      HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_delete!", 0);
   397   }
   398   env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)(uintptr_t) tmpPtr);
   400   tmpPtr = dlsym(libthread_db_handle, "td_ta_thr_iter");
   401   if (tmpPtr == 0) {
   402      HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_thr_iter!", 0);
   403   }
   404   env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)(uintptr_t) tmpPtr);
   406   tmpPtr = dlsym(libthread_db_handle, "td_thr_get_info");
   407   if (tmpPtr == 0) {
   408      HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_get_info!", 0);
   409   }
   410   env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)(uintptr_t) tmpPtr);
   412   tmpPtr = dlsym(libthread_db_handle, "td_ta_map_id2thr");
   413   if (tmpPtr == 0) {
   414      HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_map_id2thr!", 0);
   415   }
   416   env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)(uintptr_t) tmpPtr);
   418   tmpPtr = dlsym(libthread_db_handle, "td_thr_getgregs");
   419   if (tmpPtr == 0) {
   420      HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_getgregs!", 0);
   421   }
   422   env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)(uintptr_t) tmpPtr);
   424   return 1;
   425 }
   427 static int
   428 fill_thread_list(const td_thrhandle_t *p_td_thragent_t, void* cd) {
   429   DebuggerWithObject* dbgo = (DebuggerWithObject*) cd;
   430   JNIEnv* env = dbgo->env;
   431   jobject this_obj = dbgo->this_obj;
   432   jobject list = dbgo->obj;
   434   td_thrinfo_t thrinfo;
   435   p_td_thr_get_info_t p_td_thr_get_info = (p_td_thr_get_info_t) env->GetLongField(this_obj, p_td_thr_get_info_ID);
   437   if (p_td_thr_get_info(p_td_thragent_t, &thrinfo) != TD_OK)
   438     return (0);
   440   jobject threadProxy = env->CallObjectMethod(this_obj, getThreadForThreadId_ID, (jlong)(uintptr_t) thrinfo.ti_tid);
   441   CHECK_EXCEPTION_(1);
   442   env->CallBooleanMethod(list, listAdd_ID, threadProxy);
   443   CHECK_EXCEPTION_(1);
   444   return 0;
   445 }
   447 static int
   448 fill_load_object_list(void *cd, const prmap_t* pmp, const char* obj_name) {
   450   if (obj_name) {
   451      DebuggerWithObject* dbgo = (DebuggerWithObject*) cd;
   452      JNIEnv* env = dbgo->env;
   453      jobject this_obj = dbgo->this_obj;
   454      jobject list = dbgo->obj;
   456      jstring objectName = env->NewStringUTF(obj_name);
   457      CHECK_EXCEPTION_(1);
   459      jlong mapSize = (jlong) pmp->pr_size;
   460      jobject sharedObject = env->CallObjectMethod(this_obj, createLoadObject_ID,
   461                                   objectName, mapSize, (jlong)(uintptr_t)pmp->pr_vaddr);
   462      CHECK_EXCEPTION_(1);
   463      env->CallBooleanMethod(list, listAdd_ID, sharedObject);
   464      CHECK_EXCEPTION_(1);
   465   }
   467   return 0;
   468 }
   470 // Pstack_iter() proc_stack_f callback prior to Nevada-B159
   471 static int
   472 fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc, const long *argv) {
   473   DebuggerWith2Objects* dbgo2 = (DebuggerWith2Objects*) cd;
   474   JNIEnv* env = dbgo2->env;
   475   jobject this_obj = dbgo2->this_obj;
   476   jobject curFrame = dbgo2->obj2;
   478   jint pcRegIndex = env->GetIntField(this_obj, pcRegIndex_ID);
   479   jint fpRegIndex = env->GetIntField(this_obj, fpRegIndex_ID);
   481   jlong pc = (jlong) (uintptr_t) regs[pcRegIndex];
   482   jlong fp = (jlong) (uintptr_t) regs[fpRegIndex];
   484   dbgo2->obj2 = env->CallObjectMethod(this_obj, createSenderFrame_ID,
   485                                     curFrame, pc, fp);
   486   CHECK_EXCEPTION_(1);
   487   if (dbgo2->obj == 0) {
   488      dbgo2->obj = dbgo2->obj2;
   489   }
   490   return 0;
   491 }
   493 // Pstack_iter() proc_stack_f callback in Nevada-B159 or later
   494 /*ARGSUSED*/
   495 static int
   496 wrapper_fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc,
   497                          const long *argv, int frame_flags, int sig) {
   498   return(fill_cframe_list(cd, regs, argc, argv));
   499 }
   501 // part of the class sharing workaround
   503 // FIXME: !!HACK ALERT!!
   505 // The format of sharing achive file header is needed to read shared heap
   506 // file mappings. For now, I am hard coding portion of FileMapHeader here.
   507 // Refer to filemap.hpp.
   509 // FileMapHeader describes the shared space data in the file to be
   510 // mapped.  This structure gets written to a file.  It is not a class, so
   511 // that the compilers don't add any compiler-private data to it.
   513 // Refer to CompactingPermGenGen::n_regions in compactingPermGenGen.hpp
   514 const int NUM_SHARED_MAPS = 4;
   516 // Refer to FileMapInfo::_current_version in filemap.hpp
   517 const int CURRENT_ARCHIVE_VERSION = 1;
   519 struct FileMapHeader {
   520  int   _magic;              // identify file type.
   521  int   _version;            // (from enum, above.)
   522  size_t _alignment;         // how shared archive should be aligned
   525  struct space_info {
   526    int    _file_offset;     // sizeof(this) rounded to vm page size
   527    char*  _base;            // copy-on-write base address
   528    size_t _capacity;        // for validity checking
   529    size_t _used;            // for setting space top on read
   531    bool   _read_only;       // read only space?
   532    bool   _allow_exec;      // executable code in space?
   534  } _space[NUM_SHARED_MAPS]; // was _space[CompactingPermGenGen::n_regions];
   536  // Ignore the rest of the FileMapHeader. We don't need those fields here.
   537 };
   539 static bool
   540 read_jboolean(struct ps_prochandle* ph, psaddr_t addr, jboolean* pvalue) {
   541   jboolean i;
   542   if (ps_pread(ph, addr, &i, sizeof(i)) == PS_OK) {
   543     *pvalue = i;
   544     return true;
   545   } else {
   546     return false;
   547   }
   548 }
   550 static bool
   551 read_pointer(struct ps_prochandle* ph, psaddr_t addr, uintptr_t* pvalue) {
   552   uintptr_t uip;
   553   if (ps_pread(ph, addr, &uip, sizeof(uip)) == PS_OK) {
   554     *pvalue = uip;
   555     return true;
   556   } else {
   557     return false;
   558   }
   559 }
   561 static bool
   562 read_string(struct ps_prochandle* ph, psaddr_t addr, char* buf, size_t size) {
   563   char ch = ' ';
   564   size_t i = 0;
   566   while (ch != '\0') {
   567     if (ps_pread(ph, addr, &ch, sizeof(ch)) != PS_OK)
   568       return false;
   570     if (i < size - 1) {
   571       buf[i] = ch;
   572     } else { // smaller buffer
   573       return false;
   574     }
   576     i++; addr++;
   577   }
   579   buf[i] = '\0';
   580   return true;
   581 }
   583 #define USE_SHARED_SPACES_SYM   "UseSharedSpaces"
   584 // mangled symbol name for Arguments::SharedArchivePath
   585 #define SHARED_ARCHIVE_PATH_SYM "__1cJArgumentsRSharedArchivePath_"
   587 static int
   588 init_classsharing_workaround(void *cd, const prmap_t* pmap, const char* obj_name) {
   589   Debugger* dbg = (Debugger*) cd;
   590   JNIEnv*   env = dbg->env;
   591   jobject this_obj = dbg->this_obj;
   592   const char* jvm_name = 0;
   593   if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL ||
   594       (jvm_name = strstr(obj_name, "libjvm_g.so")) != NULL) {
   595     jvm_name = obj_name;
   596   } else {
   597     return 0;
   598   }
   600   struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
   602   // initialize classes[_g].jsa file descriptor field.
   603   dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, -1);
   605   // check whether class sharing is on by reading variable "UseSharedSpaces"
   606   psaddr_t useSharedSpacesAddr = 0;
   607   ps_pglobal_lookup(ph, jvm_name, USE_SHARED_SPACES_SYM, &useSharedSpacesAddr);
   608   if (useSharedSpacesAddr == 0) {
   609     THROW_NEW_DEBUGGER_EXCEPTION_("can't find 'UseSharedSpaces' flag\n", 1);
   610   }
   612   // read the value of the flag "UseSharedSpaces"
   613   // Since hotspot types are not available to build this library. So
   614   // equivalent type "jboolean" is used to read the value of "UseSharedSpaces"
   615   // which is same as hotspot type "bool".
   616   jboolean value = 0;
   617   if (read_jboolean(ph, useSharedSpacesAddr, &value) != true) {
   618     THROW_NEW_DEBUGGER_EXCEPTION_("can't read 'UseSharedSpaces' flag", 1);
   619   } else if ((int)value == 0) {
   620     print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
   621     return 1;
   622   }
   624   char classes_jsa[PATH_MAX];
   625   psaddr_t sharedArchivePathAddrAddr = 0;
   626   ps_pglobal_lookup(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM, &sharedArchivePathAddrAddr);
   627   if (sharedArchivePathAddrAddr == 0) {
   628     print_debug("can't find symbol 'Arguments::SharedArchivePath'\n");
   629     THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
   630   }
   632   uintptr_t sharedArchivePathAddr = 0;
   633   if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
   634     print_debug("can't find read pointer 'Arguments::SharedArchivePath'\n");
   635     THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
   636   }
   638   if (read_string(ph, (psaddr_t)sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
   639     print_debug("can't find read 'Arguments::SharedArchivePath' value\n");
   640     THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
   641   }
   643   print_debug("looking for %s\n", classes_jsa);
   645   // open the classes[_g].jsa
   646   int fd = libsaproc_open(classes_jsa, O_RDONLY);
   647   if (fd < 0) {
   648     char errMsg[ERR_MSG_SIZE];
   649     sprintf(errMsg, "can't open shared archive file %s", classes_jsa);
   650     THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
   651   } else {
   652     print_debug("opened shared archive file %s\n", classes_jsa);
   653   }
   655   // parse classes[_g].jsa
   656   struct FileMapHeader* pheader = (struct FileMapHeader*) malloc(sizeof(struct FileMapHeader));
   657   if (pheader == NULL) {
   658     close(fd);
   659     THROW_NEW_DEBUGGER_EXCEPTION_("can't allocate memory for shared file map header", 1);
   660   }
   662   memset(pheader, 0, sizeof(struct FileMapHeader));
   663   // read FileMapHeader
   664   size_t n = read(fd, pheader, sizeof(struct FileMapHeader));
   665   if (n != sizeof(struct FileMapHeader)) {
   666     free(pheader);
   667     close(fd);
   668     char errMsg[ERR_MSG_SIZE];
   669     sprintf(errMsg, "unable to read shared archive file map header from %s", classes_jsa);
   670     THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
   671   }
   673   // check file magic
   674   if (pheader->_magic != 0xf00baba2) {
   675     free(pheader);
   676     close(fd);
   677     char errMsg[ERR_MSG_SIZE];
   678     sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0xf00baba2",
   679                    classes_jsa, pheader->_magic);
   680     THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
   681   }
   683   // check version
   684   if (pheader->_version != CURRENT_ARCHIVE_VERSION) {
   685     free(pheader);
   686     close(fd);
   687     char errMsg[ERR_MSG_SIZE];
   688     sprintf(errMsg, "%s has wrong shared archive version %d, expecting %d",
   689                    classes_jsa, pheader->_version, CURRENT_ARCHIVE_VERSION);
   690     THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
   691   }
   693   if (_libsaproc_debug) {
   694     for (int m = 0; m < NUM_SHARED_MAPS; m++) {
   695        print_debug("shared file offset %d mapped at 0x%lx, size = %ld, read only? = %d\n",
   696           pheader->_space[m]._file_offset, pheader->_space[m]._base,
   697           pheader->_space[m]._used, pheader->_space[m]._read_only);
   698     }
   699   }
   701   // FIXME: For now, omitting other checks such as VM version etc.
   703   // store class archive file fd and map header in debugger object fields
   704   dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, fd);
   705   dbg->env->SetLongField(this_obj, p_file_map_header_ID, (jlong)(uintptr_t) pheader);
   706   return 1;
   707 }
   709 } // extern "C"
   711 // error messages for proc_arg_grab failure codes. The messages are
   712 // modified versions of comments against corresponding #defines in
   713 // libproc.h.
   714 static const char* proc_arg_grab_errmsgs[] = {
   715                       "",
   716  /* G_NOPROC */       "No such process",
   717  /* G_NOCORE */       "No such core file",
   718  /* G_NOPROCORCORE */ "No such process or core",
   719  /* G_NOEXEC */       "Cannot locate executable file",
   720  /* G_ZOMB   */       "Zombie processs",
   721  /* G_PERM   */       "No permission to attach",
   722  /* G_BUSY   */       "Another process has already attached",
   723  /* G_SYS    */       "System process - can not attach",
   724  /* G_SELF   */       "Process is self - can't debug myself!",
   725  /* G_INTR   */       "Interrupt received while grabbing",
   726  /* G_LP64   */       "debuggee is 64 bit, use java -d64 for debugger",
   727  /* G_FORMAT */       "File is not an ELF format core file - corrupted core?",
   728  /* G_ELF    */       "Libelf error while parsing an ELF file",
   729  /* G_NOTE   */       "Required PT_NOTE Phdr not present - corrupted core?",
   730 };
   732 static void attach_internal(JNIEnv* env, jobject this_obj, jstring cmdLine, jboolean isProcess) {
   733   jboolean isCopy;
   734   int gcode;
   735   const char* cmdLine_cstr = env->GetStringUTFChars(cmdLine, &isCopy);
   736   CHECK_EXCEPTION;
   738   // some older versions of libproc.so crash when trying to attach 32 bit
   739   // debugger to 64 bit core file. check and throw error.
   740 #ifndef _LP64
   741   atoi(cmdLine_cstr);
   742   if (errno) {
   743      // core file
   744      int core_fd;
   745      if ((core_fd = open64(cmdLine_cstr, O_RDONLY)) >= 0) {
   746         Elf32_Ehdr e32;
   747         if (pread64(core_fd, &e32, sizeof (e32), 0) == sizeof (e32) &&
   748             memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0 &&
   749             e32.e_type == ET_CORE && e32.e_ident[EI_CLASS] == ELFCLASS64) {
   750               close(core_fd);
   751               THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use java -d64 for debugger");
   752         }
   753         close(core_fd);
   754      }
   755      // all other conditions are handled by libproc.so.
   756   }
   757 #endif
   759   // connect to process/core
   760   struct ps_prochandle* ph = proc_arg_grab(cmdLine_cstr, (isProcess? PR_ARG_PIDS : PR_ARG_CORES), PGRAB_FORCE, &gcode);
   761   env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr);
   762   if (! ph) {
   763      if (gcode > 0 && gcode < sizeof(proc_arg_grab_errmsgs)/sizeof(const char*)) {
   764         char errMsg[ERR_MSG_SIZE];
   765         sprintf(errMsg, "Attach failed : %s", proc_arg_grab_errmsgs[gcode]);
   766         THROW_NEW_DEBUGGER_EXCEPTION(errMsg);
   767     } else {
   768         if (_libsaproc_debug && gcode == G_STRANGE) {
   769            perror("libsaproc DEBUG: ");
   770         }
   771         if (isProcess) {
   772            THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to process!");
   773         } else {
   774            THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to core file!");
   775         }
   776      }
   777   }
   779   // even though libproc.so supports 64 bit debugger and 32 bit debuggee, we don't
   780   // support such cross-bit-debugging. check for that combination and throw error.
   781 #ifdef _LP64
   782   int data_model;
   783   if (ps_pdmodel(ph, &data_model) != PS_OK) {
   784      Prelease(ph, PRELEASE_CLEAR);
   785      THROW_NEW_DEBUGGER_EXCEPTION("can't determine debuggee data model (ILP32? or LP64?)");
   786   }
   787   if (data_model == PR_MODEL_ILP32) {
   788      Prelease(ph, PRELEASE_CLEAR);
   789      THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger");
   790   }
   791 #endif
   793   env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(uintptr_t)ph);
   795   Debugger dbg;
   796   dbg.env = env;
   797   dbg.this_obj = this_obj;
   798   jthrowable exception = 0;
   799   if (! isProcess) {
   800     /*
   801      * With class sharing, shared perm. gen heap is allocated in with MAP_SHARED|PROT_READ.
   802      * These pages are mapped from the file "classes[_g].jsa". MAP_SHARED pages are not dumped
   803      * in Solaris core.To read shared heap pages, we have to read classes[_g].jsa file.
   804      */
   805     Pobject_iter(ph, init_classsharing_workaround, &dbg);
   806     exception = env->ExceptionOccurred();
   807     if (exception) {
   808       env->ExceptionClear();
   809       detach_internal(env, this_obj);
   810       env->Throw(exception);
   811       return;
   812     }
   813   }
   815   /*
   816    * Iterate over the process mappings looking
   817    * for libthread and then dlopen the appropriate
   818    * libthread_db and get function pointers.
   819    */
   820   Pobject_iter(ph, init_libthread_db_ptrs, &dbg);
   821   exception = env->ExceptionOccurred();
   822   if (exception) {
   823     env->ExceptionClear();
   824     if (!sa_ignore_threaddb) {
   825       detach_internal(env, this_obj);
   826       env->Throw(exception);
   827     }
   828     return;
   829   }
   831   // init libthread_db and create thread_db agent
   832   p_td_init_t p_td_init = (p_td_init_t) env->GetLongField(this_obj, p_td_init_ID);
   833   if (p_td_init == 0) {
   834     if (!sa_ignore_threaddb) {
   835       detach_internal(env, this_obj);
   836     }
   837     HANDLE_THREADDB_FAILURE("Did not find libthread in target process/core!");
   838   }
   840   if (p_td_init() != TD_OK) {
   841     if (!sa_ignore_threaddb) {
   842       detach_internal(env, this_obj);
   843     }
   844     HANDLE_THREADDB_FAILURE("Can't initialize thread_db!");
   845   }
   847   p_td_ta_new_t p_td_ta_new = (p_td_ta_new_t) env->GetLongField(this_obj, p_td_ta_new_ID);
   849   td_thragent_t *p_td_thragent_t = 0;
   850   if (p_td_ta_new(ph, &p_td_thragent_t) != TD_OK) {
   851     if (!sa_ignore_threaddb) {
   852       detach_internal(env, this_obj);
   853     }
   854     HANDLE_THREADDB_FAILURE("Can't create thread_db agent!");
   855   }
   856   env->SetLongField(this_obj, p_td_thragent_t_ID, (jlong)(uintptr_t) p_td_thragent_t);
   858 }
   860 /*
   861  * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   862  * Method:    attach0
   863  * Signature: (Ljava/lang/String;)V
   864  * Description: process detach
   865  */
   866 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2
   867   (JNIEnv *env, jobject this_obj, jstring pid) {
   868   attach_internal(env, this_obj, pid, JNI_TRUE);
   869 }
   871 /*
   872  * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   873  * Method:    attach0
   874  * Signature: (Ljava/lang/String;Ljava/lang/String;)V
   875  * Description: core file detach
   876  */
   877 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
   878   (JNIEnv *env, jobject this_obj, jstring executable, jstring corefile) {
   879   // ignore executable file name, libproc.so can detect a.out name anyway.
   880   attach_internal(env, this_obj, corefile, JNI_FALSE);
   881 }
   884 /*
   885  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   886  * Method:      detach0
   887  * Signature:   ()V
   888  * Description: process/core file detach
   889  */
   890 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_detach0
   891   (JNIEnv *env, jobject this_obj) {
   892   detach_internal(env, this_obj);
   893 }
   895 /*
   896  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   897  * Method:      getRemoteProcessAddressSize0
   898  * Signature:   ()I
   899  * Description: get process/core address size
   900  */
   901 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getRemoteProcessAddressSize0
   902   (JNIEnv *env, jobject this_obj) {
   903   jlong p_ps_prochandle;
   904   p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
   905   int data_model = PR_MODEL_ILP32;
   906   ps_pdmodel((struct ps_prochandle*) p_ps_prochandle, &data_model);
   907   print_debug("debuggee is %d bit\n", data_model == PR_MODEL_ILP32? 32 : 64);
   908   return (jint) data_model == PR_MODEL_ILP32? 32 : 64;
   909 }
   911 /*
   912  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   913  * Method:      getPageSize0
   914  * Signature:   ()I
   915  * Description: get process/core page size
   916  */
   917 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getPageSize0
   918   (JNIEnv *env, jobject this_obj) {
   920 /*
   921   We are not yet attached to a java process or core file. getPageSize is called from
   922   the constructor of ProcDebuggerLocal. The following won't work!
   924     jlong p_ps_prochandle;
   925     p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
   926     CHECK_EXCEPTION_(-1);
   927     struct ps_prochandle* prochandle = (struct ps_prochandle*) p_ps_prochandle;
   928     return (Pstate(prochandle) == PS_DEAD) ? Pgetauxval(prochandle, AT_PAGESZ)
   929                                            : getpagesize();
   931   So even though core may have been generated with a different page size settings, for now
   932   call getpagesize.
   933 */
   935   return getpagesize();
   936 }
   938 /*
   939  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   940  * Method:      getThreadIntegerRegisterSet0
   941  * Signature:   (J)[J
   942  * Description: get gregset for a given thread specified by thread id
   943  */
   944 JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getThreadIntegerRegisterSet0
   945   (JNIEnv *env, jobject this_obj, jlong tid) {
   946   // map the thread id to thread handle
   947   p_td_ta_map_id2thr_t p_td_ta_map_id2thr = (p_td_ta_map_id2thr_t) env->GetLongField(this_obj, p_td_ta_map_id2thr_ID);
   949   td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
   950   if (p_td_thragent_t == 0) {
   951      return 0;
   952   }
   954   td_thrhandle_t thr_handle;
   955   if (p_td_ta_map_id2thr(p_td_thragent_t, (thread_t) tid, &thr_handle) != TD_OK) {
   956      THROW_NEW_DEBUGGER_EXCEPTION_("can't map thread id to thread handle!", 0);
   957   }
   959   p_td_thr_getgregs_t p_td_thr_getgregs = (p_td_thr_getgregs_t) env->GetLongField(this_obj, p_td_thr_getgregs_ID);
   960   prgregset_t gregs;
   961   p_td_thr_getgregs(&thr_handle, gregs);
   963   jlongArray res = env->NewLongArray(NPRGREG);
   964   CHECK_EXCEPTION_(0);
   965   jboolean isCopy;
   966   jlong* ptr = env->GetLongArrayElements(res, &isCopy);
   967   for (int i = 0; i < NPRGREG; i++) {
   968     ptr[i] = (jlong) (uintptr_t) gregs[i];
   969   }
   970   env->ReleaseLongArrayElements(res, ptr, JNI_COMMIT);
   971   return res;
   972 }
   974 /*
   975  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   976  * Method:      fillThreadList0
   977  * Signature:   (Ljava/util/List;)V
   978  * Description: fills thread list of the debuggee process/core
   979  */
   980 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillThreadList0
   981   (JNIEnv *env, jobject this_obj, jobject list) {
   983   td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
   984   if (p_td_thragent_t == 0) {
   985      return;
   986   }
   988   p_td_ta_thr_iter_t p_td_ta_thr_iter = (p_td_ta_thr_iter_t) env->GetLongField(this_obj, p_td_ta_thr_iter_ID);
   990   DebuggerWithObject dbgo;
   991   dbgo.env = env;
   992   dbgo.this_obj = this_obj;
   993   dbgo.obj = list;
   995   p_td_ta_thr_iter(p_td_thragent_t, fill_thread_list, &dbgo,
   996                    TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
   997 }
   999 #ifndef SOLARIS_11_B159_OR_LATER
  1000 // building on Nevada-B158 or earlier so more hoops to jump through
  1001 static bool has_newer_Pstack_iter = false;  // older version by default
  1002 #endif
  1004 /*
  1005  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1006  * Method:      fillCFrameList0
  1007  * Signature:   ([J)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;
  1008  * Description: fills CFrame list for a given thread
  1009  */
  1010 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillCFrameList0
  1011   (JNIEnv *env, jobject this_obj, jlongArray regsArray) {
  1012   jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1014   DebuggerWith2Objects dbgo2;
  1015   dbgo2.env  = env;
  1016   dbgo2.this_obj = this_obj;
  1017   dbgo2.obj  = NULL;
  1018   dbgo2.obj2 = NULL;
  1020   jboolean isCopy;
  1021   jlong* ptr = env->GetLongArrayElements(regsArray, &isCopy);
  1022   CHECK_EXCEPTION_(0);
  1024   prgregset_t gregs;
  1025   for (int i = 0; i < NPRGREG; i++) {
  1026      gregs[i] = (uintptr_t) ptr[i];
  1029   env->ReleaseLongArrayElements(regsArray, ptr, JNI_ABORT);
  1030   CHECK_EXCEPTION_(0);
  1032 #ifdef SOLARIS_11_B159_OR_LATER
  1033   // building on Nevada-B159 or later so use the new callback
  1034   Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,
  1035               wrapper_fill_cframe_list, &dbgo2);
  1036 #else
  1037   // building on Nevada-B158 or earlier so figure out which callback to use
  1039   if (has_newer_Pstack_iter) {
  1040     // Since we're building on Nevada-B158 or earlier, we have to
  1041     // cast wrapper_fill_cframe_list to make the compiler happy.
  1042     Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,
  1043                 (proc_stack_f *)wrapper_fill_cframe_list, &dbgo2);
  1044   } else {
  1045     Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,
  1046                 fill_cframe_list, &dbgo2);
  1048 #endif // SOLARIS_11_B159_OR_LATER
  1049   return dbgo2.obj;
  1052 /*
  1053  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1054  * Method:      fillLoadObjectList0
  1055  * Signature:   (Ljava/util/List;)V
  1056  * Description: fills shared objects of the debuggee process/core
  1057  */
  1058 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillLoadObjectList0
  1059   (JNIEnv *env, jobject this_obj, jobject list) {
  1060   DebuggerWithObject dbgo;
  1061   dbgo.env = env;
  1062   dbgo.this_obj = this_obj;
  1063   dbgo.obj = list;
  1065   jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1066   Pobject_iter((struct ps_prochandle*) p_ps_prochandle, fill_load_object_list, &dbgo);
  1069 /*
  1070  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1071  * Method:      readBytesFromProcess0
  1072  * Signature:   (JJ)[B
  1073  * Description: read bytes from debuggee process/core
  1074  */
  1075 JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_readBytesFromProcess0
  1076   (JNIEnv *env, jobject this_obj, jlong address, jlong numBytes) {
  1078   jbyteArray array = env->NewByteArray(numBytes);
  1079   CHECK_EXCEPTION_(0);
  1080   jboolean isCopy;
  1081   jbyte* bufPtr = env->GetByteArrayElements(array, &isCopy);
  1082   CHECK_EXCEPTION_(0);
  1084   jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1085   ps_err_e ret = ps_pread((struct ps_prochandle*) p_ps_prochandle,
  1086                        (psaddr_t)address, bufPtr, (size_t)numBytes);
  1088   if (ret != PS_OK) {
  1089     // part of the class sharing workaround. try shared heap area
  1090     int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);
  1091     if (classes_jsa_fd != -1 && address != (jlong)0) {
  1092       print_debug("read failed at 0x%lx, attempting shared heap area\n", (long) address);
  1094       struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID);
  1095       // walk through the shared mappings -- we just have 4 of them.
  1096       // so, linear walking is okay.
  1097       for (int m = 0; m < NUM_SHARED_MAPS; m++) {
  1099         // We can skip the non-read-only maps. These are mapped as MAP_PRIVATE
  1100         // and hence will be read by libproc. Besides, the file copy may be
  1101         // stale because the process might have modified those pages.
  1102         if (pheader->_space[m]._read_only) {
  1103           jlong baseAddress = (jlong) (uintptr_t) pheader->_space[m]._base;
  1104           size_t usedSize = pheader->_space[m]._used;
  1105           if (address >= baseAddress && address < (baseAddress + usedSize)) {
  1106             // the given address falls in this shared heap area
  1107             print_debug("found shared map at 0x%lx\n", (long) baseAddress);
  1110             // If more data is asked than actually mapped from file, we need to zero fill
  1111             // till the end-of-page boundary. But, java array new does that for us. we just
  1112             // need to read as much as data available.
  1114 #define MIN2(x, y) (((x) < (y))? (x) : (y))
  1116             jlong diff = address - baseAddress;
  1117             jlong bytesToRead = MIN2(numBytes, usedSize - diff);
  1118             off_t offset = pheader->_space[m]._file_offset  + off_t(diff);
  1119             ssize_t bytesRead = pread(classes_jsa_fd, bufPtr, bytesToRead, offset);
  1120             if (bytesRead != bytesToRead) {
  1121               env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);
  1122               print_debug("shared map read failed\n");
  1123               return jbyteArray(0);
  1124             } else {
  1125               print_debug("shared map read succeeded\n");
  1126               env->ReleaseByteArrayElements(array, bufPtr, 0);
  1127               return array;
  1129           } // is in current map
  1130         } // is read only map
  1131       } // for shared maps
  1132     } // classes_jsa_fd != -1
  1133     env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);
  1134     return jbyteArray(0);
  1135   } else {
  1136     env->ReleaseByteArrayElements(array, bufPtr, 0);
  1137     return array;
  1141 /*
  1142  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1143  * Method:      writeBytesToProcess0
  1144  * Signature:   (JJ[B)V
  1145  * Description: write bytes into debugger process
  1146  */
  1147 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_writeBytesToProcess0
  1148   (JNIEnv *env, jobject this_obj, jlong address, jlong numBytes, jbyteArray data) {
  1149   jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1150   jboolean isCopy;
  1151   jbyte* ptr = env->GetByteArrayElements(data, &isCopy);
  1152   CHECK_EXCEPTION;
  1154   if (ps_pwrite((struct ps_prochandle*) p_ps_prochandle, address, ptr, numBytes) != PS_OK) {
  1155      env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
  1156      THROW_NEW_DEBUGGER_EXCEPTION("Process write failed!");
  1159   env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
  1162 /*
  1163  * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1164  * Method:    suspend0
  1165  * Signature: ()V
  1166  */
  1167 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_suspend0
  1168   (JNIEnv *env, jobject this_obj) {
  1169   jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1170   // for now don't check return value. revisit this again.
  1171   Pstop((struct ps_prochandle*) p_ps_prochandle, 1000);
  1174 /*
  1175  * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1176  * Method:    resume0
  1177  * Signature: ()V
  1178  */
  1179 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_resume0
  1180   (JNIEnv *env, jobject this_obj) {
  1181   jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1182   // for now don't check return value. revisit this again.
  1183   Psetrun((struct ps_prochandle*) p_ps_prochandle, 0, PRCFAULT|PRSTOP);
  1186 /*
  1187   * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1188   * Method:      lookupByName0
  1189   * Signature:   (Ljava/lang/String;Ljava/lang/String;)J
  1190   * Description: symbol lookup by name
  1191 */
  1192 JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByName0
  1193    (JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
  1194    jlong p_ps_prochandle;
  1195    p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1197    jboolean isCopy;
  1198    const char* objectName_cstr = NULL;
  1199    if (objectName != NULL) {
  1200      objectName_cstr = env->GetStringUTFChars(objectName, &isCopy);
  1201      CHECK_EXCEPTION_(0);
  1202    } else {
  1203      objectName_cstr = PR_OBJ_EVERY;
  1206    const char* symbolName_cstr = env->GetStringUTFChars(symbolName, &isCopy);
  1207    CHECK_EXCEPTION_(0);
  1209    psaddr_t symbol_addr = (psaddr_t) 0;
  1210    ps_pglobal_lookup((struct ps_prochandle*) p_ps_prochandle,  objectName_cstr,
  1211                     symbolName_cstr, &symbol_addr);
  1213    if (symbol_addr == 0) {
  1214       print_debug("lookup for %s in %s failed\n", symbolName_cstr, objectName_cstr);
  1217    if (objectName_cstr != PR_OBJ_EVERY) {
  1218      env->ReleaseStringUTFChars(objectName, objectName_cstr);
  1220    env->ReleaseStringUTFChars(symbolName, symbolName_cstr);
  1221    return (jlong) (uintptr_t) symbol_addr;
  1224 /*
  1225  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1226  * Method:      lookupByAddress0
  1227  * Signature:   (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
  1228  * Description: lookup symbol name for a given address
  1229  */
  1230 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByAddress0
  1231    (JNIEnv *env, jobject this_obj, jlong address) {
  1232    jlong p_ps_prochandle;
  1233    p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1235    char nameBuf[SYMBOL_BUF_SIZE + 1];
  1236    GElf_Sym sym;
  1237    int res = Plookup_by_addr((struct ps_prochandle*) p_ps_prochandle, (uintptr_t) address,
  1238                                  nameBuf, sizeof(nameBuf), &sym);
  1239    if (res != 0) { // failed
  1240       return 0;
  1243    jstring resSym = env->NewStringUTF(nameBuf);
  1244    CHECK_EXCEPTION_(0);
  1246    return env->CallObjectMethod(this_obj, createClosestSymbol_ID, resSym, (address - sym.st_value));
  1249 /*
  1250  * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1251  * Method:    demangle0
  1252  * Signature: (Ljava/lang/String;)Ljava/lang/String;
  1253  */
  1254 JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_demangle0
  1255   (JNIEnv *env, jobject this_object, jstring name) {
  1256   jboolean isCopy;
  1257   const char* ptr = env->GetStringUTFChars(name, &isCopy);
  1258   char  buf[2*SYMBOL_BUF_SIZE + 1];
  1259   jstring res = 0;
  1260   if (cplus_demangle((char*) ptr, buf, sizeof(buf)) != DEMANGLE_ESPACE) {
  1261     res = env->NewStringUTF(buf);
  1262   } else {
  1263     res = name;
  1265   env->ReleaseStringUTFChars(name, ptr);
  1266   return res;
  1269 #ifndef SOLARIS_11_B159_OR_LATER
  1270 // Determine if the OS we're running on has the newer version
  1271 // of libproc's Pstack_iter.
  1272 //
  1273 // Set env var PSTACK_ITER_DEBUG=true to debug this logic.
  1274 // Set env var PSTACK_ITER_DEBUG_RELEASE to simulate a 'release' value.
  1275 // Set env var PSTACK_ITER_DEBUG_VERSION to simulate a 'version' value.
  1276 //
  1277 // frankenputer 'uname -r -v': 5.10 Generic_141445-09
  1278 // jurassic 'uname -r -v':     5.11 snv_164
  1279 // lonepeak 'uname -r -v':     5.11 snv_127
  1280 //
  1281 static void set_has_newer_Pstack_iter(JNIEnv *env) {
  1282   static bool done_set = false;
  1284   if (done_set) {
  1285     // already set has_newer_Pstack_iter
  1286     return;
  1289   struct utsname name;
  1290   if (uname(&name) == -1) {
  1291     THROW_NEW_DEBUGGER_EXCEPTION("uname() failed!");
  1293   dprintf_2("release='%s'  version='%s'\n", name.release, name.version);
  1295   if (_Pstack_iter_debug) {
  1296     char *override = getenv("PSTACK_ITER_DEBUG_RELEASE");
  1297     if (override != NULL) {
  1298       strncpy(name.release, override, SYS_NMLN - 1);
  1299       name.release[SYS_NMLN - 2] = '\0';
  1300       dprintf_2("overriding with release='%s'\n", name.release);
  1302     override = getenv("PSTACK_ITER_DEBUG_VERSION");
  1303     if (override != NULL) {
  1304       strncpy(name.version, override, SYS_NMLN - 1);
  1305       name.version[SYS_NMLN - 2] = '\0';
  1306       dprintf_2("overriding with version='%s'\n", name.version);
  1310   // the major number corresponds to the old SunOS major number
  1311   int major = atoi(name.release);
  1312   if (major >= 6) {
  1313     dprintf_2("release is SunOS 6 or later\n");
  1314     has_newer_Pstack_iter = true;
  1315     done_set = true;
  1316     return;
  1318   if (major < 5) {
  1319     dprintf_2("release is SunOS 4 or earlier\n");
  1320     done_set = true;
  1321     return;
  1324   // some SunOS 5.* build so now check for Solaris versions
  1325   char *dot = strchr(name.release, '.');
  1326   int minor = 0;
  1327   if (dot != NULL) {
  1328     // release is major.minor format
  1329     *dot = NULL;
  1330     minor = atoi(dot + 1);
  1333   if (minor <= 10) {
  1334     dprintf_2("release is Solaris 10 or earlier\n");
  1335     done_set = true;
  1336     return;
  1337   } else if (minor >= 12) {
  1338     dprintf_2("release is Solaris 12 or later\n");
  1339     has_newer_Pstack_iter = true;
  1340     done_set = true;
  1341     return;
  1344   // some Solaris 11 build so now check for internal build numbers
  1345   if (strncmp(name.version, "snv_", 4) != 0) {
  1346     dprintf_2("release is Solaris 11 post-GA or later\n");
  1347     has_newer_Pstack_iter = true;
  1348     done_set = true;
  1349     return;
  1352   // version begins with "snv_" so a pre-GA build of Solaris 11
  1353   int build = atoi(&name.version[4]);
  1354   if (build >= 159) {
  1355     dprintf_2("release is Nevada-B159 or later\n");
  1356     has_newer_Pstack_iter = true;
  1357   } else {
  1358     dprintf_2("release is Nevada-B158 or earlier\n");
  1361   done_set = true;
  1363 #endif // !SOLARIS_11_B159_OR_LATER
  1365 /*
  1366  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1367  * Method:      initIDs
  1368  * Signature:   ()V
  1369  * Description: get JNI ids for fields and methods of ProcDebuggerLocal class
  1370  */
  1371 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_initIDs
  1372   (JNIEnv *env, jclass clazz) {
  1373   _libsaproc_debug = getenv("LIBSAPROC_DEBUG") != NULL;
  1374   if (_libsaproc_debug) {
  1375      // propagate debug mode to libproc.so
  1376      static const char* var = "LIBPROC_DEBUG=1";
  1377      putenv((char*)var);
  1380   void* libproc_handle = dlopen("libproc.so", RTLD_LAZY | RTLD_GLOBAL);
  1381   if (libproc_handle == 0)
  1382      THROW_NEW_DEBUGGER_EXCEPTION("can't load libproc.so, if you are using Solaris 5.7 or below, copy libproc.so from 5.8!");
  1384 #ifndef SOLARIS_11_B159_OR_LATER
  1385   _Pstack_iter_debug = getenv("PSTACK_ITER_DEBUG") != NULL;
  1387   set_has_newer_Pstack_iter(env);
  1388   CHECK_EXCEPTION;
  1389   dprintf_2("has_newer_Pstack_iter=%d\n", has_newer_Pstack_iter);
  1390 #endif
  1392   p_ps_prochandle_ID = env->GetFieldID(clazz, "p_ps_prochandle", "J");
  1393   CHECK_EXCEPTION;
  1395   libthread_db_handle_ID = env->GetFieldID(clazz, "libthread_db_handle", "J");
  1396   CHECK_EXCEPTION;
  1398   p_td_thragent_t_ID = env->GetFieldID(clazz, "p_td_thragent_t", "J");
  1399   CHECK_EXCEPTION;
  1401   p_td_init_ID = env->GetFieldID(clazz, "p_td_init", "J");
  1402   CHECK_EXCEPTION;
  1404   p_td_ta_new_ID = env->GetFieldID(clazz, "p_td_ta_new", "J");
  1405   CHECK_EXCEPTION;
  1407   p_td_ta_delete_ID = env->GetFieldID(clazz, "p_td_ta_delete", "J");
  1408   CHECK_EXCEPTION;
  1410   p_td_ta_thr_iter_ID = env->GetFieldID(clazz, "p_td_ta_thr_iter", "J");
  1411   CHECK_EXCEPTION;
  1413   p_td_thr_get_info_ID = env->GetFieldID(clazz, "p_td_thr_get_info", "J");
  1414   CHECK_EXCEPTION;
  1416   p_td_ta_map_id2thr_ID = env->GetFieldID(clazz, "p_td_ta_map_id2thr", "J");
  1417   CHECK_EXCEPTION;
  1419   p_td_thr_getgregs_ID = env->GetFieldID(clazz, "p_td_thr_getgregs", "J");
  1420   CHECK_EXCEPTION;
  1422   getThreadForThreadId_ID = env->GetMethodID(clazz,
  1423                             "getThreadForThreadId", "(J)Lsun/jvm/hotspot/debugger/ThreadProxy;");
  1424   CHECK_EXCEPTION;
  1426   pcRegIndex_ID = env->GetFieldID(clazz, "pcRegIndex", "I");
  1427   CHECK_EXCEPTION;
  1429   fpRegIndex_ID = env->GetFieldID(clazz, "fpRegIndex", "I");
  1430   CHECK_EXCEPTION;
  1432   createSenderFrame_ID = env->GetMethodID(clazz,
  1433                             "createSenderFrame", "(Lsun/jvm/hotspot/debugger/proc/ProcCFrame;JJ)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;");
  1434   CHECK_EXCEPTION;
  1436   createLoadObject_ID = env->GetMethodID(clazz,
  1437                             "createLoadObject", "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");
  1438   CHECK_EXCEPTION;
  1440   createClosestSymbol_ID = env->GetMethodID(clazz,
  1441                             "createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
  1442   CHECK_EXCEPTION;
  1444   listAdd_ID = env->GetMethodID(env->FindClass("java/util/List"), "add", "(Ljava/lang/Object;)Z");
  1445   CHECK_EXCEPTION;
  1447   // part of the class sharing workaround
  1448   classes_jsa_fd_ID = env->GetFieldID(clazz, "classes_jsa_fd", "I");
  1449   CHECK_EXCEPTION;
  1450   p_file_map_header_ID = env->GetFieldID(clazz, "p_file_map_header", "J");
  1451   CHECK_EXCEPTION;

mercurial