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 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 } 1788 1789 tuple_member_count = (*jenv)->CallIntMethod(jenv, 1790 jc->dtjj_tuple, g_tuplesize_jm); 1791 if (tuple_member_count < 1792 jc->dtjj_consumer->dtjc_expected) { 1793 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1794 g_pdatainvalidate_printa_jm); 1795 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1796 jc->dtjj_tuple = NULL; 1797 } 1798 1799 if (jc->dtjj_tuple == NULL) { 1800 goto printa_output; 1801 } 1802 1803 itr = uu_list_walk_start(jc->dtjj_aggval_list, 0); 1804 while ((aggval = uu_list_walk_next(itr)) != NULL) { 1805 /* 1806 * new AggregationRecord: Combine the aggregation value 1807 * with the saved tuple and add it to the current 1808 * Aggregate or PrintaRecord. 1809 */ 1810 jrec = (*jenv)->NewObject(jenv, g_aggrec_jc, 1811 g_aggrecinit_jm, jc->dtjj_tuple, 1812 aggval->dtja_value); 1813 (*jenv)->DeleteLocalRef(jenv, aggval->dtja_value); 1814 aggval->dtja_value = NULL; 1815 if (!jrec) { 1816 /* java exception pending */ 1817 WRAP_EXCEPTION(jenv); 1818 return (DTRACE_HANDLE_ABORT); 1819 } 1820 1821 /* aggregation name */ 1822 jname = (*jenv)->NewStringUTF(jenv, 1823 aggval->dtja_aggname); 1824 if (!jname) { 1825 /* OutOfMemoryError pending */ 1826 (*jenv)->DeleteLocalRef(jenv, jrec); 1827 return (DTRACE_HANDLE_ABORT); 1828 } 1829 1830 /* 1831 * If the printa() format string specifies the value of 1832 * the aggregating action multiple times, PrintaRecord 1833 * ignores the attempt to add the duplicate record. 1834 */ 1835 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1836 /* add to PrintaRecord */ 1837 (*jenv)->CallVoidMethod(jenv, 1838 jc->dtjj_probedata, 1839 g_pdataadd_aggrec_jm, 1840 jname, aggval->dtja_aggid, jrec); 1841 } else { 1842 /* add to Aggregate */ 1843 (*jenv)->CallVoidMethod(jenv, 1844 jc->dtjj_aggregate, g_aggaddrec_jm, 1845 jname, aggval->dtja_aggid, jrec); 1846 } 1847 1848 (*jenv)->DeleteLocalRef(jenv, jrec); 1849 (*jenv)->DeleteLocalRef(jenv, jname); 1850 if ((*jenv)->ExceptionCheck(jenv)) { 1851 WRAP_EXCEPTION(jenv); 1852 return (DTRACE_HANDLE_ABORT); 1853 } 1854 } 1855 uu_list_walk_end(itr); 1856 dtj_list_clear(jc->dtjj_aggval_list, dtj_aggval_destroy, 1857 jenv); 1858 1859 printa_output: 1860 if (jc->dtjj_consumer->dtjc_printa_snaptime) { 1861 /* 1862 * Get the formatted string associated with the current 1863 * tuple if this is a printa() callback. 1864 */ 1865 jstring jstr = (*jenv)->CallObjectMethod(jenv, 1866 jc->dtjj_printa_buffer, g_tostring_jm); 1867 if ((*jenv)->ExceptionCheck(jenv)) { 1868 WRAP_EXCEPTION(jenv); 1869 return (DTRACE_HANDLE_ABORT); 1870 } 1871 /* 1872 * Clear the StringBuffer: this does not throw 1873 * exceptions. Reuse the StringBuffer until the end of 1874 * the current probedata then dispose of it. 1875 */ 1876 (*jenv)->CallVoidMethod(jenv, jc->dtjj_printa_buffer, 1877 g_bufsetlen_jm, 0); 1878 /* Add formatted string to PrintaRecord */ 1879 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probedata, 1880 g_pdataadd_printa_str_jm, jc->dtjj_tuple, jstr); 1881 (*jenv)->DeleteLocalRef(jenv, jstr); 1882 if ((*jenv)->ExceptionCheck(jenv)) { 1883 WRAP_EXCEPTION(jenv); 1884 return (DTRACE_HANDLE_ABORT); 1885 } 1886 } 1887 1888 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_tuple); 1889 jc->dtjj_tuple = NULL; 1890 jc->dtjj_consumer->dtjc_expected = -1; 1891 } 1892 1893 return (DTRACE_HANDLE_OK); 1894 } 1895 1896 /* 1897 * Return B_TRUE if the aggregation is included, B_FALSE otherwise. Only in the 1898 * latter case might there be an exception pending. 1899 */ 1900 static boolean_t 1901 dtj_is_included(const dtrace_aggdata_t *data, dtj_java_consumer_t *jc) 1902 { 1903 JNIEnv *jenv = jc->dtjj_jenv; 1904 1905 if (jc->dtjj_aggregate_spec) { 1906 jboolean included; 1907 jstring aggname = NULL; 1908 1909 const dtrace_aggdesc_t *aggdesc = data->dtada_desc; 1910 aggname = (*jenv)->NewStringUTF(jenv, aggdesc->dtagd_name); 1911 if (!aggname) { 1912 /* java exception pending */ 1913 return (B_FALSE); 1914 } 1915 1916 included = (*jenv)->CallBooleanMethod(jenv, 1917 jc->dtjj_aggregate_spec, g_aggspec_included_jm, 1918 aggname); 1919 (*jenv)->DeleteLocalRef(jenv, aggname); 1920 if ((*jenv)->ExceptionCheck(jenv)) { 1921 WRAP_EXCEPTION(jenv); 1922 return (B_FALSE); 1923 } 1924 1925 return (included); 1926 } 1927 1928 return (B_TRUE); 1929 } 1930 1931 /* 1932 * Return NULL if a java exception is pending, otherwise return a new 1933 * AggregationValue instance. 1934 */ 1935 static jobject 1936 dtj_new_aggval(dtj_java_consumer_t *jc, const dtrace_aggdata_t *data, 1937 const dtrace_recdesc_t *rec) 1938 { 1939 JNIEnv *jenv = jc->dtjj_jenv; 1940 1941 jobject jvalue = NULL; /* return value */ 1942 1943 dtrace_actkind_t act; 1944 uint64_t normal; 1945 caddr_t addr; 1946 int64_t value; 1947 1948 act = rec->dtrd_action; 1949 normal = data->dtada_normal; 1950 addr = data->dtada_data + rec->dtrd_offset; 1951 if (act == DTRACEAGG_AVG) { 1952 value = dtj_average(addr, normal); 1953 } else { 1954 /* LINTED - alignment */ 1955 value = (*((int64_t *)addr)) / normal; 1956 } 1957 1958 if (act == DTRACEAGG_QUANTIZE || act == DTRACEAGG_LQUANTIZE) { 1959 jvalue = dtj_new_distribution(data, rec, jc); 1960 } else { 1961 switch (act) { 1962 case DTRACEAGG_COUNT: 1963 jvalue = (*jenv)->NewObject(jenv, g_aggcount_jc, 1964 g_aggcountinit_jm, value); 1965 break; 1966 case DTRACEAGG_SUM: 1967 jvalue = (*jenv)->NewObject(jenv, g_aggsum_jc, 1968 g_aggsuminit_jm, value); 1969 break; 1970 case DTRACEAGG_AVG: 1971 jvalue = (*jenv)->NewObject(jenv, g_aggavg_jc, 1972 g_aggavginit_jm, value, dtj_avg_total(addr, 1973 normal), dtj_avg_count(addr)); 1974 break; 1975 case DTRACEAGG_MIN: 1976 jvalue = (*jenv)->NewObject(jenv, g_aggmin_jc, 1977 g_aggmininit_jm, value); 1978 break; 1979 case DTRACEAGG_MAX: 1980 jvalue = (*jenv)->NewObject(jenv, g_aggmax_jc, 1981 g_aggmaxinit_jm, value); 1982 break; 1983 default: 1984 jvalue = NULL; 1985 dtj_throw_illegal_argument(jenv, 1986 "unexpected aggregation action: %d", act); 1987 } 1988 } 1989 1990 return (jvalue); 1991 } 1992 1993 /* 1994 * Stops the given consumer if it is running. Throws DTraceException if 1995 * dtrace_stop() fails and no other exception is already pending. Clears and 1996 * rethrows any pending exception in order to grab the global lock safely. 1997 */ 1998 void 1999 dtj_stop(dtj_java_consumer_t *jc) 2000 { 2001 JNIEnv *jenv; 2002 int rc; 2003 jthrowable e; 2004 2005 switch (jc->dtjj_consumer->dtjc_state) { 2006 case DTJ_CONSUMER_GO: 2007 case DTJ_CONSUMER_START: 2008 break; 2009 default: 2010 return; 2011 } 2012 2013 jenv = jc->dtjj_jenv; 2014 e = (*jenv)->ExceptionOccurred(jenv); 2015 if (e) { 2016 (*jenv)->ExceptionClear(jenv); 2017 } 2018 2019 (*jenv)->MonitorEnter(jenv, g_caller_jc); 2020 if ((*jenv)->ExceptionCheck(jenv)) { 2021 goto rethrow; 2022 } 2023 2024 rc = dtrace_status(jc->dtjj_consumer->dtjc_dtp); 2025 if (rc != DTRACE_STATUS_STOPPED) { 2026 rc = dtrace_stop(jc->dtjj_consumer->dtjc_dtp); 2027 } 2028 2029 (*jenv)->MonitorExit(jenv, g_caller_jc); 2030 if ((*jenv)->ExceptionCheck(jenv)) { 2031 goto rethrow; 2032 } 2033 2034 if (rc == -1) { 2035 (*jenv)->MonitorEnter(jenv, g_caller_jc); 2036 if ((*jenv)->ExceptionCheck(jenv)) { 2037 goto rethrow; 2038 } 2039 /* Do not wrap DTraceException */ 2040 dtj_throw_dtrace_exception(jc, 2041 "couldn't stop tracing: %s", 2042 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 2043 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 2044 /* safe to call with pending exception */ 2045 (*jenv)->MonitorExit(jenv, g_caller_jc); 2046 } else { 2047 jc->dtjj_consumer->dtjc_state = DTJ_CONSUMER_STOP; 2048 } 2049 2050 rethrow: 2051 if (e) { 2052 if ((*jenv)->ExceptionCheck(jenv)) { 2053 /* 2054 * Favor earlier pending exception over 2055 * exception thrown in this function. 2056 */ 2057 (*jenv)->ExceptionClear(jenv); 2058 } 2059 (*jenv)->Throw(jenv, e); 2060 (*jenv)->DeleteLocalRef(jenv, e); 2061 } 2062 } 2063 2064 /* 2065 * Return Aggregate instance, or null if java exception pending. 2066 */ 2067 jobject 2068 dtj_get_aggregate(dtj_java_consumer_t *jc) 2069 { 2070 JNIEnv *jenv = jc->dtjj_jenv; 2071 hrtime_t snaptime; 2072 int rc; 2073 2074 jobject aggregate = NULL; 2075 2076 /* 2077 * Aggregations must be snapped, walked, and cleared atomically, 2078 * otherwise clearing loses data accumulated since the most recent snap. 2079 * This per-consumer lock prevents dtrace_work() from snapping or 2080 * clearing aggregations while we're in the middle of this atomic 2081 * operation, so we continue to hold it until done clearing. 2082 */ 2083 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 2084 if ((*jenv)->ExceptionCheck(jenv)) { 2085 WRAP_EXCEPTION(jenv); 2086 return (NULL); 2087 } 2088 2089 dtj_aggwalk_init(jc); 2090 if ((*jenv)->ExceptionCheck(jenv)) { 2091 WRAP_EXCEPTION(jenv); 2092 /* release per-consumer lock */ 2093 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2094 return (NULL); 2095 } 2096 2097 /* 2098 * Snap aggregations 2099 * 2100 * We need to record the snaptime here for the caller. Leaving it to 2101 * the caller to record the snaptime before calling getAggregate() may 2102 * be inaccurate because of the indeterminate delay waiting on the 2103 * consumer lock before calling dtrace_aggregate_snap(). 2104 */ 2105 snaptime = gethrtime(); 2106 if (dtrace_aggregate_snap(jc->dtjj_consumer->dtjc_dtp) != 0) { 2107 dtj_error_t e; 2108 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 2109 /* Do not wrap DTraceException */ 2110 dtj_throw_dtrace_exception(jc, e.dtje_message); 2111 } 2112 /* release per-consumer lock */ 2113 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2114 return (NULL); 2115 } 2116 2117 /* Create the Java representation of the aggregate snapshot. */ 2118 aggregate = (*jenv)->NewObject(jenv, g_agg_jc, g_agginit_jm, 2119 snaptime); 2120 if ((*jenv)->ExceptionCheck(jenv)) { 2121 WRAP_EXCEPTION(jenv); 2122 /* release per-consumer lock */ 2123 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2124 return (NULL); 2125 } 2126 jc->dtjj_aggregate = aggregate; 2127 2128 /* 2129 * Walk the aggregate, converting the data into Java Objects. Traverse 2130 * in order by aggregation ID first and tuple second by using 2131 * dtrace_aggregate_walk_keysorted (uses varkeycmp). We cannot do the 2132 * same for aggregations generated by the printa() action, since 2133 * dtrace_work() traverses aggregation data in the order determined by 2134 * the various "aggsort" options. Functions used by both the consumer 2135 * loop and the competing getAggregate() thread must not depend on the 2136 * ordering of records by tuple key. 2137 * 2138 * It is impractical to hold the global lock around 2139 * dtrace_aggregate_print(), since it may take a long time (e.g. an 2140 * entire second) if it performs expensive conversions such as that 2141 * needed for user stack traces. Most libdtrace functions are not 2142 * guaranteed to be MT-safe, even when each thread has its own dtrace 2143 * handle; or even if they are safe, there is no guarantee that future 2144 * changes may not make them unsafe. Fortunately in this case, however, 2145 * only a per-consumer lock is necessary to avoid conflict with 2146 * dtrace_work() running in another thread (the consumer loop). 2147 */ 2148 rc = dtrace_aggregate_print(jc->dtjj_consumer->dtjc_dtp, NULL, 2149 dtrace_aggregate_walk_keysorted); 2150 if ((*jenv)->ExceptionCheck(jenv)) { 2151 WRAP_EXCEPTION(jenv); 2152 /* release per-consumer lock */ 2153 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2154 return (NULL); 2155 } 2156 if (rc != 0) { 2157 dtj_error_t e; 2158 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 2159 /* release per-consumer lock */ 2160 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2161 return (NULL); 2162 } 2163 2164 if (e.dtje_number != EINTR) { 2165 /* Do not wrap DTraceException */ 2166 dtj_throw_dtrace_exception(jc, e.dtje_message); 2167 /* release per-consumer lock */ 2168 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2169 return (NULL); 2170 } 2171 } 2172 2173 dtj_aggwalk_init(jc); 2174 if ((*jenv)->ExceptionCheck(jenv)) { 2175 WRAP_EXCEPTION(jenv); 2176 /* release per-consumer lock */ 2177 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2178 return (NULL); 2179 } 2180 2181 /* 2182 * dtrace_aggregate_clear() clears all aggregations, and we need to 2183 * clear aggregations selectively. It also fails to preserve the 2184 * lquantize() range and step size; using aggregate_walk() to clear 2185 * aggregations does not have this problem. 2186 */ 2187 rc = dtrace_aggregate_walk(jc->dtjj_consumer->dtjc_dtp, dtj_clear, jc); 2188 if ((*jenv)->ExceptionCheck(jenv)) { 2189 WRAP_EXCEPTION(jenv); 2190 /* release per-consumer lock */ 2191 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2192 return (NULL); 2193 } 2194 if (rc != 0) { 2195 dtj_error_t e; 2196 if (dtj_get_dtrace_error(jc, &e) == DTJ_OK) { 2197 /* Do not wrap DTraceException */ 2198 dtj_throw_dtrace_exception(jc, e.dtje_message); 2199 } 2200 /* release per-consumer lock */ 2201 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2202 return (NULL); 2203 } 2204 2205 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2206 if ((*jenv)->ExceptionCheck(jenv)) { 2207 WRAP_EXCEPTION(jenv); 2208 return (NULL); 2209 } 2210 2211 aggregate = jc->dtjj_aggregate; 2212 jc->dtjj_aggregate = NULL; 2213 2214 return (aggregate); 2215 } 2216 2217 /* 2218 * Process any requests, such as the setting of runtime options, enqueued during 2219 * dtrace_sleep(). A Java exception is pending if this function returns 2220 * DTJ_ERR. 2221 */ 2222 static dtj_status_t 2223 dtj_process_requests(dtj_java_consumer_t *jc) 2224 { 2225 dtj_request_t *r; 2226 uu_list_t *list = jc->dtjj_consumer->dtjc_request_list; 2227 pthread_mutex_t *list_lock = &jc->dtjj_consumer-> 2228 dtjc_request_list_lock; 2229 const char *opt; 2230 const char *val; 2231 2232 (void) pthread_mutex_lock(list_lock); 2233 while (!dtj_list_empty(list)) { 2234 r = uu_list_first(list); 2235 uu_list_remove(list, r); 2236 2237 switch (r->dtjr_type) { 2238 case DTJ_REQUEST_OPTION: 2239 opt = dtj_string_list_first(r->dtjr_args); 2240 val = dtj_string_list_last(r->dtjr_args); 2241 if (dtrace_setopt(jc->dtjj_consumer->dtjc_dtp, opt, 2242 val) == -1) { 2243 /* Do not wrap DTraceException */ 2244 dtj_throw_dtrace_exception(jc, 2245 "failed to set %s: %s", opt, 2246 dtrace_errmsg(jc->dtjj_consumer->dtjc_dtp, 2247 dtrace_errno(jc->dtjj_consumer->dtjc_dtp))); 2248 dtj_request_destroy(r, NULL); 2249 (void) pthread_mutex_unlock(list_lock); 2250 return (DTJ_ERR); 2251 } 2252 break; 2253 } 2254 dtj_request_destroy(r, NULL); 2255 } 2256 (void) pthread_mutex_unlock(list_lock); 2257 return (DTJ_OK); 2258 } 2259 2260 /* 2261 * Return DTJ_OK if the consumer loop is stopped normally by either the exit() 2262 * action or the Consumer stop() method. Otherwise return DTJ_ERR if the 2263 * consumer loop terminates abnormally with an exception pending. 2264 */ 2265 dtj_status_t 2266 dtj_consume(dtj_java_consumer_t *jc) 2267 { 2268 JNIEnv *jenv = jc->dtjj_jenv; 2269 dtrace_hdl_t *dtp = jc->dtjj_consumer->dtjc_dtp; 2270 boolean_t done = B_FALSE; 2271 dtj_error_t e; 2272 2273 do { 2274 if (!jc->dtjj_consumer->dtjc_interrupt) { 2275 dtrace_sleep(dtp); 2276 } 2277 2278 if (jc->dtjj_consumer->dtjc_interrupt) { 2279 done = B_TRUE; 2280 dtj_stop(jc); 2281 if ((*jenv)->ExceptionCheck(jenv)) { 2282 /* 2283 * Exception left pending by Consumer 2284 * getAggregate() method. 2285 */ 2286 return (DTJ_ERR); 2287 } 2288 } else if (jc->dtjj_consumer->dtjc_process_list != NULL) { 2289 int nprocs = uu_list_numnodes(jc->dtjj_consumer-> 2290 dtjc_process_list); 2291 if (jc->dtjj_consumer->dtjc_procs_ended == nprocs) { 2292 done = B_TRUE; 2293 dtj_stop(jc); 2294 } 2295 } 2296 2297 /* 2298 * Functions like dtrace_setopt() are not safe to call during 2299 * dtrace_sleep(). Check the request list every time we wake up 2300 * from dtrace_sleep(). 2301 */ 2302 if (!done) { 2303 if (dtj_process_requests(jc) != DTJ_OK) { 2304 /* Do not wrap DTraceException */ 2305 return (DTJ_ERR); 2306 } 2307 } 2308 2309 /* 2310 * Use the per-consumer lock to avoid conflict with 2311 * get_aggregate() called from another thread. 2312 */ 2313 (*jenv)->MonitorEnter(jenv, jc->dtjj_consumer_lock); 2314 if ((*jenv)->ExceptionCheck(jenv)) { 2315 WRAP_EXCEPTION(jenv); 2316 return (DTJ_ERR); 2317 } 2318 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2319 g_interval_began_jm); 2320 if ((*jenv)->ExceptionCheck(jenv)) { 2321 /* Don't wrap exception thrown from ConsumerListener */ 2322 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2323 return (DTJ_ERR); 2324 } 2325 jc->dtjj_consumer->dtjc_printa_snaptime = gethrtime(); 2326 switch (dtrace_work(dtp, NULL, dtj_chew, dtj_chewrec, jc)) { 2327 case DTRACE_WORKSTATUS_DONE: 2328 done = B_TRUE; 2329 break; 2330 case DTRACE_WORKSTATUS_OKAY: 2331 break; 2332 default: 2333 /* 2334 * Check for a pending exception that got us to this 2335 * error workstatus case. 2336 */ 2337 if ((*jenv)->ExceptionCheck(jenv)) { 2338 /* 2339 * Ensure valid initial state before releasing 2340 * the consumer lock 2341 */ 2342 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2343 /* Do not wrap DTraceException */ 2344 /* Release per-consumer lock */ 2345 (*jenv)->MonitorExit(jenv, 2346 jc->dtjj_consumer_lock); 2347 return (DTJ_ERR); 2348 } 2349 2350 if (dtj_get_dtrace_error(jc, &e) != DTJ_OK) { 2351 /* java exception pending */ 2352 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2353 /* Release per-consumer lock */ 2354 (*jenv)->MonitorExit(jenv, 2355 jc->dtjj_consumer_lock); 2356 return (DTJ_ERR); 2357 } 2358 2359 if (e.dtje_number != EINTR) { 2360 /* Do not wrap DTraceException */ 2361 dtj_throw_dtrace_exception(jc, e.dtje_message); 2362 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2363 /* Release per-consumer lock */ 2364 (*jenv)->MonitorExit(jenv, 2365 jc->dtjj_consumer_lock); 2366 return (DTJ_ERR); 2367 } 2368 } 2369 /* 2370 * Check for ConsumerException before doing anything else with 2371 * the JNIEnv. 2372 */ 2373 if ((*jenv)->ExceptionCheck(jenv)) { 2374 /* 2375 * Do not wrap exception thrown from ConsumerListener. 2376 */ 2377 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2378 /* Release per-consumer lock */ 2379 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2380 return (DTJ_ERR); 2381 } 2382 jc->dtjj_consumer->dtjc_printa_snaptime = 0; 2383 /* 2384 * Notify ConsumerListeners the the dtrace_work() interval ended 2385 * before releasing the lock. 2386 */ 2387 (*jenv)->CallVoidMethod(jenv, jc->dtjj_caller, 2388 g_interval_ended_jm); 2389 (*jenv)->MonitorExit(jenv, jc->dtjj_consumer_lock); 2390 if ((*jenv)->ExceptionCheck(jenv)) { 2391 /* Don't wrap exception thrown from ConsumerListener */ 2392 return (DTJ_ERR); 2393 } 2394 2395 /* 2396 * Check for a temporarily cleared exception set by a handler 2397 * that could not safely leave the exception pending because it 2398 * could not return an abort signal. Rethrow it now that it's 2399 * safe to do so (when it's possible to ensure that no JNI calls 2400 * will be made that are unsafe while an exception is pending). 2401 */ 2402 if (jc->dtjj_exception) { 2403 (*jenv)->Throw(jenv, jc->dtjj_exception); 2404 (*jenv)->DeleteLocalRef(jenv, jc->dtjj_exception); 2405 jc->dtjj_exception = NULL; 2406 return (DTJ_ERR); 2407 } 2408 } while (!done); 2409 2410 return (DTJ_OK); 2411 } 2412