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