1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdlib.h> 28 #include <stddef.h> 29 #include <sys/types.h> 30 #include <pthread.h> 31 #include <string.h> 32 #include <dtj_util.h> 33 34 /* 35 * dtj_util.c separates functionality that is generally useful from 36 * that which is specific to the Java DTrace API. If moved to a separate 37 * library, this functionality could be shared by other JNI wrappers. 38 */ 39 40 boolean_t g_dtj_util_debug = B_FALSE; 41 static boolean_t g_dtj_load_common = B_FALSE; 42 43 /* NativeException */ 44 jclass g_nx_jc = 0; 45 jmethodID g_nxinit_jm = 0; 46 47 /* java.io.Serializable */ 48 jclass g_serial_jc = 0; 49 50 /* java.lang.Number */ 51 jclass g_number_jc = 0; 52 jmethodID g_shortval_jm = 0; 53 jmethodID g_intval_jm = 0; 54 jmethodID g_longval_jm = 0; 55 56 /* java.lang.Byte */ 57 jclass g_byte_jc = 0; 58 jmethodID g_byteinit_jm = 0; 59 60 /* java.lang.Character */ 61 jclass g_char_jc = 0; 62 jmethodID g_charinit_jm = 0; 63 jmethodID g_charval_jm = 0; 64 65 /* java.lang.Short */ 66 jclass g_short_jc = 0; 67 jmethodID g_shortinit_jm = 0; 68 69 /* java.lang.Integer */ 70 jclass g_int_jc = 0; 71 jmethodID g_intinit_jm = 0; 72 73 /* java.lang.Long */ 74 jclass g_long_jc = 0; 75 jmethodID g_longinit_jm = 0; 76 77 /* java.math.BigInteger */ 78 jclass g_bigint_jc = 0; 79 jmethodID g_bigint_val_jsm = 0; 80 jmethodID g_bigint_div_jm = 0; 81 jmethodID g_bigint_shl_jm = 0; 82 jmethodID g_bigint_or_jm = 0; 83 jmethodID g_bigint_setbit_jm = 0; 84 85 /* java.lang.String */ 86 jclass g_string_jc = 0; 87 jmethodID g_strinit_bytes_jm = 0; 88 jmethodID g_strbytes_jm = 0; 89 jmethodID g_trim_jm = 0; 90 91 /* java.lang.StringBuilder */ 92 jclass g_buf_jc = 0; 93 jmethodID g_bufinit_jm = 0; 94 jmethodID g_buf_append_char_jm = 0; 95 jmethodID g_buf_append_int_jm = 0; 96 jmethodID g_buf_append_long_jm = 0; 97 jmethodID g_buf_append_str_jm = 0; 98 jmethodID g_buf_append_obj_jm = 0; 99 jmethodID g_buflen_jm = 0; 100 jmethodID g_bufsetlen_jm = 0; 101 102 /* java.lang.Object */ 103 jclass g_object_jc = 0; 104 jmethodID g_tostring_jm = 0; 105 jmethodID g_equals_jm = 0; 106 107 /* java.lang.Enum */ 108 jclass g_enum_jc = 0; 109 jmethodID g_enumname_jm = 0; 110 111 /* List */ 112 jclass g_list_jc = 0; 113 jmethodID g_listclear_jm = 0; 114 jmethodID g_listadd_jm = 0; 115 jmethodID g_listget_jm = 0; 116 jmethodID g_listsize_jm = 0; 117 118 /* Global list pools */ 119 static uu_list_pool_t *g_pointer_pool = NULL; 120 static uu_list_pool_t *g_string_pool = NULL; 121 122 static dtj_status_t dtj_get_jni_classes(JNIEnv *, uu_list_t *, uu_list_pool_t *, 123 uu_list_pool_t *, uu_list_pool_t *, const dtj_table_entry_t *); 124 static dtj_status_t dtj_cache_jni_methods(JNIEnv *, dtj_java_class_t *); 125 static dtj_status_t dtj_cache_jni_fields(JNIEnv *, dtj_java_class_t *); 126 127 /* Constructors */ 128 static dtj_java_class_t *dtj_java_class_create(JNIEnv *, jclass *, char *, 129 uu_list_pool_t *, uu_list_pool_t *, uu_list_pool_t *); 130 static dtj_java_method_t *dtj_java_method_create(JNIEnv *, jmethodID *, char *, 131 char *, uu_list_pool_t *); 132 static dtj_java_method_t *dtj_java_static_method_create(JNIEnv *, jmethodID *, 133 char *, char *, uu_list_pool_t *); 134 static dtj_java_field_t *dtj_java_field_create(JNIEnv *, jfieldID *, char *, 135 char *, uu_list_pool_t *); 136 static dtj_java_field_t *dtj_java_static_field_create(JNIEnv *, jfieldID *, 137 char *, char *, uu_list_pool_t *); 138 139 /* Destructors */ 140 static void dtj_java_class_destroy(void *, void *); 141 static void dtj_java_method_destroy(void *, void *); 142 static void dtj_java_field_destroy(void *, void *); 143 144 /* Comparison functions, uu_compare_fn_t signature */ 145 static int dtj_java_class_cmp(const void *, const void *, void *); 146 static int dtj_java_method_cmp(const void *, const void *, void *); 147 static int dtj_java_field_cmp(const void *, const void *, void *); 148 149 /* Java Throwable */ 150 static void dtj_throw(JNIEnv *, jclass, const char *, va_list *); 151 152 /* Support for uu_list_t wrappers */ 153 static boolean_t dtj_check_pointer_pool(void); 154 static boolean_t dtj_check_string_pool(void); 155 156 dtj_status_t 157 dtj_load_common(JNIEnv *jenv) 158 { 159 dtj_status_t status; 160 161 static const dtj_table_entry_t table[] = { 162 /* NativeException */ 163 { JCLASS, &g_nx_jc, 164 "org/opensolaris/os/dtrace/NativeException" }, 165 { JMETHOD, &g_nxinit_jm, CONSTRUCTOR, 166 "(Ljava/lang/String;ILjava/lang/Throwable;)V" }, 167 168 /* java.io.Serializable */ 169 { JCLASS, &g_serial_jc, "java/io/Serializable" }, 170 171 /* java.lang.Number */ 172 { JCLASS, &g_number_jc, "java/lang/Number" }, 173 { JMETHOD, &g_shortval_jm, "shortValue", "()S" }, 174 { JMETHOD, &g_intval_jm, "intValue", "()I" }, 175 { JMETHOD, &g_longval_jm, "longValue", "()J" }, 176 177 /* java.lang.Byte */ 178 { JCLASS, &g_byte_jc, "java/lang/Byte" }, 179 { JMETHOD, &g_byteinit_jm, CONSTRUCTOR, "(B)V" }, 180 181 /* java.lang.Character */ 182 { JCLASS, &g_char_jc, "java/lang/Character" }, 183 { JMETHOD, &g_charinit_jm, CONSTRUCTOR, "(C)V" }, 184 { JMETHOD, &g_charval_jm, "charValue", "()C" }, 185 186 /* java.lang.Short */ 187 { JCLASS, &g_short_jc, "java/lang/Short" }, 188 { JMETHOD, &g_shortinit_jm, CONSTRUCTOR, "(S)V" }, 189 190 /* java.lang.Integer */ 191 { JCLASS, &g_int_jc, "java/lang/Integer" }, 192 { JMETHOD, &g_intinit_jm, CONSTRUCTOR, "(I)V" }, 193 194 /* java.lang.Long */ 195 { JCLASS, &g_long_jc, "java/lang/Long" }, 196 { JMETHOD, &g_longinit_jm, CONSTRUCTOR, "(J)V" }, 197 198 /* java.math.BigInteger */ 199 { JCLASS, &g_bigint_jc, "java/math/BigInteger" }, 200 { JMETHOD_STATIC, &g_bigint_val_jsm, "valueOf", 201 "(J)Ljava/math/BigInteger;" }, 202 { JMETHOD, &g_bigint_div_jm, "divide", 203 "(Ljava/math/BigInteger;)Ljava/math/BigInteger;" }, 204 { JMETHOD, &g_bigint_shl_jm, "shiftLeft", 205 "(I)Ljava/math/BigInteger;" }, 206 { JMETHOD, &g_bigint_or_jm, "or", 207 "(Ljava/math/BigInteger;)Ljava/math/BigInteger;" }, 208 { JMETHOD, &g_bigint_setbit_jm, "setBit", 209 "(I)Ljava/math/BigInteger;" }, 210 211 /* java.lang.String */ 212 { JCLASS, &g_string_jc, "java/lang/String" }, 213 { JMETHOD, &g_strinit_bytes_jm, CONSTRUCTOR, "([B)V" }, 214 { JMETHOD, &g_strbytes_jm, "getBytes", "()[B" }, 215 { JMETHOD, &g_trim_jm, "trim", "()Ljava/lang/String;" }, 216 217 /* java.lang.StringBuilder */ 218 { JCLASS, &g_buf_jc, "java/lang/StringBuilder" }, 219 { JMETHOD, &g_bufinit_jm, CONSTRUCTOR, "()V" }, 220 { JMETHOD, &g_buf_append_char_jm, "append", 221 "(C)Ljava/lang/StringBuilder;" }, 222 { JMETHOD, &g_buf_append_int_jm, "append", 223 "(I)Ljava/lang/StringBuilder;" }, 224 { JMETHOD, &g_buf_append_long_jm, "append", 225 "(J)Ljava/lang/StringBuilder;" }, 226 { JMETHOD, &g_buf_append_str_jm, "append", 227 "(Ljava/lang/String;)Ljava/lang/StringBuilder;" }, 228 { JMETHOD, &g_buf_append_obj_jm, "append", 229 "(Ljava/lang/Object;)Ljava/lang/StringBuilder;" }, 230 { JMETHOD, &g_buflen_jm, "length", "()I" }, 231 { JMETHOD, &g_bufsetlen_jm, "setLength", "(I)V" }, 232 233 /* java.lang.Object */ 234 { JCLASS, &g_object_jc, "java/lang/Object" }, 235 { JMETHOD, &g_tostring_jm, "toString", 236 "()Ljava/lang/String;" }, 237 { JMETHOD, &g_equals_jm, "equals", 238 "(Ljava/lang/Object;)Z" }, 239 240 /* java.lang.Enum */ 241 { JCLASS, &g_enum_jc, "java/lang/Enum" }, 242 { JMETHOD, &g_enumname_jm, "name", 243 "()Ljava/lang/String;" }, 244 245 /* List */ 246 { JCLASS, &g_list_jc, "java/util/List" }, 247 { JMETHOD, &g_listclear_jm, "clear", "()V" }, 248 { JMETHOD, &g_listadd_jm, "add", "(Ljava/lang/Object;)Z" }, 249 { JMETHOD, &g_listget_jm, "get", "(I)Ljava/lang/Object;" }, 250 { JMETHOD, &g_listsize_jm, "size", "()I" }, 251 252 { DTJ_TYPE_END } 253 }; 254 255 status = dtj_cache_jni_classes(jenv, table); 256 if (status == DTJ_OK) { 257 g_dtj_load_common = B_TRUE; 258 } 259 return (status); 260 } 261 262 static int 263 /* ARGSUSED */ 264 dtj_java_class_cmp(const void * v1, const void * v2, void *arg) 265 { 266 const dtj_java_class_t *c1 = v1; 267 const dtj_java_class_t *c2 = v2; 268 return (strcmp(c1->djc_name, c2->djc_name)); 269 } 270 271 static int 272 /* ARGSUSED */ 273 dtj_java_method_cmp(const void *v1, const void *v2, void *arg) 274 { 275 int cmp; 276 const dtj_java_method_t *m1 = v1; 277 const dtj_java_method_t *m2 = v2; 278 cmp = strcmp(m1->djm_name, m2->djm_name); 279 if (cmp == 0) { 280 cmp = strcmp(m1->djm_signature, m2->djm_signature); 281 } 282 return (cmp); 283 } 284 285 static int 286 /* ARGSUSED */ 287 dtj_java_field_cmp(const void *v1, const void *v2, void *arg) 288 { 289 const dtj_java_field_t *f1 = v1; 290 const dtj_java_field_t *f2 = v2; 291 return (strcmp(f1->djf_name, f2->djf_name)); 292 } 293 294 static dtj_java_class_t * 295 dtj_java_class_create(JNIEnv *jenv, jclass *jc, char *name, 296 uu_list_pool_t *classpool, uu_list_pool_t *methodpool, 297 uu_list_pool_t *fieldpool) 298 { 299 dtj_java_class_t *c = uu_zalloc(sizeof (dtj_java_class_t)); 300 if (c) { 301 uu_list_node_init(c, &c->djc_node, classpool); 302 c->djc_ptr = jc; 303 c->djc_name = name; 304 c->djc_methods = uu_list_create(methodpool, NULL, 305 (g_dtj_util_debug ? UU_LIST_DEBUG : 0)); 306 if (!c->djc_methods) { 307 dtj_throw_out_of_memory(jenv, 308 "Failed method list creation"); 309 uu_list_node_fini(c, &c->djc_node, classpool); 310 free(c); 311 c = NULL; 312 } 313 c->djc_fields = uu_list_create(fieldpool, NULL, 314 (g_dtj_util_debug ? UU_LIST_DEBUG : 0)); 315 if (!c->djc_fields) { 316 dtj_throw_out_of_memory(jenv, 317 "Failed field list creation"); 318 uu_list_destroy(c->djc_methods); 319 c->djc_methods = NULL; 320 uu_list_node_fini(c, &c->djc_node, classpool); 321 free(c); 322 c = NULL; 323 } 324 } else { 325 dtj_throw_out_of_memory(jenv, 326 "Failed to allocate class description"); 327 } 328 return (c); 329 } 330 331 static dtj_java_method_t * 332 dtj_java_method_create(JNIEnv *jenv, jmethodID *jm, char *name, char *signature, 333 uu_list_pool_t *methodpool) 334 { 335 dtj_java_method_t *m = uu_zalloc(sizeof (dtj_java_method_t)); 336 if (m) { 337 uu_list_node_init(m, &m->djm_node, methodpool); 338 m->djm_ptr = jm; 339 m->djm_name = name; 340 m->djm_signature = signature; 341 m->djm_static = B_FALSE; 342 } else { 343 dtj_throw_out_of_memory(jenv, 344 "Failed to allocate method description"); 345 } 346 return (m); 347 } 348 349 static dtj_java_method_t * 350 dtj_java_static_method_create(JNIEnv *jenv, jmethodID *jm, char *name, 351 char *signature, uu_list_pool_t *methodpool) 352 { 353 dtj_java_method_t *m = dtj_java_method_create(jenv, jm, name, signature, 354 methodpool); 355 if (m) { 356 m->djm_static = B_TRUE; 357 } 358 return (m); 359 } 360 361 static dtj_java_field_t * 362 dtj_java_field_create(JNIEnv *jenv, jfieldID *jf, char *name, char *type, 363 uu_list_pool_t *fieldpool) 364 { 365 dtj_java_field_t *f = uu_zalloc(sizeof (dtj_java_field_t)); 366 if (f) { 367 uu_list_node_init(f, &f->djf_node, fieldpool); 368 f->djf_ptr = jf; 369 f->djf_name = name; 370 f->djf_type = type; 371 f->djf_static = B_FALSE; 372 } else { 373 dtj_throw_out_of_memory(jenv, 374 "Failed to allocate field description"); 375 } 376 return (f); 377 } 378 379 static dtj_java_field_t * 380 dtj_java_static_field_create(JNIEnv *jenv, jfieldID *jf, char *name, char *type, 381 uu_list_pool_t *fieldpool) 382 { 383 dtj_java_field_t *f = dtj_java_field_create(jenv, jf, name, type, 384 fieldpool); 385 if (f) { 386 f->djf_static = B_TRUE; 387 } 388 return (f); 389 } 390 391 static void 392 /* ARGSUSED */ 393 dtj_java_class_destroy(void *v, void *arg) 394 { 395 if (v) { 396 dtj_java_class_t *c = v; 397 c->djc_ptr = NULL; /* do not free user-defined storage */ 398 c->djc_name = NULL; /* string literal */ 399 dtj_list_destroy(c->djc_methods, dtj_java_method_destroy, NULL); 400 dtj_list_destroy(c->djc_fields, dtj_java_field_destroy, NULL); 401 c->djc_methods = NULL; 402 c->djc_fields = NULL; 403 uu_free(v); 404 } 405 } 406 407 static void 408 /* ARGSUSED */ 409 dtj_java_method_destroy(void *v, void *arg) 410 { 411 if (v) { 412 dtj_java_method_t *m = v; 413 m->djm_ptr = NULL; /* do not free user-defined space */ 414 m->djm_name = NULL; /* string literal */ 415 m->djm_signature = NULL; /* string literal */ 416 uu_free(v); 417 } 418 } 419 420 static void 421 /* ARGSUSED */ 422 dtj_java_field_destroy(void *v, void *arg) 423 { 424 if (v) { 425 dtj_java_field_t *f = v; 426 f->djf_ptr = NULL; /* do not free user-defined space */ 427 f->djf_name = NULL; /* string literal */ 428 f->djf_type = NULL; /* string literal */ 429 uu_free(f); 430 } 431 } 432 433 dtj_status_t 434 dtj_cache_jni_classes(JNIEnv *jenv, const dtj_table_entry_t *table) 435 { 436 dtj_java_class_t *class; 437 uu_list_pool_t *classpool; 438 uu_list_pool_t *methodpool; 439 uu_list_pool_t *fieldpool; 440 uu_list_t *classes; 441 uu_list_walk_t *itr; 442 jclass jc; 443 jclass gjc; 444 dtj_status_t status; 445 446 classpool = uu_list_pool_create("classpool", 447 sizeof (dtj_java_class_t), 448 offsetof(dtj_java_class_t, djc_node), dtj_java_class_cmp, 449 (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0)); 450 if (!classpool) { 451 dtj_throw_out_of_memory(jenv, "failed class pool creation"); 452 return (DTJ_ERR); 453 } 454 methodpool = uu_list_pool_create("methodpool", 455 sizeof (dtj_java_method_t), 456 offsetof(dtj_java_method_t, djm_node), dtj_java_method_cmp, 457 (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0)); 458 if (!methodpool) { 459 dtj_throw_out_of_memory(jenv, "failed method pool creation"); 460 return (DTJ_ERR); 461 } 462 fieldpool = uu_list_pool_create("fieldpool", 463 sizeof (dtj_java_field_t), 464 offsetof(dtj_java_field_t, djf_node), dtj_java_field_cmp, 465 (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0)); 466 if (!fieldpool) { 467 dtj_throw_out_of_memory(jenv, "failed field pool creation"); 468 return (DTJ_ERR); 469 } 470 471 classes = uu_list_create(classpool, NULL, 472 (g_dtj_util_debug ? UU_LIST_DEBUG : 0)); 473 if (!classes) { 474 dtj_throw_out_of_memory(jenv, "failed class list creation"); 475 return (DTJ_ERR); 476 } 477 478 status = dtj_get_jni_classes(jenv, classes, classpool, methodpool, 479 fieldpool, table); 480 if (status != DTJ_OK) { 481 /* java error pending */ 482 return (status); 483 } 484 485 itr = uu_list_walk_start(classes, 0); 486 while ((class = uu_list_walk_next(itr)) != NULL) { 487 jc = (*jenv)->FindClass(jenv, class->djc_name); 488 if (!jc) { 489 /* NoClassDefFoundError pending */ 490 return (DTJ_ERR); 491 } 492 gjc = (*jenv)->NewGlobalRef(jenv, jc); 493 (*jenv)->DeleteLocalRef(jenv, jc); 494 if (!gjc) { 495 dtj_throw_out_of_memory(jenv, 496 "Failed to create global class reference"); 497 return (DTJ_ERR); 498 } 499 *(class->djc_ptr) = gjc; 500 status = dtj_cache_jni_methods(jenv, class); 501 if (status != DTJ_OK) { 502 /* java error pending */ 503 return (status); 504 } 505 status = dtj_cache_jni_fields(jenv, class); 506 if (status != DTJ_OK) { 507 /* java error pending */ 508 return (status); 509 } 510 } 511 uu_list_walk_end(itr); 512 dtj_list_destroy(classes, dtj_java_class_destroy, NULL); 513 uu_list_pool_destroy(classpool); 514 uu_list_pool_destroy(methodpool); 515 uu_list_pool_destroy(fieldpool); 516 return (DTJ_OK); 517 } 518 519 /* 520 * Converts JNI table entry desriptions into java_class_t descriptors. 521 */ 522 static dtj_status_t 523 dtj_get_jni_classes(JNIEnv *jenv, uu_list_t *classes, 524 uu_list_pool_t *classpool, uu_list_pool_t *methodpool, 525 uu_list_pool_t *fieldpool, const dtj_table_entry_t *table) 526 { 527 int i; 528 dtj_java_class_t *c = NULL; 529 dtj_java_method_t *m; 530 dtj_java_field_t *f; 531 532 for (i = 0; table[i].djte_type != DTJ_TYPE_END; ++i) { 533 /* 534 * Class not added until all of its method and field information 535 * is attached, so we defer adding a class until the next 536 * element with type JCLASS. 537 */ 538 switch (table[i].djte_type) { 539 case JCLASS: 540 if (c) { 541 /* previous class */ 542 if (!dtj_list_add(classes, c)) { 543 dtj_throw_out_of_memory(jenv, 544 "Failed to add class description"); 545 /* 546 * In response to an error return value, 547 * the caller will delete the class 548 * descriptions list with any 549 * descriptions created so far. 550 */ 551 return (DTJ_ERR); 552 } 553 } 554 c = dtj_java_class_create(jenv, 555 (jclass *)table[i].djte_addr, table[i].djte_name, 556 classpool, methodpool, fieldpool); 557 if (!c) { 558 /* OutOfMemoryError pending */ 559 return (DTJ_ERR); 560 } 561 break; 562 case JMETHOD: 563 if (!c) { 564 dtj_throw_illegal_state(jenv, 565 "method description not preceded " 566 "by class description"); 567 return (DTJ_ERR); 568 } 569 m = dtj_java_method_create(jenv, 570 (jmethodID *)table[i].djte_addr, 571 table[i].djte_name, table[i].djte_desc, 572 methodpool); 573 if (!m) { 574 /* OutOfMemoryError pending */ 575 return (DTJ_ERR); 576 } 577 if (!dtj_list_add(c->djc_methods, m)) { 578 dtj_throw_out_of_memory(jenv, 579 "Failed to add method description"); 580 return (DTJ_ERR); 581 } 582 break; 583 case JMETHOD_STATIC: 584 if (!c) { 585 dtj_throw_illegal_state(jenv, 586 "static method description not preceded " 587 "by class description"); 588 return (DTJ_ERR); 589 } 590 m = dtj_java_static_method_create(jenv, 591 (jmethodID *)table[i].djte_addr, 592 table[i].djte_name, table[i].djte_desc, 593 methodpool); 594 if (!m) { 595 /* OutOfMemoryError pending */ 596 return (DTJ_ERR); 597 } 598 if (!dtj_list_add(c->djc_methods, m)) { 599 dtj_throw_out_of_memory(jenv, 600 "Failed to add static method description"); 601 return (DTJ_ERR); 602 } 603 break; 604 case JFIELD: 605 if (!c) { 606 dtj_throw_illegal_state(jenv, 607 "field description not preceded " 608 "by class description"); 609 return (DTJ_ERR); 610 } 611 f = dtj_java_field_create(jenv, 612 (jfieldID *)table[i].djte_addr, 613 table[i].djte_name, table[i].djte_desc, 614 fieldpool); 615 if (!f) { 616 /* OutOfMemoryError pending */ 617 return (DTJ_ERR); 618 } 619 if (!dtj_list_add(c->djc_fields, f)) { 620 dtj_throw_out_of_memory(jenv, 621 "Failed to add field description"); 622 return (DTJ_ERR); 623 } 624 break; 625 case JFIELD_STATIC: 626 if (!c) { 627 dtj_throw_illegal_state(jenv, 628 "static field description not preceded " 629 "by class description"); 630 return (DTJ_ERR); 631 } 632 f = dtj_java_static_field_create(jenv, 633 (jfieldID *)table[i].djte_addr, 634 table[i].djte_name, table[i].djte_desc, 635 fieldpool); 636 if (!f) { 637 /* OutOfMemoryError pending */ 638 return (DTJ_ERR); 639 } 640 if (!dtj_list_add(c->djc_fields, f)) { 641 dtj_throw_out_of_memory(jenv, 642 "Failed to add static field description"); 643 return (DTJ_ERR); 644 } 645 break; 646 default: 647 dtj_throw_illegal_state(jenv, 648 "Unexpected jni_type_e: %d", table[i].djte_type); 649 return (DTJ_ERR); 650 } 651 } 652 if (c) { 653 /* last class */ 654 if (!dtj_list_add(classes, c)) { 655 dtj_throw_out_of_memory(jenv, 656 "Failed to add class description"); 657 return (DTJ_ERR); 658 } 659 } 660 661 return (DTJ_OK); 662 } 663 664 static dtj_status_t 665 dtj_cache_jni_methods(JNIEnv *jenv, dtj_java_class_t *c) 666 { 667 dtj_java_method_t *method; 668 jmethodID jm; 669 uu_list_walk_t *itr; 670 itr = uu_list_walk_start(c->djc_methods, 0); 671 while ((method = uu_list_walk_next(itr)) != NULL) { 672 if (method->djm_static) { 673 jm = (*jenv)->GetStaticMethodID(jenv, *(c->djc_ptr), 674 method->djm_name, method->djm_signature); 675 } else { 676 jm = (*jenv)->GetMethodID(jenv, *(c->djc_ptr), 677 method->djm_name, method->djm_signature); 678 } 679 if (jm == 0) { 680 /* 681 * The pending NoSuchMethodError gives only the 682 * method name, which is not so helpful for 683 * overloaded methods and methods such as <init> 684 * that have the same name in multiple classes. 685 * Clear the pending error and throw one that 686 * includes the class name and the method 687 * signature. 688 */ 689 jclass jc; 690 char msg[DTJ_MSG_SIZE]; 691 (*jenv)->ExceptionClear(jenv); 692 (void) snprintf(msg, sizeof (msg), "%s %s %s", 693 c->djc_name, method->djm_name, 694 method->djm_signature); 695 696 jc = (*jenv)->FindClass(jenv, 697 "java/lang/NoSuchMethodError"); 698 (*jenv)->ThrowNew(jenv, jc, msg); 699 (*jenv)->DeleteLocalRef(jenv, jc); 700 return (DTJ_ERR); 701 } 702 *(method->djm_ptr) = jm; 703 } 704 uu_list_walk_end(itr); 705 return (DTJ_OK); 706 } 707 708 static dtj_status_t 709 dtj_cache_jni_fields(JNIEnv *jenv, dtj_java_class_t *c) 710 { 711 dtj_java_field_t *field; 712 jfieldID jf; 713 uu_list_walk_t *itr; 714 itr = uu_list_walk_start(c->djc_fields, 0); 715 while ((field = uu_list_walk_next(itr)) != NULL) { 716 if (field->djf_static) { 717 jf = (*jenv)->GetStaticFieldID(jenv, *(c->djc_ptr), 718 field->djf_name, field->djf_type); 719 } else { 720 jf = (*jenv)->GetFieldID(jenv, *(c->djc_ptr), 721 field->djf_name, field->djf_type); 722 } 723 if (jf == 0) { 724 jclass jc; 725 char msg[DTJ_MSG_SIZE]; 726 (*jenv)->ExceptionClear(jenv); 727 (void) snprintf(msg, sizeof (msg), 728 "%s.%s signature: %s", c->djc_name, 729 field->djf_name, field->djf_type); 730 731 jc = (*jenv)->FindClass(jenv, 732 "java/lang/NoSuchFieldError"); 733 (*jenv)->ThrowNew(jenv, jc, msg); 734 (*jenv)->DeleteLocalRef(jenv, jc); 735 return (DTJ_ERR); 736 } 737 *(field->djf_ptr) = jf; 738 } 739 uu_list_walk_end(itr); 740 return (DTJ_OK); 741 } 742 743 744 /* Common utilities */ 745 746 static void 747 dtj_throw(JNIEnv *jenv, jclass jc, const char *fmt, va_list *ap) 748 { 749 char msg[DTJ_MSG_SIZE]; 750 (void) vsnprintf(msg, sizeof (msg), fmt, *ap); 751 (*jenv)->ThrowNew(jenv, jc, msg); 752 } 753 754 void 755 dtj_throw_out_of_memory(JNIEnv *jenv, const char *fmt, ...) 756 { 757 va_list ap; 758 jclass jc; 759 /* 760 * JNI documentation unclear whether NewGlobalRef() can throw 761 * OutOfMemoryError, so we'll make this function safe in case 762 * OutOfMemoryError has already been thrown 763 */ 764 if ((*jenv)->ExceptionCheck(jenv)) { 765 return; 766 } 767 jc = (*jenv)->FindClass(jenv, 768 "java/lang/OutOfMemoryError"); 769 va_start(ap, fmt); 770 dtj_throw(jenv, jc, fmt, &ap); 771 (*jenv)->DeleteLocalRef(jenv, jc); 772 va_end(ap); 773 } 774 775 void 776 dtj_throw_null_pointer(JNIEnv *jenv, const char *fmt, ...) 777 { 778 va_list ap; 779 jclass jc = (*jenv)->FindClass(jenv, 780 "java/lang/NullPointerException"); 781 va_start(ap, fmt); 782 dtj_throw(jenv, jc, fmt, &ap); 783 (*jenv)->DeleteLocalRef(jenv, jc); 784 va_end(ap); 785 } 786 787 void 788 dtj_throw_illegal_state(JNIEnv *jenv, const char *fmt, ...) 789 { 790 va_list ap; 791 jclass jc = (*jenv)->FindClass(jenv, 792 "java/lang/IllegalStateException"); 793 va_start(ap, fmt); 794 dtj_throw(jenv, jc, fmt, &ap); 795 (*jenv)->DeleteLocalRef(jenv, jc); 796 va_end(ap); 797 } 798 799 void 800 dtj_throw_illegal_argument(JNIEnv *jenv, const char *fmt, ...) 801 { 802 va_list ap; 803 jclass jc = (*jenv)->FindClass(jenv, 804 "java/lang/IllegalArgumentException"); 805 va_start(ap, fmt); 806 dtj_throw(jenv, jc, fmt, &ap); 807 (*jenv)->DeleteLocalRef(jenv, jc); 808 va_end(ap); 809 } 810 811 void 812 dtj_throw_no_such_element(JNIEnv *jenv, const char *fmt, ...) 813 { 814 va_list ap; 815 jclass jc = (*jenv)->FindClass(jenv, 816 "java/util/NoSuchElementException"); 817 va_start(ap, fmt); 818 dtj_throw(jenv, jc, fmt, &ap); 819 (*jenv)->DeleteLocalRef(jenv, jc); 820 va_end(ap); 821 } 822 823 void 824 dtj_throw_class_cast(JNIEnv *jenv, const char *fmt, ...) 825 { 826 va_list ap; 827 jclass jc = (*jenv)->FindClass(jenv, 828 "java/lang/ClassCastException"); 829 va_start(ap, fmt); 830 dtj_throw(jenv, jc, fmt, &ap); 831 (*jenv)->DeleteLocalRef(jenv, jc); 832 va_end(ap); 833 } 834 835 void 836 dtj_throw_assertion(JNIEnv *jenv, const char *fmt, ...) 837 { 838 va_list ap; 839 jclass jc = (*jenv)->FindClass(jenv, 840 "java/lang/AssertionError"); 841 va_start(ap, fmt); 842 dtj_throw(jenv, jc, fmt, &ap); 843 (*jenv)->DeleteLocalRef(jenv, jc); 844 va_end(ap); 845 } 846 847 void 848 dtj_throw_resource_limit(JNIEnv *jenv, const char *fmt, ...) 849 { 850 va_list ap; 851 jclass jc = (*jenv)->FindClass(jenv, 852 "org/opensolaris/os/dtrace/ResourceLimitException"); 853 va_start(ap, fmt); 854 dtj_throw(jenv, jc, fmt, &ap); 855 (*jenv)->DeleteLocalRef(jenv, jc); 856 va_end(ap); 857 } 858 859 void 860 dtj_wrap_exception(JNIEnv *jenv, const char *file, int line) 861 { 862 jthrowable e = NULL; 863 jthrowable nx = NULL; 864 jstring jfile = NULL; 865 866 e = (*jenv)->ExceptionOccurred(jenv); 867 if (!e) { 868 return; 869 } 870 871 if (!g_dtj_load_common) { 872 return; 873 } 874 875 (*jenv)->ExceptionClear(jenv); 876 877 /* Unsafe to test while exception pending */ 878 if ((*jenv)->IsInstanceOf(jenv, e, g_nx_jc)) { 879 /* Already wrapped */ 880 (*jenv)->Throw(jenv, e); 881 (*jenv)->DeleteLocalRef(jenv, e); 882 return; 883 } 884 885 jfile = dtj_NewStringNative(jenv, file); 886 if ((*jenv)->ExceptionCheck(jenv)) { 887 /* 888 * Only wrap the exception if possible, otherwise just throw the 889 * original exception. 890 */ 891 (*jenv)->ExceptionClear(jenv); 892 (*jenv)->Throw(jenv, e); 893 (*jenv)->DeleteLocalRef(jenv, e); 894 return; 895 } 896 897 nx = (jthrowable)(*jenv)->NewObject(jenv, g_nx_jc, g_nxinit_jm, 898 jfile, line, e); 899 (*jenv)->DeleteLocalRef(jenv, jfile); 900 if ((*jenv)->ExceptionCheck(jenv)) { 901 (*jenv)->ExceptionClear(jenv); 902 (*jenv)->Throw(jenv, e); 903 (*jenv)->DeleteLocalRef(jenv, e); 904 return; 905 } 906 907 (*jenv)->DeleteLocalRef(jenv, e); 908 (*jenv)->Throw(jenv, nx); 909 (*jenv)->DeleteLocalRef(jenv, nx); 910 } 911 912 /* 913 * Calls the given java object's toString() method and prints the value to 914 * stdout. Useful for debugging. Guaranteed that no exception is pending when 915 * this function returns. 916 */ 917 void 918 dtj_print_object(JNIEnv *jenv, jobject jobj) 919 { 920 jstring jstr; 921 const char *cstr; 922 923 if (!g_dtj_load_common) { 924 dtj_throw_illegal_state(jenv, 925 "dtj_load_common() has not been called"); 926 (*jenv)->ExceptionDescribe(jenv); /* clears the exception */ 927 return; 928 } 929 930 if (!jobj) { 931 (void) printf("null\n"); 932 return; 933 } 934 935 jstr = (*jenv)->CallObjectMethod(jenv, jobj, g_tostring_jm); 936 if ((*jenv)->ExceptionCheck(jenv)) { 937 (*jenv)->ExceptionDescribe(jenv); /* clears the exception */ 938 return; 939 } 940 cstr = (*jenv)->GetStringUTFChars(jenv, jstr, 0); 941 if (cstr) { 942 (void) printf("%s\n", cstr); 943 } else { 944 (*jenv)->ExceptionDescribe(jenv); /* clears the exception */ 945 (*jenv)->DeleteLocalRef(jenv, jstr); 946 return; 947 } 948 (*jenv)->ReleaseStringUTFChars(jenv, jstr, cstr); 949 (*jenv)->DeleteLocalRef(jenv, jstr); 950 } 951 952 jobject 953 dtj_uint64(JNIEnv *jenv, uint64_t u) 954 { 955 int64_t i = (int64_t)u; 956 jobject val64; 957 958 if (i >= 0) { 959 val64 = (*jenv)->CallStaticObjectMethod(jenv, g_bigint_jc, 960 g_bigint_val_jsm, u); 961 } else { 962 jobject tmp; 963 964 u ^= ((uint64_t)0x1 << 63); 965 val64 = (*jenv)->CallStaticObjectMethod(jenv, g_bigint_jc, 966 g_bigint_val_jsm, u); 967 tmp = val64; 968 val64 = (*jenv)->CallObjectMethod(jenv, tmp, 969 g_bigint_setbit_jm, 63); 970 (*jenv)->DeleteLocalRef(jenv, tmp); 971 } 972 973 return (val64); 974 } 975 976 jobject 977 dtj_int128(JNIEnv *jenv, uint64_t high, uint64_t low) 978 { 979 jobject val128; 980 jobject low64; 981 jobject tmp; 982 983 val128 = (*jenv)->CallStaticObjectMethod(jenv, g_bigint_jc, 984 g_bigint_val_jsm, high); 985 tmp = val128; 986 val128 = (*jenv)->CallObjectMethod(jenv, tmp, g_bigint_shl_jm, 64); 987 (*jenv)->DeleteLocalRef(jenv, tmp); 988 low64 = dtj_uint64(jenv, low); 989 tmp = val128; 990 val128 = (*jenv)->CallObjectMethod(jenv, tmp, g_bigint_or_jm, low64); 991 (*jenv)->DeleteLocalRef(jenv, tmp); 992 (*jenv)->DeleteLocalRef(jenv, low64); 993 994 return (val128); 995 } 996 997 jstring 998 dtj_format_string(JNIEnv *jenv, const char *fmt, ...) 999 { 1000 va_list ap; 1001 char str[DTJ_MSG_SIZE]; 1002 1003 jstring jstr = NULL; 1004 1005 va_start(ap, fmt); 1006 (void) vsnprintf(str, sizeof (str), fmt, ap); 1007 va_end(ap); 1008 1009 jstr = dtj_NewStringNative(jenv, str); 1010 /* return NULL if OutOfMemoryError pending */ 1011 return (jstr); 1012 } 1013 1014 jstring 1015 dtj_NewStringNative(JNIEnv *jenv, const char *str) 1016 { 1017 jstring result; 1018 jbyteArray bytes = 0; 1019 int len; 1020 1021 if (!g_dtj_load_common) { 1022 dtj_throw_illegal_state(jenv, 1023 "dtj_load_common() has not been called"); 1024 return (NULL); 1025 } 1026 1027 len = strlen(str); 1028 1029 bytes = (*jenv)->NewByteArray(jenv, len); 1030 if (!bytes) { 1031 return (NULL); /* OutOfMemoryError pending */ 1032 } 1033 (*jenv)->SetByteArrayRegion(jenv, bytes, 0, len, 1034 (jbyte *)str); 1035 if ((*jenv)->ExceptionCheck(jenv)) { 1036 (*jenv)->DeleteLocalRef(jenv, bytes); 1037 return (NULL); /* ArrayIndexOutOfBoundsException pending */ 1038 } 1039 result = (*jenv)->NewObject(jenv, g_string_jc, g_strinit_bytes_jm, 1040 bytes); 1041 (*jenv)->DeleteLocalRef(jenv, bytes); 1042 /* return NULL result if exception pending */ 1043 return (result); 1044 } 1045 1046 char * 1047 dtj_GetStringNativeChars(JNIEnv *jenv, jstring jstr) 1048 { 1049 jbyteArray bytes = NULL; 1050 1051 jint len; 1052 char *result = NULL; 1053 1054 if (!g_dtj_load_common) { 1055 dtj_throw_illegal_state(jenv, 1056 "dtj_load_common() has not been called"); 1057 return (NULL); 1058 } 1059 1060 bytes = (*jenv)->CallObjectMethod(jenv, jstr, g_strbytes_jm); 1061 if ((*jenv)->ExceptionCheck(jenv)) { 1062 return (NULL); /* OutOfMemoryError pending */ 1063 } 1064 /* Does not throw exceptions */ 1065 len = (*jenv)->GetArrayLength(jenv, bytes); 1066 result = malloc(len + 1); 1067 if (!result) { 1068 (*jenv)->DeleteLocalRef(jenv, bytes); 1069 dtj_throw_out_of_memory(jenv, 1070 "could not allocate native chars"); 1071 return (NULL); 1072 } 1073 1074 /* Skip check for ArrayIndexOutOfBoundsException */ 1075 (*jenv)->GetByteArrayRegion(jenv, bytes, 0, len, 1076 (jbyte *)result); 1077 (*jenv)->DeleteLocalRef(jenv, bytes); 1078 result[len] = '\0'; /* NUL-terminate */ 1079 1080 return (result); 1081 } 1082 1083 void 1084 /* ARGSUSED */ 1085 dtj_ReleaseStringNativeChars(JNIEnv *jenv, jstring jstr, const char *str) 1086 { 1087 free((void *)str); 1088 } 1089 1090 char ** 1091 dtj_get_argv(JNIEnv *jenv, jobjectArray args, int *argc) 1092 { 1093 char **argv = NULL; /* return value */ 1094 const char *str; 1095 int i; 1096 1097 jstring jstr = NULL; 1098 1099 if (!g_dtj_load_common) { 1100 dtj_throw_illegal_state(jenv, 1101 "dtj_load_common() has not been called"); 1102 return (NULL); 1103 } 1104 1105 *argc = (*jenv)->GetArrayLength(jenv, args); 1106 /* 1107 * Initialize all string pointers to NULL so that in case of an error 1108 * filling in the array, free_argv() will not attempt to free the 1109 * unallocated elements. Also NULL-terminate the string array for 1110 * functions that expect terminating NULL rather than rely on argc. 1111 */ 1112 argv = uu_zalloc((sizeof (char *)) * (*argc + 1)); 1113 if (!argv) { 1114 dtj_throw_out_of_memory(jenv, "Failed to allocate args array"); 1115 return (NULL); 1116 } 1117 1118 for (i = 0; i < *argc; ++i) { 1119 jstr = (*jenv)->GetObjectArrayElement(jenv, args, i); 1120 if ((*jenv)->ExceptionCheck(jenv)) { 1121 dtj_free_argv(argv); 1122 return (NULL); 1123 } 1124 str = dtj_GetStringNativeChars(jenv, jstr); 1125 if ((*jenv)->ExceptionCheck(jenv)) { 1126 dtj_free_argv(argv); 1127 (*jenv)->DeleteLocalRef(jenv, jstr); 1128 return (NULL); 1129 } 1130 argv[i] = malloc(strlen(str) + 1); 1131 if (!argv[i]) { 1132 dtj_throw_out_of_memory(jenv, "Failed to allocate arg"); 1133 dtj_free_argv(argv); 1134 dtj_ReleaseStringNativeChars(jenv, jstr, str); 1135 (*jenv)->DeleteLocalRef(jenv, jstr); 1136 return (NULL); 1137 } 1138 (void) strcpy(argv[i], str); 1139 dtj_ReleaseStringNativeChars(jenv, jstr, str); 1140 (*jenv)->DeleteLocalRef(jenv, jstr); 1141 jstr = NULL; 1142 } 1143 1144 return (argv); 1145 } 1146 1147 char ** 1148 dtj_make_argv(JNIEnv *jenv, jstring command, int *argc) 1149 { 1150 const char *ws = "\f\n\r\t\v "; 1151 char **argv = NULL; /* return value */ 1152 const char *cmd; /* native command string */ 1153 char *s; /* writable command */ 1154 char *tok; /* token */ 1155 int len; 1156 1157 if (!g_dtj_load_common) { 1158 dtj_throw_illegal_state(jenv, 1159 "dtj_load_common() has not been called"); 1160 return (NULL); 1161 } 1162 1163 if (!command) { 1164 dtj_throw_null_pointer(jenv, "command is null"); 1165 return (NULL); 1166 } else if ((*jenv)->GetStringLength(jenv, command) == 0) { 1167 dtj_throw_illegal_argument(jenv, "command is empty"); 1168 return (NULL); 1169 } 1170 1171 cmd = dtj_GetStringNativeChars(jenv, command); 1172 if ((*jenv)->ExceptionCheck(jenv)) { 1173 return (NULL); 1174 } 1175 len = strlen(cmd); 1176 s = malloc(len + 1); 1177 if (!s) { 1178 dtj_throw_out_of_memory(jenv, 1179 "failed to allocate command string"); 1180 dtj_ReleaseStringNativeChars(jenv, command, cmd); 1181 return (NULL); 1182 } 1183 (void) strcpy(s, cmd); 1184 /* 1185 * Initialize all string pointers to NULL so that in case of an error 1186 * filling in the array, free_argv() will not attempt to free the 1187 * unallocated elements. Also NULL-terminate the string array for 1188 * functions that expect terminating NULL rather than rely on argc. 1189 * Allow for maximum length resulting from single-character tokens 1190 * separated by single spaces. 1191 */ 1192 argv = uu_zalloc(sizeof (char *) * (len / 2 + 1)); 1193 if (!argv) { 1194 dtj_throw_out_of_memory(jenv, "failed to allocate args array"); 1195 free(s); 1196 dtj_ReleaseStringNativeChars(jenv, command, cmd); 1197 return (NULL); 1198 } 1199 1200 *argc = 0; 1201 for (tok = strtok(s, ws); tok != NULL; tok = strtok(NULL, ws)) { 1202 argv[*argc] = malloc(strlen(tok) + 1); 1203 if (!argv[*argc]) { 1204 dtj_throw_out_of_memory(jenv, "Failed to allocate arg"); 1205 dtj_free_argv(argv); 1206 free(s); 1207 dtj_ReleaseStringNativeChars(jenv, command, cmd); 1208 return (NULL); 1209 } 1210 (void) strcpy(argv[(*argc)++], tok); 1211 } 1212 1213 if (*argc == 0) { 1214 dtj_throw_illegal_argument(jenv, "command is blank"); 1215 dtj_free_argv(argv); 1216 free(s); 1217 dtj_ReleaseStringNativeChars(jenv, command, cmd); 1218 return (NULL); 1219 } 1220 1221 free(s); 1222 dtj_ReleaseStringNativeChars(jenv, command, cmd); 1223 return (argv); 1224 } 1225 1226 void 1227 dtj_free_argv(char **argv) 1228 { 1229 if (argv) { 1230 char **s = argv; 1231 while (*s) { 1232 free((void *)*s); 1233 *s++ = NULL; 1234 } 1235 free((void *)argv); 1236 } 1237 } 1238 1239 1240 /* Wrappers for uu_list_t */ 1241 1242 int 1243 /* ARGSUSED */ 1244 dtj_pointer_list_entry_cmp(const void *v1, const void *v2, void *arg) 1245 { 1246 const dtj_pointer_list_entry_t *p1 = v1; 1247 const dtj_pointer_list_entry_t *p2 = v2; 1248 1249 /* 1250 * It is not valid to compare pointers using the relational operators 1251 * unless they point to elements in the same array. 1252 */ 1253 uint64_t x = (uintptr_t)p1->dple_ptr; 1254 uint64_t y = (uintptr_t)p2->dple_ptr; 1255 int rc; 1256 rc = ((x > y) ? 1 : ((x < y) ? -1 : 0)); 1257 return (rc); 1258 } 1259 1260 int 1261 /* ARGSUSED */ 1262 dtj_string_list_entry_cmp(const void *v1, const void *v2, void *arg) 1263 { 1264 const dtj_string_list_entry_t *p1 = v1; 1265 const dtj_string_list_entry_t *p2 = v2; 1266 const char *s1 = p1->dsle_value; 1267 const char *s2 = p2->dsle_value; 1268 if (s1 == NULL) { 1269 return (s2 == NULL ? 0 : -1); 1270 } 1271 if (s2 == NULL) { 1272 return (1); 1273 } 1274 return (strcmp(s1, s2)); 1275 } 1276 1277 static boolean_t 1278 dtj_check_pointer_pool(void) 1279 { 1280 if (g_pointer_pool == NULL) { 1281 g_pointer_pool = uu_list_pool_create("g_pointer_pool", 1282 sizeof (dtj_pointer_list_entry_t), 1283 offsetof(dtj_pointer_list_entry_t, dple_node), 1284 dtj_pointer_list_entry_cmp, 1285 (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0)); 1286 if (g_pointer_pool == NULL) { 1287 return (B_FALSE); 1288 } 1289 } 1290 return (B_TRUE); 1291 } 1292 1293 uu_list_t * 1294 dtj_pointer_list_create(void) 1295 { 1296 uu_list_t *list; 1297 1298 if (!dtj_check_pointer_pool()) { 1299 return (NULL); 1300 } 1301 1302 list = uu_list_create(g_pointer_pool, NULL, 1303 (g_dtj_util_debug ? UU_LIST_DEBUG : 0)); 1304 return (list); 1305 } 1306 1307 dtj_pointer_list_entry_t * 1308 dtj_pointer_list_entry_create(void *p) 1309 { 1310 dtj_pointer_list_entry_t *e; 1311 1312 if (!dtj_check_pointer_pool()) { 1313 return (NULL); 1314 } 1315 1316 e = uu_zalloc(sizeof (dtj_pointer_list_entry_t)); 1317 if (e) { 1318 uu_list_node_init(e, &e->dple_node, g_pointer_pool); 1319 e->dple_ptr = p; 1320 } 1321 return (e); 1322 } 1323 1324 static boolean_t 1325 dtj_check_string_pool(void) 1326 { 1327 if (g_string_pool == NULL) { 1328 g_string_pool = uu_list_pool_create("g_string_pool", 1329 sizeof (dtj_string_list_entry_t), 1330 offsetof(dtj_string_list_entry_t, dsle_node), 1331 dtj_string_list_entry_cmp, 1332 (g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0)); 1333 if (g_string_pool == NULL) { 1334 return (B_FALSE); 1335 } 1336 } 1337 return (B_TRUE); 1338 } 1339 1340 uu_list_t * 1341 dtj_string_list_create(void) 1342 { 1343 uu_list_t *list; 1344 1345 if (!dtj_check_string_pool()) { 1346 return (NULL); 1347 } 1348 1349 list = uu_list_create(g_string_pool, NULL, 1350 (g_dtj_util_debug ? UU_LIST_DEBUG : 0)); 1351 return (list); 1352 } 1353 1354 dtj_string_list_entry_t * 1355 dtj_string_list_entry_create(const char *s) 1356 { 1357 dtj_string_list_entry_t *e; 1358 1359 if (!dtj_check_string_pool()) { 1360 return (NULL); 1361 } 1362 1363 e = uu_zalloc(sizeof (dtj_string_list_entry_t)); 1364 if (e) { 1365 uu_list_node_init(e, &e->dsle_node, g_string_pool); 1366 if (s) { 1367 e->dsle_value = malloc(strlen(s) + 1); 1368 if (e->dsle_value) { 1369 (void) strcpy(e->dsle_value, s); 1370 } else { 1371 uu_list_node_fini(e, &e->dsle_node, 1372 g_string_pool); 1373 uu_free(e); 1374 e = NULL; 1375 } 1376 } 1377 } 1378 return (e); 1379 } 1380 1381 void 1382 dtj_pointer_list_entry_destroy(void *v, 1383 dtj_value_destroy_f *value_destroy, void *arg) 1384 { 1385 if (v) { 1386 dtj_pointer_list_entry_t *e = v; 1387 if (value_destroy) { 1388 value_destroy(e->dple_ptr, arg); 1389 } 1390 uu_list_node_fini(e, &e->dple_node, g_pointer_pool); 1391 e->dple_ptr = NULL; 1392 uu_free(v); 1393 } 1394 } 1395 1396 void 1397 /* ARGSUSED */ 1398 dtj_string_list_entry_destroy(void *v, void *arg) 1399 { 1400 if (v) { 1401 dtj_string_list_entry_t *e = v; 1402 free(e->dsle_value); 1403 uu_list_node_fini(e, &e->dsle_node, g_string_pool); 1404 e->dsle_value = NULL; 1405 uu_free(v); 1406 } 1407 } 1408 1409 void 1410 dtj_list_clear(uu_list_t *list, dtj_value_destroy_f *value_destroy, 1411 void *arg) 1412 { 1413 void *cookie; /* needed for uu_list_teardown */ 1414 void *value; 1415 1416 if (!list) { 1417 return; 1418 } 1419 1420 cookie = NULL; 1421 if (value_destroy) { 1422 while ((value = uu_list_teardown(list, &cookie)) != NULL) { 1423 value_destroy(value, arg); 1424 } 1425 } else { 1426 while ((value = uu_list_teardown(list, &cookie)) != NULL) { 1427 } 1428 } 1429 } 1430 1431 void 1432 dtj_list_destroy(uu_list_t *list, 1433 dtj_value_destroy_f *value_destroy, void *arg) 1434 { 1435 dtj_list_clear(list, value_destroy, arg); 1436 uu_list_destroy(list); 1437 } 1438 1439 void 1440 dtj_pointer_list_clear(uu_list_t *list, 1441 dtj_value_destroy_f *value_destroy, void *arg) 1442 { 1443 void *cookie; /* needed for uu_list_teardown */ 1444 dtj_pointer_list_entry_t *e; 1445 1446 if (!list) { 1447 return; 1448 } 1449 1450 cookie = NULL; 1451 while ((e = uu_list_teardown(list, &cookie)) != NULL) { 1452 dtj_pointer_list_entry_destroy(e, value_destroy, arg); 1453 } 1454 } 1455 1456 void 1457 dtj_pointer_list_destroy(uu_list_t *list, 1458 dtj_value_destroy_f *value_destroy, void *arg) 1459 { 1460 dtj_pointer_list_clear(list, value_destroy, arg); 1461 uu_list_destroy(list); 1462 } 1463 1464 void 1465 dtj_string_list_clear(uu_list_t *list) 1466 { 1467 dtj_list_clear(list, dtj_string_list_entry_destroy, NULL); 1468 } 1469 1470 void 1471 dtj_string_list_destroy(uu_list_t *list) 1472 { 1473 dtj_list_destroy(list, dtj_string_list_entry_destroy, NULL); 1474 } 1475 1476 boolean_t 1477 dtj_list_empty(uu_list_t *list) 1478 { 1479 return (uu_list_numnodes(list) == 0); 1480 } 1481 1482 boolean_t 1483 dtj_list_add(uu_list_t *list, void *value) 1484 { 1485 return (uu_list_insert_before(list, NULL, value) == 0); 1486 } 1487 1488 boolean_t 1489 dtj_pointer_list_add(uu_list_t *list, void *p) 1490 { 1491 dtj_pointer_list_entry_t *e = dtj_pointer_list_entry_create(p); 1492 if (!e) { 1493 return (B_FALSE); 1494 } 1495 return (dtj_list_add(list, e)); 1496 } 1497 1498 void * 1499 dtj_pointer_list_walk_next(uu_list_walk_t *itr) 1500 { 1501 dtj_pointer_list_entry_t *e = uu_list_walk_next(itr); 1502 if (!e) { 1503 return (DTJ_INVALID_PTR); 1504 } 1505 return (e->dple_ptr); 1506 } 1507 1508 void * 1509 dtj_pointer_list_first(uu_list_t *list) 1510 { 1511 dtj_pointer_list_entry_t *e = uu_list_first(list); 1512 if (!e) { 1513 /* NULL is a valid value; use -1 for invalid */ 1514 return (DTJ_INVALID_PTR); 1515 } 1516 return (e->dple_ptr); 1517 } 1518 1519 void * 1520 dtj_pointer_list_last(uu_list_t *list) 1521 { 1522 dtj_pointer_list_entry_t *e = uu_list_last(list); 1523 if (!e) { 1524 /* NULL is a valid value; use -1 for invalid */ 1525 return (DTJ_INVALID_PTR); 1526 } 1527 return (e->dple_ptr); 1528 } 1529 1530 boolean_t 1531 dtj_string_list_add(uu_list_t *list, const char *s) 1532 { 1533 dtj_string_list_entry_t *e = dtj_string_list_entry_create(s); 1534 if (!e) { 1535 return (B_FALSE); 1536 } 1537 return (dtj_list_add(list, e)); 1538 } 1539 1540 const char * 1541 dtj_string_list_walk_next(uu_list_walk_t *itr) 1542 { 1543 dtj_string_list_entry_t *e = uu_list_walk_next(itr); 1544 if (!e) { 1545 return (DTJ_INVALID_STR); 1546 } 1547 return (e->dsle_value); 1548 } 1549 1550 const char * 1551 dtj_string_list_first(uu_list_t *list) 1552 { 1553 dtj_string_list_entry_t *e = uu_list_first(list); 1554 if (!e) { 1555 /* NULL is a valid string value; use -1 for invalid */ 1556 return (DTJ_INVALID_STR); 1557 } 1558 return (e->dsle_value); 1559 } 1560 1561 const char * 1562 dtj_string_list_last(uu_list_t *list) 1563 { 1564 dtj_string_list_entry_t *e = uu_list_last(list); 1565 if (!e) { 1566 /* NULL is a valid string value; use -1 for invalid */ 1567 return (DTJ_INVALID_STR); 1568 } 1569 return (e->dsle_value); 1570 } 1571