/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
#include <stddef.h>
#include <pthread.h>
#include <string.h>
#include <dtj_util.h>
/*
* dtj_util.c separates functionality that is generally useful from
* that which is specific to the Java DTrace API. If moved to a separate
* library, this functionality could be shared by other JNI wrappers.
*/
/* NativeException */
/* java.io.Serializable */
/* java.lang.Number */
/* java.lang.Byte */
/* java.lang.Character */
/* java.lang.Short */
/* java.lang.Integer */
/* java.lang.Long */
/* java.math.BigInteger */
/* java.lang.String */
/* java.lang.StringBuilder */
/* java.lang.Object */
/* java.lang.Enum */
/* List */
/* Global list pools */
/* Constructors */
char *, uu_list_pool_t *);
char *, char *, uu_list_pool_t *);
char *, uu_list_pool_t *);
char *, char *, uu_list_pool_t *);
/* Destructors */
static void dtj_java_class_destroy(void *, void *);
static void dtj_java_method_destroy(void *, void *);
static void dtj_java_field_destroy(void *, void *);
/* Comparison functions, uu_compare_fn_t signature */
static int dtj_java_class_cmp(const void *, const void *, void *);
static int dtj_java_method_cmp(const void *, const void *, void *);
static int dtj_java_field_cmp(const void *, const void *, void *);
/* Java Throwable */
/* Support for uu_list_t wrappers */
static boolean_t dtj_check_pointer_pool(void);
static boolean_t dtj_check_string_pool(void);
{
/* NativeException */
/* java.io.Serializable */
/* java.lang.Number */
/* java.lang.Byte */
/* java.lang.Character */
/* java.lang.Short */
/* java.lang.Integer */
/* java.lang.Long */
/* java.math.BigInteger */
"(J)Ljava/math/BigInteger;" },
"(Ljava/math/BigInteger;)Ljava/math/BigInteger;" },
"(I)Ljava/math/BigInteger;" },
"(Ljava/math/BigInteger;)Ljava/math/BigInteger;" },
"(I)Ljava/math/BigInteger;" },
/* java.lang.String */
/* java.lang.StringBuilder */
"(C)Ljava/lang/StringBuilder;" },
"(I)Ljava/lang/StringBuilder;" },
"(J)Ljava/lang/StringBuilder;" },
/* java.lang.Object */
/* java.lang.Enum */
/* List */
{ DTJ_TYPE_END }
};
}
return (status);
}
static int
/* ARGSUSED */
{
}
static int
/* ARGSUSED */
{
int cmp;
if (cmp == 0) {
}
return (cmp);
}
static int
/* ARGSUSED */
{
}
static dtj_java_class_t *
{
if (c) {
(g_dtj_util_debug ? UU_LIST_DEBUG : 0));
if (!c->djc_methods) {
"Failed method list creation");
free(c);
c = NULL;
}
(g_dtj_util_debug ? UU_LIST_DEBUG : 0));
if (!c->djc_fields) {
"Failed field list creation");
c->djc_methods = NULL;
free(c);
c = NULL;
}
} else {
"Failed to allocate class description");
}
return (c);
}
static dtj_java_method_t *
{
if (m) {
m->djm_signature = signature;
m->djm_static = B_FALSE;
} else {
"Failed to allocate method description");
}
return (m);
}
static dtj_java_method_t *
{
if (m) {
m->djm_static = B_TRUE;
}
return (m);
}
static dtj_java_field_t *
{
if (f) {
f->djf_static = B_FALSE;
} else {
"Failed to allocate field description");
}
return (f);
}
static dtj_java_field_t *
{
if (f) {
f->djf_static = B_TRUE;
}
return (f);
}
static void
/* ARGSUSED */
{
if (v) {
dtj_java_class_t *c = v;
c->djc_methods = NULL;
c->djc_fields = NULL;
uu_free(v);
}
}
static void
/* ARGSUSED */
{
if (v) {
dtj_java_method_t *m = v;
uu_free(v);
}
}
static void
/* ARGSUSED */
{
if (v) {
dtj_java_field_t *f = v;
uu_free(f);
}
}
{
sizeof (dtj_java_class_t),
(g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
if (!classpool) {
return (DTJ_ERR);
}
sizeof (dtj_java_method_t),
(g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
if (!methodpool) {
return (DTJ_ERR);
}
sizeof (dtj_java_field_t),
(g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
if (!fieldpool) {
return (DTJ_ERR);
}
(g_dtj_util_debug ? UU_LIST_DEBUG : 0));
if (!classes) {
return (DTJ_ERR);
}
/* java error pending */
return (status);
}
if (!jc) {
/* NoClassDefFoundError pending */
return (DTJ_ERR);
}
if (!gjc) {
"Failed to create global class reference");
return (DTJ_ERR);
}
/* java error pending */
return (status);
}
/* java error pending */
return (status);
}
}
return (DTJ_OK);
}
/*
* Converts JNI table entry desriptions into java_class_t descriptors.
*/
static dtj_status_t
{
int i;
dtj_java_class_t *c = NULL;
dtj_java_field_t *f;
/*
* Class not added until all of its method and field information
* is attached, so we defer adding a class until the next
* element with type JCLASS.
*/
case JCLASS:
if (c) {
/* previous class */
if (!dtj_list_add(classes, c)) {
"Failed to add class description");
/*
* In response to an error return value,
* the caller will delete the class
* descriptions list with any
* descriptions created so far.
*/
return (DTJ_ERR);
}
}
if (!c) {
/* OutOfMemoryError pending */
return (DTJ_ERR);
}
break;
case JMETHOD:
if (!c) {
"method description not preceded "
"by class description");
return (DTJ_ERR);
}
if (!m) {
/* OutOfMemoryError pending */
return (DTJ_ERR);
}
if (!dtj_list_add(c->djc_methods, m)) {
"Failed to add method description");
return (DTJ_ERR);
}
break;
case JMETHOD_STATIC:
if (!c) {
"static method description not preceded "
"by class description");
return (DTJ_ERR);
}
if (!m) {
/* OutOfMemoryError pending */
return (DTJ_ERR);
}
if (!dtj_list_add(c->djc_methods, m)) {
"Failed to add static method description");
return (DTJ_ERR);
}
break;
case JFIELD:
if (!c) {
"field description not preceded "
"by class description");
return (DTJ_ERR);
}
if (!f) {
/* OutOfMemoryError pending */
return (DTJ_ERR);
}
if (!dtj_list_add(c->djc_fields, f)) {
"Failed to add field description");
return (DTJ_ERR);
}
break;
case JFIELD_STATIC:
if (!c) {
"static field description not preceded "
"by class description");
return (DTJ_ERR);
}
if (!f) {
/* OutOfMemoryError pending */
return (DTJ_ERR);
}
if (!dtj_list_add(c->djc_fields, f)) {
"Failed to add static field description");
return (DTJ_ERR);
}
break;
default:
return (DTJ_ERR);
}
}
if (c) {
/* last class */
if (!dtj_list_add(classes, c)) {
"Failed to add class description");
return (DTJ_ERR);
}
}
return (DTJ_OK);
}
static dtj_status_t
{
if (method->djm_static) {
} else {
}
if (jm == 0) {
/*
* The pending NoSuchMethodError gives only the
* method name, which is not so helpful for
* overloaded methods and methods such as <init>
* that have the same name in multiple classes.
* Clear the pending error and throw one that
* includes the class name and the method
* signature.
*/
return (DTJ_ERR);
}
}
return (DTJ_OK);
}
static dtj_status_t
{
if (field->djf_static) {
} else {
}
if (jf == 0) {
"%s.%s signature: %s", c->djc_name,
"java/lang/NoSuchFieldError");
return (DTJ_ERR);
}
}
return (DTJ_OK);
}
/* Common utilities */
static void
{
}
void
{
/*
* JNI documentation unclear whether NewGlobalRef() can throw
* OutOfMemoryError, so we'll make this function safe in case
* OutOfMemoryError has already been thrown
*/
return;
}
"java/lang/OutOfMemoryError");
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
"java/lang/AssertionError");
}
void
{
}
void
{
jthrowable e = NULL;
if (!e) {
return;
}
if (!g_dtj_load_common) {
return;
}
/* Unsafe to test while exception pending */
/* Already wrapped */
return;
}
/*
* Only wrap the exception if possible, otherwise just throw the
* original exception.
*/
return;
}
return;
}
}
/*
* Calls the given java object's toString() method and prints the value to
* stdout. Useful for debugging. Guaranteed that no exception is pending when
* this function returns.
*/
void
{
const char *cstr;
if (!g_dtj_load_common) {
"dtj_load_common() has not been called");
return;
}
if (!jobj) {
(void) printf("null\n");
return;
}
return;
}
if (cstr) {
} else {
return;
}
}
{
if (i >= 0) {
g_bigint_val_jsm, u);
} else {
g_bigint_val_jsm, u);
g_bigint_setbit_jm, 63);
}
return (val64);
}
{
return (val128);
}
{
/* return NULL if OutOfMemoryError pending */
return (jstr);
}
{
int len;
if (!g_dtj_load_common) {
"dtj_load_common() has not been called");
return (NULL);
}
if (!bytes) {
return (NULL); /* OutOfMemoryError pending */
}
return (NULL); /* ArrayIndexOutOfBoundsException pending */
}
bytes);
/* return NULL result if exception pending */
return (result);
}
char *
{
if (!g_dtj_load_common) {
"dtj_load_common() has not been called");
return (NULL);
}
return (NULL); /* OutOfMemoryError pending */
}
/* Does not throw exceptions */
if (!result) {
"could not allocate native chars");
return (NULL);
}
/* Skip check for ArrayIndexOutOfBoundsException */
return (result);
}
void
/* ARGSUSED */
{
}
char **
{
const char *str;
int i;
if (!g_dtj_load_common) {
"dtj_load_common() has not been called");
return (NULL);
}
/*
* Initialize all string pointers to NULL so that in case of an error
* filling in the array, free_argv() will not attempt to free the
* unallocated elements. Also NULL-terminate the string array for
* functions that expect terminating NULL rather than rely on argc.
*/
if (!argv) {
return (NULL);
}
for (i = 0; i < *argc; ++i) {
return (NULL);
}
return (NULL);
}
if (!argv[i]) {
return (NULL);
}
}
return (argv);
}
char **
{
char *s; /* writable command */
int len;
if (!g_dtj_load_common) {
"dtj_load_common() has not been called");
return (NULL);
}
if (!command) {
return (NULL);
return (NULL);
}
return (NULL);
}
if (!s) {
"failed to allocate command string");
return (NULL);
}
/*
* Initialize all string pointers to NULL so that in case of an error
* filling in the array, free_argv() will not attempt to free the
* unallocated elements. Also NULL-terminate the string array for
* functions that expect terminating NULL rather than rely on argc.
* Allow for maximum length resulting from single-character tokens
* separated by single spaces.
*/
if (!argv) {
free(s);
return (NULL);
}
*argc = 0;
free(s);
return (NULL);
}
}
if (*argc == 0) {
free(s);
return (NULL);
}
free(s);
return (argv);
}
void
{
if (argv) {
char **s = argv;
while (*s) {
free((void *)*s);
*s++ = NULL;
}
}
}
/* Wrappers for uu_list_t */
int
/* ARGSUSED */
{
/*
* It is not valid to compare pointers using the relational operators
* unless they point to elements in the same array.
*/
int rc;
return (rc);
}
int
/* ARGSUSED */
{
}
return (1);
}
}
static boolean_t
dtj_check_pointer_pool(void)
{
if (g_pointer_pool == NULL) {
sizeof (dtj_pointer_list_entry_t),
(g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
if (g_pointer_pool == NULL) {
return (B_FALSE);
}
}
return (B_TRUE);
}
dtj_pointer_list_create(void)
{
if (!dtj_check_pointer_pool()) {
return (NULL);
}
(g_dtj_util_debug ? UU_LIST_DEBUG : 0));
return (list);
}
dtj_pointer_list_entry_create(void *p)
{
if (!dtj_check_pointer_pool()) {
return (NULL);
}
e = uu_zalloc(sizeof (dtj_pointer_list_entry_t));
if (e) {
e->dple_ptr = p;
}
return (e);
}
static boolean_t
dtj_check_string_pool(void)
{
if (g_string_pool == NULL) {
sizeof (dtj_string_list_entry_t),
(g_dtj_util_debug ? UU_LIST_POOL_DEBUG : 0));
if (g_string_pool == NULL) {
return (B_FALSE);
}
}
return (B_TRUE);
}
dtj_string_list_create(void)
{
if (!dtj_check_string_pool()) {
return (NULL);
}
(g_dtj_util_debug ? UU_LIST_DEBUG : 0));
return (list);
}
dtj_string_list_entry_create(const char *s)
{
if (!dtj_check_string_pool()) {
return (NULL);
}
e = uu_zalloc(sizeof (dtj_string_list_entry_t));
if (e) {
if (s) {
if (e->dsle_value) {
(void) strcpy(e->dsle_value, s);
} else {
uu_list_node_fini(e, &e->dsle_node,
uu_free(e);
e = NULL;
}
}
}
return (e);
}
void
dtj_pointer_list_entry_destroy(void *v,
{
if (v) {
dtj_pointer_list_entry_t *e = v;
if (value_destroy) {
}
uu_free(v);
}
}
void
/* ARGSUSED */
{
if (v) {
dtj_string_list_entry_t *e = v;
free(e->dsle_value);
e->dsle_value = NULL;
uu_free(v);
}
}
void
void *arg)
{
void *value;
if (!list) {
return;
}
if (value_destroy) {
}
} else {
}
}
}
void
{
}
void
{
if (!list) {
return;
}
}
}
void
{
}
void
{
}
void
{
}
{
return (uu_list_numnodes(list) == 0);
}
{
}
{
if (!e) {
return (B_FALSE);
}
return (dtj_list_add(list, e));
}
void *
{
if (!e) {
return (DTJ_INVALID_PTR);
}
return (e->dple_ptr);
}
void *
{
if (!e) {
/* NULL is a valid value; use -1 for invalid */
return (DTJ_INVALID_PTR);
}
return (e->dple_ptr);
}
void *
{
if (!e) {
/* NULL is a valid value; use -1 for invalid */
return (DTJ_INVALID_PTR);
}
return (e->dple_ptr);
}
{
if (!e) {
return (B_FALSE);
}
return (dtj_list_add(list, e));
}
const char *
{
if (!e) {
return (DTJ_INVALID_STR);
}
return (e->dsle_value);
}
const char *
{
if (!e) {
/* NULL is a valid string value; use -1 for invalid */
return (DTJ_INVALID_STR);
}
return (e->dsle_value);
}
const char *
{
if (!e) {
/* NULL is a valid string value; use -1 for invalid */
return (DTJ_INVALID_STR);
}
return (e->dsle_value);
}