jvmtiTrace.cpp revision 3602:da91efe96a93
1/*
2 * Copyright (c) 2003, 2012, 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
65bool JvmtiTrace::_initialized = false;
66bool JvmtiTrace::_on = false;
67bool JvmtiTrace::_trace_event_controller = false;
68
69void 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
233void 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
246const 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
257const 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  typeArrayOop name = java_lang_Thread::name(threadObj);
270  if (name == NULL) {
271    return "<NOT FILLED IN>";
272  }
273  return UNICODE::as_utf8((jchar*) name->base(T_CHAR), name->length());
274}
275
276
277// return the name of the current thread
278const 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
287const 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 Klass::cast(k_oop)->external_name();
296}
297
298#endif /*JVMTI_TRACE */
299