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 <string.h>
25 #include "jvmti.h"
26 #include "agent_common.h"
27 #include "jni_tools.h"
28 #include "jvmti_tools.h"
29 
30 extern "C" {
31 
32 /* ============================================================================= */
33 
34 static jlong timeout = 0;
35 
36 #define INFO_NONE       0x00
37 #define INFO_ALL        0xFF
38 #define INFO_OBJREF     0x01
39 #define INFO_STACKREF   0x02
40 #define INFO_HEAPROOT   0x04
41 #define INFO_HEAPOBJ    0x08
42 #define INFO_HEAPOBJ    0x08
43 
44 static unsigned int info = INFO_NONE;
45 
46 #define DEBUGEE_CLASS_NAME      "nsk/jvmti/IterateOverInstancesOfClass/iterinstcls001"
47 #define ROOT_OBJECT_CLASS_NAME  "nsk/jvmti/IterateOverInstancesOfClass/iterinstcls001RootTestedClass"
48 #define ROOT_OBJECT_CLASS_SIG   "L" ROOT_OBJECT_CLASS_NAME ";"
49 #define CHAIN_OBJECT_CLASS_NAME "nsk/jvmti/IterateOverInstancesOfClass/iterinstcls001TestedClass"
50 #define CHAIN_OBJECT_CLASS_SIG  "L" CHAIN_OBJECT_CLASS_NAME ";"
51 
52 #define OBJECT_FIELD_NAME               "object"
53 #define REACHABLE_CHAIN_FIELD_NAME      "reachableChain"
54 #define UNREACHABLE_CHAIN_FIELD_NAME    "unreachableChain"
55 #define TAIL_FIELD_NAME                 "tail"
56 
57 #define DEFAULT_CHAIN_LENGTH 4
58 
59 typedef struct ObjectDescStruct {
60     jlong tag;
61     jint found;
62     int collected;
63 } ObjectDesc;
64 
65 static int chainLength = 0;
66 static int objectsCount = 0;
67 
68 static ObjectDesc* objectDescList = NULL;
69 
70 static volatile int foundUntagged = 0;
71 
72 static int fakeUserData = 0;
73 static int userDataError = 0;
74 
75 /* ============================================================================= */
76 
77 /** Obtain chain of tested objects and tag them recursively. */
getChainObjects(jvmtiEnv * jvmti,JNIEnv * jni,jobject firstObject,jfieldID firstField,const char firstFieldName[],jfieldID nextField,const char nextFieldName[],int count,ObjectDesc objectDescList[],jlong tag,int reachable)78 static int getChainObjects(jvmtiEnv* jvmti, JNIEnv* jni, jobject firstObject,
79                                     jfieldID firstField, const char firstFieldName[],
80                                     jfieldID nextField, const char nextFieldName[],
81                                     int count, ObjectDesc objectDescList[],
82                                     jlong tag, int reachable) {
83 
84     int success = NSK_TRUE;
85     jobject obj = NULL;
86     jlong objTag = (!reachable ? -tag : (tag % 2 != 0) ? tag : (jlong)0);
87 
88     if (count <= 0)
89         return NSK_TRUE;
90 
91     count--;
92     tag++;
93 
94     if (!NSK_JNI_VERIFY(jni, (obj =
95             jni->GetObjectField(firstObject, firstField)) != NULL)) {
96         nsk_jvmti_setFailStatus();
97         return NSK_FALSE;
98     }
99 
100     objectDescList[count].tag = objTag;
101     if (!NSK_JVMTI_VERIFY(
102             jvmti->SetTag(obj, objTag))) {
103         nsk_jvmti_setFailStatus();
104         return NSK_FALSE;
105     }
106     NSK_DISPLAY2("        tag=%-5ld object=0x%p\n", (long)objTag, (void*)obj);
107 
108     if (!getChainObjects(jvmti, jni, obj, nextField, nextFieldName,
109                                 nextField, nextFieldName,
110                                 count, objectDescList, tag, reachable)) {
111         return NSK_FALSE;
112     }
113 
114     NSK_TRACE(jni->DeleteLocalRef(obj));
115     return success;
116 }
117 
118 /** Obtain all tested objects from debugee class and tag them recursively. */
getTestedObjects(jvmtiEnv * jvmti,JNIEnv * jni,int chainLength,int * objectsCount,ObjectDesc ** objectDescList,jclass * testedClass)119 static int getTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength,
120                                     int *objectsCount, ObjectDesc* *objectDescList,
121                                     jclass *testedClass) {
122     jclass debugeeClass = NULL;
123     jclass rootObjectClass = NULL;
124     jclass chainObjectClass = NULL;
125 
126     jfieldID objectField = NULL;
127     jfieldID reachableChainField = NULL;
128     jfieldID unreachableChainField = NULL;
129     jfieldID tailField = NULL;
130 
131     jobject rootObject = NULL;
132 
133     jlong testedClassTag = 1;
134     jlong chainObjectTag = 100;
135 
136     *objectsCount = 2 * chainLength;
137 
138     NSK_DISPLAY1("Allocate memory for objects list: %d objects\n", *objectsCount);
139     if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)), (unsigned char**)objectDescList))) {
140         nsk_jvmti_setFailStatus();
141         return NSK_FALSE;
142     }
143     NSK_DISPLAY1("  ... allocated array: 0x%p\n", (void*)objectDescList);
144 
145     {
146         int k;
147         for (k = 0; k < *objectsCount; k++) {
148             (*objectDescList)[k].tag = 0;
149             (*objectDescList)[k].found = 0;
150             (*objectDescList)[k].collected = 0;
151         }
152     }
153 
154     NSK_DISPLAY1("Find debugee class: %s\n", DEBUGEE_CLASS_NAME);
155     if (!NSK_JNI_VERIFY(jni, (debugeeClass =
156             jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL)) {
157         nsk_jvmti_setFailStatus();
158         return NSK_FALSE;
159     }
160     NSK_DISPLAY1("  ... found class: 0x%p\n", (void*)debugeeClass);
161 
162     NSK_DISPLAY1("Find root object class: %s\n", ROOT_OBJECT_CLASS_NAME);
163     if (!NSK_JNI_VERIFY(jni, (rootObjectClass =
164             jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != NULL)) {
165         nsk_jvmti_setFailStatus();
166         return NSK_FALSE;
167     }
168     NSK_DISPLAY1("  ... found class: 0x%p\n", (void*)rootObjectClass);
169 
170     NSK_DISPLAY1("Find chain object class: %s\n", CHAIN_OBJECT_CLASS_NAME);
171     if (!NSK_JNI_VERIFY(jni, (chainObjectClass =
172             jni->FindClass(CHAIN_OBJECT_CLASS_NAME)) != NULL)) {
173         nsk_jvmti_setFailStatus();
174         return NSK_FALSE;
175     }
176     NSK_DISPLAY1("  ... found class: 0x%p\n", (void*)chainObjectClass);
177 
178     NSK_DISPLAY1("Create global ref to tested class: 0x%p\n", chainObjectClass);
179     if (!NSK_JNI_VERIFY(jni, (*testedClass = (jclass)
180             jni->NewGlobalRef(chainObjectClass)) != NULL)) {
181         nsk_jvmti_setFailStatus();
182         return NSK_FALSE;
183     }
184     NSK_DISPLAY1("  ... global ref: 0x%p\n", (void*)*testedClass);
185 
186     NSK_DISPLAY1("Find static field in debugee class: %s\n", OBJECT_FIELD_NAME);
187     if (!NSK_JNI_VERIFY(jni, (objectField =
188             jni->GetStaticFieldID(debugeeClass, OBJECT_FIELD_NAME, ROOT_OBJECT_CLASS_SIG)) != NULL)) {
189         nsk_jvmti_setFailStatus();
190         return NSK_FALSE;
191     }
192     NSK_DISPLAY1("  ... got fieldID: 0x%p\n", (void*)objectField);
193 
194     NSK_DISPLAY1("Find instance field in root object class: %s\n", REACHABLE_CHAIN_FIELD_NAME);
195     if (!NSK_JNI_VERIFY(jni, (reachableChainField =
196             jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
197         nsk_jvmti_setFailStatus();
198         return NSK_FALSE;
199     }
200     NSK_DISPLAY1("  ... got fieldID: 0x%p\n", (void*)reachableChainField);
201 
202     NSK_DISPLAY1("Find instance field in root object class: %s\n", UNREACHABLE_CHAIN_FIELD_NAME);
203     if (!NSK_JNI_VERIFY(jni, (unreachableChainField =
204             jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
205         nsk_jvmti_setFailStatus();
206         return NSK_FALSE;
207     }
208     NSK_DISPLAY1("  ... got fieldID: 0x%p\n", (void*)unreachableChainField);
209 
210     NSK_DISPLAY1("Find instance field in chain object class: %s\n", TAIL_FIELD_NAME);
211     if (!NSK_JNI_VERIFY(jni, (tailField =
212             jni->GetFieldID(chainObjectClass, TAIL_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
213         nsk_jvmti_setFailStatus();
214         return NSK_FALSE;
215     }
216     NSK_DISPLAY1("  ... got fieldID: 0x%p\n", (void*)tailField);
217 
218     NSK_DISPLAY1("Get root object from static field: %s\n", OBJECT_FIELD_NAME);
219     if (!NSK_JNI_VERIFY(jni, (rootObject =
220             jni->GetStaticObjectField(debugeeClass, objectField)) != NULL)) {
221         nsk_jvmti_setFailStatus();
222         return NSK_FALSE;
223     }
224     NSK_DISPLAY1("  ... got object: 0x%p\n", (void*)rootObject);
225 
226     NSK_DISPLAY0("Obtain and tag chain objects:\n");
227 
228     NSK_DISPLAY0("    tested class object:\n");
229     if (!NSK_JVMTI_VERIFY(
230             jvmti->SetTag(*testedClass, testedClassTag))) {
231         nsk_jvmti_setFailStatus();
232         return NSK_FALSE;
233     }
234     NSK_DISPLAY2("        tag=%-5ld object=0x%p\n", (long)testedClassTag, (void*)*testedClass);
235 
236     NSK_DISPLAY1("    reachable objects chain: %d objects\n", chainLength);
237     if (!getChainObjects(jvmti, jni, rootObject,
238                                 reachableChainField, REACHABLE_CHAIN_FIELD_NAME,
239                                 tailField, TAIL_FIELD_NAME,
240                                 chainLength, *objectDescList,
241                                 chainObjectTag, NSK_TRUE)) {
242         nsk_jvmti_setFailStatus();
243         return NSK_FALSE;
244     }
245 
246     NSK_DISPLAY1("    unreachable objects chain: %d objects\n", chainLength);
247     if (!getChainObjects(jvmti, jni, rootObject,
248                                 unreachableChainField, UNREACHABLE_CHAIN_FIELD_NAME,
249                                 tailField, TAIL_FIELD_NAME,
250                                 chainLength, *objectDescList + chainLength,
251                                 chainObjectTag, NSK_FALSE)) {
252         nsk_jvmti_setFailStatus();
253         return NSK_FALSE;
254     }
255 
256     return NSK_TRUE;
257 }
258 
259 /** Check if tagged objects were iterated. */
checkTestedObjects(jvmtiEnv * jvmti,JNIEnv * jni,int chainLength,ObjectDesc objectDescList[])260 static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni,
261                                 int chainLength, ObjectDesc objectDescList[]) {
262     int success = NSK_TRUE;
263     int expectedUntagged = 0;
264     int i;
265 
266     NSK_DISPLAY0("Following tagged/untagged objects were iterated:\n");
267 
268     NSK_DISPLAY0("    reachable objects:\n");
269     for (i = 0; i < chainLength; i++) {
270         NSK_DISPLAY2("        tag=%-5ld iterated=%d times\n",
271                         (long)objectDescList[i].tag, objectDescList[i].found);
272 
273         if (objectDescList[i].found <= 0
274                     && objectDescList[i].tag != 0) {
275             NSK_COMPLAIN2("Reachable tagged object was not iterated:\n"
276                           "#   tag:      %ld\n"
277                           "#   iterated: %d times\n",
278                             (long)objectDescList[i].tag,
279                             objectDescList[i].found);
280             nsk_jvmti_setFailStatus();
281         }
282 
283         if (objectDescList[i].tag == 0) {
284             expectedUntagged++;
285         }
286     }
287 
288     NSK_DISPLAY0("    unreachable objects:\n");
289     for (i = 0; i < chainLength; i++) {
290         NSK_DISPLAY3("        tag=%-5ld iterated=%-3d collected=%d times\n",
291                         (long)objectDescList[i + chainLength].tag,
292                         objectDescList[i + chainLength].found,
293                         objectDescList[i + chainLength].collected);
294 
295         if (objectDescList[i + chainLength].found <= 0
296                     && objectDescList[i + chainLength].collected <= 0) {
297             NSK_COMPLAIN2("Not collected unreachable tagged object was not iterated:\n"
298                           "#   tag:      %ld\n"
299                           "#   iterated: %d times\n",
300                             (long)objectDescList[i + chainLength].tag,
301                             objectDescList[i + chainLength].found);
302             nsk_jvmti_setFailStatus();
303         }
304     }
305 
306     NSK_DISPLAY0("    untagged objects:\n");
307     NSK_DISPLAY2("        total=%-3d iterated=%d objects\n",
308                                     expectedUntagged, foundUntagged);
309     if (foundUntagged != expectedUntagged) {
310         NSK_COMPLAIN2("Unexpected number of untagged objects were iterated:\n"
311                       "#   iterated untagged objects: %d\n"
312                       "#   expected:                  %d\n",
313                         foundUntagged, expectedUntagged);
314         nsk_jvmti_setFailStatus();
315     }
316 
317     return NSK_TRUE;
318 }
319 
320 /** Release references to the tested objects and free allocated memory. */
releaseTestedObjects(jvmtiEnv * jvmti,JNIEnv * jni,int chainLength,ObjectDesc * objectDescList,jclass testedClass)321 static int releaseTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength,
322                                         ObjectDesc* objectDescList, jclass testedClass) {
323     if (testedClass != NULL) {
324         NSK_DISPLAY1("Release object reference to tested class: 0x%p\n", testedClass);
325         NSK_TRACE(jni->DeleteGlobalRef(testedClass));
326     }
327 
328     if (objectDescList != NULL) {
329         NSK_DISPLAY1("Deallocate objects list: 0x%p\n", (void*)objectDescList);
330         if (!NSK_JVMTI_VERIFY(
331             jvmti->Deallocate((unsigned char*)objectDescList))) {
332             nsk_jvmti_setFailStatus();
333         }
334     }
335 
336     return NSK_TRUE;
337 }
338 
339 /* ============================================================================= */
340 
341 /** heapRootCallback for heap iterator. */
342 jvmtiIterationControl JNICALL
heapObjectCallback(jlong class_tag,jlong size,jlong * tag_ptr,void * user_data)343 heapObjectCallback(jlong class_tag, jlong size, jlong* tag_ptr, void* user_data) {
344 
345     if (info & INFO_HEAPOBJ) {
346         NSK_DISPLAY3("  heapObjectCallback: class_tag=%-3ld size=%-3ld *tag_ptr=%-5ld\n",
347                         (long)class_tag, (long)size,
348                         (long)(tag_ptr == NULL ? (jlong)0 : *tag_ptr));
349     }
350 
351     if (class_tag != 1) {
352         NSK_COMPLAIN3("Unexpected class_tag passed to heapObjectCallback:\n"
353                       "#   object tag:     %ld\n"
354                       "#   class_tag:      %ld\n"
355                       "#   size:           %ld\n",
356                         (long)*tag_ptr,
357                         (long)class_tag,
358                         (long)size);
359         nsk_jvmti_setFailStatus();
360     }
361 
362     if (tag_ptr == NULL) {
363         NSK_COMPLAIN3("NULL tag_ptr is passed to heapObjectCallback:\n"
364                       "#   tag_ptr:        0x%p\n"
365                       "#   class_tag:      %ld\n"
366                       "#   size:           %ld\n",
367                         (void*)tag_ptr,
368                         (long)class_tag,
369                         (long)size);
370         nsk_jvmti_setFailStatus();
371     } else {
372         if (*tag_ptr == 0) {
373             foundUntagged++;
374         } else {
375             int found = 0;
376             int i;
377 
378             for (i = 0; i < objectsCount; i++) {
379                 if (*tag_ptr == objectDescList[i].tag) {
380                     found++;
381                     objectDescList[i].found++;
382                     break;
383                 }
384             }
385 
386             if (found <= 0) {
387                 NSK_COMPLAIN3("Unknown tagged object passed to heapObjectCallback:\n"
388                               "#   tag:            %ld\n"
389                               "#   class_tag:      %ld\n"
390                               "#   size:           %ld\n",
391                                 (long)*tag_ptr,
392                                 (long)class_tag,
393                                 (long)size);
394                 nsk_jvmti_setFailStatus();
395             }
396         }
397     }
398 
399     if (user_data != &fakeUserData && !userDataError) {
400        NSK_COMPLAIN2("Unexpected user_data is passed to heapObjectCallback:\n"
401                       "#   expected:       0x%p\n"
402                       "#   actual:         0x%p\n",
403                       user_data,
404                       &fakeUserData);
405         nsk_jvmti_setFailStatus();
406         userDataError++;
407     }
408 
409     return JVMTI_ITERATION_CONTINUE;
410 }
411 
412 /* ============================================================================= */
413 
414 /** Agent algorithm. */
415 static void JNICALL
agentProc(jvmtiEnv * jvmti,JNIEnv * jni,void * arg)416 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
417     NSK_DISPLAY0("Wait for tested objects created\n");
418     if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
419         return;
420 
421     {
422         jclass testedClass = NULL;
423 
424         NSK_DISPLAY0(">>> Obtain and tag tested objects from debugee class\n");
425         {
426             if (!NSK_VERIFY(getTestedObjects(jvmti, jni, chainLength,
427                                         &objectsCount, &objectDescList, &testedClass)))
428                 return;
429         }
430 
431         NSK_DISPLAY0(">>> Enable OBJECT_FREE event and let debugee to clean links to unreachable objects\n");
432         {
433             jvmtiEvent event = JVMTI_EVENT_OBJECT_FREE;
434             if (!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_ENABLE, 1, &event, NULL)))
435                 return;
436 
437             if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
438                 return;
439             if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
440                 return;
441         }
442 
443         NSK_DISPLAY0(">>> Iterate over instances of tested class with filter JVMTI_HEAP_OBJECT_EITHER\n");
444         {
445             if (!NSK_JVMTI_VERIFY(
446                     jvmti->IterateOverInstancesOfClass(testedClass, JVMTI_HEAP_OBJECT_EITHER, heapObjectCallback, &fakeUserData))) {
447                 nsk_jvmti_setFailStatus();
448                 return;
449             }
450         }
451 
452         NSK_DISPLAY0(">>> Disable OBJECT_FREE event and check if tagged/untagged objects were iterated:\n");
453         {
454             jvmtiEvent event = JVMTI_EVENT_OBJECT_FREE;
455             if (!NSK_VERIFY(nsk_jvmti_enableEvents(JVMTI_DISABLE, 1, &event, NULL)))
456                 return;
457 
458             if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) {
459                 nsk_jvmti_setFailStatus();
460             }
461         }
462 
463         NSK_DISPLAY0(">>> Clean used data\n");
464         {
465             if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength,
466                                                             objectDescList, testedClass)))
467                 return;
468         }
469     }
470 
471     NSK_DISPLAY0("Let debugee to finish\n");
472     if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
473         return;
474 }
475 
476 /* ============================================================================= */
477 
478 JNIEXPORT void JNICALL
callbackObjectFree(jvmtiEnv * jvmti,jlong tag)479 callbackObjectFree(jvmtiEnv* jvmti, jlong tag) {
480     int i;
481 
482     if (info & INFO_HEAPOBJ) {
483         NSK_DISPLAY1("  <ObjectFree>: tag=%-5ld\n", tag);
484     }
485 
486     if (tag != 0) {
487         for (i = 0; i < objectsCount; i++) {
488             if (tag == objectDescList[i].tag) {
489                 objectDescList[i].collected++;
490                 break;
491             }
492         }
493     }
494 }
495 
496 /* ============================================================================= */
497 
498 /** Agent library initialization. */
499 #ifdef STATIC_BUILD
Agent_OnLoad_iterinstcls001(JavaVM * jvm,char * options,void * reserved)500 JNIEXPORT jint JNICALL Agent_OnLoad_iterinstcls001(JavaVM *jvm, char *options, void *reserved) {
501     return Agent_Initialize(jvm, options, reserved);
502 }
Agent_OnAttach_iterinstcls001(JavaVM * jvm,char * options,void * reserved)503 JNIEXPORT jint JNICALL Agent_OnAttach_iterinstcls001(JavaVM *jvm, char *options, void *reserved) {
504     return Agent_Initialize(jvm, options, reserved);
505 }
JNI_OnLoad_iterinstcls001(JavaVM * jvm,char * options,void * reserved)506 JNIEXPORT jint JNI_OnLoad_iterinstcls001(JavaVM *jvm, char *options, void *reserved) {
507     return JNI_VERSION_1_8;
508 }
509 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)510 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
511     jvmtiEnv* jvmti = NULL;
512 
513     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
514         return JNI_ERR;
515 
516     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
517 
518     {
519         const char* infoOpt = nsk_jvmti_findOptionValue("info");
520         if (infoOpt != NULL) {
521             if (strcmp(infoOpt, "none") == 0)
522                 info = INFO_NONE;
523             else if (strcmp(infoOpt, "all") == 0)
524                 info = INFO_ALL;
525             else if (strcmp(infoOpt, "objref") == 0)
526                 info = INFO_OBJREF;
527             else if (strcmp(infoOpt, "stackref") == 0)
528                 info = INFO_STACKREF;
529             else if (strcmp(infoOpt, "heaproot") == 0)
530                 info = INFO_HEAPROOT;
531             else if (strcmp(infoOpt, "heapobj") == 0)
532                 info = INFO_HEAPOBJ;
533             else {
534                 NSK_COMPLAIN1("Unknown option value: info=%s\n", infoOpt);
535                 return JNI_ERR;
536             }
537         }
538     }
539 
540     chainLength = nsk_jvmti_findOptionIntValue("objects", DEFAULT_CHAIN_LENGTH);
541     if (!NSK_VERIFY(chainLength > 0))
542         return JNI_ERR;
543 
544     if (!NSK_VERIFY((jvmti =
545             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
546         return JNI_ERR;
547 
548     {
549         jvmtiCapabilities caps;
550 
551         memset(&caps, 0, sizeof(caps));
552         caps.can_tag_objects = 1;
553         caps.can_generate_object_free_events = 1;
554         if (!NSK_JVMTI_VERIFY(
555                 jvmti->AddCapabilities(&caps))) {
556             return JNI_ERR;
557         }
558     }
559 
560     {
561         jvmtiEventCallbacks eventCallbacks;
562         memset(&eventCallbacks, 0, sizeof(eventCallbacks));
563         eventCallbacks.ObjectFree = callbackObjectFree;
564         if (!NSK_JVMTI_VERIFY(
565                 jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks))))
566             return JNI_ERR;
567     }
568 
569     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
570         return JNI_ERR;
571 
572     return JNI_OK;
573 }
574 
575 /* ============================================================================= */
576 
577 }
578