| /* | |
| * Copyright (c) 2003, 2022, 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. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * 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. | |
| */ | |
| /* Error message and general message handling functions. */ | |
| /* NOTE: We assume that most strings passed around this library are | |
| * UTF-8 (modified or standard) and not platform encoding. | |
| * Before sending any strings to the "system" (e.g. OS system | |
| * calls, or system input/output functions like fprintf) we need | |
| * to make sure that the strings are transformed from UTF-8 to | |
| * the platform encoding accepted by the system. | |
| * UTF-8 and most encodings have simple ASCII or ISO-Latin | |
| * characters as a subset, so in most cases the strings really | |
| * don't need to be converted, but we don't know that easily. | |
| * Parts of messages can be non-ASCII in some cases, so they may | |
| * include classnames, methodnames, signatures, or other pieces | |
| * that could contain non-ASCII characters, either from JNI or | |
| * JVMTI (which both return modified UTF-8 strings). | |
| * (It's possible that the platform encoding IS UTF-8, but we | |
| * assume not, just to be safe). | |
| * | |
| */ | |
| #include <stdarg.h> | |
| #include <errno.h> | |
| #include "util.h" | |
| #include "utf_util.h" | |
| #include "proc_md.h" | |
| /* Maximum number of bytes in a message, including the trailing zero. | |
| * Do not print very long messages as they could be truncated. | |
| * Use at most one pathname per message. NOTE, we use MAXPATHLEN*2 | |
| * in case each character in the pathname takes 2 bytes. | |
| */ | |
| #define MAX_MESSAGE_BUF MAXPATHLEN*2+512 | |
| /* Print message in platform encoding (assume all input is UTF-8 safe) | |
| * NOTE: This function is at the lowest level of the call tree. | |
| * Do not use the ERROR* macros here. | |
| */ | |
| static void | |
| vprint_message(FILE *fp, const char *prefix, const char *suffix, | |
| const char *format, va_list ap) | |
| { | |
| jbyte utf8buf[MAX_MESSAGE_BUF]; | |
| int len; | |
| char pbuf[MAX_MESSAGE_BUF]; | |
| /* Fill buffer with single UTF-8 string */ | |
| (void)vsnprintf((char*)utf8buf, sizeof(utf8buf), format, ap); | |
| utf8buf[sizeof(utf8buf) - 1] = 0; | |
| len = (int)strlen((char*)utf8buf); | |
| /* Convert to platform encoding (ignore errors, dangerous area) */ | |
| (void)utf8ToPlatform(utf8buf, len, pbuf, (int)sizeof(pbuf)); | |
| (void)fprintf(fp, "%s%s%s", prefix, pbuf, suffix); | |
| } | |
| /* Print message in platform encoding (assume all input is UTF-8 safe) | |
| * NOTE: This function is at the lowest level of the call tree. | |
| * Do not use the ERROR* macros here. | |
| */ | |
| void | |
| print_message(FILE *fp, const char *prefix, const char *suffix, | |
| const char *format, ...) | |
| { | |
| va_list ap; | |
| va_start(ap, format); | |
| vprint_message(fp, prefix, suffix, format, ap); | |
| va_end(ap); | |
| } | |
| /* Generate error message */ | |
| void | |
| error_message(const char *format, ...) | |
| { | |
| va_list ap; | |
| va_start(ap, format); | |
| vprint_message(stderr, "ERROR: ", "\n", format, ap); | |
| va_end(ap); | |
| if ( gdata->doerrorexit ) { | |
| EXIT_ERROR(AGENT_ERROR_INTERNAL,"Requested errorexit=y exit()"); | |
| } | |
| } | |
| /* Print plain message to stdout. */ | |
| void | |
| tty_message(const char *format, ...) | |
| { | |
| va_list ap; | |
| va_start(ap, format); | |
| vprint_message(stdout, "", "\n", format, ap); | |
| va_end(ap); | |
| (void)fflush(stdout); | |
| } | |
| /* Print assertion error message to stderr. */ | |
| void | |
| jdiAssertionFailed(char *fileName, int lineNumber, char *msg) | |
| { | |
| LOG_MISC(("ASSERT FAILED: %s : %d - %s\n", fileName, lineNumber, msg)); | |
| print_message(stderr, "ASSERT FAILED: ", "\n", | |
| "%s : %d - %s", fileName, lineNumber, msg); | |
| if (gdata && gdata->assertFatal) { | |
| EXIT_ERROR(AGENT_ERROR_INTERNAL,"Assertion Failed"); | |
| } | |
| } | |
| /* Macro for case on switch, returns string for name. */ | |
| #define CASE_RETURN_TEXT(name) case name: return #name; | |
| /* Mapping of JVMTI errors to their name */ | |
| const char * | |
| jvmtiErrorText(jvmtiError error) | |
| { | |
| switch ((int)error) { | |
| CASE_RETURN_TEXT(JVMTI_ERROR_NONE) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_THREAD) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_THREAD_GROUP) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_PRIORITY) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_THREAD_NOT_SUSPENDED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_THREAD_SUSPENDED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_THREAD_NOT_ALIVE) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_OBJECT) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_CLASS) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_CLASS_NOT_PREPARED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_METHODID) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_LOCATION) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_FIELDID) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_NO_MORE_FRAMES) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_OPAQUE_FRAME) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_TYPE_MISMATCH) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_SLOT) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_DUPLICATE) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_NOT_FOUND) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_MONITOR) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_NOT_MONITOR_OWNER) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INTERRUPT) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_CLASS_FORMAT) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_FAILS_VERIFICATION) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_TYPESTATE) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNSUPPORTED_VERSION) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_NAMES_DONT_MATCH) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNSUPPORTED_OPERATION) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_NOT_AVAILABLE) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_MUST_POSSESS_CAPABILITY) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_NULL_POINTER) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_ABSENT_INFORMATION) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_EVENT_TYPE) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_ILLEGAL_ARGUMENT) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_OUT_OF_MEMORY) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_ACCESS_DENIED) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_WRONG_PHASE) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INTERNAL) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_UNATTACHED_THREAD) | |
| CASE_RETURN_TEXT(JVMTI_ERROR_INVALID_ENVIRONMENT) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INTERNAL) | |
| CASE_RETURN_TEXT(AGENT_ERROR_VM_DEAD) | |
| CASE_RETURN_TEXT(AGENT_ERROR_NO_JNI_ENV) | |
| CASE_RETURN_TEXT(AGENT_ERROR_JNI_EXCEPTION) | |
| CASE_RETURN_TEXT(AGENT_ERROR_JVMTI_INTERNAL) | |
| CASE_RETURN_TEXT(AGENT_ERROR_JDWP_INTERNAL) | |
| CASE_RETURN_TEXT(AGENT_ERROR_NOT_CURRENT_FRAME) | |
| CASE_RETURN_TEXT(AGENT_ERROR_OUT_OF_MEMORY) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_TAG) | |
| CASE_RETURN_TEXT(AGENT_ERROR_ALREADY_INVOKING) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_INDEX) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_LENGTH) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_STRING) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_CLASS_LOADER) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_ARRAY) | |
| CASE_RETURN_TEXT(AGENT_ERROR_TRANSPORT_LOAD) | |
| CASE_RETURN_TEXT(AGENT_ERROR_TRANSPORT_INIT) | |
| CASE_RETURN_TEXT(AGENT_ERROR_NATIVE_METHOD) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_COUNT) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_FRAMEID) | |
| CASE_RETURN_TEXT(AGENT_ERROR_NULL_POINTER) | |
| CASE_RETURN_TEXT(AGENT_ERROR_ILLEGAL_ARGUMENT) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_THREAD) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_EVENT_TYPE) | |
| CASE_RETURN_TEXT(AGENT_ERROR_INVALID_OBJECT) | |
| CASE_RETURN_TEXT(AGENT_ERROR_NO_MORE_FRAMES) | |
| default: return "ERROR_unknown"; | |
| } | |
| } | |
| const char * | |
| eventText(int i) | |
| { | |
| switch ( i ) { | |
| CASE_RETURN_TEXT(EI_SINGLE_STEP) | |
| CASE_RETURN_TEXT(EI_BREAKPOINT) | |
| CASE_RETURN_TEXT(EI_FRAME_POP) | |
| CASE_RETURN_TEXT(EI_EXCEPTION) | |
| CASE_RETURN_TEXT(EI_THREAD_START) | |
| CASE_RETURN_TEXT(EI_THREAD_END) | |
| CASE_RETURN_TEXT(EI_CLASS_PREPARE) | |
| CASE_RETURN_TEXT(EI_CLASS_UNLOAD) | |
| CASE_RETURN_TEXT(EI_CLASS_LOAD) | |
| CASE_RETURN_TEXT(EI_FIELD_ACCESS) | |
| CASE_RETURN_TEXT(EI_FIELD_MODIFICATION) | |
| CASE_RETURN_TEXT(EI_EXCEPTION_CATCH) | |
| CASE_RETURN_TEXT(EI_METHOD_ENTRY) | |
| CASE_RETURN_TEXT(EI_METHOD_EXIT) | |
| CASE_RETURN_TEXT(EI_VM_INIT) | |
| CASE_RETURN_TEXT(EI_VM_DEATH) | |
| CASE_RETURN_TEXT(EI_VIRTUAL_THREAD_START) | |
| CASE_RETURN_TEXT(EI_VIRTUAL_THREAD_END) | |
| default: return "EVENT_unknown"; | |
| } | |
| } | |
| /* Macro for case on switch, returns string for name. */ | |
| #define CASE_RETURN_JDWP_ERROR_TEXT(name) case JDWP_ERROR(name): return #name; | |
| const char * | |
| jdwpErrorText(jdwpError serror) | |
| { | |
| switch ( serror ) { | |
| CASE_RETURN_JDWP_ERROR_TEXT(NONE) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_THREAD) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_THREAD_GROUP) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_PRIORITY) | |
| CASE_RETURN_JDWP_ERROR_TEXT(THREAD_NOT_SUSPENDED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(THREAD_SUSPENDED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_OBJECT) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_CLASS) | |
| CASE_RETURN_JDWP_ERROR_TEXT(CLASS_NOT_PREPARED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_METHODID) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_LOCATION) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_FIELDID) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_FRAMEID) | |
| CASE_RETURN_JDWP_ERROR_TEXT(NO_MORE_FRAMES) | |
| CASE_RETURN_JDWP_ERROR_TEXT(OPAQUE_FRAME) | |
| CASE_RETURN_JDWP_ERROR_TEXT(NOT_CURRENT_FRAME) | |
| CASE_RETURN_JDWP_ERROR_TEXT(TYPE_MISMATCH) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_SLOT) | |
| CASE_RETURN_JDWP_ERROR_TEXT(DUPLICATE) | |
| CASE_RETURN_JDWP_ERROR_TEXT(NOT_FOUND) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_MONITOR) | |
| CASE_RETURN_JDWP_ERROR_TEXT(NOT_MONITOR_OWNER) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INTERRUPT) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_CLASS_FORMAT) | |
| CASE_RETURN_JDWP_ERROR_TEXT(CIRCULAR_CLASS_DEFINITION) | |
| CASE_RETURN_JDWP_ERROR_TEXT(FAILS_VERIFICATION) | |
| CASE_RETURN_JDWP_ERROR_TEXT(ADD_METHOD_NOT_IMPLEMENTED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(SCHEMA_CHANGE_NOT_IMPLEMENTED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_TYPESTATE) | |
| CASE_RETURN_JDWP_ERROR_TEXT(HIERARCHY_CHANGE_NOT_IMPLEMENTED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(DELETE_METHOD_NOT_IMPLEMENTED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(UNSUPPORTED_VERSION) | |
| CASE_RETURN_JDWP_ERROR_TEXT(NAMES_DONT_MATCH) | |
| CASE_RETURN_JDWP_ERROR_TEXT(CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(CLASS_ATTRIBUTE_CHANGE_NOT_IMPLEMENTED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(NOT_IMPLEMENTED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(NULL_POINTER) | |
| CASE_RETURN_JDWP_ERROR_TEXT(ABSENT_INFORMATION) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_EVENT_TYPE) | |
| CASE_RETURN_JDWP_ERROR_TEXT(ILLEGAL_ARGUMENT) | |
| CASE_RETURN_JDWP_ERROR_TEXT(OUT_OF_MEMORY) | |
| CASE_RETURN_JDWP_ERROR_TEXT(ACCESS_DENIED) | |
| CASE_RETURN_JDWP_ERROR_TEXT(VM_DEAD) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INTERNAL) | |
| CASE_RETURN_JDWP_ERROR_TEXT(UNATTACHED_THREAD) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_TAG) | |
| CASE_RETURN_JDWP_ERROR_TEXT(ALREADY_INVOKING) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_INDEX) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_LENGTH) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_STRING) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_CLASS_LOADER) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_ARRAY) | |
| CASE_RETURN_JDWP_ERROR_TEXT(TRANSPORT_LOAD) | |
| CASE_RETURN_JDWP_ERROR_TEXT(TRANSPORT_INIT) | |
| CASE_RETURN_JDWP_ERROR_TEXT(NATIVE_METHOD) | |
| CASE_RETURN_JDWP_ERROR_TEXT(INVALID_COUNT) | |
| default: return "JDWP_ERROR_unknown"; | |
| } | |
| } | |
| static int p = 1; | |
| void | |
| do_pause(void) | |
| { | |
| THREAD_T tid = GET_THREAD_ID(); | |
| PID_T pid = GETPID(); | |
| int timeleft = 600; /* 10 minutes max */ | |
| int interval = 10; /* 10 second message check */ | |
| /*LINTED*/ | |
| tty_message("DEBUGGING: JDWP pause for PID %d, THREAD %d (0x%x)", | |
| /*LINTED*/ | |
| (int)(intptr_t)pid, (int)(intptr_t)tid, (int)(intptr_t)tid); | |
| while ( p && timeleft > 0 ) { | |
| (void)sleep(interval); /* 'assign p = 0;' to get out of loop */ | |
| timeleft -= interval; | |
| } | |
| if ( timeleft <= 0 ) { | |
| tty_message("DEBUGGING: JDWP pause got tired of waiting and gave up."); | |
| } | |
| } |