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