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