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