blob: c705ecfd9fbf265667bb21f8639e5227853687bd [file] [log] [blame]
/*
* 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 */