xref: /onnv-gate/usr/src/lib/libdtrace_jni/common/dtj_util.c (revision 1717:ef845d4a1074)
11449Stomee /*
21449Stomee  * CDDL HEADER START
31449Stomee  *
41449Stomee  * The contents of this file are subject to the terms of the
51449Stomee  * Common Development and Distribution License (the "License").
61449Stomee  * You may not use this file except in compliance with the License.
71449Stomee  *
81449Stomee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91449Stomee  * or http://www.opensolaris.org/os/licensing.
101449Stomee  * See the License for the specific language governing permissions
111449Stomee  * and limitations under the License.
121449Stomee  *
131449Stomee  * When distributing Covered Code, include this CDDL HEADER in each
141449Stomee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151449Stomee  * If applicable, add the following below this CDDL HEADER, with the
161449Stomee  * fields enclosed by brackets "[]" replaced with your own identifying
171449Stomee  * information: Portions Copyright [yyyy] [name of copyright owner]
181449Stomee  *
191449Stomee  * CDDL HEADER END
201449Stomee  */
211449Stomee 
221449Stomee /*
231449Stomee  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241449Stomee  * Use is subject to license terms.
251449Stomee  */
261449Stomee 
271449Stomee #pragma ident	"%Z%%M%	%I%	%E% SMI"
281449Stomee 
291449Stomee #include <stdlib.h>
301449Stomee #include <stddef.h>
311449Stomee #include <sys/types.h>
321449Stomee #include <pthread.h>
331449Stomee #include <string.h>
341449Stomee #include <dtj_util.h>
351449Stomee 
361449Stomee /*
371449Stomee  * dtj_util.c separates functionality that is generally useful from
381449Stomee  * that which is specific to the Java DTrace API.  If moved to a separate
391449Stomee  * library, this functionality could be shared by other JNI wrappers.
401449Stomee  */
411449Stomee 
421449Stomee boolean_t g_dtj_util_debug = B_FALSE;
431449Stomee static boolean_t g_dtj_load_common = B_FALSE;
441449Stomee 
451449Stomee /* NativeException */
461449Stomee jclass g_nx_jc = 0;
471449Stomee jmethodID g_nxinit_jm = 0;
481449Stomee 
491449Stomee /* java.io.Serializable */
501449Stomee jclass g_serial_jc = 0;
511449Stomee 
521449Stomee /* java.lang.Number */
531449Stomee jclass g_number_jc = 0;
541449Stomee jmethodID g_shortval_jm = 0;
551449Stomee jmethodID g_intval_jm = 0;
561449Stomee jmethodID g_longval_jm = 0;
571449Stomee 
581449Stomee /* java.lang.Byte */
591449Stomee jclass g_byte_jc = 0;
601449Stomee jmethodID g_byteinit_jm = 0;
611449Stomee 
621449Stomee /* java.lang.Character */
631449Stomee jclass g_char_jc = 0;
641449Stomee jmethodID g_charinit_jm = 0;
651449Stomee jmethodID g_charval_jm = 0;
661449Stomee 
671449Stomee /* java.lang.Short */
681449Stomee jclass g_short_jc = 0;
691449Stomee jmethodID g_shortinit_jm = 0;
701449Stomee 
711449Stomee /* java.lang.Integer */
721449Stomee jclass g_int_jc = 0;
731449Stomee jmethodID g_intinit_jm = 0;
741449Stomee 
751449Stomee /* java.lang.Long */
761449Stomee jclass g_long_jc = 0;
771449Stomee jmethodID g_longinit_jm = 0;
781449Stomee 
791449Stomee /* java.lang.String */
801449Stomee jclass g_string_jc = 0;
811449Stomee jmethodID g_strinit_bytes_jm = 0;
821449Stomee jmethodID g_strbytes_jm = 0;
831449Stomee jmethodID g_trim_jm = 0;
841449Stomee 
851449Stomee /* java.lang.StringBuffer */
861449Stomee jclass g_buf_jc = 0;
871449Stomee jmethodID g_bufinit_jm = 0;
881449Stomee jmethodID g_buf_append_char_jm = 0;
891449Stomee jmethodID g_buf_append_int_jm = 0;
901449Stomee jmethodID g_buf_append_long_jm = 0;
911449Stomee jmethodID g_buf_append_str_jm = 0;
921449Stomee jmethodID g_buf_append_obj_jm = 0;
931449Stomee jmethodID g_buflen_jm = 0;
941449Stomee jmethodID g_bufsetlen_jm = 0;
951449Stomee 
961449Stomee /* java.lang.Object */
971449Stomee jclass g_object_jc = 0;
981449Stomee jmethodID g_tostring_jm = 0;
991449Stomee jmethodID g_equals_jm = 0;
1001449Stomee 
1011449Stomee /* java.lang.Enum */
1021449Stomee jclass g_enum_jc = 0;
1031449Stomee jmethodID g_enumname_jm = 0;
1041449Stomee 
1051449Stomee /* List */
1061449Stomee jclass g_list_jc = 0;
1071449Stomee jmethodID g_listclear_jm = 0;
1081449Stomee jmethodID g_listadd_jm = 0;
1091449Stomee jmethodID g_listget_jm = 0;
1101449Stomee jmethodID g_listsize_jm = 0;
1111449Stomee 
1121449Stomee /* Global list pools */
1131449Stomee static uu_list_pool_t *g_pointer_pool = NULL;
1141449Stomee static uu_list_pool_t *g_string_pool = NULL;
1151449Stomee 
1161449Stomee static dtj_status_t dtj_get_jni_classes(JNIEnv *, uu_list_t *, uu_list_pool_t *,
1171449Stomee     uu_list_pool_t *, uu_list_pool_t *, const dtj_table_entry_t *);
1181449Stomee static dtj_status_t dtj_cache_jni_methods(JNIEnv *, dtj_java_class_t *);
1191449Stomee static dtj_status_t dtj_cache_jni_fields(JNIEnv *, dtj_java_class_t *);
1201449Stomee 
1211449Stomee /* Constructors */
1221449Stomee static dtj_java_class_t *dtj_java_class_create(JNIEnv *, jclass *, char *,
1231449Stomee     uu_list_pool_t *, uu_list_pool_t *, uu_list_pool_t *);
1241449Stomee static dtj_java_method_t *dtj_java_method_create(JNIEnv *, jmethodID *, char *,
1251449Stomee     char *, uu_list_pool_t *);
1261449Stomee static dtj_java_method_t *dtj_java_static_method_create(JNIEnv *, jmethodID *,
1271449Stomee     char *, char *, uu_list_pool_t *);
1281449Stomee static dtj_java_field_t *dtj_java_field_create(JNIEnv *, jfieldID *, char *,
1291449Stomee     char *, uu_list_pool_t *);
1301449Stomee static dtj_java_field_t *dtj_java_static_field_create(JNIEnv *, jfieldID *,
1311449Stomee     char *, char *, uu_list_pool_t *);
1321449Stomee 
1331449Stomee /* Destructors */
1341449Stomee static void dtj_java_class_destroy(void *, void *);
1351449Stomee static void dtj_java_method_destroy(void *, void *);
1361449Stomee static void dtj_java_field_destroy(void *, void *);
1371449Stomee 
1381449Stomee /* Comparison functions, uu_compare_fn_t signature */
1391449Stomee static int dtj_java_class_cmp(const void *, const void *, void *);
1401449Stomee static int dtj_java_method_cmp(const void *, const void *, void *);
1411449Stomee static int dtj_java_field_cmp(const void *, const void *, void *);
1421449Stomee 
1431449Stomee /* Java Throwable */
1441449Stomee static void dtj_throw(JNIEnv *, jclass, const char *, va_list *);
1451449Stomee 
1461449Stomee /* Support for uu_list_t wrappers */
1471449Stomee static boolean_t dtj_check_pointer_pool(void);
1481449Stomee static boolean_t dtj_check_string_pool(void);
1491449Stomee 
1501449Stomee dtj_status_t
1511449Stomee dtj_load_common(JNIEnv *jenv)
1521449Stomee {
1531449Stomee 	dtj_status_t status;
1541449Stomee 
1551449Stomee 	static const dtj_table_entry_t table[] = {
1561449Stomee 		/* NativeException */
1571449Stomee 		{ JCLASS,  &g_nx_jc,
1581449Stomee 			"org/opensolaris/os/dtrace/NativeException" },
1591449Stomee 		{ JMETHOD, &g_nxinit_jm, CONSTRUCTOR,
1601449Stomee 			"(Ljava/lang/String;ILjava/lang/Throwable;)V" },
1611449Stomee 
1621449Stomee 		/* java.io.Serializable */
1631449Stomee 		{ JCLASS,  &g_serial_jc, "java/io/Serializable" },
1641449Stomee 
1651449Stomee 		/* java.lang.Number */
1661449Stomee 		{ JCLASS,  &g_number_jc, "java/lang/Number" },
1671449Stomee 		{ JMETHOD, &g_shortval_jm, "shortValue", "()S" },
1681449Stomee 		{ JMETHOD, &g_intval_jm, "intValue", "()I" },
1691449Stomee 		{ JMETHOD, &g_longval_jm, "longValue", "()J" },
1701449Stomee 
1711449Stomee 		/* java.lang.Byte */
1721449Stomee 		{ JCLASS,  &g_byte_jc, "java/lang/Byte" },
1731449Stomee 		{ JMETHOD, &g_byteinit_jm, CONSTRUCTOR, "(B)V" },
1741449Stomee 
1751449Stomee 		/* java.lang.Character */
1761449Stomee 		{ JCLASS,  &g_char_jc, "java/lang/Character" },
1771449Stomee 		{ JMETHOD, &g_charinit_jm, CONSTRUCTOR, "(C)V" },
1781449Stomee 		{ JMETHOD, &g_charval_jm, "charValue", "()C" },
1791449Stomee 
1801449Stomee 		/* java.lang.Short */
1811449Stomee 		{ JCLASS,  &g_short_jc, "java/lang/Short" },
1821449Stomee 		{ JMETHOD, &g_shortinit_jm, CONSTRUCTOR, "(S)V" },
1831449Stomee 
1841449Stomee 		/* java.lang.Integer */
1851449Stomee 		{ JCLASS,  &g_int_jc, "java/lang/Integer" },
1861449Stomee 		{ JMETHOD, &g_intinit_jm, CONSTRUCTOR, "(I)V" },
1871449Stomee 
1881449Stomee 		/* java.lang.Long */
1891449Stomee 		{ JCLASS,  &g_long_jc, "java/lang/Long" },
1901449Stomee 		{ JMETHOD, &g_longinit_jm, CONSTRUCTOR, "(J)V" },
1911449Stomee 
1921449Stomee 		/* java.lang.String */
1931449Stomee 		{ JCLASS,  &g_string_jc, "java/lang/String" },
1941449Stomee 		{ JMETHOD, &g_strinit_bytes_jm, CONSTRUCTOR, "([B)V" },
1951449Stomee 		{ JMETHOD, &g_strbytes_jm, "getBytes", "()[B" },
1961449Stomee 		{ JMETHOD, &g_trim_jm, "trim", "()Ljava/lang/String;" },
1971449Stomee 
1981449Stomee 		/* java.lang.StringBuffer */
1991449Stomee 		{ JCLASS,  &g_buf_jc, "java/lang/StringBuffer" },
2001449Stomee 		{ JMETHOD, &g_bufinit_jm, CONSTRUCTOR, "()V" },
2011449Stomee 		{ JMETHOD, &g_buf_append_char_jm, "append",
2021449Stomee 			"(C)Ljava/lang/StringBuffer;" },
2031449Stomee 		{ JMETHOD, &g_buf_append_int_jm, "append",
2041449Stomee 			"(I)Ljava/lang/StringBuffer;" },
2051449Stomee 		{ JMETHOD, &g_buf_append_long_jm, "append",
2061449Stomee 			"(J)Ljava/lang/StringBuffer;" },
2071449Stomee 		{ JMETHOD, &g_buf_append_str_jm, "append",
2081449Stomee 			"(Ljava/lang/String;)Ljava/lang/StringBuffer;" },
2091449Stomee 		{ JMETHOD, &g_buf_append_obj_jm, "append",
2101449Stomee 			"(Ljava/lang/Object;)Ljava/lang/StringBuffer;" },
2111449Stomee 		{ JMETHOD, &g_buflen_jm, "length", "()I" },
2121449Stomee 		{ JMETHOD, &g_bufsetlen_jm, "setLength", "(I)V" },
2131449Stomee 
2141449Stomee 		/* java.lang.Object */
2151449Stomee 		{ JCLASS,  &g_object_jc, "java/lang/Object" },
2161449Stomee 		{ JMETHOD, &g_tostring_jm, "toString",
2171449Stomee 			"()Ljava/lang/String;" },
2181449Stomee 		{ JMETHOD, &g_equals_jm, "equals",
2191449Stomee 			"(Ljava/lang/Object;)Z" },
2201449Stomee 
2211449Stomee 		/* java.lang.Enum */
2221449Stomee 		{ JCLASS,  &g_enum_jc, "java/lang/Enum" },
2231449Stomee 		{ JMETHOD, &g_enumname_jm, "name",
2241449Stomee 			"()Ljava/lang/String;" },
2251449Stomee 
2261449Stomee 		/* List */
2271449Stomee 		{ JCLASS, &g_list_jc, "java/util/List" },
2281449Stomee 		{ JMETHOD, &g_listclear_jm, "clear", "()V" },
2291449Stomee 		{ JMETHOD, &g_listadd_jm, "add", "(Ljava/lang/Object;)Z" },
2301449Stomee 		{ JMETHOD, &g_listget_jm, "get", "(I)Ljava/lang/Object;" },
2311449Stomee 		{ JMETHOD, &g_listsize_jm, "size", "()I" },
2321449Stomee 
2331449Stomee 		{ DTJ_TYPE_END }
2341449Stomee 	};
2351449Stomee 
2361449Stomee 	status = dtj_cache_jni_classes(jenv, table);
2371449Stomee 	if (status == DTJ_OK) {
2381449Stomee 		g_dtj_load_common = B_TRUE;
2391449Stomee 	}
2401449Stomee 	return (status);
2411449Stomee }
2421449Stomee 
2431449Stomee static int
2441449Stomee /* ARGSUSED */
2451449Stomee dtj_java_class_cmp(const void * v1, const void * v2, void *arg)
2461449Stomee {
2471449Stomee 	const dtj_java_class_t *c1 = v1;
2481449Stomee 	const dtj_java_class_t *c2 = v2;
2491449Stomee 	return (strcmp(c1->djc_name, c2->djc_name));
2501449Stomee }
2511449Stomee 
2521449Stomee static int
2531449Stomee /* ARGSUSED */
2541449Stomee dtj_java_method_cmp(const void *v1, const void *v2, void *arg)
2551449Stomee {
2561449Stomee 	int cmp;
2571449Stomee 	const dtj_java_method_t *m1 = v1;
2581449Stomee 	const dtj_java_method_t *m2 = v2;
2591449Stomee 	cmp = strcmp(m1->djm_name, m2->djm_name);
2601449Stomee 	if (cmp == 0) {
2611449Stomee 		cmp = strcmp(m1->djm_signature, m2->djm_signature);
2621449Stomee 	}
2631449Stomee 	return (cmp);
2641449Stomee }
2651449Stomee 
2661449Stomee static int
2671449Stomee /* ARGSUSED */
2681449Stomee dtj_java_field_cmp(const void *v1, const void *v2, void *arg)
2691449Stomee {
2701449Stomee 	const dtj_java_field_t *f1 = v1;
2711449Stomee 	const dtj_java_field_t *f2 = v2;
2721449Stomee 	return (strcmp(f1->djf_name, f2->djf_name));
2731449Stomee }
2741449Stomee 
2751449Stomee static dtj_java_class_t *
2761449Stomee dtj_java_class_create(JNIEnv *jenv, jclass *jc, char *name,
2771449Stomee     uu_list_pool_t *classpool, uu_list_pool_t *methodpool,
2781449Stomee     uu_list_pool_t *fieldpool)
2791449Stomee {
2801449Stomee 	dtj_java_class_t *c = uu_zalloc(sizeof (dtj_java_class_t));
2811449Stomee 	if (c) {
2821449Stomee 		uu_list_node_init(c, &c->djc_node, classpool);
2831449Stomee 		c->djc_ptr = jc;
2841449Stomee 		c->djc_name = name;
2851449Stomee 		c->djc_methods = uu_list_create(methodpool, NULL,
2861449Stomee 		    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
2871449Stomee 		if (!c->djc_methods) {
2881449Stomee 			dtj_throw_out_of_memory(jenv,
2891449Stomee 			    "Failed method list creation");
2901449Stomee 			uu_list_node_fini(c, &c->djc_node, classpool);
2911449Stomee 			free(c);
2921449Stomee 			c = NULL;
2931449Stomee 		}
2941449Stomee 		c->djc_fields = uu_list_create(fieldpool, NULL,
2951449Stomee 		    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
2961449Stomee 		if (!c->djc_fields) {
2971449Stomee 			dtj_throw_out_of_memory(jenv,
2981449Stomee 			    "Failed field list creation");
2991449Stomee 			uu_list_destroy(c->djc_methods);
3001449Stomee 			c->djc_methods = NULL;
3011449Stomee 			uu_list_node_fini(c, &c->djc_node, classpool);
3021449Stomee 			free(c);
3031449Stomee 			c = NULL;
3041449Stomee 		}
3051449Stomee 	} else {
3061449Stomee 		dtj_throw_out_of_memory(jenv,
3071449Stomee 		    "Failed to allocate class description");
3081449Stomee 	}
3091449Stomee 	return (c);
3101449Stomee }
3111449Stomee 
3121449Stomee static dtj_java_method_t *
3131449Stomee dtj_java_method_create(JNIEnv *jenv, jmethodID *jm, char *name, char *signature,
3141449Stomee     uu_list_pool_t *methodpool)
3151449Stomee {
3161449Stomee 	dtj_java_method_t *m = uu_zalloc(sizeof (dtj_java_method_t));
3171449Stomee 	if (m) {
3181449Stomee 		uu_list_node_init(m, &m->djm_node, methodpool);
3191449Stomee 		m->djm_ptr = jm;
3201449Stomee 		m->djm_name = name;
3211449Stomee 		m->djm_signature = signature;
3221449Stomee 		m->djm_static = B_FALSE;
3231449Stomee 	} else {
3241449Stomee 		dtj_throw_out_of_memory(jenv,
3251449Stomee 		    "Failed to allocate method description");
3261449Stomee 	}
3271449Stomee 	return (m);
3281449Stomee }
3291449Stomee 
3301449Stomee static dtj_java_method_t *
3311449Stomee dtj_java_static_method_create(JNIEnv *jenv, jmethodID *jm, char *name,
3321449Stomee     char *signature, uu_list_pool_t *methodpool)
3331449Stomee {
3341449Stomee 	dtj_java_method_t *m = dtj_java_method_create(jenv, jm, name, signature,
3351449Stomee 	    methodpool);
3361449Stomee 	if (m) {
3371449Stomee 		m->djm_static = B_TRUE;
3381449Stomee 	}
3391449Stomee 	return (m);
3401449Stomee }
3411449Stomee 
3421449Stomee static dtj_java_field_t *
3431449Stomee dtj_java_field_create(JNIEnv *jenv, jfieldID *jf, char *name, char *type,
3441449Stomee     uu_list_pool_t *fieldpool)
3451449Stomee {
3461449Stomee 	dtj_java_field_t *f = uu_zalloc(sizeof (dtj_java_field_t));
3471449Stomee 	if (f) {
3481449Stomee 		uu_list_node_init(f, &f->djf_node, fieldpool);
3491449Stomee 		f->djf_ptr = jf;
3501449Stomee 		f->djf_name = name;
3511449Stomee 		f->djf_type = type;
3521449Stomee 		f->djf_static = B_FALSE;
3531449Stomee 	} else {
3541449Stomee 		dtj_throw_out_of_memory(jenv,
3551449Stomee 		    "Failed to allocate field description");
3561449Stomee 	}
3571449Stomee 	return (f);
3581449Stomee }
3591449Stomee 
3601449Stomee static dtj_java_field_t *
3611449Stomee dtj_java_static_field_create(JNIEnv *jenv, jfieldID *jf, char *name, char *type,
3621449Stomee     uu_list_pool_t *fieldpool)
3631449Stomee {
3641449Stomee 	dtj_java_field_t *f = dtj_java_field_create(jenv, jf, name, type,
3651449Stomee 	    fieldpool);
3661449Stomee 	if (f) {
3671449Stomee 		f->djf_static = B_TRUE;
3681449Stomee 	}
3691449Stomee 	return (f);
3701449Stomee }
3711449Stomee 
3721449Stomee static void
3731449Stomee /* ARGSUSED */
3741449Stomee dtj_java_class_destroy(void *v, void *arg)
3751449Stomee {
3761449Stomee 	if (v) {
3771449Stomee 		dtj_java_class_t *c = v;
3781449Stomee 		c->djc_ptr = NULL;  /* do not free user-defined storage */
3791449Stomee 		c->djc_name = NULL; /* string literal */
3801449Stomee 		dtj_list_destroy(c->djc_methods, dtj_java_method_destroy, NULL);
3811449Stomee 		dtj_list_destroy(c->djc_fields, dtj_java_field_destroy, NULL);
3821449Stomee 		c->djc_methods = NULL;
3831449Stomee 		c->djc_fields = NULL;
3841449Stomee 		uu_free(v);
3851449Stomee 	}
3861449Stomee }
3871449Stomee 
3881449Stomee static void
3891449Stomee /* ARGSUSED */
3901449Stomee dtj_java_method_destroy(void *v, void *arg)
3911449Stomee {
3921449Stomee 	if (v) {
3931449Stomee 		dtj_java_method_t *m = v;
3941449Stomee 		m->djm_ptr = NULL;	/* do not free user-defined space */
3951449Stomee 		m->djm_name = NULL;	/* string literal */
3961449Stomee 		m->djm_signature = NULL;	/* string literal */
3971449Stomee 		uu_free(v);
3981449Stomee 	}
3991449Stomee }
4001449Stomee 
4011449Stomee static void
4021449Stomee /* ARGSUSED */
4031449Stomee dtj_java_field_destroy(void *v, void *arg)
4041449Stomee {
4051449Stomee 	if (v) {
4061449Stomee 		dtj_java_field_t *f = v;
4071449Stomee 		f->djf_ptr = NULL;  /* do not free user-defined space */
4081449Stomee 		f->djf_name = NULL; /* string literal */
4091449Stomee 		f->djf_type = NULL; /* string literal */
4101449Stomee 		uu_free(f);
4111449Stomee 	}
4121449Stomee }
4131449Stomee 
4141449Stomee dtj_status_t
4151449Stomee dtj_cache_jni_classes(JNIEnv *jenv, const dtj_table_entry_t *table)
4161449Stomee {
4171449Stomee 	dtj_java_class_t *class;
4181449Stomee 	uu_list_pool_t *classpool;
4191449Stomee 	uu_list_pool_t *methodpool;
4201449Stomee 	uu_list_pool_t *fieldpool;
4211449Stomee 	uu_list_t *classes;
4221449Stomee 	uu_list_walk_t *itr;
4231449Stomee 	jclass jc;
4241449Stomee 	jclass gjc;
4251449Stomee 	dtj_status_t status;
4261449Stomee 
4271449Stomee 	classpool = uu_list_pool_create("classpool",
4281449Stomee 	    sizeof (dtj_java_class_t),
4291449Stomee 	    offsetof(dtj_java_class_t, djc_node), dtj_java_class_cmp,
4301449Stomee 	    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
4311449Stomee 	if (!classpool) {
4321449Stomee 		dtj_throw_out_of_memory(jenv, "failed class pool creation");
4331449Stomee 		return (DTJ_ERR);
4341449Stomee 	}
4351449Stomee 	methodpool = uu_list_pool_create("methodpool",
4361449Stomee 	    sizeof (dtj_java_method_t),
4371449Stomee 	    offsetof(dtj_java_method_t, djm_node), dtj_java_method_cmp,
4381449Stomee 	    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
4391449Stomee 	if (!methodpool) {
4401449Stomee 		dtj_throw_out_of_memory(jenv, "failed method pool creation");
4411449Stomee 		return (DTJ_ERR);
4421449Stomee 	}
4431449Stomee 	fieldpool = uu_list_pool_create("fieldpool",
4441449Stomee 	    sizeof (dtj_java_field_t),
4451449Stomee 	    offsetof(dtj_java_field_t, djf_node), dtj_java_field_cmp,
4461449Stomee 	    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
4471449Stomee 	if (!fieldpool) {
4481449Stomee 		dtj_throw_out_of_memory(jenv, "failed field pool creation");
4491449Stomee 		return (DTJ_ERR);
4501449Stomee 	}
4511449Stomee 
4521449Stomee 	classes = uu_list_create(classpool, NULL,
4531449Stomee 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
4541449Stomee 	if (!classes) {
4551449Stomee 		dtj_throw_out_of_memory(jenv, "failed class list creation");
4561449Stomee 		return (DTJ_ERR);
4571449Stomee 	}
4581449Stomee 
4591449Stomee 	status = dtj_get_jni_classes(jenv, classes, classpool, methodpool,
4601449Stomee 	    fieldpool, table);
4611449Stomee 	if (status != DTJ_OK) {
4621449Stomee 		/* java error pending */
4631449Stomee 		return (status);
4641449Stomee 	}
4651449Stomee 
4661449Stomee 	itr = uu_list_walk_start(classes, 0);
4671449Stomee 	while ((class = uu_list_walk_next(itr)) != NULL) {
4681449Stomee 		jc = (*jenv)->FindClass(jenv, class->djc_name);
4691449Stomee 		if (!jc) {
4701449Stomee 			/* NoClassDefFoundError pending */
4711449Stomee 			return (DTJ_ERR);
4721449Stomee 		}
4731449Stomee 		gjc = (*jenv)->NewGlobalRef(jenv, jc);
4741449Stomee 		(*jenv)->DeleteLocalRef(jenv, jc);
4751449Stomee 		if (!gjc) {
4761449Stomee 			dtj_throw_out_of_memory(jenv,
4771449Stomee 			    "Failed to create global class reference");
4781449Stomee 			return (DTJ_ERR);
4791449Stomee 		}
4801449Stomee 		*(class->djc_ptr) = gjc;
4811449Stomee 		status = dtj_cache_jni_methods(jenv, class);
4821449Stomee 		if (status != DTJ_OK) {
4831449Stomee 			/* java error pending */
4841449Stomee 			return (status);
4851449Stomee 		}
4861449Stomee 		status = dtj_cache_jni_fields(jenv, class);
4871449Stomee 		if (status != DTJ_OK) {
4881449Stomee 			/* java error pending */
4891449Stomee 			return (status);
4901449Stomee 		}
4911449Stomee 	}
4921449Stomee 	uu_list_walk_end(itr);
4931449Stomee 	dtj_list_destroy(classes, dtj_java_class_destroy, NULL);
4941449Stomee 	uu_list_pool_destroy(classpool);
4951449Stomee 	uu_list_pool_destroy(methodpool);
4961449Stomee 	uu_list_pool_destroy(fieldpool);
4971449Stomee 	return (DTJ_OK);
4981449Stomee }
4991449Stomee 
5001449Stomee /*
5011449Stomee  * Converts JNI table entry desriptions into java_class_t descriptors.
5021449Stomee  */
5031449Stomee static dtj_status_t
5041449Stomee dtj_get_jni_classes(JNIEnv *jenv, uu_list_t *classes,
5051449Stomee     uu_list_pool_t *classpool, uu_list_pool_t *methodpool,
5061449Stomee     uu_list_pool_t *fieldpool, const dtj_table_entry_t *table)
5071449Stomee {
5081449Stomee 	int i;
5091449Stomee 	dtj_java_class_t *c = NULL;
5101449Stomee 	dtj_java_method_t *m;
5111449Stomee 	dtj_java_field_t *f;
5121449Stomee 
5131449Stomee 	for (i = 0; table[i].djte_type != DTJ_TYPE_END; ++i) {
5141449Stomee 		/*
5151449Stomee 		 * Class not added until all of its method and field information
5161449Stomee 		 * is attached, so we defer adding a class until the next
5171449Stomee 		 * element with type JCLASS.
5181449Stomee 		 */
5191449Stomee 		switch (table[i].djte_type) {
5201449Stomee 		case JCLASS:
5211449Stomee 			if (c) {
5221449Stomee 				/* previous class */
5231449Stomee 				if (!dtj_list_add(classes, c)) {
5241449Stomee 					dtj_throw_out_of_memory(jenv,
5251449Stomee 					    "Failed to add class description");
5261449Stomee 					/*
5271449Stomee 					 * In response to an error return value,
5281449Stomee 					 * the caller will delete the class
5291449Stomee 					 * descriptions list with any
5301449Stomee 					 * descriptions created so far.
5311449Stomee 					 */
5321449Stomee 					return (DTJ_ERR);
5331449Stomee 				}
5341449Stomee 			}
5351449Stomee 			c = dtj_java_class_create(jenv,
5361449Stomee 			    (jclass *)table[i].djte_addr, table[i].djte_name,
5371449Stomee 			    classpool, methodpool, fieldpool);
5381449Stomee 			if (!c) {
5391449Stomee 				/* OutOfMemoryError pending */
5401449Stomee 				return (DTJ_ERR);
5411449Stomee 			}
5421449Stomee 			break;
5431449Stomee 		case JMETHOD:
5441449Stomee 			if (!c) {
5451449Stomee 				dtj_throw_illegal_state(jenv,
5461449Stomee 				    "method description not preceded "
5471449Stomee 				    "by class description");
5481449Stomee 				return (DTJ_ERR);
5491449Stomee 			}
5501449Stomee 			m = dtj_java_method_create(jenv,
5511449Stomee 			    (jmethodID *)table[i].djte_addr,
5521449Stomee 			    table[i].djte_name, table[i].djte_desc,
5531449Stomee 			    methodpool);
5541449Stomee 			if (!m) {
5551449Stomee 				/* OutOfMemoryError pending */
5561449Stomee 				return (DTJ_ERR);
5571449Stomee 			}
5581449Stomee 			if (!dtj_list_add(c->djc_methods, m)) {
5591449Stomee 				dtj_throw_out_of_memory(jenv,
5601449Stomee 				    "Failed to add method description");
5611449Stomee 				return (DTJ_ERR);
5621449Stomee 			}
5631449Stomee 			break;
5641449Stomee 		case JMETHOD_STATIC:
5651449Stomee 			if (!c) {
5661449Stomee 				dtj_throw_illegal_state(jenv,
5671449Stomee 				    "static method description not preceded "
5681449Stomee 				    "by class description");
5691449Stomee 				return (DTJ_ERR);
5701449Stomee 			}
5711449Stomee 			m = dtj_java_static_method_create(jenv,
5721449Stomee 			    (jmethodID *)table[i].djte_addr,
5731449Stomee 			    table[i].djte_name, table[i].djte_desc,
5741449Stomee 			    methodpool);
5751449Stomee 			if (!m) {
5761449Stomee 				/* OutOfMemoryError pending */
5771449Stomee 				return (DTJ_ERR);
5781449Stomee 			}
5791449Stomee 			if (!dtj_list_add(c->djc_methods, m)) {
5801449Stomee 				dtj_throw_out_of_memory(jenv,
5811449Stomee 				    "Failed to add static method description");
5821449Stomee 				return (DTJ_ERR);
5831449Stomee 			}
5841449Stomee 			break;
5851449Stomee 		case JFIELD:
5861449Stomee 			if (!c) {
5871449Stomee 				dtj_throw_illegal_state(jenv,
5881449Stomee 				    "field description not preceded "
5891449Stomee 				    "by class description");
5901449Stomee 				return (DTJ_ERR);
5911449Stomee 			}
5921449Stomee 			f = dtj_java_field_create(jenv,
5931449Stomee 			    (jfieldID *)table[i].djte_addr,
5941449Stomee 			    table[i].djte_name, table[i].djte_desc,
5951449Stomee 			    fieldpool);
5961449Stomee 			if (!f) {
5971449Stomee 				/* OutOfMemoryError pending */
5981449Stomee 				return (DTJ_ERR);
5991449Stomee 			}
6001449Stomee 			if (!dtj_list_add(c->djc_fields, f)) {
6011449Stomee 				dtj_throw_out_of_memory(jenv,
6021449Stomee 				    "Failed to add field description");
6031449Stomee 				return (DTJ_ERR);
6041449Stomee 			}
6051449Stomee 			break;
6061449Stomee 		case JFIELD_STATIC:
6071449Stomee 			if (!c) {
6081449Stomee 				dtj_throw_illegal_state(jenv,
6091449Stomee 				    "static field description not preceded "
6101449Stomee 				    "by class description");
6111449Stomee 				return (DTJ_ERR);
6121449Stomee 			}
6131449Stomee 			f = dtj_java_static_field_create(jenv,
6141449Stomee 			    (jfieldID *)table[i].djte_addr,
6151449Stomee 			    table[i].djte_name, table[i].djte_desc,
6161449Stomee 			    fieldpool);
6171449Stomee 			if (!f) {
6181449Stomee 				/* OutOfMemoryError pending */
6191449Stomee 				return (DTJ_ERR);
6201449Stomee 			}
6211449Stomee 			if (!dtj_list_add(c->djc_fields, f)) {
6221449Stomee 				dtj_throw_out_of_memory(jenv,
6231449Stomee 				    "Failed to add static field description");
6241449Stomee 				return (DTJ_ERR);
6251449Stomee 			}
6261449Stomee 			break;
6271449Stomee 		default:
6281449Stomee 			dtj_throw_illegal_state(jenv,
6291449Stomee 			    "Unexpected jni_type_e: %d", table[i].djte_type);
6301449Stomee 			return (DTJ_ERR);
6311449Stomee 		}
6321449Stomee 	}
6331449Stomee 	if (c) {
6341449Stomee 		/* last class */
6351449Stomee 		if (!dtj_list_add(classes, c)) {
6361449Stomee 			dtj_throw_out_of_memory(jenv,
6371449Stomee 			    "Failed to add class description");
6381449Stomee 			return (DTJ_ERR);
6391449Stomee 		}
6401449Stomee 	}
6411449Stomee 
6421449Stomee 	return (DTJ_OK);
6431449Stomee }
6441449Stomee 
6451449Stomee static dtj_status_t
6461449Stomee dtj_cache_jni_methods(JNIEnv *jenv, dtj_java_class_t *c)
6471449Stomee {
6481449Stomee 	dtj_java_method_t *method;
6491449Stomee 	jmethodID jm;
6501449Stomee 	uu_list_walk_t *itr;
6511449Stomee 	itr = uu_list_walk_start(c->djc_methods, 0);
6521449Stomee 	while ((method = uu_list_walk_next(itr)) != NULL) {
6531449Stomee 		if (method->djm_static) {
6541449Stomee 			jm = (*jenv)->GetStaticMethodID(jenv, *(c->djc_ptr),
6551449Stomee 			    method->djm_name, method->djm_signature);
6561449Stomee 		} else {
6571449Stomee 			jm = (*jenv)->GetMethodID(jenv, *(c->djc_ptr),
6581449Stomee 			    method->djm_name, method->djm_signature);
6591449Stomee 		}
6601449Stomee 		if (jm == 0) {
6611449Stomee 			/*
6621449Stomee 			 * The pending NoSuchMethodError gives only the
6631449Stomee 			 * method name, which is not so helpful for
6641449Stomee 			 * overloaded methods and methods such as <init>
6651449Stomee 			 * that have the same name in multiple classes.
6661449Stomee 			 * Clear the pending error and throw one that
6671449Stomee 			 * includes the class name and the method
6681449Stomee 			 * signature.
6691449Stomee 			 */
6701449Stomee 			jclass jc;
6711449Stomee 			char msg[DTJ_MSG_SIZE];
6721449Stomee 			(*jenv)->ExceptionClear(jenv);
6731449Stomee 			(void) snprintf(msg, sizeof (msg), "%s %s %s",
6741449Stomee 			    c->djc_name, method->djm_name,
6751449Stomee 			    method->djm_signature);
6761449Stomee 
6771449Stomee 			jc = (*jenv)->FindClass(jenv,
6781449Stomee 			    "java/lang/NoSuchMethodError");
6791449Stomee 			(*jenv)->ThrowNew(jenv, jc, msg);
6801449Stomee 			(*jenv)->DeleteLocalRef(jenv, jc);
6811449Stomee 			return (DTJ_ERR);
6821449Stomee 		}
6831449Stomee 		*(method->djm_ptr) = jm;
6841449Stomee 	}
6851449Stomee 	uu_list_walk_end(itr);
6861449Stomee 	return (DTJ_OK);
6871449Stomee }
6881449Stomee 
6891449Stomee static dtj_status_t
6901449Stomee dtj_cache_jni_fields(JNIEnv *jenv, dtj_java_class_t *c)
6911449Stomee {
6921449Stomee 	dtj_java_field_t *field;
6931449Stomee 	jfieldID jf;
6941449Stomee 	uu_list_walk_t *itr;
6951449Stomee 	itr = uu_list_walk_start(c->djc_fields, 0);
6961449Stomee 	while ((field = uu_list_walk_next(itr)) != NULL) {
6971449Stomee 		if (field->djf_static) {
6981449Stomee 			jf = (*jenv)->GetStaticFieldID(jenv, *(c->djc_ptr),
6991449Stomee 			    field->djf_name, field->djf_type);
7001449Stomee 		} else {
7011449Stomee 			jf = (*jenv)->GetFieldID(jenv, *(c->djc_ptr),
7021449Stomee 			    field->djf_name, field->djf_type);
7031449Stomee 		}
7041449Stomee 		if (jf == 0) {
7051449Stomee 			jclass jc;
7061449Stomee 			char msg[DTJ_MSG_SIZE];
7071449Stomee 			(*jenv)->ExceptionClear(jenv);
7081449Stomee 			(void) snprintf(msg, sizeof (msg),
7091449Stomee 			    "%s.%s signature: %s", c->djc_name,
7101449Stomee 			    field->djf_name, field->djf_type);
7111449Stomee 
7121449Stomee 			jc = (*jenv)->FindClass(jenv,
7131449Stomee 			    "java/lang/NoSuchFieldError");
7141449Stomee 			(*jenv)->ThrowNew(jenv, jc, msg);
7151449Stomee 			(*jenv)->DeleteLocalRef(jenv, jc);
7161449Stomee 			return (DTJ_ERR);
7171449Stomee 		}
7181449Stomee 		*(field->djf_ptr) = jf;
7191449Stomee 	}
7201449Stomee 	uu_list_walk_end(itr);
7211449Stomee 	return (DTJ_OK);
7221449Stomee }
7231449Stomee 
7241449Stomee 
7251449Stomee /* Common utilities */
7261449Stomee 
7271449Stomee static void
7281449Stomee dtj_throw(JNIEnv *jenv, jclass jc, const char *fmt, va_list *ap)
7291449Stomee {
7301449Stomee 	char msg[DTJ_MSG_SIZE];
7311449Stomee 	(void) vsnprintf(msg, sizeof (msg), fmt, *ap);
7321449Stomee 	(*jenv)->ThrowNew(jenv, jc, msg);
7331449Stomee }
7341449Stomee 
7351449Stomee void
7361449Stomee dtj_throw_out_of_memory(JNIEnv *jenv, const char *fmt, ...)
7371449Stomee {
7381449Stomee 	va_list ap;
7391449Stomee 	jclass jc;
7401449Stomee 	/*
7411449Stomee 	 * JNI documentation unclear whether NewGlobalRef() can throw
7421449Stomee 	 * OutOfMemoryError, so we'll make this function safe in case
7431449Stomee 	 * OutOfMemoryError has already been thrown
7441449Stomee 	 */
7451449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
7461449Stomee 		return;
7471449Stomee 	}
7481449Stomee 	jc = (*jenv)->FindClass(jenv,
7491449Stomee 	    "java/lang/OutOfMemoryError");
7501449Stomee 	va_start(ap, fmt);
7511449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
7521449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
7531449Stomee 	va_end(ap);
7541449Stomee }
7551449Stomee 
7561449Stomee void
7571449Stomee dtj_throw_null_pointer(JNIEnv *jenv, const char *fmt, ...)
7581449Stomee {
7591449Stomee 	va_list ap;
7601449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
7611449Stomee 	    "java/lang/NullPointerException");
7621449Stomee 	va_start(ap, fmt);
7631449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
7641449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
7651449Stomee 	va_end(ap);
7661449Stomee }
7671449Stomee 
7681449Stomee void
7691449Stomee dtj_throw_illegal_state(JNIEnv *jenv, const char *fmt, ...)
7701449Stomee {
7711449Stomee 	va_list ap;
7721449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
7731449Stomee 	    "java/lang/IllegalStateException");
7741449Stomee 	va_start(ap, fmt);
7751449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
7761449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
7771449Stomee 	va_end(ap);
7781449Stomee }
7791449Stomee 
7801449Stomee void
7811449Stomee dtj_throw_illegal_argument(JNIEnv *jenv, const char *fmt, ...)
7821449Stomee {
7831449Stomee 	va_list ap;
7841449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
7851449Stomee 	    "java/lang/IllegalArgumentException");
7861449Stomee 	va_start(ap, fmt);
7871449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
7881449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
7891449Stomee 	va_end(ap);
7901449Stomee }
7911449Stomee 
7921449Stomee void
7931449Stomee dtj_throw_no_such_element(JNIEnv *jenv, const char *fmt, ...)
7941449Stomee {
7951449Stomee 	va_list ap;
7961449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
7971449Stomee 	    "java/util/NoSuchElementException");
7981449Stomee 	va_start(ap, fmt);
7991449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
8001449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
8011449Stomee 	va_end(ap);
8021449Stomee }
8031449Stomee 
8041449Stomee void
8051449Stomee dtj_throw_class_cast(JNIEnv *jenv, const char *fmt, ...)
8061449Stomee {
8071449Stomee 	va_list ap;
8081449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
8091449Stomee 	    "java/lang/ClassCastException");
8101449Stomee 	va_start(ap, fmt);
8111449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
8121449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
8131449Stomee 	va_end(ap);
8141449Stomee }
8151449Stomee 
8161449Stomee void
8171449Stomee dtj_throw_assertion(JNIEnv *jenv, const char *fmt, ...)
8181449Stomee {
8191449Stomee 	va_list ap;
8201449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
8211449Stomee 	    "java/lang/AssertionError");
8221449Stomee 	va_start(ap, fmt);
8231449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
8241449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
8251449Stomee 	va_end(ap);
8261449Stomee }
8271449Stomee 
8281449Stomee void
8291449Stomee dtj_throw_resource_limit(JNIEnv *jenv, const char *fmt, ...)
8301449Stomee {
8311449Stomee 	va_list ap;
8321449Stomee 	jclass jc = (*jenv)->FindClass(jenv,
8331449Stomee 	    "org/opensolaris/os/dtrace/ResourceLimitException");
8341449Stomee 	va_start(ap, fmt);
8351449Stomee 	dtj_throw(jenv, jc, fmt, &ap);
8361449Stomee 	(*jenv)->DeleteLocalRef(jenv, jc);
8371449Stomee 	va_end(ap);
8381449Stomee }
8391449Stomee 
8401449Stomee void
8411449Stomee dtj_wrap_exception(JNIEnv *jenv, const char *file, int line)
8421449Stomee {
8431449Stomee 	jthrowable e = NULL;
8441449Stomee 	jthrowable nx = NULL;
8451449Stomee 	jstring jfile = NULL;
8461449Stomee 
8471449Stomee 	e = (*jenv)->ExceptionOccurred(jenv);
8481449Stomee 	if (!e) {
8491449Stomee 		return;
8501449Stomee 	}
8511449Stomee 
8521449Stomee 	if (!g_dtj_load_common) {
8531449Stomee 		return;
8541449Stomee 	}
8551449Stomee 
8561449Stomee 	(*jenv)->ExceptionClear(jenv);
8571449Stomee 
8581449Stomee 	/* Unsafe to test while exception pending */
8591449Stomee 	if ((*jenv)->IsInstanceOf(jenv, e, g_nx_jc)) {
8601449Stomee 		/* Already wrapped */
8611449Stomee 		(*jenv)->Throw(jenv, e);
8621449Stomee 		(*jenv)->DeleteLocalRef(jenv, e);
8631449Stomee 		return;
8641449Stomee 	}
8651449Stomee 
8661449Stomee 	jfile = dtj_NewStringNative(jenv, file);
8671449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
8681449Stomee 		/*
8691449Stomee 		 * Only wrap the exception if possible, otherwise just throw the
8701449Stomee 		 * original exception.
8711449Stomee 		 */
8721449Stomee 		(*jenv)->ExceptionClear(jenv);
8731449Stomee 		(*jenv)->Throw(jenv, e);
8741449Stomee 		(*jenv)->DeleteLocalRef(jenv, e);
8751449Stomee 		return;
8761449Stomee 	}
8771449Stomee 
8781449Stomee 	nx = (jthrowable)(*jenv)->NewObject(jenv, g_nx_jc, g_nxinit_jm,
8791449Stomee 	    jfile, line, e);
8801449Stomee 	(*jenv)->DeleteLocalRef(jenv, jfile);
8811449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
8821449Stomee 		(*jenv)->ExceptionClear(jenv);
8831449Stomee 		(*jenv)->Throw(jenv, e);
8841449Stomee 		(*jenv)->DeleteLocalRef(jenv, e);
8851449Stomee 		return;
8861449Stomee 	}
8871449Stomee 
8881449Stomee 	(*jenv)->DeleteLocalRef(jenv, e);
8891449Stomee 	(*jenv)->Throw(jenv, nx);
8901449Stomee 	(*jenv)->DeleteLocalRef(jenv, nx);
8911449Stomee }
8921449Stomee 
8931449Stomee /*
8941449Stomee  * Calls the given java object's toString() method and prints the value to
8951449Stomee  * stdout.  Useful for debugging.  Guaranteed that no exception is pending when
8961449Stomee  * this function returns.
8971449Stomee  */
8981449Stomee void
8991449Stomee dtj_print_object(JNIEnv *jenv, jobject jobj)
9001449Stomee {
9011449Stomee 	jstring jstr;
9021449Stomee 	const char *cstr;
9031449Stomee 
9041449Stomee 	if (!g_dtj_load_common) {
9051449Stomee 		dtj_throw_illegal_state(jenv,
9061449Stomee 		    "dtj_load_common() has not been called");
9071449Stomee 		(*jenv)->ExceptionDescribe(jenv); /* clears the exception */
9081449Stomee 		return;
9091449Stomee 	}
9101449Stomee 
9111449Stomee 	if (!jobj) {
9121449Stomee 		(void) printf("null\n");
9131449Stomee 		return;
9141449Stomee 	}
9151449Stomee 
9161449Stomee 	jstr = (*jenv)->CallObjectMethod(jenv, jobj, g_tostring_jm);
9171449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
9181449Stomee 		(*jenv)->ExceptionDescribe(jenv); /* clears the exception */
9191449Stomee 		return;
9201449Stomee 	}
9211449Stomee 	cstr = (*jenv)->GetStringUTFChars(jenv, jstr, 0);
9221449Stomee 	if (cstr) {
9231449Stomee 		(void) printf("%s\n", cstr);
9241449Stomee 	} else {
9251449Stomee 		(*jenv)->ExceptionDescribe(jenv); /* clears the exception */
9261449Stomee 		(*jenv)->DeleteLocalRef(jenv, jstr);
9271449Stomee 		return;
9281449Stomee 	}
9291449Stomee 	(*jenv)->ReleaseStringUTFChars(jenv, jstr, cstr);
9301449Stomee 	(*jenv)->DeleteLocalRef(jenv, jstr);
9311449Stomee }
9321449Stomee 
9331449Stomee jstring
9341449Stomee dtj_format_string(JNIEnv *jenv, const char *fmt, ...)
9351449Stomee {
9361449Stomee 	va_list ap;
9371449Stomee 	char str[DTJ_MSG_SIZE];
9381449Stomee 
9391449Stomee 	jstring jstr = NULL;
9401449Stomee 
9411449Stomee 	va_start(ap, fmt);
9421449Stomee 	(void) vsnprintf(str, sizeof (str), fmt, ap);
9431449Stomee 	va_end(ap);
9441449Stomee 
9451449Stomee 	jstr = dtj_NewStringNative(jenv, str);
9461449Stomee 	/* return NULL if OutOfMemoryError pending */
9471449Stomee 	return (jstr);
9481449Stomee }
9491449Stomee 
9501449Stomee jstring
9511449Stomee dtj_NewStringNative(JNIEnv *jenv, const char *str)
9521449Stomee {
9531449Stomee 	jstring result;
9541449Stomee 	jbyteArray bytes = 0;
9551449Stomee 	int len;
9561449Stomee 
9571449Stomee 	if (!g_dtj_load_common) {
9581449Stomee 		dtj_throw_illegal_state(jenv,
9591449Stomee 		    "dtj_load_common() has not been called");
9601449Stomee 		return (NULL);
9611449Stomee 	}
9621449Stomee 
9631449Stomee 	len = strlen(str);
9641449Stomee 
9651449Stomee 	bytes = (*jenv)->NewByteArray(jenv, len);
9661449Stomee 	if (!bytes) {
9671449Stomee 		return (NULL); /* OutOfMemoryError pending */
9681449Stomee 	}
9691449Stomee 	(*jenv)->SetByteArrayRegion(jenv, bytes, 0, len,
9701449Stomee 	    (jbyte *)str);
9711449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
9721449Stomee 		(*jenv)->DeleteLocalRef(jenv, bytes);
9731449Stomee 		return (NULL); /* ArrayIndexOutOfBoundsException pending */
9741449Stomee 	}
9751449Stomee 	result = (*jenv)->NewObject(jenv, g_string_jc, g_strinit_bytes_jm,
9761449Stomee 	    bytes);
9771449Stomee 	(*jenv)->DeleteLocalRef(jenv, bytes);
9781449Stomee 	/* return NULL result if exception pending */
9791449Stomee 	return (result);
9801449Stomee }
9811449Stomee 
9821449Stomee char *
9831449Stomee dtj_GetStringNativeChars(JNIEnv *jenv, jstring jstr)
9841449Stomee {
9851449Stomee 	jbyteArray bytes = NULL;
9861449Stomee 
9871449Stomee 	jint len;
9881449Stomee 	char *result = NULL;
9891449Stomee 
9901449Stomee 	if (!g_dtj_load_common) {
9911449Stomee 		dtj_throw_illegal_state(jenv,
9921449Stomee 		    "dtj_load_common() has not been called");
9931449Stomee 		return (NULL);
9941449Stomee 	}
9951449Stomee 
9961449Stomee 	bytes = (*jenv)->CallObjectMethod(jenv, jstr, g_strbytes_jm);
9971449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
9981449Stomee 		return (NULL); /* OutOfMemoryError pending */
9991449Stomee 	}
10001449Stomee 	/* Does not throw exceptions */
10011449Stomee 	len = (*jenv)->GetArrayLength(jenv, bytes);
10021449Stomee 	result = malloc(len + 1);
10031449Stomee 	if (!result) {
10041449Stomee 		(*jenv)->DeleteLocalRef(jenv, bytes);
10051449Stomee 		dtj_throw_out_of_memory(jenv,
10061449Stomee 		    "could not allocate native chars");
10071449Stomee 		return (NULL);
10081449Stomee 	}
10091449Stomee 
10101449Stomee 	/* Skip check for ArrayIndexOutOfBoundsException */
10111449Stomee 	(*jenv)->GetByteArrayRegion(jenv, bytes, 0, len,
10121449Stomee 	    (jbyte *)result);
10131449Stomee 	(*jenv)->DeleteLocalRef(jenv, bytes);
10141449Stomee 	result[len] = '\0'; /* NUL-terminate */
10151449Stomee 
10161449Stomee 	return (result);
10171449Stomee }
10181449Stomee 
10191449Stomee void
10201449Stomee /* ARGSUSED */
10211449Stomee dtj_ReleaseStringNativeChars(JNIEnv *jenv, jstring jstr, const char *str)
10221449Stomee {
10231449Stomee 	free((void *)str);
10241449Stomee }
10251449Stomee 
10261449Stomee char **
10271449Stomee dtj_get_argv(JNIEnv *jenv, jobjectArray args, int *argc)
10281449Stomee {
10291449Stomee 	char **argv = NULL; /* return value */
10301449Stomee 	const char *str;
10311449Stomee 	int i;
10321449Stomee 
10331449Stomee 	jstring jstr = NULL;
10341449Stomee 
10351449Stomee 	if (!g_dtj_load_common) {
10361449Stomee 		dtj_throw_illegal_state(jenv,
10371449Stomee 		    "dtj_load_common() has not been called");
10381449Stomee 		return (NULL);
10391449Stomee 	}
10401449Stomee 
10411449Stomee 	*argc = (*jenv)->GetArrayLength(jenv, args);
10421449Stomee 	/*
10431449Stomee 	 * Initialize all string pointers to NULL so that in case of an error
10441449Stomee 	 * filling in the array, free_argv() will not attempt to free the
10451449Stomee 	 * unallocated elements.  Also NULL-terminate the string array for
10461449Stomee 	 * functions that expect terminating NULL rather than rely on argc.
10471449Stomee 	 */
10481449Stomee 	argv = uu_zalloc((sizeof (char *)) * (*argc + 1));
10491449Stomee 	if (!argv) {
10501449Stomee 		dtj_throw_out_of_memory(jenv, "Failed to allocate args array");
10511449Stomee 		return (NULL);
10521449Stomee 	}
10531449Stomee 
10541449Stomee 	for (i = 0; i < *argc; ++i) {
10551449Stomee 		jstr = (*jenv)->GetObjectArrayElement(jenv, args, i);
10561449Stomee 		if ((*jenv)->ExceptionCheck(jenv)) {
10571449Stomee 			dtj_free_argv(argv);
10581449Stomee 			return (NULL);
10591449Stomee 		}
10601449Stomee 		str = dtj_GetStringNativeChars(jenv, jstr);
10611449Stomee 		if ((*jenv)->ExceptionCheck(jenv)) {
10621449Stomee 			dtj_free_argv(argv);
10631449Stomee 			(*jenv)->DeleteLocalRef(jenv, jstr);
10641449Stomee 			return (NULL);
10651449Stomee 		}
10661449Stomee 		argv[i] = malloc(strlen(str) + 1);
10671449Stomee 		if (!argv[i]) {
10681449Stomee 			dtj_throw_out_of_memory(jenv, "Failed to allocate arg");
10691449Stomee 			dtj_free_argv(argv);
10701449Stomee 			dtj_ReleaseStringNativeChars(jenv, jstr, str);
10711449Stomee 			(*jenv)->DeleteLocalRef(jenv, jstr);
10721449Stomee 			return (NULL);
10731449Stomee 		}
10741449Stomee 		(void) strcpy(argv[i], str);
10751449Stomee 		dtj_ReleaseStringNativeChars(jenv, jstr, str);
10761449Stomee 		(*jenv)->DeleteLocalRef(jenv, jstr);
10771449Stomee 		jstr = NULL;
10781449Stomee 	}
10791449Stomee 
10801449Stomee 	return (argv);
10811449Stomee }
10821449Stomee 
10831449Stomee char **
10841449Stomee dtj_make_argv(JNIEnv *jenv, jstring command, int *argc)
10851449Stomee {
10861449Stomee 	const char *ws = "\f\n\r\t\v ";
10871449Stomee 	char **argv = NULL; /* return value */
10881449Stomee 	const char *cmd; /* native command string */
10891449Stomee 	char *s; /* writable command */
10901449Stomee 	char *tok; /* token */
10911449Stomee 	int len;
10921449Stomee 
10931449Stomee 	if (!g_dtj_load_common) {
10941449Stomee 		dtj_throw_illegal_state(jenv,
10951449Stomee 		    "dtj_load_common() has not been called");
10961449Stomee 		return (NULL);
10971449Stomee 	}
10981449Stomee 
10991449Stomee 	if (!command) {
11001449Stomee 		dtj_throw_null_pointer(jenv, "command is null");
11011449Stomee 		return (NULL);
11021449Stomee 	} else if ((*jenv)->GetStringLength(jenv, command) == 0) {
11031449Stomee 		dtj_throw_illegal_argument(jenv, "command is empty");
11041449Stomee 		return (NULL);
11051449Stomee 	}
11061449Stomee 
11071449Stomee 	cmd = dtj_GetStringNativeChars(jenv, command);
11081449Stomee 	if ((*jenv)->ExceptionCheck(jenv)) {
11091449Stomee 		return (NULL);
11101449Stomee 	}
11111449Stomee 	len = strlen(cmd);
11121449Stomee 	s = malloc(len + 1);
11131449Stomee 	if (!s) {
11141449Stomee 		dtj_throw_out_of_memory(jenv,
11151449Stomee 		    "failed to allocate command string");
11161449Stomee 		dtj_ReleaseStringNativeChars(jenv, command, cmd);
11171449Stomee 		return (NULL);
11181449Stomee 	}
11191449Stomee 	(void) strcpy(s, cmd);
11201449Stomee 	/*
11211449Stomee 	 * Initialize all string pointers to NULL so that in case of an error
11221449Stomee 	 * filling in the array, free_argv() will not attempt to free the
11231449Stomee 	 * unallocated elements.  Also NULL-terminate the string array for
11241449Stomee 	 * functions that expect terminating NULL rather than rely on argc.
11251449Stomee 	 * Allow for maximum length resulting from single-character tokens
11261449Stomee 	 * separated by single spaces.
11271449Stomee 	 */
11281449Stomee 	argv = uu_zalloc(sizeof (char *) * (len / 2 + 1));
11291449Stomee 	if (!argv) {
11301449Stomee 		dtj_throw_out_of_memory(jenv, "failed to allocate args array");
11311449Stomee 		free(s);
11321449Stomee 		dtj_ReleaseStringNativeChars(jenv, command, cmd);
11331449Stomee 		return (NULL);
11341449Stomee 	}
11351449Stomee 
11361449Stomee 	*argc = 0;
11371449Stomee 	for (tok = strtok(s, ws); tok != NULL; tok = strtok(NULL, ws)) {
11381449Stomee 		argv[*argc] = malloc(strlen(tok) + 1);
11391449Stomee 		if (!argv[*argc]) {
11401449Stomee 			dtj_throw_out_of_memory(jenv, "Failed to allocate arg");
11411449Stomee 			dtj_free_argv(argv);
11421449Stomee 			free(s);
11431449Stomee 			dtj_ReleaseStringNativeChars(jenv, command, cmd);
11441449Stomee 			return (NULL);
11451449Stomee 		}
11461449Stomee 		(void) strcpy(argv[(*argc)++], tok);
11471449Stomee 	}
11481449Stomee 
11491449Stomee 	if (*argc == 0) {
11501449Stomee 		dtj_throw_illegal_argument(jenv, "command is blank");
11511449Stomee 		dtj_free_argv(argv);
11521449Stomee 		free(s);
11531449Stomee 		dtj_ReleaseStringNativeChars(jenv, command, cmd);
11541449Stomee 		return (NULL);
11551449Stomee 	}
11561449Stomee 
11571449Stomee 	free(s);
11581449Stomee 	dtj_ReleaseStringNativeChars(jenv, command, cmd);
11591449Stomee 	return (argv);
11601449Stomee }
11611449Stomee 
11621449Stomee void
11631449Stomee dtj_free_argv(char **argv)
11641449Stomee {
11651449Stomee 	if (argv) {
11661449Stomee 		char **s = argv;
11671449Stomee 		while (*s) {
11681449Stomee 			free((void *)*s);
11691449Stomee 			*s++ = NULL;
11701449Stomee 		}
11711449Stomee 		free((void *)argv);
11721449Stomee 	}
11731449Stomee }
11741449Stomee 
11751449Stomee 
11761449Stomee /* Wrappers for uu_list_t */
11771449Stomee 
11781449Stomee int
11791449Stomee /* ARGSUSED */
11801449Stomee dtj_pointer_list_entry_cmp(const void *v1, const void *v2, void *arg)
11811449Stomee {
11821449Stomee 	const dtj_pointer_list_entry_t *p1 = v1;
11831449Stomee 	const dtj_pointer_list_entry_t *p2 = v2;
11841449Stomee 
11851449Stomee 	/*
11861449Stomee 	 * It is not valid to compare pointers using the relational operators
11871449Stomee 	 * unless they point to elements in the same array.
11881449Stomee 	 */
1189*1717Swesolows 	uint64_t x = (uintptr_t)p1->dple_ptr;
1190*1717Swesolows 	uint64_t y = (uintptr_t)p2->dple_ptr;
11911449Stomee 	int rc;
11921449Stomee 	rc = ((x > y) ? 1 : ((x < y) ? -1 : 0));
11931449Stomee 	return (rc);
11941449Stomee }
11951449Stomee 
11961449Stomee int
11971449Stomee /* ARGSUSED */
11981449Stomee dtj_string_list_entry_cmp(const void *v1, const void *v2, void *arg)
11991449Stomee {
12001449Stomee 	const dtj_string_list_entry_t *p1 = v1;
12011449Stomee 	const dtj_string_list_entry_t *p2 = v2;
12021449Stomee 	const char *s1 = p1->dsle_value;
12031449Stomee 	const char *s2 = p2->dsle_value;
12041449Stomee 	if (s1 == NULL) {
12051449Stomee 		return (s2 == NULL ? 0 : -1);
12061449Stomee 	}
12071449Stomee 	if (s2 == NULL) {
12081449Stomee 		return (1);
12091449Stomee 	}
12101449Stomee 	return (strcmp(s1, s2));
12111449Stomee }
12121449Stomee 
12131449Stomee static boolean_t
12141449Stomee dtj_check_pointer_pool(void)
12151449Stomee {
12161449Stomee 	if (g_pointer_pool == NULL) {
12171449Stomee 		g_pointer_pool = uu_list_pool_create("g_pointer_pool",
12181449Stomee 		    sizeof (dtj_pointer_list_entry_t),
12191449Stomee 		    offsetof(dtj_pointer_list_entry_t, dple_node),
12201449Stomee 		    dtj_pointer_list_entry_cmp,
12211449Stomee 		    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
12221449Stomee 		if (g_pointer_pool == NULL) {
12231449Stomee 			return (B_FALSE);
12241449Stomee 		}
12251449Stomee 	}
12261449Stomee 	return (B_TRUE);
12271449Stomee }
12281449Stomee 
12291449Stomee uu_list_t *
12301449Stomee dtj_pointer_list_create(void)
12311449Stomee {
12321449Stomee 	uu_list_t *list;
12331449Stomee 
12341449Stomee 	if (!dtj_check_pointer_pool()) {
12351449Stomee 		return (NULL);
12361449Stomee 	}
12371449Stomee 
12381449Stomee 	list = uu_list_create(g_pointer_pool, NULL,
12391449Stomee 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
12401449Stomee 	return (list);
12411449Stomee }
12421449Stomee 
12431449Stomee dtj_pointer_list_entry_t *
12441449Stomee dtj_pointer_list_entry_create(void *p)
12451449Stomee {
12461449Stomee 	dtj_pointer_list_entry_t *e;
12471449Stomee 
12481449Stomee 	if (!dtj_check_pointer_pool()) {
12491449Stomee 		return (NULL);
12501449Stomee 	}
12511449Stomee 
12521449Stomee 	e = uu_zalloc(sizeof (dtj_pointer_list_entry_t));
12531449Stomee 	if (e) {
12541449Stomee 		uu_list_node_init(e, &e->dple_node, g_pointer_pool);
12551449Stomee 		e->dple_ptr = p;
12561449Stomee 	}
12571449Stomee 	return (e);
12581449Stomee }
12591449Stomee 
12601449Stomee static boolean_t
12611449Stomee dtj_check_string_pool(void)
12621449Stomee {
12631449Stomee 	if (g_string_pool == NULL) {
12641449Stomee 		g_string_pool = uu_list_pool_create("g_string_pool",
12651449Stomee 		    sizeof (dtj_string_list_entry_t),
12661449Stomee 		    offsetof(dtj_string_list_entry_t, dsle_node),
12671449Stomee 		    dtj_string_list_entry_cmp,
12681449Stomee 		    (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
12691449Stomee 		if (g_string_pool == NULL) {
12701449Stomee 			return (B_FALSE);
12711449Stomee 		}
12721449Stomee 	}
12731449Stomee 	return (B_TRUE);
12741449Stomee }
12751449Stomee 
12761449Stomee uu_list_t *
12771449Stomee dtj_string_list_create(void)
12781449Stomee {
12791449Stomee 	uu_list_t *list;
12801449Stomee 
12811449Stomee 	if (!dtj_check_string_pool()) {
12821449Stomee 		return (NULL);
12831449Stomee 	}
12841449Stomee 
12851449Stomee 	list = uu_list_create(g_string_pool, NULL,
12861449Stomee 	    (g_dtj_util_debug ? UU_LIST_DEBUG : 0));
12871449Stomee 	return (list);
12881449Stomee }
12891449Stomee 
12901449Stomee dtj_string_list_entry_t *
12911449Stomee dtj_string_list_entry_create(const char *s)
12921449Stomee {
12931449Stomee 	dtj_string_list_entry_t *e;
12941449Stomee 
12951449Stomee 	if (!dtj_check_string_pool()) {
12961449Stomee 		return (NULL);
12971449Stomee 	}
12981449Stomee 
12991449Stomee 	e = uu_zalloc(sizeof (dtj_string_list_entry_t));
13001449Stomee 	if (e) {
13011449Stomee 		uu_list_node_init(e, &e->dsle_node, g_string_pool);
13021449Stomee 		if (s) {
13031449Stomee 			e->dsle_value = malloc(strlen(s) + 1);
13041449Stomee 			if (e->dsle_value) {
13051449Stomee 				(void) strcpy(e->dsle_value, s);
13061449Stomee 			} else {
13071449Stomee 				uu_list_node_fini(e, &e->dsle_node,
13081449Stomee 				    g_string_pool);
13091449Stomee 				uu_free(e);
13101449Stomee 				e = NULL;
13111449Stomee 			}
13121449Stomee 		}
13131449Stomee 	}
13141449Stomee 	return (e);
13151449Stomee }
13161449Stomee 
13171449Stomee void
13181449Stomee dtj_pointer_list_entry_destroy(void *v,
13191449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
13201449Stomee {
13211449Stomee 	if (v) {
13221449Stomee 		dtj_pointer_list_entry_t *e = v;
13231449Stomee 		if (value_destroy) {
13241449Stomee 			value_destroy(e->dple_ptr, arg);
13251449Stomee 		}
13261449Stomee 		uu_list_node_fini(e, &e->dple_node, g_pointer_pool);
13271449Stomee 		e->dple_ptr = NULL;
13281449Stomee 		uu_free(v);
13291449Stomee 	}
13301449Stomee }
13311449Stomee 
13321449Stomee void
13331449Stomee /* ARGSUSED */
13341449Stomee dtj_string_list_entry_destroy(void *v, void *arg)
13351449Stomee {
13361449Stomee 	if (v) {
13371449Stomee 		dtj_string_list_entry_t *e = v;
13381449Stomee 		free(e->dsle_value);
13391449Stomee 		uu_list_node_fini(e, &e->dsle_node, g_string_pool);
13401449Stomee 		e->dsle_value = NULL;
13411449Stomee 		uu_free(v);
13421449Stomee 	}
13431449Stomee }
13441449Stomee 
13451449Stomee void
13461449Stomee dtj_list_clear(uu_list_t *list, dtj_value_destroy_f *value_destroy,
13471449Stomee     void *arg)
13481449Stomee {
13491449Stomee 	void *cookie; /* needed for uu_list_teardown */
13501449Stomee 	void *value;
13511449Stomee 
13521449Stomee 	if (!list) {
13531449Stomee 		return;
13541449Stomee 	}
13551449Stomee 
13561449Stomee 	cookie = NULL;
13571449Stomee 	if (value_destroy) {
13581449Stomee 		while ((value = uu_list_teardown(list, &cookie)) != NULL) {
13591449Stomee 			value_destroy(value, arg);
13601449Stomee 		}
13611449Stomee 	} else {
13621449Stomee 		while ((value = uu_list_teardown(list, &cookie)) != NULL) {
13631449Stomee 		}
13641449Stomee 	}
13651449Stomee }
13661449Stomee 
13671449Stomee void
13681449Stomee dtj_list_destroy(uu_list_t *list,
13691449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
13701449Stomee {
13711449Stomee 	dtj_list_clear(list, value_destroy, arg);
13721449Stomee 	uu_list_destroy(list);
13731449Stomee }
13741449Stomee 
13751449Stomee void
13761449Stomee dtj_pointer_list_clear(uu_list_t *list,
13771449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
13781449Stomee {
13791449Stomee 	void *cookie; /* needed for uu_list_teardown */
13801449Stomee 	dtj_pointer_list_entry_t *e;
13811449Stomee 
13821449Stomee 	if (!list) {
13831449Stomee 		return;
13841449Stomee 	}
13851449Stomee 
13861449Stomee 	cookie = NULL;
13871449Stomee 	while ((e = uu_list_teardown(list, &cookie)) != NULL) {
13881449Stomee 		dtj_pointer_list_entry_destroy(e, value_destroy, arg);
13891449Stomee 	}
13901449Stomee }
13911449Stomee 
13921449Stomee void
13931449Stomee dtj_pointer_list_destroy(uu_list_t *list,
13941449Stomee     dtj_value_destroy_f *value_destroy, void *arg)
13951449Stomee {
13961449Stomee 	dtj_pointer_list_clear(list, value_destroy, arg);
13971449Stomee 	uu_list_destroy(list);
13981449Stomee }
13991449Stomee 
14001449Stomee void
14011449Stomee dtj_string_list_clear(uu_list_t *list)
14021449Stomee {
14031449Stomee 	dtj_list_clear(list, dtj_string_list_entry_destroy, NULL);
14041449Stomee }
14051449Stomee 
14061449Stomee void
14071449Stomee dtj_string_list_destroy(uu_list_t *list)
14081449Stomee {
14091449Stomee 	dtj_list_destroy(list, dtj_string_list_entry_destroy, NULL);
14101449Stomee }
14111449Stomee 
14121449Stomee boolean_t
14131449Stomee dtj_list_empty(uu_list_t *list)
14141449Stomee {
14151449Stomee 	return (uu_list_numnodes(list) == 0);
14161449Stomee }
14171449Stomee 
14181449Stomee boolean_t
14191449Stomee dtj_list_add(uu_list_t *list, void *value)
14201449Stomee {
14211449Stomee 	return (uu_list_insert_before(list, NULL, value) == 0);
14221449Stomee }
14231449Stomee 
14241449Stomee boolean_t
14251449Stomee dtj_pointer_list_add(uu_list_t *list, void *p)
14261449Stomee {
14271449Stomee 	dtj_pointer_list_entry_t *e = dtj_pointer_list_entry_create(p);
14281449Stomee 	if (!e) {
14291449Stomee 		return (B_FALSE);
14301449Stomee 	}
14311449Stomee 	return (dtj_list_add(list, e));
14321449Stomee }
14331449Stomee 
14341449Stomee void *
14351449Stomee dtj_pointer_list_walk_next(uu_list_walk_t *itr)
14361449Stomee {
14371449Stomee 	dtj_pointer_list_entry_t *e = uu_list_walk_next(itr);
14381449Stomee 	if (!e) {
14391449Stomee 		return (DTJ_INVALID_PTR);
14401449Stomee 	}
14411449Stomee 	return (e->dple_ptr);
14421449Stomee }
14431449Stomee 
14441449Stomee void *
14451449Stomee dtj_pointer_list_first(uu_list_t *list)
14461449Stomee {
14471449Stomee 	dtj_pointer_list_entry_t *e = uu_list_first(list);
14481449Stomee 	if (!e) {
14491449Stomee 		/* NULL is a valid value; use -1 for invalid */
14501449Stomee 		return (DTJ_INVALID_PTR);
14511449Stomee 	}
14521449Stomee 	return (e->dple_ptr);
14531449Stomee }
14541449Stomee 
14551449Stomee void *
14561449Stomee dtj_pointer_list_last(uu_list_t *list)
14571449Stomee {
14581449Stomee 	dtj_pointer_list_entry_t *e = uu_list_last(list);
14591449Stomee 	if (!e) {
14601449Stomee 		/* NULL is a valid value; use -1 for invalid */
14611449Stomee 		return (DTJ_INVALID_PTR);
14621449Stomee 	}
14631449Stomee 	return (e->dple_ptr);
14641449Stomee }
14651449Stomee 
14661449Stomee boolean_t
14671449Stomee dtj_string_list_add(uu_list_t *list, const char *s)
14681449Stomee {
14691449Stomee 	dtj_string_list_entry_t *e = dtj_string_list_entry_create(s);
14701449Stomee 	if (!e) {
14711449Stomee 		return (B_FALSE);
14721449Stomee 	}
14731449Stomee 	return (dtj_list_add(list, e));
14741449Stomee }
14751449Stomee 
14761449Stomee const char *
14771449Stomee dtj_string_list_walk_next(uu_list_walk_t *itr)
14781449Stomee {
14791449Stomee 	dtj_string_list_entry_t *e = uu_list_walk_next(itr);
14801449Stomee 	if (!e) {
14811449Stomee 		return (DTJ_INVALID_STR);
14821449Stomee 	}
14831449Stomee 	return (e->dsle_value);
14841449Stomee }
14851449Stomee 
14861449Stomee const char *
14871449Stomee dtj_string_list_first(uu_list_t *list)
14881449Stomee {
14891449Stomee 	dtj_string_list_entry_t *e = uu_list_first(list);
14901449Stomee 	if (!e) {
14911449Stomee 		/* NULL is a valid string value; use -1 for invalid */
14921449Stomee 		return (DTJ_INVALID_STR);
14931449Stomee 	}
14941449Stomee 	return (e->dsle_value);
14951449Stomee }
14961449Stomee 
14971449Stomee const char *
14981449Stomee dtj_string_list_last(uu_list_t *list)
14991449Stomee {
15001449Stomee 	dtj_string_list_entry_t *e = uu_list_last(list);
15011449Stomee 	if (!e) {
15021449Stomee 		/* NULL is a valid string value; use -1 for invalid */
15031449Stomee 		return (DTJ_INVALID_STR);
15041449Stomee 	}
15051449Stomee 	return (e->dsle_value);
15061449Stomee }
1507