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