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 <stdio.h> 30 #include <ctype.h> 31 #include <limits.h> 32 #include <errno.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <strings.h> 36 #include <sys/wait.h> 37 #include <limits.h> 38 #include <signal.h> 39 #include <libproc.h> 40 #include <pthread.h> 41 #include <dtrace_jni.h> 42 43 /* 44 * Implements the work done in the running consumer loop. The native Java 45 * methods (JNI layer) are implemented in dtrace_jni.c. 46 */ 47 48 /* Record handler passed to dtrace_work() */ 49 static int dtj_chewrec(const dtrace_probedata_t *, const dtrace_recdesc_t *, 50 void *); 51 /* Probe data handler passed to dtrace_work() */ 52 static int dtj_chew(const dtrace_probedata_t *, void *); 53 54 /* Processes requests from LocalConsumer enqueued during dtrace_sleep() */ 55 static dtj_status_t dtj_process_requests(dtj_java_consumer_t *); 56 57 /* 58 * Callback handlers set in dtj_set_callback_handlers(), called from libdtrace 59 * in the consumer loop (from dtrace_work()) 60 */ 61 static int dtj_drophandler(const dtrace_dropdata_t *, void *); 62 static int dtj_errhandler(const dtrace_errdata_t *, void *); 63 static void dtj_prochandler(struct ps_prochandle *, const char *, void *); 64 static int dtj_setopthandler(const dtrace_setoptdata_t *, void *); 65 /* 66 * Buffered output handler called from libdtrace in both the consumer loop (from 67 * dtrace_work()) and the get_aggregate() function (from 68 * dtrace_aggregate_print()). 69 */ 70 static int dtj_bufhandler(const dtrace_bufdata_t *, void *); 71 72 /* Conversion of libdtrace data into Java Objects */ 73 static jobject dtj_recdata(dtj_java_consumer_t *, uint32_t, caddr_t); 74 static jobject dtj_bytedata(JNIEnv *, uint32_t, caddr_t); 75 static jobject dtj_new_stack_record(const caddr_t, const dtrace_recdesc_t *, 76 dtj_java_consumer_t *); 77 static jobject dtj_new_probedata_stack_record(const dtrace_probedata_t *, 78 const dtrace_recdesc_t *, dtj_java_consumer_t *); 79 /* Aggregation data */ 80 static jobject dtj_new_tuple_stack_record(const dtrace_aggdata_t *, 81 const dtrace_recdesc_t *, const char *, dtj_java_consumer_t *); 82 static jobject dtj_new_distribution(const dtrace_aggdata_t *, 83 const dtrace_recdesc_t *, dtj_java_consumer_t *); 84 static jobject dtj_new_aggval(dtj_java_consumer_t *, const dtrace_aggdata_t *, 85 const dtrace_recdesc_t *); 86 static int64_t dtj_average(caddr_t, uint64_t); 87 static int64_t dtj_avg_total(caddr_t, uint64_t); 88 static int64_t dtj_avg_count(caddr_t); 89 90 /* Aggregation functions */ 91 static void dtj_aggwalk_init(dtj_java_consumer_t *); 92 static int dtj_agghandler(const dtrace_bufdata_t *, dtj_java_consumer_t *); 93 static boolean_t dtj_is_included(const dtrace_aggdata_t *, 94 dtj_java_consumer_t *); 95 static void dtj_attach_frames(dtj_java_consumer_t *, jobject, 96 jobjectArray); 97 static boolean_t dtj_is_stack_action(dtrace_actkind_t); 98 static int dtj_clear(const dtrace_aggdata_t *, void *); 99 100 /* 101 * The consumer loop needs to protect calls to libdtrace functions with a global 102 * lock. JNI native method calls in dtrace_jni.c are already protected and do 103 * not need this function. 104 */ 105 dtj_status_t 106 dtj_get_dtrace_error(dtj_java_consumer_t *jc, dtj_error_t *e) 107 { 108 JNIEnv *jenv = jc->dtjj_jenv; 109 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 110 111 /* Grab global lock */ 112 (*jenv)->MonitorEnter(jenv, g_caller_jc); 113 if ((*jenv)->ExceptionCheck(jenv)) { 114 WRAP_EXCEPTION(jenv); 115 return (DTJ_ERR); 116 } 117 e->dtje_number = dtrace_errno(dtp); 118 e->dtje_message = dtrace_errmsg(dtp, e->dtje_number); 119 (*jenv)->MonitorExit(jenv, g_caller_jc); 120 if ((*jenv)->ExceptionCheck(jenv)) { 121 WRAP_EXCEPTION(jenv); 122 return (DTJ_ERR); 123 } 124 return (DTJ_OK); 125 } 126 127 /* 128 * Protected by global lock (LocalConsumer.class) that protects call to 129 * Java_org_opensolaris_os_dtrace_LocalConsumer__1go() 130 */ 131 dtj_status_t 132 dtj_set_callback_handlers(dtj_java_consumer_t *jc) 133 { 134 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 135 dtrace_optval_t optval; 136 137 /* 138 * The user argument to the bufhandler is the lookup key used to obtain 139 * the thread-specific java consumer. The java consumer contains JNI 140 * state specific to either the consumer loop or the getAggregate() 141 * call. 142 */ 143 if (dtrace_handle_buffered(dtp, &dtj_bufhandler, NULL) == -1) { 144 dtj_throw_dtrace_exception(jc, 145 "failed to establish buffered handler: %s", 146 dtrace_errmsg(dtp, dtrace_errno(dtp))); 147 return (DTJ_ERR); 148 } 149 150 if (dtrace_handle_drop(dtp, &dtj_drophandler, NULL) == -1) { 151 dtj_throw_dtrace_exception(jc, 152 "failed to establish drop handler: %s", 153 dtrace_errmsg(dtp, dtrace_errno(dtp))); 154 return (DTJ_ERR); 155 } 156 157 if (dtrace_handle_err(dtp, &dtj_errhandler, NULL) == -1) { 158 dtj_throw_dtrace_exception(jc, 159 "failed to establish error handler: %s", 160 dtrace_errmsg(dtp, dtrace_errno(dtp))); 161 return (DTJ_ERR); 162 } 163 164 if (dtrace_handle_proc(dtp, &dtj_prochandler, NULL) == -1) { 165 dtj_throw_dtrace_exception(jc, 166 "failed to establish proc handler: %s", 167 dtrace_errmsg(dtp, dtrace_errno(dtp))); 168 return (DTJ_ERR); 169 } 170 171 if (dtrace_getopt(dtp, "flowindent", &optval) == -1) { 172 dtj_throw_dtrace_exception(jc, 173 "couldn't get option %s: %s", "flowindent", 174 dtrace_errmsg(dtp, dtrace_errno(dtp))); 175 return (DTJ_ERR); 176 } 177 178 jc->dtjj_consumer->dtjc_flow = (optval != DTRACEOPT_UNSET); 179 180 if (dtrace_handle_setopt(dtp, &dtj_setopthandler, NULL) == -1) { 181 dtj_throw_dtrace_exception(jc, 182 "failed to establish setopt handler: %s", 183 dtrace_errmsg(dtp, dtrace_errno(dtp))); 184 return (DTJ_ERR); 185 } 186 187 return (DTJ_OK); 188 } 189 190 static int 191 /* ARGSUSED */ 192 dtj_drophandler(const dtrace_dropdata_t *data, void *arg) 193 { 194 dtj_java_consumer_t *jc; 195 JNIEnv *jenv; 196 197 const char *dropkind; 198 199 jstring msg = NULL; 200 jstring kind = NULL; 201 jobject drop = NULL; 202 203 jc = pthread_getspecific(g_dtj_consumer_key); 204 jenv = jc->dtjj_jenv; 205 206 msg = dtj_NewStringNative(jenv, data->dtdda_msg); 207 if ((*jenv)->ExceptionCheck(jenv)) { 208 return (DTRACE_HANDLE_ABORT); 209 } 210 switch (data->dtdda_kind) { 211 case DTRACEDROP_PRINCIPAL: 212 dropkind = "PRINCIPAL"; 213 break; 214 case DTRACEDROP_AGGREGATION: 215 dropkind = "AGGREGATION"; 216 break; 217 case DTRACEDROP_DYNAMIC: 218 dropkind = "DYNAMIC"; 219 break; 220 case DTRACEDROP_DYNRINSE: 221 dropkind = "DYNRINSE"; 222 break; 223 case DTRACEDROP_DYNDIRTY: 224 dropkind = "DYNDIRTY"; 225 break; 226 case DTRACEDROP_SPEC: 227 dropkind = "SPEC"; 228 break; 229 case DTRACEDROP_SPECBUSY: 230 dropkind = "SPECBUSY"; 231 break; 232 case DTRACEDROP_SPECUNAVAIL: 233 dropkind = "SPECUNAVAIL"; 234 break; 235 case DTRACEDROP_STKSTROVERFLOW: 236 dropkind = "STKSTROVERFLOW"; 237 break; 238 case DTRACEDROP_DBLERROR: 239 dropkind = "DBLERROR"; 240 break; 241 default: 242 dropkind = "UNKNOWN"; 243 } 244 kind = (*jenv)->NewStringUTF(jenv, dropkind); 245 if ((*jenv)->ExceptionCheck(jenv)) { 246 (*jenv)->DeleteLocalRef(jenv, msg); 247 return (DTRACE_HANDLE_ABORT); 248 } 249 drop = (*jenv)->NewObject(jenv, g_drop_jc, g_dropinit_jm, 250 data->dtdda_cpu, kind, data->dtdda_drops, data->dtdda_total, msg); 251 (*jenv)->DeleteLocalRef(jenv, kind); 252 (*jenv)->DeleteLocalRef(jenv, msg); 253 if ((*jenv)->ExceptionCheck(jenv)) { 254 return (DTRACE_HANDLE_ABORT); 255 } 256 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, g_drop_jm, drop); 257 (*jenv)->DeleteLocalRef(jenv, drop); 258 if ((*jenv)->ExceptionCheck(jenv)) { 259 return (DTRACE_HANDLE_ABORT); 260 } 261 262 return (DTRACE_HANDLE_OK); 263 } 264 265 static int 266 /* ARGSUSED */ 267 dtj_errhandler(const dtrace_errdata_t *data, void *arg) 268 { 269 dtj_java_consumer_t *jc; 270 JNIEnv *jenv; 271 272 const char *f; 273 int64_t addr; 274 275 jobject probe = NULL; 276 jstring fault = NULL; 277 jstring msg = NULL; 278 jobject error = NULL; 279 280 jc = pthread_getspecific(g_dtj_consumer_key); 281 jenv = jc->dtjj_jenv; 282 283 probe = dtj_new_probedesc(jc, data->dteda_pdesc); 284 if (!probe) { 285 return (DTRACE_HANDLE_ABORT); 286 } 287 f = dtj_get_fault_name(data->dteda_fault); 288 if (f) { 289 fault = (*jenv)->NewStringUTF(jenv, f); 290 if ((*jenv)->ExceptionCheck(jenv)) { 291 (*jenv)->DeleteLocalRef(jenv, probe); 292 return (DTRACE_HANDLE_ABORT); 293 } 294 } 295 switch (data->dteda_fault) { 296 case DTRACEFLT_BADADDR: 297 case DTRACEFLT_BADALIGN: 298 addr = data->dteda_addr; 299 break; 300 default: 301 addr = -1; 302 } 303 msg = dtj_NewStringNative(jenv, data->dteda_msg); 304 if ((*jenv)->ExceptionCheck(jenv)) { 305 (*jenv)->DeleteLocalRef(jenv, probe); 306 (*jenv)->DeleteLocalRef(jenv, fault); 307 return (DTRACE_HANDLE_ABORT); 308 } 309 error = (*jenv)->NewObject(jenv, g_error_jc, g_errinit_jm, 310 probe, 311 data->dteda_edesc->dtepd_epid, 312 data->dteda_cpu, 313 data->dteda_action, 314 data->dteda_offset, 315 fault, addr, msg); 316 (*jenv)->DeleteLocalRef(jenv, msg); 317 (*jenv)->DeleteLocalRef(jenv, fault); 318 (*jenv)->DeleteLocalRef(jenv, probe); 319 if ((*jenv)->ExceptionCheck(jenv)) { 320 return (DTRACE_HANDLE_ABORT); 321 } 322 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, g_error_jm, error); 323 (*jenv)->DeleteLocalRef(jenv, error); 324 if ((*jenv)->ExceptionCheck(jenv)) { 325 return (DTRACE_HANDLE_ABORT); 326 } 327 328 return (DTRACE_HANDLE_OK); 329 } 330 331 /* 332 * Since the function signature does not allow us to return an abort signal, we 333 * need to temporarily clear any pending exception before returning, since 334 * without the abort we can't guarantee that the exception will be checked in 335 * time to prevent invalid JNI function calls. 336 */ 337 static void 338 /* ARGSUSED */ 339 dtj_prochandler(struct ps_prochandle *P, const char *msg, void *arg) 340 { 341 dtj_java_consumer_t *jc; 342 JNIEnv *jenv; 343 344 const psinfo_t *prp = Ppsinfo(P); 345 int pid = Pstatus(P)->pr_pid; 346 int signal = -1; 347 char signame[SIG2STR_MAX]; 348 const char *statusname; 349 int exit = INT_MAX; /* invalid initial status */ 350 351 jstring status = NULL; 352 jstring signalName = NULL; 353 jstring message = NULL; 354 jobject process = NULL; 355 356 jc = pthread_getspecific(g_dtj_consumer_key); 357 jenv = jc->dtjj_jenv; 358 359 switch (Pstate(P)) { 360 case PS_RUN: 361 statusname = "RUN"; 362 break; 363 case PS_STOP: 364 statusname = "STOP"; 365 break; 366 case PS_UNDEAD: 367 statusname = "UNDEAD"; 368 if (prp != NULL) { 369 exit = WEXITSTATUS(prp->pr_wstat); 370 } 371 if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { 372 signal = WTERMSIG(prp->pr_wstat); 373 (void) proc_signame(signal, signame, sizeof (signame)); 374 signalName = (*jenv)->NewStringUTF(jenv, signame); 375 if ((*jenv)->ExceptionCheck(jenv)) { 376 goto proc_end; 377 } 378 } 379 ++jc->dtjj_consumer->dtjc_procs_ended; 380 break; 381 case PS_LOST: 382 statusname = "LOST"; 383 ++jc->dtjj_consumer->dtjc_procs_ended; 384 break; 385 case PS_DEAD: 386 /* 387 * PS_DEAD not handled by dtrace.c prochandler, still this is a 388 * case of process termination and it can't hurt to handle it. 389 */ 390 statusname = "DEAD"; 391 ++jc->dtjj_consumer->dtjc_procs_ended; 392 break; 393 default: 394 /* 395 * Unexpected, but erring on the side of tolerance by not 396 * crashing the consumer. Failure to notify listeners of 397 * process state not handled by the dtrace.c prochandler does 398 * not seem serious. 399 */ 400 return; 401 } 402 403 status = (*jenv)->NewStringUTF(jenv, statusname); 404 if ((*jenv)->ExceptionCheck(jenv)) { 405 (*jenv)->DeleteLocalRef(jenv, signalName); 406 goto proc_end; 407 } 408 if (msg) { 409 message = dtj_NewStringNative(jenv, msg); 410 if (!message) { 411 (*jenv)->DeleteLocalRef(jenv, status); 412 (*jenv)->DeleteLocalRef(jenv, signalName); 413 goto proc_end; 414 } 415 } 416 process = (*jenv)->NewObject(jenv, g_process_jc, g_procinit_jm, 417 pid, status, signal, signalName, NULL, message); 418 (*jenv)->DeleteLocalRef(jenv, status); 419 (*jenv)->DeleteLocalRef(jenv, signalName); 420 (*jenv)->DeleteLocalRef(jenv, message); 421 if ((*jenv)->ExceptionCheck(jenv)) { 422 goto proc_end; 423 } 424 if (exit != INT_MAX) { 425 /* valid exit status */ 426 (*jenv)->CallVoidMethod(jenv, process, g_procexit_jm, exit); 427 if ((*jenv)->ExceptionCheck(jenv)) { 428 (*jenv)->DeleteLocalRef(jenv, process); 429 goto proc_end; 430 } 431 } 432 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, g_proc_jm, process); 433 (*jenv)->DeleteLocalRef(jenv, process); 434 435 proc_end: 436 437 if ((*jenv)->ExceptionCheck(jenv)) { 438 /* 439 * Save the exception so we can rethrow it later when it's safe. 440 */ 441 if (!jc->dtjj_exception) { 442 jthrowable e = (*jenv)->ExceptionOccurred(jenv); 443 jc->dtjj_exception = e; 444 } 445 (*jenv)->ExceptionClear(jenv); 446 } 447 } 448 449 static int 450 /* ARGSUSED */ 451 dtj_setopthandler(const dtrace_setoptdata_t *data, void *arg) 452 { 453 dtj_java_consumer_t *jc; 454 455 jc = pthread_getspecific(g_dtj_consumer_key); 456 if (strcmp(data->dtsda_option, "flowindent") == 0) { 457 jc->dtjj_consumer->dtjc_flow = 458 (data->dtsda_newval != DTRACEOPT_UNSET); 459 } 460 return (DTRACE_HANDLE_OK); 461 } 462 463 /* 464 * Most of this function lifted from libdtrace/common/dt_consume.c 465 * dt_print_bytes(). 466 */ 467 static jobject 468 dtj_bytedata(JNIEnv *jenv, uint32_t nbytes, caddr_t addr) 469 { 470 /* 471 * If the byte stream is a series of printable characters, followed by 472 * a terminating byte, we print it out as a string. Otherwise, we 473 * assume that it's something else and just print the bytes. 474 */ 475 int i, j; 476 char *c = addr; 477 478 jobject jobj = NULL; /* return value */ 479 480 if (nbytes == 0) { 481 return ((*jenv)->NewStringUTF(jenv, "")); 482 } 483 484 for (i = 0; i < nbytes; i++) { 485 /* 486 * We define a "printable character" to be one for which 487 * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 488 * or a character which is either backspace or the bell. 489 * Backspace and the bell are regrettably special because 490 * they fail the first two tests -- and yet they are entirely 491 * printable. These are the only two control characters that 492 * have meaning for the terminal and for which isprint(3C) and 493 * isspace(3C) return 0. 494 */ 495 if (isprint(c[i]) || isspace(c[i]) || 496 c[i] == '\b' || c[i] == '\a') 497 continue; 498 499 if (c[i] == '\0' && i > 0) { 500 /* 501 * This looks like it might be a string. Before we 502 * assume that it is indeed a string, check the 503 * remainder of the byte range; if it contains 504 * additional non-nul characters, we'll assume that 505 * it's a binary stream that just happens to look like 506 * a string. 507 */ 508 for (j = i + 1; j < nbytes; j++) { 509 if (c[j] != '\0') 510 break; 511 } 512 513 if (j != nbytes) 514 break; 515 516 /* It's a string */ 517 return (dtj_NewStringNative(jenv, (char *)addr)); 518 } 519 520 break; 521 } 522 523 if (i == nbytes) { 524 /* 525 * The byte range is all printable characters, but there is 526 * no trailing nul byte. We'll assume that it's a string. 527 */ 528 char *s = malloc(nbytes + 1); 529 if (!s) { 530 dtj_throw_out_of_memory(jenv, 531 "failed to allocate string value"); 532 return (NULL); 533 } 534 (void) strncpy(s, c, nbytes); 535 s[nbytes] = '\0'; 536 jobj = dtj_NewStringNative(jenv, s); 537 free(s); 538 return (jobj); 539 } 540 541 /* return byte array */ 542 jobj = (*jenv)->NewByteArray(jenv, nbytes); 543 if ((*jenv)->ExceptionCheck(jenv)) { 544 return (NULL); 545 } 546 (*jenv)->SetByteArrayRegion(jenv, (jbyteArray)jobj, 0, nbytes, 547 (const jbyte *)c); 548 if ((*jenv)->ExceptionCheck(jenv)) { 549 WRAP_EXCEPTION(jenv); 550 (*jenv)->DeleteLocalRef(jenv, jobj); 551 return (NULL); 552 } 553 return (jobj); 554 } 555 556 /* 557 * Return NULL if memory could not be allocated (OutOfMemoryError is thrown in 558 * that case). 559 */ 560 static jobject 561 dtj_recdata(dtj_java_consumer_t *jc, uint32_t size, caddr_t addr) 562 { 563 JNIEnv *jenv = jc->dtjj_jenv; 564 jobject jobj; 565 566 switch (size) { 567 case 1: 568 jobj = (*jenv)->NewObject(jenv, g_byte_jc, 569 g_byteinit_jm, *((char *)addr)); 570 break; 571 case 2: 572 jobj = (*jenv)->NewObject(jenv, g_short_jc, 573 /* LINTED - alignment */ 574 g_shortinit_jm, *((int16_t *)addr)); 575 break; 576 case 4: 577 jobj = (*jenv)->NewObject(jenv, g_int_jc, 578 /* LINTED - alignment */ 579 g_intinit_jm, *((int32_t *)addr)); 580 break; 581 case 8: 582 jobj = (*jenv)->NewObject(jenv, g_long_jc, 583 /* LINTED - alignment */ 584 g_longinit_jm, *((int64_t *)addr)); 585 break; 586 default: 587 jobj = dtj_bytedata(jenv, size, addr); 588 break; 589 } 590 591 return (jobj); 592 } 593 594 /* 595 * This is the record handling function passed to dtrace_work(). It differs 596 * from the bufhandler registered with dtrace_handle_buffered() as follows: 597 * 598 * 1. It does not have access to libdtrace formatted output. 599 * 2. It is called once for every D program statement, not for every 600 * output-producing D action or aggregation record. A statement may be a 601 * variable assignment, having no size and producing no output. 602 * 3. It is called for the D exit() action; the bufhandler is not. 603 * 4. In response to the printa() action, it is called with a record having an 604 * action of type DTRACEACT_PRINTA. The bufhandler never sees that action 605 * value. It only sees the output-producing aggregation records. 606 * 5. It is called with a NULL record at the end of each probedata. 607 */ 608 static int 609 dtj_chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, 610 void *arg) 611 { 612 dtj_java_consumer_t *jc = arg; 613 JNIEnv *jenv = jc->dtjj_jenv; 614 615 const dtrace_eprobedesc_t *edesc = data->dtpda_edesc; 616 dtrace_actkind_t act; 617 int r; 618 619 /* 620 * Update the record index to that of the current record, or to that of 621 * the last record if rec is NULL (signalling end of probe data). 622 */ 623 if (rec == NULL) { 624 r = edesc->dtepd_nrecs; /* end of probe data */ 625 } else { 626 /* 627 * This record handler is called once for the printf() action, 628 * but there may be multiple records in the probedata 629 * corresponding to the unformatted elements of that printf(). 630 * We don't know ahead of time how many probedata records 631 * libdtrace will consume to produce output for one printf() 632 * action, so we look back at the previous call to dtj_chewrec() 633 * to see how many probedata records were consumed. All 634 * non-null elements in the range from the previous record index 635 * up to and not including the current record index are assumed 636 * to be unformatted printf() elements, and will be attached to 637 * the PrintfRecord from the previous call. A null element in 638 * that range is the result of a D program statement preceding 639 * the printf() that is not a D action. These generate 640 * probedata records accounted for by the null placeholder, but 641 * do not advance the probedata offset and are not part of the 642 * subsequent printf(). 643 * 644 * If rec->dtrd_size == 0, the record represents a D program 645 * statement that is not a D action. It has no size and does 646 * not advance the offset in the probedata. Handle it normally 647 * without special-casing or premature return, since in all 648 * cases we look at the previous record later in this function. 649 */ 650 for (r = jc->dtjj_consumer->dtjc_probedata_rec_i; 651 ((r < edesc->dtepd_nrecs) && 652 (edesc->dtepd_rec[r].dtrd_offset < rec->dtrd_offset)); 653 ++r) { 654 } 655 } 656 657 /* 658 * Attach the Java representations of the libdtrace data elements 659 * pertaining to the previous call to this record handler to the 660 * previous Java Record. (All data elements belonging to the current 661 * probedata are added to a single list by the probedata consumer 662 * function dtj_chew() before this record consumer function is ever 663 * called.) For example, if the previous Record was generated by the 664 * printf() action, and dtj_chew() listed 3 records for its 3 665 * unformatted elements, those 3 libdtrace records comprise 1 666 * PrintfRecord. Note that we cannot know how many data elements apply 667 * to the current rec until we find out the data index where the next 668 * rec starts. (The knowledge of how many probedata records to consume 669 * is private to libdtrace.) 670 */ 671 if (jc->dtjj_consumer->dtjc_probedata_act == DTRACEACT_PRINTF) { 672 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 673 g_pdataattach_jm, 674 jc->dtjj_consumer->dtjc_probedata_rec_i, r - 1); 675 if ((*jenv)->ExceptionCheck(jenv)) { 676 WRAP_EXCEPTION(jenv); 677 return (DTRACE_CONSUME_ABORT); 678 } 679 } 680 681 if (rec == NULL) { 682 /* 683 * End of probe data. Notify listeners of the new ProbeData 684 * instance. 685 */ 686 if (jc->dtjj_probedata) { 687 /* previous probedata */ 688 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 689 g_pdataclear_jm); 690 if ((*jenv)->ExceptionCheck(jenv)) { 691 WRAP_EXCEPTION(jenv); 692 return (DTRACE_CONSUME_ABORT); 693 } 694 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 695 g_pdatanext_jm, jc->dtjj_probedata); 696 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_probedata); 697 jc->dtjj_probedata = NULL; 698 if ((*jenv)->ExceptionCheck(jenv)) { 699 /* 700 * Do not wrap exception thrown from 701 * ConsumerListener. 702 */ 703 return (DTRACE_CONSUME_ABORT); 704 } 705 } 706 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_printa_buffer); 707 jc->dtjj_printa_buffer = NULL; 708 return (DTRACE_CONSUME_NEXT); 709 } 710 711 act = rec->dtrd_action; 712 713 /* Set previous record action and data index to current */ 714 jc->dtjj_consumer->dtjc_probedata_act = act; 715 jc->dtjj_consumer->dtjc_probedata_rec_i = r; 716 717 switch (act) { 718 case DTRACEACT_DIFEXPR: 719 if (rec->dtrd_size == 0) { 720 /* 721 * The current record is not a D action, but a program 722 * statement such as a variable assignment, not to be 723 * confused with the trace() action. 724 */ 725 break; 726 } 727 /* 728 * Add a Record for the trace() action that references the 729 * native probedata element listed at the current index. 730 */ 731 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 732 g_pdataadd_trace_jm, 733 jc->dtjj_consumer->dtjc_probedata_rec_i); 734 if ((*jenv)->ExceptionCheck(jenv)) { 735 WRAP_EXCEPTION(jenv); 736 return (DTRACE_CONSUME_ABORT); 737 } 738 break; 739 case DTRACEACT_PRINTF: 740 /* 741 * Just add an empty PrintfRecord for now. We'll attach the 742 * unformatted elements in a subsequent call to this function. 743 * (We don't know how many there will be.) 744 */ 745 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 746 g_pdataadd_printf_jm); 747 if ((*jenv)->ExceptionCheck(jenv)) { 748 WRAP_EXCEPTION(jenv); 749 return (DTRACE_CONSUME_ABORT); 750 } 751 /* defer formatted string to dtj_bufhandler() */ 752 break; 753 case DTRACEACT_PRINTA: { 754 jobject jbuf = NULL; 755 756 dtj_aggwalk_init(jc); 757 if ((*jenv)->ExceptionCheck(jenv)) { 758 WRAP_EXCEPTION(jenv); 759 return (DTRACE_CONSUME_ABORT); 760 } 761 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 762 g_pdataadd_printa_jm, 763 jc->dtjj_consumer->dtjc_printa_snaptime, 764 (rec->dtrd_format != 0)); 765 if ((*jenv)->ExceptionCheck(jenv)) { 766 WRAP_EXCEPTION(jenv); 767 return (DTRACE_CONSUME_ABORT); 768 } 769 if (jc->dtjj_printa_buffer == NULL) { 770 /* 771 * Create a StringBuffer to collect the pieces of 772 * formatted output into a single String. 773 */ 774 jbuf = (*jenv)->NewObject(jenv, g_buf_jc, 775 g_bufinit_jm); 776 if (!jbuf) { 777 /* OutOfMemoryError pending */ 778 return (DTRACE_CONSUME_ABORT); 779 } 780 jc->dtjj_printa_buffer = jbuf; 781 } 782 /* defer aggregation records to dtj_bufhandler() */ 783 break; 784 } 785 case DTRACEACT_EXIT: 786 /* 787 * Add a Record for the exit() action that references the native 788 * probedata element listed at the current index. 789 */ 790 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 791 g_pdataadd_exit_jm, 792 jc->dtjj_consumer->dtjc_probedata_rec_i); 793 if ((*jenv)->ExceptionCheck(jenv)) { 794 WRAP_EXCEPTION(jenv); 795 return (DTRACE_CONSUME_ABORT); 796 } 797 return (DTRACE_CONSUME_NEXT); 798 } 799 800 return (DTRACE_CONSUME_THIS); 801 } 802 803 /* 804 * This is the probe handling function passed to dtrace_work(). It is is called 805 * once every time a probe fires. It is the first of all the callbacks for the 806 * current probe. It is followed by multiple callbacks to dtj_chewrec(), one 807 * for each probedata record. Each call to dtj_chewrec() is followed by zero or 808 * more callbacks to the bufhandler, one for each output-producing action or 809 * aggregation record. 810 */ 811 static int 812 dtj_chew(const dtrace_probedata_t *data, void *arg) 813 { 814 dtj_java_consumer_t *jc = arg; 815 JNIEnv *jenv = jc->dtjj_jenv; 816 817 dtrace_eprobedesc_t *edesc; 818 dtrace_probedesc_t *pdesc; 819 dtrace_recdesc_t *rec; 820 int epid; 821 int cpu; 822 int nrecs; 823 int i; 824 825 jobject jpdata = NULL; 826 jobject jprobe = NULL; 827 jobject jflow = NULL; 828 jstring jflowkind = NULL; 829 jobject jobj = NULL; 830 831 edesc = data->dtpda_edesc; 832 epid = (int)edesc->dtepd_epid; 833 pdesc = data->dtpda_pdesc; 834 cpu = (int)data->dtpda_cpu; 835 if ((jprobe = dtj_new_probedesc(jc, pdesc)) == NULL) { 836 /* java exception pending */ 837 return (DTRACE_CONSUME_ABORT); 838 } 839 nrecs = edesc->dtepd_nrecs; 840 841 if (jc->dtjj_consumer->dtjc_flow) { 842 const char *kind; 843 switch (data->dtpda_flow) { 844 case DTRACEFLOW_ENTRY: 845 kind = "ENTRY"; 846 break; 847 case DTRACEFLOW_RETURN: 848 kind = "RETURN"; 849 break; 850 case DTRACEFLOW_NONE: 851 kind = "NONE"; 852 break; 853 default: 854 kind = NULL; 855 } 856 if (kind != NULL) { 857 int depth; 858 jflowkind = (*jenv)->NewStringUTF(jenv, kind); 859 if ((*jenv)->ExceptionCheck(jenv)) { 860 WRAP_EXCEPTION(jenv); 861 (*jenv)->DeleteLocalRef(jenv, jprobe); 862 return (DTRACE_CONSUME_ABORT); 863 } 864 /* 865 * Use the knowledge that libdtrace indents 2 spaces per 866 * level in the call stack to calculate the depth. 867 */ 868 depth = (data->dtpda_indent / 2); 869 jflow = (*jenv)->NewObject(jenv, g_flow_jc, 870 g_flowinit_jm, jflowkind, depth); 871 (*jenv)->DeleteLocalRef(jenv, jflowkind); 872 if ((*jenv)->ExceptionCheck(jenv)) { 873 WRAP_EXCEPTION(jenv); 874 (*jenv)->DeleteLocalRef(jenv, jprobe); 875 return (DTRACE_CONSUME_ABORT); 876 } 877 } 878 } 879 880 /* Create ProbeData instance */ 881 jpdata = (*jenv)->NewObject(jenv, g_pdata_jc, g_pdatainit_jm, 882 epid, cpu, jprobe, jflow, nrecs); 883 (*jenv)->DeleteLocalRef(jenv, jprobe); 884 (*jenv)->DeleteLocalRef(jenv, jflow); 885 if ((*jenv)->ExceptionCheck(jenv)) { 886 WRAP_EXCEPTION(jenv); 887 return (DTRACE_CONSUME_ABORT); 888 } 889 890 /* 891 * Populate the ProbeData list of Java data elements in advance so we 892 * don't need to peek back in the record handler at libdtrace records 893 * that have already been consumed. In the Java API, each ProbeData 894 * Record is generated by one D action, while in the native libdtrace 895 * there may be more than one probedata record (each a single data 896 * element) per D action. For example PrintfRecord has multiple 897 * unformatted elements, each represented by a native probedata record, 898 * but combined by the API into a single PrintfRecord. 899 */ 900 for (i = 0; i < nrecs; ++i) { 901 rec = &edesc->dtepd_rec[i]; 902 /* 903 * A statement that is not a D action, such as assignment to a 904 * variable, has no size. Add a NULL placeholder to the scratch 905 * list of Java probedata elements in that case. 906 */ 907 jobj = NULL; /* initialize object reference to null */ 908 if (rec->dtrd_size > 0) { 909 if (dtj_is_stack_action(rec->dtrd_action)) { 910 jobj = dtj_new_probedata_stack_record(data, 911 rec, jc); 912 } else { 913 jobj = dtj_recdata(jc, rec->dtrd_size, 914 (data->dtpda_data + rec->dtrd_offset)); 915 } 916 if ((*jenv)->ExceptionCheck(jenv)) { 917 WRAP_EXCEPTION(jenv); 918 (*jenv)->DeleteLocalRef(jenv, jpdata); 919 return (DTRACE_CONSUME_ABORT); 920 } 921 } 922 923 (*jenv)->CallVoidMethod(jenv, jpdata, g_pdataadd_jm, jobj); 924 (*jenv)->DeleteLocalRef(jenv, jobj); 925 if ((*jenv)->ExceptionCheck(jenv)) { 926 WRAP_EXCEPTION(jenv); 927 (*jenv)->DeleteLocalRef(jenv, jpdata); 928 return (DTRACE_CONSUME_ABORT); 929 } 930 } 931 932 if (jc->dtjj_probedata != NULL) { 933 dtj_throw_illegal_state(jenv, "unfinished probedata"); 934 WRAP_EXCEPTION(jenv); 935 (*jenv)->DeleteLocalRef(jenv, jpdata); 936 return (DTRACE_CONSUME_ABORT); 937 } 938 jc->dtjj_probedata = jpdata; 939 940 /* Initialize per-consumer probedata fields */ 941 jc->dtjj_consumer->dtjc_probedata_rec_i = 0; 942 jc->dtjj_consumer->dtjc_probedata_act = DTRACEACT_NONE; 943 dtj_aggwalk_init(jc); 944 if ((*jenv)->ExceptionCheck(jenv)) { 945 WRAP_EXCEPTION(jenv); 946 return (DTRACE_CONSUME_ABORT); 947 } 948 949 return (DTRACE_CONSUME_THIS); 950 } 951 952 /* 953 * This is the buffered output handler registered with dtrace_handle_buffered(). 954 * It's purpose is to make the output of the libdtrace print routines available 955 * to this API, without writing any of it to a file (such as stdout). This is 956 * needed for the stack(), ustack(), and jstack() actions to get human-readable 957 * stack values, since there is no public function in libdtrace to convert stack 958 * values to strings. It is also used to get the formatted output of the D 959 * printf() and printa() actions. 960 * 961 * The bufhandler is called once for each output-producing, non-aggregating D 962 * action, such as trace() or printf(), and once for each libdtrace aggregation 963 * record (whether in response to the D printa() action, or the Consumer 964 * getAggregate() method). In the simple printa() case that takes one 965 * aggregation and does not specify a format string, there is one libdtrace 966 * record per tuple element plus one for the corresponding value. The complete 967 * tuple/value pair becomes a single AggregationRecord exported by the API. 968 * When multiple aggregations are passed to printa(), each tuple is associated 969 * with a list of values, one from each aggregation. If a printa() format 970 * string does not specify placeholders for every aggregation value and tuple 971 * member, callbacks for those values and tuple members are omitted (and the 972 * data is omitted from the resulting PrintaRecord). 973 * 974 * Notes to characterize some non-obvious bufhandler behavior: 975 * 976 * 1. dtj_bufhandler() is never called with bufdata->dtbda_recdesc->dtrd_action 977 * DTRACEACT_PRINTA. That action only appears in the probedata consumer 978 * functions dtj_chew() and dtj_chewrec() before the bufhandler is called with 979 * subsequent aggregation records. 980 * 981 * 2. If printa() specifies a format string argument, then the bufhandler is 982 * called only for those elements of the tuple/value pair that are included in 983 * the format string. If a stack() tuple member is omitted from the format 984 * string, its human-readable representation will not be available to this API, 985 * so the stack frame array is also omitted from the resulting 986 * AggregationRecord. The bufhandler is also called once for each string of 987 * characters surrounding printa() format string placeholders. For example, 988 * " %@d %d stack%k\n" results in the following callbacks: 989 * - two spaces 990 * - the aggregation value 991 * - a single space 992 * - the first tuple member (an integer) 993 * - " stack" 994 * - the second tuple member (a stack) 995 * - a newline 996 * A NULL record (NULL dtbda_recdesc) distinguishes a callback with interstitial 997 * format string characters from a callback with a tuple member or aggregation 998 * value (which has a non-NULL recdesc). The contents are also distinguished by 999 * the following flags: 1000 * DTRACE_BUFDATA_AGGKEY 1001 * DTRACE_BUFDATA_AGGVAL 1002 * DTRACE_BUFDATA_AGGFORMAT 1003 * DTRACE_BUFDATA_AGGLAST 1004 * 1005 * There is no final callback with the complete formatted string, so that must 1006 * be concatenated across multiple callbacks to the bufhandler. 1007 * 1008 * 3. bufdata->dtbda_probe->dtpda_data may be overwritten by libdtrace print 1009 * routines. The address is cached in the dtj_chew() function in case it is 1010 * needed in the bufhandler. 1011 */ 1012 static int 1013 /* ARGSUSED */ 1014 dtj_bufhandler(const dtrace_bufdata_t *bufdata, void *arg) 1015 { 1016 dtj_java_consumer_t *jc; 1017 JNIEnv *jenv; 1018 const dtrace_recdesc_t *rec; 1019 dtrace_actkind_t act = DTRACEACT_NONE; 1020 const char *s; 1021 1022 jobject jstr = NULL; 1023 1024 /* 1025 * Get the thread-specific java consumer. The bufhandler needs access 1026 * to the correct JNI state specific to either the consumer loop or the 1027 * getAggregate() call (aggregation snapshots can be requested 1028 * asynchronously while the consumer loop generates PrintaRecords in 1029 * dtrace_work() for ConsumerListeners). 1030 */ 1031 jc = pthread_getspecific(g_dtj_consumer_key); 1032 jenv = jc->dtjj_jenv; 1033 1034 /* 1035 * In at least one corner case (printa with multiple aggregations and a 1036 * format string that does not completely specify the tuple), returning 1037 * DTRACE_HANDLE_ABORT does not prevent a subsequent callback to this 1038 * bufhandler. This check ensures that the invalid call is ignored. 1039 */ 1040 if ((*jenv)->ExceptionCheck(jenv)) { 1041 return (DTRACE_HANDLE_ABORT); 1042 } 1043 1044 if (bufdata->dtbda_aggdata) { 1045 return (dtj_agghandler(bufdata, jc)); 1046 } 1047 1048 s = bufdata->dtbda_buffered; 1049 if (s == NULL) { 1050 return (DTRACE_HANDLE_OK); 1051 } 1052 1053 rec = bufdata->dtbda_recdesc; 1054 if (rec) { 1055 act = rec->dtrd_action; 1056 } 1057 1058 switch (act) { 1059 case DTRACEACT_DIFEXPR: 1060 /* trace() action */ 1061 break; 1062 case DTRACEACT_PRINTF: 1063 /* 1064 * Only the formatted string was not available to dtj_chewrec(), 1065 * so we attach that now. 1066 */ 1067 jstr = dtj_NewStringNative(jenv, s); 1068 if ((*jenv)->ExceptionCheck(jenv)) { 1069 WRAP_EXCEPTION(jenv); 1070 return (DTRACE_HANDLE_ABORT); 1071 } 1072 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1073 g_pdataset_formatted_jm, jstr); 1074 (*jenv)->DeleteLocalRef(jenv, jstr); 1075 if ((*jenv)->ExceptionCheck(jenv)) { 1076 WRAP_EXCEPTION(jenv); 1077 return (DTRACE_HANDLE_ABORT); 1078 } 1079 break; 1080 case DTRACEACT_STACK: 1081 case DTRACEACT_USTACK: 1082 case DTRACEACT_JSTACK: 1083 /* stand-alone stack(), ustack(), or jstack() action */ 1084 jstr = (*jenv)->NewStringUTF(jenv, s); 1085 if (!jstr) { 1086 /* OutOfMemoryError pending */ 1087 return (DTRACE_HANDLE_ABORT); 1088 } 1089 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1090 g_pdataadd_stack_jm, 1091 jc->dtjj_consumer->dtjc_probedata_rec_i, jstr); 1092 (*jenv)->DeleteLocalRef(jenv, jstr); 1093 if ((*jenv)->ExceptionCheck(jenv)) { 1094 WRAP_EXCEPTION(jenv); 1095 return (DTRACE_HANDLE_ABORT); 1096 } 1097 break; 1098 default: 1099 /* 1100 * The record handler dtj_chewrec() defers nothing else to this 1101 * bufhandler. 1102 */ 1103 break; 1104 } 1105 1106 return (DTRACE_HANDLE_OK); 1107 } 1108 1109 static boolean_t 1110 dtj_is_stack_action(dtrace_actkind_t act) 1111 { 1112 boolean_t stack_action; 1113 switch (act) { 1114 case DTRACEACT_STACK: 1115 case DTRACEACT_USTACK: 1116 case DTRACEACT_JSTACK: 1117 stack_action = B_TRUE; 1118 break; 1119 default: 1120 stack_action = B_FALSE; 1121 } 1122 return (stack_action); 1123 } 1124 1125 /* 1126 * Called by get_aggregate() to clear only those aggregations specified by the 1127 * caller. 1128 */ 1129 static int 1130 dtj_clear(const dtrace_aggdata_t *data, void *arg) 1131 { 1132 dtj_java_consumer_t *jc = arg; 1133 jboolean cleared = JNI_FALSE; 1134 1135 jstring jname = NULL; 1136 1137 if (jc->dtjj_aggregate_spec) { 1138 JNIEnv *jenv = jc->dtjj_jenv; 1139 1140 dtrace_aggdesc_t *aggdesc = data->dtada_desc; 1141 1142 jname = (*jenv)->NewStringUTF(jenv, aggdesc->dtagd_name); 1143 if (!jname) { 1144 /* java exception pending */ 1145 return (DTRACE_AGGWALK_ABORT); 1146 } 1147 1148 cleared = (*jenv)->CallBooleanMethod(jenv, 1149 jc->dtjj_aggregate_spec, g_aggspec_cleared_jm, jname); 1150 (*jenv)->DeleteLocalRef(jenv, jname); 1151 if ((*jenv)->ExceptionCheck(jenv)) { 1152 WRAP_EXCEPTION(jenv); 1153 return (DTRACE_AGGWALK_ABORT); 1154 } 1155 } 1156 1157 return (cleared ? DTRACE_AGGWALK_CLEAR : DTRACE_AGGWALK_NEXT); 1158 } 1159 1160 static int64_t 1161 dtj_average(caddr_t addr, uint64_t normal) 1162 { 1163 /* LINTED - alignment */ 1164 uint64_t *data = (uint64_t *)addr; 1165 1166 return (data[0] ? 1167 (long long)(data[1] / normal / data[0]) : 0); 1168 } 1169 1170 static int64_t 1171 dtj_avg_total(caddr_t addr, uint64_t normal) 1172 { 1173 /* LINTED - alignment */ 1174 uint64_t *data = (uint64_t *)addr; 1175 1176 return ((long long)(data[1] / normal)); 1177 } 1178 1179 static int64_t 1180 dtj_avg_count(caddr_t addr) 1181 { 1182 /* LINTED - alignment */ 1183 uint64_t *data = (uint64_t *)addr; 1184 1185 return ((long long)data[0]); 1186 } 1187 1188 static jobject 1189 dtj_new_probedata_stack_record(const dtrace_probedata_t *data, 1190 const dtrace_recdesc_t *rec, dtj_java_consumer_t *jc) 1191 { 1192 caddr_t addr; 1193 1194 /* Get raw stack data */ 1195 addr = data->dtpda_data + rec->dtrd_offset; 1196 return (dtj_new_stack_record(addr, rec, jc)); 1197 } 1198 1199 static jobject 1200 dtj_new_tuple_stack_record(const dtrace_aggdata_t *data, 1201 const dtrace_recdesc_t *rec, const char *s, dtj_java_consumer_t *jc) 1202 { 1203 caddr_t addr; 1204 JNIEnv *jenv = jc->dtjj_jenv; 1205 1206 jobjectArray frames = NULL; 1207 jobject jobj = NULL; /* tuple element */ 1208 jstring jstr = NULL; 1209 1210 /* Get raw stack data */ 1211 addr = data->dtada_data + rec->dtrd_offset; 1212 jobj = dtj_new_stack_record(addr, rec, jc); 1213 if (!jobj) { 1214 return (NULL); /* java exception pending */ 1215 } 1216 1217 jstr = dtj_NewStringNative(jenv, s); 1218 if ((*jenv)->ExceptionCheck(jenv)) { 1219 (*jenv)->DeleteLocalRef(jenv, jobj); 1220 return (NULL); 1221 } 1222 frames = (*jenv)->CallStaticObjectMethod(jenv, g_stack_jc, 1223 g_parsestack_jsm, jstr); 1224 (*jenv)->DeleteLocalRef(jenv, jstr); 1225 if ((*jenv)->ExceptionCheck(jenv)) { 1226 (*jenv)->DeleteLocalRef(jenv, jobj); 1227 return (NULL); 1228 } 1229 dtj_attach_frames(jc, jobj, frames); 1230 (*jenv)->DeleteLocalRef(jenv, frames); 1231 if ((*jenv)->ExceptionCheck(jenv)) { 1232 return (NULL); 1233 } 1234 1235 return (jobj); 1236 } 1237 1238 /* Caller must be holding per-consumer lock */ 1239 static void 1240 dtj_aggwalk_init(dtj_java_consumer_t *jc) 1241 { 1242 jc->dtjj_consumer->dtjc_aggid = -1; 1243 jc->dtjj_consumer->dtjc_expected = -1; 1244 if (jc->dtjj_tuple != NULL) { 1245 /* assert without crashing */ 1246 dtj_throw_illegal_state(jc->dtjj_jenv, 1247 "stale aggregation tuple"); 1248 } 1249 } 1250 1251 static jobject 1252 dtj_new_stack_record(caddr_t addr, const dtrace_recdesc_t *rec, 1253 dtj_java_consumer_t *jc) 1254 { 1255 JNIEnv *jenv = jc->dtjj_jenv; 1256 1257 dtrace_actkind_t act; 1258 uint64_t *pc; 1259 pid_t pid = -1; 1260 int size; /* size of raw bytes not including trailing zeros */ 1261 int i; /* index of last non-zero byte */ 1262 1263 jbyteArray raw = NULL; 1264 jobject stack = NULL; /* return value */ 1265 1266 /* trim trailing zeros */ 1267 for (i = rec->dtrd_size - 1; (i >= 0) && !addr[i]; --i) { 1268 } 1269 size = (i + 1); 1270 raw = (*jenv)->NewByteArray(jenv, size); 1271 if (!raw) { 1272 return (NULL); /* OutOfMemoryError pending */ 1273 } 1274 (*jenv)->SetByteArrayRegion(jenv, raw, 0, size, 1275 (const jbyte *)addr); 1276 if ((*jenv)->ExceptionCheck(jenv)) { 1277 WRAP_EXCEPTION(jenv); 1278 (*jenv)->DeleteLocalRef(jenv, raw); 1279 return (NULL); 1280 } 1281 1282 /* Create StackValueRecord instance from raw stack data */ 1283 act = rec->dtrd_action; 1284 switch (act) { 1285 case DTRACEACT_STACK: 1286 stack = (*jenv)->NewObject(jenv, g_stack_jc, 1287 g_stackinit_jm, raw); 1288 break; 1289 case DTRACEACT_USTACK: 1290 case DTRACEACT_JSTACK: 1291 /* Get pid of user process */ 1292 pc = (uint64_t *)(uintptr_t)addr; 1293 pid = (pid_t)*pc; 1294 stack = (*jenv)->NewObject(jenv, g_ustack_jc, 1295 g_ustackinit_jm, pid, raw); 1296 break; 1297 default: 1298 dtj_throw_illegal_argument(jenv, 1299 "Expected stack action, got %d\n", act); 1300 } 1301 (*jenv)->DeleteLocalRef(jenv, raw); 1302 if ((*jenv)->ExceptionCheck(jenv)) { 1303 WRAP_EXCEPTION(jenv); 1304 return (NULL); 1305 } 1306 return (stack); 1307 } 1308 1309 /* 1310 * Return NULL if java exception pending, otherwise return Distribution value. 1311 */ 1312 static jobject 1313 dtj_new_distribution(const dtrace_aggdata_t *data, const dtrace_recdesc_t *rec, 1314 dtj_java_consumer_t *jc) 1315 { 1316 JNIEnv *jenv = jc->dtjj_jenv; 1317 1318 jlongArray jbuckets = NULL; 1319 jobject jdist = NULL; /* return value */ 1320 1321 dtrace_actkind_t act = rec->dtrd_action; 1322 /* LINTED - alignment */ 1323 int64_t *aggbuckets = (int64_t *) 1324 (data->dtada_data + rec->dtrd_offset); 1325 size_t size = rec->dtrd_size; 1326 int64_t value; 1327 uint64_t normal = data->dtada_normal; 1328 int64_t base, step; 1329 int levels; 1330 int n; /* number of buckets */ 1331 1332 /* distribution */ 1333 if (act == DTRACEAGG_LQUANTIZE) { 1334 /* first "bucket" used for range and step */ 1335 value = *aggbuckets++; 1336 base = DTRACE_LQUANTIZE_BASE(value); 1337 step = DTRACE_LQUANTIZE_STEP(value); 1338 levels = DTRACE_LQUANTIZE_LEVELS(value); 1339 size -= sizeof (int64_t); /* exclude non-bucket */ 1340 /* 1341 * Add one for the base bucket and one for the bucket of values 1342 * less than the base. 1343 */ 1344 n = levels + 2; 1345 } else { 1346 n = DTRACE_QUANTIZE_NBUCKETS; 1347 levels = n - 1; /* levels excludes base */ 1348 } 1349 if (size != (n * sizeof (uint64_t)) || n < 1) { 1350 dtj_throw_illegal_state(jenv, 1351 "size mismatch: record %d, buckets %d", size, 1352 (n * sizeof (uint64_t))); 1353 WRAP_EXCEPTION(jenv); 1354 return (NULL); 1355 } 1356 1357 jbuckets = (*jenv)->NewLongArray(jenv, n); 1358 if (!jbuckets) { 1359 return (NULL); /* exception pending */ 1360 } 1361 if (n > 0) { 1362 (*jenv)->SetLongArrayRegion(jenv, jbuckets, 0, n, aggbuckets); 1363 /* check for ArrayIndexOutOfBounds */ 1364 if ((*jenv)->ExceptionCheck(jenv)) { 1365 WRAP_EXCEPTION(jenv); 1366 (*jenv)->DeleteLocalRef(jenv, jbuckets); 1367 return (NULL); 1368 } 1369 } 1370 1371 if (act == DTRACEAGG_LQUANTIZE) { 1372 /* Must pass 64-bit base and step or constructor gets junk. */ 1373 jdist = (*jenv)->NewObject(jenv, g_ldist_jc, g_ldistinit_jm, 1374 base, step, jbuckets); 1375 } else { 1376 jdist = (*jenv)->NewObject(jenv, g_dist_jc, g_distinit_jm, 1377 jbuckets); 1378 } 1379 1380 (*jenv)->DeleteLocalRef(jenv, jbuckets); 1381 if (!jdist) { 1382 return (NULL); /* exception pending */ 1383 } 1384 1385 if (normal != 1) { 1386 (*jenv)->CallVoidMethod(jenv, jdist, g_dist_normal_jm, normal); 1387 if ((*jenv)->ExceptionCheck(jenv)) { 1388 WRAP_EXCEPTION(jenv); 1389 (*jenv)->DeleteLocalRef(jenv, jdist); 1390 return (NULL); 1391 } 1392 } 1393 return (jdist); 1394 } 1395 1396 static void 1397 dtj_attach_frames(dtj_java_consumer_t *jc, jobject stack, 1398 jobjectArray frames) 1399 { 1400 JNIEnv *jenv = jc->dtjj_jenv; 1401 1402 if ((*jenv)->IsInstanceOf(jenv, stack, g_stack_jc)) { 1403 (*jenv)->CallVoidMethod(jenv, stack, g_stackset_frames_jm, 1404 frames); 1405 } else if ((*jenv)->IsInstanceOf(jenv, stack, g_ustack_jc)) { 1406 (*jenv)->CallVoidMethod(jenv, stack, g_ustackset_frames_jm, 1407 frames); 1408 } 1409 } 1410 1411 /* 1412 * Note: It is not valid to look outside the current libdtrace record in the 1413 * given aggdata (except to get the aggregation ID from the first record). 1414 * 1415 * Return DTRACE_HANDLE_ABORT if java exception pending, otherwise 1416 * DTRACE_HANDLE_OK. 1417 */ 1418 static int 1419 dtj_agghandler(const dtrace_bufdata_t *bufdata, dtj_java_consumer_t *jc) 1420 { 1421 JNIEnv *jenv = jc->dtjj_jenv; 1422 1423 const dtrace_aggdata_t *aggdata = bufdata->dtbda_aggdata; 1424 const dtrace_aggdesc_t *aggdesc; 1425 const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc; 1426 const char *s = bufdata->dtbda_buffered; 1427 dtrace_actkind_t act = DTRACEACT_NONE; 1428 int64_t aggid; 1429 1430 jobject jobj = NULL; 1431 1432 if (aggdata == NULL) { 1433 /* Assert without crashing */ 1434 dtj_throw_illegal_state(jenv, "null aggdata"); 1435 WRAP_EXCEPTION(jenv); 1436 return (DTRACE_HANDLE_ABORT); 1437 } 1438 aggdesc = aggdata->dtada_desc; 1439 1440 /* 1441 * Get the aggregation ID from the first record. 1442 */ 1443 /* LINTED - alignment */ 1444 aggid = *((int64_t *)(aggdata->dtada_data + 1445 aggdesc->dtagd_rec[0].dtrd_offset)); 1446 if (aggid < 0) { 1447 /* Assert without crashing */ 1448 dtj_throw_illegal_argument(jenv, "negative aggregation ID"); 1449 WRAP_EXCEPTION(jenv); 1450 return (DTRACE_HANDLE_ABORT); 1451 } 1452 1453 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1454 /* Append buffered output if this is a printa() callback. */ 1455 jstring jstr = dtj_NewStringNative(jenv, s); 1456 if ((*jenv)->ExceptionCheck(jenv)) { 1457 WRAP_EXCEPTION(jenv); 1458 return (DTRACE_HANDLE_ABORT); 1459 } 1460 /* 1461 * StringBuffer append() returns a reference to the 1462 * StringBuffer; must not leak the returned reference. 1463 */ 1464 jobj = (*jenv)->CallObjectMethod(jenv, 1465 jc->dtjj_printa_buffer, g_buf_append_str_jm, jstr); 1466 (*jenv)->DeleteLocalRef(jenv, jstr); 1467 (*jenv)->DeleteLocalRef(jenv, jobj); 1468 if ((*jenv)->ExceptionCheck(jenv)) { 1469 WRAP_EXCEPTION(jenv); 1470 return (DTRACE_HANDLE_ABORT); 1471 } 1472 } else { 1473 /* 1474 * Test whether to include the aggregation if this is a 1475 * getAggregate() callback. Optimization: perform the inclusion 1476 * test only when the aggregation has changed. 1477 */ 1478 if (aggid != jc->dtjj_consumer->dtjc_aggid) { 1479 jc->dtjj_consumer->dtjc_included = 1480 dtj_is_included(aggdata, jc); 1481 if ((*jenv)->ExceptionCheck(jenv)) { 1482 WRAP_EXCEPTION(jenv); 1483 return (DTRACE_HANDLE_ABORT); 1484 } 1485 } 1486 if (!jc->dtjj_consumer->dtjc_included) { 1487 return (DTRACE_HANDLE_OK); 1488 } 1489 } 1490 jc->dtjj_consumer->dtjc_aggid = aggid; 1491 1492 /* 1493 * Determine the expected number of tuple members. While it is not 1494 * technically valid to look outside the current record in the current 1495 * aggdata, this implementation does so without a known failure case. 1496 * Any method relying only on the current callback record makes riskier 1497 * assumptions and still does not cover every corner case (for example, 1498 * counting the records from index 1 up to and not including the index 1499 * of the current DTRACE_BUFDATA_AGGVAL record, which fails when a 1500 * format string specifies the value ahead of one or more tuple 1501 * elements). Knowing that the calculation of the expected tuple size 1502 * is technically invalid (because it looks outside the current record), 1503 * we make the calculation at the earliest opportunity, before anything 1504 * might happen to invalidate any part of the aggdata. It ought to be 1505 * safe in any case: dtrd_action and dtrd_size do not appear ever to be 1506 * overwritten, and dtrd_offset is not used outside the current record. 1507 * 1508 * It is possible (if the assumptions here ever prove untrue) that the 1509 * libdtrace buffered output handler may need to be enhanced to provide 1510 * the expected number of tuple members. 1511 */ 1512 if (jc->dtjj_consumer->dtjc_expected < 0) { 1513 int r; 1514 for (r = 1; r < aggdesc->dtagd_nrecs; ++r) { 1515 act = aggdesc->dtagd_rec[r].dtrd_action; 1516 if (DTRACEACT_ISAGG(act) || 1517 aggdesc->dtagd_rec[r].dtrd_size == 0) { 1518 break; 1519 } 1520 } 1521 jc->dtjj_consumer->dtjc_expected = r - 1; 1522 } 1523 1524 if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGKEY) { 1525 /* record value is a tuple member */ 1526 1527 if (jc->dtjj_tuple == NULL) { 1528 jc->dtjj_tuple = (*jenv)->NewObject(jenv, 1529 g_tuple_jc, g_tupleinit_jm); 1530 if (!jc->dtjj_tuple) { 1531 /* java exception pending */ 1532 return (DTRACE_HANDLE_ABORT); 1533 } 1534 } 1535 1536 act = rec->dtrd_action; 1537 1538 switch (act) { 1539 case DTRACEACT_STACK: 1540 case DTRACEACT_USTACK: 1541 case DTRACEACT_JSTACK: 1542 jobj = dtj_new_tuple_stack_record(aggdata, rec, s, jc); 1543 break; 1544 default: 1545 jobj = dtj_recdata(jc, rec->dtrd_size, 1546 (aggdata->dtada_data + rec->dtrd_offset)); 1547 } 1548 1549 if (!jobj) { 1550 /* java exception pending */ 1551 return (DTRACE_HANDLE_ABORT); 1552 } 1553 1554 (*jenv)->CallVoidMethod(jenv, jc->dtjj_tuple, 1555 g_tupleadd_jm, jobj); 1556 (*jenv)->DeleteLocalRef(jenv, jobj); 1557 if ((*jenv)->ExceptionCheck(jenv)) { 1558 WRAP_EXCEPTION(jenv); 1559 return (DTRACE_HANDLE_ABORT); 1560 } 1561 } else if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGVAL) { 1562 /* 1563 * Record value is that of an aggregating action. The printa() 1564 * format string may place the tuple ahead of the aggregation 1565 * value(s), so we can't be sure we have the tuple until we get 1566 * the AGGLAST flag indicating the last callback associated with 1567 * the current tuple. Save the aggregation value or values 1568 * (multiple values if more than one aggregation is passed to 1569 * printa()) until then. 1570 */ 1571 dtj_aggval_t *aggval; 1572 1573 jstring jvalue = NULL; 1574 1575 jvalue = dtj_new_aggval(jc, aggdata, rec); 1576 if (!jvalue) { 1577 /* java exception pending */ 1578 WRAP_EXCEPTION(jenv); 1579 return (DTRACE_HANDLE_ABORT); 1580 } 1581 aggval = dtj_aggval_create(jenv, jvalue, aggdesc->dtagd_name, 1582 aggid); 1583 if (!aggval) { 1584 /* OutOfMemoryError pending */ 1585 (*jenv)->DeleteLocalRef(jenv, jvalue); 1586 return (DTRACE_HANDLE_ABORT); 1587 } 1588 if (!dtj_list_add(jc->dtjj_aggval_list, aggval)) { 1589 /* deletes jvalue reference */ 1590 dtj_aggval_destroy(aggval, jenv); 1591 dtj_throw_out_of_memory(jenv, "Failed to add aggval"); 1592 return (DTRACE_HANDLE_ABORT); 1593 } 1594 } 1595 1596 if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGLAST) { 1597 /* No more values associated with the current tuple. */ 1598 1599 dtj_aggval_t *aggval; 1600 uu_list_walk_t *itr; 1601 int tuple_member_count; 1602 1603 jobject jrec = NULL; 1604 jstring jname = NULL; 1605 1606 if (jc->dtjj_consumer->dtjc_expected == 0) { 1607 /* 1608 * singleton aggregation declared in D with no square 1609 * brackets 1610 */ 1611 jc->dtjj_tuple = (*jenv)->GetStaticObjectField(jenv, 1612 g_tuple_jc, g_tuple_EMPTY_jsf); 1613 if (jc->dtjj_tuple == NULL) { 1614 dtj_throw_out_of_memory(jenv, 1615 "Failed to reference Tuple.EMPTY"); 1616 return (DTRACE_HANDLE_ABORT); 1617 } 1618 } 1619 1620 if (jc->dtjj_tuple == NULL) { 1621 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1622 g_pdatainvalidate_printa_jm); 1623 } 1624 1625 tuple_member_count = (*jenv)->CallIntMethod(jenv, 1626 jc->dtjj_tuple, g_tuplesize_jm); 1627 if (tuple_member_count < 1628 jc->dtjj_consumer->dtjc_expected) { 1629 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1630 g_pdatainvalidate_printa_jm); 1631 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1632 jc->dtjj_tuple = NULL; 1633 } 1634 1635 if (jc->dtjj_tuple == NULL) { 1636 goto printa_output; 1637 } 1638 1639 itr = uu_list_walk_start(jc->dtjj_aggval_list, 0); 1640 while ((aggval = uu_list_walk_next(itr)) != NULL) { 1641 /* 1642 * new AggregationRecord: Combine the aggregation value 1643 * with the saved tuple and add it to the current 1644 * Aggregate or PrintaRecord. 1645 */ 1646 jrec = (*jenv)->NewObject(jenv, g_aggrec_jc, 1647 g_aggrecinit_jm, jc->dtjj_tuple, 1648 aggval->dtja_value); 1649 (*jenv)->DeleteLocalRef(jenv, aggval->dtja_value); 1650 aggval->dtja_value = NULL; 1651 if (!jrec) { 1652 /* java exception pending */ 1653 WRAP_EXCEPTION(jenv); 1654 return (DTRACE_HANDLE_ABORT); 1655 } 1656 1657 /* aggregation name */ 1658 jname = (*jenv)->NewStringUTF(jenv, 1659 aggval->dtja_aggname); 1660 if (!jname) { 1661 /* OutOfMemoryError pending */ 1662 (*jenv)->DeleteLocalRef(jenv, jrec); 1663 return (DTRACE_HANDLE_ABORT); 1664 } 1665 1666 /* 1667 * If the printa() format string specifies the value of 1668 * the aggregating action multiple times, PrintaRecord 1669 * ignores the attempt to add the duplicate record. 1670 */ 1671 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1672 /* add to PrintaRecord */ 1673 (*jenv)->CallVoidMethod(jenv, 1674 jc->dtjj_probedata, 1675 g_pdataadd_aggrec_jm, 1676 jname, aggval->dtja_aggid, jrec); 1677 } else { 1678 /* add to Aggregate */ 1679 (*jenv)->CallVoidMethod(jenv, 1680 jc->dtjj_aggregate, g_aggaddrec_jm, 1681 jname, aggval->dtja_aggid, jrec); 1682 } 1683 1684 (*jenv)->DeleteLocalRef(jenv, jrec); 1685 (*jenv)->DeleteLocalRef(jenv, jname); 1686 if ((*jenv)->ExceptionCheck(jenv)) { 1687 WRAP_EXCEPTION(jenv); 1688 return (DTRACE_HANDLE_ABORT); 1689 } 1690 } 1691 uu_list_walk_end(itr); 1692 dtj_list_clear(jc->dtjj_aggval_list, dtj_aggval_destroy, 1693 jenv); 1694 1695 printa_output: 1696 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1697 /* 1698 * Get the formatted string associated with the current 1699 * tuple if this is a printa() callback. 1700 */ 1701 jstring jstr = (*jenv)->CallObjectMethod(jenv, 1702 jc->dtjj_printa_buffer, g_tostring_jm); 1703 if ((*jenv)->ExceptionCheck(jenv)) { 1704 WRAP_EXCEPTION(jenv); 1705 return (DTRACE_HANDLE_ABORT); 1706 } 1707 /* 1708 * Clear the StringBuffer: this does not throw 1709 * exceptions. Reuse the StringBuffer until the end of 1710 * the current probedata then dispose of it. 1711 */ 1712 (*jenv)->CallVoidMethod(jenv, jc->dtjj_printa_buffer, 1713 g_bufsetlen_jm, 0); 1714 /* Add formatted string to PrintaRecord */ 1715 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1716 g_pdataadd_printa_str_jm, jc->dtjj_tuple, jstr); 1717 (*jenv)->DeleteLocalRef(jenv, jstr); 1718 if ((*jenv)->ExceptionCheck(jenv)) { 1719 WRAP_EXCEPTION(jenv); 1720 return (DTRACE_HANDLE_ABORT); 1721 } 1722 } 1723 1724 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1725 jc->dtjj_tuple = NULL; 1726 jc->dtjj_consumer->dtjc_expected = -1; 1727 } 1728 1729 return (DTRACE_HANDLE_OK); 1730 } 1731 1732 /* 1733 * Return B_TRUE if the aggregation is included, B_FALSE otherwise. Only in the 1734 * latter case might there be an exception pending. 1735 */ 1736 static boolean_t 1737 dtj_is_included(const dtrace_aggdata_t *data, dtj_java_consumer_t *jc) 1738 { 1739 JNIEnv *jenv = jc->dtjj_jenv; 1740 1741 if (jc->dtjj_aggregate_spec) { 1742 jboolean included; 1743 jstring aggname = NULL; 1744 1745 const dtrace_aggdesc_t *aggdesc = data->dtada_desc; 1746 aggname = (*jenv)->NewStringUTF(jenv, aggdesc->dtagd_name); 1747 if (!aggname) { 1748 /* java exception pending */ 1749 return (B_FALSE); 1750 } 1751 1752 included = (*jenv)->CallBooleanMethod(jenv, 1753 jc->dtjj_aggregate_spec, g_aggspec_included_jm, 1754 aggname); 1755 (*jenv)->DeleteLocalRef(jenv, aggname); 1756 if ((*jenv)->ExceptionCheck(jenv)) { 1757 WRAP_EXCEPTION(jenv); 1758 return (B_FALSE); 1759 } 1760 1761 return (included); 1762 } 1763 1764 return (B_TRUE); 1765 } 1766 1767 /* 1768 * Return NULL if a java exception is pending, otherwise return a new 1769 * AggregationValue instance. 1770 */ 1771 static jobject 1772 dtj_new_aggval(dtj_java_consumer_t *jc, const dtrace_aggdata_t *data, 1773 const dtrace_recdesc_t *rec) 1774 { 1775 JNIEnv *jenv = jc->dtjj_jenv; 1776 1777 jobject jvalue = NULL; /* return value */ 1778 1779 dtrace_actkind_t act; 1780 uint64_t normal; 1781 caddr_t addr; 1782 int64_t value; 1783 1784 act = rec->dtrd_action; 1785 normal = data->dtada_normal; 1786 addr = data->dtada_data + rec->dtrd_offset; 1787 if (act == DTRACEAGG_AVG) { 1788 value = dtj_average(addr, normal); 1789 } else { 1790 /* LINTED - alignment */ 1791 value = (*((int64_t *)addr)) / normal; 1792 } 1793 1794 if (act == DTRACEAGG_QUANTIZE || act == DTRACEAGG_LQUANTIZE) { 1795 jvalue = dtj_new_distribution(data, rec, jc); 1796 } else { 1797 switch (act) { 1798 case DTRACEAGG_COUNT: 1799 jvalue = (*jenv)->NewObject(jenv, g_aggcount_jc, 1800 g_aggcountinit_jm, value); 1801 break; 1802 case DTRACEAGG_SUM: 1803 jvalue = (*jenv)->NewObject(jenv, g_aggsum_jc, 1804 g_aggsuminit_jm, value); 1805 break; 1806 case DTRACEAGG_AVG: 1807 jvalue = (*jenv)->NewObject(jenv, g_aggavg_jc, 1808 g_aggavginit_jm, value, dtj_avg_total(addr, 1809 normal), dtj_avg_count(addr)); 1810 break; 1811 case DTRACEAGG_MIN: 1812 jvalue = (*jenv)->NewObject(jenv, g_aggmin_jc, 1813 g_aggmininit_jm, value); 1814 break; 1815 case DTRACEAGG_MAX: 1816 jvalue = (*jenv)->NewObject(jenv, g_aggmax_jc, 1817 g_aggmaxinit_jm, value); 1818 break; 1819 default: 1820 jvalue = NULL; 1821 dtj_throw_illegal_argument(jenv, 1822 "unexpected aggregation action: %d", act); 1823 } 1824 } 1825 1826 return (jvalue); 1827 } 1828 1829 /* 1830 * Stops the given consumer if it is running. Throws DTraceException if 1831 * dtrace_stop() fails and no other exception is already pending. Clears and 1832 * rethrows any pending exception in order to grab the global lock safely. 1833 */ 1834 void 1835 dtj_stop(dtj_java_consumer_t *jc) 1836 { 1837 JNIEnv *jenv; 1838 int rc; 1839 jthrowable e; 1840 1841 switch (jc->dtjj_consumer->dtjc_state) { 1842 case DTJ_CONSUMER_GO: 1843 case DTJ_CONSUMER_START: 1844 break; 1845 default: 1846 return; 1847 } 1848 1849 jenv = jc->dtjj_jenv; 1850 e = (*jenv)->ExceptionOccurred(jenv); 1851 if (e) { 1852 (*jenv)->ExceptionClear(jenv); 1853 } 1854 1855 (*jenv)->MonitorEnter(jenv, g_caller_jc); 1856 if ((*jenv)->ExceptionCheck(jenv)) { 1857 goto rethrow; 1858 } 1859 1860 rc = dtrace_status(jc->dtjj_consumer->dtjc_dtp); 1861 if (rc != DTRACE_STATUS_STOPPED) { 1862 rc = dtrace_stop(jc->dtjj_consumer->dtjc_dtp); 1863 } 1864 1865 (*jenv)->MonitorExit(jenv, g_caller_jc); 1866 if ((*jenv)->ExceptionCheck(jenv)) { 1867 goto rethrow; 1868 } 1869 1870 if (rc == -1) { 1871 (*jenv)->MonitorEnter(jenv, g_caller_jc); 1872 if ((*jenv)->ExceptionCheck(jenv)) { 1873 goto rethrow; 1874 } 1875 /* Do not wrap DTraceException */ 1876 dtj_throw_dtrace_exception(jc, 1877 "couldn't stop tracing: %s", 1878 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 1879 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 1880 /* safe to call with pending exception */ 1881 (*jenv)->MonitorExit(jenv, g_caller_jc); 1882 } else { 1883 jc->dtjj_consumer->dtjc_state = DTJ_CONSUMER_STOP; 1884 } 1885 1886 rethrow: 1887 if (e) { 1888 if ((*jenv)->ExceptionCheck(jenv)) { 1889 /* 1890 * Favor earlier pending exception over 1891 * exception thrown in this function. 1892 */ 1893 (*jenv)->ExceptionClear(jenv); 1894 } 1895 (*jenv)->Throw(jenv, e); 1896 (*jenv)->DeleteLocalRef(jenv, e); 1897 } 1898 } 1899 1900 /* 1901 * Return Aggregate instance, or null if java exception pending. 1902 */ 1903 jobject 1904 dtj_get_aggregate(dtj_java_consumer_t *jc) 1905 { 1906 JNIEnv *jenv = jc->dtjj_jenv; 1907 hrtime_t snaptime; 1908 int rc; 1909 1910 jobject aggregate = NULL; 1911 1912 /* 1913 * Aggregations must be snapped, walked, and cleared atomically, 1914 * otherwise clearing loses data accumulated since the most recent snap. 1915 * This per-consumer lock prevents dtrace_work() from snapping or 1916 * clearing aggregations while we're in the middle of this atomic 1917 * operation, so we continue to hold it until done clearing. 1918 */ 1919 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 1920 if ((*jenv)->ExceptionCheck(jenv)) { 1921 WRAP_EXCEPTION(jenv); 1922 return (NULL); 1923 } 1924 1925 dtj_aggwalk_init(jc); 1926 if ((*jenv)->ExceptionCheck(jenv)) { 1927 WRAP_EXCEPTION(jenv); 1928 /* release per-consumer lock */ 1929 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 1930 return (NULL); 1931 } 1932 1933 /* 1934 * Snap aggregations 1935 * 1936 * We need to record the snaptime here for the caller. Leaving it to 1937 * the caller to record the snaptime before calling getAggregate() may 1938 * be inaccurate because of the indeterminate delay waiting on the 1939 * consumer lock before calling dtrace_aggregate_snap(). 1940 */ 1941 snaptime = gethrtime(); 1942 if (dtrace_aggregate_snap(jc->dtjj_consumer->dtjc_dtp) != 0) { 1943 dtj_error_t e; 1944 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 1945 /* Do not wrap DTraceException */ 1946 dtj_throw_dtrace_exception(jc, e.dtje_message); 1947 } 1948 /* release per-consumer lock */ 1949 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 1950 return (NULL); 1951 } 1952 1953 /* Create the Java representation of the aggregate snapshot. */ 1954 aggregate = (*jenv)->NewObject(jenv, g_agg_jc, g_agginit_jm, 1955 snaptime); 1956 if ((*jenv)->ExceptionCheck(jenv)) { 1957 WRAP_EXCEPTION(jenv); 1958 /* release per-consumer lock */ 1959 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 1960 return (NULL); 1961 } 1962 jc->dtjj_aggregate = aggregate; 1963 1964 /* 1965 * Walk the aggregate, converting the data into Java Objects. Traverse 1966 * in order by aggregation ID first and tuple second by using 1967 * dtrace_aggregate_walk_keysorted (uses varkeycmp). We cannot do the 1968 * same for aggregations generated by the printa() action, since 1969 * dtrace_work() traverses aggregation data in the order determined by 1970 * the various "aggsort" options. Functions used by both the consumer 1971 * loop and the competing getAggregate() thread must not depend on the 1972 * ordering of records by tuple key. 1973 * 1974 * It is impractical to hold the global lock around 1975 * dtrace_aggregate_print(), since it may take a long time (e.g. an 1976 * entire second) if it performs expensive conversions such as that 1977 * needed for user stack traces. Most libdtrace functions are not 1978 * guaranteed to be MT-safe, even when each thread has its own dtrace 1979 * handle; or even if they are safe, there is no guarantee that future 1980 * changes may not make them unsafe. Fortunately in this case, however, 1981 * only a per-consumer lock is necessary to avoid conflict with 1982 * dtrace_work() running in another thread (the consumer loop). 1983 */ 1984 rc = dtrace_aggregate_print(jc->dtjj_consumer->dtjc_dtp, NULL, 1985 dtrace_aggregate_walk_keysorted); 1986 if ((*jenv)->ExceptionCheck(jenv)) { 1987 WRAP_EXCEPTION(jenv); 1988 /* release per-consumer lock */ 1989 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 1990 return (NULL); 1991 } 1992 if (rc != 0) { 1993 dtj_error_t e; 1994 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 1995 /* release per-consumer lock */ 1996 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 1997 return (NULL); 1998 } 1999 2000 if (e.dtje_number != EINTR) { 2001 /* Do not wrap DTraceException */ 2002 dtj_throw_dtrace_exception(jc, e.dtje_message); 2003 /* release per-consumer lock */ 2004 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2005 return (NULL); 2006 } 2007 } 2008 2009 dtj_aggwalk_init(jc); 2010 if ((*jenv)->ExceptionCheck(jenv)) { 2011 WRAP_EXCEPTION(jenv); 2012 /* release per-consumer lock */ 2013 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2014 return (NULL); 2015 } 2016 2017 /* 2018 * dtrace_aggregate_clear() clears all aggregations, and we need to 2019 * clear aggregations selectively. It also fails to preserve the 2020 * lquantize() range and step size; using aggregate_walk() to clear 2021 * aggregations does not have this problem. 2022 */ 2023 rc = dtrace_aggregate_walk(jc->dtjj_consumer->dtjc_dtp, dtj_clear, jc); 2024 if ((*jenv)->ExceptionCheck(jenv)) { 2025 WRAP_EXCEPTION(jenv); 2026 /* release per-consumer lock */ 2027 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2028 return (NULL); 2029 } 2030 if (rc != 0) { 2031 dtj_error_t e; 2032 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 2033 /* Do not wrap DTraceException */ 2034 dtj_throw_dtrace_exception(jc, e.dtje_message); 2035 } 2036 /* release per-consumer lock */ 2037 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2038 return (NULL); 2039 } 2040 2041 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2042 if ((*jenv)->ExceptionCheck(jenv)) { 2043 WRAP_EXCEPTION(jenv); 2044 return (NULL); 2045 } 2046 2047 aggregate = jc->dtjj_aggregate; 2048 jc->dtjj_aggregate = NULL; 2049 2050 return (aggregate); 2051 } 2052 2053 /* 2054 * Process any requests, such as the setting of runtime options, enqueued during 2055 * dtrace_sleep(). A Java exception is pending if this function returns 2056 * DTJ_ERR. 2057 */ 2058 static dtj_status_t 2059 dtj_process_requests(dtj_java_consumer_t *jc) 2060 { 2061 dtj_request_t *r; 2062 uu_list_t *list = jc->dtjj_consumer->dtjc_request_list; 2063 pthread_mutex_t *list_lock = &jc->dtjj_consumer-> 2064 dtjc_request_list_lock; 2065 const char *opt; 2066 const char *val; 2067 2068 (void) pthread_mutex_lock(list_lock); 2069 while (!dtj_list_empty(list)) { 2070 r = uu_list_first(list); 2071 uu_list_remove(list, r); 2072 2073 switch (r->dtjr_type) { 2074 case DTJ_REQUEST_OPTION: 2075 opt = dtj_string_list_first(r->dtjr_args); 2076 val = dtj_string_list_last(r->dtjr_args); 2077 if (dtrace_setopt(jc->dtjj_consumer->dtjc_dtp, opt, 2078 val) == -1) { 2079 /* Do not wrap DTraceException */ 2080 dtj_throw_dtrace_exception(jc, 2081 "failed to set %s: %s", opt, 2082 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 2083 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 2084 dtj_request_destroy(r, NULL); 2085 (void) pthread_mutex_unlock(list_lock); 2086 return (DTJ_ERR); 2087 } 2088 break; 2089 } 2090 dtj_request_destroy(r, NULL); 2091 } 2092 (void) pthread_mutex_unlock(list_lock); 2093 return (DTJ_OK); 2094 } 2095 2096 /* 2097 * Return DTJ_OK if the consumer loop is stopped normally by either the exit() 2098 * action or the Consumer stop() method. Otherwise return DTJ_ERR if the 2099 * consumer loop terminates abnormally with an exception pending. 2100 */ 2101 dtj_status_t 2102 dtj_consume(dtj_java_consumer_t *jc) 2103 { 2104 JNIEnv *jenv = jc->dtjj_jenv; 2105 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 2106 boolean_t done = B_FALSE; 2107 dtj_error_t e; 2108 2109 do { 2110 if (!jc->dtjj_consumer->dtjc_interrupt) { 2111 dtrace_sleep(dtp); 2112 } 2113 2114 if (jc->dtjj_consumer->dtjc_interrupt) { 2115 done = B_TRUE; 2116 dtj_stop(jc); 2117 if ((*jenv)->ExceptionCheck(jenv)) { 2118 /* 2119 * Exception left pending by Consumer 2120 * getAggregate() method. 2121 */ 2122 return (DTJ_ERR); 2123 } 2124 } else if (jc->dtjj_consumer->dtjc_process_list != NULL) { 2125 int nprocs = uu_list_numnodes(jc->dtjj_consumer-> 2126 dtjc_process_list); 2127 if (jc->dtjj_consumer->dtjc_procs_ended == nprocs) { 2128 done = B_TRUE; 2129 dtj_stop(jc); 2130 } 2131 } 2132 2133 /* 2134 * Functions like dtrace_setopt() are not safe to call during 2135 * dtrace_sleep(). Check the request list every time we wake up 2136 * from dtrace_sleep(). 2137 */ 2138 if (!done) { 2139 if (dtj_process_requests(jc) != DTJ_OK) { 2140 /* Do not wrap DTraceException */ 2141 return (DTJ_ERR); 2142 } 2143 } 2144 2145 /* 2146 * Use the per-consumer lock to avoid conflict with 2147 * get_aggregate() called from another thread. 2148 */ 2149 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 2150 if ((*jenv)->ExceptionCheck(jenv)) { 2151 WRAP_EXCEPTION(jenv); 2152 return (DTJ_ERR); 2153 } 2154 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2155 g_interval_began_jm); 2156 if ((*jenv)->ExceptionCheck(jenv)) { 2157 /* Don't wrap exception thrown from ConsumerListener */ 2158 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2159 return (DTJ_ERR); 2160 } 2161 jc->dtjj_consumer->dtjc_printa_snaptime = gethrtime(); 2162 switch (dtrace_work(dtp, NULL, dtj_chew, dtj_chewrec, jc)) { 2163 case DTRACE_WORKSTATUS_DONE: 2164 done = B_TRUE; 2165 break; 2166 case DTRACE_WORKSTATUS_OKAY: 2167 break; 2168 default: 2169 /* 2170 * Check for a pending exception that got us to this 2171 * error workstatus case. 2172 */ 2173 if ((*jenv)->ExceptionCheck(jenv)) { 2174 /* 2175 * Ensure valid initial state before releasing 2176 * the consumer lock 2177 */ 2178 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2179 /* Do not wrap DTraceException */ 2180 /* Release per-consumer lock */ 2181 (*jenv)->MonitorExit(jenv, 2182 jc->dtjj_consumer_lock); 2183 return (DTJ_ERR); 2184 } 2185 2186 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 2187 /* java exception pending */ 2188 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2189 /* Release per-consumer lock */ 2190 (*jenv)->MonitorExit(jenv, 2191 jc->dtjj_consumer_lock); 2192 return (DTJ_ERR); 2193 } 2194 2195 if (e.dtje_number != EINTR) { 2196 /* Do not wrap DTraceException */ 2197 dtj_throw_dtrace_exception(jc, e.dtje_message); 2198 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2199 /* Release per-consumer lock */ 2200 (*jenv)->MonitorExit(jenv, 2201 jc->dtjj_consumer_lock); 2202 return (DTJ_ERR); 2203 } 2204 } 2205 /* 2206 * Check for ConsumerException before doing anything else with 2207 * the JNIEnv. 2208 */ 2209 if ((*jenv)->ExceptionCheck(jenv)) { 2210 /* 2211 * Do not wrap exception thrown from ConsumerListener. 2212 */ 2213 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2214 /* Release per-consumer lock */ 2215 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2216 return (DTJ_ERR); 2217 } 2218 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2219 /* 2220 * Notify ConsumerListeners the the dtrace_work() interval ended 2221 * before releasing the lock. 2222 */ 2223 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2224 g_interval_ended_jm); 2225 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2226 if ((*jenv)->ExceptionCheck(jenv)) { 2227 /* Don't wrap exception thrown from ConsumerListener */ 2228 return (DTJ_ERR); 2229 } 2230 2231 /* 2232 * Check for a temporarily cleared exception set by a handler 2233 * that could not safely leave the exception pending because it 2234 * could not return an abort signal. Rethrow it now that it's 2235 * safe to do so (when it's possible to ensure that no JNI calls 2236 * will be made that are unsafe while an exception is pending). 2237 */ 2238 if (jc->dtjj_exception) { 2239 (*jenv)->Throw(jenv, jc->dtjj_exception); 2240 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_exception); 2241 jc->dtjj_exception = NULL; 2242 return (DTJ_ERR); 2243 } 2244 } while (!done); 2245 2246 return (DTJ_OK); 2247 } 2248