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