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