Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/agent/src/os/solaris/proc/saproc.cpp
38840 views
1
/*
2
* Copyright (c) 2002, 2018, 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 "salibproc.h"
26
#include "sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal.h"
27
#ifndef SOLARIS_11_B159_OR_LATER
28
#include <sys/utsname.h>
29
#endif
30
#include <thread_db.h>
31
#include <strings.h>
32
#include <limits.h>
33
#include <demangle.h>
34
#include <stdarg.h>
35
#include <stdlib.h>
36
#include <errno.h>
37
38
#define CHECK_EXCEPTION_(value) if(env->ExceptionOccurred()) { return value; }
39
#define CHECK_EXCEPTION if(env->ExceptionOccurred()) { return;}
40
#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throwNewDebuggerException(env, str); return value; }
41
#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throwNewDebuggerException(env, str); return;}
42
43
#define SYMBOL_BUF_SIZE 256
44
#define ERR_MSG_SIZE (PATH_MAX + 256)
45
46
// debug modes
47
static int _libsaproc_debug = 0;
48
#ifndef SOLARIS_11_B159_OR_LATER
49
static bool _Pstack_iter_debug = false;
50
51
static void dprintf_2(const char* format,...) {
52
if (_Pstack_iter_debug) {
53
va_list alist;
54
55
va_start(alist, format);
56
fputs("Pstack_iter DEBUG: ", stderr);
57
vfprintf(stderr, format, alist);
58
va_end(alist);
59
}
60
}
61
#endif // !SOLARIS_11_B159_OR_LATER
62
63
static void print_debug(const char* format,...) {
64
if (_libsaproc_debug) {
65
va_list alist;
66
67
va_start(alist, format);
68
fputs("libsaproc DEBUG: ", stderr);
69
vfprintf(stderr, format, alist);
70
va_end(alist);
71
}
72
}
73
74
struct Debugger {
75
JNIEnv* env;
76
jobject this_obj;
77
};
78
79
struct DebuggerWithObject : Debugger {
80
jobject obj;
81
};
82
83
struct DebuggerWith2Objects : DebuggerWithObject {
84
jobject obj2;
85
};
86
87
/*
88
* Portions of user thread level detail gathering code is from pstack source
89
* code. See pstack.c in Solaris 2.8 user commands source code.
90
*/
91
92
static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) {
93
env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
94
}
95
96
// JNI ids for some fields, methods
97
98
// libproc handler pointer
99
static jfieldID p_ps_prochandle_ID = 0;
100
101
// libthread.so dlopen handle, thread agent ptr and function pointers
102
static jfieldID libthread_db_handle_ID = 0;
103
static jfieldID p_td_thragent_t_ID = 0;
104
static jfieldID p_td_init_ID = 0;
105
static jfieldID p_td_ta_new_ID = 0;
106
static jfieldID p_td_ta_delete_ID = 0;
107
static jfieldID p_td_ta_thr_iter_ID = 0;
108
static jfieldID p_td_thr_get_info_ID = 0;
109
static jfieldID p_td_ta_map_id2thr_ID = 0;
110
static jfieldID p_td_thr_getgregs_ID = 0;
111
112
// reg index fields
113
static jfieldID pcRegIndex_ID = 0;
114
static jfieldID fpRegIndex_ID = 0;
115
116
// part of the class sharing workaround
117
static jfieldID classes_jsa_fd_ID = 0;
118
static jfieldID p_file_map_header_ID = 0;
119
120
// method ids
121
122
static jmethodID getThreadForThreadId_ID = 0;
123
static jmethodID createSenderFrame_ID = 0;
124
static jmethodID createLoadObject_ID = 0;
125
static jmethodID createClosestSymbol_ID = 0;
126
static jmethodID listAdd_ID = 0;
127
128
/*
129
* Functions we need from libthread_db
130
*/
131
typedef td_err_e
132
(*p_td_init_t)(void);
133
typedef td_err_e
134
(*p_td_ta_new_t)(void *, td_thragent_t **);
135
typedef td_err_e
136
(*p_td_ta_delete_t)(td_thragent_t *);
137
typedef td_err_e
138
(*p_td_ta_thr_iter_t)(const td_thragent_t *, td_thr_iter_f *, void *,
139
td_thr_state_e, int, sigset_t *, unsigned);
140
typedef td_err_e
141
(*p_td_thr_get_info_t)(const td_thrhandle_t *, td_thrinfo_t *);
142
typedef td_err_e
143
(*p_td_ta_map_id2thr_t)(const td_thragent_t *, thread_t, td_thrhandle_t *);
144
typedef td_err_e
145
(*p_td_thr_getgregs_t)(const td_thrhandle_t *, prgregset_t);
146
147
static void
148
clear_libthread_db_ptrs(JNIEnv* env, jobject this_obj) {
149
// release libthread_db agent, if we had created
150
p_td_ta_delete_t p_td_ta_delete = 0;
151
p_td_ta_delete = (p_td_ta_delete_t) env->GetLongField(this_obj, p_td_ta_delete_ID);
152
153
td_thragent_t *p_td_thragent_t = 0;
154
p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
155
if (p_td_thragent_t != 0 && p_td_ta_delete != 0) {
156
p_td_ta_delete(p_td_thragent_t);
157
}
158
159
// dlclose libthread_db.so
160
void* libthread_db_handle = (void*) env->GetLongField(this_obj, libthread_db_handle_ID);
161
if (libthread_db_handle != 0) {
162
dlclose(libthread_db_handle);
163
}
164
165
env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)0);
166
env->SetLongField(this_obj, p_td_init_ID, (jlong)0);
167
env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)0);
168
env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)0);
169
env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)0);
170
env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)0);
171
env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)0);
172
env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)0);
173
}
174
175
176
static void detach_internal(JNIEnv* env, jobject this_obj) {
177
// clear libthread_db stuff
178
clear_libthread_db_ptrs(env, this_obj);
179
180
// release ptr to ps_prochandle
181
jlong p_ps_prochandle;
182
p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
183
if (p_ps_prochandle != 0L) {
184
Prelease((struct ps_prochandle*) p_ps_prochandle, PRELEASE_CLEAR);
185
}
186
187
// part of the class sharing workaround
188
int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);
189
if (classes_jsa_fd != -1) {
190
close(classes_jsa_fd);
191
struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID);
192
if (pheader != NULL) {
193
free(pheader);
194
}
195
}
196
}
197
198
// Is it okay to ignore libthread_db failure? Set env var to ignore
199
// libthread_db failure. You can still debug, but will miss threads
200
// related functionality.
201
static bool sa_ignore_threaddb = (getenv("SA_IGNORE_THREADDB") != 0);
202
203
#define HANDLE_THREADDB_FAILURE(msg) \
204
if (sa_ignore_threaddb) { \
205
printf("libsaproc WARNING: %s\n", msg); \
206
return; \
207
} else { \
208
THROW_NEW_DEBUGGER_EXCEPTION(msg); \
209
}
210
211
#define HANDLE_THREADDB_FAILURE_(msg, ret) \
212
if (sa_ignore_threaddb) { \
213
printf("libsaproc WARNING: %s\n", msg); \
214
return ret; \
215
} else { \
216
THROW_NEW_DEBUGGER_EXCEPTION_(msg, ret); \
217
}
218
219
static const char * alt_root = NULL;
220
static int alt_root_len = -1;
221
222
#define SA_ALTROOT "SA_ALTROOT"
223
224
static void init_alt_root() {
225
if (alt_root_len == -1) {
226
alt_root = getenv(SA_ALTROOT);
227
if (alt_root)
228
alt_root_len = strlen(alt_root);
229
else
230
alt_root_len = 0;
231
}
232
}
233
234
// This function is a complete substitute for the open system call
235
// since it's also used to override open calls from libproc to
236
// implement as a pathmap style facility for the SA. If libproc
237
// starts using other interfaces then this might have to extended to
238
// cover other calls.
239
extern "C" int libsaproc_open(const char * name, int oflag, ...) {
240
if (oflag == O_RDONLY) {
241
init_alt_root();
242
243
if (_libsaproc_debug) {
244
printf("libsaproc DEBUG: libsaproc_open %s\n", name);
245
}
246
247
if (alt_root_len > 0) {
248
int fd = -1;
249
char alt_path[PATH_MAX+1];
250
251
strcpy(alt_path, alt_root);
252
strcat(alt_path, name);
253
fd = open(alt_path, O_RDONLY);
254
if (fd >= 0) {
255
if (_libsaproc_debug) {
256
printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path);
257
}
258
return fd;
259
}
260
261
if (strrchr(name, '/')) {
262
strcpy(alt_path, alt_root);
263
strcat(alt_path, strrchr(name, '/'));
264
fd = open(alt_path, O_RDONLY);
265
if (fd >= 0) {
266
if (_libsaproc_debug) {
267
printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path);
268
}
269
return fd;
270
}
271
}
272
}
273
}
274
275
{
276
mode_t mode;
277
va_list ap;
278
va_start(ap, oflag);
279
mode = va_arg(ap, mode_t);
280
va_end(ap);
281
282
return open(name, oflag, mode);
283
}
284
}
285
286
287
static void * pathmap_dlopen(const char * name, int mode) {
288
init_alt_root();
289
290
if (_libsaproc_debug) {
291
printf("libsaproc DEBUG: pathmap_dlopen %s\n", name);
292
}
293
294
void * handle = NULL;
295
if (alt_root_len > 0) {
296
char alt_path[PATH_MAX+1];
297
strcpy(alt_path, alt_root);
298
strcat(alt_path, name);
299
handle = dlopen(alt_path, mode);
300
if (_libsaproc_debug && handle) {
301
printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);
302
}
303
304
if (handle == NULL && strrchr(name, '/')) {
305
strcpy(alt_path, alt_root);
306
strcat(alt_path, strrchr(name, '/'));
307
handle = dlopen(alt_path, mode);
308
if (_libsaproc_debug && handle) {
309
printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);
310
}
311
}
312
}
313
if (handle == NULL) {
314
handle = dlopen(name, mode);
315
}
316
if (_libsaproc_debug) {
317
printf("libsaproc DEBUG: pathmap_dlopen %s return 0x%lx\n", name, (unsigned long) handle);
318
}
319
return handle;
320
}
321
322
// libproc and libthread_db callback functions
323
324
extern "C" {
325
326
static int
327
init_libthread_db_ptrs(void *cd, const prmap_t *pmp, const char *object_name) {
328
Debugger* dbg = (Debugger*) cd;
329
JNIEnv* env = dbg->env;
330
jobject this_obj = dbg->this_obj;
331
struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
332
333
char *s1 = 0, *s2 = 0;
334
char libthread_db[PATH_MAX];
335
336
if (strstr(object_name, "/libthread.so.") == NULL)
337
return (0);
338
339
/*
340
* We found a libthread.
341
* dlopen() the matching libthread_db and get the thread agent handle.
342
*/
343
if (Pstatus(ph)->pr_dmodel == PR_MODEL_NATIVE) {
344
(void) strcpy(libthread_db, object_name);
345
s1 = (char*) strstr(object_name, ".so.");
346
s2 = (char*) strstr(libthread_db, ".so.");
347
(void) strcpy(s2, "_db");
348
s2 += 3;
349
(void) strcpy(s2, s1);
350
} else {
351
#ifdef _LP64
352
/*
353
* The victim process is 32-bit, we are 64-bit.
354
* We have to find the 64-bit version of libthread_db
355
* that matches the victim's 32-bit version of libthread.
356
*/
357
(void) strcpy(libthread_db, object_name);
358
s1 = (char*) strstr(object_name, "/libthread.so.");
359
s2 = (char*) strstr(libthread_db, "/libthread.so.");
360
(void) strcpy(s2, "/64");
361
s2 += 3;
362
(void) strcpy(s2, s1);
363
s1 = (char*) strstr(s1, ".so.");
364
s2 = (char*) strstr(s2, ".so.");
365
(void) strcpy(s2, "_db");
366
s2 += 3;
367
(void) strcpy(s2, s1);
368
#else
369
return (0);
370
#endif /* _LP64 */
371
}
372
373
void* libthread_db_handle = 0;
374
if ((libthread_db_handle = pathmap_dlopen(libthread_db, RTLD_LAZY|RTLD_LOCAL)) == NULL) {
375
char errMsg[PATH_MAX + 256];
376
sprintf(errMsg, "Can't load %s!", libthread_db);
377
HANDLE_THREADDB_FAILURE_(errMsg, 0);
378
}
379
env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)(uintptr_t)libthread_db_handle);
380
381
void* tmpPtr = 0;
382
tmpPtr = dlsym(libthread_db_handle, "td_init");
383
if (tmpPtr == 0) {
384
HANDLE_THREADDB_FAILURE_("dlsym failed on td_init!", 0);
385
}
386
env->SetLongField(this_obj, p_td_init_ID, (jlong)(uintptr_t) tmpPtr);
387
388
tmpPtr =dlsym(libthread_db_handle, "td_ta_new");
389
if (tmpPtr == 0) {
390
HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_new!", 0);
391
}
392
env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)(uintptr_t) tmpPtr);
393
394
tmpPtr = dlsym(libthread_db_handle, "td_ta_delete");
395
if (tmpPtr == 0) {
396
HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_delete!", 0);
397
}
398
env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)(uintptr_t) tmpPtr);
399
400
tmpPtr = dlsym(libthread_db_handle, "td_ta_thr_iter");
401
if (tmpPtr == 0) {
402
HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_thr_iter!", 0);
403
}
404
env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)(uintptr_t) tmpPtr);
405
406
tmpPtr = dlsym(libthread_db_handle, "td_thr_get_info");
407
if (tmpPtr == 0) {
408
HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_get_info!", 0);
409
}
410
env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)(uintptr_t) tmpPtr);
411
412
tmpPtr = dlsym(libthread_db_handle, "td_ta_map_id2thr");
413
if (tmpPtr == 0) {
414
HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_map_id2thr!", 0);
415
}
416
env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)(uintptr_t) tmpPtr);
417
418
tmpPtr = dlsym(libthread_db_handle, "td_thr_getgregs");
419
if (tmpPtr == 0) {
420
HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_getgregs!", 0);
421
}
422
env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)(uintptr_t) tmpPtr);
423
424
return 1;
425
}
426
427
static int
428
fill_thread_list(const td_thrhandle_t *p_td_thragent_t, void* cd) {
429
DebuggerWithObject* dbgo = (DebuggerWithObject*) cd;
430
JNIEnv* env = dbgo->env;
431
jobject this_obj = dbgo->this_obj;
432
jobject list = dbgo->obj;
433
434
td_thrinfo_t thrinfo;
435
p_td_thr_get_info_t p_td_thr_get_info = (p_td_thr_get_info_t) env->GetLongField(this_obj, p_td_thr_get_info_ID);
436
437
if (p_td_thr_get_info(p_td_thragent_t, &thrinfo) != TD_OK)
438
return (0);
439
440
jobject threadProxy = env->CallObjectMethod(this_obj, getThreadForThreadId_ID, (jlong)(uintptr_t) thrinfo.ti_tid);
441
CHECK_EXCEPTION_(1);
442
env->CallBooleanMethod(list, listAdd_ID, threadProxy);
443
CHECK_EXCEPTION_(1);
444
return 0;
445
}
446
447
static int
448
fill_load_object_list(void *cd, const prmap_t* pmp, const char* obj_name) {
449
450
if (obj_name) {
451
DebuggerWithObject* dbgo = (DebuggerWithObject*) cd;
452
JNIEnv* env = dbgo->env;
453
jobject this_obj = dbgo->this_obj;
454
jobject list = dbgo->obj;
455
456
jstring objectName = env->NewStringUTF(obj_name);
457
CHECK_EXCEPTION_(1);
458
459
jlong mapSize = (jlong) pmp->pr_size;
460
jobject sharedObject = env->CallObjectMethod(this_obj, createLoadObject_ID,
461
objectName, mapSize, (jlong)(uintptr_t)pmp->pr_vaddr);
462
CHECK_EXCEPTION_(1);
463
env->CallBooleanMethod(list, listAdd_ID, sharedObject);
464
CHECK_EXCEPTION_(1);
465
}
466
467
return 0;
468
}
469
470
// Pstack_iter() proc_stack_f callback prior to Nevada-B159
471
static int
472
fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc, const long *argv) {
473
DebuggerWith2Objects* dbgo2 = (DebuggerWith2Objects*) cd;
474
JNIEnv* env = dbgo2->env;
475
jobject this_obj = dbgo2->this_obj;
476
jobject curFrame = dbgo2->obj2;
477
478
jint pcRegIndex = env->GetIntField(this_obj, pcRegIndex_ID);
479
jint fpRegIndex = env->GetIntField(this_obj, fpRegIndex_ID);
480
481
jlong pc = (jlong) (uintptr_t) regs[pcRegIndex];
482
jlong fp = (jlong) (uintptr_t) regs[fpRegIndex];
483
484
dbgo2->obj2 = env->CallObjectMethod(this_obj, createSenderFrame_ID,
485
curFrame, pc, fp);
486
CHECK_EXCEPTION_(1);
487
if (dbgo2->obj == 0) {
488
dbgo2->obj = dbgo2->obj2;
489
}
490
return 0;
491
}
492
493
// Pstack_iter() proc_stack_f callback in Nevada-B159 or later
494
/*ARGSUSED*/
495
static int
496
wrapper_fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc,
497
const long *argv, int frame_flags, int sig) {
498
return(fill_cframe_list(cd, regs, argc, argv));
499
}
500
501
// part of the class sharing workaround
502
503
// FIXME: !!HACK ALERT!!
504
505
// The format of sharing achive file header is needed to read shared heap
506
// file mappings. For now, I am hard coding portion of FileMapHeader here.
507
// Refer to filemap.hpp.
508
509
// FileMapHeader describes the shared space data in the file to be
510
// mapped. This structure gets written to a file. It is not a class, so
511
// that the compilers don't add any compiler-private data to it.
512
513
const int NUM_SHARED_MAPS = 4;
514
515
// Refer to FileMapInfo::_current_version in filemap.hpp
516
const int CURRENT_ARCHIVE_VERSION = 1;
517
518
struct FileMapHeader {
519
int _magic; // identify file type.
520
int _version; // (from enum, above.)
521
size_t _alignment; // how shared archive should be aligned
522
523
524
struct space_info {
525
int _file_offset; // sizeof(this) rounded to vm page size
526
char* _base; // copy-on-write base address
527
size_t _capacity; // for validity checking
528
size_t _used; // for setting space top on read
529
530
bool _read_only; // read only space?
531
bool _allow_exec; // executable code in space?
532
533
} _space[NUM_SHARED_MAPS];
534
535
// Ignore the rest of the FileMapHeader. We don't need those fields here.
536
};
537
538
static bool
539
read_jboolean(struct ps_prochandle* ph, psaddr_t addr, jboolean* pvalue) {
540
jboolean i;
541
if (ps_pread(ph, addr, &i, sizeof(i)) == PS_OK) {
542
*pvalue = i;
543
return true;
544
} else {
545
return false;
546
}
547
}
548
549
static bool
550
read_pointer(struct ps_prochandle* ph, psaddr_t addr, uintptr_t* pvalue) {
551
uintptr_t uip;
552
if (ps_pread(ph, addr, &uip, sizeof(uip)) == PS_OK) {
553
*pvalue = uip;
554
return true;
555
} else {
556
return false;
557
}
558
}
559
560
static bool
561
read_string(struct ps_prochandle* ph, psaddr_t addr, char* buf, size_t size) {
562
char ch = ' ';
563
size_t i = 0;
564
565
while (ch != '\0') {
566
if (ps_pread(ph, addr, &ch, sizeof(ch)) != PS_OK)
567
return false;
568
569
if (i < size - 1) {
570
buf[i] = ch;
571
} else { // smaller buffer
572
return false;
573
}
574
575
i++; addr++;
576
}
577
578
buf[i] = '\0';
579
return true;
580
}
581
582
#define USE_SHARED_SPACES_SYM "UseSharedSpaces"
583
// mangled symbol name for Arguments::SharedArchivePath
584
#define SHARED_ARCHIVE_PATH_SYM "__1cJArgumentsRSharedArchivePath_"
585
586
static int
587
init_classsharing_workaround(void *cd, const prmap_t* pmap, const char* obj_name) {
588
Debugger* dbg = (Debugger*) cd;
589
JNIEnv* env = dbg->env;
590
jobject this_obj = dbg->this_obj;
591
const char* jvm_name = 0;
592
if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL) {
593
jvm_name = obj_name;
594
} else {
595
return 0;
596
}
597
598
struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
599
600
// initialize classes.jsa file descriptor field.
601
dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, -1);
602
603
// check whether class sharing is on by reading variable "UseSharedSpaces"
604
psaddr_t useSharedSpacesAddr = 0;
605
ps_pglobal_lookup(ph, jvm_name, USE_SHARED_SPACES_SYM, &useSharedSpacesAddr);
606
if (useSharedSpacesAddr == 0) {
607
THROW_NEW_DEBUGGER_EXCEPTION_("can't find 'UseSharedSpaces' flag\n", 1);
608
}
609
610
// read the value of the flag "UseSharedSpaces"
611
// Since hotspot types are not available to build this library. So
612
// equivalent type "jboolean" is used to read the value of "UseSharedSpaces"
613
// which is same as hotspot type "bool".
614
jboolean value = 0;
615
if (read_jboolean(ph, useSharedSpacesAddr, &value) != true) {
616
THROW_NEW_DEBUGGER_EXCEPTION_("can't read 'UseSharedSpaces' flag", 1);
617
} else if ((int)value == 0) {
618
print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
619
return 1;
620
}
621
622
char classes_jsa[PATH_MAX];
623
psaddr_t sharedArchivePathAddrAddr = 0;
624
ps_pglobal_lookup(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM, &sharedArchivePathAddrAddr);
625
if (sharedArchivePathAddrAddr == 0) {
626
print_debug("can't find symbol 'Arguments::SharedArchivePath'\n");
627
THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
628
}
629
630
uintptr_t sharedArchivePathAddr = 0;
631
if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
632
print_debug("can't find read pointer 'Arguments::SharedArchivePath'\n");
633
THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
634
}
635
636
if (read_string(ph, (psaddr_t)sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
637
print_debug("can't find read 'Arguments::SharedArchivePath' value\n");
638
THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
639
}
640
641
print_debug("looking for %s\n", classes_jsa);
642
643
// open the classes.jsa
644
int fd = libsaproc_open(classes_jsa, O_RDONLY);
645
if (fd < 0) {
646
char errMsg[ERR_MSG_SIZE];
647
sprintf(errMsg, "can't open shared archive file %s", classes_jsa);
648
THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
649
} else {
650
print_debug("opened shared archive file %s\n", classes_jsa);
651
}
652
653
// parse classes.jsa
654
struct FileMapHeader* pheader = (struct FileMapHeader*) malloc(sizeof(struct FileMapHeader));
655
if (pheader == NULL) {
656
close(fd);
657
THROW_NEW_DEBUGGER_EXCEPTION_("can't allocate memory for shared file map header", 1);
658
}
659
660
memset(pheader, 0, sizeof(struct FileMapHeader));
661
// read FileMapHeader
662
size_t n = read(fd, pheader, sizeof(struct FileMapHeader));
663
if (n != sizeof(struct FileMapHeader)) {
664
char errMsg[ERR_MSG_SIZE];
665
sprintf(errMsg, "unable to read shared archive file map header from %s", classes_jsa);
666
close(fd);
667
free(pheader);
668
THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
669
}
670
671
// check file magic
672
if (pheader->_magic != 0xf00baba2) {
673
char errMsg[ERR_MSG_SIZE];
674
sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0xf00baba2",
675
classes_jsa, pheader->_magic);
676
close(fd);
677
free(pheader);
678
THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
679
}
680
681
// check version
682
if (pheader->_version != CURRENT_ARCHIVE_VERSION) {
683
char errMsg[ERR_MSG_SIZE];
684
sprintf(errMsg, "%s has wrong shared archive version %d, expecting %d",
685
classes_jsa, pheader->_version, CURRENT_ARCHIVE_VERSION);
686
close(fd);
687
free(pheader);
688
THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
689
}
690
691
if (_libsaproc_debug) {
692
for (int m = 0; m < NUM_SHARED_MAPS; m++) {
693
print_debug("shared file offset %d mapped at 0x%lx, size = %ld, read only? = %d\n",
694
pheader->_space[m]._file_offset, pheader->_space[m]._base,
695
pheader->_space[m]._used, pheader->_space[m]._read_only);
696
}
697
}
698
699
// FIXME: For now, omitting other checks such as VM version etc.
700
701
// store class archive file fd and map header in debugger object fields
702
dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, fd);
703
dbg->env->SetLongField(this_obj, p_file_map_header_ID, (jlong)(uintptr_t) pheader);
704
return 1;
705
}
706
707
} // extern "C"
708
709
// error messages for proc_arg_grab failure codes. The messages are
710
// modified versions of comments against corresponding #defines in
711
// libproc.h.
712
static const char* proc_arg_grab_errmsgs[] = {
713
"",
714
/* G_NOPROC */ "No such process",
715
/* G_NOCORE */ "No such core file",
716
/* G_NOPROCORCORE */ "No such process or core",
717
/* G_NOEXEC */ "Cannot locate executable file",
718
/* G_ZOMB */ "Zombie processs",
719
/* G_PERM */ "No permission to attach",
720
/* G_BUSY */ "Another process has already attached",
721
/* G_SYS */ "System process - can not attach",
722
/* G_SELF */ "Process is self - can't debug myself!",
723
/* G_INTR */ "Interrupt received while grabbing",
724
/* G_LP64 */ "debuggee is 64 bit, use java -d64 for debugger",
725
/* G_FORMAT */ "File is not an ELF format core file - corrupted core?",
726
/* G_ELF */ "Libelf error while parsing an ELF file",
727
/* G_NOTE */ "Required PT_NOTE Phdr not present - corrupted core?",
728
};
729
730
static void attach_internal(JNIEnv* env, jobject this_obj, jstring cmdLine, jboolean isProcess) {
731
jboolean isCopy;
732
int gcode;
733
const char* cmdLine_cstr = env->GetStringUTFChars(cmdLine, &isCopy);
734
CHECK_EXCEPTION;
735
736
// some older versions of libproc.so crash when trying to attach 32 bit
737
// debugger to 64 bit core file. check and throw error.
738
#ifndef _LP64
739
atoi(cmdLine_cstr);
740
if (errno) {
741
// core file
742
int core_fd;
743
if ((core_fd = open64(cmdLine_cstr, O_RDONLY)) >= 0) {
744
Elf32_Ehdr e32;
745
if (pread64(core_fd, &e32, sizeof (e32), 0) == sizeof (e32) &&
746
memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0 &&
747
e32.e_type == ET_CORE && e32.e_ident[EI_CLASS] == ELFCLASS64) {
748
close(core_fd);
749
THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use java -d64 for debugger");
750
}
751
close(core_fd);
752
}
753
// all other conditions are handled by libproc.so.
754
}
755
#endif
756
757
// connect to process/core
758
ps_prochandle_t* ph = proc_arg_grab(cmdLine_cstr, (isProcess? PR_ARG_PIDS : PR_ARG_CORES), PGRAB_FORCE, &gcode, NULL);
759
760
env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr);
761
if (! ph) {
762
if (gcode > 0 && gcode < sizeof(proc_arg_grab_errmsgs)/sizeof(const char*)) {
763
char errMsg[ERR_MSG_SIZE];
764
sprintf(errMsg, "Attach failed : %s", proc_arg_grab_errmsgs[gcode]);
765
THROW_NEW_DEBUGGER_EXCEPTION(errMsg);
766
} else {
767
if (_libsaproc_debug && gcode == G_STRANGE) {
768
perror("libsaproc DEBUG: ");
769
}
770
if (isProcess) {
771
THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to process!");
772
} else {
773
THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to core file!");
774
}
775
}
776
}
777
778
// even though libproc.so supports 64 bit debugger and 32 bit debuggee, we don't
779
// support such cross-bit-debugging. check for that combination and throw error.
780
#ifdef _LP64
781
int data_model;
782
if (ps_pdmodel(ph, &data_model) != PS_OK) {
783
Prelease(ph, PRELEASE_CLEAR);
784
THROW_NEW_DEBUGGER_EXCEPTION("can't determine debuggee data model (ILP32? or LP64?)");
785
}
786
if (data_model == PR_MODEL_ILP32) {
787
Prelease(ph, PRELEASE_CLEAR);
788
THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger");
789
}
790
#endif
791
792
env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(uintptr_t)ph);
793
794
Debugger dbg;
795
dbg.env = env;
796
dbg.this_obj = this_obj;
797
jthrowable exception = 0;
798
if (! isProcess) {
799
/*
800
* With class sharing, shared perm. gen heap is allocated in with MAP_SHARED|PROT_READ.
801
* These pages are mapped from the file "classes.jsa". MAP_SHARED pages are not dumped
802
* in Solaris core.To read shared heap pages, we have to read classes.jsa file.
803
*/
804
Pobject_iter(ph, init_classsharing_workaround, &dbg);
805
exception = env->ExceptionOccurred();
806
if (exception) {
807
env->ExceptionClear();
808
detach_internal(env, this_obj);
809
env->Throw(exception);
810
return;
811
}
812
}
813
814
/*
815
* Iterate over the process mappings looking
816
* for libthread and then dlopen the appropriate
817
* libthread_db and get function pointers.
818
*/
819
Pobject_iter(ph, init_libthread_db_ptrs, &dbg);
820
exception = env->ExceptionOccurred();
821
if (exception) {
822
env->ExceptionClear();
823
if (!sa_ignore_threaddb) {
824
detach_internal(env, this_obj);
825
env->Throw(exception);
826
}
827
return;
828
}
829
830
// init libthread_db and create thread_db agent
831
p_td_init_t p_td_init = (p_td_init_t) env->GetLongField(this_obj, p_td_init_ID);
832
if (p_td_init == 0) {
833
if (!sa_ignore_threaddb) {
834
detach_internal(env, this_obj);
835
}
836
HANDLE_THREADDB_FAILURE("Did not find libthread in target process/core!");
837
}
838
839
if (p_td_init() != TD_OK) {
840
if (!sa_ignore_threaddb) {
841
detach_internal(env, this_obj);
842
}
843
HANDLE_THREADDB_FAILURE("Can't initialize thread_db!");
844
}
845
846
p_td_ta_new_t p_td_ta_new = (p_td_ta_new_t) env->GetLongField(this_obj, p_td_ta_new_ID);
847
848
td_thragent_t *p_td_thragent_t = 0;
849
if (p_td_ta_new(ph, &p_td_thragent_t) != TD_OK) {
850
if (!sa_ignore_threaddb) {
851
detach_internal(env, this_obj);
852
}
853
HANDLE_THREADDB_FAILURE("Can't create thread_db agent!");
854
}
855
env->SetLongField(this_obj, p_td_thragent_t_ID, (jlong)(uintptr_t) p_td_thragent_t);
856
857
}
858
859
/*
860
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
861
* Method: attach0
862
* Signature: (Ljava/lang/String;)V
863
* Description: process detach
864
*/
865
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2
866
(JNIEnv *env, jobject this_obj, jstring pid) {
867
attach_internal(env, this_obj, pid, JNI_TRUE);
868
}
869
870
/*
871
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
872
* Method: attach0
873
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
874
* Description: core file detach
875
*/
876
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
877
(JNIEnv *env, jobject this_obj, jstring executable, jstring corefile) {
878
// ignore executable file name, libproc.so can detect a.out name anyway.
879
attach_internal(env, this_obj, corefile, JNI_FALSE);
880
}
881
882
883
/*
884
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
885
* Method: detach0
886
* Signature: ()V
887
* Description: process/core file detach
888
*/
889
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_detach0
890
(JNIEnv *env, jobject this_obj) {
891
detach_internal(env, this_obj);
892
}
893
894
/*
895
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
896
* Method: getRemoteProcessAddressSize0
897
* Signature: ()I
898
* Description: get process/core address size
899
*/
900
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getRemoteProcessAddressSize0
901
(JNIEnv *env, jobject this_obj) {
902
jlong p_ps_prochandle;
903
p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
904
int data_model = PR_MODEL_ILP32;
905
ps_pdmodel((struct ps_prochandle*) p_ps_prochandle, &data_model);
906
print_debug("debuggee is %d bit\n", data_model == PR_MODEL_ILP32? 32 : 64);
907
return (jint) data_model == PR_MODEL_ILP32? 32 : 64;
908
}
909
910
/*
911
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
912
* Method: getPageSize0
913
* Signature: ()I
914
* Description: get process/core page size
915
*/
916
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getPageSize0
917
(JNIEnv *env, jobject this_obj) {
918
919
/*
920
We are not yet attached to a java process or core file. getPageSize is called from
921
the constructor of ProcDebuggerLocal. The following won't work!
922
923
jlong p_ps_prochandle;
924
p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
925
CHECK_EXCEPTION_(-1);
926
struct ps_prochandle* prochandle = (struct ps_prochandle*) p_ps_prochandle;
927
return (Pstate(prochandle) == PS_DEAD) ? Pgetauxval(prochandle, AT_PAGESZ)
928
: getpagesize();
929
930
So even though core may have been generated with a different page size settings, for now
931
call getpagesize.
932
*/
933
934
return getpagesize();
935
}
936
937
/*
938
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
939
* Method: getThreadIntegerRegisterSet0
940
* Signature: (J)[J
941
* Description: get gregset for a given thread specified by thread id
942
*/
943
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getThreadIntegerRegisterSet0
944
(JNIEnv *env, jobject this_obj, jlong tid) {
945
// map the thread id to thread handle
946
p_td_ta_map_id2thr_t p_td_ta_map_id2thr = (p_td_ta_map_id2thr_t) env->GetLongField(this_obj, p_td_ta_map_id2thr_ID);
947
948
td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
949
if (p_td_thragent_t == 0) {
950
return 0;
951
}
952
953
td_thrhandle_t thr_handle;
954
if (p_td_ta_map_id2thr(p_td_thragent_t, (thread_t) tid, &thr_handle) != TD_OK) {
955
THROW_NEW_DEBUGGER_EXCEPTION_("can't map thread id to thread handle!", 0);
956
}
957
958
p_td_thr_getgregs_t p_td_thr_getgregs = (p_td_thr_getgregs_t) env->GetLongField(this_obj, p_td_thr_getgregs_ID);
959
prgregset_t gregs;
960
p_td_thr_getgregs(&thr_handle, gregs);
961
962
jlongArray res = env->NewLongArray(NPRGREG);
963
CHECK_EXCEPTION_(0);
964
jboolean isCopy;
965
jlong* ptr = env->GetLongArrayElements(res, &isCopy);
966
for (int i = 0; i < NPRGREG; i++) {
967
ptr[i] = (jlong) (uintptr_t) gregs[i];
968
}
969
env->ReleaseLongArrayElements(res, ptr, JNI_COMMIT);
970
return res;
971
}
972
973
/*
974
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
975
* Method: fillThreadList0
976
* Signature: (Ljava/util/List;)V
977
* Description: fills thread list of the debuggee process/core
978
*/
979
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillThreadList0
980
(JNIEnv *env, jobject this_obj, jobject list) {
981
982
td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
983
if (p_td_thragent_t == 0) {
984
return;
985
}
986
987
p_td_ta_thr_iter_t p_td_ta_thr_iter = (p_td_ta_thr_iter_t) env->GetLongField(this_obj, p_td_ta_thr_iter_ID);
988
989
DebuggerWithObject dbgo;
990
dbgo.env = env;
991
dbgo.this_obj = this_obj;
992
dbgo.obj = list;
993
994
p_td_ta_thr_iter(p_td_thragent_t, fill_thread_list, &dbgo,
995
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
996
}
997
998
#ifndef SOLARIS_11_B159_OR_LATER
999
// building on Nevada-B158 or earlier so more hoops to jump through
1000
static bool has_newer_Pstack_iter = false; // older version by default
1001
#endif
1002
1003
/*
1004
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1005
* Method: fillCFrameList0
1006
* Signature: ([J)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;
1007
* Description: fills CFrame list for a given thread
1008
*/
1009
JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillCFrameList0
1010
(JNIEnv *env, jobject this_obj, jlongArray regsArray) {
1011
jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
1012
1013
DebuggerWith2Objects dbgo2;
1014
dbgo2.env = env;
1015
dbgo2.this_obj = this_obj;
1016
dbgo2.obj = NULL;
1017
dbgo2.obj2 = NULL;
1018
1019
jboolean isCopy;
1020
jlong* ptr = env->GetLongArrayElements(regsArray, &isCopy);
1021
CHECK_EXCEPTION_(0);
1022
1023
prgregset_t gregs;
1024
for (int i = 0; i < NPRGREG; i++) {
1025
gregs[i] = (uintptr_t) ptr[i];
1026
}
1027
1028
env->ReleaseLongArrayElements(regsArray, ptr, JNI_ABORT);
1029
CHECK_EXCEPTION_(0);
1030
1031
#ifdef SOLARIS_11_B159_OR_LATER
1032
// building on Nevada-B159 or later so use the new callback
1033
Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,
1034
wrapper_fill_cframe_list, &dbgo2);
1035
#else
1036
// building on Nevada-B158 or earlier so figure out which callback to use
1037
1038
if (has_newer_Pstack_iter) {
1039
// Since we're building on Nevada-B158 or earlier, we have to
1040
// cast wrapper_fill_cframe_list to make the compiler happy.
1041
Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,
1042
(proc_stack_f *)wrapper_fill_cframe_list, &dbgo2);
1043
} else {
1044
Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,
1045
fill_cframe_list, &dbgo2);
1046
}
1047
#endif // SOLARIS_11_B159_OR_LATER
1048
return dbgo2.obj;
1049
}
1050
1051
/*
1052
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1053
* Method: fillLoadObjectList0
1054
* Signature: (Ljava/util/List;)V
1055
* Description: fills shared objects of the debuggee process/core
1056
*/
1057
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillLoadObjectList0
1058
(JNIEnv *env, jobject this_obj, jobject list) {
1059
DebuggerWithObject dbgo;
1060
dbgo.env = env;
1061
dbgo.this_obj = this_obj;
1062
dbgo.obj = list;
1063
1064
jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
1065
Pobject_iter((struct ps_prochandle*) p_ps_prochandle, fill_load_object_list, &dbgo);
1066
}
1067
1068
/*
1069
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1070
* Method: readBytesFromProcess0
1071
* Signature: (JJ)[B
1072
* Description: read bytes from debuggee process/core
1073
*/
1074
JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_readBytesFromProcess0
1075
(JNIEnv *env, jobject this_obj, jlong address, jlong numBytes) {
1076
1077
jbyteArray array = env->NewByteArray(numBytes);
1078
CHECK_EXCEPTION_(0);
1079
jboolean isCopy;
1080
jbyte* bufPtr = env->GetByteArrayElements(array, &isCopy);
1081
CHECK_EXCEPTION_(0);
1082
1083
jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
1084
ps_err_e ret = ps_pread((struct ps_prochandle*) p_ps_prochandle,
1085
(psaddr_t)address, bufPtr, (size_t)numBytes);
1086
1087
if (ret != PS_OK) {
1088
// part of the class sharing workaround. try shared heap area
1089
int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);
1090
if (classes_jsa_fd != -1 && address != (jlong)0) {
1091
print_debug("read failed at 0x%lx, attempting shared heap area\n", (long) address);
1092
1093
struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID);
1094
// walk through the shared mappings -- we just have 4 of them.
1095
// so, linear walking is okay.
1096
for (int m = 0; m < NUM_SHARED_MAPS; m++) {
1097
1098
// We can skip the non-read-only maps. These are mapped as MAP_PRIVATE
1099
// and hence will be read by libproc. Besides, the file copy may be
1100
// stale because the process might have modified those pages.
1101
if (pheader->_space[m]._read_only) {
1102
jlong baseAddress = (jlong) (uintptr_t) pheader->_space[m]._base;
1103
size_t usedSize = pheader->_space[m]._used;
1104
if (address >= baseAddress && address < (baseAddress + usedSize)) {
1105
// the given address falls in this shared heap area
1106
print_debug("found shared map at 0x%lx\n", (long) baseAddress);
1107
1108
1109
// If more data is asked than actually mapped from file, we need to zero fill
1110
// till the end-of-page boundary. But, java array new does that for us. we just
1111
// need to read as much as data available.
1112
1113
#define MIN2(x, y) (((x) < (y))? (x) : (y))
1114
1115
jlong diff = address - baseAddress;
1116
jlong bytesToRead = MIN2(numBytes, usedSize - diff);
1117
off_t offset = pheader->_space[m]._file_offset + off_t(diff);
1118
ssize_t bytesRead = pread(classes_jsa_fd, bufPtr, bytesToRead, offset);
1119
if (bytesRead != bytesToRead) {
1120
env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);
1121
print_debug("shared map read failed\n");
1122
return jbyteArray(0);
1123
} else {
1124
print_debug("shared map read succeeded\n");
1125
env->ReleaseByteArrayElements(array, bufPtr, 0);
1126
return array;
1127
}
1128
} // is in current map
1129
} // is read only map
1130
} // for shared maps
1131
} // classes_jsa_fd != -1
1132
env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);
1133
return jbyteArray(0);
1134
} else {
1135
env->ReleaseByteArrayElements(array, bufPtr, 0);
1136
return array;
1137
}
1138
}
1139
1140
/*
1141
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1142
* Method: writeBytesToProcess0
1143
* Signature: (JJ[B)V
1144
* Description: write bytes into debugger process
1145
*/
1146
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_writeBytesToProcess0
1147
(JNIEnv *env, jobject this_obj, jlong address, jlong numBytes, jbyteArray data) {
1148
jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
1149
jboolean isCopy;
1150
jbyte* ptr = env->GetByteArrayElements(data, &isCopy);
1151
CHECK_EXCEPTION;
1152
1153
if (ps_pwrite((struct ps_prochandle*) p_ps_prochandle, address, ptr, numBytes) != PS_OK) {
1154
env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
1155
THROW_NEW_DEBUGGER_EXCEPTION("Process write failed!");
1156
}
1157
1158
env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
1159
}
1160
1161
/*
1162
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1163
* Method: suspend0
1164
* Signature: ()V
1165
*/
1166
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_suspend0
1167
(JNIEnv *env, jobject this_obj) {
1168
jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
1169
// for now don't check return value. revisit this again.
1170
Pstop((struct ps_prochandle*) p_ps_prochandle, 1000);
1171
}
1172
1173
/*
1174
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1175
* Method: resume0
1176
* Signature: ()V
1177
*/
1178
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_resume0
1179
(JNIEnv *env, jobject this_obj) {
1180
jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
1181
// for now don't check return value. revisit this again.
1182
Psetrun((struct ps_prochandle*) p_ps_prochandle, 0, PRCFAULT|PRSTOP);
1183
}
1184
1185
/*
1186
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1187
* Method: lookupByName0
1188
* Signature: (Ljava/lang/String;Ljava/lang/String;)J
1189
* Description: symbol lookup by name
1190
*/
1191
JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByName0
1192
(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
1193
jlong p_ps_prochandle;
1194
p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
1195
1196
jboolean isCopy;
1197
const char* objectName_cstr = NULL;
1198
if (objectName != NULL) {
1199
objectName_cstr = env->GetStringUTFChars(objectName, &isCopy);
1200
CHECK_EXCEPTION_(0);
1201
} else {
1202
objectName_cstr = PR_OBJ_EVERY;
1203
}
1204
1205
const char* symbolName_cstr = env->GetStringUTFChars(symbolName, &isCopy);
1206
CHECK_EXCEPTION_(0);
1207
1208
psaddr_t symbol_addr = (psaddr_t) 0;
1209
ps_pglobal_lookup((struct ps_prochandle*) p_ps_prochandle, objectName_cstr,
1210
symbolName_cstr, &symbol_addr);
1211
1212
if (symbol_addr == 0) {
1213
print_debug("lookup for %s in %s failed\n", symbolName_cstr, objectName_cstr);
1214
}
1215
1216
if (objectName_cstr != PR_OBJ_EVERY) {
1217
env->ReleaseStringUTFChars(objectName, objectName_cstr);
1218
}
1219
env->ReleaseStringUTFChars(symbolName, symbolName_cstr);
1220
return (jlong) (uintptr_t) symbol_addr;
1221
}
1222
1223
/*
1224
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1225
* Method: lookupByAddress0
1226
* Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
1227
* Description: lookup symbol name for a given address
1228
*/
1229
JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByAddress0
1230
(JNIEnv *env, jobject this_obj, jlong address) {
1231
jlong p_ps_prochandle;
1232
p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
1233
1234
char nameBuf[SYMBOL_BUF_SIZE + 1];
1235
GElf_Sym sym;
1236
int res = Plookup_by_addr((struct ps_prochandle*) p_ps_prochandle, (uintptr_t) address,
1237
nameBuf, sizeof(nameBuf), &sym, NULL);
1238
1239
if (res != 0) { // failed
1240
return 0;
1241
}
1242
1243
jstring resSym = env->NewStringUTF(nameBuf);
1244
CHECK_EXCEPTION_(0);
1245
1246
return env->CallObjectMethod(this_obj, createClosestSymbol_ID, resSym, (address - sym.st_value));
1247
}
1248
1249
/*
1250
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1251
* Method: demangle0
1252
* Signature: (Ljava/lang/String;)Ljava/lang/String;
1253
*/
1254
JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_demangle0
1255
(JNIEnv *env, jobject this_object, jstring name) {
1256
jboolean isCopy;
1257
const char* ptr = env->GetStringUTFChars(name, &isCopy);
1258
char buf[2*SYMBOL_BUF_SIZE + 1];
1259
jstring res = 0;
1260
if (cplus_demangle((char*) ptr, buf, sizeof(buf)) != DEMANGLE_ESPACE) {
1261
res = env->NewStringUTF(buf);
1262
} else {
1263
res = name;
1264
}
1265
env->ReleaseStringUTFChars(name, ptr);
1266
return res;
1267
}
1268
1269
#ifndef SOLARIS_11_B159_OR_LATER
1270
// Determine if the OS we're running on has the newer version
1271
// of libproc's Pstack_iter.
1272
//
1273
// Set env var PSTACK_ITER_DEBUG=true to debug this logic.
1274
// Set env var PSTACK_ITER_DEBUG_RELEASE to simulate a 'release' value.
1275
// Set env var PSTACK_ITER_DEBUG_VERSION to simulate a 'version' value.
1276
//
1277
// frankenputer 'uname -r -v': 5.10 Generic_141445-09
1278
// jurassic 'uname -r -v': 5.11 snv_164
1279
// lonepeak 'uname -r -v': 5.11 snv_127
1280
//
1281
static void set_has_newer_Pstack_iter(JNIEnv *env) {
1282
static bool done_set = false;
1283
1284
if (done_set) {
1285
// already set has_newer_Pstack_iter
1286
return;
1287
}
1288
1289
struct utsname name;
1290
if (uname(&name) == -1) {
1291
THROW_NEW_DEBUGGER_EXCEPTION("uname() failed!");
1292
}
1293
dprintf_2("release='%s' version='%s'\n", name.release, name.version);
1294
1295
if (_Pstack_iter_debug) {
1296
char *override = getenv("PSTACK_ITER_DEBUG_RELEASE");
1297
if (override != NULL) {
1298
strncpy(name.release, override, SYS_NMLN - 1);
1299
name.release[SYS_NMLN - 2] = '\0';
1300
dprintf_2("overriding with release='%s'\n", name.release);
1301
}
1302
override = getenv("PSTACK_ITER_DEBUG_VERSION");
1303
if (override != NULL) {
1304
strncpy(name.version, override, SYS_NMLN - 1);
1305
name.version[SYS_NMLN - 2] = '\0';
1306
dprintf_2("overriding with version='%s'\n", name.version);
1307
}
1308
}
1309
1310
// the major number corresponds to the old SunOS major number
1311
int major = atoi(name.release);
1312
if (major >= 6) {
1313
dprintf_2("release is SunOS 6 or later\n");
1314
has_newer_Pstack_iter = true;
1315
done_set = true;
1316
return;
1317
}
1318
if (major < 5) {
1319
dprintf_2("release is SunOS 4 or earlier\n");
1320
done_set = true;
1321
return;
1322
}
1323
1324
// some SunOS 5.* build so now check for Solaris versions
1325
char *dot = strchr(name.release, '.');
1326
int minor = 0;
1327
if (dot != NULL) {
1328
// release is major.minor format
1329
*dot = NULL;
1330
minor = atoi(dot + 1);
1331
}
1332
1333
if (minor <= 10) {
1334
dprintf_2("release is Solaris 10 or earlier\n");
1335
done_set = true;
1336
return;
1337
} else if (minor >= 12) {
1338
dprintf_2("release is Solaris 12 or later\n");
1339
has_newer_Pstack_iter = true;
1340
done_set = true;
1341
return;
1342
}
1343
1344
// some Solaris 11 build so now check for internal build numbers
1345
if (strncmp(name.version, "snv_", 4) != 0) {
1346
dprintf_2("release is Solaris 11 post-GA or later\n");
1347
has_newer_Pstack_iter = true;
1348
done_set = true;
1349
return;
1350
}
1351
1352
// version begins with "snv_" so a pre-GA build of Solaris 11
1353
int build = atoi(&name.version[4]);
1354
if (build >= 159) {
1355
dprintf_2("release is Nevada-B159 or later\n");
1356
has_newer_Pstack_iter = true;
1357
} else {
1358
dprintf_2("release is Nevada-B158 or earlier\n");
1359
}
1360
1361
done_set = true;
1362
}
1363
#endif // !SOLARIS_11_B159_OR_LATER
1364
1365
/*
1366
* Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
1367
* Method: initIDs
1368
* Signature: ()V
1369
* Description: get JNI ids for fields and methods of ProcDebuggerLocal class
1370
*/
1371
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_initIDs
1372
(JNIEnv *env, jclass clazz) {
1373
_libsaproc_debug = getenv("LIBSAPROC_DEBUG") != NULL;
1374
if (_libsaproc_debug) {
1375
// propagate debug mode to libproc.so
1376
static const char* var = "LIBPROC_DEBUG=1";
1377
putenv((char*)var);
1378
}
1379
1380
void* libproc_handle = dlopen("libproc.so", RTLD_LAZY | RTLD_GLOBAL);
1381
if (libproc_handle == 0)
1382
THROW_NEW_DEBUGGER_EXCEPTION("can't load libproc.so, if you are using Solaris 5.7 or below, copy libproc.so from 5.8!");
1383
1384
#ifndef SOLARIS_11_B159_OR_LATER
1385
_Pstack_iter_debug = getenv("PSTACK_ITER_DEBUG") != NULL;
1386
1387
set_has_newer_Pstack_iter(env);
1388
CHECK_EXCEPTION;
1389
dprintf_2("has_newer_Pstack_iter=%d\n", has_newer_Pstack_iter);
1390
#endif
1391
1392
p_ps_prochandle_ID = env->GetFieldID(clazz, "p_ps_prochandle", "J");
1393
CHECK_EXCEPTION;
1394
1395
libthread_db_handle_ID = env->GetFieldID(clazz, "libthread_db_handle", "J");
1396
CHECK_EXCEPTION;
1397
1398
p_td_thragent_t_ID = env->GetFieldID(clazz, "p_td_thragent_t", "J");
1399
CHECK_EXCEPTION;
1400
1401
p_td_init_ID = env->GetFieldID(clazz, "p_td_init", "J");
1402
CHECK_EXCEPTION;
1403
1404
p_td_ta_new_ID = env->GetFieldID(clazz, "p_td_ta_new", "J");
1405
CHECK_EXCEPTION;
1406
1407
p_td_ta_delete_ID = env->GetFieldID(clazz, "p_td_ta_delete", "J");
1408
CHECK_EXCEPTION;
1409
1410
p_td_ta_thr_iter_ID = env->GetFieldID(clazz, "p_td_ta_thr_iter", "J");
1411
CHECK_EXCEPTION;
1412
1413
p_td_thr_get_info_ID = env->GetFieldID(clazz, "p_td_thr_get_info", "J");
1414
CHECK_EXCEPTION;
1415
1416
p_td_ta_map_id2thr_ID = env->GetFieldID(clazz, "p_td_ta_map_id2thr", "J");
1417
CHECK_EXCEPTION;
1418
1419
p_td_thr_getgregs_ID = env->GetFieldID(clazz, "p_td_thr_getgregs", "J");
1420
CHECK_EXCEPTION;
1421
1422
getThreadForThreadId_ID = env->GetMethodID(clazz,
1423
"getThreadForThreadId", "(J)Lsun/jvm/hotspot/debugger/ThreadProxy;");
1424
CHECK_EXCEPTION;
1425
1426
pcRegIndex_ID = env->GetFieldID(clazz, "pcRegIndex", "I");
1427
CHECK_EXCEPTION;
1428
1429
fpRegIndex_ID = env->GetFieldID(clazz, "fpRegIndex", "I");
1430
CHECK_EXCEPTION;
1431
1432
createSenderFrame_ID = env->GetMethodID(clazz,
1433
"createSenderFrame", "(Lsun/jvm/hotspot/debugger/proc/ProcCFrame;JJ)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;");
1434
CHECK_EXCEPTION;
1435
1436
createLoadObject_ID = env->GetMethodID(clazz,
1437
"createLoadObject", "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");
1438
CHECK_EXCEPTION;
1439
1440
createClosestSymbol_ID = env->GetMethodID(clazz,
1441
"createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
1442
CHECK_EXCEPTION;
1443
1444
listAdd_ID = env->GetMethodID(env->FindClass("java/util/List"), "add", "(Ljava/lang/Object;)Z");
1445
CHECK_EXCEPTION;
1446
1447
// part of the class sharing workaround
1448
classes_jsa_fd_ID = env->GetFieldID(clazz, "classes_jsa_fd", "I");
1449
CHECK_EXCEPTION;
1450
p_file_map_header_ID = env->GetFieldID(clazz, "p_file_map_header", "J");
1451
CHECK_EXCEPTION;
1452
}
1453
1454