1 /* 2 * Copyright (c) 2003, 2014, 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 "prims/jvmtiTrace.hpp" 28 29 // 30 // class JvmtiTrace 31 // 32 // Support for JVMTI tracing code 33 // 34 // ------------ 35 // Usage: 36 // -XX:TraceJVMTI=DESC,DESC,DESC 37 // 38 // DESC is DOMAIN ACTION KIND 39 // 40 // DOMAIN is function name 41 // event name 42 // "all" (all functions and events) 43 // "func" (all functions except boring) 44 // "allfunc" (all functions) 45 // "event" (all events) 46 // "ec" (event controller) 47 // 48 // ACTION is "+" (add) 49 // "-" (remove) 50 // 51 // KIND is 52 // for func 53 // "i" (input params) 54 // "e" (error returns) 55 // "o" (output) 56 // for event 57 // "t" (event triggered aka posted) 58 // "s" (event sent) 59 // 60 // Example: 61 // -XX:TraceJVMTI=ec+,GetCallerFrame+ie,Breakpoint+s 62 63 #ifdef JVMTI_TRACE 64 65 bool JvmtiTrace::_initialized = false; 66 bool JvmtiTrace::_on = false; 67 bool JvmtiTrace::_trace_event_controller = false; 68 69 void JvmtiTrace::initialize() { 70 if (_initialized) { 71 return; 72 } 73 SafeResourceMark rm; 74 75 const char *very_end; 76 const char *curr; 77 if (TraceJVMTI != NULL) { 78 curr = TraceJVMTI; 79 } else { 80 curr = ""; // hack in fixed tracing here 81 } 82 very_end = curr + strlen(curr); 83 while (curr < very_end) { 84 const char *curr_end = strchr(curr, ','); 85 if (curr_end == NULL) { 86 curr_end = very_end; 87 } 88 const char *op_pos = strchr(curr, '+'); 89 const char *minus_pos = strchr(curr, '-'); 90 if (minus_pos != NULL && (minus_pos < op_pos || op_pos == NULL)) { 91 op_pos = minus_pos; 92 } 93 char op; 94 const char *flags = op_pos + 1; 95 const char *flags_end = curr_end; 96 if (op_pos == NULL || op_pos > curr_end) { 97 flags = "ies"; 98 flags_end = flags + strlen(flags); 99 op_pos = curr_end; 100 op = '+'; 101 } else { 102 op = *op_pos; 103 } 104 jbyte bits = 0; 105 for (; flags < flags_end; ++flags) { 106 switch (*flags) { 107 case 'i': 108 bits |= SHOW_IN; 109 break; 110 case 'I': 111 bits |= SHOW_IN_DETAIL; 112 break; 113 case 'e': 114 bits |= SHOW_ERROR; 115 break; 116 case 'o': 117 bits |= SHOW_OUT; 118 break; 119 case 'O': 120 bits |= SHOW_OUT_DETAIL; 121 break; 122 case 't': 123 bits |= SHOW_EVENT_TRIGGER; 124 break; 125 case 's': 126 bits |= SHOW_EVENT_SENT; 127 break; 128 default: 129 tty->print_cr("Invalid trace flag '%c'", *flags); 130 break; 131 } 132 } 133 const int FUNC = 1; 134 const int EXCLUDE = 2; 135 const int ALL_FUNC = 4; 136 const int EVENT = 8; 137 const int ALL_EVENT = 16; 138 int domain = 0; 139 size_t len = op_pos - curr; 140 if (op_pos == curr) { 141 domain = ALL_FUNC | FUNC | ALL_EVENT | EVENT | EXCLUDE; 142 } else if (len==3 && strncmp(curr, "all", 3)==0) { 143 domain = ALL_FUNC | FUNC | ALL_EVENT | EVENT; 144 } else if (len==7 && strncmp(curr, "allfunc", 7)==0) { 145 domain = ALL_FUNC | FUNC; 146 } else if (len==4 && strncmp(curr, "func", 4)==0) { 147 domain = ALL_FUNC | FUNC | EXCLUDE; 148 } else if (len==8 && strncmp(curr, "allevent", 8)==0) { 149 domain = ALL_EVENT | EVENT; 150 } else if (len==5 && strncmp(curr, "event", 5)==0) { 151 domain = ALL_EVENT | EVENT; 152 } else if (len==2 && strncmp(curr, "ec", 2)==0) { 153 _trace_event_controller = true; 154 tty->print_cr("JVMTI Tracing the event controller"); 155 } else { 156 domain = FUNC | EVENT; // go searching 157 } 158 159 int exclude_index = 0; 160 if (domain & FUNC) { 161 if (domain & ALL_FUNC) { 162 if (domain & EXCLUDE) { 163 tty->print("JVMTI Tracing all significant functions"); 164 } else { 165 tty->print_cr("JVMTI Tracing all functions"); 166 } 167 } 168 for (int i = 0; i <= _max_function_index; ++i) { 169 if (domain & EXCLUDE && i == _exclude_functions[exclude_index]) { 170 ++exclude_index; 171 } else { 172 bool do_op = false; 173 if (domain & ALL_FUNC) { 174 do_op = true; 175 } else { 176 const char *fname = function_name(i); 177 if (fname != NULL) { 178 size_t fnlen = strlen(fname); 179 if (len==fnlen && strncmp(curr, fname, fnlen)==0) { 180 tty->print_cr("JVMTI Tracing the function: %s", fname); 181 do_op = true; 182 } 183 } 184 } 185 if (do_op) { 186 if (op == '+') { 187 _trace_flags[i] |= bits; 188 } else { 189 _trace_flags[i] &= ~bits; 190 } 191 _on = true; 192 } 193 } 194 } 195 } 196 if (domain & EVENT) { 197 if (domain & ALL_EVENT) { 198 tty->print_cr("JVMTI Tracing all events"); 199 } 200 for (int i = 0; i <= _max_event_index; ++i) { 201 bool do_op = false; 202 if (domain & ALL_EVENT) { 203 do_op = true; 204 } else { 205 const char *ename = event_name(i); 206 if (ename != NULL) { 207 size_t evtlen = strlen(ename); 208 if (len==evtlen && strncmp(curr, ename, evtlen)==0) { 209 tty->print_cr("JVMTI Tracing the event: %s", ename); 210 do_op = true; 211 } 212 } 213 } 214 if (do_op) { 215 if (op == '+') { 216 _event_trace_flags[i] |= bits; 217 } else { 218 _event_trace_flags[i] &= ~bits; 219 } 220 _on = true; 221 } 222 } 223 } 224 if (!_on && (domain & (FUNC|EVENT))) { 225 tty->print_cr("JVMTI Trace domain not found"); 226 } 227 curr = curr_end + 1; 228 } 229 _initialized = true; 230 } 231 232 233 void JvmtiTrace::shutdown() { 234 int i; 235 _on = false; 236 _trace_event_controller = false; 237 for (i = 0; i <= _max_function_index; ++i) { 238 _trace_flags[i] = 0; 239 } 240 for (i = 0; i <= _max_event_index; ++i) { 241 _event_trace_flags[i] = 0; 242 } 243 } 244 245 246 const char* JvmtiTrace::enum_name(const char** names, const jint* values, jint value) { 247 for (int index = 0; names[index] != 0; ++index) { 248 if (values[index] == value) { 249 return names[index]; 250 } 251 } 252 return "*INVALID-ENUM-VALUE*"; 253 } 254 255 256 // return a valid string no matter what state the thread is in 257 const char *JvmtiTrace::safe_get_thread_name(Thread *thread) { 258 if (thread == NULL) { 259 return "NULL"; 260 } 261 if (!thread->is_Java_thread()) { 262 return thread->name(); 263 } 264 JavaThread *java_thread = (JavaThread *)thread; 265 oop threadObj = java_thread->threadObj(); 266 if (threadObj == NULL) { 267 return "NULL"; 268 } 269 oop name = java_lang_Thread::name(threadObj); 270 if (name == NULL) { 271 return "<NOT FILLED IN>"; 272 } 273 return java_lang_String::as_utf8_string(name); 274 } 275 276 277 // return the name of the current thread 278 const char *JvmtiTrace::safe_get_current_thread_name() { 279 if (JvmtiEnv::is_vm_live()) { 280 return JvmtiTrace::safe_get_thread_name(Thread::current()); 281 } else { 282 return "VM not live"; 283 } 284 } 285 286 // return a valid string no matter what the state of k_mirror 287 const char * JvmtiTrace::get_class_name(oop k_mirror) { 288 if (java_lang_Class::is_primitive(k_mirror)) { 289 return "primitive"; 290 } 291 Klass* k_oop = java_lang_Class::as_Klass(k_mirror); 292 if (k_oop == NULL) { 293 return "INVALID"; 294 } 295 return k_oop->external_name(); 296 } 297 298 #endif /*JVMTI_TRACE */