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