xref: /titanic_44/usr/src/lib/libdtrace_jni/common/dtj_consume.c (revision 9dd0f810214fdc8e1af881a9a5c4b6927629ff9e)
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