Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m
38833 views
/*1* Copyright (c) 2002, 2015, 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 <objc/objc-runtime.h>25#import <Foundation/Foundation.h>26#import <JavaNativeFoundation/JavaNativeFoundation.h>2728#include <jni.h>2930#import <mach/mach.h>31#import <mach/mach_types.h>32#import <sys/sysctl.h>33#import <stdio.h>34#import <stdarg.h>35#import <stdlib.h>36#import <strings.h>37#import <dlfcn.h>38#import <limits.h>39#import <errno.h>40#import <sys/types.h>41#import <sys/ptrace.h>42#include "libproc_impl.h"4344#define UNSUPPORTED_ARCH "Unsupported architecture!"4546#if defined(x86_64) && !defined(amd64)47#define amd64 148#endif4950#if amd6451#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"52#elif defined(aarch64)53#include "sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext.h"54#else55#error UNSUPPORTED_ARCH56#endif5758static jfieldID symbolicatorID = 0; // set in _init059static jfieldID taskID = 0; // set in _init06061static jfieldID p_ps_prochandle_ID = 0;62static jfieldID loadObjectList_ID = 0;63static jmethodID listAdd_ID = 0;6465static jmethodID createClosestSymbol_ID = 0;66static jmethodID createLoadObject_ID = 0;67static jmethodID getJavaThreadsInfo_ID = 0;6869// indicator if thread id (lwpid_t) was set70static bool _threads_filled = false;7172static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {73(*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);74}7576static id getSymbolicator(JNIEnv *env, jobject this_obj) {77jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID);78return (id)(intptr_t)ptr;79}8081static void putTask(JNIEnv *env, jobject this_obj, task_t task) {82(*env)->SetLongField(env, this_obj, taskID, (jlong)task);83}8485static task_t getTask(JNIEnv *env, jobject this_obj) {86jlong ptr = (*env)->GetLongField(env, this_obj, taskID);87return (task_t)ptr;88}8990#define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }91#define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}92#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; }93#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}94#define CHECK_EXCEPTION_CLEAR if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); }95#define CHECK_EXCEPTION_CLEAR_VOID if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return; }96#define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; }9798static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {99jclass exceptionClass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException");100CHECK_EXCEPTION;101(*env)->ThrowNew(env, exceptionClass, errMsg);102}103104static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {105jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID);106return (struct ps_prochandle*)(intptr_t)ptr;107}108109#if defined(__i386__)110#define hsdb_thread_state_t x86_thread_state32_t111#define hsdb_float_state_t x86_float_state32_t112#define HSDB_THREAD_STATE x86_THREAD_STATE32113#define HSDB_FLOAT_STATE x86_FLOAT_STATE32114#define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT115#define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE32_COUNT116#elif defined(__x86_64__)117#define hsdb_thread_state_t x86_thread_state64_t118#define hsdb_float_state_t x86_float_state64_t119#define HSDB_THREAD_STATE x86_THREAD_STATE64120#define HSDB_FLOAT_STATE x86_FLOAT_STATE64121#define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT122#define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT123#elif defined(aarch64)124#define hsdb_thread_state_t arm_thread_state64_t125#define hsdb_float_state_t arm_neon_state64_t126#define HSDB_THREAD_STATE ARM_THREAD_STATE64127#define HSDB_FLOAT_STATE ARM_NEON_STATE64128#define HSDB_THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT129#define HSDB_FLOAT_STATE_COUNT ARM_NEON_STATE64_COUNT130#else131#error UNSUPPORTED_ARCH132#endif133134/*135* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal136* Method: init0137* Signature: ()V138*/139JNIEXPORT void JNICALL140Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {141symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");142CHECK_EXCEPTION;143taskID = (*env)->GetFieldID(env, cls, "task", "J");144CHECK_EXCEPTION;145146// for core file147p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J");148CHECK_EXCEPTION;149loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;");150CHECK_EXCEPTION;151152// methods we use153createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol",154"(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");155CHECK_EXCEPTION;156createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject",157"(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");158CHECK_EXCEPTION;159160// java.util.List method we call161jclass listClass = (*env)->FindClass(env, "java/util/List");162CHECK_EXCEPTION;163listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z");164CHECK_EXCEPTION;165getJavaThreadsInfo_ID = (*env)->GetMethodID(env, cls, "getJavaThreadsInfo",166"()[J");167CHECK_EXCEPTION;168169init_libproc(getenv("LIBSAPROC_DEBUG") != NULL);170}171172JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize173(JNIEnv *env, jclass cls)174{175#ifdef _LP64176return 8;177#else178#error UNSUPPORTED_ARCH179#endif180}181182/** called by Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0 */183jlong lookupByNameIncore(184JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jstring objectName, jstring symbolName)185{186const char *objectName_cstr, *symbolName_cstr;187jlong addr;188jboolean isCopy;189objectName_cstr = NULL;190if (objectName != NULL) {191objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy);192CHECK_EXCEPTION_(0);193}194symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);195CHECK_EXCEPTION_(0);196197print_debug("look for %s \n", symbolName_cstr);198addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);199200if (objectName_cstr != NULL) {201(*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);202}203(*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);204return addr;205}206207/*208* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal209* Method: lookupByName0210* Signature: (Ljava/lang/String;Ljava/lang/String;)J211*/212JNIEXPORT jlong JNICALL213Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(214JNIEnv *env, jobject this_obj,215jstring objectName, jstring symbolName)216{217struct ps_prochandle* ph = get_proc_handle(env, this_obj);218if (ph != NULL && ph->core != NULL) {219return lookupByNameIncore(env, ph, this_obj, objectName, symbolName);220}221222jlong address = 0;223224JNF_COCOA_ENTER(env);225NSString *symbolNameString = JNFJavaToNSString(env, symbolName);226227print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]);228229id symbolicator = getSymbolicator(env, this_obj);230if (symbolicator != nil) {231uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend;232address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);233}234235print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);236JNF_COCOA_EXIT(env);237238return address;239}240241/*242* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal243* Method: lookupByAddress0244* Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;245*/246JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0247(JNIEnv *env, jobject this_obj, jlong addr) {248uintptr_t offset;249const char* sym = NULL;250jstring sym_string;251252struct ps_prochandle* ph = get_proc_handle(env, this_obj);253if (ph != NULL && ph->core != NULL) {254sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);255if (sym == NULL) return 0;256sym_string = (*env)->NewStringUTF(env, sym);257CHECK_EXCEPTION_(0);258return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,259sym_string, (jlong)offset);260}261return 0;262}263264/** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */265jbyteArray readBytesFromCore(266JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes)267{268jboolean isCopy;269jbyteArray array;270jbyte *bufPtr;271ps_err_e err;272273array = (*env)->NewByteArray(env, numBytes);274CHECK_EXCEPTION_(0);275bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy);276CHECK_EXCEPTION_(0);277278err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes);279(*env)->ReleaseByteArrayElements(env, array, bufPtr, 0);280return (err == PS_OK)? array : 0;281}282283/*284* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal285* Method: readBytesFromProcess0286* Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;287*/288JNIEXPORT jbyteArray JNICALL289Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(290JNIEnv *env, jobject this_obj,291jlong addr, jlong numBytes)292{293print_debug("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);294295// must allocate storage instead of using former parameter buf296jbyteArray array;297298struct ps_prochandle* ph = get_proc_handle(env, this_obj);299if (ph != NULL && ph->core != NULL) {300return readBytesFromCore(env, ph, this_obj, addr, numBytes);301}302303array = (*env)->NewByteArray(env, numBytes);304CHECK_EXCEPTION_(0);305306unsigned long alignedAddress;307unsigned long alignedLength = 0;308kern_return_t result;309vm_offset_t *pages;310int *mapped;311long pageCount;312uint byteCount;313int i;314unsigned long remaining;315316alignedAddress = trunc_page(addr);317if (addr != alignedAddress) {318alignedLength += addr - alignedAddress;319}320alignedLength = round_page(numBytes);321pageCount = alignedLength/vm_page_size;322323// Allocate storage for pages and flags.324pages = malloc(pageCount * sizeof(vm_offset_t));325mapped = calloc(pageCount, sizeof(int));326327task_t gTask = getTask(env, this_obj);328// Try to read each of the pages.329for (i = 0; i < pageCount; i++) {330result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size,331&pages[i], &byteCount);332mapped[i] = (result == KERN_SUCCESS);333// assume all failures are unmapped pages334}335336print_debug("%ld pages\n", pageCount);337338remaining = numBytes;339340for (i = 0; i < pageCount; i++) {341unsigned long len = vm_page_size;342unsigned long start = 0;343344if (i == 0) {345start = addr - alignedAddress;346len = vm_page_size - start;347}348349if (i == (pageCount - 1)) {350len = remaining;351}352353if (mapped[i]) {354print_debug("page %d mapped (len %ld start %ld)\n", i, len, start);355(*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start));356vm_deallocate(mach_task_self(), pages[i], vm_page_size);357}358359remaining -= len;360}361362free (pages);363free (mapped);364return array;365}366367/** Only used for core file reading, set thread_id for threads which is got after core file parsed.368* Thread context is available in Mach-O core file but thread id is not. We can get thread id369* from Threads which store all java threads information when they are created. Here we can identify370* them as java threads by checking if a thread's rsp or rbp within a java thread's stack.371* Note Macosx uses unique_thread_id which is different from other platforms though printed ids372* are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long373* integers to host all java threads' id, stack_start, stack_end as:374* [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...]375*376* The work cannot be done at init0 since Threads is not available yet(VM not initialized yet).377* This function should be called only once if succeeded378*/379bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {380int n = 0, i = 0, j;381struct reg regs;382383jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID);384CHECK_EXCEPTION_(false);385int len = (int)(*env)->GetArrayLength(env, thrinfos);386uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL);387CHECK_EXCEPTION_(false);388n = get_num_threads(ph);389print_debug("fill_java_threads called, num_of_thread = %d\n", n);390for (i = 0; i < n; i++) {391if (!get_nth_lwp_regs(ph, i, ®s)) {392print_debug("Could not get regs of thread %d, already set!\n", i);393return false;394}395for (j = 0; j < len; j += 3) {396lwpid_t uid = cinfos[j];397uint64_t beg = cinfos[j + 1];398uint64_t end = cinfos[j + 2];399#if defined(amd64)400if ((regs.r_rsp < end && regs.r_rsp >= beg) ||401(regs.r_rbp < end && regs.r_rbp >= beg)) {402set_lwp_id(ph, i, uid);403break;404}405#elif defined(aarch64)406if ((regs.r_sp < end && regs.r_sp >= beg) ||407(regs.r_fp < end && regs.r_fp >= beg)) {408set_lwp_id(ph, i, uid);409break;410}411#else412#error UNSUPPORTED_ARCH413#endif414}415}416(*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0);417CHECK_EXCEPTION_(false);418return true;419}420421/* For core file only, called from422* Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0423*/424jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id, struct ps_prochandle* ph) {425if (!_threads_filled) {426if (!fill_java_threads(env, this_obj, ph)) {427throw_new_debugger_exception(env, "Failed to fill in threads");428return 0;429} else {430_threads_filled = true;431}432}433434struct reg gregs;435jboolean isCopy;436jlongArray array;437jlong *regs;438439if (get_lwp_regs(ph, lwp_id, &gregs) != true) {440THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);441}442443#undef NPRGREG444#undef REG_INDEX445#if amd64446#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG447#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg448449array = (*env)->NewLongArray(env, NPRGREG);450CHECK_EXCEPTION_(0);451regs = (*env)->GetLongArrayElements(env, array, &isCopy);452453regs[REG_INDEX(R15)] = gregs.r_r15;454regs[REG_INDEX(R14)] = gregs.r_r14;455regs[REG_INDEX(R13)] = gregs.r_r13;456regs[REG_INDEX(R12)] = gregs.r_r12;457regs[REG_INDEX(RBP)] = gregs.r_rbp;458regs[REG_INDEX(RBX)] = gregs.r_rbx;459regs[REG_INDEX(R11)] = gregs.r_r11;460regs[REG_INDEX(R10)] = gregs.r_r10;461regs[REG_INDEX(R9)] = gregs.r_r9;462regs[REG_INDEX(R8)] = gregs.r_r8;463regs[REG_INDEX(RAX)] = gregs.r_rax;464regs[REG_INDEX(RCX)] = gregs.r_rcx;465regs[REG_INDEX(RDX)] = gregs.r_rdx;466regs[REG_INDEX(RSI)] = gregs.r_rsi;467regs[REG_INDEX(RDI)] = gregs.r_rdi;468regs[REG_INDEX(RIP)] = gregs.r_rip;469regs[REG_INDEX(CS)] = gregs.r_cs;470regs[REG_INDEX(RSP)] = gregs.r_rsp;471regs[REG_INDEX(SS)] = gregs.r_ss;472regs[REG_INDEX(FSBASE)] = 0;473regs[REG_INDEX(GSBASE)] = 0;474regs[REG_INDEX(DS)] = gregs.r_ds;475regs[REG_INDEX(ES)] = gregs.r_es;476regs[REG_INDEX(FS)] = gregs.r_fs;477regs[REG_INDEX(GS)] = gregs.r_gs;478regs[REG_INDEX(TRAPNO)] = gregs.r_trapno;479regs[REG_INDEX(RFL)] = gregs.r_rflags;480481#elif defined(aarch64)482#define NPRGREG sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_NPRGREG483#define REG_INDEX(reg) sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_##reg484485array = (*env)->NewLongArray(env, NPRGREG);486CHECK_EXCEPTION_(0);487regs = (*env)->GetLongArrayElements(env, array, &isCopy);488489regs[REG_INDEX(R0)] = gregs.r_r0;490regs[REG_INDEX(R1)] = gregs.r_r1;491regs[REG_INDEX(R2)] = gregs.r_r2;492regs[REG_INDEX(R3)] = gregs.r_r3;493regs[REG_INDEX(R4)] = gregs.r_r4;494regs[REG_INDEX(R5)] = gregs.r_r5;495regs[REG_INDEX(R6)] = gregs.r_r6;496regs[REG_INDEX(R7)] = gregs.r_r7;497regs[REG_INDEX(R8)] = gregs.r_r8;498regs[REG_INDEX(R9)] = gregs.r_r9;499regs[REG_INDEX(R10)] = gregs.r_r10;500regs[REG_INDEX(R11)] = gregs.r_r11;501regs[REG_INDEX(R12)] = gregs.r_r12;502regs[REG_INDEX(R13)] = gregs.r_r13;503regs[REG_INDEX(R14)] = gregs.r_r14;504regs[REG_INDEX(R15)] = gregs.r_r15;505regs[REG_INDEX(R16)] = gregs.r_r16;506regs[REG_INDEX(R17)] = gregs.r_r17;507regs[REG_INDEX(R18)] = gregs.r_r18;508regs[REG_INDEX(R19)] = gregs.r_r19;509regs[REG_INDEX(R20)] = gregs.r_r20;510regs[REG_INDEX(R21)] = gregs.r_r21;511regs[REG_INDEX(R22)] = gregs.r_r22;512regs[REG_INDEX(R23)] = gregs.r_r23;513regs[REG_INDEX(R24)] = gregs.r_r24;514regs[REG_INDEX(R25)] = gregs.r_r25;515regs[REG_INDEX(R26)] = gregs.r_r26;516regs[REG_INDEX(R27)] = gregs.r_r27;517regs[REG_INDEX(R28)] = gregs.r_r28;518regs[REG_INDEX(FP)] = gregs.r_fp;519regs[REG_INDEX(LR)] = gregs.r_lr;520regs[REG_INDEX(SP)] = gregs.r_sp;521regs[REG_INDEX(PC)] = gregs.r_pc;522523#endif /* amd64 */524(*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);525return array;526}527528/*529* Lookup the thread_t that corresponds to the given thread_id.530* The thread_id should be the result from calling thread_info() with THREAD_IDENTIFIER_INFO531* and reading the m_ident_info.thread_id returned.532* The returned thread_t is the mach send right to the kernel port for the corresponding thread.533*534* We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self()535* in the VM, but that thread port is not valid for a remote debugger to access the thread.536*/537thread_t538lookupThreadFromThreadId(task_t task, jlong thread_id) {539print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id);540541thread_array_t thread_list = NULL;542mach_msg_type_number_t thread_list_count = 0;543thread_t result_thread = 0;544int i;545546// get the list of all the send rights547kern_return_t result = task_threads(task, &thread_list, &thread_list_count);548if (result != KERN_SUCCESS) {549print_debug("task_threads returned 0x%x\n", result);550return 0;551}552553for(i = 0 ; i < thread_list_count; i++) {554thread_identifier_info_data_t m_ident_info;555mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;556557// get the THREAD_IDENTIFIER_INFO for the send right558result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);559if (result != KERN_SUCCESS) {560print_debug("thread_info returned 0x%x\n", result);561break;562}563564// if this is the one we're looking for, return the send right565if (thread_id == m_ident_info.thread_id)566{567result_thread = thread_list[i];568break;569}570}571572vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t));573vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count);574575return result_thread;576}577578579/*580* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal581* Method: getThreadIntegerRegisterSet0582* Signature: (J)[J583*/584JNIEXPORT jlongArray JNICALL585Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(586JNIEnv *env, jobject this_obj,587jlong thread_id)588{589print_debug("getThreadRegisterSet0 called\n");590591struct ps_prochandle* ph = get_proc_handle(env, this_obj);592if (ph != NULL && ph->core != NULL) {593return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id, ph);594}595596kern_return_t result;597thread_t tid;598mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT;599hsdb_thread_state_t state;600jlongArray registerArray;601jlong *primitiveArray;602task_t gTask = getTask(env, this_obj);603604tid = lookupThreadFromThreadId(gTask, thread_id);605606result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);607608if (result != KERN_SUCCESS) {609print_error("getregs: thread_get_state(%d) failed (%d)\n", tid, result);610return NULL;611}612613// 64 bit614print_debug("Getting threads for a 64-bit process\n");615registerArray = (*env)->NewLongArray(env, NPRGREG);616CHECK_EXCEPTION_(0);617primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);618619#if amd64620#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG621#undef REG_INDEX622#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg623624primitiveArray[REG_INDEX(R15)] = state.__r15;625primitiveArray[REG_INDEX(R14)] = state.__r14;626primitiveArray[REG_INDEX(R13)] = state.__r13;627primitiveArray[REG_INDEX(R12)] = state.__r12;628primitiveArray[REG_INDEX(R11)] = state.__r11;629primitiveArray[REG_INDEX(R10)] = state.__r10;630primitiveArray[REG_INDEX(R9)] = state.__r9;631primitiveArray[REG_INDEX(R8)] = state.__r8;632primitiveArray[REG_INDEX(RDI)] = state.__rdi;633primitiveArray[REG_INDEX(RSI)] = state.__rsi;634primitiveArray[REG_INDEX(RBP)] = state.__rbp;635primitiveArray[REG_INDEX(RBX)] = state.__rbx;636primitiveArray[REG_INDEX(RDX)] = state.__rdx;637primitiveArray[REG_INDEX(RCX)] = state.__rcx;638primitiveArray[REG_INDEX(RAX)] = state.__rax;639primitiveArray[REG_INDEX(TRAPNO)] = 0; // trapno, not used640primitiveArray[REG_INDEX(ERR)] = 0; // err, not used641primitiveArray[REG_INDEX(RIP)] = state.__rip;642primitiveArray[REG_INDEX(CS)] = state.__cs;643primitiveArray[REG_INDEX(RFL)] = state.__rflags;644primitiveArray[REG_INDEX(RSP)] = state.__rsp;645primitiveArray[REG_INDEX(SS)] = 0; // We don't have SS646primitiveArray[REG_INDEX(FS)] = state.__fs;647primitiveArray[REG_INDEX(GS)] = state.__gs;648primitiveArray[REG_INDEX(ES)] = 0;649primitiveArray[REG_INDEX(DS)] = 0;650primitiveArray[REG_INDEX(FSBASE)] = 0;651primitiveArray[REG_INDEX(GSBASE)] = 0;652653#elif defined(aarch64)654#define NPRGREG sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_NPRGREG655#define REG_INDEX(reg) sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_##reg656657primitiveArray[REG_INDEX(R0)] = state.__x[0];658primitiveArray[REG_INDEX(R1)] = state.__x[1];659primitiveArray[REG_INDEX(R2)] = state.__x[2];660primitiveArray[REG_INDEX(R3)] = state.__x[3];661primitiveArray[REG_INDEX(R4)] = state.__x[4];662primitiveArray[REG_INDEX(R5)] = state.__x[5];663primitiveArray[REG_INDEX(R6)] = state.__x[6];664primitiveArray[REG_INDEX(R7)] = state.__x[7];665primitiveArray[REG_INDEX(R8)] = state.__x[8];666primitiveArray[REG_INDEX(R9)] = state.__x[9];667primitiveArray[REG_INDEX(R10)] = state.__x[10];668primitiveArray[REG_INDEX(R11)] = state.__x[11];669primitiveArray[REG_INDEX(R12)] = state.__x[12];670primitiveArray[REG_INDEX(R13)] = state.__x[13];671primitiveArray[REG_INDEX(R14)] = state.__x[14];672primitiveArray[REG_INDEX(R15)] = state.__x[15];673primitiveArray[REG_INDEX(R16)] = state.__x[16];674primitiveArray[REG_INDEX(R17)] = state.__x[17];675primitiveArray[REG_INDEX(R18)] = state.__x[18];676primitiveArray[REG_INDEX(R19)] = state.__x[19];677primitiveArray[REG_INDEX(R20)] = state.__x[20];678primitiveArray[REG_INDEX(R21)] = state.__x[21];679primitiveArray[REG_INDEX(R22)] = state.__x[22];680primitiveArray[REG_INDEX(R23)] = state.__x[23];681primitiveArray[REG_INDEX(R24)] = state.__x[24];682primitiveArray[REG_INDEX(R25)] = state.__x[25];683primitiveArray[REG_INDEX(R26)] = state.__x[26];684primitiveArray[REG_INDEX(R27)] = state.__x[27];685primitiveArray[REG_INDEX(R28)] = state.__x[28];686primitiveArray[REG_INDEX(FP)] = state.__fp;687primitiveArray[REG_INDEX(LR)] = state.__lr;688primitiveArray[REG_INDEX(SP)] = state.__sp;689primitiveArray[REG_INDEX(PC)] = state.__pc;690691#else692#error UNSUPPORTED_ARCH693#endif /* amd64 */694695print_debug("set registers\n");696(*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);697698return registerArray;699}700701/*702* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal703* Method: translateTID0704* Signature: (I)I705*/706JNIEXPORT jint JNICALL707Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(708JNIEnv *env, jobject this_obj, jint tid)709{710print_debug("translateTID0 called on tid = 0x%x\n", (int)tid);711712kern_return_t result;713thread_t foreign_tid, usable_tid;714mach_msg_type_name_t type;715716foreign_tid = tid;717718task_t gTask = getTask(env, this_obj);719result = mach_port_extract_right(gTask, foreign_tid,720MACH_MSG_TYPE_COPY_SEND,721&usable_tid, &type);722if (result != KERN_SUCCESS)723return -1;724725print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);726727return (jint) usable_tid;728}729730731static bool ptrace_continue(pid_t pid, int signal) {732// pass the signal to the process so we don't swallow it733int res;734if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) {735print_error("attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res);736return false;737}738return true;739}740741// waits until the ATTACH has stopped the process742// by signal SIGSTOP743static bool ptrace_waitpid(pid_t pid) {744int ret;745int status;746while (true) {747// Wait for debuggee to stop.748ret = waitpid(pid, &status, 0);749if (ret >= 0) {750if (WIFSTOPPED(status)) {751// Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP752// will still be pending and delivered when the process is DETACHED and the process753// will go to sleep.754if (WSTOPSIG(status) == SIGSTOP) {755// Debuggee stopped by SIGSTOP.756return true;757}758if (!ptrace_continue(pid, WSTOPSIG(status))) {759print_error("attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));760return false;761}762} else {763print_error("attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status);764return false;765}766} else {767switch (errno) {768case EINTR:769continue;770break;771case ECHILD:772print_error("attach: waitpid() failed. Child process pid (%d) does not exist \n", pid);773break;774case EINVAL:775print_error("attach: waitpid() failed. Invalid options argument.\n");776break;777default:778print_error("attach: waitpid() failed. Unexpected error %d\n",errno);779break;780}781return false;782}783}784}785786// attach to a process/thread specified by "pid"787static bool ptrace_attach(pid_t pid) {788int res;789if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) {790print_error("ptrace(PT_ATTACH, %d) failed with %d\n", pid, res);791return false;792} else {793return ptrace_waitpid(pid);794}795}796797/*798* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal799* Method: attach0800* Signature: (I)V801*/802JNIEXPORT void JNICALL803Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(804JNIEnv *env, jobject this_obj, jint jpid)805{806print_debug("attach0 called for jpid=%d\n", (int)jpid);807808JNF_COCOA_ENTER(env);809810kern_return_t result;811task_t gTask = 0;812result = task_for_pid(mach_task_self(), jpid, &gTask);813if (result != KERN_SUCCESS) {814print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result);815THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.");816}817putTask(env, this_obj, gTask);818819// use ptrace to stop the process820// on os x, ptrace only needs to be called on the process, not the individual threads821if (ptrace_attach(jpid) != true) {822mach_port_deallocate(mach_task_self(), gTask);823THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");824}825826id symbolicator = nil;827id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");828if (jrsSymbolicator != nil) {829id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;830symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);831}832if (symbolicator != nil) {833CFRetain(symbolicator); // pin symbolicator while in java heap834}835836putSymbolicator(env, this_obj, symbolicator);837if (symbolicator == nil) {838THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");839}840841JNF_COCOA_EXIT(env);842}843844/** For core file,845called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */846static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {847int n = 0, i = 0;848849// add load objects850n = get_num_libs(ph);851for (i = 0; i < n; i++) {852uintptr_t base;853const char* name;854jobject loadObject;855jobject loadObjectList;856jstring nameString;857858base = get_lib_base(ph, i);859name = get_lib_name(ph, i);860nameString = (*env)->NewStringUTF(env, name);861CHECK_EXCEPTION;862loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID,863nameString, (jlong)0, (jlong)base);864CHECK_EXCEPTION;865loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);866CHECK_EXCEPTION;867(*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject);868CHECK_EXCEPTION;869}870}871872/*873* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal874* Method: attach0875* Signature: (Ljava/lang/String;Ljava/lang/String;)V876*/877JNIEXPORT void JNICALL878Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2(879JNIEnv *env, jobject this_obj, jstring execName, jstring coreName)880{881const char *execName_cstr;882const char *coreName_cstr;883jboolean isCopy;884struct ps_prochandle* ph;885886execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy);887CHECK_EXCEPTION;888coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy);889CHECK_EXCEPTION;890891print_debug("attach: %s %s\n", execName_cstr, coreName_cstr);892893if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {894(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);895(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);896THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");897}898(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);899(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);900(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);901fillLoadObjects(env, this_obj, ph);902}903904/*905* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal906* Method: detach0907* Signature: ()V908*/909JNIEXPORT void JNICALL910Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(911JNIEnv *env, jobject this_obj)912{913print_debug("detach0 called\n");914struct ps_prochandle* ph = get_proc_handle(env, this_obj);915if (ph != NULL && ph->core != NULL) {916Prelease(ph);917return;918}919JNF_COCOA_ENTER(env);920task_t gTask = getTask(env, this_obj);921922// detach from the ptraced process causing it to resume execution923int pid;924kern_return_t k_res;925k_res = pid_for_task(gTask, &pid);926if (k_res != KERN_SUCCESS) {927print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res);928}929else {930int res = ptrace(PT_DETACH, pid, 0, 0);931if (res < 0) {932print_error("detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res);933}934}935936mach_port_deallocate(mach_task_self(), gTask);937id symbolicator = getSymbolicator(env, this_obj);938if (symbolicator != nil) {939CFRelease(symbolicator);940}941JNF_COCOA_EXIT(env);942}943944945