1/* 2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25#include "precompiled.hpp" 26#include "jvmtifiles/jvmtiEnv.hpp" 27#include "logging/log.hpp" 28#include "logging/logConfiguration.hpp" 29#include "memory/resourceArea.hpp" 30#include "prims/jvmtiTrace.hpp" 31 32// 33// class JvmtiTrace 34// 35// Support for JVMTI tracing code 36// 37// ------------ 38// Usage: 39// -XX:TraceJVMTI=DESC,DESC,DESC 40// 41// DESC is DOMAIN ACTION KIND 42// 43// DOMAIN is function name 44// event name 45// "all" (all functions and events) 46// "func" (all functions except boring) 47// "allfunc" (all functions) 48// "event" (all events) 49// "ec" (event controller) 50// 51// ACTION is "+" (add) 52// "-" (remove) 53// 54// KIND is 55// for func 56// "i" (input params) 57// "e" (error returns) 58// "o" (output) 59// for event 60// "t" (event triggered aka posted) 61// "s" (event sent) 62// 63// Example: 64// -XX:TraceJVMTI=ec+,GetCallerFrame+ie,Breakpoint+s 65 66#ifdef JVMTI_TRACE 67 68bool JvmtiTrace::_initialized = false; 69bool JvmtiTrace::_on = false; 70bool JvmtiTrace::_trace_event_controller = false; 71 72void JvmtiTrace::initialize() { 73 if (_initialized) { 74 return; 75 } 76 SafeResourceMark rm; 77 78 const char *very_end; 79 const char *curr; 80 if (TraceJVMTI != NULL) { 81 curr = TraceJVMTI; 82 } else { 83 curr = ""; // hack in fixed tracing here 84 } 85 86 // Enable UL for JVMTI tracing 87 if (strlen(curr) > 0) { 88 if (!log_is_enabled(Trace, jvmti)) { 89 log_warning(arguments)("-XX:+TraceJVMTI specified, " 90 "but no log output configured for the 'jvmti' tag on Trace level. " 91 "Defaulting to -Xlog:jvmti=trace"); 92 LogConfiguration::configure_stdout(LogLevel::Trace, true, LOG_TAGS(jvmti)); 93 } 94 } 95 96 very_end = curr + strlen(curr); 97 while (curr < very_end) { 98 const char *curr_end = strchr(curr, ','); 99 if (curr_end == NULL) { 100 curr_end = very_end; 101 } 102 const char *op_pos = strchr(curr, '+'); 103 const char *minus_pos = strchr(curr, '-'); 104 if (minus_pos != NULL && (minus_pos < op_pos || op_pos == NULL)) { 105 op_pos = minus_pos; 106 } 107 char op; 108 const char *flags = op_pos + 1; 109 const char *flags_end = curr_end; 110 if (op_pos == NULL || op_pos > curr_end) { 111 flags = "ies"; 112 flags_end = flags + strlen(flags); 113 op_pos = curr_end; 114 op = '+'; 115 } else { 116 op = *op_pos; 117 } 118 jbyte bits = 0; 119 for (; flags < flags_end; ++flags) { 120 switch (*flags) { 121 case 'i': 122 bits |= SHOW_IN; 123 break; 124 case 'I': 125 bits |= SHOW_IN_DETAIL; 126 break; 127 case 'e': 128 bits |= SHOW_ERROR; 129 break; 130 case 'o': 131 bits |= SHOW_OUT; 132 break; 133 case 'O': 134 bits |= SHOW_OUT_DETAIL; 135 break; 136 case 't': 137 bits |= SHOW_EVENT_TRIGGER; 138 break; 139 case 's': 140 bits |= SHOW_EVENT_SENT; 141 break; 142 default: 143 log_warning(jvmti)("Invalid trace flag '%c'", *flags); 144 break; 145 } 146 } 147 const int FUNC = 1; 148 const int EXCLUDE = 2; 149 const int ALL_FUNC = 4; 150 const int EVENT = 8; 151 const int ALL_EVENT = 16; 152 int domain = 0; 153 size_t len = op_pos - curr; 154 if (op_pos == curr) { 155 domain = ALL_FUNC | FUNC | ALL_EVENT | EVENT | EXCLUDE; 156 } else if (len==3 && strncmp(curr, "all", 3)==0) { 157 domain = ALL_FUNC | FUNC | ALL_EVENT | EVENT; 158 } else if (len==7 && strncmp(curr, "allfunc", 7)==0) { 159 domain = ALL_FUNC | FUNC; 160 } else if (len==4 && strncmp(curr, "func", 4)==0) { 161 domain = ALL_FUNC | FUNC | EXCLUDE; 162 } else if (len==8 && strncmp(curr, "allevent", 8)==0) { 163 domain = ALL_EVENT | EVENT; 164 } else if (len==5 && strncmp(curr, "event", 5)==0) { 165 domain = ALL_EVENT | EVENT; 166 } else if (len==2 && strncmp(curr, "ec", 2)==0) { 167 _trace_event_controller = true; 168 log_trace(jvmti)("Tracing the event controller"); 169 } else { 170 domain = FUNC | EVENT; // go searching 171 } 172 173 int exclude_index = 0; 174 if (domain & FUNC) { 175 if (domain & ALL_FUNC) { 176 if (domain & EXCLUDE) { 177 log_trace(jvmti)("Tracing all significant functions"); 178 } else { 179 log_trace(jvmti)("Tracing all functions"); 180 } 181 } 182 for (int i = 0; i <= _max_function_index; ++i) { 183 if (domain & EXCLUDE && i == _exclude_functions[exclude_index]) { 184 ++exclude_index; 185 } else { 186 bool do_op = false; 187 if (domain & ALL_FUNC) { 188 do_op = true; 189 } else { 190 const char *fname = function_name(i); 191 if (fname != NULL) { 192 size_t fnlen = strlen(fname); 193 if (len==fnlen && strncmp(curr, fname, fnlen)==0) { 194 log_trace(jvmti)("Tracing the function: %s", fname); 195 do_op = true; 196 } 197 } 198 } 199 if (do_op) { 200 if (op == '+') { 201 _trace_flags[i] |= bits; 202 } else { 203 _trace_flags[i] &= ~bits; 204 } 205 _on = true; 206 } 207 } 208 } 209 } 210 if (domain & EVENT) { 211 if (domain & ALL_EVENT) { 212 log_trace(jvmti)("Tracing all events"); 213 } 214 for (int i = 0; i <= _max_event_index; ++i) { 215 bool do_op = false; 216 if (domain & ALL_EVENT) { 217 do_op = true; 218 } else { 219 const char *ename = event_name(i); 220 if (ename != NULL) { 221 size_t evtlen = strlen(ename); 222 if (len==evtlen && strncmp(curr, ename, evtlen)==0) { 223 log_trace(jvmti)("Tracing the event: %s", ename); 224 do_op = true; 225 } 226 } 227 } 228 if (do_op) { 229 if (op == '+') { 230 _event_trace_flags[i] |= bits; 231 } else { 232 _event_trace_flags[i] &= ~bits; 233 } 234 _on = true; 235 } 236 } 237 } 238 if (!_on && (domain & (FUNC|EVENT))) { 239 log_warning(jvmti)("Trace domain not found"); 240 } 241 curr = curr_end + 1; 242 } 243 _initialized = true; 244} 245 246 247void JvmtiTrace::shutdown() { 248 int i; 249 _on = false; 250 _trace_event_controller = false; 251 for (i = 0; i <= _max_function_index; ++i) { 252 _trace_flags[i] = 0; 253 } 254 for (i = 0; i <= _max_event_index; ++i) { 255 _event_trace_flags[i] = 0; 256 } 257} 258 259 260const char* JvmtiTrace::enum_name(const char** names, const jint* values, jint value) { 261 for (int index = 0; names[index] != 0; ++index) { 262 if (values[index] == value) { 263 return names[index]; 264 } 265 } 266 return "*INVALID-ENUM-VALUE*"; 267} 268 269 270// return a valid string no matter what state the thread is in 271const char *JvmtiTrace::safe_get_thread_name(Thread *thread) { 272 if (thread == NULL) { 273 return "NULL"; 274 } 275 if (!thread->is_Java_thread()) { 276 return thread->name(); 277 } 278 JavaThread *java_thread = (JavaThread *)thread; 279 oop threadObj = java_thread->threadObj(); 280 if (threadObj == NULL) { 281 return "NULL"; 282 } 283 oop name = java_lang_Thread::name(threadObj); 284 if (name == NULL) { 285 return "<NOT FILLED IN>"; 286 } 287 return java_lang_String::as_utf8_string(name); 288} 289 290 291// return the name of the current thread 292const char *JvmtiTrace::safe_get_current_thread_name() { 293 if (JvmtiEnv::is_vm_live()) { 294 return JvmtiTrace::safe_get_thread_name(Thread::current()); 295 } else { 296 return "VM not live"; 297 } 298} 299 300// return a valid string no matter what the state of k_mirror 301const char * JvmtiTrace::get_class_name(oop k_mirror) { 302 if (java_lang_Class::is_primitive(k_mirror)) { 303 return "primitive"; 304 } 305 Klass* k_oop = java_lang_Class::as_Klass(k_mirror); 306 if (k_oop == NULL) { 307 return "INVALID"; 308 } 309 return k_oop->external_name(); 310} 311 312#endif /*JVMTI_TRACE */ 313