• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_RUNTIME_TOOLING_PT_HOOKS_WRAPPER_H_
17 #define PANDA_RUNTIME_TOOLING_PT_HOOKS_WRAPPER_H_
18 
19 #include "runtime/include/tooling/debug_interface.h"
20 #include "os/mutex.h"
21 #include "runtime/include/managed_thread.h"
22 #include "pt_thread_info.h"
23 #include "pt_hook_type_info.h"
24 
25 // NOLINTNEXTLINE
26 #define ASSERT_PT_HOOK_NATIVE_CONTEXT() \
27     ASSERT(MTManagedThread::GetCurrent() != nullptr && MTManagedThread::GetCurrent()->IsInNativeCode())
28 
29 namespace panda::tooling {
30 class ScopedNativePtHook {
31 public:
ScopedNativePtHook()32     ScopedNativePtHook()
33     {
34         ManagedThread *managed_thread = ManagedThread::GetCurrent();
35         ASSERT(managed_thread != nullptr);
36         thread_type_ = managed_thread->GetThreadType();
37         if (thread_type_ == Thread::ThreadType::THREAD_TYPE_MANAGED) {
38             return;
39         }
40 
41         ASSERT(thread_type_ == Thread::ThreadType::THREAD_TYPE_MT_MANAGED);
42         MTManagedThread *mt_managed_thread = MTManagedThread::CastFromThread(managed_thread);
43         if (!mt_managed_thread->IsInNativeCode()) {
44             mt_managed_thread_ = mt_managed_thread;
45             mt_managed_thread_->NativeCodeBegin();
46         }
47 
48         PtPushLocalFrameFromNative();
49     }
50 
~ScopedNativePtHook()51     ~ScopedNativePtHook()
52     {
53         if (thread_type_ == Thread::ThreadType::THREAD_TYPE_MANAGED) {
54             return;
55         }
56         ASSERT(thread_type_ == Thread::ThreadType::THREAD_TYPE_MT_MANAGED);
57 
58         PtPopLocalFrameFromNative();
59         if (mt_managed_thread_ != nullptr) {
60             mt_managed_thread_->NativeCodeEnd();
61         }
62     }
63 
64     NO_COPY_SEMANTIC(ScopedNativePtHook);
65     NO_MOVE_SEMANTIC(ScopedNativePtHook);
66 
67 private:
68     MTManagedThread *mt_managed_thread_ = nullptr;
69     Thread::ThreadType thread_type_ = Thread::ThreadType::THREAD_TYPE_NONE;
70 };
71 
72 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
73 class PtHooksWrapper : public PtHooks {
74 public:
SetHooks(PtHooks * hooks)75     void SetHooks(PtHooks *hooks)
76     {
77         os::memory::WriteLockHolder wholder(hooks_rwlock_);
78         hooks_ = hooks;
79     }
80 
EnableGlobalHook(PtHookType hookType)81     void EnableGlobalHook(PtHookType hookType)
82     {
83         global_hook_type_info_.Enable(hookType);
84     }
85 
DisableGlobalHook(PtHookType hookType)86     void DisableGlobalHook(PtHookType hookType)
87     {
88         global_hook_type_info_.Disable(hookType);
89     }
90 
EnableAllGlobalHook()91     void EnableAllGlobalHook()
92     {
93         global_hook_type_info_.EnableAll();
94     }
95 
DisableAllGlobalHook()96     void DisableAllGlobalHook()
97     {
98         global_hook_type_info_.DisableAll();
99     }
100 
101     // Wrappers for hooks
Breakpoint(PtThread thread,const PtLocation & location)102     void Breakpoint(PtThread thread, const PtLocation &location) override
103     {
104         os::memory::ReadLockHolder rholder(hooks_rwlock_);
105         ASSERT(vmdeath_did_not_happen_);
106         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_BREAKPOINT)) {
107             return;
108         }
109         ScopedNativePtHook nativeScope;
110         ASSERT_PT_HOOK_NATIVE_CONTEXT();
111         hooks_->Breakpoint(thread, location);
112     }
113 
LoadModule(std::string_view pandaFile)114     void LoadModule(std::string_view pandaFile) override
115     {
116         os::memory::ReadLockHolder rholder(hooks_rwlock_);
117         ASSERT(vmdeath_did_not_happen_);
118         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_LOAD_MODULE)) {
119             return;
120         }
121         ScopedNativePtHook nativeScope;
122         ASSERT_PT_HOOK_NATIVE_CONTEXT();
123         hooks_->LoadModule(pandaFile);
124     }
125 
Paused(PauseReason reason)126     void Paused(PauseReason reason) override
127     {
128         os::memory::ReadLockHolder rholder(hooks_rwlock_);
129         ASSERT(vmdeath_did_not_happen_);
130         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_PAUSED)) {
131             return;
132         }
133         ScopedNativePtHook nativeScope;
134         ASSERT_PT_HOOK_NATIVE_CONTEXT();
135         hooks_->Paused(reason);
136     }
137 
Exception(PtThread thread,const PtLocation & location,PtObject exceptionObject,const PtLocation & catchLocation)138     void Exception(PtThread thread, const PtLocation &location, PtObject exceptionObject,
139                    const PtLocation &catchLocation) override
140     {
141         os::memory::ReadLockHolder rholder(hooks_rwlock_);
142         ASSERT(vmdeath_did_not_happen_);
143         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXCEPTION)) {
144             return;
145         }
146         ScopedNativePtHook nativeScope;
147         ASSERT_PT_HOOK_NATIVE_CONTEXT();
148         hooks_->Exception(thread, location, exceptionObject, catchLocation);
149     }
150 
ExceptionCatch(PtThread thread,const PtLocation & location,PtObject exceptionObject)151     void ExceptionCatch(PtThread thread, const PtLocation &location, PtObject exceptionObject) override
152     {
153         os::memory::ReadLockHolder rholder(hooks_rwlock_);
154         ASSERT(vmdeath_did_not_happen_);
155         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXCEPTION_CATCH)) {
156             return;
157         }
158         ScopedNativePtHook nativeScope;
159         ASSERT_PT_HOOK_NATIVE_CONTEXT();
160         hooks_->ExceptionCatch(thread, location, exceptionObject);
161     }
162 
PropertyAccess(PtThread thread,const PtLocation & location,PtObject object,PtProperty property)163     void PropertyAccess(PtThread thread, const PtLocation &location, PtObject object, PtProperty property) override
164     {
165         os::memory::ReadLockHolder rholder(hooks_rwlock_);
166         ASSERT(vmdeath_did_not_happen_);
167         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_PROPERTY_ACCESS)) {
168             return;
169         }
170         ScopedNativePtHook nativeScope;
171         ASSERT_PT_HOOK_NATIVE_CONTEXT();
172         hooks_->PropertyAccess(thread, location, object, property);
173     }
174 
PropertyModification(PtThread thread,const PtLocation & location,PtObject object,PtProperty property,PtValue newValue)175     void PropertyModification(PtThread thread, const PtLocation &location, PtObject object, PtProperty property,
176                               PtValue newValue) override
177     {
178         os::memory::ReadLockHolder rholder(hooks_rwlock_);
179         ASSERT(vmdeath_did_not_happen_);
180         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_PROPERTY_MODIFICATION)) {
181             return;
182         }
183         ScopedNativePtHook nativeScope;
184         ASSERT_PT_HOOK_NATIVE_CONTEXT();
185         hooks_->PropertyModification(thread, location, object, property, newValue);
186     }
187 
FramePop(PtThread thread,PtMethod method,bool wasPoppedByException)188     void FramePop(PtThread thread, PtMethod method, bool wasPoppedByException) override
189     {
190         os::memory::ReadLockHolder rholder(hooks_rwlock_);
191         ASSERT(vmdeath_did_not_happen_);
192         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_FRAME_POP)) {
193             return;
194         }
195         ScopedNativePtHook nativeScope;
196         ASSERT_PT_HOOK_NATIVE_CONTEXT();
197         hooks_->FramePop(thread, method, wasPoppedByException);
198     }
199 
GarbageCollectionFinish()200     void GarbageCollectionFinish() override
201     {
202         // ASSERT(ManagedThread::GetCurrent() == nullptr)
203         os::memory::ReadLockHolder rholder(hooks_rwlock_);
204         ASSERT(vmdeath_did_not_happen_);
205         if (hooks_ == nullptr || !GlobalHookIsEnabled(PtHookType::PT_HOOK_TYPE_GARBAGE_COLLECTION_FINISH)) {
206             return;
207         }
208         // Called in an unmanaged thread
209         hooks_->GarbageCollectionFinish();
210     }
211 
GarbageCollectionStart()212     void GarbageCollectionStart() override
213     {
214         // ASSERT(ManagedThread::GetCurrent() == nullptr)
215         os::memory::ReadLockHolder rholder(hooks_rwlock_);
216         ASSERT(vmdeath_did_not_happen_);
217         if (hooks_ == nullptr || !GlobalHookIsEnabled(PtHookType::PT_HOOK_TYPE_GARBAGE_COLLECTION_START)) {
218             return;
219         }
220         // Called in an unmanaged thread
221         hooks_->GarbageCollectionStart();
222     }
223 
MethodEntry(PtThread thread,PtMethod method)224     void MethodEntry(PtThread thread, PtMethod method) override
225     {
226         os::memory::ReadLockHolder rholder(hooks_rwlock_);
227         ASSERT(vmdeath_did_not_happen_);
228         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_METHOD_ENTRY)) {
229             return;
230         }
231         ScopedNativePtHook nativeScope;
232         ASSERT_PT_HOOK_NATIVE_CONTEXT();
233         hooks_->MethodEntry(thread, method);
234     }
235 
MethodExit(PtThread thread,PtMethod method,bool wasPoppedByException,PtValue returnValue)236     void MethodExit(PtThread thread, PtMethod method, bool wasPoppedByException, PtValue returnValue) override
237     {
238         os::memory::ReadLockHolder rholder(hooks_rwlock_);
239         ASSERT(vmdeath_did_not_happen_);
240         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_METHOD_EXIT)) {
241             return;
242         }
243         ScopedNativePtHook nativeScope;
244         ASSERT_PT_HOOK_NATIVE_CONTEXT();
245         hooks_->MethodExit(thread, method, wasPoppedByException, returnValue);
246     }
247 
SingleStep(PtThread thread,const PtLocation & location)248     void SingleStep(PtThread thread, const PtLocation &location) override
249     {
250         os::memory::ReadLockHolder rholder(hooks_rwlock_);
251         ASSERT(vmdeath_did_not_happen_);
252         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_SINGLE_STEP)) {
253             return;
254         }
255         ScopedNativePtHook nativeScope;
256         ASSERT_PT_HOOK_NATIVE_CONTEXT();
257         hooks_->SingleStep(thread, location);
258     }
259 
ThreadStart(PtThread thread)260     void ThreadStart(PtThread thread) override
261     {
262         os::memory::ReadLockHolder rholder(hooks_rwlock_);
263         ASSERT(vmdeath_did_not_happen_);
264         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_THREAD_START)) {
265             return;
266         }
267         ScopedNativePtHook nativeScope;
268         ASSERT_PT_HOOK_NATIVE_CONTEXT();
269         hooks_->ThreadStart(thread);
270     }
271 
ThreadEnd(PtThread thread)272     void ThreadEnd(PtThread thread) override
273     {
274         os::memory::ReadLockHolder rholder(hooks_rwlock_);
275         ASSERT(vmdeath_did_not_happen_);
276         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_THREAD_END)) {
277             return;
278         }
279         ScopedNativePtHook nativeScope;
280         ASSERT_PT_HOOK_NATIVE_CONTEXT();
281         hooks_->ThreadEnd(thread);
282     }
283 
VmStart()284     void VmStart() override
285     {
286         os::memory::ReadLockHolder rholder(hooks_rwlock_);
287         ASSERT(vmdeath_did_not_happen_);
288         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_VM_START)) {
289             return;
290         }
291         ScopedNativePtHook nativeScope;
292         ASSERT_PT_HOOK_NATIVE_CONTEXT();
293         hooks_->VmStart();
294     }
295 
VmInitialization(PtThread thread)296     void VmInitialization(PtThread thread) override
297     {
298         os::memory::ReadLockHolder rholder(hooks_rwlock_);
299         ASSERT(vmdeath_did_not_happen_);
300         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_VM_INITIALIZATION)) {
301             return;
302         }
303         ScopedNativePtHook nativeScope;
304         ASSERT_PT_HOOK_NATIVE_CONTEXT();
305         hooks_->VmInitialization(thread);
306     }
307 
VmDeath()308     void VmDeath() override
309     {
310         os::memory::ReadLockHolder rholder(hooks_rwlock_);
311         ASSERT(vmdeath_did_not_happen_);
312 #ifndef NDEBUG
313         vmdeath_did_not_happen_ = false;
314 #endif
315         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_VM_DEATH)) {
316             return;
317         }
318         ManagedThread *thread = ManagedThread::GetCurrent();
319         LOG_IF(thread->IsThreadAlive(), FATAL, RUNTIME) << "Main Thread should have been destroyed";
320         hooks_->VmDeath();
321     }
322 
ExceptionRevoked(ExceptionWrapper reason,ExceptionID exceptionId)323     void ExceptionRevoked(ExceptionWrapper reason, ExceptionID exceptionId) override
324     {
325         os::memory::ReadLockHolder rholder(hooks_rwlock_);
326         ASSERT(vmdeath_did_not_happen_);
327         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXCEPTION_REVOKED)) {
328             return;
329         }
330         ScopedNativePtHook nativeScope;
331         ASSERT_PT_HOOK_NATIVE_CONTEXT();
332         hooks_->ExceptionRevoked(reason, exceptionId);
333     }
334 
ExecutionContextCreated(ExecutionContextWrapper context)335     void ExecutionContextCreated(ExecutionContextWrapper context) override
336     {
337         os::memory::ReadLockHolder rholder(hooks_rwlock_);
338         ASSERT(vmdeath_did_not_happen_);
339         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXECUTION_CONTEXT_CREATEED)) {
340             return;
341         }
342         ScopedNativePtHook nativeScope;
343         ASSERT_PT_HOOK_NATIVE_CONTEXT();
344         hooks_->ExecutionContextCreated(context);
345     }
346 
ExecutionContextDestroyed(ExecutionContextWrapper context)347     void ExecutionContextDestroyed(ExecutionContextWrapper context) override
348     {
349         os::memory::ReadLockHolder rholder(hooks_rwlock_);
350         ASSERT(vmdeath_did_not_happen_);
351         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXECUTION_CONTEXT_DESTROYED)) {
352             return;
353         }
354         ScopedNativePtHook nativeScope;
355         ASSERT_PT_HOOK_NATIVE_CONTEXT();
356         hooks_->ExecutionContextDestroyed(context);
357     }
358 
ExecutionContextsCleared()359     void ExecutionContextsCleared() override
360     {
361         os::memory::ReadLockHolder rholder(hooks_rwlock_);
362         ASSERT(vmdeath_did_not_happen_);
363         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXECUTION_CONTEXTS_CLEARED)) {
364             return;
365         }
366         ScopedNativePtHook nativeScope;
367         ASSERT_PT_HOOK_NATIVE_CONTEXT();
368         hooks_->ExecutionContextsCleared();
369     }
370 
InspectRequested(PtObject object,PtObject hints)371     void InspectRequested(PtObject object, PtObject hints) override
372     {
373         os::memory::ReadLockHolder rholder(hooks_rwlock_);
374         ASSERT(vmdeath_did_not_happen_);
375         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_INSPECT_REQUESTED)) {
376             return;
377         }
378         ScopedNativePtHook nativeScope;
379         ASSERT_PT_HOOK_NATIVE_CONTEXT();
380         hooks_->InspectRequested(object, hints);
381     }
382 
ClassLoad(PtThread thread,PtClass klass)383     void ClassLoad(PtThread thread, PtClass klass) override
384     {
385         os::memory::ReadLockHolder rholder(hooks_rwlock_);
386         ASSERT(vmdeath_did_not_happen_);
387         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_CLASS_LOAD)) {
388             return;
389         }
390         ScopedNativePtHook nativeScope;
391         ASSERT_PT_HOOK_NATIVE_CONTEXT();
392         hooks_->ClassLoad(thread, klass);
393     }
394 
ClassPrepare(PtThread thread,PtClass klass)395     void ClassPrepare(PtThread thread, PtClass klass) override
396     {
397         os::memory::ReadLockHolder rholder(hooks_rwlock_);
398         ASSERT(vmdeath_did_not_happen_);
399         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_CLASS_PREPARE)) {
400             return;
401         }
402         ScopedNativePtHook nativeScope;
403         ASSERT_PT_HOOK_NATIVE_CONTEXT();
404         hooks_->ClassPrepare(thread, klass);
405     }
406 
MonitorWait(PtThread thread,PtObject object,int64_t timeout)407     void MonitorWait(PtThread thread, PtObject object, int64_t timeout) override
408     {
409         os::memory::ReadLockHolder rholder(hooks_rwlock_);
410         ASSERT(vmdeath_did_not_happen_);
411         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_MONITOR_WAIT)) {
412             return;
413         }
414         ScopedNativePtHook nativeScope;
415         ASSERT_PT_HOOK_NATIVE_CONTEXT();
416         hooks_->MonitorWait(thread, object, timeout);
417     }
418 
MonitorWaited(PtThread thread,PtObject object,bool timedOut)419     void MonitorWaited(PtThread thread, PtObject object, bool timedOut) override
420     {
421         os::memory::ReadLockHolder rholder(hooks_rwlock_);
422         ASSERT(vmdeath_did_not_happen_);
423         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_MONITOR_WAITED)) {
424             return;
425         }
426         ScopedNativePtHook nativeScope;
427         ASSERT_PT_HOOK_NATIVE_CONTEXT();
428         hooks_->MonitorWaited(thread, object, timedOut);
429     }
430 
MonitorContendedEnter(PtThread thread,PtObject object)431     void MonitorContendedEnter(PtThread thread, PtObject object) override
432     {
433         os::memory::ReadLockHolder rholder(hooks_rwlock_);
434         ASSERT(vmdeath_did_not_happen_);
435         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_MONITOR_CONTENDED_ENTER)) {
436             return;
437         }
438         ScopedNativePtHook nativeScope;
439         ASSERT_PT_HOOK_NATIVE_CONTEXT();
440         hooks_->MonitorContendedEnter(thread, object);
441     }
442 
MonitorContendedEntered(PtThread thread,PtObject object)443     void MonitorContendedEntered(PtThread thread, PtObject object) override
444     {
445         os::memory::ReadLockHolder rholder(hooks_rwlock_);
446         ASSERT(vmdeath_did_not_happen_);
447         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_MONITOR_CONTENDED_ENTERED)) {
448             return;
449         }
450         ScopedNativePtHook nativeScope;
451         ASSERT_PT_HOOK_NATIVE_CONTEXT();
452         hooks_->MonitorContendedEntered(thread, object);
453     }
454 
ObjectAlloc(PtClass klass,PtObject object,PtThread thread,size_t size)455     void ObjectAlloc(PtClass klass, PtObject object, PtThread thread, size_t size) override
456     {
457         os::memory::ReadLockHolder rholder(hooks_rwlock_);
458         ASSERT(vmdeath_did_not_happen_);
459         if (hooks_ == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_OBJECT_ALLOC)) {
460             return;
461         }
462         ScopedNativePtHook nativeScope;
463         ASSERT_PT_HOOK_NATIVE_CONTEXT();
464         hooks_->ObjectAlloc(klass, object, thread, size);
465     }
466 
467 private:
GlobalHookIsEnabled(PtHookType type)468     bool GlobalHookIsEnabled(PtHookType type) const
469     {
470         return global_hook_type_info_.IsEnabled(type);
471     }
472 
HookIsEnabled(PtHookType type)473     bool HookIsEnabled(PtHookType type) const
474     {
475         if (GlobalHookIsEnabled(type)) {
476             return true;
477         }
478 
479         MTManagedThread *mt_managed_thread = MTManagedThread::GetCurrent();
480         ASSERT(mt_managed_thread != nullptr);
481 
482         // Check local value
483         return mt_managed_thread->GetPtThreadInfo()->GetHookTypeInfo().IsEnabled(type);
484     }
485 
486     PtHooks *hooks_ = nullptr;
487     mutable os::memory::RWLock hooks_rwlock_;
488 
489     PtHookTypeInfo global_hook_type_info_ {true};
490 
491 #ifndef NDEBUG
492     bool vmdeath_did_not_happen_ = true;
493 #endif
494 };
495 
496 }  // namespace panda::tooling
497 
498 #endif  // PANDA_RUNTIME_TOOLING_PT_HOOKS_WRAPPER_H_
499