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