--- old/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c 2020-05-20 18:10:27.182115987 -0700 +++ /dev/null 2020-03-09 18:57:19.455001459 -0700 @@ -1,562 +0,0 @@ -/* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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... - -#define DTRACE_ALLOC_PROBES 0x1 -#define DTRACE_METHOD_PROBES 0x2 -#define DTRACE_MONITOR_PROBES 0x4 -#define DTRACE_ALL_PROBES -1 - -// generic error messages -#define JVM_ERR_OUT_OF_MEMORY "out of memory (native heap)" -#define JVM_ERR_INVALID_PARAM "invalid input parameter(s)" -#define JVM_ERR_NULL_PARAM "input paramater is NULL" - -// error messages for attach -#define JVM_ERR_CANT_OPEN_DOOR "cannot open door file" -#define JVM_ERR_CANT_CREATE_ATTACH_FILE "cannot create attach file" -#define JVM_ERR_DOOR_FILE_PERMISSION "door file is not secure" -#define JVM_ERR_CANT_SIGNAL "cannot send SIGQUIT to target" - -// error messages for enable probe -#define JVM_ERR_DOOR_CMD_SEND "door command send failed" -#define JVM_ERR_DOOR_CANT_READ_STATUS "cannot read door command status" -#define JVM_ERR_DOOR_CMD_STATUS "door command error status" - -// error message for detach -#define JVM_ERR_CANT_CLOSE_DOOR "cannot close door file" - -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - -struct _jvm_t { - pid_t pid; - int door_fd; -}; - -static int libjvm_dtrace_debug; -static void print_debug(const char* fmt,...) { - if (libjvm_dtrace_debug) { - va_list alist; - va_start(alist, fmt); - fputs("libjvm_dtrace DEBUG: ", stderr); - vfprintf(stderr, fmt, alist); - va_end(alist); - } -} - -/* Key for thread local error message */ -static thread_key_t jvm_error_key; - -/* init function for this library */ -static void init_jvm_dtrace() { - /* check for env. var for debug mode */ - libjvm_dtrace_debug = getenv("LIBJVM_DTRACE_DEBUG") != NULL; - /* create key for thread local error message */ - if (thr_keycreate(&jvm_error_key, NULL) != 0) { - 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 */ -static void set_jvm_error(const char* msg) { - thr_setspecific(jvm_error_key, (void*)msg); -} - -/* clear thread local error message */ -static void clear_jvm_error() { - thr_setspecific(jvm_error_key, NULL); -} - -/* file handling functions that can handle interrupt */ - -static int file_open(const char* path, int flag) { - int ret; - RESTARTABLE(open(path, flag), ret); - return ret; -} - -static int file_close(int fd) { - return close(fd); -} - -static int file_read(int fd, char* buf, int len) { - int ret; - RESTARTABLE(read(fd, buf, len), ret); - return ret; -} - -/* send SIGQUIT signal to given process */ -static int send_sigquit(pid_t pid) { - int ret; - RESTARTABLE(kill(pid, SIGQUIT), ret); - return ret; -} - -/* called to check permissions on attach file */ -static int check_permission(const char* path) { - struct stat64 sb; - uid_t uid, gid; - int res; - - /* - * Check that the path is owned by the effective uid/gid of this - * process. Also check that group/other access is not allowed. - */ - uid = geteuid(); - gid = getegid(); - - res = stat64(path, &sb); - if (res != 0) { - print_debug("stat failed for %s\n", path); - return -1; - } - - if ((sb.st_uid != uid) || (sb.st_gid != gid) || - ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0)) { - print_debug("well-known file %s is not secure\n", path); - return -1; - } - return 0; -} - -#define ATTACH_FILE_PATTERN "/tmp/.attach_pid%d" - -/* fill-in the name of attach file name in given buffer */ -static void fill_attach_file_name(char* path, int len, pid_t pid) { - memset(path, 0, len); - sprintf(path, ATTACH_FILE_PATTERN, pid); -} - -#define DOOR_FILE_PATTERN "/tmp/.java_pid%d" - -/* open door file for the given JVM */ -static int open_door(pid_t pid) { - char path[PATH_MAX + 1]; - int fd; - - sprintf(path, DOOR_FILE_PATTERN, pid); - fd = file_open(path, O_RDONLY); - if (fd < 0) { - set_jvm_error(JVM_ERR_CANT_OPEN_DOOR); - print_debug("cannot open door file %s\n", path); - return -1; - } - print_debug("opened door file %s\n", path); - if (check_permission(path) != 0) { - set_jvm_error(JVM_ERR_DOOR_FILE_PERMISSION); - print_debug("check permission failed for %s\n", path); - file_close(fd); - fd = -1; - } - return fd; -} - -/* create attach file for given process */ -static int create_attach_file(pid_t pid) { - char path[PATH_MAX + 1]; - int fd; - fill_attach_file_name(path, sizeof(path), pid); - fd = file_open(path, O_CREAT | O_RDWR); - if (fd < 0) { - set_jvm_error(JVM_ERR_CANT_CREATE_ATTACH_FILE); - print_debug("cannot create file %s\n", path); - } else { - print_debug("created attach file %s\n", path); - } - return fd; -} - -/* delete attach file for given process */ -static void delete_attach_file(pid_t pid) { - char path[PATH_MAX + 1]; - fill_attach_file_name(path, sizeof(path), pid); - int res = unlink(path); - if (res) { - print_debug("cannot delete attach file %s\n", path); - } else { - print_debug("deleted attach file %s\n", path); - } -} - -/* attach to given JVM */ -jvm_t* jvm_attach(pid_t pid) { - jvm_t* jvm; - int door_fd, attach_fd, i = 0; - - jvm = (jvm_t*) calloc(1, sizeof(jvm_t)); - if (jvm == NULL) { - set_jvm_error(JVM_ERR_OUT_OF_MEMORY); - print_debug("calloc failed in %s at %d\n", __FILE__, __LINE__); - return NULL; - } - jvm->pid = pid; - attach_fd = -1; - - door_fd = open_door(pid); - if (door_fd < 0) { - print_debug("trying to create attach file\n"); - if ((attach_fd = create_attach_file(pid)) < 0) { - goto quit; - } - - /* send QUIT signal to the target so that it will - * check for the attach file. - */ - if (send_sigquit(pid) != 0) { - set_jvm_error(JVM_ERR_CANT_SIGNAL); - print_debug("sending SIGQUIT failed\n"); - goto quit; - } - - /* give the target VM time to start the attach mechanism */ - do { - int res; - RESTARTABLE(poll(0, 0, 200), res); - door_fd = open_door(pid); - i++; - } while (i <= 50 && door_fd == -1); - if (door_fd < 0) { - print_debug("Unable to open door to process %d\n", pid); - goto quit; - } - } - -quit: - if (attach_fd >= 0) { - file_close(attach_fd); - delete_attach_file(jvm->pid); - } - if (door_fd >= 0) { - jvm->door_fd = door_fd; - clear_jvm_error(); - } else { - free(jvm); - jvm = NULL; - } - return jvm; -} - -/* return the last thread local error message */ -const char* jvm_get_last_error() { - const char* res = NULL; - thr_getspecific(jvm_error_key, (void**)&res); - return res; -} - -/* detach the givenb JVM */ -int jvm_detach(jvm_t* jvm) { - if (jvm) { - int res = 0; - if (jvm->door_fd != -1) { - if (file_close(jvm->door_fd) != 0) { - set_jvm_error(JVM_ERR_CANT_CLOSE_DOOR); - res = -1; - } else { - clear_jvm_error(); - } - } - free(jvm); - return res; - } else { - set_jvm_error(JVM_ERR_NULL_PARAM); - 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. - */ -static const char* translate_error(int err) { - int table_size = sizeof(error_messages) / sizeof(error_messages[0]); - int i; - - for (i=0; i\0\0 - */ - if (cstr == NULL) { - print_debug("command name is NULL\n"); - goto quit; - } - size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2; - buf = (char*)malloc(size); - if (buf != NULL) { - char* pos = buf; - strcpy(buf, PROTOCOL_VERSION); - pos += strlen(PROTOCOL_VERSION)+1; - strcpy(pos, cstr); - } else { - set_jvm_error(JVM_ERR_OUT_OF_MEMORY); - print_debug("malloc failed at %d in %s\n", __LINE__, __FILE__); - goto quit; - } - - /* - * Next we iterate over the arguments and extend the buffer - * to include them. - */ - for (i=0; idoor_fd, &door_args), rc); - - /* - * door_call failed - */ - if (rc == -1) { - print_debug("door_call failed\n"); - } else { - /* - * door_call succeeded but the call didn't return the expected jint. - */ - if (door_args.data_size < sizeof(int)) { - print_debug("Enqueue error - reason unknown as result is truncated!"); - } else { - int* res = (int*)(door_args.data_ptr); - if (*res != 0) { - const char* msg = translate_error(*res); - if (msg == NULL) { - print_debug("Unable to enqueue command to target VM: %d\n", *res); - } else { - print_debug("Unable to enqueue command to target VM: %s\n", msg); - } - } else { - /* - * The door call should return a file descriptor to one end of - * a socket pair - */ - if ((door_args.desc_ptr != NULL) && - (door_args.desc_num == 1) && - (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) { - result = door_args.desc_ptr->d_data.d_desc.d_descriptor; - } else { - print_debug("Reply from enqueue missing descriptor!\n"); - } - } - } - } - -quit: - if (buf) free(buf); - return result; -} - -/* read status code for a door command */ -static int read_status(int fd) { - char ch, buf[16]; - int index = 0; - - while (1) { - if (file_read(fd, &ch, sizeof(ch)) != sizeof(ch)) { - set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS); - print_debug("door cmd status: read status failed\n"); - return -1; - } - buf[index++] = ch; - if (ch == '\n') { - buf[index - 1] = '\0'; - return atoi(buf); - } - if (index == sizeof(buf)) { - set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS); - print_debug("door cmd status: read status overflow\n"); - return -1; - } - } -} - -static const char* ENABLE_DPROBES_CMD = "enabledprobes"; - -/* enable one or more DTrace probes for a given JVM */ -int jvm_enable_dtprobes(jvm_t* jvm, int num_probe_types, const char** probe_types) { - int fd, status = 0; - char ch; - const char* args[1]; - char buf[16]; - int probe_type = 0, index; - int count = 0; - - if (jvm == NULL) { - set_jvm_error(JVM_ERR_NULL_PARAM); - print_debug("jvm_t* is NULL\n"); - return -1; - } - - if (num_probe_types == 0 || probe_types == NULL || - probe_types[0] == NULL) { - set_jvm_error(JVM_ERR_INVALID_PARAM); - print_debug("invalid probe type argument(s)\n"); - return -1; - } - - for (index = 0; index < num_probe_types; index++) { - const char* p = probe_types[index]; - if (strcmp(p, JVM_DTPROBE_OBJECT_ALLOC) == 0) { - probe_type |= DTRACE_ALLOC_PROBES; - count++; - } else if (strcmp(p, JVM_DTPROBE_METHOD_ENTRY) == 0 || - strcmp(p, JVM_DTPROBE_METHOD_RETURN) == 0) { - probe_type |= DTRACE_METHOD_PROBES; - 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) { - probe_type |= DTRACE_MONITOR_PROBES; - count++; - } else if (strcmp(p, JVM_DTPROBE_ALL) == 0) { - probe_type |= DTRACE_ALL_PROBES; - count++; - } - } - - if (count == 0) { - return count; - } - sprintf(buf, "%d", probe_type); - args[0] = buf; - - fd = enqueue_command(jvm, ENABLE_DPROBES_CMD, 1, args); - if (fd < 0) { - set_jvm_error(JVM_ERR_DOOR_CMD_SEND); - return -1; - } - - status = read_status(fd); - // non-zero status is error - if (status) { - set_jvm_error(JVM_ERR_DOOR_CMD_STATUS); - print_debug("%s command failed (status: %d) in target JVM\n", - ENABLE_DPROBES_CMD, status); - file_close(fd); - return -1; - } - // read from stream until EOF - while (file_read(fd, &ch, sizeof(ch)) == sizeof(ch)) { - if (libjvm_dtrace_debug) { - printf("%c", ch); - } - } - - file_close(fd); - clear_jvm_error(); - return count; -}