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