Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c
38833 views
/*1* Copyright (c) 2002, 2013, 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 <jni.h>25#include "libproc.h"2627#include <elf.h>28#include <sys/types.h>29#include <sys/stat.h>30#include <fcntl.h>31#include <stdlib.h>32#include <string.h>33#include <limits.h>3435#if defined(x86_64) && !defined(amd64)36#define amd64 137#endif3839#ifdef i38640#include "sun_jvm_hotspot_debugger_x86_X86ThreadContext.h"41#endif4243#ifdef amd6444#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"45#endif4647#if defined(sparc) || defined(sparcv9)48#include "sun_jvm_hotspot_debugger_sparc_SPARCThreadContext.h"49#endif5051#ifdef aarch6452#include "sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext.h"53#endif5455static jfieldID p_ps_prochandle_ID = 0;56static jfieldID threadList_ID = 0;57static jfieldID loadObjectList_ID = 0;5859static jmethodID createClosestSymbol_ID = 0;60static jmethodID createLoadObject_ID = 0;61static jmethodID getThreadForThreadId_ID = 0;62static jmethodID listAdd_ID = 0;6364#define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }65#define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}66#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; }67#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}6869void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {70(*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg);71}7273struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {74jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID);75return (struct ps_prochandle*)(intptr_t)ptr;76}7778/*79* Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal80* Method: init081* Signature: ()V82*/83JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_init084(JNIEnv *env, jclass cls) {85jclass listClass;8687if (init_libproc(getenv("LIBSAPROC_DEBUG") != NULL) != true) {88THROW_NEW_DEBUGGER_EXCEPTION("can't initialize libproc");89}9091// fields we use92p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J");93CHECK_EXCEPTION;94threadList_ID = (*env)->GetFieldID(env, cls, "threadList", "Ljava/util/List;");95CHECK_EXCEPTION;96loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;");97CHECK_EXCEPTION;9899// methods we use100createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol",101"(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");102CHECK_EXCEPTION;103createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject",104"(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");105CHECK_EXCEPTION;106getThreadForThreadId_ID = (*env)->GetMethodID(env, cls, "getThreadForThreadId",107"(J)Lsun/jvm/hotspot/debugger/ThreadProxy;");108CHECK_EXCEPTION;109// java.util.List method we call110listClass = (*env)->FindClass(env, "java/util/List");111CHECK_EXCEPTION;112listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z");113CHECK_EXCEPTION;114}115116JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getAddressSize117(JNIEnv *env, jclass cls)118{119#ifdef _LP64120return 8;121#else122return 4;123#endif124125}126127128static void fillThreadsAndLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {129int n = 0, i = 0;130131// add threads132n = get_num_threads(ph);133for (i = 0; i < n; i++) {134jobject thread;135jobject threadList;136lwpid_t lwpid;137138lwpid = get_lwp_id(ph, i);139thread = (*env)->CallObjectMethod(env, this_obj, getThreadForThreadId_ID,140(jlong)lwpid);141CHECK_EXCEPTION;142threadList = (*env)->GetObjectField(env, this_obj, threadList_ID);143CHECK_EXCEPTION;144(*env)->CallBooleanMethod(env, threadList, listAdd_ID, thread);145CHECK_EXCEPTION;146}147148// add load objects149n = get_num_libs(ph);150for (i = 0; i < n; i++) {151uintptr_t base;152const char* name;153jobject loadObject;154jobject loadObjectList;155156base = get_lib_base(ph, i);157name = get_lib_name(ph, i);158loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID,159(*env)->NewStringUTF(env, name), (jlong)0, (jlong)base);160CHECK_EXCEPTION;161loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);162CHECK_EXCEPTION;163(*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject);164CHECK_EXCEPTION;165}166}167168169/*170* Verify that a named ELF binary file (core or executable) has the same171* bitness as ourselves.172* Throw an exception if there is a mismatch or other problem.173*174* If we proceed using a mismatched debugger/debuggee, the best to hope175* for is a missing symbol, the worst is a crash searching for debug symbols.176*/177void verifyBitness(JNIEnv *env, const char *binaryName) {178int fd = open(binaryName, O_RDONLY);179if (fd < 0) {180THROW_NEW_DEBUGGER_EXCEPTION("cannot open binary file");181}182unsigned char elf_ident[EI_NIDENT];183int i = read(fd, &elf_ident, sizeof(elf_ident));184close(fd);185186if (i < 0) {187THROW_NEW_DEBUGGER_EXCEPTION("cannot read binary file");188}189#ifndef _LP64190if (elf_ident[EI_CLASS] == ELFCLASS64) {191THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use 64-bit java for debugger");192}193#else194if (elf_ident[EI_CLASS] != ELFCLASS64) {195THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger");196}197#endif198}199200201/*202* Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal203* Method: attach0204* Signature: (I)V205*/206JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_attach0__I207(JNIEnv *env, jobject this_obj, jint jpid) {208209// For bitness checking, locate binary at /proc/jpid/exe210char buf[PATH_MAX];211snprintf((char *) &buf, PATH_MAX, "/proc/%d/exe", jpid);212verifyBitness(env, (char *) &buf);213CHECK_EXCEPTION;214215char err_buf[200];216struct ps_prochandle* ph;217if ( (ph = Pgrab(jpid, err_buf, sizeof(err_buf))) == NULL) {218char msg[230];219snprintf(msg, sizeof(msg), "Can't attach to the process: %s", err_buf);220THROW_NEW_DEBUGGER_EXCEPTION(msg);221}222(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);223fillThreadsAndLoadObjects(env, this_obj, ph);224}225226/*227* Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal228* Method: attach0229* Signature: (Ljava/lang/String;Ljava/lang/String;)V230*/231JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2232(JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) {233const char *execName_cstr;234const char *coreName_cstr;235jboolean isCopy;236struct ps_prochandle* ph;237238execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy);239CHECK_EXCEPTION;240coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy);241CHECK_EXCEPTION;242243verifyBitness(env, execName_cstr);244CHECK_EXCEPTION;245246if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {247(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);248(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);249THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");250}251(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);252(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);253(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);254fillThreadsAndLoadObjects(env, this_obj, ph);255}256257/*258* Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal259* Method: detach0260* Signature: ()V261*/262JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_detach0263(JNIEnv *env, jobject this_obj) {264struct ps_prochandle* ph = get_proc_handle(env, this_obj);265if (ph != NULL) {266Prelease(ph);267}268}269270/*271* Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal272* Method: lookupByName0273* Signature: (Ljava/lang/String;Ljava/lang/String;)J274*/275JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_lookupByName0276(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {277const char *objectName_cstr, *symbolName_cstr;278jlong addr;279jboolean isCopy;280struct ps_prochandle* ph = get_proc_handle(env, this_obj);281282objectName_cstr = NULL;283if (objectName != NULL) {284objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy);285CHECK_EXCEPTION_(0);286}287symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);288CHECK_EXCEPTION_(0);289290addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);291292if (objectName_cstr != NULL) {293(*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);294}295(*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);296return addr;297}298299/*300* Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal301* Method: lookupByAddress0302* Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;303*/304JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_lookupByAddress0305(JNIEnv *env, jobject this_obj, jlong addr) {306uintptr_t offset;307const char* sym = NULL;308309struct ps_prochandle* ph = get_proc_handle(env, this_obj);310sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);311if (sym == NULL) return 0;312return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,313(*env)->NewStringUTF(env, sym), (jlong)offset);314}315316/*317* Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal318* Method: readBytesFromProcess0319* Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;320*/321JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_readBytesFromProcess0322(JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) {323324jboolean isCopy;325jbyteArray array;326jbyte *bufPtr;327ps_err_e err;328329array = (*env)->NewByteArray(env, numBytes);330CHECK_EXCEPTION_(0);331bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy);332CHECK_EXCEPTION_(0);333334err = ps_pdread(get_proc_handle(env, this_obj), (psaddr_t) (uintptr_t)addr, bufPtr, numBytes);335(*env)->ReleaseByteArrayElements(env, array, bufPtr, 0);336return (err == PS_OK)? array : 0;337}338339#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) || defined(aarch64)340JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0341(JNIEnv *env, jobject this_obj, jint lwp_id) {342343struct user_regs_struct gregs;344jboolean isCopy;345jlongArray array;346jlong *regs;347int i;348349struct ps_prochandle* ph = get_proc_handle(env, this_obj);350if (get_lwp_regs(ph, lwp_id, &gregs) != true) {351THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);352}353354#undef NPRGREG355#ifdef i386356#define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG357#endif358#ifdef amd64359#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG360#endif361#ifdef aarch64362#define NPRGREG sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_NPRGREG363#endif364#if defined(sparc) || defined(sparcv9)365#define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG366#endif367368array = (*env)->NewLongArray(env, NPRGREG);369CHECK_EXCEPTION_(0);370regs = (*env)->GetLongArrayElements(env, array, &isCopy);371372#undef REG_INDEX373374#ifdef i386375#define REG_INDEX(reg) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##reg376377regs[REG_INDEX(GS)] = (uintptr_t) gregs.xgs;378regs[REG_INDEX(FS)] = (uintptr_t) gregs.xfs;379regs[REG_INDEX(ES)] = (uintptr_t) gregs.xes;380regs[REG_INDEX(DS)] = (uintptr_t) gregs.xds;381regs[REG_INDEX(EDI)] = (uintptr_t) gregs.edi;382regs[REG_INDEX(ESI)] = (uintptr_t) gregs.esi;383regs[REG_INDEX(FP)] = (uintptr_t) gregs.ebp;384regs[REG_INDEX(SP)] = (uintptr_t) gregs.esp;385regs[REG_INDEX(EBX)] = (uintptr_t) gregs.ebx;386regs[REG_INDEX(EDX)] = (uintptr_t) gregs.edx;387regs[REG_INDEX(ECX)] = (uintptr_t) gregs.ecx;388regs[REG_INDEX(EAX)] = (uintptr_t) gregs.eax;389regs[REG_INDEX(PC)] = (uintptr_t) gregs.eip;390regs[REG_INDEX(CS)] = (uintptr_t) gregs.xcs;391regs[REG_INDEX(SS)] = (uintptr_t) gregs.xss;392393#endif /* i386 */394395#ifdef amd64396#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg397398regs[REG_INDEX(R15)] = gregs.r15;399regs[REG_INDEX(R14)] = gregs.r14;400regs[REG_INDEX(R13)] = gregs.r13;401regs[REG_INDEX(R12)] = gregs.r12;402regs[REG_INDEX(RBP)] = gregs.rbp;403regs[REG_INDEX(RBX)] = gregs.rbx;404regs[REG_INDEX(R11)] = gregs.r11;405regs[REG_INDEX(R10)] = gregs.r10;406regs[REG_INDEX(R9)] = gregs.r9;407regs[REG_INDEX(R8)] = gregs.r8;408regs[REG_INDEX(RAX)] = gregs.rax;409regs[REG_INDEX(RCX)] = gregs.rcx;410regs[REG_INDEX(RDX)] = gregs.rdx;411regs[REG_INDEX(RSI)] = gregs.rsi;412regs[REG_INDEX(RDI)] = gregs.rdi;413regs[REG_INDEX(RIP)] = gregs.rip;414regs[REG_INDEX(CS)] = gregs.cs;415regs[REG_INDEX(RSP)] = gregs.rsp;416regs[REG_INDEX(SS)] = gregs.ss;417regs[REG_INDEX(FSBASE)] = gregs.fs_base;418regs[REG_INDEX(GSBASE)] = gregs.gs_base;419regs[REG_INDEX(DS)] = gregs.ds;420regs[REG_INDEX(ES)] = gregs.es;421regs[REG_INDEX(FS)] = gregs.fs;422regs[REG_INDEX(GS)] = gregs.gs;423424#endif /* amd64 */425426#if defined(sparc) || defined(sparcv9)427428#define REG_INDEX(reg) sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_##reg429430#ifdef _LP64431regs[REG_INDEX(R_PSR)] = gregs.tstate;432regs[REG_INDEX(R_PC)] = gregs.tpc;433regs[REG_INDEX(R_nPC)] = gregs.tnpc;434regs[REG_INDEX(R_Y)] = gregs.y;435#else436regs[REG_INDEX(R_PSR)] = gregs.psr;437regs[REG_INDEX(R_PC)] = gregs.pc;438regs[REG_INDEX(R_nPC)] = gregs.npc;439regs[REG_INDEX(R_Y)] = gregs.y;440#endif441regs[REG_INDEX(R_G0)] = 0 ;442regs[REG_INDEX(R_G1)] = gregs.u_regs[0];443regs[REG_INDEX(R_G2)] = gregs.u_regs[1];444regs[REG_INDEX(R_G3)] = gregs.u_regs[2];445regs[REG_INDEX(R_G4)] = gregs.u_regs[3];446regs[REG_INDEX(R_G5)] = gregs.u_regs[4];447regs[REG_INDEX(R_G6)] = gregs.u_regs[5];448regs[REG_INDEX(R_G7)] = gregs.u_regs[6];449regs[REG_INDEX(R_O0)] = gregs.u_regs[7];450regs[REG_INDEX(R_O1)] = gregs.u_regs[8];451regs[REG_INDEX(R_O2)] = gregs.u_regs[ 9];452regs[REG_INDEX(R_O3)] = gregs.u_regs[10];453regs[REG_INDEX(R_O4)] = gregs.u_regs[11];454regs[REG_INDEX(R_O5)] = gregs.u_regs[12];455regs[REG_INDEX(R_O6)] = gregs.u_regs[13];456regs[REG_INDEX(R_O7)] = gregs.u_regs[14];457#endif /* sparc */458459#if defined(aarch64)460461#define REG_INDEX(reg) sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_##reg462463{464int i;465for (i = 0; i < 31; i++)466regs[i] = gregs.regs[i];467regs[REG_INDEX(SP)] = gregs.sp;468regs[REG_INDEX(PC)] = gregs.pc;469}470#endif /* aarch64 */471472473(*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);474return array;475}476#endif477478479