/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include <door.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <thread.h>
#include <unistd.h>
#include "jvm_dtrace.h"
// NOTE: These constants are used in JVM code as well.
// KEEP JVM CODE IN SYNC if you are going to change these...
// generic error messages
// error messages for attach
// error messages for enable probe
// error message for detach
do { \
} while(0)
struct _jvm_t {
int door_fd;
};
static int libjvm_dtrace_debug;
if (libjvm_dtrace_debug) {
}
}
/* Key for thread local error message */
/* init function for this library */
static void init_jvm_dtrace() {
/* check for env. var for debug mode */
/* create key for thread local error message */
print_debug("can't create thread_key_t for jvm error key\n");
// exit(1); ?
}
}
#pragma init(init_jvm_dtrace)
/* set thread local error message */
}
/* clear thread local error message */
static void clear_jvm_error() {
}
/* file handling functions that can handle interrupt */
int ret;
return ret;
}
int ret;
return ret;
}
int ret;
return ret;
}
/* send SIGQUIT signal to given process */
int ret;
return ret;
}
/* called to check permissions on attach file */
int res;
/*
*/
if (res != 0) {
return -1;
}
return -1;
}
return 0;
}
/* fill-in the name of attach file name in given buffer */
}
/* open door file for the given JVM */
int fd;
if (fd < 0) {
return -1;
}
if (check_permission(path) != 0) {
file_close(fd);
fd = -1;
}
return fd;
}
/* create attach file for given process */
int fd;
if (fd < 0) {
} else {
}
return fd;
}
/* delete attach file for given process */
if (res) {
} else {
}
}
/* attach to given JVM */
return NULL;
}
attach_fd = -1;
if (door_fd < 0) {
print_debug("trying to create attach file\n");
goto quit;
}
/* send QUIT signal to the target so that it will
* check for the attach file.
*/
if (send_sigquit(pid) != 0) {
print_debug("sending SIGQUIT failed\n");
goto quit;
}
/* give the target VM time to start the attach mechanism */
do {
int res;
i++;
if (door_fd < 0) {
goto quit;
}
}
quit:
if (attach_fd >= 0) {
}
if (door_fd >= 0) {
} else {
}
return jvm;
}
/* return the last thread local error message */
const char* jvm_get_last_error() {
return res;
}
/* detach the givenb JVM */
if (jvm) {
int res;
res = -1;
} else {
res = 0;
}
}
return res;
} else {
print_debug("jvm_t* is NULL\n");
return -1;
}
}
/*
* A simple table to translate some known errors into reasonable
* error messages
*/
static struct {
int err;
const char* msg;
} const error_messages[] = {
{ 100, "Bad request" },
{ 101, "Protocol mismatch" },
{ 102, "Resource failure" },
{ 103, "Internal error" },
{ 104, "Permission denied" },
};
/*
* Lookup the given error code and return the appropriate
* message. If not found return NULL.
*/
int i;
for (i=0; i<table_size; i++) {
return error_messages[i].msg;
}
}
return NULL;
}
/*
* Current protocol version
*/
/*
* Enqueue attach-on-demand command to the given JVM
*/
static
int rc, i;
/*
* First we get the command string and create the start of the
* argument string to send to the target VM:
* <ver>\0<cmd>\0
*/
print_debug("command name is NULL\n");
goto quit;
}
} else {
goto quit;
}
/*
* Next we iterate over the arguments and extend the buffer
* to include them.
*/
for (i=0; i<arg_count; i++) {
goto quit;
}
}
}
/*
* The arguments to the door function are in 'buf' so we now
* do the door call
*/
/*
* door_call failed
*/
if (rc == -1) {
print_debug("door_call failed\n");
} else {
/*
* door_call succeeded but the call didn't return the the expected jint.
*/
print_debug("Enqueue error - reason unknown as result is truncated!");
} else {
if (*res != 0) {
} else {
}
} else {
/*
* The door call should return a file descriptor to one end of
* a socket pair
*/
} else {
print_debug("Reply from enqueue missing descriptor!\n");
}
}
}
}
quit:
return result;
}
/* read status code for a door command */
int index = 0;
while (1) {
print_debug("door cmd status: read status failed\n");
return -1;
}
if (ch == '\n') {
}
print_debug("door cmd status: read status overflow\n");
return -1;
}
}
}
/* enable one or more DTrace probes for a given JVM */
char ch;
int count = 0;
print_debug("jvm_t* is NULL\n");
return -1;
}
probe_types[0] == NULL) {
print_debug("invalid probe type argument(s)\n");
return -1;
}
const char* p = probe_types[index];
if (strcmp(p, JVM_DTPROBE_OBJECT_ALLOC) == 0) {
count++;
} else if (strcmp(p, JVM_DTPROBE_METHOD_ENTRY) == 0 ||
strcmp(p, JVM_DTPROBE_METHOD_RETURN) == 0) {
count++;
} else if (strcmp(p, JVM_DTPROBE_MONITOR_ENTER) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_ENTERED) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_EXIT) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_WAIT) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_WAITED) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_NOTIFY) == 0 ||
strcmp(p, JVM_DTPROBE_MONITOR_NOTIFYALL) == 0) {
count++;
} else if (strcmp(p, JVM_DTPROBE_ALL) == 0) {
count++;
}
}
if (count == 0) {
return count;
}
if (fd < 0) {
return -1;
}
// non-zero status is error
if (status) {
print_debug("%s command failed (status: %d) in target JVM\n",
file_close(fd);
return -1;
}
// read from stream until EOF
if (libjvm_dtrace_debug) {
}
}
file_close(fd);
return count;
}