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 <errno.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <libgen.h>
33 #include <assert.h>
34 #include <strings.h>
35 #include <libproc.h>
36 #include <pthread.h>
37 #include <dtrace_jni.h>
38 /* generated by javah */
39 #include <LocalConsumer.h>
40
41 /*
42 * dtrace_jni.c defines all the native methods of the Java DTrace API. Every
43 * native method is declared in a single class, LocalConsumer.java.
44 *
45 * Notes:
46 *
47 * The data generating loop must explicitly release every object reference it
48 * obtains in order to avoid a memory leak. A local JNI object reference is not
49 * automatically released until control returns to java, which never happens as
50 * long as the data generating loop runs. This applies to any JNI function that
51 * obtains an object reference (such as CallObjectMethod() or NewObject()). A
52 * local reference is released by calling DeleteLocalRef(), which is safe to
53 * call with an exception pending.
54 *
55 * It is important to check for an exception after calling java code from native
56 * C, such as after notifying the java consumer of new data. Failure to do this
57 * makes it possible for users of the interface to crash the JVM by throwing an
58 * exception in java code.
59 *
60 * Some JNI functions, like GetIntField() or ReleaseStringUTFChars(), do not
61 * need to be checked for exceptions.
62 *
63 * GetStringUTFChars() returns NULL if and only if an exception was thrown.
64 *
65 * It is important to stop a DTrace consumer and remove it if an exception
66 * occurs. This API guarantees that a consumer is stopped automatically if it
67 * throws an exception. An application running multiple DTrace consumers
68 * simultaneously should be able to continue running the others normally if any
69 * fail.
70 *
71 * Calls to libdtrace are not guaranteed to be MT-safe. Even if they are
72 * currently MT-safe, they are not guaranteed to remain that way. To address
73 * this, a global lock (the LocalConsumer.class reference) is used around calls
74 * to libdtrace. In many cases, the locking is done in java, which should be
75 * indicated in this file by a comment above the function that assumes prior
76 * locking. To access the same global lock from native C code, the JNI function
77 * MonitorEnter() is used. Each MonitorEnter() must have a matching
78 * MonitorExit() or the application will hang (all consumer threads). The
79 * consumer loop and the getAggregate() method require a per-consumer lock
80 * rather than a global lock; in that case the argument to MonitorEnter() and
81 * MonitorExit() is the consumerLock member of the LocalConsumer, not the
82 * LocalConsumer itself.
83 */
84
85 /*
86 * Increment the version whenever there is a change in the interface between
87 * Java and native code, whether from Java into native code:
88 * - LocalConsumer.h (generated by javah)
89 * or from native code back into Java:
90 * - dtj_table_load() in dtj_jnitab.c
91 * Changes to dtj_load_common() in dtj_util.c should not normally require a
92 * version update, since dtj_util.c defines classes in the JDK, not classes in
93 * the Java DTrace API.
94 *
95 * This version needs to match the version in LocalConsumer.java
96 */
97 #define DTRACE_JNI_VERSION 3
98
99 #define FIRST_HANDLE 0 /* sequence-generated consumer ID */
100 #define NO_HANDLE -1
101 #define INITIAL_CAPACITY 8 /* initial size of consumer array */
102 #define MAX_CAPACITY_INCREMENT 1024
103
104 static boolean_t g_dtj_load = B_FALSE;
105 static int g_handle_seq = NO_HANDLE;
106 /*
107 * key: caller's consumer handle (int)
108 * value: per-consumer data includes dtrace handle (consumer_t *)
109 */
110 static dtj_consumer_t **g_consumer_table = NULL;
111 static size_t g_consumer_capacity = 0;
112 static size_t g_consumer_count = 0;
113 static size_t g_max_capacity_increment = MAX_CAPACITY_INCREMENT;
114 static size_t g_max_consumers = 0; /* no maximum */
115 static boolean_t g_init = B_FALSE;
116 static pthread_mutex_t g_table_lock;
117 static pthread_mutexattr_t g_table_lock_attr;
118 pthread_key_t g_dtj_consumer_key;
119
120 static int dtj_get_handle(JNIEnv *, jobject);
121 static dtj_status_t dtj_get_java_consumer(JNIEnv *, jobject,
122 dtj_java_consumer_t *);
123 static const char *dtj_getexecname(void);
124 static jobject dtj_get_program_info(dtj_java_consumer_t *, dtrace_proginfo_t *);
125 static jobject dtj_add_program(dtj_java_consumer_t *, dtj_program_t *);
126 static void dtj_flag(uint_t *, uint_t, boolean_t *, boolean_t *);
127 static boolean_t dtj_cflag(dtj_java_consumer_t *, const char *, boolean_t *,
128 boolean_t *);
129 static void dtj_list_probes(JNIEnv *, jobject, jobject, jobject,
130 dtrace_probe_f *);
131 static void dtj_list_compiled_probes(JNIEnv *, jobject, jobject, jobject,
132 dtrace_probe_f *);
133 static int dtj_list_probe(dtrace_hdl_t *, const dtrace_probedesc_t *, void *);
134 static int dtj_list_probe_detail(dtrace_hdl_t *, const dtrace_probedesc_t *,
135 void *);
136 static int dtj_list_stmt(dtrace_hdl_t *, dtrace_prog_t *, dtrace_stmtdesc_t *,
137 void *);
138 static boolean_t dtj_add_consumer(JNIEnv *, dtj_consumer_t *, int *);
139 static dtj_consumer_t *dtj_remove_consumer(JNIEnv *, jobject);
140 static dtj_consumer_t *dtj_remove_consumer_at(int);
141
142 /*
143 * Gets a sequence-generated consumer ID, or NO_HANDLE if exception pending
144 */
145 static int
dtj_get_handle(JNIEnv * jenv,jobject caller)146 dtj_get_handle(JNIEnv *jenv, jobject caller)
147 {
148 int handle;
149
150 if (!g_dtj_load) {
151 dtj_throw_illegal_state(jenv, "JNI table not loaded");
152 return (NO_HANDLE);
153 }
154 handle = (*jenv)->CallIntMethod(jenv, caller, g_gethandle_jm);
155 if ((*jenv)->ExceptionCheck(jenv)) {
156 return (NO_HANDLE);
157 }
158 if (handle == NO_HANDLE) {
159 dtj_throw_illegal_state(jenv, "no consumer handle");
160 }
161 return (handle);
162 }
163
164 /*
165 * Populates the given java consumer created for use in the current native
166 * method call. If the return value is DTJ_ERR, a java exception is pending.
167 * Throws IllegalStateException if the caller does not have a valid handle.
168 * Throws NoSuchElementException if the caller's handle is not in the global
169 * caller table.
170 */
171 static dtj_status_t
dtj_get_java_consumer(JNIEnv * jenv,jobject caller,dtj_java_consumer_t * jc)172 dtj_get_java_consumer(JNIEnv *jenv, jobject caller, dtj_java_consumer_t *jc)
173 {
174 dtj_consumer_t *consumer;
175 int handle = dtj_get_handle(jenv, caller);
176 if (handle == NO_HANDLE) {
177 return (DTJ_ERR); /* java exception pending */
178 }
179 (void) pthread_mutex_lock(&g_table_lock);
180 if (g_consumer_table) {
181 if ((handle >= 0) && (handle < g_consumer_capacity)) {
182 consumer = g_consumer_table[handle];
183 } else {
184 consumer = NULL;
185 }
186 } else {
187 consumer = NULL;
188 }
189 (void) pthread_mutex_unlock(&g_table_lock);
190 if (consumer == NULL) {
191 dtj_throw_no_such_element(jenv, "consumer handle %d", handle);
192 return (DTJ_ERR);
193 }
194
195 /* Initialize java consumer */
196 bzero(jc, sizeof (dtj_java_consumer_t));
197
198 /* Attach per-consumer data */
199 jc->dtjj_consumer = consumer;
200
201 /* Attach per-JNI-invocation data */
202 jc->dtjj_caller = caller;
203 jc->dtjj_jenv = jenv;
204
205 return (DTJ_OK);
206 }
207
208 /*
209 * Adds a consumer to the global consumer table.
210 * Returns B_TRUE if successful; a java exception is pending otherwise.
211 * Postcondition: if successful, g_handle_seq is the handle of the consumer just
212 * added.
213 */
214 static boolean_t
dtj_add_consumer(JNIEnv * jenv,dtj_consumer_t * c,int * seq)215 dtj_add_consumer(JNIEnv *jenv, dtj_consumer_t *c, int *seq)
216 {
217 int start;
218
219 if (!g_init) {
220 (void) pthread_key_create(&g_dtj_consumer_key, NULL);
221 (void) pthread_mutexattr_init(&g_table_lock_attr);
222 (void) pthread_mutexattr_settype(&g_table_lock_attr,
223 PTHREAD_MUTEX_RECURSIVE);
224 (void) pthread_mutex_init(&g_table_lock,
225 &g_table_lock_attr);
226 g_init = B_TRUE;
227 }
228
229 *seq = NO_HANDLE;
230 (void) pthread_mutex_lock(&g_table_lock);
231 if (g_consumer_table == NULL) {
232 g_consumer_table = malloc(INITIAL_CAPACITY *
233 sizeof (dtj_consumer_t *));
234 if (!g_consumer_table) {
235 g_handle_seq = NO_HANDLE;
236 dtj_throw_out_of_memory(jenv,
237 "could not allocate consumer table");
238 (void) pthread_mutex_unlock(&g_table_lock);
239 return (B_FALSE);
240 }
241 bzero(g_consumer_table, (INITIAL_CAPACITY *
242 sizeof (dtj_consumer_t *)));
243 g_consumer_capacity = INITIAL_CAPACITY;
244 } else if ((g_max_consumers > 0) && (g_consumer_count >=
245 g_max_consumers)) {
246 dtj_throw_resource_limit(jenv, "Too many consumers");
247 (void) pthread_mutex_unlock(&g_table_lock);
248 return (B_FALSE);
249 } else if (g_consumer_count >= g_consumer_capacity) {
250 dtj_consumer_t **t;
251 size_t new_capacity;
252
253 if (g_consumer_capacity <= g_max_capacity_increment) {
254 new_capacity = (g_consumer_capacity * 2);
255 } else {
256 new_capacity = (g_consumer_capacity +
257 g_max_capacity_increment);
258 }
259
260 if ((g_max_consumers > 0) && (new_capacity > g_max_consumers)) {
261 new_capacity = g_max_consumers;
262 }
263
264 t = realloc(g_consumer_table,
265 new_capacity * sizeof (dtj_consumer_t *));
266 if (!t) {
267 dtj_throw_out_of_memory(jenv,
268 "could not reallocate consumer table");
269 (void) pthread_mutex_unlock(&g_table_lock);
270 return (B_FALSE);
271 }
272
273 g_consumer_table = t;
274 bzero(g_consumer_table + g_consumer_capacity, ((new_capacity -
275 g_consumer_capacity) * sizeof (dtj_consumer_t *)));
276 g_consumer_capacity = new_capacity;
277 }
278
279 /* Look for an empty slot in the table */
280 g_handle_seq = (g_handle_seq == NO_HANDLE
281 ? FIRST_HANDLE : g_handle_seq + 1);
282 if (g_handle_seq >= g_consumer_capacity) {
283 g_handle_seq = FIRST_HANDLE;
284 }
285 start = g_handle_seq; /* guard against infinite loop */
286 while (g_consumer_table[g_handle_seq] != NULL) {
287 ++g_handle_seq;
288 if (g_handle_seq == start) {
289 dtj_throw_illegal_state(jenv, "consumer table full,"
290 " but count %d < capacity %d",
291 g_consumer_count, g_consumer_capacity);
292 (void) pthread_mutex_unlock(&g_table_lock);
293 return (B_FALSE);
294 } else if (g_handle_seq >= g_consumer_capacity) {
295 g_handle_seq = FIRST_HANDLE;
296 }
297 }
298 g_consumer_table[g_handle_seq] = c;
299 *seq = g_handle_seq;
300 ++g_consumer_count;
301 (void) pthread_mutex_unlock(&g_table_lock);
302 return (B_TRUE);
303 }
304
305 /*
306 * Removes a consumer from the global consumer table. The call may be initiated
307 * from Java code or from native code (because an exception has occurred).
308 * Precondition: no exception pending (any pending exception must be temporarily
309 * cleared)
310 * Returns NULL if the caller is not in the table or if this function throws an
311 * exception; either case leaves the global consumer table unchanged.
312 * Throws IllegalStateException if the caller does not have a valid handle.
313 */
314 static dtj_consumer_t *
dtj_remove_consumer(JNIEnv * jenv,jobject caller)315 dtj_remove_consumer(JNIEnv *jenv, jobject caller)
316 {
317 dtj_consumer_t *consumer;
318 int handle = dtj_get_handle(jenv, caller);
319 if (handle == NO_HANDLE) {
320 return (NULL); /* java exception pending */
321 }
322 consumer = dtj_remove_consumer_at(handle);
323 return (consumer);
324 }
325
326 /*
327 * Returns NULL if there is no consumer with the given handle. Does not throw
328 * exceptions.
329 */
330 static dtj_consumer_t *
dtj_remove_consumer_at(int handle)331 dtj_remove_consumer_at(int handle)
332 {
333 dtj_consumer_t *consumer;
334 (void) pthread_mutex_lock(&g_table_lock);
335 if (g_consumer_table) {
336 if ((handle >= 0) && (handle < g_consumer_capacity)) {
337 consumer = g_consumer_table[handle];
338 if (consumer != NULL) {
339 g_consumer_table[handle] = NULL;
340 --g_consumer_count;
341 if (g_consumer_count == 0) {
342 free(g_consumer_table);
343 g_consumer_table = NULL;
344 g_consumer_capacity = 0;
345 g_handle_seq = NO_HANDLE;
346 }
347 }
348 } else {
349 consumer = NULL;
350 }
351 } else {
352 consumer = NULL;
353 }
354 (void) pthread_mutex_unlock(&g_table_lock);
355 return (consumer);
356 }
357
358 /*
359 * Gets the name of the executable in case it is an application with an embedded
360 * JVM and not "java". Implementation is copied from lib/mpss/common/mpss.c.
361 * The use of static auxv_t makes the MT-level unsafe. The caller is expected
362 * to use the global lock (LocalConsumer.class).
363 */
364 static const char *
dtj_getexecname(void)365 dtj_getexecname(void)
366 {
367 const char *execname = NULL;
368 static auxv_t auxb;
369
370 /*
371 * The first time through, read the initial aux vector that was
372 * passed to the process at exec(2). Only do this once.
373 */
374 int fd = open("/proc/self/auxv", O_RDONLY);
375
376 if (fd >= 0) {
377 while (read(fd, &auxb, sizeof (auxv_t)) == sizeof (auxv_t)) {
378 if (auxb.a_type == AT_SUN_EXECNAME) {
379 execname = auxb.a_un.a_ptr;
380 break;
381 }
382 }
383 (void) close(fd);
384 }
385 return (execname);
386 }
387
388 /*
389 * Add the compiled program to a list of programs the API expects to enable.
390 * Returns the Program instance identifying the listed program, or NULL if the
391 * Program constructor fails (exception pending in that case).
392 */
393 static jobject
dtj_add_program(dtj_java_consumer_t * jc,dtj_program_t * p)394 dtj_add_program(dtj_java_consumer_t *jc, dtj_program_t *p)
395 {
396 JNIEnv *jenv = jc->dtjj_jenv;
397
398 jobject jprogram = NULL;
399
400 switch (p->dtjp_type) {
401 case DTJ_PROGRAM_STRING:
402 jprogram = (*jenv)->NewObject(jenv, g_program_jc,
403 g_proginit_jm);
404 break;
405 case DTJ_PROGRAM_FILE:
406 jprogram = (*jenv)->NewObject(jenv, g_programfile_jc,
407 g_fproginit_jm);
408 break;
409 default:
410 dtj_throw_illegal_argument(jenv, "unexpected program type %d\n",
411 p->dtjp_type);
412 }
413 if ((*jenv)->ExceptionCheck(jenv)) {
414 return (NULL);
415 }
416
417 /* Does not throw exceptions */
418 (*jenv)->SetIntField(jenv, jprogram, g_progid_jf,
419 uu_list_numnodes(jc->dtjj_consumer->dtjc_program_list));
420
421 if (!dtj_list_add(jc->dtjj_consumer->dtjc_program_list, p)) {
422 (*jenv)->DeleteLocalRef(jenv, jprogram);
423 dtj_throw_out_of_memory(jenv,
424 "could not add program");
425 return (NULL);
426 }
427
428 return (jprogram);
429 }
430
431 /*
432 * Returns a new ProgramInfo, or NULL if the constructor fails (java exception
433 * pending in that case).
434 */
435 static jobject
dtj_get_program_info(dtj_java_consumer_t * jc,dtrace_proginfo_t * pinfo)436 dtj_get_program_info(dtj_java_consumer_t *jc, dtrace_proginfo_t *pinfo)
437 {
438 JNIEnv *jenv = jc->dtjj_jenv;
439
440 jobject minProbeAttributes = NULL;
441 jobject minStatementAttributes = NULL;
442 jobject programInfo = NULL; /* return value */
443
444 minProbeAttributes = dtj_new_attribute(jc, &pinfo->dpi_descattr);
445 if (!minProbeAttributes) {
446 return (NULL); /* java exception pending */
447 }
448 minStatementAttributes = dtj_new_attribute(jc, &pinfo->dpi_stmtattr);
449 if (!minStatementAttributes) {
450 (*jenv)->DeleteLocalRef(jenv, minProbeAttributes);
451 return (NULL); /* java exception pending */
452 }
453
454 programInfo = (*jenv)->NewObject(jenv, g_proginfo_jc,
455 g_proginfoinit_jm, minProbeAttributes, minStatementAttributes,
456 pinfo->dpi_matches);
457 (*jenv)->DeleteLocalRef(jenv, minProbeAttributes);
458 (*jenv)->DeleteLocalRef(jenv, minStatementAttributes);
459
460 return (programInfo);
461 }
462
463 /*
464 * Called by LocalConsumer static initializer.
465 */
466 JNIEXPORT void JNICALL
467 /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1checkVersion(JNIEnv * env,jclass class,jint version)468 Java_org_opensolaris_os_dtrace_LocalConsumer__1checkVersion(JNIEnv *env,
469 jclass class, jint version)
470 {
471 if (version != DTRACE_JNI_VERSION) {
472 dtj_throw_illegal_state(env,
473 "LocalConsumer version %d incompatible with native "
474 "implementation version %d", version, DTRACE_JNI_VERSION);
475 }
476 }
477
478 /*
479 * Called by LocalConsumer static initializer.
480 */
481 JNIEXPORT void JNICALL
482 /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1loadJniTable(JNIEnv * env,jclass class)483 Java_org_opensolaris_os_dtrace_LocalConsumer__1loadJniTable(JNIEnv *env,
484 jclass class)
485 {
486 if (g_dtj_load) {
487 /*
488 * JNI table includes a global reference to the LocalConsumer
489 * class, preventing the class from being unloaded. The
490 * LocalConsumer static initializer should never execute more
491 * than once.
492 */
493 dtj_throw_illegal_state(env, "JNI table already loaded");
494 return;
495 }
496
497 /* If this fails, a Java Error (e.g. NoSuchMethodError) is pending */
498 if (dtj_load(env) == DTJ_OK) {
499 g_dtj_load = B_TRUE;
500 }
501 }
502
503 /*
504 * Protected by global lock (LocalConsumer.class)
505 */
506 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1open(JNIEnv * env,jobject obj,jobjectArray flags)507 Java_org_opensolaris_os_dtrace_LocalConsumer__1open(JNIEnv *env, jobject obj,
508 jobjectArray flags)
509 {
510 dtrace_hdl_t *dtp;
511 dtj_consumer_t *c;
512 const char *f; /* flag name */
513 int oflags = 0;
514 int i, len;
515 int id;
516 int err;
517
518 jobject flag = NULL;
519 jstring flagname = NULL;
520
521 if (!g_dtj_load) {
522 dtj_throw_illegal_state(env, "JNI table not loaded");
523 return;
524 }
525
526 c = dtj_consumer_create(env);
527 if (!c) {
528 return; /* java exception pending */
529 }
530
531 /* Get open flags */
532 len = (flags ? (*env)->GetArrayLength(env, flags) : 0);
533 for (i = 0; i < len; ++i) {
534 flag = (*env)->GetObjectArrayElement(env, flags, i);
535 if ((*env)->ExceptionCheck(env)) {
536 dtj_consumer_destroy(c);
537 return;
538 }
539
540 flagname = (*env)->CallObjectMethod(env, flag, g_enumname_jm);
541 (*env)->DeleteLocalRef(env, flag);
542 if ((*env)->ExceptionCheck(env)) {
543 dtj_consumer_destroy(c);
544 return;
545 }
546 f = (*env)->GetStringUTFChars(env, flagname, NULL);
547 if ((*env)->ExceptionCheck(env)) {
548 (*env)->DeleteLocalRef(env, flagname);
549 dtj_consumer_destroy(c);
550 return;
551 }
552 if (strcmp(f, "ILP32") == 0) {
553 oflags |= DTRACE_O_ILP32;
554 } else if (strcmp(f, "LP64") == 0) {
555 oflags |= DTRACE_O_LP64;
556 }
557 (*env)->ReleaseStringUTFChars(env, flagname, f);
558 (*env)->DeleteLocalRef(env, flagname);
559 }
560
561 /* Check for mutually exclusive flags */
562 if ((oflags & DTRACE_O_ILP32) && (oflags & DTRACE_O_LP64)) {
563 dtj_throw_illegal_argument(env,
564 "Cannot set both ILP32 and LP64");
565 dtj_consumer_destroy(c);
566 return;
567 }
568
569 /*
570 * Make sure we can add the consumer before calling dtrace_open().
571 * Repeated calls to open() when the consumer table is maxed out should
572 * avoid calling dtrace_open(). (Normally there is no limit to the size
573 * of the consumer table, but the undocumented JAVA_DTRACE_MAX_CONSUMERS
574 * system property lets you set a limit after which
575 * ResourceLimitException is thrown.)
576 */
577 if (!dtj_add_consumer(env, c, &id)) {
578 dtj_consumer_destroy(c);
579 return; /* java exception pending */
580 }
581
582 (*env)->CallVoidMethod(env, obj, g_sethandle_jm, id);
583 if ((*env)->ExceptionCheck(env)) {
584 (void) dtj_remove_consumer_at(id);
585 dtj_consumer_destroy(c);
586 return;
587 }
588
589 if ((dtp = dtrace_open(DTRACE_VERSION, oflags, &err)) == NULL) {
590 dtj_java_consumer_t jc;
591 jc.dtjj_jenv = env;
592 dtj_throw_dtrace_exception(&jc, dtrace_errmsg(NULL, err));
593 (void) dtj_remove_consumer_at(id);
594 dtj_consumer_destroy(c);
595 return;
596 }
597 c->dtjc_dtp = dtp; /* set consumer handle to native DTrace library */
598 }
599
600 static void
dtj_flag(uint_t * flags,uint_t flag,boolean_t * get,boolean_t * set)601 dtj_flag(uint_t *flags, uint_t flag, boolean_t *get, boolean_t *set)
602 {
603 assert((get && !set) || (set && !get));
604
605 if (get) {
606 *get = (*flags & flag);
607 } else {
608 if (*set) {
609 *flags |= flag;
610 } else {
611 *flags &= ~flag;
612 }
613 }
614 }
615
616 /*
617 * Returns B_TRUE if opt is a recognized compile flag, B_FALSE otherwise.
618 */
619 static boolean_t
dtj_cflag(dtj_java_consumer_t * jc,const char * opt,boolean_t * get,boolean_t * set)620 dtj_cflag(dtj_java_consumer_t *jc, const char *opt, boolean_t *get,
621 boolean_t *set)
622 {
623 boolean_t is_cflag = B_TRUE;
624 uint_t *flags = &jc->dtjj_consumer->dtjc_cflags;
625
626 /* see lib/libdtrace/common/dt_options.c */
627 if (strcmp(opt, "argref") == 0) {
628 dtj_flag(flags, DTRACE_C_ARGREF, get, set);
629 } else if (strcmp(opt, "cpp") == 0) {
630 dtj_flag(flags, DTRACE_C_CPP, get, set);
631 } else if (strcmp(opt, "defaultargs") == 0) {
632 dtj_flag(flags, DTRACE_C_DEFARG, get, set);
633 } else if (strcmp(opt, "empty") == 0) {
634 dtj_flag(flags, DTRACE_C_EMPTY, get, set);
635 } else if (strcmp(opt, "errtags") == 0) {
636 dtj_flag(flags, DTRACE_C_ETAGS, get, set);
637 } else if (strcmp(opt, "knodefs") == 0) {
638 dtj_flag(flags, DTRACE_C_KNODEF, get, set);
639 } else if (strcmp(opt, "nolibs") == 0) {
640 dtj_flag(flags, DTRACE_C_NOLIBS, get, set);
641 } else if (strcmp(opt, "pspec") == 0) {
642 dtj_flag(flags, DTRACE_C_PSPEC, get, set);
643 } else if (strcmp(opt, "unodefs") == 0) {
644 dtj_flag(flags, DTRACE_C_UNODEF, get, set);
645 } else if (strcmp(opt, "verbose") == 0) {
646 dtj_flag(flags, DTRACE_C_DIFV, get, set);
647 } else if (strcmp(opt, "zdefs") == 0) {
648 dtj_flag(flags, DTRACE_C_ZDEFS, get, set);
649 } else {
650 is_cflag = B_FALSE;
651 }
652
653 if (is_cflag && set &&
654 (jc->dtjj_consumer->dtjc_state != DTJ_CONSUMER_INIT)) {
655 dtj_throw_illegal_state(jc->dtjj_jenv,
656 "cannot set compile time option \"%s\" after calling go()",
657 opt);
658 return (is_cflag);
659 }
660
661 return (is_cflag);
662 }
663
664 /*
665 * Protected by global lock (LocalConsumer.class)
666 */
667 JNIEXPORT jobject JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1compileString(JNIEnv * env,jobject obj,jstring program,jobjectArray args)668 Java_org_opensolaris_os_dtrace_LocalConsumer__1compileString(JNIEnv *env,
669 jobject obj, jstring program, jobjectArray args)
670 {
671 const char *prog;
672 dtj_java_consumer_t jc;
673 dtrace_hdl_t *dtp;
674 dtj_program_t *p;
675 int argc = 0;
676 char **argv = NULL;
677
678 jstring jprogram = NULL;
679
680 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
681 return (NULL); /* java exception pending */
682 }
683 dtp = jc.dtjj_consumer->dtjc_dtp;
684
685 prog = (*env)->GetStringUTFChars(env, program, 0);
686 if ((*env)->ExceptionCheck(env)) {
687 return (NULL);
688 }
689
690 p = dtj_program_create(env, DTJ_PROGRAM_STRING, prog);
691 if (!p) {
692 (*env)->ReleaseStringUTFChars(env, program, prog);
693 return (NULL); /* java exception pending */
694 }
695
696 if (args) {
697 argv = dtj_get_argv(env, args, &argc);
698 if ((*env)->ExceptionCheck(env)) {
699 (*env)->ReleaseStringUTFChars(env, program, prog);
700 dtj_program_destroy(p, NULL);
701 return (NULL);
702 }
703 }
704
705 if ((p->dtjp_program = dtrace_program_strcompile(dtp,
706 prog, DTRACE_PROBESPEC_NAME, jc.dtjj_consumer->dtjc_cflags,
707 argc, argv)) == NULL) {
708 dtj_throw_dtrace_exception(&jc,
709 "invalid probe specifier %s: %s",
710 prog, dtrace_errmsg(dtp, dtrace_errno(dtp)));
711 (*env)->ReleaseStringUTFChars(env, program, prog);
712 dtj_program_destroy(p, NULL);
713 dtj_free_argv(argv);
714 return (NULL);
715 }
716 (*env)->ReleaseStringUTFChars(env, program, prog);
717 dtj_free_argv(argv);
718
719 jprogram = dtj_add_program(&jc, p);
720 return (jprogram); /* NULL if exception pending */
721 }
722
723 /*
724 * Protected by global lock (LocalConsumer.class)
725 */
726 JNIEXPORT jobject JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1compileFile(JNIEnv * env,jobject obj,jstring filename,jobjectArray args)727 Java_org_opensolaris_os_dtrace_LocalConsumer__1compileFile(JNIEnv *env,
728 jobject obj, jstring filename, jobjectArray args)
729 {
730 FILE *fp;
731 const char *file;
732 dtj_java_consumer_t jc;
733 dtrace_hdl_t *dtp;
734 dtj_program_t *p;
735 int argc = 0;
736 char **argv = NULL;
737
738 jstring jprogram = NULL;
739
740 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
741 return (NULL); /* java exception pending */
742 }
743 dtp = jc.dtjj_consumer->dtjc_dtp;
744
745 file = dtj_GetStringNativeChars(env, filename);
746 if ((fp = fopen(file, "r")) == NULL) {
747 dtj_throw_dtrace_exception(&jc, "failed to open %s", file);
748 dtj_ReleaseStringNativeChars(env, filename, file);
749 return (NULL);
750 }
751
752 p = dtj_program_create(env, DTJ_PROGRAM_FILE, file);
753 if (!p) {
754 (void) fclose(fp);
755 dtj_ReleaseStringNativeChars(env, filename, file);
756 return (NULL); /* java exception pending */
757 }
758
759 if (args) {
760 argv = dtj_get_argv(env, args, &argc);
761 if ((*env)->ExceptionCheck(env)) {
762 (void) fclose(fp);
763 dtj_ReleaseStringNativeChars(env, filename, file);
764 dtj_program_destroy(p, NULL);
765 return (NULL);
766 }
767 }
768
769 if ((p->dtjp_program = dtrace_program_fcompile(dtp,
770 fp, jc.dtjj_consumer->dtjc_cflags, argc, argv)) == NULL) {
771 dtj_throw_dtrace_exception(&jc,
772 "failed to compile script %s: %s", file,
773 dtrace_errmsg(dtp, dtrace_errno(dtp)));
774 (void) fclose(fp);
775 dtj_ReleaseStringNativeChars(env, filename, file);
776 dtj_program_destroy(p, NULL);
777 dtj_free_argv(argv);
778 return (NULL);
779 }
780 (void) fclose(fp);
781 dtj_ReleaseStringNativeChars(env, filename, file);
782 dtj_free_argv(argv);
783
784 jprogram = dtj_add_program(&jc, p);
785 return (jprogram); /* NULL if exception pending */
786 }
787
788 /*
789 * Protected by global lock (LocalConsumer.class)
790 */
791 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1exec(JNIEnv * env,jobject obj,jobject program)792 Java_org_opensolaris_os_dtrace_LocalConsumer__1exec(JNIEnv *env, jobject obj,
793 jobject program)
794 {
795 dtj_java_consumer_t jc;
796 dtrace_hdl_t *dtp;
797 int progid = -1;
798 uu_list_walk_t *itr;
799 dtj_program_t *p;
800 dtrace_proginfo_t *pinfo = NULL;
801 int i;
802
803 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
804 return; /* java exception pending */
805 }
806 dtp = jc.dtjj_consumer->dtjc_dtp;
807
808 if (program) {
809 progid = (*env)->GetIntField(env, program, g_progid_jf);
810 }
811
812 if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
813 dtj_throw_illegal_state(env, "no program compiled");
814 return;
815 }
816
817 itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
818 for (i = 0; (p = uu_list_walk_next(itr)) != NULL; ++i) {
819 /* enable all probes or those of given program only */
820 if ((progid != -1) && (progid != i)) {
821 continue;
822 }
823
824 if (p->dtjp_enabled) {
825 dtj_throw_illegal_state(env, "program already enabled");
826 uu_list_walk_end(itr);
827 return;
828 }
829
830 pinfo = &p->dtjp_info;
831 if (dtrace_program_exec(dtp, p->dtjp_program, pinfo) == -1) {
832 dtj_throw_dtrace_exception(&jc,
833 "failed to enable %s: %s", p->dtjp_name,
834 dtrace_errmsg(dtp, dtrace_errno(dtp)));
835 uu_list_walk_end(itr);
836 return;
837 }
838 p->dtjp_enabled = B_TRUE;
839 }
840 uu_list_walk_end(itr);
841
842 if (program) {
843 jobject programInfo = NULL;
844
845 if (!pinfo) {
846 /*
847 * Consumer.enable() has already checked that the
848 * program was compiled by this consumer. This is an
849 * implementation error, not a user error.
850 */
851 dtj_throw_illegal_state(env, "program not found");
852 return;
853 }
854
855 programInfo = dtj_get_program_info(&jc, pinfo);
856 if (!programInfo) {
857 return; /* java exception pending */
858 }
859
860 (*env)->SetObjectField(env, program, g_proginfo_jf,
861 programInfo);
862 (*env)->DeleteLocalRef(env, programInfo);
863 }
864 }
865
866 /*
867 * Protected by global lock (LocalConsumer.class)
868 */
869 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1getProgramInfo(JNIEnv * env,jobject obj,jobject program)870 Java_org_opensolaris_os_dtrace_LocalConsumer__1getProgramInfo(JNIEnv *env,
871 jobject obj, jobject program)
872 {
873 dtj_java_consumer_t jc;
874 dtrace_hdl_t *dtp;
875 int progid;
876 uu_list_walk_t *itr;
877 dtj_program_t *p;
878 dtrace_proginfo_t *pinfo = NULL;
879 int i;
880
881 jobject programInfo = NULL;
882
883 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
884 return; /* java exception pending */
885 }
886 dtp = jc.dtjj_consumer->dtjc_dtp;
887
888 progid = (*env)->GetIntField(env, program, g_progid_jf);
889
890 if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
891 dtj_throw_illegal_state(env, "no program compiled");
892 return;
893 }
894
895 itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
896 for (i = 0; ((p = uu_list_walk_next(itr)) != NULL) && !pinfo; ++i) {
897 if (progid != i) {
898 /* get info of given program only */
899 continue;
900 }
901
902 pinfo = &p->dtjp_info;
903 dtrace_program_info(dtp, p->dtjp_program, pinfo);
904 }
905 uu_list_walk_end(itr);
906
907 programInfo = dtj_get_program_info(&jc, pinfo);
908 if (!programInfo) {
909 return; /* java exception pending */
910 }
911
912 (*env)->SetObjectField(env, program, g_proginfo_jf,
913 programInfo);
914 (*env)->DeleteLocalRef(env, programInfo);
915 }
916
917 /*
918 * Protected by global lock (LocalConsumer.class)
919 */
920 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1setOption(JNIEnv * env,jobject obj,jstring option,jstring value)921 Java_org_opensolaris_os_dtrace_LocalConsumer__1setOption(JNIEnv *env,
922 jobject obj, jstring option, jstring value)
923 {
924 dtj_java_consumer_t jc;
925 const char *opt;
926 const char *val;
927 boolean_t on;
928
929 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
930 return; /* java exception pending */
931 }
932
933 opt = (*env)->GetStringUTFChars(env, option, 0);
934 if (!opt) {
935 dtj_throw_out_of_memory(env,
936 "could not allocate option string");
937 return;
938 }
939
940 if (value) {
941 val = (*env)->GetStringUTFChars(env, value, 0);
942 if (!val) {
943 dtj_throw_out_of_memory(env,
944 "could not allocate option value string");
945 (*env)->ReleaseStringUTFChars(env, option, opt);
946 return;
947 }
948 } else {
949 /*
950 * dtrace_setopt() sets option to 0 if value is NULL. That's
951 * not the same thing as unsetting a boolean option, since
952 * libdtrace uses -2 to mean unset. We'll leave it to
953 * LocalConsumer.java to disallow null or not.
954 */
955 val = NULL;
956 }
957
958 /*
959 * Check for boolean compile-time options not handled by
960 * dtrace_setopt().
961 */
962 on = (!val || (strcmp(val, "unset") != 0));
963 if (dtj_cflag(&jc, opt, NULL, &on)) {
964 (*env)->ReleaseStringUTFChars(env, option, opt);
965 if (value) {
966 (*env)->ReleaseStringUTFChars(env, value, val);
967 }
968 return;
969 }
970
971 /*
972 * The transition from INIT to GO is protected by synchronization
973 * (a per-consumer lock) in LocalConsumer.java, ensuring that go() and
974 * setOption() execute sequentially.
975 */
976 if (jc.dtjj_consumer->dtjc_state != DTJ_CONSUMER_INIT) {
977 /*
978 * If the consumer is already running, defer setting the option
979 * until we wake up from dtrace_sleep.
980 */
981 dtj_request_t *request;
982
983
984 (void) pthread_mutex_lock(
985 &jc.dtjj_consumer->dtjc_request_list_lock);
986 request = dtj_request_create(env, DTJ_REQUEST_OPTION, opt, val);
987 if (request) {
988 if (!dtj_list_add(jc.dtjj_consumer->dtjc_request_list,
989 request)) {
990 dtj_throw_out_of_memory(env,
991 "Failed to add setOption request");
992 }
993 } /* else java exception pending */
994 (void) pthread_mutex_unlock(
995 &jc.dtjj_consumer->dtjc_request_list_lock);
996 } else {
997 dtrace_hdl_t *dtp = jc.dtjj_consumer->dtjc_dtp;
998 if (dtrace_setopt(dtp, opt, val) == -1) {
999 dtj_throw_dtrace_exception(&jc, dtrace_errmsg(dtp,
1000 dtrace_errno(dtp)));
1001 }
1002 }
1003
1004 (*env)->ReleaseStringUTFChars(env, option, opt);
1005 if (value) {
1006 (*env)->ReleaseStringUTFChars(env, value, val);
1007 }
1008 }
1009
1010 /*
1011 * Protected by global lock (LocalConsumer.class)
1012 */
1013 JNIEXPORT jlong JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1getOption(JNIEnv * env,jobject obj,jstring option)1014 Java_org_opensolaris_os_dtrace_LocalConsumer__1getOption(JNIEnv *env,
1015 jobject obj, jstring option)
1016 {
1017 dtj_java_consumer_t jc;
1018 dtrace_hdl_t *dtp;
1019 const char *opt;
1020 dtrace_optval_t optval;
1021 boolean_t cflag;
1022
1023 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1024 return (0); /* java exception pending */
1025 }
1026 dtp = jc.dtjj_consumer->dtjc_dtp;
1027
1028 opt = (*env)->GetStringUTFChars(env, option, 0);
1029 if (!opt) {
1030 dtj_throw_out_of_memory(env,
1031 "could not allocate option string");
1032 return (0);
1033 }
1034
1035 /*
1036 * Check for boolean compile-time options not handled by
1037 * dtrace_setopt().
1038 */
1039 if (dtj_cflag(&jc, opt, &cflag, NULL)) {
1040 (*env)->ReleaseStringUTFChars(env, option, opt);
1041 return (cflag ? 1 : DTRACEOPT_UNSET);
1042 }
1043
1044 if (dtrace_getopt(dtp, opt, &optval) == -1) {
1045 dtj_throw_dtrace_exception(&jc,
1046 "couldn't get option %s: %s", opt,
1047 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1048 (*env)->ReleaseStringUTFChars(env, option, opt);
1049 return (0);
1050 }
1051 (*env)->ReleaseStringUTFChars(env, option, opt);
1052 return (optval);
1053 }
1054
1055 /*
1056 * Throws IllegalStateException if not all compiled programs are enabled.
1057 */
1058 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1checkProgramEnabling(JNIEnv * env,jobject obj)1059 Java_org_opensolaris_os_dtrace_LocalConsumer__1checkProgramEnabling(JNIEnv *env,
1060 jobject obj)
1061 {
1062 dtj_java_consumer_t jc;
1063 dtj_program_t *p;
1064 uu_list_walk_t *itr;
1065
1066 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1067 return; /* java exception pending */
1068 }
1069
1070 if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
1071 dtj_throw_illegal_state(env, "no program compiled");
1072 return;
1073 }
1074
1075 itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
1076 while ((p = uu_list_walk_next(itr)) != NULL) {
1077 if (!p->dtjp_enabled) {
1078 const char *type;
1079 switch (p->dtjp_type) {
1080 case DTJ_PROGRAM_STRING:
1081 type = "description";
1082 break;
1083 case DTJ_PROGRAM_FILE:
1084 type = "script";
1085 break;
1086 default:
1087 assert(p->dtjp_type == DTJ_PROGRAM_STRING ||
1088 p->dtjp_type == DTJ_PROGRAM_FILE);
1089 }
1090 dtj_throw_illegal_state(env,
1091 "Not all compiled probes are enabled. "
1092 "Compiled %s %s not enabled.",
1093 type, p->dtjp_name);
1094 uu_list_walk_end(itr);
1095 return;
1096 }
1097 }
1098 uu_list_walk_end(itr);
1099 }
1100
1101 JNIEXPORT jboolean JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1isEnabled(JNIEnv * env,jobject obj)1102 Java_org_opensolaris_os_dtrace_LocalConsumer__1isEnabled(JNIEnv *env,
1103 jobject obj)
1104 {
1105 dtj_java_consumer_t jc;
1106 dtj_program_t *p;
1107 uu_list_walk_t *itr;
1108
1109 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1110 return (JNI_FALSE); /* java exception pending */
1111 }
1112
1113 if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
1114 return (JNI_FALSE); /* no program compiled */
1115 }
1116
1117 itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
1118 while ((p = uu_list_walk_next(itr)) != NULL) {
1119 if (!p->dtjp_enabled) {
1120 uu_list_walk_end(itr);
1121 return (JNI_FALSE);
1122 }
1123 }
1124 uu_list_walk_end(itr);
1125
1126 return (JNI_TRUE);
1127 }
1128
1129 /*
1130 * Protected by global lock (LocalConsumer.class)
1131 */
1132 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1go(JNIEnv * env,jobject obj)1133 Java_org_opensolaris_os_dtrace_LocalConsumer__1go(JNIEnv *env, jobject obj)
1134 {
1135 dtj_java_consumer_t jc;
1136 dtrace_hdl_t *dtp;
1137
1138 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1139 return; /* java exception pending */
1140 }
1141 dtp = jc.dtjj_consumer->dtjc_dtp;
1142
1143 if (dtj_set_callback_handlers(&jc) != DTJ_OK) {
1144 return; /* java exception pending */
1145 }
1146
1147 if (dtrace_go(dtp) != 0) {
1148 dtj_throw_dtrace_exception(&jc,
1149 "could not enable tracing: %s",
1150 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1151 return;
1152 }
1153
1154 jc.dtjj_consumer->dtjc_state = DTJ_CONSUMER_GO;
1155 }
1156
1157 /*
1158 * Protected by global lock (LocalConsumer.class). Called when aborting the
1159 * consumer loop before it starts.
1160 */
1161 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1stop(JNIEnv * env,jobject obj)1162 Java_org_opensolaris_os_dtrace_LocalConsumer__1stop(JNIEnv *env,
1163 jobject obj)
1164 {
1165 dtj_java_consumer_t jc;
1166 dtrace_hdl_t *dtp;
1167
1168 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1169 return; /* java exception pending */
1170 }
1171 dtp = jc.dtjj_consumer->dtjc_dtp;
1172
1173 if (dtrace_stop(dtp) == -1) {
1174 dtj_throw_dtrace_exception(&jc,
1175 "couldn't stop tracing: %s",
1176 dtrace_errmsg(jc.dtjj_consumer->dtjc_dtp,
1177 dtrace_errno(jc.dtjj_consumer->dtjc_dtp)));
1178 } else {
1179 jc.dtjj_consumer->dtjc_state = DTJ_CONSUMER_STOP;
1180 }
1181 }
1182
1183 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1consume(JNIEnv * env,jobject obj)1184 Java_org_opensolaris_os_dtrace_LocalConsumer__1consume(JNIEnv *env,
1185 jobject obj)
1186 {
1187 dtj_java_consumer_t jc;
1188 dtrace_hdl_t *dtp;
1189
1190 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1191 return; /* java exception pending */
1192 }
1193 dtp = jc.dtjj_consumer->dtjc_dtp;
1194 jc.dtjj_consumer->dtjc_state = DTJ_CONSUMER_START;
1195
1196 if (dtj_java_consumer_init(env, &jc) != DTJ_OK) {
1197 return; /* java exception pending */
1198 }
1199
1200 /*
1201 * Must set the thread-specific java consumer before starting the
1202 * dtrace_work() loop because the bufhandler can also be invoked by
1203 * getAggregate() from another thread. The bufhandler needs access to
1204 * the correct JNI state specific to either the consumer loop or the
1205 * getAggregate() call.
1206 */
1207 (void) pthread_setspecific(g_dtj_consumer_key, &jc);
1208
1209 if (jc.dtjj_consumer->dtjc_process_list != NULL) {
1210 struct ps_prochandle *P;
1211 uu_list_walk_t *itr;
1212
1213 /* Must not call MonitorEnter with a pending exception */
1214 if ((*env)->ExceptionCheck(env)) {
1215 dtj_java_consumer_fini(env, &jc);
1216 return; /* java exception pending */
1217 }
1218 (*env)->MonitorEnter(env, g_caller_jc);
1219 if ((*env)->ExceptionCheck(env)) {
1220 dtj_java_consumer_fini(env, &jc);
1221 return; /* java exception pending */
1222 }
1223
1224 itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_process_list,
1225 0);
1226 while ((P = dtj_pointer_list_walk_next(itr)) !=
1227 DTJ_INVALID_PTR) {
1228 dtrace_proc_continue(dtp, P);
1229 }
1230 uu_list_walk_end(itr);
1231
1232 (*env)->MonitorExit(env, g_caller_jc);
1233 if ((*env)->ExceptionCheck(env)) {
1234 dtj_java_consumer_fini(env, &jc);
1235 return; /* java exception pending */
1236 }
1237 }
1238
1239 /*
1240 * Blocking call starts consumer loop.
1241 */
1242 (void) dtj_consume(&jc);
1243
1244 dtj_java_consumer_fini(env, &jc);
1245 /*
1246 * Stop the consumer after the consumer loop terminates, whether
1247 * normally because of the exit() action or LocalConsumer.stop(), or
1248 * abnormally because of an exception. The call is ignored if the
1249 * consumer is already stopped. It is safe to call dtj_stop() with a
1250 * pending exception.
1251 */
1252 dtj_stop(&jc);
1253 }
1254
1255 /*
1256 * Interrupts a running consumer. May be called from any thread.
1257 */
1258 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1interrupt(JNIEnv * env,jobject obj)1259 Java_org_opensolaris_os_dtrace_LocalConsumer__1interrupt(JNIEnv *env,
1260 jobject obj)
1261 {
1262 dtj_java_consumer_t jc;
1263
1264 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1265 return; /* java exception pending */
1266 }
1267
1268 jc.dtjj_consumer->dtjc_interrupt = B_TRUE;
1269 }
1270
1271 /*
1272 * Protected by global lock (LocalConsumer.class)
1273 */
1274 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1close(JNIEnv * env,jobject obj)1275 Java_org_opensolaris_os_dtrace_LocalConsumer__1close(JNIEnv *env, jobject obj)
1276 {
1277 dtj_java_consumer_t jc;
1278 dtrace_hdl_t *dtp;
1279
1280 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1281 return; /* java exception pending */
1282 }
1283 dtp = jc.dtjj_consumer->dtjc_dtp;
1284
1285 /*
1286 * Need to release any created procs here, since the consumer_t
1287 * destructor (called by _destroy) will not have access to the dtrace
1288 * handle needed to release them (this function closes the dtrace
1289 * handle).
1290 */
1291 if (jc.dtjj_consumer->dtjc_process_list != NULL) {
1292 struct ps_prochandle *P;
1293 uu_list_walk_t *itr;
1294 itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_process_list,
1295 0);
1296 while ((P = dtj_pointer_list_walk_next(itr)) !=
1297 DTJ_INVALID_PTR) {
1298 dtrace_proc_release(dtp, P);
1299 }
1300 uu_list_walk_end(itr);
1301 }
1302
1303 dtrace_close(dtp);
1304 }
1305
1306 /*
1307 * Static Consumer.java method
1308 */
1309 JNIEXPORT jint JNICALL
1310 /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1openCount(JNIEnv * env,jclass c)1311 Java_org_opensolaris_os_dtrace_LocalConsumer__1openCount(JNIEnv *env, jclass c)
1312 {
1313 int open;
1314 (void) pthread_mutex_lock(&g_table_lock);
1315 if (g_consumer_table == NULL) {
1316 open = 0;
1317 } else {
1318 open = g_consumer_count;
1319 }
1320 (void) pthread_mutex_unlock(&g_table_lock);
1321 return (open);
1322 }
1323
1324 /*
1325 * Static Consumer.java method
1326 */
1327 JNIEXPORT jlong JNICALL
1328 /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1quantizeBucket(JNIEnv * env,jclass c,jint bucket)1329 Java_org_opensolaris_os_dtrace_LocalConsumer__1quantizeBucket(JNIEnv *env,
1330 jclass c, jint bucket)
1331 {
1332 return (DTRACE_QUANTIZE_BUCKETVAL(bucket));
1333 }
1334
1335 /*
1336 * Protected by global lock (LocalConsumer.class)
1337 */
1338 JNIEXPORT jstring JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupKernelFunction(JNIEnv * jenv,jobject caller,jobject address)1339 Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupKernelFunction(
1340 JNIEnv *jenv, jobject caller, jobject address)
1341 {
1342 dtj_java_consumer_t jc;
1343 dtrace_hdl_t *dtp;
1344
1345 jstring jfunc; /* return value */
1346
1347 GElf_Addr addr;
1348 char dummy;
1349 char *s;
1350 int rc;
1351
1352 if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) {
1353 return (NULL); /* java exception pending */
1354 }
1355 dtp = jc.dtjj_consumer->dtjc_dtp;
1356
1357 /* Does not throw exceptions */
1358 if ((*jenv)->IsInstanceOf(jenv, address, g_int_jc)) {
1359 /* intValue() of class Number does not throw exceptions */
1360 addr = (GElf_Addr)(uint32_t)(*jenv)->CallIntMethod(jenv,
1361 address, g_intval_jm);
1362 } else if ((*jenv)->IsInstanceOf(jenv, address, g_number_jc)) {
1363 /* longValue() of class Number does not throw exceptions */
1364 addr = (GElf_Addr)(*jenv)->CallLongMethod(jenv,
1365 address, g_longval_jm);
1366 } else {
1367 dtj_throw_class_cast(jenv, "Expected Number address");
1368 return (NULL);
1369 }
1370
1371 rc = dtrace_addr2str(dtp, addr, &dummy, 1);
1372 s = malloc(rc + 1);
1373 if (!s) {
1374 dtj_throw_out_of_memory(jenv,
1375 "Failed to allocate kernel function name");
1376 return (NULL);
1377 }
1378 (void) dtrace_addr2str(dtp, addr, s, rc + 1);
1379
1380 jfunc = (*jenv)->NewStringUTF(jenv, s);
1381 free(s);
1382 return (jfunc);
1383 }
1384
1385 /*
1386 * Protected by global lock in Consumer.java
1387 */
1388 JNIEXPORT jstring JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupUserFunction(JNIEnv * jenv,jobject caller,jint pid,jobject address)1389 Java_org_opensolaris_os_dtrace_LocalConsumer__1lookupUserFunction(JNIEnv *jenv,
1390 jobject caller, jint pid, jobject address)
1391 {
1392 dtj_java_consumer_t jc;
1393 dtrace_hdl_t *dtp;
1394
1395 jstring jfunc; /* return value */
1396
1397 GElf_Addr addr;
1398 char dummy;
1399 char *s;
1400 int rc;
1401
1402 if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) {
1403 return (NULL); /* java exception pending */
1404 }
1405 dtp = jc.dtjj_consumer->dtjc_dtp;
1406
1407 /* Does not throw exceptions */
1408 if ((*jenv)->IsInstanceOf(jenv, address, g_int_jc)) {
1409 /* intValue() of class Number does not throw exceptions */
1410 addr = (GElf_Addr)(uint32_t)(*jenv)->CallIntMethod(jenv,
1411 address, g_intval_jm);
1412 } else if ((*jenv)->IsInstanceOf(jenv, address, g_number_jc)) {
1413 /* longValue() of class Number does not throw exceptions */
1414 addr = (GElf_Addr)(*jenv)->CallLongMethod(jenv,
1415 address, g_longval_jm);
1416 } else {
1417 dtj_throw_class_cast(jenv, "Expected Number address");
1418 return (NULL);
1419 }
1420
1421 rc = dtrace_uaddr2str(dtp, pid, addr, &dummy, 1);
1422 s = malloc(rc + 1);
1423 if (!s) {
1424 dtj_throw_out_of_memory(jenv,
1425 "Failed to allocate user function name");
1426 return (NULL);
1427 }
1428 (void) dtrace_uaddr2str(dtp, pid, addr, s, rc + 1);
1429
1430 jfunc = (*jenv)->NewStringUTF(jenv, s);
1431 free(s);
1432 return (jfunc);
1433 }
1434
1435 JNIEXPORT jobject JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1getAggregate(JNIEnv * env,jobject obj,jobject spec)1436 Java_org_opensolaris_os_dtrace_LocalConsumer__1getAggregate(JNIEnv *env,
1437 jobject obj, jobject spec)
1438 {
1439 dtj_java_consumer_t jc;
1440
1441 jobject aggregate = NULL;
1442
1443 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1444 return (NULL); /* java exception pending */
1445 }
1446
1447 if (dtj_java_consumer_init(env, &jc) != DTJ_OK) {
1448 return (NULL); /* java exception pending */
1449 }
1450 jc.dtjj_aggregate_spec = spec;
1451
1452 /*
1453 * Must set the thread-specific java consumer before calling any
1454 * function that triggers callbacks to the bufhandler set by
1455 * dtrace_handle_buffered(). The bufhandler needs access to the correct
1456 * JNI state specific to either the consumer loop or the
1457 * getAggregate() call.
1458 */
1459 (void) pthread_setspecific(g_dtj_consumer_key, &jc);
1460 aggregate = dtj_get_aggregate(&jc);
1461 if (!aggregate) {
1462 /* java exception pending */
1463 jc.dtjj_consumer->dtjc_interrupt = B_TRUE;
1464 }
1465 /*
1466 * Cleans up only references created by this JNI invocation. Leaves
1467 * cached per-consumer state untouched.
1468 */
1469 dtj_java_consumer_fini(env, &jc);
1470 return (aggregate);
1471 }
1472
1473 /*
1474 * Returns the pid of the created process, or -1 in case of an error (java
1475 * exception pending).
1476 * Protected by global lock (LocalConsumer.class)
1477 */
1478 JNIEXPORT int JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1createProcess(JNIEnv * jenv,jobject caller,jstring command)1479 Java_org_opensolaris_os_dtrace_LocalConsumer__1createProcess(JNIEnv *jenv,
1480 jobject caller, jstring command)
1481 {
1482 dtj_java_consumer_t jc;
1483 dtrace_hdl_t *dtp;
1484 struct ps_prochandle *P;
1485 char **argv;
1486 int argc;
1487
1488 if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) {
1489 return (-1); /* java exception pending */
1490 }
1491 dtp = jc.dtjj_consumer->dtjc_dtp;
1492
1493 if (jc.dtjj_consumer->dtjc_process_list == NULL) {
1494 jc.dtjj_consumer->dtjc_process_list = dtj_pointer_list_create();
1495 if (!jc.dtjj_consumer->dtjc_process_list) {
1496 dtj_throw_out_of_memory(jenv,
1497 "Could not allocate process list");
1498 return (-1);
1499 }
1500 }
1501
1502 argv = dtj_make_argv(jenv, command, &argc);
1503 if ((*jenv)->ExceptionCheck(jenv)) {
1504 return (-1);
1505 }
1506
1507 P = dtrace_proc_create(dtp, argv[0], argv);
1508 dtj_free_argv(argv);
1509
1510 if (!P) {
1511 dtj_throw_dtrace_exception(&jc, dtrace_errmsg(dtp,
1512 dtrace_errno(dtp)));
1513 return (-1);
1514 }
1515
1516 if (!dtj_pointer_list_add(jc.dtjj_consumer->dtjc_process_list, P)) {
1517 dtj_throw_out_of_memory(jenv,
1518 "Failed to add process to process list");
1519 dtrace_proc_release(dtp, P);
1520 return (-1);
1521 }
1522 return (Pstatus(P)->pr_pid);
1523 }
1524
1525 /*
1526 * Protected by global lock (LocalConsumer.class)
1527 */
1528 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1grabProcess(JNIEnv * jenv,jobject caller,jint pid)1529 Java_org_opensolaris_os_dtrace_LocalConsumer__1grabProcess(JNIEnv *jenv,
1530 jobject caller, jint pid)
1531 {
1532 dtj_java_consumer_t jc;
1533 dtrace_hdl_t *dtp;
1534 struct ps_prochandle *P;
1535
1536 if (dtj_get_java_consumer(jenv, caller, &jc) != DTJ_OK) {
1537 return; /* java exception pending */
1538 }
1539 dtp = jc.dtjj_consumer->dtjc_dtp;
1540
1541 if (jc.dtjj_consumer->dtjc_process_list == NULL) {
1542 jc.dtjj_consumer->dtjc_process_list = dtj_pointer_list_create();
1543 if (jc.dtjj_consumer->dtjc_process_list == NULL) {
1544 dtj_throw_out_of_memory(jenv,
1545 "Could not allocate process list");
1546 return;
1547 }
1548 }
1549
1550 P = dtrace_proc_grab(dtp, (pid_t)pid, 0);
1551 if (!P) {
1552 dtj_throw_dtrace_exception(&jc, dtrace_errmsg(dtp,
1553 dtrace_errno(dtp)));
1554 return;
1555 }
1556
1557 if (!dtj_pointer_list_add(jc.dtjj_consumer->dtjc_process_list, P)) {
1558 dtj_throw_out_of_memory(jenv,
1559 "Failed to add process to process list");
1560 dtrace_proc_release(dtp, P);
1561 return;
1562 }
1563 }
1564
1565 /*
1566 * Lists all probes, or lists matching probes (using the matching rules from
1567 * Table 4-1 of the DTrace manual).
1568 *
1569 * In the future it may be desirable to support an array of probe filters rather
1570 * than a single filter. It could be that if a probe matched any of the given
1571 * filters, it would be included (implied logical OR).
1572 *
1573 * Protected by global lock (LocalConsumer.class)
1574 * param list: an empty list to populate (this function empties the list if it
1575 * is not empty already)
1576 * param filter: a ProbeDescription instance; the list will include only probes
1577 * that match the filter (match all probes if filter is null)
1578 */
1579 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbes(JNIEnv * env,jobject obj,jobject list,jobject filter)1580 Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbes(JNIEnv *env,
1581 jobject obj, jobject list, jobject filter)
1582 {
1583 dtj_list_probes(env, obj, list, filter, dtj_list_probe);
1584 }
1585
1586 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbeDetail(JNIEnv * env,jobject obj,jobject list,jobject filter)1587 Java_org_opensolaris_os_dtrace_LocalConsumer__1listProbeDetail(JNIEnv *env,
1588 jobject obj, jobject list, jobject filter)
1589 {
1590 dtj_list_probes(env, obj, list, filter, dtj_list_probe_detail);
1591 }
1592
1593 static void
dtj_list_probes(JNIEnv * env,jobject obj,jobject list,jobject filter,dtrace_probe_f * func)1594 dtj_list_probes(JNIEnv *env, jobject obj, jobject list, jobject filter,
1595 dtrace_probe_f *func)
1596 {
1597 dtj_java_consumer_t jc;
1598 dtrace_hdl_t *dtp;
1599 dtrace_probedesc_t probe;
1600 dtrace_probedesc_t *pdp = NULL;
1601 const char *probestr;
1602 int rc;
1603
1604 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1605 return; /* java exception pending */
1606 }
1607 dtp = jc.dtjj_consumer->dtjc_dtp;
1608
1609 jc.dtjj_probelist = list;
1610
1611 /* clear in-out list parameter */
1612 (*env)->CallVoidMethod(env, list, g_listclear_jm);
1613 if ((*env)->ExceptionCheck(env)) {
1614 return;
1615 }
1616
1617 if (filter) {
1618 jstring jprobestr = NULL;
1619
1620 jprobestr = (*env)->CallObjectMethod(env, filter,
1621 g_tostring_jm);
1622 if ((*env)->ExceptionCheck(env)) {
1623 return;
1624 }
1625 probestr = (*env)->GetStringUTFChars(env, jprobestr, NULL);
1626 if (!probestr) {
1627 (*env)->DeleteLocalRef(env, jprobestr);
1628 return; /* java exception pending */
1629 }
1630
1631 bzero(&probe, sizeof (probe));
1632 rc = dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, probestr,
1633 &probe);
1634 (*env)->ReleaseStringUTFChars(env, jprobestr, probestr);
1635 (*env)->DeleteLocalRef(env, jprobestr);
1636 if (rc == -1) {
1637 dtj_throw_dtrace_exception(&jc,
1638 "%s is not a valid probe description: %s",
1639 probestr, dtrace_errmsg(dtp,
1640 dtrace_errno(dtp)));
1641 return;
1642 }
1643
1644 pdp = &probe;
1645 }
1646
1647 (void) dtrace_probe_iter(dtp, pdp, func, &jc);
1648 }
1649
1650 /*
1651 * Returns 0 to indicate success, or -1 to cause dtrace_probe_iter() to return a
1652 * negative value prematurely (indicating no match or failure).
1653 */
1654 static int
1655 /* ARGSUSED */
dtj_list_probe(dtrace_hdl_t * dtp,const dtrace_probedesc_t * pdp,void * arg)1656 dtj_list_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg)
1657 {
1658 dtj_java_consumer_t *jc = arg;
1659 JNIEnv *jenv = jc->dtjj_jenv;
1660
1661 jobject jprobedesc = NULL;
1662
1663 jprobedesc = dtj_new_probedesc(jc, pdp);
1664 if (!jprobedesc) {
1665 return (-1); /* java exception pending */
1666 }
1667
1668 /* add probe to list */
1669 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probelist, g_listadd_jm,
1670 jprobedesc);
1671 (*jenv)->DeleteLocalRef(jenv, jprobedesc);
1672 if ((*jenv)->ExceptionCheck(jenv)) {
1673 return (-1);
1674 }
1675
1676 return (0);
1677 }
1678
1679 /*ARGSUSED*/
1680 static int
dtj_list_probe_detail(dtrace_hdl_t * dtp,const dtrace_probedesc_t * pdp,void * arg)1681 dtj_list_probe_detail(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
1682 void *arg)
1683 {
1684 dtj_java_consumer_t *jc = arg;
1685 JNIEnv *jenv = jc->dtjj_jenv;
1686 dtrace_probeinfo_t p;
1687
1688 jobject jprobedesc = NULL;
1689 jobject jprobeinfo = NULL;
1690 jobject jprobe = NULL;
1691
1692 jprobedesc = dtj_new_probedesc(jc, pdp);
1693 if (!jprobedesc) {
1694 return (-1); /* java exception pending */
1695 }
1696
1697 /*
1698 * If dtrace_probe_info() returns a non-zero value, dtrace_errno is set
1699 * for us. In that case, ignore the dtrace error and simply omit probe
1700 * info. That error is implicitly cleared the next time a call is made
1701 * using the same dtrace handle.
1702 */
1703 if (dtrace_probe_info(dtp, pdp, &p) == 0) {
1704 /* create probe info instance */
1705 jprobeinfo = dtj_new_probeinfo(jc, &p);
1706 if (!jprobeinfo) {
1707 (*jenv)->DeleteLocalRef(jenv, jprobedesc);
1708 return (-1); /* java exception pending */
1709 }
1710 }
1711
1712 /* create listed probe instance */
1713 jprobe = (*jenv)->NewObject(jenv, g_probe_jc, g_probeinit_jm,
1714 jprobedesc, jprobeinfo);
1715 (*jenv)->DeleteLocalRef(jenv, jprobedesc);
1716 (*jenv)->DeleteLocalRef(jenv, jprobeinfo);
1717 if (!jprobe) {
1718 return (-1); /* java exception pending */
1719 }
1720
1721 /* add probe to list */
1722 (*jenv)->CallVoidMethod(jenv, jc->dtjj_probelist, g_listadd_jm,
1723 jprobe);
1724 (*jenv)->DeleteLocalRef(jenv, jprobe);
1725 if ((*jenv)->ExceptionCheck(jenv)) {
1726 return (-1);
1727 }
1728
1729 return (0);
1730 }
1731
1732 /*ARGSUSED*/
1733 static int
dtj_list_stmt(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmtdesc_t * stp,void * arg)1734 dtj_list_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
1735 dtrace_stmtdesc_t *stp, void *arg)
1736 {
1737 dtj_java_consumer_t *jc = arg;
1738 dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc;
1739
1740 if (edp == jc->dtjj_consumer->dtjc_last_probe) {
1741 return (0);
1742 }
1743
1744 if (dtrace_probe_iter(dtp, &edp->dted_probe,
1745 jc->dtjj_consumer->dtjc_plistfunc, arg) != 0) {
1746 dtj_throw_dtrace_exception(jc,
1747 "failed to match %s:%s:%s:%s: %s",
1748 edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod,
1749 edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name,
1750 dtrace_errmsg(dtp, dtrace_errno(dtp)));
1751 return (1);
1752 }
1753
1754 jc->dtjj_consumer->dtjc_last_probe = edp;
1755 return (0);
1756 }
1757
1758 /*
1759 * Protected by global lock in Consumer.java
1760 */
1761 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbes(JNIEnv * env,jobject obj,jobject list,jobject program)1762 Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbes(JNIEnv *env,
1763 jobject obj, jobject list, jobject program)
1764 {
1765 dtj_list_compiled_probes(env, obj, list, program, dtj_list_probe);
1766 }
1767
1768 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbeDetail(JNIEnv * env,jobject obj,jobject list,jobject program)1769 Java_org_opensolaris_os_dtrace_LocalConsumer__1listCompiledProbeDetail(
1770 JNIEnv *env, jobject obj, jobject list, jobject program)
1771 {
1772 dtj_list_compiled_probes(env, obj, list, program,
1773 dtj_list_probe_detail);
1774 }
1775
1776 static void
dtj_list_compiled_probes(JNIEnv * env,jobject obj,jobject list,jobject program,dtrace_probe_f * func)1777 dtj_list_compiled_probes(JNIEnv *env, jobject obj, jobject list,
1778 jobject program, dtrace_probe_f *func)
1779 {
1780 dtj_java_consumer_t jc;
1781 dtrace_hdl_t *dtp;
1782 uu_list_walk_t *itr;
1783 dtj_program_t *p;
1784 boolean_t found;
1785 int progid = -1;
1786 int i;
1787
1788 if (dtj_get_java_consumer(env, obj, &jc) != DTJ_OK) {
1789 return; /* java exception pending */
1790 }
1791 dtp = jc.dtjj_consumer->dtjc_dtp;
1792 jc.dtjj_probelist = list;
1793
1794 (*env)->CallVoidMethod(env, list, g_listclear_jm);
1795 if ((*env)->ExceptionCheck(env)) {
1796 return;
1797 }
1798
1799 if (program) {
1800 if (dtj_list_empty(jc.dtjj_consumer->dtjc_program_list)) {
1801 dtj_throw_no_such_element(env, "no compiled program");
1802 return;
1803 }
1804 progid = (*env)->GetIntField(env, program, g_progid_jf);
1805 if (progid == -1) {
1806 dtj_throw_illegal_argument(env, "invalid program");
1807 return;
1808 }
1809 }
1810
1811 jc.dtjj_consumer->dtjc_plistfunc = func;
1812 found = B_FALSE;
1813 itr = uu_list_walk_start(jc.dtjj_consumer->dtjc_program_list, 0);
1814 for (i = 0; (p = uu_list_walk_next(itr)) != NULL; ++i) {
1815 if ((progid != -1) && (progid != i)) {
1816 continue;
1817 }
1818
1819 found = B_TRUE;
1820 (void) dtrace_stmt_iter(dtp, p->dtjp_program,
1821 (dtrace_stmt_f *)dtj_list_stmt, &jc);
1822 }
1823 uu_list_walk_end(itr);
1824
1825 if (program && !found) {
1826 dtj_throw_no_such_element(env, "program not found");
1827 }
1828 }
1829
1830 /*
1831 * Static LocalConsumer.java method
1832 * Protected by global lock (LocalConsumer.class)
1833 */
1834 JNIEXPORT jstring JNICALL
1835 /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1getVersion(JNIEnv * env,jclass class)1836 Java_org_opensolaris_os_dtrace_LocalConsumer__1getVersion(JNIEnv *env,
1837 jclass class)
1838 {
1839 /*
1840 * Handles the case of locale-specific encoding of the user-visible
1841 * version string containing non-ASCII characters.
1842 */
1843 return (dtj_NewStringNative(env, _dtrace_version));
1844 }
1845
1846 /*
1847 * Static LocalConsumer.java method
1848 * Protected by global lock (LocalConsumer.class)
1849 */
1850 JNIEXPORT jstring JNICALL
1851 /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1getExecutableName(JNIEnv * env,jclass class)1852 Java_org_opensolaris_os_dtrace_LocalConsumer__1getExecutableName(JNIEnv *env,
1853 jclass class)
1854 {
1855 jstring jname = NULL;
1856 const char *name = NULL;
1857 char *s;
1858 int len;
1859
1860 name = dtj_getexecname();
1861 len = strlen(name);
1862 s = malloc(len + 1);
1863 if (!s) {
1864 dtj_throw_out_of_memory(env, "Failed to allocate execname");
1865 return (NULL);
1866 }
1867 (void) strcpy(s, name);
1868 name = basename(s);
1869 free(s);
1870 jname = (*env)->NewStringUTF(env, name);
1871 return (jname);
1872 }
1873
1874 /*
1875 * Static LocalConsumer.java method
1876 */
1877 JNIEXPORT void JNICALL
1878 /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1setMaximumConsumers(JNIEnv * env,jclass class,jint max)1879 Java_org_opensolaris_os_dtrace_LocalConsumer__1setMaximumConsumers(JNIEnv *env,
1880 jclass class, jint max)
1881 {
1882 g_max_consumers = max;
1883 }
1884
1885 /*
1886 * Static LocalConsumer.java method
1887 */
1888 JNIEXPORT void JNICALL
1889 /* ARGSUSED */
Java_org_opensolaris_os_dtrace_LocalConsumer__1setDebug(JNIEnv * env,jclass class,jboolean debug)1890 Java_org_opensolaris_os_dtrace_LocalConsumer__1setDebug(JNIEnv *env,
1891 jclass class, jboolean debug)
1892 {
1893 g_dtj_util_debug = debug;
1894 }
1895
1896 JNIEXPORT void JNICALL
Java_org_opensolaris_os_dtrace_LocalConsumer__1destroy(JNIEnv * env,jobject obj)1897 Java_org_opensolaris_os_dtrace_LocalConsumer__1destroy(JNIEnv *env, jobject obj)
1898 {
1899 dtj_consumer_t *c;
1900
1901 c = dtj_remove_consumer(env, obj);
1902 if (c == NULL) {
1903 return; /* java exception pending */
1904 }
1905 dtj_consumer_destroy(c);
1906 }
1907