Path: blob/master/src/jdk.hotspot.agent/macosx/native/libsaproc/MacosxDebuggerLocal.m
41149 views
/*1* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2021, Azul Systems, Inc. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include <objc/objc-runtime.h>26#import <Foundation/Foundation.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 <string.h>35#import <stdarg.h>36#import <stdlib.h>37#import <strings.h>38#import <dlfcn.h>39#import <limits.h>40#import <errno.h>41#import <sys/types.h>42#import <sys/ptrace.h>43#include "libproc_impl.h"4445#if defined(amd64)46#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"47#elif defined(aarch64)48#include "sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext.h"49#else50#error UNSUPPORTED_ARCH51#endif5253static jfieldID symbolicatorID = 0; // set in _init054static jfieldID taskID = 0; // set in _init05556static jfieldID p_ps_prochandle_ID = 0;57static jfieldID loadObjectList_ID = 0;58static jmethodID listAdd_ID = 0;5960static jmethodID createClosestSymbol_ID = 0;61static jmethodID createLoadObject_ID = 0;62static jmethodID getJavaThreadsInfo_ID = 0;6364// indicator if thread id (lwpid_t) was set65static bool _threads_filled = false;6667// mach_exc_server defined in the generated mach_excServer.c68extern boolean_t mach_exc_server(mach_msg_header_t *input_msg_hdr,69mach_msg_header_t *output_msg_hdr);7071kern_return_t catch_mach_exception_raise(72mach_port_t exception_port, mach_port_t thread,73mach_port_t task, exception_type_t exception,74mach_exception_data_t code,75mach_msg_type_number_t code_cnt);7677kern_return_t catch_mach_exception_raise_state(78mach_port_t exception_port, exception_type_t exception,79const mach_exception_data_t code, mach_msg_type_number_t code_cnt,80int *flavor, const thread_state_t old_state,81mach_msg_type_number_t old_state_cnt, thread_state_t new_state,82mach_msg_type_number_t *new_state_cnt);8384kern_return_t catch_mach_exception_raise_state_identity(85mach_port_t exception_port, mach_port_t thread, mach_port_t task,86exception_type_t exception, mach_exception_data_t code,87mach_msg_type_number_t code_cnt, int *flavor, thread_state_t old_state,88mach_msg_type_number_t old_state_cnt, thread_state_t new_state,89mach_msg_type_number_t *new_state_cnt);9091static struct exception_saved_state {92exception_mask_t saved_masks[EXC_TYPES_COUNT];93mach_port_t saved_ports[EXC_TYPES_COUNT];94exception_behavior_t saved_behaviors[EXC_TYPES_COUNT];95thread_state_flavor_t saved_flavors[EXC_TYPES_COUNT];96mach_msg_type_number_t saved_exception_types_count;97} exception_saved_state;9899static mach_port_t tgt_exception_port;100101// Mirrors __Reply__mach_exception_raise_t generated in mach_excServer.c102static struct rep_msg {103mach_msg_header_t header;104NDR_record_t ndr;105kern_return_t ret_code;106} rep_msg;107108// Mirrors __Request__mach_exception_raise_t generated in mach_excServer.c109// with a large trailing pad to avoid MACH_MSG_RCV_TOO_LARGE110static struct exc_msg {111mach_msg_header_t header;112// start of the kernel processed data113mach_msg_body_t msgh_body;114mach_msg_port_descriptor_t thread;115mach_msg_port_descriptor_t task;116// end of the kernel processed data117NDR_record_t ndr;118exception_type_t exception;119mach_msg_type_number_t code_cnt;120mach_exception_data_t code; // an array of int64_t121char pad[512];122} exc_msg;123124static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {125(*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);126}127128static id getSymbolicator(JNIEnv *env, jobject this_obj) {129jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID);130return (id)(intptr_t)ptr;131}132133static void putTask(JNIEnv *env, jobject this_obj, task_t task) {134(*env)->SetLongField(env, this_obj, taskID, (jlong)task);135}136137static task_t getTask(JNIEnv *env, jobject this_obj) {138jlong ptr = (*env)->GetLongField(env, this_obj, taskID);139return (task_t)ptr;140}141142#define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; }143#define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;}144#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; }145#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}146#define CHECK_EXCEPTION_CLEAR if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); }147#define CHECK_EXCEPTION_CLEAR_VOID if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return; }148#define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; }149150static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {151jclass exceptionClass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException");152CHECK_EXCEPTION;153(*env)->ThrowNew(env, exceptionClass, errMsg);154}155156static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {157jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID);158return (struct ps_prochandle*)(intptr_t)ptr;159}160161#if defined(amd64)162#define hsdb_thread_state_t x86_thread_state64_t163#define hsdb_float_state_t x86_float_state64_t164#define HSDB_THREAD_STATE x86_THREAD_STATE64165#define HSDB_FLOAT_STATE x86_FLOAT_STATE64166#define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT167#define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT168#elif defined(aarch64)169#define hsdb_thread_state_t arm_thread_state64_t170#define hsdb_float_state_t arm_neon_state64_t171#define HSDB_THREAD_STATE ARM_THREAD_STATE64172#define HSDB_FLOAT_STATE ARM_NEON_STATE64173#define HSDB_THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT174#define HSDB_FLOAT_STATE_COUNT ARM_NEON_STATE64_COUNT175#else176#error UNSUPPORTED_ARCH177#endif178179/*180* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal181* Method: init0182* Signature: ()V183*/184JNIEXPORT void JNICALL185Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {186symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");187CHECK_EXCEPTION;188taskID = (*env)->GetFieldID(env, cls, "task", "J");189CHECK_EXCEPTION;190191// for core file192p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J");193CHECK_EXCEPTION;194loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;");195CHECK_EXCEPTION;196197// methods we use198createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol",199"(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");200CHECK_EXCEPTION;201createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject",202"(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");203CHECK_EXCEPTION;204205// java.util.List method we call206jclass listClass = (*env)->FindClass(env, "java/util/List");207CHECK_EXCEPTION;208listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z");209CHECK_EXCEPTION;210getJavaThreadsInfo_ID = (*env)->GetMethodID(env, cls, "getJavaThreadsInfo",211"()[J");212CHECK_EXCEPTION;213214init_libproc(getenv("LIBSAPROC_DEBUG") != NULL);215}216217JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize218(JNIEnv *env, jclass cls)219{220#ifdef _LP64221return 8;222#else223#error UNSUPPORTED_ARCH224#endif225}226227/** called by Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0 */228jlong lookupByNameIncore(229JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jstring objectName, jstring symbolName)230{231const char *objectName_cstr, *symbolName_cstr;232jlong addr;233jboolean isCopy;234objectName_cstr = NULL;235if (objectName != NULL) {236objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy);237CHECK_EXCEPTION_(0);238}239symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);240if ((*env)->ExceptionOccurred(env)) {241if (objectName_cstr != NULL) {242(*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);243}244return 0;245}246247print_debug("look for %s \n", symbolName_cstr);248addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);249250if (objectName_cstr != NULL) {251(*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);252}253(*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);254return addr;255}256257/* Create a pool and initiate a try block to catch any exception */258#define JNI_COCOA_ENTER(env) \259NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \260@try {261262/* Don't allow NSExceptions to escape to Java.263* If there is a Java exception that has been thrown that should escape.264* And ensure we drain the auto-release pool.265*/266#define JNI_COCOA_EXIT(env) \267} \268@catch (NSException *e) { \269NSLog(@"%@", [e callStackSymbols]); \270} \271@finally { \272[pool drain]; \273};274275static NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {276277if (jstr == NULL) {278return NULL;279}280jsize len = (*env)->GetStringLength(env, jstr);281const jchar *chars = (*env)->GetStringChars(env, jstr, NULL);282if (chars == NULL) {283return NULL;284}285NSString *result = [NSString stringWithCharacters:(UniChar *)chars length:len];286(*env)->ReleaseStringChars(env, jstr, chars);287return result;288}289290/*291* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal292* Method: lookupByName0293* Signature: (Ljava/lang/String;Ljava/lang/String;)J294*/295JNIEXPORT jlong JNICALL296Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(297JNIEnv *env, jobject this_obj,298jstring objectName, jstring symbolName)299{300struct ps_prochandle* ph = get_proc_handle(env, this_obj);301if (ph != NULL && ph->core != NULL) {302return lookupByNameIncore(env, ph, this_obj, objectName, symbolName);303}304305jlong address = 0;306307JNI_COCOA_ENTER(env);308309NSString *symbolNameString = JavaStringToNSString(env, symbolName);310311print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]);312313id symbolicator = getSymbolicator(env, this_obj);314if (symbolicator != nil) {315uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend;316address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);317}318319print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);320JNI_COCOA_EXIT(env);321322return address;323}324325/*326* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal327* Method: lookupByAddress0328* Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;329*/330JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0331(JNIEnv *env, jobject this_obj, jlong addr) {332uintptr_t offset;333const char* sym = NULL;334jstring sym_string;335336struct ps_prochandle* ph = get_proc_handle(env, this_obj);337if (ph != NULL && ph->core != NULL) {338sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);339if (sym == NULL) return 0;340sym_string = (*env)->NewStringUTF(env, sym);341CHECK_EXCEPTION_(0);342return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,343sym_string, (jlong)offset);344}345return 0;346}347348/** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */349jbyteArray readBytesFromCore(350JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes)351{352jboolean isCopy;353jbyteArray array;354jbyte *bufPtr;355ps_err_e err;356357array = (*env)->NewByteArray(env, numBytes);358CHECK_EXCEPTION_(0);359bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy);360CHECK_EXCEPTION_(0);361362err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes);363(*env)->ReleaseByteArrayElements(env, array, bufPtr, 0);364return (err == PS_OK)? array : 0;365}366367/*368* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal369* Method: readBytesFromProcess0370* Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;371*/372JNIEXPORT jbyteArray JNICALL373Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(374JNIEnv *env, jobject this_obj,375jlong addr, jlong numBytes)376{377print_debug("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);378379// must allocate storage instead of using former parameter buf380jbyteArray array;381382struct ps_prochandle* ph = get_proc_handle(env, this_obj);383if (ph != NULL && ph->core != NULL) {384return readBytesFromCore(env, ph, this_obj, addr, numBytes);385}386387array = (*env)->NewByteArray(env, numBytes);388CHECK_EXCEPTION_(0);389390unsigned long alignedAddress;391unsigned long alignedLength = 0;392kern_return_t result;393vm_offset_t *pages;394int *mapped;395long pageCount;396uint byteCount;397int i;398unsigned long remaining;399400alignedAddress = trunc_page(addr);401if (addr != alignedAddress) {402alignedLength += addr - alignedAddress;403}404alignedLength = round_page(numBytes);405pageCount = alignedLength/vm_page_size;406407// Allocate storage for pages and flags.408pages = malloc(pageCount * sizeof(vm_offset_t));409if (pages == NULL) {410(*env)->DeleteLocalRef(env, array);411return NULL;412}413mapped = calloc(pageCount, sizeof(int));414if (mapped == NULL) {415(*env)->DeleteLocalRef(env, array);416free(pages);417return NULL;418}419420task_t gTask = getTask(env, this_obj);421// Try to read each of the pages.422for (i = 0; i < pageCount; i++) {423result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size,424&pages[i], &byteCount);425mapped[i] = (result == KERN_SUCCESS);426// assume all failures are unmapped pages427}428429print_debug("%ld pages\n", pageCount);430431remaining = numBytes;432433for (i = 0; i < pageCount; i++) {434unsigned long len = vm_page_size;435unsigned long start = 0;436437if (i == 0) {438start = addr - alignedAddress;439len = vm_page_size - start;440}441442if (i == (pageCount - 1)) {443len = remaining;444}445446if (mapped[i]) {447print_debug("page %d mapped (len %ld start %ld)\n", i, len, start);448(*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start));449vm_deallocate(mach_task_self(), pages[i], vm_page_size);450}451452remaining -= len;453}454455free (pages);456free (mapped);457return array;458}459460/** Only used for core file reading, set thread_id for threads which is got after core file parsed.461* Thread context is available in Mach-O core file but thread id is not. We can get thread id462* from Threads which store all java threads information when they are created. Here we can identify463* them as java threads by checking if a thread's rsp or rbp within a java thread's stack.464* Note Macosx uses unique_thread_id which is different from other platforms though printed ids465* are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long466* integers to host all java threads' id, stack_start, stack_end as:467* [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...]468*469* The work cannot be done at init0 since Threads is not available yet(VM not initialized yet).470* This function should be called only once if succeeded471*/472bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {473int n = 0, i = 0, j;474struct reg regs;475476jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID);477CHECK_EXCEPTION_(false);478int len = (int)(*env)->GetArrayLength(env, thrinfos);479uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL);480CHECK_EXCEPTION_(false);481n = get_num_threads(ph);482print_debug("fill_java_threads called, num_of_thread = %d\n", n);483for (i = 0; i < n; i++) {484if (!get_nth_lwp_regs(ph, i, ®s)) {485print_debug("Could not get regs of thread %d, already set!\n", i);486(*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0);487return false;488}489for (j = 0; j < len; j += 3) {490lwpid_t uid = cinfos[j];491uint64_t beg = cinfos[j + 1];492uint64_t end = cinfos[j + 2];493#if defined(amd64)494if ((regs.r_rsp < end && regs.r_rsp >= beg) ||495(regs.r_rbp < end && regs.r_rbp >= beg)) {496set_lwp_id(ph, i, uid);497break;498}499#elif defined(aarch64)500if ((regs.r_sp < end && regs.r_sp >= beg) ||501(regs.r_fp < end && regs.r_fp >= beg)) {502set_lwp_id(ph, i, uid);503break;504}505#else506#error UNSUPPORTED_ARCH507#endif508}509}510(*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0);511CHECK_EXCEPTION_(false);512return true;513}514515/* For core file only, called from516* Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0517*/518jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id, struct ps_prochandle* ph) {519if (!_threads_filled) {520if (!fill_java_threads(env, this_obj, ph)) {521throw_new_debugger_exception(env, "Failed to fill in threads");522return 0;523} else {524_threads_filled = true;525}526}527528struct reg gregs;529jboolean isCopy;530jlongArray array;531jlong *regs;532533if (get_lwp_regs(ph, lwp_id, &gregs) != true) {534THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);535}536537#undef NPRGREG538#undef REG_INDEX539#if defined(amd64)540#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG541#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg542#elif defined(aarch64)543#define NPRGREG sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_NPRGREG544#define REG_INDEX(reg) sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_##reg545#else546#error UNSUPPORTED_ARCH547#endif548549array = (*env)->NewLongArray(env, NPRGREG);550CHECK_EXCEPTION_(0);551regs = (*env)->GetLongArrayElements(env, array, &isCopy);552553#if defined(amd64)554555regs[REG_INDEX(R15)] = gregs.r_r15;556regs[REG_INDEX(R14)] = gregs.r_r14;557regs[REG_INDEX(R13)] = gregs.r_r13;558regs[REG_INDEX(R12)] = gregs.r_r12;559regs[REG_INDEX(RBP)] = gregs.r_rbp;560regs[REG_INDEX(RBX)] = gregs.r_rbx;561regs[REG_INDEX(R11)] = gregs.r_r11;562regs[REG_INDEX(R10)] = gregs.r_r10;563regs[REG_INDEX(R9)] = gregs.r_r9;564regs[REG_INDEX(R8)] = gregs.r_r8;565regs[REG_INDEX(RAX)] = gregs.r_rax;566regs[REG_INDEX(RCX)] = gregs.r_rcx;567regs[REG_INDEX(RDX)] = gregs.r_rdx;568regs[REG_INDEX(RSI)] = gregs.r_rsi;569regs[REG_INDEX(RDI)] = gregs.r_rdi;570regs[REG_INDEX(RIP)] = gregs.r_rip;571regs[REG_INDEX(CS)] = gregs.r_cs;572regs[REG_INDEX(RSP)] = gregs.r_rsp;573regs[REG_INDEX(SS)] = gregs.r_ss;574regs[REG_INDEX(FSBASE)] = 0;575regs[REG_INDEX(GSBASE)] = 0;576regs[REG_INDEX(DS)] = gregs.r_ds;577regs[REG_INDEX(ES)] = gregs.r_es;578regs[REG_INDEX(FS)] = gregs.r_fs;579regs[REG_INDEX(GS)] = gregs.r_gs;580regs[REG_INDEX(TRAPNO)] = gregs.r_trapno;581regs[REG_INDEX(RFL)] = gregs.r_rflags;582583#elif defined(aarch64)584585regs[REG_INDEX(R0)] = gregs.r_r0;586regs[REG_INDEX(R1)] = gregs.r_r1;587regs[REG_INDEX(R2)] = gregs.r_r2;588regs[REG_INDEX(R3)] = gregs.r_r3;589regs[REG_INDEX(R4)] = gregs.r_r4;590regs[REG_INDEX(R5)] = gregs.r_r5;591regs[REG_INDEX(R6)] = gregs.r_r6;592regs[REG_INDEX(R7)] = gregs.r_r7;593regs[REG_INDEX(R8)] = gregs.r_r8;594regs[REG_INDEX(R9)] = gregs.r_r9;595regs[REG_INDEX(R10)] = gregs.r_r10;596regs[REG_INDEX(R11)] = gregs.r_r11;597regs[REG_INDEX(R12)] = gregs.r_r12;598regs[REG_INDEX(R13)] = gregs.r_r13;599regs[REG_INDEX(R14)] = gregs.r_r14;600regs[REG_INDEX(R15)] = gregs.r_r15;601regs[REG_INDEX(R16)] = gregs.r_r16;602regs[REG_INDEX(R17)] = gregs.r_r17;603regs[REG_INDEX(R18)] = gregs.r_r18;604regs[REG_INDEX(R19)] = gregs.r_r19;605regs[REG_INDEX(R20)] = gregs.r_r20;606regs[REG_INDEX(R21)] = gregs.r_r21;607regs[REG_INDEX(R22)] = gregs.r_r22;608regs[REG_INDEX(R23)] = gregs.r_r23;609regs[REG_INDEX(R24)] = gregs.r_r24;610regs[REG_INDEX(R25)] = gregs.r_r25;611regs[REG_INDEX(R26)] = gregs.r_r26;612regs[REG_INDEX(R27)] = gregs.r_r27;613regs[REG_INDEX(R28)] = gregs.r_r28;614regs[REG_INDEX(FP)] = gregs.r_fp;615regs[REG_INDEX(LR)] = gregs.r_lr;616regs[REG_INDEX(SP)] = gregs.r_sp;617regs[REG_INDEX(PC)] = gregs.r_pc;618619#else620#error UNSUPPORTED_ARCH621#endif622623(*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);624return array;625}626627/*628* Lookup the thread_t that corresponds to the given thread_id.629* The thread_id should be the result from calling thread_info() with THREAD_IDENTIFIER_INFO630* and reading the m_ident_info.thread_id returned.631* The returned thread_t is the mach send right to the kernel port for the corresponding thread.632*633* We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self()634* in the VM, but that thread port is not valid for a remote debugger to access the thread.635*/636thread_t637lookupThreadFromThreadId(task_t task, jlong thread_id) {638print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id);639640thread_array_t thread_list = NULL;641mach_msg_type_number_t thread_list_count = 0;642thread_t result_thread = 0;643int i;644645// get the list of all the send rights646kern_return_t result = task_threads(task, &thread_list, &thread_list_count);647if (result != KERN_SUCCESS) {648print_debug("task_threads returned 0x%x\n", result);649return 0;650}651652for(i = 0 ; i < thread_list_count; i++) {653thread_identifier_info_data_t m_ident_info;654mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;655656// get the THREAD_IDENTIFIER_INFO for the send right657result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);658if (result != KERN_SUCCESS) {659print_debug("thread_info returned 0x%x\n", result);660break;661}662663// if this is the one we're looking for, return the send right664if (thread_id == m_ident_info.thread_id)665{666result_thread = thread_list[i];667break;668}669}670671vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t));672vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count);673674return result_thread;675}676677678/*679* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal680* Method: getThreadIntegerRegisterSet0681* Signature: (J)[J682*/683JNIEXPORT jlongArray JNICALL684Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(685JNIEnv *env, jobject this_obj,686jlong thread_id)687{688print_debug("getThreadIntegerRegisterSet0 called\n");689690struct ps_prochandle* ph = get_proc_handle(env, this_obj);691if (ph != NULL && ph->core != NULL) {692return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id, ph);693}694695kern_return_t result;696thread_t tid;697mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT;698hsdb_thread_state_t state;699jlongArray registerArray;700jlong *primitiveArray;701task_t gTask = getTask(env, this_obj);702703tid = lookupThreadFromThreadId(gTask, thread_id);704705result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);706707if (result != KERN_SUCCESS) {708// This is not considered fatal. Unlike on Linux and Windows, we haven't seen a709// failure to get thread registers, but if it were to fail the response should710// be the same. By ignoring this error and returning NULL, stacking walking code711// will get null registers and fallback to using the "last java frame" if setup.712fprintf(stdout, "WARNING: getThreadIntegerRegisterSet0: thread_get_state failed (%d) for thread (%d)\n",713result, tid);714fflush(stdout);715return NULL;716}717718#undef NPRGREG719#if defined(amd64)720#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG721#elif defined(aarch64)722#define NPRGREG sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_NPRGREG723#else724#error UNSUPPORTED_ARCH725#endif726727// 64 bit728print_debug("Getting threads for a 64-bit process\n");729registerArray = (*env)->NewLongArray(env, NPRGREG);730CHECK_EXCEPTION_(0);731primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);732733#if defined(amd64)734735primitiveArray[REG_INDEX(R15)] = state.__r15;736primitiveArray[REG_INDEX(R14)] = state.__r14;737primitiveArray[REG_INDEX(R13)] = state.__r13;738primitiveArray[REG_INDEX(R12)] = state.__r12;739primitiveArray[REG_INDEX(R11)] = state.__r11;740primitiveArray[REG_INDEX(R10)] = state.__r10;741primitiveArray[REG_INDEX(R9)] = state.__r9;742primitiveArray[REG_INDEX(R8)] = state.__r8;743primitiveArray[REG_INDEX(RDI)] = state.__rdi;744primitiveArray[REG_INDEX(RSI)] = state.__rsi;745primitiveArray[REG_INDEX(RBP)] = state.__rbp;746primitiveArray[REG_INDEX(RBX)] = state.__rbx;747primitiveArray[REG_INDEX(RDX)] = state.__rdx;748primitiveArray[REG_INDEX(RCX)] = state.__rcx;749primitiveArray[REG_INDEX(RAX)] = state.__rax;750primitiveArray[REG_INDEX(TRAPNO)] = 0; // trapno, not used751primitiveArray[REG_INDEX(ERR)] = 0; // err, not used752primitiveArray[REG_INDEX(RIP)] = state.__rip;753primitiveArray[REG_INDEX(CS)] = state.__cs;754primitiveArray[REG_INDEX(RFL)] = state.__rflags;755primitiveArray[REG_INDEX(RSP)] = state.__rsp;756primitiveArray[REG_INDEX(SS)] = 0; // We don't have SS757primitiveArray[REG_INDEX(FS)] = state.__fs;758primitiveArray[REG_INDEX(GS)] = state.__gs;759primitiveArray[REG_INDEX(ES)] = 0;760primitiveArray[REG_INDEX(DS)] = 0;761primitiveArray[REG_INDEX(FSBASE)] = 0;762primitiveArray[REG_INDEX(GSBASE)] = 0;763764#elif defined(aarch64)765766primitiveArray[REG_INDEX(R0)] = state.__x[0];767primitiveArray[REG_INDEX(R1)] = state.__x[1];768primitiveArray[REG_INDEX(R2)] = state.__x[2];769primitiveArray[REG_INDEX(R3)] = state.__x[3];770primitiveArray[REG_INDEX(R4)] = state.__x[4];771primitiveArray[REG_INDEX(R5)] = state.__x[5];772primitiveArray[REG_INDEX(R6)] = state.__x[6];773primitiveArray[REG_INDEX(R7)] = state.__x[7];774primitiveArray[REG_INDEX(R8)] = state.__x[8];775primitiveArray[REG_INDEX(R9)] = state.__x[9];776primitiveArray[REG_INDEX(R10)] = state.__x[10];777primitiveArray[REG_INDEX(R11)] = state.__x[11];778primitiveArray[REG_INDEX(R12)] = state.__x[12];779primitiveArray[REG_INDEX(R13)] = state.__x[13];780primitiveArray[REG_INDEX(R14)] = state.__x[14];781primitiveArray[REG_INDEX(R15)] = state.__x[15];782primitiveArray[REG_INDEX(R16)] = state.__x[16];783primitiveArray[REG_INDEX(R17)] = state.__x[17];784primitiveArray[REG_INDEX(R18)] = state.__x[18];785primitiveArray[REG_INDEX(R19)] = state.__x[19];786primitiveArray[REG_INDEX(R20)] = state.__x[20];787primitiveArray[REG_INDEX(R21)] = state.__x[21];788primitiveArray[REG_INDEX(R22)] = state.__x[22];789primitiveArray[REG_INDEX(R23)] = state.__x[23];790primitiveArray[REG_INDEX(R24)] = state.__x[24];791primitiveArray[REG_INDEX(R25)] = state.__x[25];792primitiveArray[REG_INDEX(R26)] = state.__x[26];793primitiveArray[REG_INDEX(R27)] = state.__x[27];794primitiveArray[REG_INDEX(R28)] = state.__x[28];795primitiveArray[REG_INDEX(FP)] = state.__fp;796primitiveArray[REG_INDEX(LR)] = state.__lr;797primitiveArray[REG_INDEX(SP)] = state.__sp;798primitiveArray[REG_INDEX(PC)] = state.__pc;799800#else801#error UNSUPPORTED_ARCH802#endif803804print_debug("set registers\n");805806(*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);807return registerArray;808}809810/*811* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal812* Method: translateTID0813* Signature: (I)I814*/815JNIEXPORT jint JNICALL816Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(817JNIEnv *env, jobject this_obj, jint tid)818{819print_debug("translateTID0 called on tid = 0x%x\n", (int)tid);820821kern_return_t result;822thread_t foreign_tid, usable_tid;823mach_msg_type_name_t type;824825foreign_tid = tid;826827task_t gTask = getTask(env, this_obj);828result = mach_port_extract_right(gTask, foreign_tid,829MACH_MSG_TYPE_COPY_SEND,830&usable_tid, &type);831if (result != KERN_SUCCESS)832return -1;833834print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);835836return (jint) usable_tid;837}838839// attach to a process/thread specified by "pid"840static bool ptrace_attach(pid_t pid) {841errno = 0;842ptrace(PT_ATTACHEXC, pid, 0, 0);843844if (errno != 0) {845print_error("ptrace_attach: ptrace(PT_ATTACHEXC,...) failed: %s", strerror(errno));846return false;847}848return true;849}850851kern_return_t catch_mach_exception_raise(852mach_port_t exception_port, mach_port_t thread_port, mach_port_t task_port,853exception_type_t exception_type, mach_exception_data_t codes,854mach_msg_type_number_t num_codes) {855856print_debug("catch_mach_exception_raise: Exception port = %d thread_port = %d "857"task port %d exc type = %d num_codes %d\n",858exception_port, thread_port, task_port, exception_type, num_codes);859860// This message should denote a Unix soft signal, with861// 1. the exception type = EXC_SOFTWARE862// 2. codes[0] (which is the code) = EXC_SOFT_SIGNAL863// 3. codes[1] (which is the sub-code) = SIGSTOP864if (!(exception_type == EXC_SOFTWARE &&865codes[0] == EXC_SOFT_SIGNAL &&866codes[num_codes -1] == SIGSTOP)) {867print_error("catch_mach_exception_raise: Message doesn't denote a Unix "868"soft signal. exception_type = %d, codes[0] = %d, "869"codes[num_codes -1] = %d, num_codes = %d\n",870exception_type, codes[0], codes[num_codes - 1], num_codes);871return MACH_RCV_INVALID_TYPE;872}873return KERN_SUCCESS;874}875876kern_return_t catch_mach_exception_raise_state(877mach_port_t exception_port, exception_type_t exception, const mach_exception_data_t code,878mach_msg_type_number_t code_cnt, int *flavor, const thread_state_t old_state,879mach_msg_type_number_t old_state_cnt, thread_state_t new_state,880mach_msg_type_number_t *new_state_cnt) {881return MACH_RCV_INVALID_TYPE;882}883884885kern_return_t catch_mach_exception_raise_state_identity(886mach_port_t exception_port, mach_port_t thread, mach_port_t task,887exception_type_t exception, mach_exception_data_t code,888mach_msg_type_number_t code_cnt, int *flavor,889thread_state_t old_state, mach_msg_type_number_t old_state_cnt,890thread_state_t new_state, mach_msg_type_number_t *new_state_cnt) {891return MACH_RCV_INVALID_TYPE;892}893894// wait to receive an exception message895static bool wait_for_exception() {896kern_return_t result;897898result = mach_msg(&exc_msg.header,899MACH_RCV_MSG,9000,901sizeof(exc_msg),902tgt_exception_port,903MACH_MSG_TIMEOUT_NONE,904MACH_PORT_NULL);905906if (result != MACH_MSG_SUCCESS) {907print_error("attach: wait_for_exception: mach_msg() failed: '%s' (%d)\n",908mach_error_string(result), result);909return false;910}911912if (mach_exc_server(&exc_msg.header, &rep_msg.header) == false ||913rep_msg.ret_code != KERN_SUCCESS) {914print_error("attach: wait_for_exception: mach_exc_server failure\n");915if (rep_msg.ret_code != KERN_SUCCESS) {916print_error("catch_mach_exception_raise() failed '%s' (%d)\n",917mach_error_string(rep_msg.ret_code), rep_msg.ret_code);918}919return false;920}921922print_debug("reply msg from mach_exc_server: (msg->{bits = %#x, size = %u, "923"remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x},)",924rep_msg.header.msgh_bits, rep_msg.header.msgh_size,925rep_msg.header.msgh_remote_port, rep_msg.header.msgh_local_port,926rep_msg.header.msgh_reserved, rep_msg.header.msgh_id);927928return true;929}930931/*932* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal933* Method: attach0934* Signature: (I)V935*/936JNIEXPORT void JNICALL937Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(938JNIEnv *env, jobject this_obj, jint jpid)939{940print_debug("attach0 called for jpid=%d\n", (int)jpid);941942JNI_COCOA_ENTER(env);943944kern_return_t result;945task_t gTask = 0;946947result = task_for_pid(mach_task_self(), jpid, &gTask);948if (result != KERN_SUCCESS) {949print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result);950THROW_NEW_DEBUGGER_EXCEPTION(951"Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.");952}953putTask(env, this_obj, gTask);954955// Allocate an exception port.956result = mach_port_allocate(mach_task_self(),957MACH_PORT_RIGHT_RECEIVE,958&tgt_exception_port);959if (result != KERN_SUCCESS) {960print_error("attach: mach_port_allocate() for tgt_exception_port failed: '%s' (%d)\n",961mach_error_string(result), result);962THROW_NEW_DEBUGGER_EXCEPTION(963"Can't attach to the process. Couldn't allocate an exception port.");964}965966// Enable the new exception port to send messages.967result = mach_port_insert_right (mach_task_self(),968tgt_exception_port,969tgt_exception_port,970MACH_MSG_TYPE_MAKE_SEND);971if (result != KERN_SUCCESS) {972print_error("attach: mach_port_insert_right() failed for port 0x%x: '%s' (%d)\n",973tgt_exception_port, mach_error_string(result), result);974THROW_NEW_DEBUGGER_EXCEPTION(975"Can't attach to the process. Couldn't add send privileges to the exception port.");976}977978// Save the existing original exception ports registered with the target979// process (for later restoration while detaching from the process).980result = task_get_exception_ports(gTask,981EXC_MASK_ALL,982exception_saved_state.saved_masks,983&exception_saved_state.saved_exception_types_count,984exception_saved_state.saved_ports,985exception_saved_state.saved_behaviors,986exception_saved_state.saved_flavors);987988if (result != KERN_SUCCESS) {989print_error("attach: task_get_exception_ports() failed: '%s' (%d)\n",990mach_error_string(result), result);991THROW_NEW_DEBUGGER_EXCEPTION(992"Can't attach to the process. Could not get the target exception ports.");993}994995// register the exception port to be used for all future exceptions with the996// target process.997result = task_set_exception_ports(gTask,998EXC_MASK_ALL,999tgt_exception_port,1000EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,1001THREAD_STATE_NONE);10021003if (result != KERN_SUCCESS) {1004print_error("attach: task_set_exception_ports() failed -- port 0x%x: '%s' (%d)\n",1005tgt_exception_port, mach_error_string(result), result);1006mach_port_deallocate(mach_task_self(), gTask);1007mach_port_deallocate(mach_task_self(), tgt_exception_port);1008THROW_NEW_DEBUGGER_EXCEPTION(1009"Can't attach to the process. Could not register the exception port "1010"with the target process.");1011}10121013// use ptrace to stop the process1014// on os x, ptrace only needs to be called on the process, not the individual threads1015if (ptrace_attach(jpid) != true) {1016print_error("attach: ptrace failure in attaching to %d\n", (int)jpid);1017mach_port_deallocate(mach_task_self(), gTask);1018mach_port_deallocate(mach_task_self(), tgt_exception_port);1019THROW_NEW_DEBUGGER_EXCEPTION("Can't ptrace attach to the process");1020}10211022if (wait_for_exception() != true) {1023mach_port_deallocate(mach_task_self(), gTask);1024mach_port_deallocate(mach_task_self(), tgt_exception_port);1025THROW_NEW_DEBUGGER_EXCEPTION(1026"Can't attach to the process. Issues with reception of the exception message.");1027}10281029// suspend all the threads in the task1030result = task_suspend(gTask);1031if (result != KERN_SUCCESS) {1032print_error("attach: task_suspend() failed: '%s' (%d)\n",1033mach_error_string(result), result);1034mach_port_deallocate(mach_task_self(), gTask);1035mach_port_deallocate(mach_task_self(), tgt_exception_port);1036THROW_NEW_DEBUGGER_EXCEPTION("Can't attach. Unable to suspend all the threads in the task.");1037}10381039id symbolicator = nil;1040id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");1041if (jrsSymbolicator != nil) {1042id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;1043symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);1044}1045if (symbolicator != nil) {1046CFRetain(symbolicator); // pin symbolicator while in java heap1047}10481049putSymbolicator(env, this_obj, symbolicator);1050if (symbolicator == nil) {1051mach_port_deallocate(mach_task_self(), gTask);1052mach_port_deallocate(mach_task_self(), tgt_exception_port);1053THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");1054}10551056JNI_COCOA_EXIT(env);1057}10581059/** For core file,1060called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */1061static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {1062int n = 0, i = 0;1063jobject loadObjectList;10641065loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);1066CHECK_EXCEPTION;10671068// add load objects1069n = get_num_libs(ph);1070for (i = 0; i < n; i++) {1071uintptr_t base, memsz;1072const char* name;1073jobject loadObject;1074jstring nameString;10751076get_lib_addr_range(ph, i, &base, &memsz);1077name = get_lib_name(ph, i);1078nameString = (*env)->NewStringUTF(env, name);1079CHECK_EXCEPTION;1080loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID,1081nameString, (jlong)memsz, (jlong)base);1082CHECK_EXCEPTION;1083(*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject);1084CHECK_EXCEPTION;1085(*env)->DeleteLocalRef(env, nameString);1086(*env)->DeleteLocalRef(env, loadObject);1087}1088}10891090/*1091* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal1092* Method: attach01093* Signature: (Ljava/lang/String;Ljava/lang/String;)V1094*/1095JNIEXPORT void JNICALL1096Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2(1097JNIEnv *env, jobject this_obj, jstring execName, jstring coreName)1098{1099const char *execName_cstr;1100const char *coreName_cstr;1101jboolean isCopy;1102struct ps_prochandle* ph;11031104execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy);1105CHECK_EXCEPTION;1106coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy);1107if ((*env)->ExceptionOccurred(env)) {1108(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);1109return;1110}11111112print_debug("attach: %s %s\n", execName_cstr, coreName_cstr);11131114if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {1115(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);1116(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);1117THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");1118}1119(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);1120(*env)->ReleaseStringUTFChars(env, execName, execName_cstr);1121(*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);1122fillLoadObjects(env, this_obj, ph);1123}11241125static void detach_cleanup(task_t gTask, JNIEnv *env, jobject this_obj, bool throw_exception) {1126mach_port_deallocate(mach_task_self(), tgt_exception_port);1127mach_port_deallocate(mach_task_self(), gTask);11281129id symbolicator = getSymbolicator(env, this_obj);1130if (symbolicator != nil) {1131CFRelease(symbolicator);1132}1133if (throw_exception) {1134THROW_NEW_DEBUGGER_EXCEPTION("Cannot detach.");1135}1136}11371138/*1139* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal1140* Method: detach01141* Signature: ()V1142*/1143JNIEXPORT void JNICALL1144Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(1145JNIEnv *env, jobject this_obj)1146{1147print_debug("detach0 called\n");1148struct ps_prochandle* ph = get_proc_handle(env, this_obj);1149if (ph != NULL && ph->core != NULL) {1150Prelease(ph);1151return;1152}11531154JNI_COCOA_ENTER(env);11551156task_t gTask = getTask(env, this_obj);1157kern_return_t k_res = 0;11581159// Restore the pre-saved original exception ports registered with the target process1160for (uint32_t i = 0; i < exception_saved_state.saved_exception_types_count; ++i) {1161k_res = task_set_exception_ports(gTask,1162exception_saved_state.saved_masks[i],1163exception_saved_state.saved_ports[i],1164exception_saved_state.saved_behaviors[i],1165exception_saved_state.saved_flavors[i]);1166if (k_res != KERN_SUCCESS) {1167print_error("detach: task_set_exception_ports failed with %d while "1168"restoring the target exception ports.\n", k_res);1169detach_cleanup(gTask, env, this_obj, true);1170}1171}11721173// detach from the ptraced process causing it to resume execution1174int pid;1175k_res = pid_for_task(gTask, &pid);1176if (k_res != KERN_SUCCESS) {1177print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res);1178detach_cleanup(gTask, env, this_obj, true);1179}1180else {1181errno = 0;1182ptrace(PT_DETACH, pid, (caddr_t)1, 0);1183if (errno != 0) {1184print_error("detach: ptrace(PT_DETACH,...) failed: %s", strerror(errno));1185detach_cleanup(gTask, env, this_obj, true);1186}1187}11881189// reply to the previous exception message1190k_res = mach_msg(&rep_msg.header,1191MACH_SEND_MSG| MACH_SEND_INTERRUPT,1192rep_msg.header.msgh_size,11930,1194MACH_PORT_NULL,1195MACH_MSG_TIMEOUT_NONE,1196MACH_PORT_NULL);1197if (k_res != MACH_MSG_SUCCESS) {1198print_error("detach: mach_msg() for replying to pending exceptions failed: '%s' (%d)\n",1199mach_error_string(k_res), k_res);1200detach_cleanup(gTask, env, this_obj, true);1201}12021203detach_cleanup(gTask, env, this_obj, false);12041205JNI_COCOA_EXIT(env);1206}120712081209