src/hotspot/share/prims/jvmtiTrace.cpp
changeset 47216 71c04702a3d5
parent 37992 c7ec6a3275f7
child 51614 36773a4fe3e7
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     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 
       
    68 bool JvmtiTrace::_initialized = false;
       
    69 bool JvmtiTrace::_on = false;
       
    70 bool JvmtiTrace::_trace_event_controller = false;
       
    71 
       
    72 void 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 
       
   247 void 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 
       
   260 const 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
       
   271 const 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
       
   292 const 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
       
   301 const 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 */