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
initialize()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
shutdown()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
enum_name(const char ** names,const jint * values,jint value)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
safe_get_thread_name(Thread * thread)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
safe_get_current_thread_name()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
get_class_name(oop 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 */
313