0N/A/*
1879N/A * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1472N/A * or visit www.oracle.com if you need additional information or have any
1472N/A * questions.
0N/A *
0N/A */
0N/A
1879N/A#include "precompiled.hpp"
1879N/A#include "jvmtifiles/jvmtiEnv.hpp"
1879N/A#include "prims/jvmtiTrace.hpp"
0N/A
0N/A//
0N/A// class JvmtiTrace
0N/A//
0N/A// Support for JVMTI tracing code
0N/A//
0N/A// ------------
0N/A// Usage:
0N/A// -XX:TraceJVMTI=DESC,DESC,DESC
0N/A//
0N/A// DESC is DOMAIN ACTION KIND
0N/A//
0N/A// DOMAIN is function name
0N/A// event name
0N/A// "all" (all functions and events)
0N/A// "func" (all functions except boring)
0N/A// "allfunc" (all functions)
0N/A// "event" (all events)
0N/A// "ec" (event controller)
0N/A//
0N/A// ACTION is "+" (add)
0N/A// "-" (remove)
0N/A//
0N/A// KIND is
0N/A// for func
0N/A// "i" (input params)
0N/A// "e" (error returns)
0N/A// "o" (output)
0N/A// for event
0N/A// "t" (event triggered aka posted)
0N/A// "s" (event sent)
0N/A//
0N/A// Example:
0N/A// -XX:TraceJVMTI=ec+,GetCallerFrame+ie,Breakpoint+s
0N/A
0N/A#ifdef JVMTI_TRACE
0N/A
0N/Abool JvmtiTrace::_initialized = false;
0N/Abool JvmtiTrace::_on = false;
0N/Abool JvmtiTrace::_trace_event_controller = false;
0N/A
0N/Avoid JvmtiTrace::initialize() {
0N/A if (_initialized) {
0N/A return;
0N/A }
0N/A SafeResourceMark rm;
0N/A
0N/A const char *very_end;
0N/A const char *curr;
370N/A if (TraceJVMTI != NULL) {
0N/A curr = TraceJVMTI;
0N/A } else {
0N/A curr = ""; // hack in fixed tracing here
0N/A }
0N/A very_end = curr + strlen(curr);
0N/A while (curr < very_end) {
0N/A const char *curr_end = strchr(curr, ',');
0N/A if (curr_end == NULL) {
0N/A curr_end = very_end;
0N/A }
0N/A const char *op_pos = strchr(curr, '+');
0N/A const char *minus_pos = strchr(curr, '-');
0N/A if (minus_pos != NULL && (minus_pos < op_pos || op_pos == NULL)) {
0N/A op_pos = minus_pos;
0N/A }
0N/A char op;
0N/A const char *flags = op_pos + 1;
0N/A const char *flags_end = curr_end;
0N/A if (op_pos == NULL || op_pos > curr_end) {
0N/A flags = "ies";
0N/A flags_end = flags + strlen(flags);
0N/A op_pos = curr_end;
0N/A op = '+';
0N/A } else {
0N/A op = *op_pos;
0N/A }
0N/A jbyte bits = 0;
0N/A for (; flags < flags_end; ++flags) {
0N/A switch (*flags) {
0N/A case 'i':
0N/A bits |= SHOW_IN;
0N/A break;
0N/A case 'I':
0N/A bits |= SHOW_IN_DETAIL;
0N/A break;
0N/A case 'e':
0N/A bits |= SHOW_ERROR;
0N/A break;
0N/A case 'o':
0N/A bits |= SHOW_OUT;
0N/A break;
0N/A case 'O':
0N/A bits |= SHOW_OUT_DETAIL;
0N/A break;
0N/A case 't':
0N/A bits |= SHOW_EVENT_TRIGGER;
0N/A break;
0N/A case 's':
0N/A bits |= SHOW_EVENT_SENT;
0N/A break;
0N/A default:
0N/A tty->print_cr("Invalid trace flag '%c'", *flags);
0N/A break;
0N/A }
0N/A }
0N/A const int FUNC = 1;
0N/A const int EXCLUDE = 2;
0N/A const int ALL_FUNC = 4;
0N/A const int EVENT = 8;
0N/A const int ALL_EVENT = 16;
0N/A int domain = 0;
0N/A size_t len = op_pos - curr;
0N/A if (op_pos == curr) {
0N/A domain = ALL_FUNC | FUNC | ALL_EVENT | EVENT | EXCLUDE;
0N/A } else if (len==3 && strncmp(curr, "all", 3)==0) {
0N/A domain = ALL_FUNC | FUNC | ALL_EVENT | EVENT;
0N/A } else if (len==7 && strncmp(curr, "allfunc", 7)==0) {
0N/A domain = ALL_FUNC | FUNC;
0N/A } else if (len==4 && strncmp(curr, "func", 4)==0) {
0N/A domain = ALL_FUNC | FUNC | EXCLUDE;
0N/A } else if (len==8 && strncmp(curr, "allevent", 8)==0) {
0N/A domain = ALL_EVENT | EVENT;
0N/A } else if (len==5 && strncmp(curr, "event", 5)==0) {
0N/A domain = ALL_EVENT | EVENT;
0N/A } else if (len==2 && strncmp(curr, "ec", 2)==0) {
0N/A _trace_event_controller = true;
0N/A tty->print_cr("JVMTI Tracing the event controller");
0N/A } else {
0N/A domain = FUNC | EVENT; // go searching
0N/A }
0N/A
0N/A int exclude_index = 0;
0N/A if (domain & FUNC) {
0N/A if (domain & ALL_FUNC) {
0N/A if (domain & EXCLUDE) {
0N/A tty->print("JVMTI Tracing all significant functions");
0N/A } else {
0N/A tty->print_cr("JVMTI Tracing all functions");
0N/A }
0N/A }
0N/A for (int i = 0; i <= _max_function_index; ++i) {
0N/A if (domain & EXCLUDE && i == _exclude_functions[exclude_index]) {
0N/A ++exclude_index;
0N/A } else {
0N/A bool do_op = false;
0N/A if (domain & ALL_FUNC) {
0N/A do_op = true;
0N/A } else {
0N/A const char *fname = function_name(i);
0N/A if (fname != NULL) {
0N/A size_t fnlen = strlen(fname);
0N/A if (len==fnlen && strncmp(curr, fname, fnlen)==0) {
0N/A tty->print_cr("JVMTI Tracing the function: %s", fname);
0N/A do_op = true;
0N/A }
0N/A }
0N/A }
0N/A if (do_op) {
0N/A if (op == '+') {
0N/A _trace_flags[i] |= bits;
0N/A } else {
0N/A _trace_flags[i] &= ~bits;
0N/A }
0N/A _on = true;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A if (domain & EVENT) {
0N/A if (domain & ALL_EVENT) {
0N/A tty->print_cr("JVMTI Tracing all events");
0N/A }
0N/A for (int i = 0; i <= _max_event_index; ++i) {
0N/A bool do_op = false;
0N/A if (domain & ALL_EVENT) {
0N/A do_op = true;
0N/A } else {
0N/A const char *ename = event_name(i);
0N/A if (ename != NULL) {
0N/A size_t evtlen = strlen(ename);
0N/A if (len==evtlen && strncmp(curr, ename, evtlen)==0) {
0N/A tty->print_cr("JVMTI Tracing the event: %s", ename);
0N/A do_op = true;
0N/A }
0N/A }
0N/A }
0N/A if (do_op) {
0N/A if (op == '+') {
0N/A _event_trace_flags[i] |= bits;
0N/A } else {
0N/A _event_trace_flags[i] &= ~bits;
0N/A }
0N/A _on = true;
0N/A }
0N/A }
0N/A }
0N/A if (!_on && (domain & (FUNC|EVENT))) {
0N/A tty->print_cr("JVMTI Trace domain not found");
0N/A }
0N/A curr = curr_end + 1;
0N/A }
0N/A _initialized = true;
0N/A}
0N/A
0N/A
0N/Avoid JvmtiTrace::shutdown() {
0N/A int i;
0N/A _on = false;
0N/A _trace_event_controller = false;
0N/A for (i = 0; i <= _max_function_index; ++i) {
0N/A _trace_flags[i] = 0;
0N/A }
0N/A for (i = 0; i <= _max_event_index; ++i) {
0N/A _event_trace_flags[i] = 0;
0N/A }
0N/A}
0N/A
0N/A
0N/Aconst char* JvmtiTrace::enum_name(const char** names, const jint* values, jint value) {
0N/A for (int index = 0; names[index] != 0; ++index) {
0N/A if (values[index] == value) {
0N/A return names[index];
0N/A }
0N/A }
0N/A return "*INVALID-ENUM-VALUE*";
0N/A}
0N/A
0N/A
0N/A// return a valid string no matter what state the thread is in
0N/Aconst char *JvmtiTrace::safe_get_thread_name(Thread *thread) {
0N/A if (thread == NULL) {
0N/A return "NULL";
0N/A }
0N/A if (!thread->is_Java_thread()) {
0N/A return thread->name();
0N/A }
0N/A JavaThread *java_thread = (JavaThread *)thread;
0N/A oop threadObj = java_thread->threadObj();
0N/A if (threadObj == NULL) {
0N/A return "NULL";
0N/A }
0N/A typeArrayOop name = java_lang_Thread::name(threadObj);
0N/A if (name == NULL) {
0N/A return "<NOT FILLED IN>";
0N/A }
0N/A return UNICODE::as_utf8((jchar*) name->base(T_CHAR), name->length());
0N/A}
0N/A
0N/A
0N/A// return the name of the current thread
0N/Aconst char *JvmtiTrace::safe_get_current_thread_name() {
0N/A if (JvmtiEnv::is_vm_live()) {
0N/A return JvmtiTrace::safe_get_thread_name(Thread::current());
0N/A } else {
0N/A return "VM not live";
0N/A }
0N/A}
0N/A
0N/A// return a valid string no matter what the state of k_mirror
0N/Aconst char * JvmtiTrace::get_class_name(oop k_mirror) {
0N/A if (java_lang_Class::is_primitive(k_mirror)) {
0N/A return "primitive";
0N/A }
0N/A klassOop k_oop = java_lang_Class::as_klassOop(k_mirror);
0N/A if (k_oop == NULL) {
0N/A return "INVALID";
0N/A }
0N/A return Klass::cast(k_oop)->external_name();
0N/A}
0N/A
0N/A#endif /*JVMTI_TRACE */