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

changeset 435
a61af66fc99e
child 964
8db2b3e46c38
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/agent/src/os/solaris/proc/saproc.cpp	Sat Dec 01 00:00:00 2007 +0000
     1.3 @@ -0,0 +1,1300 @@
     1.4 +/*
     1.5 + * Copyright 2002-2007 Sun Microsystems, Inc.  All Rights Reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    1.24 + * have any questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +#include "salibproc.h"
    1.29 +#include "sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal.h"
    1.30 +#include <thread_db.h>
    1.31 +#include <strings.h>
    1.32 +#include <limits.h>
    1.33 +#include <demangle.h>
    1.34 +#include <stdarg.h>
    1.35 +#include <stdlib.h>
    1.36 +#include <errno.h>
    1.37 +
    1.38 +#define CHECK_EXCEPTION_(value) if(env->ExceptionOccurred()) { return value; }
    1.39 +#define CHECK_EXCEPTION if(env->ExceptionOccurred()) { return;}
    1.40 +#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throwNewDebuggerException(env, str); return value; }
    1.41 +#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throwNewDebuggerException(env, str); return;}
    1.42 +
    1.43 +#define SYMBOL_BUF_SIZE  256
    1.44 +#define ERR_MSG_SIZE     (PATH_MAX + 256)
    1.45 +
    1.46 +// debug mode
    1.47 +static int _libsaproc_debug = 0;
    1.48 +
    1.49 +static void print_debug(const char* format,...) {
    1.50 +  if (_libsaproc_debug) {
    1.51 +    va_list alist;
    1.52 +
    1.53 +    va_start(alist, format);
    1.54 +    fputs("libsaproc DEBUG: ", stderr);
    1.55 +    vfprintf(stderr, format, alist);
    1.56 +    va_end(alist);
    1.57 +  }
    1.58 +}
    1.59 +
    1.60 +struct Debugger {
    1.61 +    JNIEnv* env;
    1.62 +    jobject this_obj;
    1.63 +};
    1.64 +
    1.65 +struct DebuggerWithObject : Debugger {
    1.66 +    jobject obj;
    1.67 +};
    1.68 +
    1.69 +struct DebuggerWith2Objects : DebuggerWithObject {
    1.70 +    jobject obj2;
    1.71 +};
    1.72 +
    1.73 +/*
    1.74 +* Portions of user thread level detail gathering code is from pstack source
    1.75 +* code. See pstack.c in Solaris 2.8 user commands source code.
    1.76 +*/
    1.77 +
    1.78 +static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) {
    1.79 +  env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
    1.80 +}
    1.81 +
    1.82 +// JNI ids for some fields, methods
    1.83 +
    1.84 +// libproc handler pointer
    1.85 +static jfieldID p_ps_prochandle_ID = 0;
    1.86 +
    1.87 +// libthread.so dlopen handle, thread agent ptr and function pointers
    1.88 +static jfieldID libthread_db_handle_ID   = 0;
    1.89 +static jfieldID p_td_thragent_t_ID       = 0;
    1.90 +static jfieldID p_td_init_ID             = 0;
    1.91 +static jfieldID p_td_ta_new_ID           = 0;
    1.92 +static jfieldID p_td_ta_delete_ID        = 0;
    1.93 +static jfieldID p_td_ta_thr_iter_ID      = 0;
    1.94 +static jfieldID p_td_thr_get_info_ID     = 0;
    1.95 +static jfieldID p_td_ta_map_id2thr_ID    = 0;
    1.96 +static jfieldID p_td_thr_getgregs_ID     = 0;
    1.97 +
    1.98 +// reg index fields
    1.99 +static jfieldID pcRegIndex_ID            = 0;
   1.100 +static jfieldID fpRegIndex_ID            = 0;
   1.101 +
   1.102 +// part of the class sharing workaround
   1.103 +static jfieldID classes_jsa_fd_ID        = 0;
   1.104 +static jfieldID p_file_map_header_ID     = 0;
   1.105 +
   1.106 +// method ids
   1.107 +
   1.108 +static jmethodID getThreadForThreadId_ID = 0;
   1.109 +static jmethodID createSenderFrame_ID    = 0;
   1.110 +static jmethodID createLoadObject_ID     = 0;
   1.111 +static jmethodID createClosestSymbol_ID  = 0;
   1.112 +static jmethodID listAdd_ID              = 0;
   1.113 +
   1.114 +/*
   1.115 + * Functions we need from libthread_db
   1.116 + */
   1.117 +typedef td_err_e
   1.118 +        (*p_td_init_t)(void);
   1.119 +typedef td_err_e
   1.120 +        (*p_td_ta_new_t)(void *, td_thragent_t **);
   1.121 +typedef td_err_e
   1.122 +        (*p_td_ta_delete_t)(td_thragent_t *);
   1.123 +typedef td_err_e
   1.124 +        (*p_td_ta_thr_iter_t)(const td_thragent_t *, td_thr_iter_f *, void *,
   1.125 +                td_thr_state_e, int, sigset_t *, unsigned);
   1.126 +typedef td_err_e
   1.127 +        (*p_td_thr_get_info_t)(const td_thrhandle_t *, td_thrinfo_t *);
   1.128 +typedef td_err_e
   1.129 +        (*p_td_ta_map_id2thr_t)(const td_thragent_t *, thread_t,  td_thrhandle_t *);
   1.130 +typedef td_err_e
   1.131 +        (*p_td_thr_getgregs_t)(const td_thrhandle_t *, prgregset_t);
   1.132 +
   1.133 +static void
   1.134 +clear_libthread_db_ptrs(JNIEnv* env, jobject this_obj) {
   1.135 +  // release libthread_db agent, if we had created
   1.136 +  p_td_ta_delete_t p_td_ta_delete = 0;
   1.137 +  p_td_ta_delete = (p_td_ta_delete_t) env->GetLongField(this_obj, p_td_ta_delete_ID);
   1.138 +
   1.139 +  td_thragent_t *p_td_thragent_t = 0;
   1.140 +  p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
   1.141 +  if (p_td_thragent_t != 0 && p_td_ta_delete != 0) {
   1.142 +     p_td_ta_delete(p_td_thragent_t);
   1.143 +  }
   1.144 +
   1.145 +  // dlclose libthread_db.so
   1.146 +  void* libthread_db_handle = (void*) env->GetLongField(this_obj, libthread_db_handle_ID);
   1.147 +  if (libthread_db_handle != 0) {
   1.148 +    dlclose(libthread_db_handle);
   1.149 +  }
   1.150 +
   1.151 +  env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)0);
   1.152 +  env->SetLongField(this_obj, p_td_init_ID, (jlong)0);
   1.153 +  env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)0);
   1.154 +  env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)0);
   1.155 +  env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)0);
   1.156 +  env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)0);
   1.157 +  env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)0);
   1.158 +  env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)0);
   1.159 +}
   1.160 +
   1.161 +
   1.162 +static void detach_internal(JNIEnv* env, jobject this_obj) {
   1.163 +  // clear libthread_db stuff
   1.164 +  clear_libthread_db_ptrs(env, this_obj);
   1.165 +
   1.166 +  // release ptr to ps_prochandle
   1.167 +  jlong p_ps_prochandle;
   1.168 +  p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
   1.169 +  if (p_ps_prochandle != 0L) {
   1.170 +    Prelease((struct ps_prochandle*) p_ps_prochandle, PRELEASE_CLEAR);
   1.171 +  }
   1.172 +
   1.173 +  // part of the class sharing workaround
   1.174 +  int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);
   1.175 +  if (classes_jsa_fd != -1) {
   1.176 +    close(classes_jsa_fd);
   1.177 +    struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID);
   1.178 +    if (pheader != NULL) {
   1.179 +      free(pheader);
   1.180 +    }
   1.181 +  }
   1.182 +}
   1.183 +
   1.184 +// Is it okay to ignore libthread_db failure? Set env var to ignore
   1.185 +// libthread_db failure. You can still debug, but will miss threads
   1.186 +// related functionality.
   1.187 +static bool sa_ignore_threaddb = (getenv("SA_IGNORE_THREADDB") != 0);
   1.188 +
   1.189 +#define HANDLE_THREADDB_FAILURE(msg)          \
   1.190 +  if (sa_ignore_threaddb) {                   \
   1.191 +     printf("libsaproc WARNING: %s\n", msg);  \
   1.192 +     return;                                  \
   1.193 +  } else {                                    \
   1.194 +     THROW_NEW_DEBUGGER_EXCEPTION(msg);       \
   1.195 +  }
   1.196 +
   1.197 +#define HANDLE_THREADDB_FAILURE_(msg, ret)    \
   1.198 +  if (sa_ignore_threaddb) {                   \
   1.199 +     printf("libsaproc WARNING: %s\n", msg);  \
   1.200 +     return ret;                              \
   1.201 +  } else {                                    \
   1.202 +     THROW_NEW_DEBUGGER_EXCEPTION_(msg, ret); \
   1.203 +  }
   1.204 +
   1.205 +static const char * alt_root = NULL;
   1.206 +static int alt_root_len = -1;
   1.207 +
   1.208 +#define SA_ALTROOT "SA_ALTROOT"
   1.209 +
   1.210 +static void init_alt_root() {
   1.211 +  if (alt_root_len == -1) {
   1.212 +    alt_root = getenv(SA_ALTROOT);
   1.213 +    if (alt_root)
   1.214 +      alt_root_len = strlen(alt_root);
   1.215 +    else
   1.216 +      alt_root_len = 0;
   1.217 +  }
   1.218 +}
   1.219 +
   1.220 +static int find_file_hook(const char * name, int elf_checksum) {
   1.221 +  init_alt_root();
   1.222 +
   1.223 +  if (_libsaproc_debug) {
   1.224 +    printf("libsaproc DEBUG: find_file_hook %s 0x%x\n", name, elf_checksum);
   1.225 +  }
   1.226 +
   1.227 +  if (alt_root_len > 0) {
   1.228 +    int fd = -1;
   1.229 +    char alt_path[PATH_MAX+1];
   1.230 +
   1.231 +    strcpy(alt_path, alt_root);
   1.232 +    strcat(alt_path, name);
   1.233 +    fd = open(alt_path, O_RDONLY);
   1.234 +    if (fd >= 0) {
   1.235 +      if (_libsaproc_debug) {
   1.236 +        printf("libsaproc DEBUG: find_file_hook substituted %s\n", alt_path);
   1.237 +      }
   1.238 +      return fd;
   1.239 +    }
   1.240 +
   1.241 +    if (strrchr(name, '/')) {
   1.242 +      strcpy(alt_path, alt_root);
   1.243 +      strcat(alt_path, strrchr(name, '/'));
   1.244 +      fd = open(alt_path, O_RDONLY);
   1.245 +      if (fd >= 0) {
   1.246 +        if (_libsaproc_debug) {
   1.247 +          printf("libsaproc DEBUG: find_file_hook substituted %s\n", alt_path);
   1.248 +        }
   1.249 +        return fd;
   1.250 +      }
   1.251 +    }
   1.252 +  }
   1.253 +  return -1;
   1.254 +}
   1.255 +
   1.256 +static int pathmap_open(const char* name) {
   1.257 +  int fd = open(name, O_RDONLY);
   1.258 +  if (fd < 0) {
   1.259 +    fd = find_file_hook(name, 0);
   1.260 +  }
   1.261 +  return fd;
   1.262 +}
   1.263 +
   1.264 +static void * pathmap_dlopen(const char * name, int mode) {
   1.265 +  init_alt_root();
   1.266 +
   1.267 +  if (_libsaproc_debug) {
   1.268 +    printf("libsaproc DEBUG: pathmap_dlopen %s\n", name);
   1.269 +  }
   1.270 +
   1.271 +  void * handle = NULL;
   1.272 +  if (alt_root_len > 0) {
   1.273 +    char alt_path[PATH_MAX+1];
   1.274 +    strcpy(alt_path, alt_root);
   1.275 +    strcat(alt_path, name);
   1.276 +    handle = dlopen(alt_path, mode);
   1.277 +    if (_libsaproc_debug && handle) {
   1.278 +      printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);
   1.279 +    }
   1.280 +
   1.281 +    if (handle == NULL && strrchr(name, '/')) {
   1.282 +      strcpy(alt_path, alt_root);
   1.283 +      strcat(alt_path, strrchr(name, '/'));
   1.284 +      handle = dlopen(alt_path, mode);
   1.285 +      if (_libsaproc_debug && handle) {
   1.286 +        printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);
   1.287 +      }
   1.288 +    }
   1.289 +  }
   1.290 +  if (handle == NULL) {
   1.291 +    handle = dlopen(name, mode);
   1.292 +  }
   1.293 +  if (_libsaproc_debug) {
   1.294 +    printf("libsaproc DEBUG: pathmap_dlopen %s return 0x%x\n", name, handle);
   1.295 +  }
   1.296 +  return handle;
   1.297 +}
   1.298 +
   1.299 +// libproc and libthread_db callback functions
   1.300 +
   1.301 +extern "C" {
   1.302 +
   1.303 +static int
   1.304 +init_libthread_db_ptrs(void *cd, const prmap_t *pmp, const char *object_name) {
   1.305 +  Debugger* dbg = (Debugger*) cd;
   1.306 +  JNIEnv* env = dbg->env;
   1.307 +  jobject this_obj = dbg->this_obj;
   1.308 +  struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
   1.309 +
   1.310 +  char *s1 = 0, *s2 = 0;
   1.311 +  char libthread_db[PATH_MAX];
   1.312 +
   1.313 +  if (strstr(object_name, "/libthread.so.") == NULL)
   1.314 +     return (0);
   1.315 +
   1.316 +  /*
   1.317 +   * We found a libthread.
   1.318 +   * dlopen() the matching libthread_db and get the thread agent handle.
   1.319 +   */
   1.320 +  if (Pstatus(ph)->pr_dmodel == PR_MODEL_NATIVE) {
   1.321 +     (void) strcpy(libthread_db, object_name);
   1.322 +     s1 = (char*) strstr(object_name, ".so.");
   1.323 +     s2 = (char*) strstr(libthread_db, ".so.");
   1.324 +     (void) strcpy(s2, "_db");
   1.325 +     s2 += 3;
   1.326 +     (void) strcpy(s2, s1);
   1.327 +  } else {
   1.328 +#ifdef _LP64
   1.329 +     /*
   1.330 +      * The victim process is 32-bit, we are 64-bit.
   1.331 +      * We have to find the 64-bit version of libthread_db
   1.332 +      * that matches the victim's 32-bit version of libthread.
   1.333 +      */
   1.334 +     (void) strcpy(libthread_db, object_name);
   1.335 +     s1 = (char*) strstr(object_name, "/libthread.so.");
   1.336 +     s2 = (char*) strstr(libthread_db, "/libthread.so.");
   1.337 +     (void) strcpy(s2, "/64");
   1.338 +     s2 += 3;
   1.339 +     (void) strcpy(s2, s1);
   1.340 +     s1 = (char*) strstr(s1, ".so.");
   1.341 +     s2 = (char*) strstr(s2, ".so.");
   1.342 +     (void) strcpy(s2, "_db");
   1.343 +     s2 += 3;
   1.344 +     (void) strcpy(s2, s1);
   1.345 +#else
   1.346 +     return (0);
   1.347 +#endif  /* _LP64 */
   1.348 +  }
   1.349 +
   1.350 +  void* libthread_db_handle = 0;
   1.351 +  if ((libthread_db_handle = pathmap_dlopen(libthread_db, RTLD_LAZY|RTLD_LOCAL)) == NULL) {
   1.352 +     char errMsg[PATH_MAX + 256];
   1.353 +     sprintf(errMsg, "Can't load %s!", libthread_db);
   1.354 +     HANDLE_THREADDB_FAILURE_(errMsg, 0);
   1.355 +  }
   1.356 +  env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)(uintptr_t)libthread_db_handle);
   1.357 +
   1.358 +  void* tmpPtr = 0;
   1.359 +  tmpPtr = dlsym(libthread_db_handle, "td_init");
   1.360 +  if (tmpPtr == 0) {
   1.361 +     HANDLE_THREADDB_FAILURE_("dlsym failed on td_init!", 0);
   1.362 +  }
   1.363 +  env->SetLongField(this_obj, p_td_init_ID, (jlong)(uintptr_t) tmpPtr);
   1.364 +
   1.365 +  tmpPtr =dlsym(libthread_db_handle, "td_ta_new");
   1.366 +  if (tmpPtr == 0) {
   1.367 +     HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_new!", 0);
   1.368 +  }
   1.369 +  env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)(uintptr_t) tmpPtr);
   1.370 +
   1.371 +  tmpPtr = dlsym(libthread_db_handle, "td_ta_delete");
   1.372 +  if (tmpPtr == 0) {
   1.373 +     HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_delete!", 0);
   1.374 +  }
   1.375 +  env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)(uintptr_t) tmpPtr);
   1.376 +
   1.377 +  tmpPtr = dlsym(libthread_db_handle, "td_ta_thr_iter");
   1.378 +  if (tmpPtr == 0) {
   1.379 +     HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_thr_iter!", 0);
   1.380 +  }
   1.381 +  env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)(uintptr_t) tmpPtr);
   1.382 +
   1.383 +  tmpPtr = dlsym(libthread_db_handle, "td_thr_get_info");
   1.384 +  if (tmpPtr == 0) {
   1.385 +     HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_get_info!", 0);
   1.386 +  }
   1.387 +  env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)(uintptr_t) tmpPtr);
   1.388 +
   1.389 +  tmpPtr = dlsym(libthread_db_handle, "td_ta_map_id2thr");
   1.390 +  if (tmpPtr == 0) {
   1.391 +     HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_map_id2thr!", 0);
   1.392 +  }
   1.393 +  env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)(uintptr_t) tmpPtr);
   1.394 +
   1.395 +  tmpPtr = dlsym(libthread_db_handle, "td_thr_getgregs");
   1.396 +  if (tmpPtr == 0) {
   1.397 +     HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_getgregs!", 0);
   1.398 +  }
   1.399 +  env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)(uintptr_t) tmpPtr);
   1.400 +
   1.401 +  return 1;
   1.402 +}
   1.403 +
   1.404 +static int
   1.405 +fill_thread_list(const td_thrhandle_t *p_td_thragent_t, void* cd) {
   1.406 +  DebuggerWithObject* dbgo = (DebuggerWithObject*) cd;
   1.407 +  JNIEnv* env = dbgo->env;
   1.408 +  jobject this_obj = dbgo->this_obj;
   1.409 +  jobject list = dbgo->obj;
   1.410 +
   1.411 +  td_thrinfo_t thrinfo;
   1.412 +  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);
   1.413 +
   1.414 +  if (p_td_thr_get_info(p_td_thragent_t, &thrinfo) != TD_OK)
   1.415 +    return (0);
   1.416 +
   1.417 +  jobject threadProxy = env->CallObjectMethod(this_obj, getThreadForThreadId_ID, (jlong)(uintptr_t) thrinfo.ti_tid);
   1.418 +  CHECK_EXCEPTION_(1);
   1.419 +  env->CallBooleanMethod(list, listAdd_ID, threadProxy);
   1.420 +  CHECK_EXCEPTION_(1);
   1.421 +  return 0;
   1.422 +}
   1.423 +
   1.424 +static int
   1.425 +fill_load_object_list(void *cd, const prmap_t* pmp, const char* obj_name) {
   1.426 +
   1.427 +  if (obj_name) {
   1.428 +     DebuggerWithObject* dbgo = (DebuggerWithObject*) cd;
   1.429 +     JNIEnv* env = dbgo->env;
   1.430 +     jobject this_obj = dbgo->this_obj;
   1.431 +     jobject list = dbgo->obj;
   1.432 +
   1.433 +     jstring objectName = env->NewStringUTF(obj_name);
   1.434 +     CHECK_EXCEPTION_(1);
   1.435 +
   1.436 +     jlong mapSize = (jlong) pmp->pr_size;
   1.437 +     jobject sharedObject = env->CallObjectMethod(this_obj, createLoadObject_ID,
   1.438 +                                  objectName, mapSize, (jlong)(uintptr_t)pmp->pr_vaddr);
   1.439 +     CHECK_EXCEPTION_(1);
   1.440 +     env->CallBooleanMethod(list, listAdd_ID, sharedObject);
   1.441 +     CHECK_EXCEPTION_(1);
   1.442 +  }
   1.443 +
   1.444 +  return 0;
   1.445 +}
   1.446 +
   1.447 +static int
   1.448 +fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc, const long *argv) {
   1.449 +  DebuggerWith2Objects* dbgo2 = (DebuggerWith2Objects*) cd;
   1.450 +  JNIEnv* env = dbgo2->env;
   1.451 +  jobject this_obj = dbgo2->this_obj;
   1.452 +  jobject curFrame = dbgo2->obj2;
   1.453 +
   1.454 +  jint pcRegIndex = env->GetIntField(this_obj, pcRegIndex_ID);
   1.455 +  jint fpRegIndex = env->GetIntField(this_obj, fpRegIndex_ID);
   1.456 +
   1.457 +  jlong pc = (jlong) (uintptr_t) regs[pcRegIndex];
   1.458 +  jlong fp = (jlong) (uintptr_t) regs[fpRegIndex];
   1.459 +
   1.460 +  dbgo2->obj2 = env->CallObjectMethod(this_obj, createSenderFrame_ID,
   1.461 +                                    curFrame, pc, fp);
   1.462 +  CHECK_EXCEPTION_(1);
   1.463 +  if (dbgo2->obj == 0) {
   1.464 +     dbgo2->obj = dbgo2->obj2;
   1.465 +  }
   1.466 +  return 0;
   1.467 +}
   1.468 +
   1.469 +// part of the class sharing workaround
   1.470 +
   1.471 +// FIXME: !!HACK ALERT!!
   1.472 +
   1.473 +// The format of sharing achive file header is needed to read shared heap
   1.474 +// file mappings. For now, I am hard coding portion of FileMapHeader here.
   1.475 +// Refer to filemap.hpp.
   1.476 +
   1.477 +// FileMapHeader describes the shared space data in the file to be
   1.478 +// mapped.  This structure gets written to a file.  It is not a class, so
   1.479 +// that the compilers don't add any compiler-private data to it.
   1.480 +
   1.481 +// Refer to CompactingPermGenGen::n_regions in compactingPermGenGen.hpp
   1.482 +const int NUM_SHARED_MAPS = 4;
   1.483 +
   1.484 +// Refer to FileMapInfo::_current_version in filemap.hpp
   1.485 +const int CURRENT_ARCHIVE_VERSION = 1;
   1.486 +
   1.487 +struct FileMapHeader {
   1.488 + int   _magic;              // identify file type.
   1.489 + int   _version;            // (from enum, above.)
   1.490 + size_t _alignment;         // how shared archive should be aligned
   1.491 +
   1.492 +
   1.493 + struct space_info {
   1.494 +   int    _file_offset;     // sizeof(this) rounded to vm page size
   1.495 +   char*  _base;            // copy-on-write base address
   1.496 +   size_t _capacity;        // for validity checking
   1.497 +   size_t _used;            // for setting space top on read
   1.498 +
   1.499 +   bool   _read_only;       // read only space?
   1.500 +   bool   _allow_exec;      // executable code in space?
   1.501 +
   1.502 + } _space[NUM_SHARED_MAPS]; // was _space[CompactingPermGenGen::n_regions];
   1.503 +
   1.504 + // Ignore the rest of the FileMapHeader. We don't need those fields here.
   1.505 +};
   1.506 +
   1.507 +static bool
   1.508 +read_int(struct ps_prochandle* ph, psaddr_t addr, int* pvalue) {
   1.509 +  int i;
   1.510 +  if (ps_pread(ph, addr, &i, sizeof(i)) == PS_OK) {
   1.511 +    *pvalue = i;
   1.512 +    return true;
   1.513 +  } else {
   1.514 +    return false;
   1.515 +  }
   1.516 +}
   1.517 +
   1.518 +static bool
   1.519 +read_pointer(struct ps_prochandle* ph, psaddr_t addr, uintptr_t* pvalue) {
   1.520 +  uintptr_t uip;
   1.521 +  if (ps_pread(ph, addr, &uip, sizeof(uip)) == PS_OK) {
   1.522 +    *pvalue = uip;
   1.523 +    return true;
   1.524 +  } else {
   1.525 +    return false;
   1.526 +  }
   1.527 +}
   1.528 +
   1.529 +static bool
   1.530 +read_string(struct ps_prochandle* ph, psaddr_t addr, char* buf, size_t size) {
   1.531 +  char ch = ' ';
   1.532 +  size_t i = 0;
   1.533 +
   1.534 +  while (ch != '\0') {
   1.535 +    if (ps_pread(ph, addr, &ch, sizeof(ch)) != PS_OK)
   1.536 +      return false;
   1.537 +
   1.538 +    if (i < size - 1) {
   1.539 +      buf[i] = ch;
   1.540 +    } else { // smaller buffer
   1.541 +      return false;
   1.542 +    }
   1.543 +
   1.544 +    i++; addr++;
   1.545 +  }
   1.546 +
   1.547 +  buf[i] = '\0';
   1.548 +  return true;
   1.549 +}
   1.550 +
   1.551 +#define USE_SHARED_SPACES_SYM   "UseSharedSpaces"
   1.552 +// mangled symbol name for Arguments::SharedArchivePath
   1.553 +#define SHARED_ARCHIVE_PATH_SYM "__1cJArgumentsRSharedArchivePath_"
   1.554 +
   1.555 +static int
   1.556 +init_classsharing_workaround(void *cd, const prmap_t* pmap, const char* obj_name) {
   1.557 +  Debugger* dbg = (Debugger*) cd;
   1.558 +  JNIEnv*   env = dbg->env;
   1.559 +  jobject this_obj = dbg->this_obj;
   1.560 +  const char* jvm_name = 0;
   1.561 +  if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL ||
   1.562 +      (jvm_name = strstr(obj_name, "libjvm_g.so")) != NULL) {
   1.563 +    jvm_name = obj_name;
   1.564 +  } else {
   1.565 +    return 0;
   1.566 +  }
   1.567 +
   1.568 +  struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
   1.569 +
   1.570 +  // initialize classes[_g].jsa file descriptor field.
   1.571 +  dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, -1);
   1.572 +
   1.573 +  // check whether class sharing is on by reading variable "UseSharedSpaces"
   1.574 +  psaddr_t useSharedSpacesAddr = 0;
   1.575 +  ps_pglobal_lookup(ph, jvm_name, USE_SHARED_SPACES_SYM, &useSharedSpacesAddr);
   1.576 +  if (useSharedSpacesAddr == 0) {
   1.577 +    THROW_NEW_DEBUGGER_EXCEPTION_("can't find 'UseSharedSpaces' flag\n", 1);
   1.578 +  }
   1.579 +
   1.580 +  // read the value of the flag "UseSharedSpaces"
   1.581 +  int value = 0;
   1.582 +  if (read_int(ph, useSharedSpacesAddr, &value) != true) {
   1.583 +    THROW_NEW_DEBUGGER_EXCEPTION_("can't read 'UseSharedSpaces' flag", 1);
   1.584 +  } else if (value == 0) {
   1.585 +    print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
   1.586 +    return 1;
   1.587 +  }
   1.588 +
   1.589 +  char classes_jsa[PATH_MAX];
   1.590 +  psaddr_t sharedArchivePathAddrAddr = 0;
   1.591 +  ps_pglobal_lookup(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM, &sharedArchivePathAddrAddr);
   1.592 +  if (sharedArchivePathAddrAddr == 0) {
   1.593 +    print_debug("can't find symbol 'Arguments::SharedArchivePath'\n");
   1.594 +    THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
   1.595 +  }
   1.596 +
   1.597 +  uintptr_t sharedArchivePathAddr = 0;
   1.598 +  if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
   1.599 +    print_debug("can't find read pointer 'Arguments::SharedArchivePath'\n");
   1.600 +    THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
   1.601 +  }
   1.602 +
   1.603 +  if (read_string(ph, (psaddr_t)sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
   1.604 +    print_debug("can't find read 'Arguments::SharedArchivePath' value\n");
   1.605 +    THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
   1.606 +  }
   1.607 +
   1.608 +  print_debug("looking for %s\n", classes_jsa);
   1.609 +
   1.610 +  // open the classes[_g].jsa
   1.611 +  int fd = pathmap_open(classes_jsa);
   1.612 +  if (fd < 0) {
   1.613 +    char errMsg[ERR_MSG_SIZE];
   1.614 +    sprintf(errMsg, "can't open shared archive file %s", classes_jsa);
   1.615 +    THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
   1.616 +  } else {
   1.617 +    print_debug("opened shared archive file %s\n", classes_jsa);
   1.618 +  }
   1.619 +
   1.620 +  // parse classes[_g].jsa
   1.621 +  struct FileMapHeader* pheader = (struct FileMapHeader*) malloc(sizeof(struct FileMapHeader));
   1.622 +  if (pheader == NULL) {
   1.623 +    close(fd);
   1.624 +    THROW_NEW_DEBUGGER_EXCEPTION_("can't allocate memory for shared file map header", 1);
   1.625 +  }
   1.626 +
   1.627 +  memset(pheader, 0, sizeof(struct FileMapHeader));
   1.628 +  // read FileMapHeader
   1.629 +  size_t n = read(fd, pheader, sizeof(struct FileMapHeader));
   1.630 +  if (n != sizeof(struct FileMapHeader)) {
   1.631 +    free(pheader);
   1.632 +    close(fd);
   1.633 +    char errMsg[ERR_MSG_SIZE];
   1.634 +    sprintf(errMsg, "unable to read shared archive file map header from %s", classes_jsa);
   1.635 +    THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
   1.636 +  }
   1.637 +
   1.638 +  // check file magic
   1.639 +  if (pheader->_magic != 0xf00baba2) {
   1.640 +    free(pheader);
   1.641 +    close(fd);
   1.642 +    char errMsg[ERR_MSG_SIZE];
   1.643 +    sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0xf00baba2",
   1.644 +                   classes_jsa, pheader->_magic);
   1.645 +    THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
   1.646 +  }
   1.647 +
   1.648 +  // check version
   1.649 +  if (pheader->_version != CURRENT_ARCHIVE_VERSION) {
   1.650 +    free(pheader);
   1.651 +    close(fd);
   1.652 +    char errMsg[ERR_MSG_SIZE];
   1.653 +    sprintf(errMsg, "%s has wrong shared archive version %d, expecting %d",
   1.654 +                   classes_jsa, pheader->_version, CURRENT_ARCHIVE_VERSION);
   1.655 +    THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
   1.656 +  }
   1.657 +
   1.658 +  if (_libsaproc_debug) {
   1.659 +    for (int m = 0; m < NUM_SHARED_MAPS; m++) {
   1.660 +       print_debug("shared file offset %d mapped at 0x%lx, size = %ld, read only? = %d\n",
   1.661 +          pheader->_space[m]._file_offset, pheader->_space[m]._base,
   1.662 +          pheader->_space[m]._used, pheader->_space[m]._read_only);
   1.663 +    }
   1.664 +  }
   1.665 +
   1.666 +  // FIXME: For now, omitting other checks such as VM version etc.
   1.667 +
   1.668 +  // store class archive file fd and map header in debugger object fields
   1.669 +  dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, fd);
   1.670 +  dbg->env->SetLongField(this_obj, p_file_map_header_ID, (jlong)(uintptr_t) pheader);
   1.671 +  return 1;
   1.672 +}
   1.673 +
   1.674 +} // extern "C"
   1.675 +
   1.676 +// error messages for proc_arg_grab failure codes. The messages are
   1.677 +// modified versions of comments against corresponding #defines in
   1.678 +// libproc.h.
   1.679 +static const char* proc_arg_grab_errmsgs[] = {
   1.680 +                      "",
   1.681 + /* G_NOPROC */       "No such process",
   1.682 + /* G_NOCORE */       "No such core file",
   1.683 + /* G_NOPROCORCORE */ "No such process or core",
   1.684 + /* G_NOEXEC */       "Cannot locate executable file",
   1.685 + /* G_ZOMB   */       "Zombie processs",
   1.686 + /* G_PERM   */       "No permission to attach",
   1.687 + /* G_BUSY   */       "Another process has already attached",
   1.688 + /* G_SYS    */       "System process - can not attach",
   1.689 + /* G_SELF   */       "Process is self - can't debug myself!",
   1.690 + /* G_INTR   */       "Interrupt received while grabbing",
   1.691 + /* G_LP64   */       "debuggee is 64 bit, use java -d64 for debugger",
   1.692 + /* G_FORMAT */       "File is not an ELF format core file - corrupted core?",
   1.693 + /* G_ELF    */       "Libelf error while parsing an ELF file",
   1.694 + /* G_NOTE   */       "Required PT_NOTE Phdr not present - corrupted core?",
   1.695 +};
   1.696 +
   1.697 +static void attach_internal(JNIEnv* env, jobject this_obj, jstring cmdLine, jboolean isProcess) {
   1.698 +  jboolean isCopy;
   1.699 +  int gcode;
   1.700 +  const char* cmdLine_cstr = env->GetStringUTFChars(cmdLine, &isCopy);
   1.701 +  CHECK_EXCEPTION;
   1.702 +
   1.703 +  // some older versions of libproc.so crash when trying to attach 32 bit
   1.704 +  // debugger to 64 bit core file. check and throw error.
   1.705 +#ifndef _LP64
   1.706 +  atoi(cmdLine_cstr);
   1.707 +  if (errno) {
   1.708 +     // core file
   1.709 +     int core_fd;
   1.710 +     if ((core_fd = open64(cmdLine_cstr, O_RDONLY)) >= 0) {
   1.711 +        Elf32_Ehdr e32;
   1.712 +        if (pread64(core_fd, &e32, sizeof (e32), 0) == sizeof (e32) &&
   1.713 +            memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0 &&
   1.714 +            e32.e_type == ET_CORE && e32.e_ident[EI_CLASS] == ELFCLASS64) {
   1.715 +              close(core_fd);
   1.716 +              THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use java -d64 for debugger");
   1.717 +        }
   1.718 +        close(core_fd);
   1.719 +     }
   1.720 +     // all other conditions are handled by libproc.so.
   1.721 +  }
   1.722 +#endif
   1.723 +
   1.724 +  // connect to process/core
   1.725 +  struct ps_prochandle* ph = proc_arg_grab(cmdLine_cstr, (isProcess? PR_ARG_PIDS : PR_ARG_CORES), PGRAB_FORCE, &gcode);
   1.726 +  env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr);
   1.727 +  if (! ph) {
   1.728 +     if (gcode > 0 && gcode < sizeof(proc_arg_grab_errmsgs)/sizeof(const char*)) {
   1.729 +        char errMsg[ERR_MSG_SIZE];
   1.730 +        sprintf(errMsg, "Attach failed : %s", proc_arg_grab_errmsgs[gcode]);
   1.731 +        THROW_NEW_DEBUGGER_EXCEPTION(errMsg);
   1.732 +    } else {
   1.733 +        if (_libsaproc_debug && gcode == G_STRANGE) {
   1.734 +           perror("libsaproc DEBUG: ");
   1.735 +        }
   1.736 +        if (isProcess) {
   1.737 +           THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to process!");
   1.738 +        } else {
   1.739 +           THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to core file!");
   1.740 +        }
   1.741 +     }
   1.742 +  }
   1.743 +
   1.744 +  // even though libproc.so supports 64 bit debugger and 32 bit debuggee, we don't
   1.745 +  // support such cross-bit-debugging. check for that combination and throw error.
   1.746 +#ifdef _LP64
   1.747 +  int data_model;
   1.748 +  if (ps_pdmodel(ph, &data_model) != PS_OK) {
   1.749 +     Prelease(ph, PRELEASE_CLEAR);
   1.750 +     THROW_NEW_DEBUGGER_EXCEPTION("can't determine debuggee data model (ILP32? or LP64?)");
   1.751 +  }
   1.752 +  if (data_model == PR_MODEL_ILP32) {
   1.753 +     Prelease(ph, PRELEASE_CLEAR);
   1.754 +     THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger");
   1.755 +  }
   1.756 +#endif
   1.757 +
   1.758 +  env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(uintptr_t)ph);
   1.759 +
   1.760 +  Debugger dbg;
   1.761 +  dbg.env = env;
   1.762 +  dbg.this_obj = this_obj;
   1.763 +  jthrowable exception = 0;
   1.764 +  if (! isProcess) {
   1.765 +    /*
   1.766 +     * With class sharing, shared perm. gen heap is allocated in with MAP_SHARED|PROT_READ.
   1.767 +     * These pages are mapped from the file "classes[_g].jsa". MAP_SHARED pages are not dumped
   1.768 +     * in Solaris core.To read shared heap pages, we have to read classes[_g].jsa file.
   1.769 +     */
   1.770 +    Pobject_iter(ph, init_classsharing_workaround, &dbg);
   1.771 +    exception = env->ExceptionOccurred();
   1.772 +    if (exception) {
   1.773 +      env->ExceptionClear();
   1.774 +      detach_internal(env, this_obj);
   1.775 +      env->Throw(exception);
   1.776 +      return;
   1.777 +    }
   1.778 +  }
   1.779 +
   1.780 +  /*
   1.781 +   * Iterate over the process mappings looking
   1.782 +   * for libthread and then dlopen the appropriate
   1.783 +   * libthread_db and get function pointers.
   1.784 +   */
   1.785 +  Pobject_iter(ph, init_libthread_db_ptrs, &dbg);
   1.786 +  exception = env->ExceptionOccurred();
   1.787 +  if (exception) {
   1.788 +    env->ExceptionClear();
   1.789 +    if (!sa_ignore_threaddb) {
   1.790 +      detach_internal(env, this_obj);
   1.791 +      env->Throw(exception);
   1.792 +    }
   1.793 +    return;
   1.794 +  }
   1.795 +
   1.796 +  // init libthread_db and create thread_db agent
   1.797 +  p_td_init_t p_td_init = (p_td_init_t) env->GetLongField(this_obj, p_td_init_ID);
   1.798 +  if (p_td_init == 0) {
   1.799 +    if (!sa_ignore_threaddb) {
   1.800 +      detach_internal(env, this_obj);
   1.801 +    }
   1.802 +    HANDLE_THREADDB_FAILURE("Did not find libthread in target process/core!");
   1.803 +  }
   1.804 +
   1.805 +  if (p_td_init() != TD_OK) {
   1.806 +    if (!sa_ignore_threaddb) {
   1.807 +      detach_internal(env, this_obj);
   1.808 +    }
   1.809 +    HANDLE_THREADDB_FAILURE("Can't initialize thread_db!");
   1.810 +  }
   1.811 +
   1.812 +  p_td_ta_new_t p_td_ta_new = (p_td_ta_new_t) env->GetLongField(this_obj, p_td_ta_new_ID);
   1.813 +
   1.814 +  td_thragent_t *p_td_thragent_t = 0;
   1.815 +  if (p_td_ta_new(ph, &p_td_thragent_t) != TD_OK) {
   1.816 +    if (!sa_ignore_threaddb) {
   1.817 +      detach_internal(env, this_obj);
   1.818 +    }
   1.819 +    HANDLE_THREADDB_FAILURE("Can't create thread_db agent!");
   1.820 +  }
   1.821 +  env->SetLongField(this_obj, p_td_thragent_t_ID, (jlong)(uintptr_t) p_td_thragent_t);
   1.822 +
   1.823 +}
   1.824 +
   1.825 +/*
   1.826 + * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   1.827 + * Method:    attach0
   1.828 + * Signature: (Ljava/lang/String;)V
   1.829 + * Description: process detach
   1.830 + */
   1.831 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2
   1.832 +  (JNIEnv *env, jobject this_obj, jstring pid) {
   1.833 +  attach_internal(env, this_obj, pid, JNI_TRUE);
   1.834 +}
   1.835 +
   1.836 +/*
   1.837 + * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   1.838 + * Method:    attach0
   1.839 + * Signature: (Ljava/lang/String;Ljava/lang/String;)V
   1.840 + * Description: core file detach
   1.841 + */
   1.842 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
   1.843 +  (JNIEnv *env, jobject this_obj, jstring executable, jstring corefile) {
   1.844 +  // ignore executable file name, libproc.so can detect a.out name anyway.
   1.845 +  attach_internal(env, this_obj, corefile, JNI_FALSE);
   1.846 +}
   1.847 +
   1.848 +
   1.849 +/*
   1.850 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   1.851 + * Method:      detach0
   1.852 + * Signature:   ()V
   1.853 + * Description: process/core file detach
   1.854 + */
   1.855 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_detach0
   1.856 +  (JNIEnv *env, jobject this_obj) {
   1.857 +  detach_internal(env, this_obj);
   1.858 +}
   1.859 +
   1.860 +/*
   1.861 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   1.862 + * Method:      getRemoteProcessAddressSize0
   1.863 + * Signature:   ()I
   1.864 + * Description: get process/core address size
   1.865 + */
   1.866 +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getRemoteProcessAddressSize0
   1.867 +  (JNIEnv *env, jobject this_obj) {
   1.868 +  jlong p_ps_prochandle;
   1.869 +  p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
   1.870 +  int data_model = PR_MODEL_ILP32;
   1.871 +  ps_pdmodel((struct ps_prochandle*) p_ps_prochandle, &data_model);
   1.872 +  print_debug("debuggee is %d bit\n", data_model == PR_MODEL_ILP32? 32 : 64);
   1.873 +  return (jint) data_model == PR_MODEL_ILP32? 32 : 64;
   1.874 +}
   1.875 +
   1.876 +/*
   1.877 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   1.878 + * Method:      getPageSize0
   1.879 + * Signature:   ()I
   1.880 + * Description: get process/core page size
   1.881 + */
   1.882 +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getPageSize0
   1.883 +  (JNIEnv *env, jobject this_obj) {
   1.884 +
   1.885 +/*
   1.886 +  We are not yet attached to a java process or core file. getPageSize is called from
   1.887 +  the constructor of ProcDebuggerLocal. The following won't work!
   1.888 +
   1.889 +    jlong p_ps_prochandle;
   1.890 +    p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
   1.891 +    CHECK_EXCEPTION_(-1);
   1.892 +    struct ps_prochandle* prochandle = (struct ps_prochandle*) p_ps_prochandle;
   1.893 +    return (Pstate(prochandle) == PS_DEAD) ? Pgetauxval(prochandle, AT_PAGESZ)
   1.894 +                                           : getpagesize();
   1.895 +
   1.896 +  So even though core may have been generated with a different page size settings, for now
   1.897 +  call getpagesize.
   1.898 +*/
   1.899 +
   1.900 +  return getpagesize();
   1.901 +}
   1.902 +
   1.903 +/*
   1.904 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   1.905 + * Method:      getThreadIntegerRegisterSet0
   1.906 + * Signature:   (J)[J
   1.907 + * Description: get gregset for a given thread specified by thread id
   1.908 + */
   1.909 +JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getThreadIntegerRegisterSet0
   1.910 +  (JNIEnv *env, jobject this_obj, jlong tid) {
   1.911 +  // map the thread id to thread handle
   1.912 +  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);
   1.913 +
   1.914 +  td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
   1.915 +  if (p_td_thragent_t == 0) {
   1.916 +     return 0;
   1.917 +  }
   1.918 +
   1.919 +  td_thrhandle_t thr_handle;
   1.920 +  if (p_td_ta_map_id2thr(p_td_thragent_t, (thread_t) tid, &thr_handle) != TD_OK) {
   1.921 +     THROW_NEW_DEBUGGER_EXCEPTION_("can't map thread id to thread handle!", 0);
   1.922 +  }
   1.923 +
   1.924 +  p_td_thr_getgregs_t p_td_thr_getgregs = (p_td_thr_getgregs_t) env->GetLongField(this_obj, p_td_thr_getgregs_ID);
   1.925 +  prgregset_t gregs;
   1.926 +  p_td_thr_getgregs(&thr_handle, gregs);
   1.927 +
   1.928 +  jlongArray res = env->NewLongArray(NPRGREG);
   1.929 +  CHECK_EXCEPTION_(0);
   1.930 +  jboolean isCopy;
   1.931 +  jlong* ptr = env->GetLongArrayElements(res, &isCopy);
   1.932 +  for (int i = 0; i < NPRGREG; i++) {
   1.933 +    ptr[i] = (jlong) (uintptr_t) gregs[i];
   1.934 +  }
   1.935 +  env->ReleaseLongArrayElements(res, ptr, JNI_COMMIT);
   1.936 +  return res;
   1.937 +}
   1.938 +
   1.939 +/*
   1.940 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   1.941 + * Method:      fillThreadList0
   1.942 + * Signature:   (Ljava/util/List;)V
   1.943 + * Description: fills thread list of the debuggee process/core
   1.944 + */
   1.945 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillThreadList0
   1.946 +  (JNIEnv *env, jobject this_obj, jobject list) {
   1.947 +
   1.948 +  td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
   1.949 +  if (p_td_thragent_t == 0) {
   1.950 +     return;
   1.951 +  }
   1.952 +
   1.953 +  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);
   1.954 +
   1.955 +  DebuggerWithObject dbgo;
   1.956 +  dbgo.env = env;
   1.957 +  dbgo.this_obj = this_obj;
   1.958 +  dbgo.obj = list;
   1.959 +
   1.960 +  p_td_ta_thr_iter(p_td_thragent_t, fill_thread_list, &dbgo,
   1.961 +                   TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
   1.962 +}
   1.963 +
   1.964 +/*
   1.965 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   1.966 + * Method:      fillCFrameList0
   1.967 + * Signature:   ([J)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;
   1.968 + * Description: fills CFrame list for a given thread
   1.969 + */
   1.970 +JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillCFrameList0
   1.971 +  (JNIEnv *env, jobject this_obj, jlongArray regsArray) {
   1.972 +  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
   1.973 +
   1.974 +  DebuggerWith2Objects dbgo2;
   1.975 +  dbgo2.env  = env;
   1.976 +  dbgo2.this_obj = this_obj;
   1.977 +  dbgo2.obj  = NULL;
   1.978 +  dbgo2.obj2 = NULL;
   1.979 +
   1.980 +  jboolean isCopy;
   1.981 +  jlong* ptr = env->GetLongArrayElements(regsArray, &isCopy);
   1.982 +  CHECK_EXCEPTION_(0);
   1.983 +
   1.984 +  prgregset_t gregs;
   1.985 +  for (int i = 0; i < NPRGREG; i++) {
   1.986 +     gregs[i] = (uintptr_t) ptr[i];
   1.987 +  }
   1.988 +
   1.989 +  env->ReleaseLongArrayElements(regsArray, ptr, JNI_ABORT);
   1.990 +  CHECK_EXCEPTION_(0);
   1.991 +  Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs, fill_cframe_list, &dbgo2);
   1.992 +  return dbgo2.obj;
   1.993 +}
   1.994 +
   1.995 +/*
   1.996 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
   1.997 + * Method:      fillLoadObjectList0
   1.998 + * Signature:   (Ljava/util/List;)V
   1.999 + * Description: fills shared objects of the debuggee process/core
  1.1000 + */
  1.1001 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillLoadObjectList0
  1.1002 +  (JNIEnv *env, jobject this_obj, jobject list) {
  1.1003 +  DebuggerWithObject dbgo;
  1.1004 +  dbgo.env = env;
  1.1005 +  dbgo.this_obj = this_obj;
  1.1006 +  dbgo.obj = list;
  1.1007 +
  1.1008 +  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1.1009 +  Pobject_iter((struct ps_prochandle*) p_ps_prochandle, fill_load_object_list, &dbgo);
  1.1010 +}
  1.1011 +
  1.1012 +/*
  1.1013 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1.1014 + * Method:      readBytesFromProcess0
  1.1015 + * Signature:   (JJ)[B
  1.1016 + * Description: read bytes from debuggee process/core
  1.1017 + */
  1.1018 +JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_readBytesFromProcess0
  1.1019 +  (JNIEnv *env, jobject this_obj, jlong address, jlong numBytes) {
  1.1020 +
  1.1021 +  jbyteArray array = env->NewByteArray(numBytes);
  1.1022 +  CHECK_EXCEPTION_(0);
  1.1023 +  jboolean isCopy;
  1.1024 +  jbyte* bufPtr = env->GetByteArrayElements(array, &isCopy);
  1.1025 +  CHECK_EXCEPTION_(0);
  1.1026 +
  1.1027 +  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1.1028 +  ps_err_e ret = ps_pread((struct ps_prochandle*) p_ps_prochandle,
  1.1029 +                       (psaddr_t)address, bufPtr, (size_t)numBytes);
  1.1030 +
  1.1031 +  if (ret != PS_OK) {
  1.1032 +    // part of the class sharing workaround. try shared heap area
  1.1033 +    int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);
  1.1034 +    if (classes_jsa_fd != -1 && address != (jlong)0) {
  1.1035 +      print_debug("read failed at 0x%lx, attempting shared heap area\n", (long) address);
  1.1036 +
  1.1037 +      struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID);
  1.1038 +      // walk through the shared mappings -- we just have 4 of them.
  1.1039 +      // so, linear walking is okay.
  1.1040 +      for (int m = 0; m < NUM_SHARED_MAPS; m++) {
  1.1041 +
  1.1042 +        // We can skip the non-read-only maps. These are mapped as MAP_PRIVATE
  1.1043 +        // and hence will be read by libproc. Besides, the file copy may be
  1.1044 +        // stale because the process might have modified those pages.
  1.1045 +        if (pheader->_space[m]._read_only) {
  1.1046 +          jlong baseAddress = (jlong) (uintptr_t) pheader->_space[m]._base;
  1.1047 +          size_t usedSize = pheader->_space[m]._used;
  1.1048 +          if (address >= baseAddress && address < (baseAddress + usedSize)) {
  1.1049 +            // the given address falls in this shared heap area
  1.1050 +            print_debug("found shared map at 0x%lx\n", (long) baseAddress);
  1.1051 +
  1.1052 +
  1.1053 +            // If more data is asked than actually mapped from file, we need to zero fill
  1.1054 +            // till the end-of-page boundary. But, java array new does that for us. we just
  1.1055 +            // need to read as much as data available.
  1.1056 +
  1.1057 +#define MIN2(x, y) (((x) < (y))? (x) : (y))
  1.1058 +
  1.1059 +            jlong diff = address - baseAddress;
  1.1060 +            jlong bytesToRead = MIN2(numBytes, usedSize - diff);
  1.1061 +            off_t offset = pheader->_space[m]._file_offset  + off_t(diff);
  1.1062 +            ssize_t bytesRead = pread(classes_jsa_fd, bufPtr, bytesToRead, offset);
  1.1063 +            if (bytesRead != bytesToRead) {
  1.1064 +              env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);
  1.1065 +              print_debug("shared map read failed\n");
  1.1066 +              return jbyteArray(0);
  1.1067 +            } else {
  1.1068 +              print_debug("shared map read succeeded\n");
  1.1069 +              env->ReleaseByteArrayElements(array, bufPtr, 0);
  1.1070 +              return array;
  1.1071 +            }
  1.1072 +          } // is in current map
  1.1073 +        } // is read only map
  1.1074 +      } // for shared maps
  1.1075 +    } // classes_jsa_fd != -1
  1.1076 +    env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);
  1.1077 +    return jbyteArray(0);
  1.1078 +  } else {
  1.1079 +    env->ReleaseByteArrayElements(array, bufPtr, 0);
  1.1080 +    return array;
  1.1081 +  }
  1.1082 +}
  1.1083 +
  1.1084 +/*
  1.1085 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1.1086 + * Method:      writeBytesToProcess0
  1.1087 + * Signature:   (JJ[B)V
  1.1088 + * Description: write bytes into debugger process
  1.1089 + */
  1.1090 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_writeBytesToProcess0
  1.1091 +  (JNIEnv *env, jobject this_obj, jlong address, jlong numBytes, jbyteArray data) {
  1.1092 +  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1.1093 +  jboolean isCopy;
  1.1094 +  jbyte* ptr = env->GetByteArrayElements(data, &isCopy);
  1.1095 +  CHECK_EXCEPTION;
  1.1096 +
  1.1097 +  if (ps_pwrite((struct ps_prochandle*) p_ps_prochandle, address, ptr, numBytes) != PS_OK) {
  1.1098 +     env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
  1.1099 +     THROW_NEW_DEBUGGER_EXCEPTION("Process write failed!");
  1.1100 +  }
  1.1101 +
  1.1102 +  env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
  1.1103 +}
  1.1104 +
  1.1105 +/*
  1.1106 + * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1.1107 + * Method:    suspend0
  1.1108 + * Signature: ()V
  1.1109 + */
  1.1110 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_suspend0
  1.1111 +  (JNIEnv *env, jobject this_obj) {
  1.1112 +  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1.1113 +  // for now don't check return value. revisit this again.
  1.1114 +  Pstop((struct ps_prochandle*) p_ps_prochandle, 1000);
  1.1115 +}
  1.1116 +
  1.1117 +/*
  1.1118 + * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1.1119 + * Method:    resume0
  1.1120 + * Signature: ()V
  1.1121 + */
  1.1122 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_resume0
  1.1123 +  (JNIEnv *env, jobject this_obj) {
  1.1124 +  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1.1125 +  // for now don't check return value. revisit this again.
  1.1126 +  Psetrun((struct ps_prochandle*) p_ps_prochandle, 0, PRCFAULT|PRSTOP);
  1.1127 +}
  1.1128 +
  1.1129 +/*
  1.1130 +  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1.1131 +  * Method:      lookupByName0
  1.1132 +  * Signature:   (Ljava/lang/String;Ljava/lang/String;)J
  1.1133 +  * Description: symbol lookup by name
  1.1134 +*/
  1.1135 +JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByName0
  1.1136 +   (JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
  1.1137 +   jlong p_ps_prochandle;
  1.1138 +   p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1.1139 +
  1.1140 +   jboolean isCopy;
  1.1141 +   const char* objectName_cstr = NULL;
  1.1142 +   if (objectName != NULL) {
  1.1143 +     objectName_cstr = env->GetStringUTFChars(objectName, &isCopy);
  1.1144 +     CHECK_EXCEPTION_(0);
  1.1145 +   } else {
  1.1146 +     objectName_cstr = PR_OBJ_EVERY;
  1.1147 +   }
  1.1148 +
  1.1149 +   const char* symbolName_cstr = env->GetStringUTFChars(symbolName, &isCopy);
  1.1150 +   CHECK_EXCEPTION_(0);
  1.1151 +
  1.1152 +   psaddr_t symbol_addr = (psaddr_t) 0;
  1.1153 +   ps_pglobal_lookup((struct ps_prochandle*) p_ps_prochandle,  objectName_cstr,
  1.1154 +                    symbolName_cstr, &symbol_addr);
  1.1155 +
  1.1156 +   if (symbol_addr == 0) {
  1.1157 +      print_debug("lookup for %s in %s failed\n", symbolName_cstr, objectName_cstr);
  1.1158 +   }
  1.1159 +
  1.1160 +   if (objectName_cstr != PR_OBJ_EVERY) {
  1.1161 +     env->ReleaseStringUTFChars(objectName, objectName_cstr);
  1.1162 +   }
  1.1163 +   env->ReleaseStringUTFChars(symbolName, symbolName_cstr);
  1.1164 +   return (jlong) (uintptr_t) symbol_addr;
  1.1165 +}
  1.1166 +
  1.1167 +/*
  1.1168 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1.1169 + * Method:      lookupByAddress0
  1.1170 + * Signature:   (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
  1.1171 + * Description: lookup symbol name for a given address
  1.1172 + */
  1.1173 +JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByAddress0
  1.1174 +   (JNIEnv *env, jobject this_obj, jlong address) {
  1.1175 +   jlong p_ps_prochandle;
  1.1176 +   p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
  1.1177 +
  1.1178 +   char nameBuf[SYMBOL_BUF_SIZE + 1];
  1.1179 +   GElf_Sym sym;
  1.1180 +   int res = Plookup_by_addr((struct ps_prochandle*) p_ps_prochandle, (uintptr_t) address,
  1.1181 +                                 nameBuf, sizeof(nameBuf), &sym);
  1.1182 +   if (res != 0) { // failed
  1.1183 +      return 0;
  1.1184 +   }
  1.1185 +
  1.1186 +   jstring resSym = env->NewStringUTF(nameBuf);
  1.1187 +   CHECK_EXCEPTION_(0);
  1.1188 +
  1.1189 +   return env->CallObjectMethod(this_obj, createClosestSymbol_ID, resSym, (address - sym.st_value));
  1.1190 +}
  1.1191 +
  1.1192 +/*
  1.1193 + * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1.1194 + * Method:    demangle0
  1.1195 + * Signature: (Ljava/lang/String;)Ljava/lang/String;
  1.1196 + */
  1.1197 +JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_demangle0
  1.1198 +  (JNIEnv *env, jobject this_object, jstring name) {
  1.1199 +  jboolean isCopy;
  1.1200 +  const char* ptr = env->GetStringUTFChars(name, &isCopy);
  1.1201 +  char  buf[2*SYMBOL_BUF_SIZE + 1];
  1.1202 +  jstring res = 0;
  1.1203 +  if (cplus_demangle((char*) ptr, buf, sizeof(buf)) != DEMANGLE_ESPACE) {
  1.1204 +    res = env->NewStringUTF(buf);
  1.1205 +  } else {
  1.1206 +    res = name;
  1.1207 +  }
  1.1208 +  env->ReleaseStringUTFChars(name, ptr);
  1.1209 +  return res;
  1.1210 +}
  1.1211 +
  1.1212 +typedef int (*find_file_hook_t)(const char *, int elf_checksum);
  1.1213 +
  1.1214 +/*
  1.1215 + * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
  1.1216 + * Method:      initIDs
  1.1217 + * Signature:   ()V
  1.1218 + * Description: get JNI ids for fields and methods of ProcDebuggerLocal class
  1.1219 + */
  1.1220 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_initIDs
  1.1221 +  (JNIEnv *env, jclass clazz) {
  1.1222 +  _libsaproc_debug = getenv("LIBSAPROC_DEBUG") != NULL;
  1.1223 +  if (_libsaproc_debug) {
  1.1224 +     // propagate debug mode to libproc.so
  1.1225 +     static const char* var = "LIBPROC_DEBUG=1";
  1.1226 +     putenv((char*)var);
  1.1227 +  }
  1.1228 +
  1.1229 +  void* libproc_handle = dlopen("libproc.so", RTLD_LAZY | RTLD_GLOBAL);
  1.1230 +  if (libproc_handle == 0)
  1.1231 +     THROW_NEW_DEBUGGER_EXCEPTION("can't load libproc.so, if you are using Solaris 5.7 or below, copy libproc.so from 5.8!");
  1.1232 +
  1.1233 +  // If possible, set shared object find file hook.
  1.1234 +  void (*set_hook)(find_file_hook_t) = (void(*)(find_file_hook_t))dlsym(libproc_handle, "Pset_find_file_hook");
  1.1235 +  if (set_hook) {
  1.1236 +    // we found find file hook symbol, set up our hook function.
  1.1237 +    set_hook(find_file_hook);
  1.1238 +  } else if (getenv(SA_ALTROOT)) {
  1.1239 +    printf("libsaproc WARNING: %s set, but can't set file hook. " \
  1.1240 +           "Did you use right version of libproc.so?\n", SA_ALTROOT);
  1.1241 +  }
  1.1242 +
  1.1243 +  p_ps_prochandle_ID = env->GetFieldID(clazz, "p_ps_prochandle", "J");
  1.1244 +  CHECK_EXCEPTION;
  1.1245 +
  1.1246 +  libthread_db_handle_ID = env->GetFieldID(clazz, "libthread_db_handle", "J");
  1.1247 +  CHECK_EXCEPTION;
  1.1248 +
  1.1249 +  p_td_thragent_t_ID = env->GetFieldID(clazz, "p_td_thragent_t", "J");
  1.1250 +  CHECK_EXCEPTION;
  1.1251 +
  1.1252 +  p_td_init_ID = env->GetFieldID(clazz, "p_td_init", "J");
  1.1253 +  CHECK_EXCEPTION;
  1.1254 +
  1.1255 +  p_td_ta_new_ID = env->GetFieldID(clazz, "p_td_ta_new", "J");
  1.1256 +  CHECK_EXCEPTION;
  1.1257 +
  1.1258 +  p_td_ta_delete_ID = env->GetFieldID(clazz, "p_td_ta_delete", "J");
  1.1259 +  CHECK_EXCEPTION;
  1.1260 +
  1.1261 +  p_td_ta_thr_iter_ID = env->GetFieldID(clazz, "p_td_ta_thr_iter", "J");
  1.1262 +  CHECK_EXCEPTION;
  1.1263 +
  1.1264 +  p_td_thr_get_info_ID = env->GetFieldID(clazz, "p_td_thr_get_info", "J");
  1.1265 +  CHECK_EXCEPTION;
  1.1266 +
  1.1267 +  p_td_ta_map_id2thr_ID = env->GetFieldID(clazz, "p_td_ta_map_id2thr", "J");
  1.1268 +  CHECK_EXCEPTION;
  1.1269 +
  1.1270 +  p_td_thr_getgregs_ID = env->GetFieldID(clazz, "p_td_thr_getgregs", "J");
  1.1271 +  CHECK_EXCEPTION;
  1.1272 +
  1.1273 +  getThreadForThreadId_ID = env->GetMethodID(clazz,
  1.1274 +                            "getThreadForThreadId", "(J)Lsun/jvm/hotspot/debugger/ThreadProxy;");
  1.1275 +  CHECK_EXCEPTION;
  1.1276 +
  1.1277 +  pcRegIndex_ID = env->GetFieldID(clazz, "pcRegIndex", "I");
  1.1278 +  CHECK_EXCEPTION;
  1.1279 +
  1.1280 +  fpRegIndex_ID = env->GetFieldID(clazz, "fpRegIndex", "I");
  1.1281 +  CHECK_EXCEPTION;
  1.1282 +
  1.1283 +  createSenderFrame_ID = env->GetMethodID(clazz,
  1.1284 +                            "createSenderFrame", "(Lsun/jvm/hotspot/debugger/proc/ProcCFrame;JJ)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;");
  1.1285 +  CHECK_EXCEPTION;
  1.1286 +
  1.1287 +  createLoadObject_ID = env->GetMethodID(clazz,
  1.1288 +                            "createLoadObject", "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");
  1.1289 +  CHECK_EXCEPTION;
  1.1290 +
  1.1291 +  createClosestSymbol_ID = env->GetMethodID(clazz,
  1.1292 +                            "createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
  1.1293 +  CHECK_EXCEPTION;
  1.1294 +
  1.1295 +  listAdd_ID = env->GetMethodID(env->FindClass("java/util/List"), "add", "(Ljava/lang/Object;)Z");
  1.1296 +  CHECK_EXCEPTION;
  1.1297 +
  1.1298 +  // part of the class sharing workaround
  1.1299 +  classes_jsa_fd_ID = env->GetFieldID(clazz, "classes_jsa_fd", "I");
  1.1300 +  CHECK_EXCEPTION;
  1.1301 +  p_file_map_header_ID = env->GetFieldID(clazz, "p_file_map_header", "J");
  1.1302 +  CHECK_EXCEPTION;
  1.1303 +}

mercurial