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