Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/agent/src/os/solaris/proc/saproc.cpp
38840 views
/*1* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "salibproc.h"25#include "sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal.h"26#ifndef SOLARIS_11_B159_OR_LATER27#include <sys/utsname.h>28#endif29#include <thread_db.h>30#include <strings.h>31#include <limits.h>32#include <demangle.h>33#include <stdarg.h>34#include <stdlib.h>35#include <errno.h>3637#define CHECK_EXCEPTION_(value) if(env->ExceptionOccurred()) { return value; }38#define CHECK_EXCEPTION if(env->ExceptionOccurred()) { return;}39#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throwNewDebuggerException(env, str); return value; }40#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throwNewDebuggerException(env, str); return;}4142#define SYMBOL_BUF_SIZE 25643#define ERR_MSG_SIZE (PATH_MAX + 256)4445// debug modes46static int _libsaproc_debug = 0;47#ifndef SOLARIS_11_B159_OR_LATER48static bool _Pstack_iter_debug = false;4950static void dprintf_2(const char* format,...) {51if (_Pstack_iter_debug) {52va_list alist;5354va_start(alist, format);55fputs("Pstack_iter DEBUG: ", stderr);56vfprintf(stderr, format, alist);57va_end(alist);58}59}60#endif // !SOLARIS_11_B159_OR_LATER6162static void print_debug(const char* format,...) {63if (_libsaproc_debug) {64va_list alist;6566va_start(alist, format);67fputs("libsaproc DEBUG: ", stderr);68vfprintf(stderr, format, alist);69va_end(alist);70}71}7273struct Debugger {74JNIEnv* env;75jobject this_obj;76};7778struct DebuggerWithObject : Debugger {79jobject obj;80};8182struct DebuggerWith2Objects : DebuggerWithObject {83jobject obj2;84};8586/*87* Portions of user thread level detail gathering code is from pstack source88* code. See pstack.c in Solaris 2.8 user commands source code.89*/9091static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) {92env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg);93}9495// JNI ids for some fields, methods9697// libproc handler pointer98static jfieldID p_ps_prochandle_ID = 0;99100// libthread.so dlopen handle, thread agent ptr and function pointers101static jfieldID libthread_db_handle_ID = 0;102static jfieldID p_td_thragent_t_ID = 0;103static jfieldID p_td_init_ID = 0;104static jfieldID p_td_ta_new_ID = 0;105static jfieldID p_td_ta_delete_ID = 0;106static jfieldID p_td_ta_thr_iter_ID = 0;107static jfieldID p_td_thr_get_info_ID = 0;108static jfieldID p_td_ta_map_id2thr_ID = 0;109static jfieldID p_td_thr_getgregs_ID = 0;110111// reg index fields112static jfieldID pcRegIndex_ID = 0;113static jfieldID fpRegIndex_ID = 0;114115// part of the class sharing workaround116static jfieldID classes_jsa_fd_ID = 0;117static jfieldID p_file_map_header_ID = 0;118119// method ids120121static jmethodID getThreadForThreadId_ID = 0;122static jmethodID createSenderFrame_ID = 0;123static jmethodID createLoadObject_ID = 0;124static jmethodID createClosestSymbol_ID = 0;125static jmethodID listAdd_ID = 0;126127/*128* Functions we need from libthread_db129*/130typedef td_err_e131(*p_td_init_t)(void);132typedef td_err_e133(*p_td_ta_new_t)(void *, td_thragent_t **);134typedef td_err_e135(*p_td_ta_delete_t)(td_thragent_t *);136typedef td_err_e137(*p_td_ta_thr_iter_t)(const td_thragent_t *, td_thr_iter_f *, void *,138td_thr_state_e, int, sigset_t *, unsigned);139typedef td_err_e140(*p_td_thr_get_info_t)(const td_thrhandle_t *, td_thrinfo_t *);141typedef td_err_e142(*p_td_ta_map_id2thr_t)(const td_thragent_t *, thread_t, td_thrhandle_t *);143typedef td_err_e144(*p_td_thr_getgregs_t)(const td_thrhandle_t *, prgregset_t);145146static void147clear_libthread_db_ptrs(JNIEnv* env, jobject this_obj) {148// release libthread_db agent, if we had created149p_td_ta_delete_t p_td_ta_delete = 0;150p_td_ta_delete = (p_td_ta_delete_t) env->GetLongField(this_obj, p_td_ta_delete_ID);151152td_thragent_t *p_td_thragent_t = 0;153p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);154if (p_td_thragent_t != 0 && p_td_ta_delete != 0) {155p_td_ta_delete(p_td_thragent_t);156}157158// dlclose libthread_db.so159void* libthread_db_handle = (void*) env->GetLongField(this_obj, libthread_db_handle_ID);160if (libthread_db_handle != 0) {161dlclose(libthread_db_handle);162}163164env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)0);165env->SetLongField(this_obj, p_td_init_ID, (jlong)0);166env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)0);167env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)0);168env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)0);169env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)0);170env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)0);171env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)0);172}173174175static void detach_internal(JNIEnv* env, jobject this_obj) {176// clear libthread_db stuff177clear_libthread_db_ptrs(env, this_obj);178179// release ptr to ps_prochandle180jlong p_ps_prochandle;181p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);182if (p_ps_prochandle != 0L) {183Prelease((struct ps_prochandle*) p_ps_prochandle, PRELEASE_CLEAR);184}185186// part of the class sharing workaround187int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);188if (classes_jsa_fd != -1) {189close(classes_jsa_fd);190struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID);191if (pheader != NULL) {192free(pheader);193}194}195}196197// Is it okay to ignore libthread_db failure? Set env var to ignore198// libthread_db failure. You can still debug, but will miss threads199// related functionality.200static bool sa_ignore_threaddb = (getenv("SA_IGNORE_THREADDB") != 0);201202#define HANDLE_THREADDB_FAILURE(msg) \203if (sa_ignore_threaddb) { \204printf("libsaproc WARNING: %s\n", msg); \205return; \206} else { \207THROW_NEW_DEBUGGER_EXCEPTION(msg); \208}209210#define HANDLE_THREADDB_FAILURE_(msg, ret) \211if (sa_ignore_threaddb) { \212printf("libsaproc WARNING: %s\n", msg); \213return ret; \214} else { \215THROW_NEW_DEBUGGER_EXCEPTION_(msg, ret); \216}217218static const char * alt_root = NULL;219static int alt_root_len = -1;220221#define SA_ALTROOT "SA_ALTROOT"222223static void init_alt_root() {224if (alt_root_len == -1) {225alt_root = getenv(SA_ALTROOT);226if (alt_root)227alt_root_len = strlen(alt_root);228else229alt_root_len = 0;230}231}232233// This function is a complete substitute for the open system call234// since it's also used to override open calls from libproc to235// implement as a pathmap style facility for the SA. If libproc236// starts using other interfaces then this might have to extended to237// cover other calls.238extern "C" int libsaproc_open(const char * name, int oflag, ...) {239if (oflag == O_RDONLY) {240init_alt_root();241242if (_libsaproc_debug) {243printf("libsaproc DEBUG: libsaproc_open %s\n", name);244}245246if (alt_root_len > 0) {247int fd = -1;248char alt_path[PATH_MAX+1];249250strcpy(alt_path, alt_root);251strcat(alt_path, name);252fd = open(alt_path, O_RDONLY);253if (fd >= 0) {254if (_libsaproc_debug) {255printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path);256}257return fd;258}259260if (strrchr(name, '/')) {261strcpy(alt_path, alt_root);262strcat(alt_path, strrchr(name, '/'));263fd = open(alt_path, O_RDONLY);264if (fd >= 0) {265if (_libsaproc_debug) {266printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path);267}268return fd;269}270}271}272}273274{275mode_t mode;276va_list ap;277va_start(ap, oflag);278mode = va_arg(ap, mode_t);279va_end(ap);280281return open(name, oflag, mode);282}283}284285286static void * pathmap_dlopen(const char * name, int mode) {287init_alt_root();288289if (_libsaproc_debug) {290printf("libsaproc DEBUG: pathmap_dlopen %s\n", name);291}292293void * handle = NULL;294if (alt_root_len > 0) {295char alt_path[PATH_MAX+1];296strcpy(alt_path, alt_root);297strcat(alt_path, name);298handle = dlopen(alt_path, mode);299if (_libsaproc_debug && handle) {300printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);301}302303if (handle == NULL && strrchr(name, '/')) {304strcpy(alt_path, alt_root);305strcat(alt_path, strrchr(name, '/'));306handle = dlopen(alt_path, mode);307if (_libsaproc_debug && handle) {308printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);309}310}311}312if (handle == NULL) {313handle = dlopen(name, mode);314}315if (_libsaproc_debug) {316printf("libsaproc DEBUG: pathmap_dlopen %s return 0x%lx\n", name, (unsigned long) handle);317}318return handle;319}320321// libproc and libthread_db callback functions322323extern "C" {324325static int326init_libthread_db_ptrs(void *cd, const prmap_t *pmp, const char *object_name) {327Debugger* dbg = (Debugger*) cd;328JNIEnv* env = dbg->env;329jobject this_obj = dbg->this_obj;330struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);331332char *s1 = 0, *s2 = 0;333char libthread_db[PATH_MAX];334335if (strstr(object_name, "/libthread.so.") == NULL)336return (0);337338/*339* We found a libthread.340* dlopen() the matching libthread_db and get the thread agent handle.341*/342if (Pstatus(ph)->pr_dmodel == PR_MODEL_NATIVE) {343(void) strcpy(libthread_db, object_name);344s1 = (char*) strstr(object_name, ".so.");345s2 = (char*) strstr(libthread_db, ".so.");346(void) strcpy(s2, "_db");347s2 += 3;348(void) strcpy(s2, s1);349} else {350#ifdef _LP64351/*352* The victim process is 32-bit, we are 64-bit.353* We have to find the 64-bit version of libthread_db354* that matches the victim's 32-bit version of libthread.355*/356(void) strcpy(libthread_db, object_name);357s1 = (char*) strstr(object_name, "/libthread.so.");358s2 = (char*) strstr(libthread_db, "/libthread.so.");359(void) strcpy(s2, "/64");360s2 += 3;361(void) strcpy(s2, s1);362s1 = (char*) strstr(s1, ".so.");363s2 = (char*) strstr(s2, ".so.");364(void) strcpy(s2, "_db");365s2 += 3;366(void) strcpy(s2, s1);367#else368return (0);369#endif /* _LP64 */370}371372void* libthread_db_handle = 0;373if ((libthread_db_handle = pathmap_dlopen(libthread_db, RTLD_LAZY|RTLD_LOCAL)) == NULL) {374char errMsg[PATH_MAX + 256];375sprintf(errMsg, "Can't load %s!", libthread_db);376HANDLE_THREADDB_FAILURE_(errMsg, 0);377}378env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)(uintptr_t)libthread_db_handle);379380void* tmpPtr = 0;381tmpPtr = dlsym(libthread_db_handle, "td_init");382if (tmpPtr == 0) {383HANDLE_THREADDB_FAILURE_("dlsym failed on td_init!", 0);384}385env->SetLongField(this_obj, p_td_init_ID, (jlong)(uintptr_t) tmpPtr);386387tmpPtr =dlsym(libthread_db_handle, "td_ta_new");388if (tmpPtr == 0) {389HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_new!", 0);390}391env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)(uintptr_t) tmpPtr);392393tmpPtr = dlsym(libthread_db_handle, "td_ta_delete");394if (tmpPtr == 0) {395HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_delete!", 0);396}397env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)(uintptr_t) tmpPtr);398399tmpPtr = dlsym(libthread_db_handle, "td_ta_thr_iter");400if (tmpPtr == 0) {401HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_thr_iter!", 0);402}403env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)(uintptr_t) tmpPtr);404405tmpPtr = dlsym(libthread_db_handle, "td_thr_get_info");406if (tmpPtr == 0) {407HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_get_info!", 0);408}409env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)(uintptr_t) tmpPtr);410411tmpPtr = dlsym(libthread_db_handle, "td_ta_map_id2thr");412if (tmpPtr == 0) {413HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_map_id2thr!", 0);414}415env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)(uintptr_t) tmpPtr);416417tmpPtr = dlsym(libthread_db_handle, "td_thr_getgregs");418if (tmpPtr == 0) {419HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_getgregs!", 0);420}421env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)(uintptr_t) tmpPtr);422423return 1;424}425426static int427fill_thread_list(const td_thrhandle_t *p_td_thragent_t, void* cd) {428DebuggerWithObject* dbgo = (DebuggerWithObject*) cd;429JNIEnv* env = dbgo->env;430jobject this_obj = dbgo->this_obj;431jobject list = dbgo->obj;432433td_thrinfo_t thrinfo;434p_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);435436if (p_td_thr_get_info(p_td_thragent_t, &thrinfo) != TD_OK)437return (0);438439jobject threadProxy = env->CallObjectMethod(this_obj, getThreadForThreadId_ID, (jlong)(uintptr_t) thrinfo.ti_tid);440CHECK_EXCEPTION_(1);441env->CallBooleanMethod(list, listAdd_ID, threadProxy);442CHECK_EXCEPTION_(1);443return 0;444}445446static int447fill_load_object_list(void *cd, const prmap_t* pmp, const char* obj_name) {448449if (obj_name) {450DebuggerWithObject* dbgo = (DebuggerWithObject*) cd;451JNIEnv* env = dbgo->env;452jobject this_obj = dbgo->this_obj;453jobject list = dbgo->obj;454455jstring objectName = env->NewStringUTF(obj_name);456CHECK_EXCEPTION_(1);457458jlong mapSize = (jlong) pmp->pr_size;459jobject sharedObject = env->CallObjectMethod(this_obj, createLoadObject_ID,460objectName, mapSize, (jlong)(uintptr_t)pmp->pr_vaddr);461CHECK_EXCEPTION_(1);462env->CallBooleanMethod(list, listAdd_ID, sharedObject);463CHECK_EXCEPTION_(1);464}465466return 0;467}468469// Pstack_iter() proc_stack_f callback prior to Nevada-B159470static int471fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc, const long *argv) {472DebuggerWith2Objects* dbgo2 = (DebuggerWith2Objects*) cd;473JNIEnv* env = dbgo2->env;474jobject this_obj = dbgo2->this_obj;475jobject curFrame = dbgo2->obj2;476477jint pcRegIndex = env->GetIntField(this_obj, pcRegIndex_ID);478jint fpRegIndex = env->GetIntField(this_obj, fpRegIndex_ID);479480jlong pc = (jlong) (uintptr_t) regs[pcRegIndex];481jlong fp = (jlong) (uintptr_t) regs[fpRegIndex];482483dbgo2->obj2 = env->CallObjectMethod(this_obj, createSenderFrame_ID,484curFrame, pc, fp);485CHECK_EXCEPTION_(1);486if (dbgo2->obj == 0) {487dbgo2->obj = dbgo2->obj2;488}489return 0;490}491492// Pstack_iter() proc_stack_f callback in Nevada-B159 or later493/*ARGSUSED*/494static int495wrapper_fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc,496const long *argv, int frame_flags, int sig) {497return(fill_cframe_list(cd, regs, argc, argv));498}499500// part of the class sharing workaround501502// FIXME: !!HACK ALERT!!503504// The format of sharing achive file header is needed to read shared heap505// file mappings. For now, I am hard coding portion of FileMapHeader here.506// Refer to filemap.hpp.507508// FileMapHeader describes the shared space data in the file to be509// mapped. This structure gets written to a file. It is not a class, so510// that the compilers don't add any compiler-private data to it.511512const int NUM_SHARED_MAPS = 4;513514// Refer to FileMapInfo::_current_version in filemap.hpp515const int CURRENT_ARCHIVE_VERSION = 1;516517struct FileMapHeader {518int _magic; // identify file type.519int _version; // (from enum, above.)520size_t _alignment; // how shared archive should be aligned521522523struct space_info {524int _file_offset; // sizeof(this) rounded to vm page size525char* _base; // copy-on-write base address526size_t _capacity; // for validity checking527size_t _used; // for setting space top on read528529bool _read_only; // read only space?530bool _allow_exec; // executable code in space?531532} _space[NUM_SHARED_MAPS];533534// Ignore the rest of the FileMapHeader. We don't need those fields here.535};536537static bool538read_jboolean(struct ps_prochandle* ph, psaddr_t addr, jboolean* pvalue) {539jboolean i;540if (ps_pread(ph, addr, &i, sizeof(i)) == PS_OK) {541*pvalue = i;542return true;543} else {544return false;545}546}547548static bool549read_pointer(struct ps_prochandle* ph, psaddr_t addr, uintptr_t* pvalue) {550uintptr_t uip;551if (ps_pread(ph, addr, &uip, sizeof(uip)) == PS_OK) {552*pvalue = uip;553return true;554} else {555return false;556}557}558559static bool560read_string(struct ps_prochandle* ph, psaddr_t addr, char* buf, size_t size) {561char ch = ' ';562size_t i = 0;563564while (ch != '\0') {565if (ps_pread(ph, addr, &ch, sizeof(ch)) != PS_OK)566return false;567568if (i < size - 1) {569buf[i] = ch;570} else { // smaller buffer571return false;572}573574i++; addr++;575}576577buf[i] = '\0';578return true;579}580581#define USE_SHARED_SPACES_SYM "UseSharedSpaces"582// mangled symbol name for Arguments::SharedArchivePath583#define SHARED_ARCHIVE_PATH_SYM "__1cJArgumentsRSharedArchivePath_"584585static int586init_classsharing_workaround(void *cd, const prmap_t* pmap, const char* obj_name) {587Debugger* dbg = (Debugger*) cd;588JNIEnv* env = dbg->env;589jobject this_obj = dbg->this_obj;590const char* jvm_name = 0;591if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL) {592jvm_name = obj_name;593} else {594return 0;595}596597struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);598599// initialize classes.jsa file descriptor field.600dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, -1);601602// check whether class sharing is on by reading variable "UseSharedSpaces"603psaddr_t useSharedSpacesAddr = 0;604ps_pglobal_lookup(ph, jvm_name, USE_SHARED_SPACES_SYM, &useSharedSpacesAddr);605if (useSharedSpacesAddr == 0) {606THROW_NEW_DEBUGGER_EXCEPTION_("can't find 'UseSharedSpaces' flag\n", 1);607}608609// read the value of the flag "UseSharedSpaces"610// Since hotspot types are not available to build this library. So611// equivalent type "jboolean" is used to read the value of "UseSharedSpaces"612// which is same as hotspot type "bool".613jboolean value = 0;614if (read_jboolean(ph, useSharedSpacesAddr, &value) != true) {615THROW_NEW_DEBUGGER_EXCEPTION_("can't read 'UseSharedSpaces' flag", 1);616} else if ((int)value == 0) {617print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");618return 1;619}620621char classes_jsa[PATH_MAX];622psaddr_t sharedArchivePathAddrAddr = 0;623ps_pglobal_lookup(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM, &sharedArchivePathAddrAddr);624if (sharedArchivePathAddrAddr == 0) {625print_debug("can't find symbol 'Arguments::SharedArchivePath'\n");626THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);627}628629uintptr_t sharedArchivePathAddr = 0;630if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {631print_debug("can't find read pointer 'Arguments::SharedArchivePath'\n");632THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);633}634635if (read_string(ph, (psaddr_t)sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {636print_debug("can't find read 'Arguments::SharedArchivePath' value\n");637THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);638}639640print_debug("looking for %s\n", classes_jsa);641642// open the classes.jsa643int fd = libsaproc_open(classes_jsa, O_RDONLY);644if (fd < 0) {645char errMsg[ERR_MSG_SIZE];646sprintf(errMsg, "can't open shared archive file %s", classes_jsa);647THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);648} else {649print_debug("opened shared archive file %s\n", classes_jsa);650}651652// parse classes.jsa653struct FileMapHeader* pheader = (struct FileMapHeader*) malloc(sizeof(struct FileMapHeader));654if (pheader == NULL) {655close(fd);656THROW_NEW_DEBUGGER_EXCEPTION_("can't allocate memory for shared file map header", 1);657}658659memset(pheader, 0, sizeof(struct FileMapHeader));660// read FileMapHeader661size_t n = read(fd, pheader, sizeof(struct FileMapHeader));662if (n != sizeof(struct FileMapHeader)) {663char errMsg[ERR_MSG_SIZE];664sprintf(errMsg, "unable to read shared archive file map header from %s", classes_jsa);665close(fd);666free(pheader);667THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);668}669670// check file magic671if (pheader->_magic != 0xf00baba2) {672char errMsg[ERR_MSG_SIZE];673sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0xf00baba2",674classes_jsa, pheader->_magic);675close(fd);676free(pheader);677THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);678}679680// check version681if (pheader->_version != CURRENT_ARCHIVE_VERSION) {682char errMsg[ERR_MSG_SIZE];683sprintf(errMsg, "%s has wrong shared archive version %d, expecting %d",684classes_jsa, pheader->_version, CURRENT_ARCHIVE_VERSION);685close(fd);686free(pheader);687THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);688}689690if (_libsaproc_debug) {691for (int m = 0; m < NUM_SHARED_MAPS; m++) {692print_debug("shared file offset %d mapped at 0x%lx, size = %ld, read only? = %d\n",693pheader->_space[m]._file_offset, pheader->_space[m]._base,694pheader->_space[m]._used, pheader->_space[m]._read_only);695}696}697698// FIXME: For now, omitting other checks such as VM version etc.699700// store class archive file fd and map header in debugger object fields701dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, fd);702dbg->env->SetLongField(this_obj, p_file_map_header_ID, (jlong)(uintptr_t) pheader);703return 1;704}705706} // extern "C"707708// error messages for proc_arg_grab failure codes. The messages are709// modified versions of comments against corresponding #defines in710// libproc.h.711static const char* proc_arg_grab_errmsgs[] = {712"",713/* G_NOPROC */ "No such process",714/* G_NOCORE */ "No such core file",715/* G_NOPROCORCORE */ "No such process or core",716/* G_NOEXEC */ "Cannot locate executable file",717/* G_ZOMB */ "Zombie processs",718/* G_PERM */ "No permission to attach",719/* G_BUSY */ "Another process has already attached",720/* G_SYS */ "System process - can not attach",721/* G_SELF */ "Process is self - can't debug myself!",722/* G_INTR */ "Interrupt received while grabbing",723/* G_LP64 */ "debuggee is 64 bit, use java -d64 for debugger",724/* G_FORMAT */ "File is not an ELF format core file - corrupted core?",725/* G_ELF */ "Libelf error while parsing an ELF file",726/* G_NOTE */ "Required PT_NOTE Phdr not present - corrupted core?",727};728729static void attach_internal(JNIEnv* env, jobject this_obj, jstring cmdLine, jboolean isProcess) {730jboolean isCopy;731int gcode;732const char* cmdLine_cstr = env->GetStringUTFChars(cmdLine, &isCopy);733CHECK_EXCEPTION;734735// some older versions of libproc.so crash when trying to attach 32 bit736// debugger to 64 bit core file. check and throw error.737#ifndef _LP64738atoi(cmdLine_cstr);739if (errno) {740// core file741int core_fd;742if ((core_fd = open64(cmdLine_cstr, O_RDONLY)) >= 0) {743Elf32_Ehdr e32;744if (pread64(core_fd, &e32, sizeof (e32), 0) == sizeof (e32) &&745memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0 &&746e32.e_type == ET_CORE && e32.e_ident[EI_CLASS] == ELFCLASS64) {747close(core_fd);748THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use java -d64 for debugger");749}750close(core_fd);751}752// all other conditions are handled by libproc.so.753}754#endif755756// connect to process/core757ps_prochandle_t* ph = proc_arg_grab(cmdLine_cstr, (isProcess? PR_ARG_PIDS : PR_ARG_CORES), PGRAB_FORCE, &gcode, NULL);758759env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr);760if (! ph) {761if (gcode > 0 && gcode < sizeof(proc_arg_grab_errmsgs)/sizeof(const char*)) {762char errMsg[ERR_MSG_SIZE];763sprintf(errMsg, "Attach failed : %s", proc_arg_grab_errmsgs[gcode]);764THROW_NEW_DEBUGGER_EXCEPTION(errMsg);765} else {766if (_libsaproc_debug && gcode == G_STRANGE) {767perror("libsaproc DEBUG: ");768}769if (isProcess) {770THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to process!");771} else {772THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to core file!");773}774}775}776777// even though libproc.so supports 64 bit debugger and 32 bit debuggee, we don't778// support such cross-bit-debugging. check for that combination and throw error.779#ifdef _LP64780int data_model;781if (ps_pdmodel(ph, &data_model) != PS_OK) {782Prelease(ph, PRELEASE_CLEAR);783THROW_NEW_DEBUGGER_EXCEPTION("can't determine debuggee data model (ILP32? or LP64?)");784}785if (data_model == PR_MODEL_ILP32) {786Prelease(ph, PRELEASE_CLEAR);787THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger");788}789#endif790791env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(uintptr_t)ph);792793Debugger dbg;794dbg.env = env;795dbg.this_obj = this_obj;796jthrowable exception = 0;797if (! isProcess) {798/*799* With class sharing, shared perm. gen heap is allocated in with MAP_SHARED|PROT_READ.800* These pages are mapped from the file "classes.jsa". MAP_SHARED pages are not dumped801* in Solaris core.To read shared heap pages, we have to read classes.jsa file.802*/803Pobject_iter(ph, init_classsharing_workaround, &dbg);804exception = env->ExceptionOccurred();805if (exception) {806env->ExceptionClear();807detach_internal(env, this_obj);808env->Throw(exception);809return;810}811}812813/*814* Iterate over the process mappings looking815* for libthread and then dlopen the appropriate816* libthread_db and get function pointers.817*/818Pobject_iter(ph, init_libthread_db_ptrs, &dbg);819exception = env->ExceptionOccurred();820if (exception) {821env->ExceptionClear();822if (!sa_ignore_threaddb) {823detach_internal(env, this_obj);824env->Throw(exception);825}826return;827}828829// init libthread_db and create thread_db agent830p_td_init_t p_td_init = (p_td_init_t) env->GetLongField(this_obj, p_td_init_ID);831if (p_td_init == 0) {832if (!sa_ignore_threaddb) {833detach_internal(env, this_obj);834}835HANDLE_THREADDB_FAILURE("Did not find libthread in target process/core!");836}837838if (p_td_init() != TD_OK) {839if (!sa_ignore_threaddb) {840detach_internal(env, this_obj);841}842HANDLE_THREADDB_FAILURE("Can't initialize thread_db!");843}844845p_td_ta_new_t p_td_ta_new = (p_td_ta_new_t) env->GetLongField(this_obj, p_td_ta_new_ID);846847td_thragent_t *p_td_thragent_t = 0;848if (p_td_ta_new(ph, &p_td_thragent_t) != TD_OK) {849if (!sa_ignore_threaddb) {850detach_internal(env, this_obj);851}852HANDLE_THREADDB_FAILURE("Can't create thread_db agent!");853}854env->SetLongField(this_obj, p_td_thragent_t_ID, (jlong)(uintptr_t) p_td_thragent_t);855856}857858/*859* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal860* Method: attach0861* Signature: (Ljava/lang/String;)V862* Description: process detach863*/864JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2865(JNIEnv *env, jobject this_obj, jstring pid) {866attach_internal(env, this_obj, pid, JNI_TRUE);867}868869/*870* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal871* Method: attach0872* Signature: (Ljava/lang/String;Ljava/lang/String;)V873* Description: core file detach874*/875JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2876(JNIEnv *env, jobject this_obj, jstring executable, jstring corefile) {877// ignore executable file name, libproc.so can detect a.out name anyway.878attach_internal(env, this_obj, corefile, JNI_FALSE);879}880881882/*883* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal884* Method: detach0885* Signature: ()V886* Description: process/core file detach887*/888JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_detach0889(JNIEnv *env, jobject this_obj) {890detach_internal(env, this_obj);891}892893/*894* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal895* Method: getRemoteProcessAddressSize0896* Signature: ()I897* Description: get process/core address size898*/899JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getRemoteProcessAddressSize0900(JNIEnv *env, jobject this_obj) {901jlong p_ps_prochandle;902p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);903int data_model = PR_MODEL_ILP32;904ps_pdmodel((struct ps_prochandle*) p_ps_prochandle, &data_model);905print_debug("debuggee is %d bit\n", data_model == PR_MODEL_ILP32? 32 : 64);906return (jint) data_model == PR_MODEL_ILP32? 32 : 64;907}908909/*910* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal911* Method: getPageSize0912* Signature: ()I913* Description: get process/core page size914*/915JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getPageSize0916(JNIEnv *env, jobject this_obj) {917918/*919We are not yet attached to a java process or core file. getPageSize is called from920the constructor of ProcDebuggerLocal. The following won't work!921922jlong p_ps_prochandle;923p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);924CHECK_EXCEPTION_(-1);925struct ps_prochandle* prochandle = (struct ps_prochandle*) p_ps_prochandle;926return (Pstate(prochandle) == PS_DEAD) ? Pgetauxval(prochandle, AT_PAGESZ)927: getpagesize();928929So even though core may have been generated with a different page size settings, for now930call getpagesize.931*/932933return getpagesize();934}935936/*937* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal938* Method: getThreadIntegerRegisterSet0939* Signature: (J)[J940* Description: get gregset for a given thread specified by thread id941*/942JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getThreadIntegerRegisterSet0943(JNIEnv *env, jobject this_obj, jlong tid) {944// map the thread id to thread handle945p_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);946947td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);948if (p_td_thragent_t == 0) {949return 0;950}951952td_thrhandle_t thr_handle;953if (p_td_ta_map_id2thr(p_td_thragent_t, (thread_t) tid, &thr_handle) != TD_OK) {954THROW_NEW_DEBUGGER_EXCEPTION_("can't map thread id to thread handle!", 0);955}956957p_td_thr_getgregs_t p_td_thr_getgregs = (p_td_thr_getgregs_t) env->GetLongField(this_obj, p_td_thr_getgregs_ID);958prgregset_t gregs;959p_td_thr_getgregs(&thr_handle, gregs);960961jlongArray res = env->NewLongArray(NPRGREG);962CHECK_EXCEPTION_(0);963jboolean isCopy;964jlong* ptr = env->GetLongArrayElements(res, &isCopy);965for (int i = 0; i < NPRGREG; i++) {966ptr[i] = (jlong) (uintptr_t) gregs[i];967}968env->ReleaseLongArrayElements(res, ptr, JNI_COMMIT);969return res;970}971972/*973* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal974* Method: fillThreadList0975* Signature: (Ljava/util/List;)V976* Description: fills thread list of the debuggee process/core977*/978JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillThreadList0979(JNIEnv *env, jobject this_obj, jobject list) {980981td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);982if (p_td_thragent_t == 0) {983return;984}985986p_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);987988DebuggerWithObject dbgo;989dbgo.env = env;990dbgo.this_obj = this_obj;991dbgo.obj = list;992993p_td_ta_thr_iter(p_td_thragent_t, fill_thread_list, &dbgo,994TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);995}996997#ifndef SOLARIS_11_B159_OR_LATER998// building on Nevada-B158 or earlier so more hoops to jump through999static bool has_newer_Pstack_iter = false; // older version by default1000#endif10011002/*1003* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1004* Method: fillCFrameList01005* Signature: ([J)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;1006* Description: fills CFrame list for a given thread1007*/1008JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillCFrameList01009(JNIEnv *env, jobject this_obj, jlongArray regsArray) {1010jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);10111012DebuggerWith2Objects dbgo2;1013dbgo2.env = env;1014dbgo2.this_obj = this_obj;1015dbgo2.obj = NULL;1016dbgo2.obj2 = NULL;10171018jboolean isCopy;1019jlong* ptr = env->GetLongArrayElements(regsArray, &isCopy);1020CHECK_EXCEPTION_(0);10211022prgregset_t gregs;1023for (int i = 0; i < NPRGREG; i++) {1024gregs[i] = (uintptr_t) ptr[i];1025}10261027env->ReleaseLongArrayElements(regsArray, ptr, JNI_ABORT);1028CHECK_EXCEPTION_(0);10291030#ifdef SOLARIS_11_B159_OR_LATER1031// building on Nevada-B159 or later so use the new callback1032Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,1033wrapper_fill_cframe_list, &dbgo2);1034#else1035// building on Nevada-B158 or earlier so figure out which callback to use10361037if (has_newer_Pstack_iter) {1038// Since we're building on Nevada-B158 or earlier, we have to1039// cast wrapper_fill_cframe_list to make the compiler happy.1040Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,1041(proc_stack_f *)wrapper_fill_cframe_list, &dbgo2);1042} else {1043Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,1044fill_cframe_list, &dbgo2);1045}1046#endif // SOLARIS_11_B159_OR_LATER1047return dbgo2.obj;1048}10491050/*1051* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1052* Method: fillLoadObjectList01053* Signature: (Ljava/util/List;)V1054* Description: fills shared objects of the debuggee process/core1055*/1056JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillLoadObjectList01057(JNIEnv *env, jobject this_obj, jobject list) {1058DebuggerWithObject dbgo;1059dbgo.env = env;1060dbgo.this_obj = this_obj;1061dbgo.obj = list;10621063jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);1064Pobject_iter((struct ps_prochandle*) p_ps_prochandle, fill_load_object_list, &dbgo);1065}10661067/*1068* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1069* Method: readBytesFromProcess01070* Signature: (JJ)[B1071* Description: read bytes from debuggee process/core1072*/1073JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_readBytesFromProcess01074(JNIEnv *env, jobject this_obj, jlong address, jlong numBytes) {10751076jbyteArray array = env->NewByteArray(numBytes);1077CHECK_EXCEPTION_(0);1078jboolean isCopy;1079jbyte* bufPtr = env->GetByteArrayElements(array, &isCopy);1080CHECK_EXCEPTION_(0);10811082jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);1083ps_err_e ret = ps_pread((struct ps_prochandle*) p_ps_prochandle,1084(psaddr_t)address, bufPtr, (size_t)numBytes);10851086if (ret != PS_OK) {1087// part of the class sharing workaround. try shared heap area1088int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);1089if (classes_jsa_fd != -1 && address != (jlong)0) {1090print_debug("read failed at 0x%lx, attempting shared heap area\n", (long) address);10911092struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID);1093// walk through the shared mappings -- we just have 4 of them.1094// so, linear walking is okay.1095for (int m = 0; m < NUM_SHARED_MAPS; m++) {10961097// We can skip the non-read-only maps. These are mapped as MAP_PRIVATE1098// and hence will be read by libproc. Besides, the file copy may be1099// stale because the process might have modified those pages.1100if (pheader->_space[m]._read_only) {1101jlong baseAddress = (jlong) (uintptr_t) pheader->_space[m]._base;1102size_t usedSize = pheader->_space[m]._used;1103if (address >= baseAddress && address < (baseAddress + usedSize)) {1104// the given address falls in this shared heap area1105print_debug("found shared map at 0x%lx\n", (long) baseAddress);110611071108// If more data is asked than actually mapped from file, we need to zero fill1109// till the end-of-page boundary. But, java array new does that for us. we just1110// need to read as much as data available.11111112#define MIN2(x, y) (((x) < (y))? (x) : (y))11131114jlong diff = address - baseAddress;1115jlong bytesToRead = MIN2(numBytes, usedSize - diff);1116off_t offset = pheader->_space[m]._file_offset + off_t(diff);1117ssize_t bytesRead = pread(classes_jsa_fd, bufPtr, bytesToRead, offset);1118if (bytesRead != bytesToRead) {1119env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);1120print_debug("shared map read failed\n");1121return jbyteArray(0);1122} else {1123print_debug("shared map read succeeded\n");1124env->ReleaseByteArrayElements(array, bufPtr, 0);1125return array;1126}1127} // is in current map1128} // is read only map1129} // for shared maps1130} // classes_jsa_fd != -11131env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);1132return jbyteArray(0);1133} else {1134env->ReleaseByteArrayElements(array, bufPtr, 0);1135return array;1136}1137}11381139/*1140* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1141* Method: writeBytesToProcess01142* Signature: (JJ[B)V1143* Description: write bytes into debugger process1144*/1145JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_writeBytesToProcess01146(JNIEnv *env, jobject this_obj, jlong address, jlong numBytes, jbyteArray data) {1147jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);1148jboolean isCopy;1149jbyte* ptr = env->GetByteArrayElements(data, &isCopy);1150CHECK_EXCEPTION;11511152if (ps_pwrite((struct ps_prochandle*) p_ps_prochandle, address, ptr, numBytes) != PS_OK) {1153env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);1154THROW_NEW_DEBUGGER_EXCEPTION("Process write failed!");1155}11561157env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);1158}11591160/*1161* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1162* Method: suspend01163* Signature: ()V1164*/1165JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_suspend01166(JNIEnv *env, jobject this_obj) {1167jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);1168// for now don't check return value. revisit this again.1169Pstop((struct ps_prochandle*) p_ps_prochandle, 1000);1170}11711172/*1173* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1174* Method: resume01175* Signature: ()V1176*/1177JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_resume01178(JNIEnv *env, jobject this_obj) {1179jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);1180// for now don't check return value. revisit this again.1181Psetrun((struct ps_prochandle*) p_ps_prochandle, 0, PRCFAULT|PRSTOP);1182}11831184/*1185* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1186* Method: lookupByName01187* Signature: (Ljava/lang/String;Ljava/lang/String;)J1188* Description: symbol lookup by name1189*/1190JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByName01191(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {1192jlong p_ps_prochandle;1193p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);11941195jboolean isCopy;1196const char* objectName_cstr = NULL;1197if (objectName != NULL) {1198objectName_cstr = env->GetStringUTFChars(objectName, &isCopy);1199CHECK_EXCEPTION_(0);1200} else {1201objectName_cstr = PR_OBJ_EVERY;1202}12031204const char* symbolName_cstr = env->GetStringUTFChars(symbolName, &isCopy);1205CHECK_EXCEPTION_(0);12061207psaddr_t symbol_addr = (psaddr_t) 0;1208ps_pglobal_lookup((struct ps_prochandle*) p_ps_prochandle, objectName_cstr,1209symbolName_cstr, &symbol_addr);12101211if (symbol_addr == 0) {1212print_debug("lookup for %s in %s failed\n", symbolName_cstr, objectName_cstr);1213}12141215if (objectName_cstr != PR_OBJ_EVERY) {1216env->ReleaseStringUTFChars(objectName, objectName_cstr);1217}1218env->ReleaseStringUTFChars(symbolName, symbolName_cstr);1219return (jlong) (uintptr_t) symbol_addr;1220}12211222/*1223* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1224* Method: lookupByAddress01225* Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;1226* Description: lookup symbol name for a given address1227*/1228JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByAddress01229(JNIEnv *env, jobject this_obj, jlong address) {1230jlong p_ps_prochandle;1231p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);12321233char nameBuf[SYMBOL_BUF_SIZE + 1];1234GElf_Sym sym;1235int res = Plookup_by_addr((struct ps_prochandle*) p_ps_prochandle, (uintptr_t) address,1236nameBuf, sizeof(nameBuf), &sym, NULL);12371238if (res != 0) { // failed1239return 0;1240}12411242jstring resSym = env->NewStringUTF(nameBuf);1243CHECK_EXCEPTION_(0);12441245return env->CallObjectMethod(this_obj, createClosestSymbol_ID, resSym, (address - sym.st_value));1246}12471248/*1249* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1250* Method: demangle01251* Signature: (Ljava/lang/String;)Ljava/lang/String;1252*/1253JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_demangle01254(JNIEnv *env, jobject this_object, jstring name) {1255jboolean isCopy;1256const char* ptr = env->GetStringUTFChars(name, &isCopy);1257char buf[2*SYMBOL_BUF_SIZE + 1];1258jstring res = 0;1259if (cplus_demangle((char*) ptr, buf, sizeof(buf)) != DEMANGLE_ESPACE) {1260res = env->NewStringUTF(buf);1261} else {1262res = name;1263}1264env->ReleaseStringUTFChars(name, ptr);1265return res;1266}12671268#ifndef SOLARIS_11_B159_OR_LATER1269// Determine if the OS we're running on has the newer version1270// of libproc's Pstack_iter.1271//1272// Set env var PSTACK_ITER_DEBUG=true to debug this logic.1273// Set env var PSTACK_ITER_DEBUG_RELEASE to simulate a 'release' value.1274// Set env var PSTACK_ITER_DEBUG_VERSION to simulate a 'version' value.1275//1276// frankenputer 'uname -r -v': 5.10 Generic_141445-091277// jurassic 'uname -r -v': 5.11 snv_1641278// lonepeak 'uname -r -v': 5.11 snv_1271279//1280static void set_has_newer_Pstack_iter(JNIEnv *env) {1281static bool done_set = false;12821283if (done_set) {1284// already set has_newer_Pstack_iter1285return;1286}12871288struct utsname name;1289if (uname(&name) == -1) {1290THROW_NEW_DEBUGGER_EXCEPTION("uname() failed!");1291}1292dprintf_2("release='%s' version='%s'\n", name.release, name.version);12931294if (_Pstack_iter_debug) {1295char *override = getenv("PSTACK_ITER_DEBUG_RELEASE");1296if (override != NULL) {1297strncpy(name.release, override, SYS_NMLN - 1);1298name.release[SYS_NMLN - 2] = '\0';1299dprintf_2("overriding with release='%s'\n", name.release);1300}1301override = getenv("PSTACK_ITER_DEBUG_VERSION");1302if (override != NULL) {1303strncpy(name.version, override, SYS_NMLN - 1);1304name.version[SYS_NMLN - 2] = '\0';1305dprintf_2("overriding with version='%s'\n", name.version);1306}1307}13081309// the major number corresponds to the old SunOS major number1310int major = atoi(name.release);1311if (major >= 6) {1312dprintf_2("release is SunOS 6 or later\n");1313has_newer_Pstack_iter = true;1314done_set = true;1315return;1316}1317if (major < 5) {1318dprintf_2("release is SunOS 4 or earlier\n");1319done_set = true;1320return;1321}13221323// some SunOS 5.* build so now check for Solaris versions1324char *dot = strchr(name.release, '.');1325int minor = 0;1326if (dot != NULL) {1327// release is major.minor format1328*dot = NULL;1329minor = atoi(dot + 1);1330}13311332if (minor <= 10) {1333dprintf_2("release is Solaris 10 or earlier\n");1334done_set = true;1335return;1336} else if (minor >= 12) {1337dprintf_2("release is Solaris 12 or later\n");1338has_newer_Pstack_iter = true;1339done_set = true;1340return;1341}13421343// some Solaris 11 build so now check for internal build numbers1344if (strncmp(name.version, "snv_", 4) != 0) {1345dprintf_2("release is Solaris 11 post-GA or later\n");1346has_newer_Pstack_iter = true;1347done_set = true;1348return;1349}13501351// version begins with "snv_" so a pre-GA build of Solaris 111352int build = atoi(&name.version[4]);1353if (build >= 159) {1354dprintf_2("release is Nevada-B159 or later\n");1355has_newer_Pstack_iter = true;1356} else {1357dprintf_2("release is Nevada-B158 or earlier\n");1358}13591360done_set = true;1361}1362#endif // !SOLARIS_11_B159_OR_LATER13631364/*1365* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal1366* Method: initIDs1367* Signature: ()V1368* Description: get JNI ids for fields and methods of ProcDebuggerLocal class1369*/1370JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_initIDs1371(JNIEnv *env, jclass clazz) {1372_libsaproc_debug = getenv("LIBSAPROC_DEBUG") != NULL;1373if (_libsaproc_debug) {1374// propagate debug mode to libproc.so1375static const char* var = "LIBPROC_DEBUG=1";1376putenv((char*)var);1377}13781379void* libproc_handle = dlopen("libproc.so", RTLD_LAZY | RTLD_GLOBAL);1380if (libproc_handle == 0)1381THROW_NEW_DEBUGGER_EXCEPTION("can't load libproc.so, if you are using Solaris 5.7 or below, copy libproc.so from 5.8!");13821383#ifndef SOLARIS_11_B159_OR_LATER1384_Pstack_iter_debug = getenv("PSTACK_ITER_DEBUG") != NULL;13851386set_has_newer_Pstack_iter(env);1387CHECK_EXCEPTION;1388dprintf_2("has_newer_Pstack_iter=%d\n", has_newer_Pstack_iter);1389#endif13901391p_ps_prochandle_ID = env->GetFieldID(clazz, "p_ps_prochandle", "J");1392CHECK_EXCEPTION;13931394libthread_db_handle_ID = env->GetFieldID(clazz, "libthread_db_handle", "J");1395CHECK_EXCEPTION;13961397p_td_thragent_t_ID = env->GetFieldID(clazz, "p_td_thragent_t", "J");1398CHECK_EXCEPTION;13991400p_td_init_ID = env->GetFieldID(clazz, "p_td_init", "J");1401CHECK_EXCEPTION;14021403p_td_ta_new_ID = env->GetFieldID(clazz, "p_td_ta_new", "J");1404CHECK_EXCEPTION;14051406p_td_ta_delete_ID = env->GetFieldID(clazz, "p_td_ta_delete", "J");1407CHECK_EXCEPTION;14081409p_td_ta_thr_iter_ID = env->GetFieldID(clazz, "p_td_ta_thr_iter", "J");1410CHECK_EXCEPTION;14111412p_td_thr_get_info_ID = env->GetFieldID(clazz, "p_td_thr_get_info", "J");1413CHECK_EXCEPTION;14141415p_td_ta_map_id2thr_ID = env->GetFieldID(clazz, "p_td_ta_map_id2thr", "J");1416CHECK_EXCEPTION;14171418p_td_thr_getgregs_ID = env->GetFieldID(clazz, "p_td_thr_getgregs", "J");1419CHECK_EXCEPTION;14201421getThreadForThreadId_ID = env->GetMethodID(clazz,1422"getThreadForThreadId", "(J)Lsun/jvm/hotspot/debugger/ThreadProxy;");1423CHECK_EXCEPTION;14241425pcRegIndex_ID = env->GetFieldID(clazz, "pcRegIndex", "I");1426CHECK_EXCEPTION;14271428fpRegIndex_ID = env->GetFieldID(clazz, "fpRegIndex", "I");1429CHECK_EXCEPTION;14301431createSenderFrame_ID = env->GetMethodID(clazz,1432"createSenderFrame", "(Lsun/jvm/hotspot/debugger/proc/ProcCFrame;JJ)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;");1433CHECK_EXCEPTION;14341435createLoadObject_ID = env->GetMethodID(clazz,1436"createLoadObject", "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");1437CHECK_EXCEPTION;14381439createClosestSymbol_ID = env->GetMethodID(clazz,1440"createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");1441CHECK_EXCEPTION;14421443listAdd_ID = env->GetMethodID(env->FindClass("java/util/List"), "add", "(Ljava/lang/Object;)Z");1444CHECK_EXCEPTION;14451446// part of the class sharing workaround1447classes_jsa_fd_ID = env->GetFieldID(clazz, "classes_jsa_fd", "I");1448CHECK_EXCEPTION;1449p_file_map_header_ID = env->GetFieldID(clazz, "p_file_map_header", "J");1450CHECK_EXCEPTION;1451}145214531454