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