1 /* Copyright (C) 2016 The Android Open Source Project
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This file implements interfaces from the file jvmti.h. This implementation
5 * is licensed under the same terms as the file jvmti.h. The
6 * copyright and license information for the file jvmti.h follows.
7 *
8 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10 *
11 * This code is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 only, as
13 * published by the Free Software Foundation. Oracle designates this
14 * particular file as subject to the "Classpath" exception as provided
15 * by Oracle in the LICENSE file that accompanied this code.
16 *
17 * This code is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * version 2 for more details (a copy is included in the LICENSE file that
21 * accompanied this code).
22 *
23 * You should have received a copy of the GNU General Public License version
24 * 2 along with this work; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28 * or visit www.oracle.com if you need additional information or have any
29 * questions.
30 */
31
32 #include "events-inl.h"
33
34 #include "art_jvmti.h"
35 #include "base/logging.h"
36 #include "gc/allocation_listener.h"
37 #include "gc/gc_pause_listener.h"
38 #include "gc/heap.h"
39 #include "handle_scope-inl.h"
40 #include "instrumentation.h"
41 #include "jni_env_ext-inl.h"
42 #include "mirror/class.h"
43 #include "mirror/object-inl.h"
44 #include "runtime.h"
45 #include "ScopedLocalRef.h"
46 #include "scoped_thread_state_change-inl.h"
47 #include "thread-inl.h"
48
49 namespace openjdkjvmti {
50
IsEnabledAnywhere(ArtJvmtiEvent event)51 bool EventMasks::IsEnabledAnywhere(ArtJvmtiEvent event) {
52 return global_event_mask.Test(event) || unioned_thread_event_mask.Test(event);
53 }
54
GetEventMask(art::Thread * thread)55 EventMask& EventMasks::GetEventMask(art::Thread* thread) {
56 if (thread == nullptr) {
57 return global_event_mask;
58 }
59
60 for (auto& pair : thread_event_masks) {
61 const UniqueThread& unique_thread = pair.first;
62 if (unique_thread.first == thread &&
63 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
64 return pair.second;
65 }
66 }
67
68 // TODO: Remove old UniqueThread with the same pointer, if exists.
69
70 thread_event_masks.emplace_back(UniqueThread(thread, thread->GetTid()), EventMask());
71 return thread_event_masks.back().second;
72 }
73
GetEventMaskOrNull(art::Thread * thread)74 EventMask* EventMasks::GetEventMaskOrNull(art::Thread* thread) {
75 if (thread == nullptr) {
76 return &global_event_mask;
77 }
78
79 for (auto& pair : thread_event_masks) {
80 const UniqueThread& unique_thread = pair.first;
81 if (unique_thread.first == thread &&
82 unique_thread.second == static_cast<uint32_t>(thread->GetTid())) {
83 return &pair.second;
84 }
85 }
86
87 return nullptr;
88 }
89
90
EnableEvent(art::Thread * thread,ArtJvmtiEvent event)91 void EventMasks::EnableEvent(art::Thread* thread, ArtJvmtiEvent event) {
92 DCHECK(EventMask::EventIsInRange(event));
93 GetEventMask(thread).Set(event);
94 if (thread != nullptr) {
95 unioned_thread_event_mask.Set(event, true);
96 }
97 }
98
DisableEvent(art::Thread * thread,ArtJvmtiEvent event)99 void EventMasks::DisableEvent(art::Thread* thread, ArtJvmtiEvent event) {
100 DCHECK(EventMask::EventIsInRange(event));
101 GetEventMask(thread).Set(event, false);
102 if (thread != nullptr) {
103 // Regenerate union for the event.
104 bool union_value = false;
105 for (auto& pair : thread_event_masks) {
106 union_value |= pair.second.Test(event);
107 if (union_value) {
108 break;
109 }
110 }
111 unioned_thread_event_mask.Set(event, union_value);
112 }
113 }
114
HandleChangedCapabilities(const jvmtiCapabilities & caps,bool caps_added)115 void EventMasks::HandleChangedCapabilities(const jvmtiCapabilities& caps, bool caps_added) {
116 if (UNLIKELY(caps.can_retransform_classes == 1)) {
117 // If we are giving this env the retransform classes cap we need to switch all events of
118 // NonTransformable to Transformable and vice versa.
119 ArtJvmtiEvent to_remove = caps_added ? ArtJvmtiEvent::kClassFileLoadHookNonRetransformable
120 : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
121 ArtJvmtiEvent to_add = caps_added ? ArtJvmtiEvent::kClassFileLoadHookRetransformable
122 : ArtJvmtiEvent::kClassFileLoadHookNonRetransformable;
123 if (global_event_mask.Test(to_remove)) {
124 CHECK(!global_event_mask.Test(to_add));
125 global_event_mask.Set(to_remove, false);
126 global_event_mask.Set(to_add, true);
127 }
128
129 if (unioned_thread_event_mask.Test(to_remove)) {
130 CHECK(!unioned_thread_event_mask.Test(to_add));
131 unioned_thread_event_mask.Set(to_remove, false);
132 unioned_thread_event_mask.Set(to_add, true);
133 }
134 for (auto thread_mask : thread_event_masks) {
135 if (thread_mask.second.Test(to_remove)) {
136 CHECK(!thread_mask.second.Test(to_add));
137 thread_mask.second.Set(to_remove, false);
138 thread_mask.second.Set(to_add, true);
139 }
140 }
141 }
142 }
143
RegisterArtJvmTiEnv(ArtJvmTiEnv * env)144 void EventHandler::RegisterArtJvmTiEnv(ArtJvmTiEnv* env) {
145 // Since we never shrink this array we might as well try to fill gaps.
146 auto it = std::find(envs.begin(), envs.end(), nullptr);
147 if (it != envs.end()) {
148 *it = env;
149 } else {
150 envs.push_back(env);
151 }
152 }
153
RemoveArtJvmTiEnv(ArtJvmTiEnv * env)154 void EventHandler::RemoveArtJvmTiEnv(ArtJvmTiEnv* env) {
155 // Since we might be currently iterating over the envs list we cannot actually erase elements.
156 // Instead we will simply replace them with 'nullptr' and skip them manually.
157 auto it = std::find(envs.begin(), envs.end(), env);
158 if (it != envs.end()) {
159 *it = nullptr;
160 for (size_t i = static_cast<size_t>(ArtJvmtiEvent::kMinEventTypeVal);
161 i <= static_cast<size_t>(ArtJvmtiEvent::kMaxEventTypeVal);
162 ++i) {
163 RecalculateGlobalEventMask(static_cast<ArtJvmtiEvent>(i));
164 }
165 }
166 }
167
IsThreadControllable(ArtJvmtiEvent event)168 static bool IsThreadControllable(ArtJvmtiEvent event) {
169 switch (event) {
170 case ArtJvmtiEvent::kVmInit:
171 case ArtJvmtiEvent::kVmStart:
172 case ArtJvmtiEvent::kVmDeath:
173 case ArtJvmtiEvent::kThreadStart:
174 case ArtJvmtiEvent::kCompiledMethodLoad:
175 case ArtJvmtiEvent::kCompiledMethodUnload:
176 case ArtJvmtiEvent::kDynamicCodeGenerated:
177 case ArtJvmtiEvent::kDataDumpRequest:
178 return false;
179
180 default:
181 return true;
182 }
183 }
184
185 class JvmtiAllocationListener : public art::gc::AllocationListener {
186 public:
JvmtiAllocationListener(EventHandler * handler)187 explicit JvmtiAllocationListener(EventHandler* handler) : handler_(handler) {}
188
ObjectAllocated(art::Thread * self,art::ObjPtr<art::mirror::Object> * obj,size_t byte_count)189 void ObjectAllocated(art::Thread* self, art::ObjPtr<art::mirror::Object>* obj, size_t byte_count)
190 OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
191 DCHECK_EQ(self, art::Thread::Current());
192
193 if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kVmObjectAlloc)) {
194 art::StackHandleScope<1> hs(self);
195 auto h = hs.NewHandleWrapper(obj);
196 // jvmtiEventVMObjectAlloc parameters:
197 // jvmtiEnv *jvmti_env,
198 // JNIEnv* jni_env,
199 // jthread thread,
200 // jobject object,
201 // jclass object_klass,
202 // jlong size
203 art::JNIEnvExt* jni_env = self->GetJniEnv();
204
205 jthread thread_peer;
206 if (self->IsStillStarting()) {
207 thread_peer = nullptr;
208 } else {
209 thread_peer = jni_env->AddLocalReference<jthread>(self->GetPeer());
210 }
211
212 ScopedLocalRef<jthread> thread(jni_env, thread_peer);
213 ScopedLocalRef<jobject> object(
214 jni_env, jni_env->AddLocalReference<jobject>(*obj));
215 ScopedLocalRef<jclass> klass(
216 jni_env, jni_env->AddLocalReference<jclass>(obj->Ptr()->GetClass()));
217
218 handler_->DispatchEvent<ArtJvmtiEvent::kVmObjectAlloc>(self,
219 reinterpret_cast<JNIEnv*>(jni_env),
220 thread.get(),
221 object.get(),
222 klass.get(),
223 static_cast<jlong>(byte_count));
224 }
225 }
226
227 private:
228 EventHandler* handler_;
229 };
230
SetupObjectAllocationTracking(art::gc::AllocationListener * listener,bool enable)231 static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener, bool enable) {
232 // We must not hold the mutator lock here, but if we're in FastJNI, for example, we might. For
233 // now, do a workaround: (possibly) acquire and release.
234 art::ScopedObjectAccess soa(art::Thread::Current());
235 art::ScopedThreadSuspension sts(soa.Self(), art::ThreadState::kSuspended);
236 if (enable) {
237 art::Runtime::Current()->GetHeap()->SetAllocationListener(listener);
238 } else {
239 art::Runtime::Current()->GetHeap()->RemoveAllocationListener();
240 }
241 }
242
243 // Report GC pauses (see spec) as GARBAGE_COLLECTION_START and GARBAGE_COLLECTION_END.
244 class JvmtiGcPauseListener : public art::gc::GcPauseListener {
245 public:
JvmtiGcPauseListener(EventHandler * handler)246 explicit JvmtiGcPauseListener(EventHandler* handler)
247 : handler_(handler),
248 start_enabled_(false),
249 finish_enabled_(false) {}
250
StartPause()251 void StartPause() OVERRIDE {
252 handler_->DispatchEvent<ArtJvmtiEvent::kGarbageCollectionStart>(nullptr);
253 }
254
EndPause()255 void EndPause() OVERRIDE {
256 handler_->DispatchEvent<ArtJvmtiEvent::kGarbageCollectionFinish>(nullptr);
257 }
258
IsEnabled()259 bool IsEnabled() {
260 return start_enabled_ || finish_enabled_;
261 }
262
SetStartEnabled(bool e)263 void SetStartEnabled(bool e) {
264 start_enabled_ = e;
265 }
266
SetFinishEnabled(bool e)267 void SetFinishEnabled(bool e) {
268 finish_enabled_ = e;
269 }
270
271 private:
272 EventHandler* handler_;
273 bool start_enabled_;
274 bool finish_enabled_;
275 };
276
SetupGcPauseTracking(JvmtiGcPauseListener * listener,ArtJvmtiEvent event,bool enable)277 static void SetupGcPauseTracking(JvmtiGcPauseListener* listener, ArtJvmtiEvent event, bool enable) {
278 bool old_state = listener->IsEnabled();
279
280 if (event == ArtJvmtiEvent::kGarbageCollectionStart) {
281 listener->SetStartEnabled(enable);
282 } else {
283 listener->SetFinishEnabled(enable);
284 }
285
286 bool new_state = listener->IsEnabled();
287
288 if (old_state != new_state) {
289 if (new_state) {
290 art::Runtime::Current()->GetHeap()->SetGcPauseListener(listener);
291 } else {
292 art::Runtime::Current()->GetHeap()->RemoveGcPauseListener();
293 }
294 }
295 }
296
297 // Handle special work for the given event type, if necessary.
HandleEventType(ArtJvmtiEvent event,bool enable)298 void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) {
299 switch (event) {
300 case ArtJvmtiEvent::kVmObjectAlloc:
301 SetupObjectAllocationTracking(alloc_listener_.get(), enable);
302 return;
303
304 case ArtJvmtiEvent::kGarbageCollectionStart:
305 case ArtJvmtiEvent::kGarbageCollectionFinish:
306 SetupGcPauseTracking(gc_pause_listener_.get(), event, enable);
307 return;
308
309 default:
310 break;
311 }
312 }
313
314 // Checks to see if the env has the capabilities associated with the given event.
HasAssociatedCapability(ArtJvmTiEnv * env,ArtJvmtiEvent event)315 static bool HasAssociatedCapability(ArtJvmTiEnv* env,
316 ArtJvmtiEvent event) {
317 jvmtiCapabilities caps = env->capabilities;
318 switch (event) {
319 case ArtJvmtiEvent::kBreakpoint:
320 return caps.can_generate_breakpoint_events == 1;
321
322 case ArtJvmtiEvent::kCompiledMethodLoad:
323 case ArtJvmtiEvent::kCompiledMethodUnload:
324 return caps.can_generate_compiled_method_load_events == 1;
325
326 case ArtJvmtiEvent::kException:
327 case ArtJvmtiEvent::kExceptionCatch:
328 return caps.can_generate_exception_events == 1;
329
330 case ArtJvmtiEvent::kFieldAccess:
331 return caps.can_generate_field_access_events == 1;
332
333 case ArtJvmtiEvent::kFieldModification:
334 return caps.can_generate_field_modification_events == 1;
335
336 case ArtJvmtiEvent::kFramePop:
337 return caps.can_generate_frame_pop_events == 1;
338
339 case ArtJvmtiEvent::kGarbageCollectionStart:
340 case ArtJvmtiEvent::kGarbageCollectionFinish:
341 return caps.can_generate_garbage_collection_events == 1;
342
343 case ArtJvmtiEvent::kMethodEntry:
344 return caps.can_generate_method_entry_events == 1;
345
346 case ArtJvmtiEvent::kMethodExit:
347 return caps.can_generate_method_exit_events == 1;
348
349 case ArtJvmtiEvent::kMonitorContendedEnter:
350 case ArtJvmtiEvent::kMonitorContendedEntered:
351 case ArtJvmtiEvent::kMonitorWait:
352 case ArtJvmtiEvent::kMonitorWaited:
353 return caps.can_generate_monitor_events == 1;
354
355 case ArtJvmtiEvent::kNativeMethodBind:
356 return caps.can_generate_native_method_bind_events == 1;
357
358 case ArtJvmtiEvent::kObjectFree:
359 return caps.can_generate_object_free_events == 1;
360
361 case ArtJvmtiEvent::kSingleStep:
362 return caps.can_generate_single_step_events == 1;
363
364 case ArtJvmtiEvent::kVmObjectAlloc:
365 return caps.can_generate_vm_object_alloc_events == 1;
366
367 default:
368 return true;
369 }
370 }
371
SetEvent(ArtJvmTiEnv * env,art::Thread * thread,ArtJvmtiEvent event,jvmtiEventMode mode)372 jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env,
373 art::Thread* thread,
374 ArtJvmtiEvent event,
375 jvmtiEventMode mode) {
376 if (thread != nullptr) {
377 art::ThreadState state = thread->GetState();
378 if (state == art::ThreadState::kStarting ||
379 state == art::ThreadState::kTerminated ||
380 thread->IsStillStarting()) {
381 return ERR(THREAD_NOT_ALIVE);
382 }
383 if (!IsThreadControllable(event)) {
384 return ERR(ILLEGAL_ARGUMENT);
385 }
386 }
387
388 if (mode != JVMTI_ENABLE && mode != JVMTI_DISABLE) {
389 return ERR(ILLEGAL_ARGUMENT);
390 }
391
392 if (!EventMask::EventIsInRange(event)) {
393 return ERR(INVALID_EVENT_TYPE);
394 }
395
396 if (!HasAssociatedCapability(env, event)) {
397 return ERR(MUST_POSSESS_CAPABILITY);
398 }
399
400 bool old_state = global_mask.Test(event);
401
402 if (mode == JVMTI_ENABLE) {
403 env->event_masks.EnableEvent(thread, event);
404 global_mask.Set(event);
405 } else {
406 DCHECK_EQ(mode, JVMTI_DISABLE);
407
408 env->event_masks.DisableEvent(thread, event);
409 RecalculateGlobalEventMask(event);
410 }
411
412 bool new_state = global_mask.Test(event);
413
414 // Handle any special work required for the event type.
415 if (new_state != old_state) {
416 HandleEventType(event, mode == JVMTI_ENABLE);
417 }
418
419 return ERR(NONE);
420 }
421
EventHandler()422 EventHandler::EventHandler() {
423 alloc_listener_.reset(new JvmtiAllocationListener(this));
424 gc_pause_listener_.reset(new JvmtiGcPauseListener(this));
425 }
426
~EventHandler()427 EventHandler::~EventHandler() {
428 }
429
430 } // namespace openjdkjvmti
431