1 /*
2 * Copyright (c) 2003, 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 #include <stdlib.h>
25 #include <string.h>
26
27 #include "native_thread.h"
28 #include "jni_tools.h"
29 #include "jvmti_tools.h"
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 /* ============================================================================= */
36
37 /* Be careful: do not build shared library which will be linked with different
38 * agent libs while global variables are used
39 * Now the same source is used to build different agent libs, so these
40 * variables are not shared between agents */
41
42 static jthread agentThread = NULL;
43 static jvmtiStartFunction agentThreadProc = NULL;
44 static void* agentThreadArg = NULL;
45
46
47 typedef enum {NEW, RUNNABLE, WAITING, SUSPENDED, TERMINATED} thread_state_t;
48
49 typedef struct agent_data_t {
50 volatile thread_state_t thread_state;
51 int last_debuggee_status;
52 jrawMonitorID monitor;
53 } agent_data_t;
54
55 static agent_data_t agent_data;
56
57 static jvmtiEnv* jvmti_env = NULL;
58 static JavaVM* jvm = NULL;
59 static JNIEnv* jni_env = NULL;
60
61 static volatile int currentAgentStatus = NSK_STATUS_PASSED;
62
63 /* ============================================================================= */
64
nsk_jvmti_setFailStatus()65 void nsk_jvmti_setFailStatus() {
66 currentAgentStatus = NSK_STATUS_FAILED;
67 }
68
nsk_jvmti_isFailStatus()69 int nsk_jvmti_isFailStatus() {
70 return (nsk_jvmti_getStatus() != NSK_STATUS_PASSED);
71 }
72
nsk_jvmti_getStatus()73 jint nsk_jvmti_getStatus() {
74 return currentAgentStatus;
75 }
76
77 /* ============================================================================= */
init_agent_data(jvmtiEnv * jvmti_env,agent_data_t * data)78 static jvmtiError init_agent_data(jvmtiEnv *jvmti_env, agent_data_t *data) {
79 data->thread_state = NEW;
80 data->last_debuggee_status = NSK_STATUS_PASSED;
81
82 return NSK_CPP_STUB3(CreateRawMonitor, jvmti_env, "agent_data_monitor", &data->monitor);
83 }
84
85 /** Reset agent data to prepare for another run. */
nsk_jvmti_resetAgentData()86 void nsk_jvmti_resetAgentData() {
87 rawMonitorEnter(jvmti_env, agent_data.monitor);
88 /* wait for agentThreadWrapper() to finish */
89 while (agent_data.thread_state != TERMINATED) {
90 rawMonitorWait(jvmti_env, agent_data.monitor, 10);
91 }
92 agent_data.thread_state = NEW;
93 agent_data.last_debuggee_status = NSK_STATUS_PASSED;
94 rawMonitorExit(jvmti_env, agent_data.monitor);
95 }
96
free_agent_data(jvmtiEnv * jvmti_env,agent_data_t * data)97 static jvmtiError free_agent_data(jvmtiEnv *jvmti_env, agent_data_t *data) {
98 return NSK_CPP_STUB2(DestroyRawMonitor, jvmti_env, data->monitor);
99 }
100
101 /** Create JVMTI environment. */
nsk_jvmti_createJVMTIEnv(JavaVM * javaVM,void * reserved)102 jvmtiEnv* nsk_jvmti_createJVMTIEnv(JavaVM* javaVM, void* reserved) {
103 jvm = javaVM;
104 if (!NSK_VERIFY(
105 NSK_CPP_STUB3(GetEnv, javaVM, (void **)&jvmti_env, JVMTI_VERSION_1_1) == JNI_OK)) {
106 nsk_jvmti_setFailStatus();
107 return NULL;
108 }
109
110 if (!NSK_JVMTI_VERIFY(init_agent_data(jvmti_env, &agent_data))) {
111 nsk_jvmti_setFailStatus();
112 return NULL;
113 }
114
115 return jvmti_env;
116 }
117
118 /** Dispose JVMTI environment */
nsk_jvmti_disposeJVMTIEnv(jvmtiEnv * jvmti_env)119 static int nsk_jvmti_disposeJVMTIEnv(jvmtiEnv* jvmti_env) {
120 if (jvmti_env != NULL) {
121 if (!NSK_JVMTI_VERIFY(
122 NSK_CPP_STUB1(DisposeEnvironment, jvmti_env))) {
123 nsk_jvmti_setFailStatus();
124 return NSK_FALSE;
125 }
126
127 if (!NSK_JVMTI_VERIFY(free_agent_data(jvmti_env, &agent_data))) {
128 nsk_jvmti_setFailStatus();
129 return NSK_FALSE;
130 }
131 }
132 return NSK_TRUE;
133 }
134
135 /** Get JNI environment for agent thread. */
nsk_jvmti_getAgentJNIEnv()136 JNIEnv* nsk_jvmti_getAgentJNIEnv() {
137 return jni_env;
138 }
139
140 /** Get JVMTI environment for agent */
nsk_jvmti_getAgentJVMTIEnv()141 jvmtiEnv* nsk_jvmti_getAgentJVMTIEnv() {
142 return jvmti_env;
143 }
144
145 /* ============================================================================= */
set_agent_thread_state(thread_state_t value)146 static void set_agent_thread_state(thread_state_t value) {
147 rawMonitorEnter(jvmti_env, agent_data.monitor);
148 agent_data.thread_state = value;
149 rawMonitorNotify(jvmti_env, agent_data.monitor);
150 rawMonitorExit(jvmti_env, agent_data.monitor);
151 }
152
153 /** Wrapper for user agent thread. */
154 static void JNICALL
agentThreadWrapper(jvmtiEnv * jvmti_env,JNIEnv * agentJNI,void * arg)155 agentThreadWrapper(jvmtiEnv* jvmti_env, JNIEnv* agentJNI, void* arg) {
156 jni_env = agentJNI;
157
158 /* run user agent proc */
159 {
160 set_agent_thread_state(RUNNABLE);
161
162 NSK_TRACE((*agentThreadProc)(jvmti_env, agentJNI, agentThreadArg));
163
164 set_agent_thread_state(TERMINATED);
165 }
166
167 /* finalize agent thread */
168 {
169 /* gelete global ref for agent thread */
170 NSK_CPP_STUB2(DeleteGlobalRef, agentJNI, agentThread);
171 agentThread = NULL;
172 }
173 }
174
175 /** Start wrapper for user agent thread. */
startAgentThreadWrapper(JNIEnv * jni_env,jvmtiEnv * jvmti_env)176 static jthread startAgentThreadWrapper(JNIEnv *jni_env, jvmtiEnv* jvmti_env) {
177 const jint THREAD_PRIORITY = JVMTI_THREAD_MAX_PRIORITY;
178 const char* THREAD_NAME = "JVMTI agent thread";
179 const char* THREAD_CLASS_NAME = "java/lang/Thread";
180 const char* THREAD_CTOR_NAME = "<init>";
181 const char* THREAD_CTOR_SIGNATURE = "(Ljava/lang/String;)V";
182
183 jobject threadName = NULL;
184 jclass threadClass = NULL;
185 jmethodID threadCtor = NULL;
186 jobject threadObject = NULL;
187 jobject threadGlobalRef = NULL;
188
189 if (!NSK_JNI_VERIFY(jni_env, (threadClass =
190 NSK_CPP_STUB2(FindClass, jni_env, THREAD_CLASS_NAME)) != NULL)) {
191 return NULL;
192 }
193
194 if (!NSK_JNI_VERIFY(jni_env, (threadCtor =
195 NSK_CPP_STUB4(GetMethodID, jni_env, threadClass, THREAD_CTOR_NAME, THREAD_CTOR_SIGNATURE)) != NULL))
196 return NULL;
197
198 if (!NSK_JNI_VERIFY(jni_env, (threadName =
199 NSK_CPP_STUB2(NewStringUTF, jni_env, THREAD_NAME)) != NULL))
200 return NULL;
201
202 if (!NSK_JNI_VERIFY(jni_env, (threadObject =
203 NSK_CPP_STUB4(NewObject, jni_env, threadClass, threadCtor, threadName)) != NULL))
204 return NULL;
205
206 if (!NSK_JNI_VERIFY(jni_env, (threadGlobalRef =
207 NSK_CPP_STUB2(NewGlobalRef, jni_env, threadObject)) != NULL)) {
208 NSK_CPP_STUB2(DeleteLocalRef, jni_env, threadObject);
209 return NULL;
210 }
211 agentThread = (jthread)threadGlobalRef;
212
213 if (!NSK_JVMTI_VERIFY(
214 NSK_CPP_STUB5(RunAgentThread, jvmti_env, agentThread,
215 &agentThreadWrapper, agentThreadArg, THREAD_PRIORITY))) {
216 NSK_CPP_STUB2(DeleteGlobalRef, jni_env, threadGlobalRef);
217 NSK_CPP_STUB2(DeleteLocalRef, jni_env, threadObject);
218 return NULL;
219 }
220 return agentThread;
221 }
222
223 /** Register user agent thread with arg. */
nsk_jvmti_setAgentProc(jvmtiStartFunction proc,void * arg)224 int nsk_jvmti_setAgentProc(jvmtiStartFunction proc, void* arg) {
225 agentThreadProc = proc;
226 agentThreadArg = arg;
227 return NSK_TRUE;
228 }
229
230 /** Get agent thread ref. */
nsk_jvmti_getAgentThread()231 jthread nsk_jvmti_getAgentThread() {
232 return agentThread;
233 }
234
235 /** Run registered user agent thread via wrapper. */
nsk_jvmti_runAgentThread(JNIEnv * jni_env,jvmtiEnv * jvmti_env)236 static jthread nsk_jvmti_runAgentThread(JNIEnv *jni_env, jvmtiEnv* jvmti_env) {
237 /* start agent thread wrapper */
238 jthread thread = startAgentThreadWrapper(jni_env, jvmti_env);
239 if (thread == NULL) {
240 nsk_jvmti_setFailStatus();
241 return NULL;
242 }
243
244 return thread;
245 }
246
247 /* ============================================================================= */
248
249 /** Sleep current thread. */
nsk_jvmti_sleep(jlong timeout)250 void nsk_jvmti_sleep(jlong timeout) {
251 int seconds = (int)((timeout + 999) / 1000);
252 THREAD_sleep(seconds);
253 }
254
255 /** Sync point called from Java code. */
syncDebuggeeStatus(JNIEnv * jni_env,jvmtiEnv * jvmti_env,jint debuggeeStatus)256 static jint syncDebuggeeStatus(JNIEnv* jni_env, jvmtiEnv* jvmti_env, jint debuggeeStatus) {
257 jint result = NSK_STATUS_FAILED;
258
259 rawMonitorEnter(jvmti_env, agent_data.monitor);
260
261 /* save last debugee status */
262 agent_data.last_debuggee_status = debuggeeStatus;
263
264 /* we don't enter if-stmt in second call */
265 if (agent_data.thread_state == NEW) {
266 if (nsk_jvmti_runAgentThread(jni_env, jvmti_env) == NULL)
267 goto monitor_exit_and_return;
268
269 /* SP2.2-w - wait for agent thread */
270 while (agent_data.thread_state == NEW) {
271 rawMonitorWait(jvmti_env, agent_data.monitor, 0);
272 }
273 }
274
275 /* wait for sync permit */
276 /* we don't enter loop in first call */
277 while (agent_data.thread_state != WAITING && agent_data.thread_state != TERMINATED) {
278 /* SP4.2-w - second wait for agent thread */
279 rawMonitorWait(jvmti_env, agent_data.monitor, 0);
280 }
281
282 if (agent_data.thread_state != TERMINATED) {
283 agent_data.thread_state = SUSPENDED;
284 /* SP3.2-n - notify to start test */
285 /* SP6.2-n - notify to end test */
286 rawMonitorNotify(jvmti_env, agent_data.monitor);
287 }
288 else {
289 NSK_COMPLAIN0("Debuggee status sync aborted because agent thread has finished\n");
290 goto monitor_exit_and_return;
291 }
292
293 /* update status from debuggee */
294 if (debuggeeStatus != NSK_STATUS_PASSED) {
295 nsk_jvmti_setFailStatus();
296 }
297
298 while (agent_data.thread_state == SUSPENDED) {
299 /* SP5.2-w - wait while testing */
300 /* SP7.2 - wait for agent end */
301 rawMonitorWait(jvmti_env, agent_data.monitor, 0);
302 }
303
304 agent_data.last_debuggee_status = nsk_jvmti_getStatus();
305 result = agent_data.last_debuggee_status;
306
307 monitor_exit_and_return:
308 rawMonitorExit(jvmti_env, agent_data.monitor);
309 return result;
310 }
311
312 /** Wait for sync point with Java code. */
nsk_jvmti_waitForSync(jlong timeout)313 int nsk_jvmti_waitForSync(jlong timeout) {
314 static const int inc_timeout = 1000;
315
316 jlong t = 0;
317 int result = NSK_TRUE;
318
319 rawMonitorEnter(jvmti_env, agent_data.monitor);
320
321 agent_data.thread_state = WAITING;
322
323 /* SP2.2-n - notify agent is waiting and wait */
324 /* SP4.1-n - notify agent is waiting and wait */
325 rawMonitorNotify(jvmti_env, agent_data.monitor);
326
327 while (agent_data.thread_state == WAITING) {
328 /* SP3.2-w - wait to start test */
329 /* SP6.2-w - wait to end test */
330 rawMonitorWait(jvmti_env, agent_data.monitor, inc_timeout);
331
332 if (timeout == 0) continue;
333
334 t += inc_timeout;
335
336 if (t >= timeout) break;
337 }
338
339 if (agent_data.thread_state == WAITING) {
340 NSK_COMPLAIN1("No status sync occured for timeout: %"LL"d ms\n", timeout);
341 nsk_jvmti_setFailStatus();
342 result = NSK_FALSE;
343 }
344
345 rawMonitorExit(jvmti_env, agent_data.monitor);
346
347 return result;
348 }
349
350 /** Resume java code suspended on sync point. */
nsk_jvmti_resumeSync()351 int nsk_jvmti_resumeSync() {
352 int result;
353 rawMonitorEnter(jvmti_env, agent_data.monitor);
354
355 if (agent_data.thread_state == SUSPENDED) {
356 result = NSK_TRUE;
357 agent_data.thread_state = RUNNABLE;
358 /* SP5.2-n - notify suspend done */
359 /* SP7.2-n - notify agent end */
360 rawMonitorNotify(jvmti_env, agent_data.monitor);
361 }
362 else {
363 NSK_COMPLAIN0("Debuggee was not suspended on status sync\n");
364 nsk_jvmti_setFailStatus();
365 result = NSK_FALSE;
366 }
367
368 rawMonitorExit(jvmti_env, agent_data.monitor);
369 return NSK_TRUE;
370 }
371
372 /** Native function for Java code to provide sync point. */
373 JNIEXPORT jint JNICALL
Java_nsk_share_jvmti_DebugeeClass_checkStatus(JNIEnv * jni_env,jclass cls,jint debuggeeStatus)374 Java_nsk_share_jvmti_DebugeeClass_checkStatus(JNIEnv* jni_env, jclass cls, jint debuggeeStatus) {
375 jint status;
376 NSK_TRACE(status = syncDebuggeeStatus(jni_env, jvmti_env, debuggeeStatus));
377 return status;
378 }
379
380 /** Native function for Java code to reset agent data. */
381 JNIEXPORT void JNICALL
Java_nsk_share_jvmti_DebugeeClass_resetAgentData(JNIEnv * jni_env,jclass cls)382 Java_nsk_share_jvmti_DebugeeClass_resetAgentData(JNIEnv* jni_env, jclass cls) {
383 NSK_TRACE(nsk_jvmti_resetAgentData());
384 }
385
386 /* ============================================================================= */
387
388 /** Find loaded class by signature. */
nsk_jvmti_classBySignature(const char signature[])389 jclass nsk_jvmti_classBySignature(const char signature[]) {
390 jclass* classes = NULL;
391 jint count = 0;
392 jclass foundClass = NULL;
393 int i;
394
395 if (!NSK_VERIFY(signature != NULL)) {
396 nsk_jvmti_setFailStatus();
397 return NULL;
398 }
399
400 if (!NSK_JVMTI_VERIFY(
401 NSK_CPP_STUB3(GetLoadedClasses, jvmti_env, &count, &classes))) {
402 nsk_jvmti_setFailStatus();
403 return NULL;
404 }
405
406 for (i = 0; i < count; i++) {
407 char* sig = NULL;
408 char* generic = NULL;
409
410 if (!NSK_JVMTI_VERIFY(
411 NSK_CPP_STUB4(GetClassSignature, jvmti_env, classes[i], &sig, &generic))) {
412 nsk_jvmti_setFailStatus();
413 break;
414 }
415
416 if (sig != NULL && strcmp(signature, sig) == 0) {
417 foundClass = classes[i];
418 }
419
420 if (!(NSK_JVMTI_VERIFY(
421 NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)sig))
422 && NSK_JVMTI_VERIFY(
423 NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)generic)))) {
424 nsk_jvmti_setFailStatus();
425 break;
426 }
427
428 if (foundClass != NULL)
429 break;
430 }
431
432 if (!NSK_JVMTI_VERIFY(
433 NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)classes))) {
434 nsk_jvmti_setFailStatus();
435 return NULL;
436 }
437
438 if (!NSK_JNI_VERIFY(jni_env, (foundClass = (jclass)
439 NSK_CPP_STUB2(NewGlobalRef, jni_env, foundClass)) != NULL)) {
440 nsk_jvmti_setFailStatus();
441 return NULL;
442 }
443
444 return foundClass;
445 }
446
447 /** Find alive thread by name. */
nsk_jvmti_threadByName(const char name[])448 jthread nsk_jvmti_threadByName(const char name[]) {
449 jthread* threads = NULL;
450 jint count = 0;
451 jthread foundThread = NULL;
452 int i;
453
454 if (!NSK_VERIFY(name != NULL)) {
455 nsk_jvmti_setFailStatus();
456 return NULL;
457 }
458
459 if (!NSK_JVMTI_VERIFY(
460 NSK_CPP_STUB3(GetAllThreads, jvmti_env, &count, &threads))) {
461 nsk_jvmti_setFailStatus();
462 return NULL;
463 }
464
465 for (i = 0; i < count; i++) {
466 jvmtiThreadInfo info;
467
468 if (!NSK_JVMTI_VERIFY(
469 NSK_CPP_STUB3(GetThreadInfo, jvmti_env, threads[i], &info))) {
470 nsk_jvmti_setFailStatus();
471 break;
472 }
473
474 if (info.name != NULL && strcmp(name, info.name) == 0) {
475 foundThread = threads[i];
476 break;
477 }
478 }
479
480 if (!NSK_JVMTI_VERIFY(
481 NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)threads))) {
482 nsk_jvmti_setFailStatus();
483 return NULL;
484 }
485
486 if (!NSK_JNI_VERIFY(jni_env, (foundThread = (jthread)
487 NSK_CPP_STUB2(NewGlobalRef, jni_env, foundThread)) != NULL)) {
488 nsk_jvmti_setFailStatus();
489 return NULL;
490 }
491
492 return foundThread;
493 }
494
495
496 /* ============================================================================= */
497
498 /** Add all capabilities for finding line locations. */
nsk_jvmti_addLocationCapabilities()499 int nsk_jvmti_addLocationCapabilities() {
500 jvmtiCapabilities caps;
501
502 memset(&caps, 0, sizeof(caps));
503 caps.can_get_line_numbers = 1;
504 if (!NSK_JVMTI_VERIFY(
505 NSK_CPP_STUB2(AddCapabilities, jvmti_env, &caps)))
506 return NSK_FALSE;
507
508 return NSK_TRUE;
509 }
510
511 /** Add all capabilities for using breakpoints. */
nsk_jvmti_addBreakpointCapabilities()512 int nsk_jvmti_addBreakpointCapabilities() {
513 jvmtiCapabilities caps;
514
515 if (!nsk_jvmti_addLocationCapabilities())
516 return NSK_FALSE;
517
518 memset(&caps, 0, sizeof(caps));
519 caps.can_generate_breakpoint_events = 1;
520 if (!NSK_JVMTI_VERIFY(
521 NSK_CPP_STUB2(AddCapabilities, jvmti_env, &caps)))
522 return NSK_FALSE;
523
524 return NSK_TRUE;
525 }
526
527 /** Find line location. */
nsk_jvmti_getLineLocation(jclass cls,jmethodID method,int line)528 jlocation nsk_jvmti_getLineLocation(jclass cls, jmethodID method, int line) {
529 jint count = 0;
530 jvmtiLineNumberEntry* table = NULL;
531 jlocation location = NSK_JVMTI_INVALID_JLOCATION;
532 int i;
533
534 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetLineNumberTable, jvmti_env, method, &count, &table)))
535 return NSK_JVMTI_INVALID_JLOCATION;
536
537 for (i = 0; i < count; i++) {
538 if (table[i].line_number == line) {
539 location = table[i].start_location;
540 break;
541 }
542 }
543
544 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)table)))
545 return NSK_JVMTI_INVALID_JLOCATION;
546
547 return location;
548 }
549
550 /** Set breakpoint to a line. */
nsk_jvmti_setLineBreakpoint(jclass cls,jmethodID method,int line)551 jlocation nsk_jvmti_setLineBreakpoint(jclass cls, jmethodID method, int line) {
552 jlocation location = NSK_JVMTI_INVALID_JLOCATION;
553
554 if (!NSK_VERIFY((location =
555 nsk_jvmti_getLineLocation(cls, method, line)) != NSK_JVMTI_INVALID_JLOCATION))
556 return NSK_JVMTI_INVALID_JLOCATION;
557
558 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetBreakpoint, jvmti_env, method, location)))
559 return NSK_JVMTI_INVALID_JLOCATION;
560
561 return location;
562 }
563
564 /** Remove breakpoint from a line. */
nsk_jvmti_clearLineBreakpoint(jclass cls,jmethodID method,int line)565 jlocation nsk_jvmti_clearLineBreakpoint(jclass cls, jmethodID method, int line) {
566 jlocation location = NSK_JVMTI_INVALID_JLOCATION;
567
568 if (!NSK_VERIFY((location =
569 nsk_jvmti_getLineLocation(cls, method, line)) != NSK_JVMTI_INVALID_JLOCATION))
570 return NSK_JVMTI_INVALID_JLOCATION;
571
572 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(ClearBreakpoint, jvmti_env, method, location)))
573 return NSK_JVMTI_INVALID_JLOCATION;
574
575 return location;
576 }
577
578 /* ============================================================================= */
579
580 /** Enable or disable given events. */
nsk_jvmti_enableEvents(jvmtiEventMode enable,int size,jvmtiEvent list[],jthread thread)581 int nsk_jvmti_enableEvents(jvmtiEventMode enable, int size, jvmtiEvent list[], jthread thread) {
582 int i;
583
584 for (i = 0; i < size; i++) {
585 if (!NSK_JVMTI_VERIFY(
586 NSK_CPP_STUB4(SetEventNotificationMode, jvmti_env, enable,
587 list[i], thread))) {
588 nsk_jvmti_setFailStatus();
589 return NSK_FALSE;
590 }
591 }
592 return NSK_TRUE;
593 }
594
595 /* ============================================================================= */
596
597 typedef jint (JNICALL *checkStatus_type)(JNIEnv* jni_env, jclass cls, jint debuggeeStatus);
598
599 static checkStatus_type checkStatus_func = NULL;
600
601 /**
602 * Proxy function to gain sequential access to checkStatus of each agent
603 */
604 JNIEXPORT jint JNICALL
MA_checkStatus(JNIEnv * jni_env,jclass cls,jint debuggeeStatus)605 MA_checkStatus(JNIEnv* jni_env, jclass cls, jint debuggeeStatus) {
606 jint status;
607
608 NSK_TRACE(status = syncDebuggeeStatus(jni_env, jvmti_env, debuggeeStatus));
609 return (*checkStatus_func)(jni_env, cls, status);
610 }
611
612 /**
613 * nativeMethodBind callback:
614 * if needed, redirects checkStatus native method call
615 */
nativeMethodBind(jvmtiEnv * jvmti_env,JNIEnv * jni_env,jthread thread,jmethodID mid,void * address,void ** new_address_ptr)616 static void JNICALL nativeMethodBind(jvmtiEnv* jvmti_env, JNIEnv *jni_env,
617 jthread thread, jmethodID mid,
618 void* address, void** new_address_ptr) {
619 const char* BIND_CLASS_NAME = "Lnsk/share/jvmti/DebugeeClass;";
620 const char* BIND_METHOD_NAME = "checkStatus";
621 const char* BIND_METHOD_SIGNATURE = "(I)I";
622
623 jvmtiPhase phase;
624 jclass cls;
625 char *class_sig = NULL;
626 char *name = NULL;
627 char *sig = NULL;
628
629 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetPhase, jvmti_env, &phase))) {
630 nsk_jvmti_setFailStatus();
631 return;
632 }
633
634 if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE)
635 return;
636
637 if (NSK_JVMTI_VERIFY(
638 NSK_CPP_STUB5(GetMethodName, jvmti_env, mid, &name, &sig, NULL))) {
639 if (strcmp(name, BIND_METHOD_NAME) == 0 &&
640 strcmp(sig, BIND_METHOD_SIGNATURE) == 0) {
641
642 if (NSK_JVMTI_VERIFY(
643 NSK_CPP_STUB3(GetMethodDeclaringClass, jvmti_env, mid, &cls))
644 && NSK_JVMTI_VERIFY(
645 NSK_CPP_STUB4(GetClassSignature, jvmti_env, cls, &class_sig, NULL))
646 && strcmp(class_sig, BIND_CLASS_NAME) == 0
647 && address != (void*)Java_nsk_share_jvmti_DebugeeClass_checkStatus) {
648 checkStatus_func = (checkStatus_type)address;
649 NSK_TRACE(*new_address_ptr = (void*)MA_checkStatus);
650 }
651 }
652 }
653
654 if (name != NULL)
655 NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)name);
656
657 if (sig != NULL)
658 NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)sig);
659
660 if (class_sig != NULL)
661 NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)class_sig);
662 }
663
664 /**
665 * Initialize multiple agent:
666 * establish processing of nativeMethodBind events
667 */
nsk_jvmti_init_MA(jvmtiEventCallbacks * callbacks)668 int nsk_jvmti_init_MA(jvmtiEventCallbacks* callbacks) {
669
670 if (callbacks == NULL) {
671 NSK_COMPLAIN0("callbacks should not be NULL\n");
672 nsk_jvmti_setFailStatus();
673 return NSK_FALSE;
674 }
675
676 if (callbacks->NativeMethodBind != NULL) {
677 NSK_COMPLAIN0("callbacks.NativeMethodBind should be NULL\n");
678 nsk_jvmti_setFailStatus();
679 return NSK_FALSE;
680 }
681
682 {
683 jvmtiCapabilities caps;
684 memset(&caps, 0, sizeof(caps));
685 caps.can_generate_native_method_bind_events = 1;
686 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, jvmti_env, &caps)))
687 return NSK_FALSE;
688 }
689
690 callbacks->NativeMethodBind = nativeMethodBind;
691 if (!NSK_JVMTI_VERIFY(
692 NSK_CPP_STUB3(SetEventCallbacks, jvmti_env, callbacks,
693 sizeof(jvmtiEventCallbacks))))
694 return NSK_FALSE;
695
696 if (!NSK_JVMTI_VERIFY(
697 NSK_CPP_STUB4(SetEventNotificationMode, jvmti_env, JVMTI_ENABLE,
698 JVMTI_EVENT_NATIVE_METHOD_BIND, NULL)))
699 return NSK_FALSE;
700
701 return NSK_TRUE;
702 }
703
704 /* ============================================================================= */
705
nsk_jvmti_isOptionalEvent(jvmtiEvent event)706 int nsk_jvmti_isOptionalEvent(jvmtiEvent event) {
707
708 return (event == JVMTI_EVENT_EXCEPTION)
709 || (event == JVMTI_EVENT_EXCEPTION_CATCH)
710 || (event == JVMTI_EVENT_SINGLE_STEP)
711 || (event == JVMTI_EVENT_FRAME_POP)
712 || (event == JVMTI_EVENT_BREAKPOINT)
713 || (event == JVMTI_EVENT_FIELD_ACCESS)
714 || (event == JVMTI_EVENT_FIELD_MODIFICATION)
715 || (event == JVMTI_EVENT_METHOD_ENTRY)
716 || (event == JVMTI_EVENT_METHOD_EXIT)
717 || (event == JVMTI_EVENT_NATIVE_METHOD_BIND)
718 || (event == JVMTI_EVENT_COMPILED_METHOD_LOAD)
719 || (event == JVMTI_EVENT_COMPILED_METHOD_UNLOAD)
720 || (event == JVMTI_EVENT_MONITOR_WAIT)
721 || (event == JVMTI_EVENT_MONITOR_WAITED)
722 || (event == JVMTI_EVENT_MONITOR_CONTENDED_ENTER)
723 || (event == JVMTI_EVENT_MONITOR_CONTENDED_ENTERED)
724 || (event == JVMTI_EVENT_GARBAGE_COLLECTION_START)
725 || (event == JVMTI_EVENT_GARBAGE_COLLECTION_FINISH)
726 || (event == JVMTI_EVENT_OBJECT_FREE)
727 || (event == JVMTI_EVENT_VM_OBJECT_ALLOC);
728 }
729
730 /* ============================================================================= */
731
nsk_jvmti_showPossessedCapabilities(jvmtiEnv * jvmti_env)732 void nsk_jvmti_showPossessedCapabilities(jvmtiEnv *jvmti_env) {
733
734 jvmtiCapabilities caps;
735
736 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetCapabilities, jvmti_env, &caps))) {
737 return;
738 }
739
740 NSK_DISPLAY0("\n");
741 NSK_DISPLAY0("Possessed capabilities:\n");
742 NSK_DISPLAY0("-----------------------\n");
743 if (caps.can_tag_objects)
744 NSK_DISPLAY0("\tcan_tag_objects\n");
745 if (caps.can_generate_field_modification_events)
746 NSK_DISPLAY0("\tcan_generate_field_modification_events\n");
747 if (caps.can_generate_field_access_events)
748 NSK_DISPLAY0("\tcan_generate_field_access_events\n");
749 if (caps.can_get_bytecodes)
750 NSK_DISPLAY0("\tcan_get_bytecodes\n");
751 if (caps.can_get_synthetic_attribute)
752 NSK_DISPLAY0("\tcan_get_synthetic_attribute\n");
753 if (caps.can_get_owned_monitor_info)
754 NSK_DISPLAY0("\tcan_get_owned_monitor_info\n");
755 if (caps.can_get_current_contended_monitor)
756 NSK_DISPLAY0("\tcan_get_current_contended_monitor\n");
757 if (caps.can_get_monitor_info)
758 NSK_DISPLAY0("\tcan_get_monitor_info\n");
759 if (caps.can_pop_frame)
760 NSK_DISPLAY0("\tcan_pop_frame\n");
761 if (caps.can_redefine_classes)
762 NSK_DISPLAY0("\tcan_redefine_classes\n");
763 if (caps.can_signal_thread)
764 NSK_DISPLAY0("\tcan_signal_thread\n");
765 if (caps.can_get_source_file_name)
766 NSK_DISPLAY0("\tcan_get_source_file_name\n");
767 if (caps.can_get_line_numbers)
768 NSK_DISPLAY0("\tcan_get_line_numbers\n");
769 if (caps.can_get_source_debug_extension)
770 NSK_DISPLAY0("\tcan_get_source_debug_extension\n");
771 if (caps.can_access_local_variables)
772 NSK_DISPLAY0("\tcan_access_local_variables\n");
773 if (caps.can_maintain_original_method_order)
774 NSK_DISPLAY0("\tcan_maintain_original_method_order\n");
775 if (caps.can_generate_single_step_events)
776 NSK_DISPLAY0("\tcan_generate_single_step_events\n");
777 if (caps.can_generate_exception_events)
778 NSK_DISPLAY0("\tcan_generate_exception_events\n");
779 if (caps.can_generate_frame_pop_events)
780 NSK_DISPLAY0("\tcan_generate_frame_pop_events\n");
781 if (caps.can_generate_breakpoint_events)
782 NSK_DISPLAY0("\tcan_generate_breakpoint_events\n");
783 if (caps.can_suspend)
784 NSK_DISPLAY0("\tcan_suspend\n");
785 if (caps.can_get_current_thread_cpu_time)
786 NSK_DISPLAY0("\tcan_get_current_thread_cpu_time\n");
787 if (caps.can_get_thread_cpu_time)
788 NSK_DISPLAY0("\tcan_get_thread_cpu_time\n");
789 if (caps.can_generate_method_entry_events)
790 NSK_DISPLAY0("\tcan_generate_method_entry_events\n");
791 if (caps.can_generate_method_exit_events)
792 NSK_DISPLAY0("\tcan_generate_method_exit_events\n");
793 if (caps.can_generate_all_class_hook_events)
794 NSK_DISPLAY0("\tcan_generate_all_class_hook_events\n");
795 if (caps.can_generate_compiled_method_load_events)
796 NSK_DISPLAY0("\tcan_generate_compiled_method_load_events\n");
797 if (caps.can_generate_monitor_events)
798 NSK_DISPLAY0("\tcan_generate_monitor_events\n");
799 if (caps.can_generate_vm_object_alloc_events)
800 NSK_DISPLAY0("\tcan_generate_vm_object_alloc_events\n");
801 if (caps.can_generate_native_method_bind_events)
802 NSK_DISPLAY0("\tcan_generate_native_method_bind_events\n");
803 if (caps.can_generate_garbage_collection_events)
804 NSK_DISPLAY0("\tcan_generate_garbage_collection_events\n");
805 if (caps.can_generate_object_free_events)
806 NSK_DISPLAY0("\tcan_generate_object_free_events\n");
807
808 NSK_DISPLAY0("\n");
809 }
810
811 /* ============================================================================= */
812
813 #ifdef __cplusplus
814 }
815 #endif
816