1/*
2 * Copyright (c) 2002, 2017, Oracle and/or its affiliates. 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 it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 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 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include <objc/objc-runtime.h>
26#import <Foundation/Foundation.h>
27#import <JavaNativeFoundation/JavaNativeFoundation.h>
28#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
29
30#include <jni.h>
31
32#import <mach/mach.h>
33#import <mach/mach_types.h>
34#import <sys/sysctl.h>
35#import <stdio.h>
36#import <stdarg.h>
37#import <stdlib.h>
38#import <strings.h>
39#import <dlfcn.h>
40#import <limits.h>
41#import <errno.h>
42#import <sys/types.h>
43#import <sys/ptrace.h>
44#include "libproc_impl.h"
45
46#define UNSUPPORTED_ARCH "Unsupported architecture!"
47
48#if defined(x86_64) && !defined(amd64)
49#define amd64 1
50#endif
51
52#if amd64
53#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
54#else
55#error UNSUPPORTED_ARCH
56#endif
57
58static jfieldID symbolicatorID = 0; // set in _init0
59static jfieldID taskID = 0; // set in _init0
60
61static jfieldID p_ps_prochandle_ID = 0;
62static jfieldID loadObjectList_ID = 0;
63static jmethodID listAdd_ID = 0;
64
65static jmethodID createClosestSymbol_ID = 0;
66static jmethodID createLoadObject_ID = 0;
67static jmethodID getJavaThreadsInfo_ID = 0;
68
69// indicator if thread id (lwpid_t) was set
70static bool _threads_filled = false;
71
72static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {
73  (*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);
74}
75
76static id getSymbolicator(JNIEnv *env, jobject this_obj) {
77  jlong ptr = (*env)->GetLongField(env, this_obj, symbolicatorID);
78  return (id)(intptr_t)ptr;
79}
80
81static void putTask(JNIEnv *env, jobject this_obj, task_t task) {
82  (*env)->SetLongField(env, this_obj, taskID, (jlong)task);
83}
84
85static task_t getTask(JNIEnv *env, jobject this_obj) {
86  jlong ptr = (*env)->GetLongField(env, this_obj, taskID);
87  return (task_t)ptr;
88}
89
90#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; } 
97
98static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
99  jclass exceptionClass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException");
100  CHECK_EXCEPTION;
101  (*env)->ThrowNew(env, exceptionClass, errMsg);
102}
103
104static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {
105  jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID);
106  return (struct ps_prochandle*)(intptr_t)ptr;
107}
108
109#if defined(__i386__)
110    #define hsdb_thread_state_t     x86_thread_state32_t
111    #define hsdb_float_state_t      x86_float_state32_t
112    #define HSDB_THREAD_STATE       x86_THREAD_STATE32
113    #define HSDB_FLOAT_STATE        x86_FLOAT_STATE32
114    #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
115    #define HSDB_FLOAT_STATE_COUNT  x86_FLOAT_STATE32_COUNT
116#elif defined(__x86_64__)
117    #define hsdb_thread_state_t     x86_thread_state64_t
118    #define hsdb_float_state_t      x86_float_state64_t
119    #define HSDB_THREAD_STATE       x86_THREAD_STATE64
120    #define HSDB_FLOAT_STATE        x86_FLOAT_STATE64
121    #define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
122    #define HSDB_FLOAT_STATE_COUNT  x86_FLOAT_STATE64_COUNT
123#else
124    #error UNSUPPORTED_ARCH
125#endif
126
127/*
128 * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
129 * Method:    init0
130 * Signature: ()V
131 */
132JNIEXPORT void JNICALL 
133Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) {
134  symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");
135  CHECK_EXCEPTION;
136  taskID = (*env)->GetFieldID(env, cls, "task", "J");
137  CHECK_EXCEPTION;
138
139  // for core file
140  p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J");
141  CHECK_EXCEPTION;
142  loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;");
143  CHECK_EXCEPTION;
144
145  // methods we use
146  createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol",
147                    "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
148  CHECK_EXCEPTION;
149  createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject",
150                    "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");
151  CHECK_EXCEPTION;
152
153  // java.util.List method we call
154  jclass listClass = (*env)->FindClass(env, "java/util/List");
155  CHECK_EXCEPTION;
156  listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z");
157  CHECK_EXCEPTION;
158  getJavaThreadsInfo_ID = (*env)->GetMethodID(env, cls, "getJavaThreadsInfo",
159                                                     "()[J");
160  CHECK_EXCEPTION;
161
162  init_libproc(getenv("LIBSAPROC_DEBUG") != NULL);
163}
164
165JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize
166  (JNIEnv *env, jclass cls)
167{
168#ifdef _LP64
169  return 8;
170#else
171  #error UNSUPPORTED_ARCH
172#endif
173}
174
175/** called by Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0 */
176jlong lookupByNameIncore(
177  JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jstring objectName, jstring symbolName)
178{
179  const char *objectName_cstr, *symbolName_cstr;
180  jlong addr;
181  jboolean isCopy;
182  objectName_cstr = NULL;
183  if (objectName != NULL) {
184    objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy);
185    CHECK_EXCEPTION_(0);
186  }
187  symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);
188  CHECK_EXCEPTION_(0);
189
190  print_debug("look for %s \n", symbolName_cstr);
191  addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);
192
193  if (objectName_cstr != NULL) {
194    (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);
195  }
196  (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);
197  return addr;
198}
199
200/*
201 * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
202 * Method:    lookupByName0
203 * Signature: (Ljava/lang/String;Ljava/lang/String;)J
204 */
205JNIEXPORT jlong JNICALL 
206Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(
207  JNIEnv *env, jobject this_obj, 
208  jstring objectName, jstring symbolName) 
209{
210  struct ps_prochandle* ph = get_proc_handle(env, this_obj);
211  if (ph != NULL && ph->core != NULL) {
212    return lookupByNameIncore(env, ph, this_obj, objectName, symbolName);
213  }
214
215  jlong address = 0;
216
217JNF_COCOA_ENTER(env);
218  NSString *symbolNameString = JNFJavaToNSString(env, symbolName);
219
220  print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]);
221
222  id symbolicator = getSymbolicator(env, this_obj);
223  if (symbolicator != nil) {
224    uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend;
225    address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);
226  }
227
228  print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);
229JNF_COCOA_EXIT(env);
230
231  return address;
232}
233
234/*
235 * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
236 * Method:    lookupByAddress0
237 * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
238 */
239JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0
240  (JNIEnv *env, jobject this_obj, jlong addr) {
241  uintptr_t offset;
242  const char* sym = NULL;
243  jstring sym_string;
244
245  struct ps_prochandle* ph = get_proc_handle(env, this_obj);
246  if (ph != NULL && ph->core != NULL) {
247    sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
248    if (sym == NULL) return 0;
249    sym_string = (*env)->NewStringUTF(env, sym);
250    CHECK_EXCEPTION_(0);
251    return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
252                                                sym_string, (jlong)offset);
253  }
254  return 0;
255}
256
257/** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */
258jbyteArray readBytesFromCore(
259  JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes)
260{
261  jboolean isCopy;
262  jbyteArray array;
263  jbyte *bufPtr;
264  ps_err_e err;
265
266  array = (*env)->NewByteArray(env, numBytes);
267  CHECK_EXCEPTION_(0);
268  bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy);
269  CHECK_EXCEPTION_(0);
270
271  err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes);
272  (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0);
273  return (err == PS_OK)? array : 0;
274}
275
276/*
277 * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
278 * Method:    readBytesFromProcess0
279 * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
280 */
281JNIEXPORT jbyteArray JNICALL
282Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
283  JNIEnv *env, jobject this_obj, 
284  jlong addr, jlong numBytes) 
285{
286  print_debug("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);
287
288  // must allocate storage instead of using former parameter buf
289  jbyteArray array;
290
291  struct ps_prochandle* ph = get_proc_handle(env, this_obj);
292  if (ph != NULL && ph->core != NULL) {
293    return readBytesFromCore(env, ph, this_obj, addr, numBytes);
294  }
295
296  array = (*env)->NewByteArray(env, numBytes);
297  CHECK_EXCEPTION_(0);
298
299  unsigned long alignedAddress;
300  unsigned long alignedLength = 0;
301  kern_return_t result;
302  vm_offset_t *pages;
303  int *mapped;
304  long pageCount;
305  uint byteCount;
306  int i;
307  unsigned long remaining;
308
309  alignedAddress = trunc_page(addr);
310  if (addr != alignedAddress) {
311    alignedLength += addr - alignedAddress;
312  }
313  alignedLength = round_page(numBytes);
314  pageCount = alignedLength/vm_page_size;
315
316  // Allocate storage for pages and flags.
317  pages = malloc(pageCount * sizeof(vm_offset_t));
318  mapped = calloc(pageCount, sizeof(int));
319
320  task_t gTask = getTask(env, this_obj);
321  // Try to read each of the pages.
322  for (i = 0; i < pageCount; i++) {
323    result = vm_read(gTask, alignedAddress + i*vm_page_size, vm_page_size, 
324		     &pages[i], &byteCount);
325    mapped[i] = (result == KERN_SUCCESS); 
326    // assume all failures are unmapped pages
327  }
328
329  print_debug("%ld pages\n", pageCount);
330	
331  remaining = numBytes;
332	
333  for (i = 0; i < pageCount; i++) {
334    unsigned long len = vm_page_size;
335    unsigned long start = 0;
336
337    if (i == 0) {
338      start = addr - alignedAddress;
339      len = vm_page_size - start;
340    }
341
342    if (i == (pageCount - 1)) {
343      len = remaining;
344    }
345
346    if (mapped[i]) {
347      print_debug("page %d mapped (len %ld start %ld)\n", i, len, start);
348      (*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start));
349      vm_deallocate(mach_task_self(), pages[i], vm_page_size);
350    }
351
352    remaining -= len;
353  }
354
355  free (pages);
356  free (mapped);
357  return array;
358}
359
360/** Only used for core file reading, set thread_id for threads which is got after core file parsed.
361  * Thread context is available in Mach-O core file but thread id is not. We can get thread id
362  * from Threads which store all java threads information when they are created. Here we can identify
363  * them as java threads by checking if a thread's rsp or rbp within a java thread's stack.
364  * Note Macosx uses unique_thread_id which is different from other platforms though printed ids
365  * are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long
366  * integers to host all java threads' id, stack_start, stack_end as:
367  * [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...]
368  *
369  * The work cannot be done at init0 since Threads is not available yet(VM not initialized yet). 
370  * This function should be called only once if succeeded
371  */ 
372bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
373  int n = 0, i = 0, j;
374  struct reg regs;
375  
376  jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID);
377  CHECK_EXCEPTION_(false);
378  int len = (int)(*env)->GetArrayLength(env, thrinfos);
379  uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL);
380  CHECK_EXCEPTION_(false); 
381  n = get_num_threads(ph);
382  print_debug("fill_java_threads called, num_of_thread = %d\n", n);
383  for (i = 0; i < n; i++) {
384    if (!get_nth_lwp_regs(ph, i, &regs)) {
385      print_debug("Could not get regs of thread %d, already set!\n", i);
386      return false;
387    }
388    for (j = 0; j < len; j += 3) {
389      lwpid_t  uid = cinfos[j];
390      uint64_t beg = cinfos[j + 1];
391      uint64_t end = cinfos[j + 2]; 
392      if ((regs.r_rsp < end && regs.r_rsp >= beg) ||
393          (regs.r_rbp < end && regs.r_rbp >= beg)) {
394        set_lwp_id(ph, i, uid);
395        break;
396      }
397    }
398  }
399  (*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0);
400  CHECK_EXCEPTION_(false);
401  return true;
402}
403
404/* For core file only, called from
405 * Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0
406 */
407jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id, struct ps_prochandle* ph) {
408  if (!_threads_filled)  {
409    if (!fill_java_threads(env, this_obj, ph)) {
410      throw_new_debugger_exception(env, "Failed to fill in threads");
411      return 0;
412    } else {
413      _threads_filled = true;
414    }
415  }
416
417  struct reg gregs;
418  jboolean isCopy;
419  jlongArray array;
420  jlong *regs;
421
422  if (get_lwp_regs(ph, lwp_id, &gregs) != true) {
423    THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);
424  }
425
426#undef NPRGREG
427#undef REG_INDEX
428#if amd64
429#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
430#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg
431
432  array = (*env)->NewLongArray(env, NPRGREG);
433  CHECK_EXCEPTION_(0);
434  regs = (*env)->GetLongArrayElements(env, array, &isCopy);
435
436  regs[REG_INDEX(R15)] = gregs.r_r15;
437  regs[REG_INDEX(R14)] = gregs.r_r14;
438  regs[REG_INDEX(R13)] = gregs.r_r13;
439  regs[REG_INDEX(R12)] = gregs.r_r12;
440  regs[REG_INDEX(RBP)] = gregs.r_rbp;
441  regs[REG_INDEX(RBX)] = gregs.r_rbx;
442  regs[REG_INDEX(R11)] = gregs.r_r11;
443  regs[REG_INDEX(R10)] = gregs.r_r10;
444  regs[REG_INDEX(R9)]  = gregs.r_r9;
445  regs[REG_INDEX(R8)]  = gregs.r_r8;
446  regs[REG_INDEX(RAX)] = gregs.r_rax;
447  regs[REG_INDEX(RCX)] = gregs.r_rcx;
448  regs[REG_INDEX(RDX)] = gregs.r_rdx;
449  regs[REG_INDEX(RSI)] = gregs.r_rsi;
450  regs[REG_INDEX(RDI)] = gregs.r_rdi;
451  regs[REG_INDEX(RIP)] = gregs.r_rip;
452  regs[REG_INDEX(CS)]  = gregs.r_cs;
453  regs[REG_INDEX(RSP)] = gregs.r_rsp;
454  regs[REG_INDEX(SS)]  = gregs.r_ss;
455  regs[REG_INDEX(FSBASE)] = 0;
456  regs[REG_INDEX(GSBASE)] = 0;
457  regs[REG_INDEX(DS)] = gregs.r_ds;
458  regs[REG_INDEX(ES)] = gregs.r_es;
459  regs[REG_INDEX(FS)] = gregs.r_fs;
460  regs[REG_INDEX(GS)] = gregs.r_gs;
461  regs[REG_INDEX(TRAPNO)] = gregs.r_trapno;
462  regs[REG_INDEX(RFL)]    = gregs.r_rflags;
463
464#endif /* amd64 */
465  (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);
466  return array;
467}
468
469/*
470 * Lookup the thread_t that corresponds to the given thread_id.
471 * The thread_id should be the result from calling thread_info() with THREAD_IDENTIFIER_INFO
472 * and reading the m_ident_info.thread_id returned.
473 * The returned thread_t is the mach send right to the kernel port for the corresponding thread.
474 *
475 * We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self()
476 * in the VM, but that thread port is not valid for a remote debugger to access the thread.
477 */
478thread_t
479lookupThreadFromThreadId(task_t task, jlong thread_id) {
480  print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id);
481  
482  thread_array_t thread_list = NULL;
483  mach_msg_type_number_t thread_list_count = 0;
484  thread_t result_thread = 0;
485  int i;
486  
487  // get the list of all the send rights
488  kern_return_t result = task_threads(task, &thread_list, &thread_list_count);
489  if (result != KERN_SUCCESS) {
490    print_debug("task_threads returned 0x%x\n", result);
491    return 0;
492  }
493  
494  for(i = 0 ; i < thread_list_count; i++) {
495    thread_identifier_info_data_t m_ident_info;
496    mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
497
498    // get the THREAD_IDENTIFIER_INFO for the send right
499    result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
500    if (result != KERN_SUCCESS) {
501      print_debug("thread_info returned 0x%x\n", result);
502      break;
503    }
504    
505    // if this is the one we're looking for, return the send right
506    if (thread_id == m_ident_info.thread_id)
507    {
508      result_thread = thread_list[i];
509      break;
510    }
511  }
512  
513  vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t));
514  vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count);
515  
516  return result_thread;
517}
518
519
520/*
521 * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
522 * Method:    getThreadIntegerRegisterSet0
523 * Signature: (J)[J
524 */
525JNIEXPORT jlongArray JNICALL 
526Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(
527  JNIEnv *env, jobject this_obj, 
528  jlong thread_id) 
529{
530  print_debug("getThreadRegisterSet0 called\n");
531
532  struct ps_prochandle* ph = get_proc_handle(env, this_obj);
533  if (ph != NULL && ph->core != NULL) {
534    return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id, ph);
535  }
536
537  kern_return_t result;
538  thread_t tid;
539  mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT;
540  hsdb_thread_state_t state;
541  jlongArray registerArray;
542  jlong *primitiveArray;
543  task_t gTask = getTask(env, this_obj);
544
545  tid = lookupThreadFromThreadId(gTask, thread_id);
546
547  result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);
548
549  if (result != KERN_SUCCESS) {
550    print_error("getregs: thread_get_state(%d) failed (%d)\n", tid, result);
551    return NULL;
552  }
553
554#if amd64
555#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
556#undef REG_INDEX
557#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg
558
559  // 64 bit
560  print_debug("Getting threads for a 64-bit process\n");
561  registerArray = (*env)->NewLongArray(env, NPRGREG);
562  CHECK_EXCEPTION_(0);
563  primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
564
565  primitiveArray[REG_INDEX(R15)] = state.__r15;
566  primitiveArray[REG_INDEX(R14)] = state.__r14;
567  primitiveArray[REG_INDEX(R13)] = state.__r13;
568  primitiveArray[REG_INDEX(R12)] = state.__r12;
569  primitiveArray[REG_INDEX(R11)] = state.__r11;
570  primitiveArray[REG_INDEX(R10)] = state.__r10;
571  primitiveArray[REG_INDEX(R9)]  = state.__r9;
572  primitiveArray[REG_INDEX(R8)]  = state.__r8;
573  primitiveArray[REG_INDEX(RDI)] = state.__rdi;
574  primitiveArray[REG_INDEX(RSI)] = state.__rsi;
575  primitiveArray[REG_INDEX(RBP)] = state.__rbp;
576  primitiveArray[REG_INDEX(RBX)] = state.__rbx;
577  primitiveArray[REG_INDEX(RDX)] = state.__rdx;
578  primitiveArray[REG_INDEX(RCX)] = state.__rcx;
579  primitiveArray[REG_INDEX(RAX)] = state.__rax;
580  primitiveArray[REG_INDEX(TRAPNO)] = 0;            // trapno, not used
581  primitiveArray[REG_INDEX(ERR)]    = 0;            // err, not used 
582  primitiveArray[REG_INDEX(RIP)] = state.__rip;
583  primitiveArray[REG_INDEX(CS)]  = state.__cs;
584  primitiveArray[REG_INDEX(RFL)] = state.__rflags;
585  primitiveArray[REG_INDEX(RSP)] = state.__rsp;
586  primitiveArray[REG_INDEX(SS)] = 0;                // We don't have SS
587  primitiveArray[REG_INDEX(FS)] = state.__fs;
588  primitiveArray[REG_INDEX(GS)] = state.__gs;
589  primitiveArray[REG_INDEX(ES)] = 0;
590  primitiveArray[REG_INDEX(DS)] = 0;
591  primitiveArray[REG_INDEX(FSBASE)] = 0;
592  primitiveArray[REG_INDEX(GSBASE)] = 0;
593  print_debug("set registers\n");
594
595  (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
596
597#else
598#error UNSUPPORTED_ARCH
599#endif /* amd64 */
600
601  return registerArray;
602}
603
604/*
605 * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
606 * Method:    translateTID0
607 * Signature: (I)I
608 */
609JNIEXPORT jint JNICALL
610Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(
611  JNIEnv *env, jobject this_obj, jint tid) 
612{
613  print_debug("translateTID0 called on tid = 0x%x\n", (int)tid);
614
615  kern_return_t result;
616  thread_t foreign_tid, usable_tid;
617  mach_msg_type_name_t type;
618  
619  foreign_tid = tid;
620    
621  task_t gTask = getTask(env, this_obj);
622  result = mach_port_extract_right(gTask, foreign_tid, 
623				   MACH_MSG_TYPE_COPY_SEND, 
624				   &usable_tid, &type);
625  if (result != KERN_SUCCESS)
626    return -1;
627    
628  print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);
629    
630  return (jint) usable_tid;
631}
632
633
634static bool ptrace_continue(pid_t pid, int signal) {
635  // pass the signal to the process so we don't swallow it
636  int res;
637  if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) {
638    print_error("attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res);
639    return false;
640  }
641  return true;
642}
643
644// waits until the ATTACH has stopped the process
645// by signal SIGSTOP
646static bool ptrace_waitpid(pid_t pid) {
647  int ret;
648  int status;
649  while (true) {
650    // Wait for debuggee to stop.
651    ret = waitpid(pid, &status, 0);
652    if (ret >= 0) {
653      if (WIFSTOPPED(status)) {
654        // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP
655        // will still be pending and delivered when the process is DETACHED and the process
656        // will go to sleep.
657        if (WSTOPSIG(status) == SIGSTOP) {
658          // Debuggee stopped by SIGSTOP.
659          return true;
660        }
661        if (!ptrace_continue(pid, WSTOPSIG(status))) {
662          print_error("attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
663          return false;
664        }
665      } else {
666        print_error("attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
667        return false;
668      }
669    } else {
670      switch (errno) {
671        case EINTR:
672          continue;
673          break;
674        case ECHILD:
675          print_error("attach: waitpid() failed. Child process pid (%d) does not exist \n", pid);
676          break;
677        case EINVAL:
678          print_error("attach: waitpid() failed. Invalid options argument.\n");
679          break;
680        default:
681          print_error("attach: waitpid() failed. Unexpected error %d\n",errno);
682          break;
683      }
684      return false;
685    }
686  }
687}
688
689// attach to a process/thread specified by "pid"
690static bool ptrace_attach(pid_t pid) {
691  int res;
692  if ((res = ptrace(PT_ATTACHEXC, pid, 0, 0)) < 0) {
693    print_error("ptrace(PT_ATTACHEXC, %d) failed with %d\n", pid, res);
694    return false;
695  } else {
696    return ptrace_waitpid(pid);
697  }
698}
699
700/*
701 * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
702 * Method:    attach0
703 * Signature: (I)V
704 */
705JNIEXPORT void JNICALL
706Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
707  JNIEnv *env, jobject this_obj, jint jpid)
708{
709  print_debug("attach0 called for jpid=%d\n", (int)jpid);
710
711JNF_COCOA_ENTER(env);
712
713  kern_return_t result;
714  task_t gTask = 0;
715  result = task_for_pid(mach_task_self(), jpid, &gTask);
716  if (result != KERN_SUCCESS) {
717    print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result);
718    THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.");
719  }
720  putTask(env, this_obj, gTask);
721
722  // use ptrace to stop the process
723  // on os x, ptrace only needs to be called on the process, not the individual threads
724  if (ptrace_attach(jpid) != true) {
725    mach_port_deallocate(mach_task_self(), gTask);
726    THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
727  }
728
729  id symbolicator = nil;
730  id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");
731  if (jrsSymbolicator != nil) {
732    id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;
733    symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);
734  }
735  if (symbolicator != nil) {
736    CFRetain(symbolicator); // pin symbolicator while in java heap
737  }
738
739  putSymbolicator(env, this_obj, symbolicator);
740  if (symbolicator == nil) {
741    THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");
742  }
743
744JNF_COCOA_EXIT(env);
745}
746
747/** For core file, 
748    called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */
749static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
750  int n = 0, i = 0;
751
752  // add load objects
753  n = get_num_libs(ph);
754  for (i = 0; i < n; i++) {
755     uintptr_t base;
756     const char* name;
757     jobject loadObject;
758     jobject loadObjectList;
759     jstring nameString;
760
761     base = get_lib_base(ph, i);
762     name = get_lib_name(ph, i);
763     nameString = (*env)->NewStringUTF(env, name);
764     CHECK_EXCEPTION;
765     loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID,
766                                            nameString, (jlong)0, (jlong)base);
767     CHECK_EXCEPTION;
768     loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);
769     CHECK_EXCEPTION;
770     (*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject);
771     CHECK_EXCEPTION;
772  }
773}
774
775/*
776 * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
777 * Method:    attach0
778 * Signature: (Ljava/lang/String;Ljava/lang/String;)V
779 */
780JNIEXPORT void JNICALL
781Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2(
782  JNIEnv *env, jobject this_obj, jstring execName, jstring coreName)
783{
784  const char *execName_cstr;
785  const char *coreName_cstr;
786  jboolean isCopy;
787  struct ps_prochandle* ph;
788
789  execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy);
790  CHECK_EXCEPTION;
791  coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy);
792  CHECK_EXCEPTION;
793
794  print_debug("attach: %s %s\n", execName_cstr, coreName_cstr);
795
796  if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {
797    (*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
798    (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
799    THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");
800  }
801  (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
802  (*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
803  (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
804  fillLoadObjects(env, this_obj, ph);
805}
806
807/*
808 * Class:     sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
809 * Method:    detach0
810 * Signature: ()V
811 */
812JNIEXPORT void JNICALL
813Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
814  JNIEnv *env, jobject this_obj)
815{
816  print_debug("detach0 called\n");
817  struct ps_prochandle* ph = get_proc_handle(env, this_obj);
818  if (ph != NULL && ph->core != NULL) {
819     Prelease(ph);
820     return;
821  }
822JNF_COCOA_ENTER(env);
823  task_t gTask = getTask(env, this_obj);
824
825  // detach from the ptraced process causing it to resume execution
826  int pid;
827  kern_return_t k_res;
828  k_res = pid_for_task(gTask, &pid);
829  if (k_res != KERN_SUCCESS) {
830    print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res);
831  }
832  else {
833    int res = ptrace(PT_DETACH, pid, 0, 0);
834    if (res < 0) {
835      print_error("detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res);
836    }
837  }
838
839  mach_port_deallocate(mach_task_self(), gTask);
840  id symbolicator = getSymbolicator(env, this_obj);
841  if (symbolicator != nil) {
842    CFRelease(symbolicator);
843  }
844JNF_COCOA_EXIT(env);
845}
846