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