| /* |
| * Copyright (c) 2003, 2016, 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 "precompiled.hpp" |
| #include "jvmtifiles/jvmtiEnv.hpp" |
| #include "prims/jvmtiTrace.hpp" |
| |
| // |
| // class JvmtiTrace |
| // |
| // Support for JVMTI tracing code |
| // |
| // ------------ |
| // Usage: |
| // -XX:TraceJVMTI=DESC,DESC,DESC |
| // |
| // DESC is DOMAIN ACTION KIND |
| // |
| // DOMAIN is function name |
| // event name |
| // "all" (all functions and events) |
| // "func" (all functions except boring) |
| // "allfunc" (all functions) |
| // "event" (all events) |
| // "ec" (event controller) |
| // |
| // ACTION is "+" (add) |
| // "-" (remove) |
| // |
| // KIND is |
| // for func |
| // "i" (input params) |
| // "e" (error returns) |
| // "o" (output) |
| // for event |
| // "t" (event triggered aka posted) |
| // "s" (event sent) |
| // |
| // Example: |
| // -XX:TraceJVMTI=ec+,GetCallerFrame+ie,Breakpoint+s |
| |
| #ifdef JVMTI_TRACE |
| |
| bool JvmtiTrace::_initialized = false; |
| bool JvmtiTrace::_on = false; |
| bool JvmtiTrace::_trace_event_controller = false; |
| |
| void JvmtiTrace::initialize() { |
| if (_initialized) { |
| return; |
| } |
| SafeResourceMark rm; |
| |
| const char *very_end; |
| const char *curr; |
| if (TraceJVMTI != NULL) { |
| curr = TraceJVMTI; |
| } else { |
| curr = ""; // hack in fixed tracing here |
| } |
| very_end = curr + strlen(curr); |
| while (curr < very_end) { |
| const char *curr_end = strchr(curr, ','); |
| if (curr_end == NULL) { |
| curr_end = very_end; |
| } |
| const char *op_pos = strchr(curr, '+'); |
| const char *minus_pos = strchr(curr, '-'); |
| if (minus_pos != NULL && (minus_pos < op_pos || op_pos == NULL)) { |
| op_pos = minus_pos; |
| } |
| char op; |
| const char *flags = op_pos + 1; |
| const char *flags_end = curr_end; |
| if (op_pos == NULL || op_pos > curr_end) { |
| flags = "ies"; |
| flags_end = flags + strlen(flags); |
| op_pos = curr_end; |
| op = '+'; |
| } else { |
| op = *op_pos; |
| } |
| jbyte bits = 0; |
| for (; flags < flags_end; ++flags) { |
| switch (*flags) { |
| case 'i': |
| bits |= SHOW_IN; |
| break; |
| case 'I': |
| bits |= SHOW_IN_DETAIL; |
| break; |
| case 'e': |
| bits |= SHOW_ERROR; |
| break; |
| case 'o': |
| bits |= SHOW_OUT; |
| break; |
| case 'O': |
| bits |= SHOW_OUT_DETAIL; |
| break; |
| case 't': |
| bits |= SHOW_EVENT_TRIGGER; |
| break; |
| case 's': |
| bits |= SHOW_EVENT_SENT; |
| break; |
| default: |
| tty->print_cr("Invalid trace flag '%c'", *flags); |
| break; |
| } |
| } |
| const int FUNC = 1; |
| const int EXCLUDE = 2; |
| const int ALL_FUNC = 4; |
| const int EVENT = 8; |
| const int ALL_EVENT = 16; |
| int domain = 0; |
| size_t len = op_pos - curr; |
| if (op_pos == curr) { |
| domain = ALL_FUNC | FUNC | ALL_EVENT | EVENT | EXCLUDE; |
| } else if (len==3 && strncmp(curr, "all", 3)==0) { |
| domain = ALL_FUNC | FUNC | ALL_EVENT | EVENT; |
| } else if (len==7 && strncmp(curr, "allfunc", 7)==0) { |
| domain = ALL_FUNC | FUNC; |
| } else if (len==4 && strncmp(curr, "func", 4)==0) { |
| domain = ALL_FUNC | FUNC | EXCLUDE; |
| } else if (len==8 && strncmp(curr, "allevent", 8)==0) { |
| domain = ALL_EVENT | EVENT; |
| } else if (len==5 && strncmp(curr, "event", 5)==0) { |
| domain = ALL_EVENT | EVENT; |
| } else if (len==2 && strncmp(curr, "ec", 2)==0) { |
| _trace_event_controller = true; |
| tty->print_cr("JVMTI Tracing the event controller"); |
| } else { |
| domain = FUNC | EVENT; // go searching |
| } |
| |
| int exclude_index = 0; |
| if (domain & FUNC) { |
| if (domain & ALL_FUNC) { |
| if (domain & EXCLUDE) { |
| tty->print("JVMTI Tracing all significant functions"); |
| } else { |
| tty->print_cr("JVMTI Tracing all functions"); |
| } |
| } |
| for (int i = 0; i <= _max_function_index; ++i) { |
| if (domain & EXCLUDE && i == _exclude_functions[exclude_index]) { |
| ++exclude_index; |
| } else { |
| bool do_op = false; |
| if (domain & ALL_FUNC) { |
| do_op = true; |
| } else { |
| const char *fname = function_name(i); |
| if (fname != NULL) { |
| size_t fnlen = strlen(fname); |
| if (len==fnlen && strncmp(curr, fname, fnlen)==0) { |
| tty->print_cr("JVMTI Tracing the function: %s", fname); |
| do_op = true; |
| } |
| } |
| } |
| if (do_op) { |
| if (op == '+') { |
| _trace_flags[i] |= bits; |
| } else { |
| _trace_flags[i] &= ~bits; |
| } |
| _on = true; |
| } |
| } |
| } |
| } |
| if (domain & EVENT) { |
| if (domain & ALL_EVENT) { |
| tty->print_cr("JVMTI Tracing all events"); |
| } |
| for (int i = 0; i <= _max_event_index; ++i) { |
| bool do_op = false; |
| if (domain & ALL_EVENT) { |
| do_op = true; |
| } else { |
| const char *ename = event_name(i); |
| if (ename != NULL) { |
| size_t evtlen = strlen(ename); |
| if (len==evtlen && strncmp(curr, ename, evtlen)==0) { |
| tty->print_cr("JVMTI Tracing the event: %s", ename); |
| do_op = true; |
| } |
| } |
| } |
| if (do_op) { |
| if (op == '+') { |
| _event_trace_flags[i] |= bits; |
| } else { |
| _event_trace_flags[i] &= ~bits; |
| } |
| _on = true; |
| } |
| } |
| } |
| if (!_on && (domain & (FUNC|EVENT))) { |
| tty->print_cr("JVMTI Trace domain not found"); |
| } |
| curr = curr_end + 1; |
| } |
| _initialized = true; |
| } |
| |
| |
| void JvmtiTrace::shutdown() { |
| int i; |
| _on = false; |
| _trace_event_controller = false; |
| for (i = 0; i <= _max_function_index; ++i) { |
| _trace_flags[i] = 0; |
| } |
| for (i = 0; i <= _max_event_index; ++i) { |
| _event_trace_flags[i] = 0; |
| } |
| } |
| |
| |
| const char* JvmtiTrace::enum_name(const char** names, const jint* values, jint value) { |
| for (int index = 0; names[index] != 0; ++index) { |
| if (values[index] == value) { |
| return names[index]; |
| } |
| } |
| return "*INVALID-ENUM-VALUE*"; |
| } |
| |
| |
| // return a valid string no matter what state the thread is in |
| const char *JvmtiTrace::safe_get_thread_name(Thread *thread) { |
| if (thread == NULL) { |
| return "NULL"; |
| } |
| if (!thread->is_Java_thread()) { |
| return thread->name(); |
| } |
| JavaThread *java_thread = (JavaThread *)thread; |
| oop threadObj = java_thread->threadObj(); |
| if (threadObj == NULL) { |
| return "NULL"; |
| } |
| oop name = java_lang_Thread::name(threadObj); |
| if (name == NULL) { |
| return "<NOT FILLED IN>"; |
| } |
| return java_lang_String::as_utf8_string(name); |
| } |
| |
| |
| // return the name of the current thread |
| const char *JvmtiTrace::safe_get_current_thread_name() { |
| if (JvmtiEnv::is_vm_live()) { |
| return JvmtiTrace::safe_get_thread_name(Thread::current()); |
| } else { |
| return "VM not live"; |
| } |
| } |
| |
| // return a valid string no matter what the state of k_mirror |
| const char * JvmtiTrace::get_class_name(oop k_mirror) { |
| if (java_lang_Class::is_primitive(k_mirror)) { |
| return "primitive"; |
| } |
| Klass* k_oop = java_lang_Class::as_Klass(k_mirror); |
| if (k_oop == NULL) { |
| return "INVALID"; |
| } |
| return k_oop->external_name(); |
| } |
| |
| #endif /*JVMTI_TRACE */ |