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