• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 <atomic>
20 #include "runtime/include/tooling/debug_interface.h"
21 #include "os/mutex.h"
22 #include "runtime/include/mtmanaged_thread.h"
23 #include "pt_thread_info.h"
24 #include "pt_hook_type_info.h"
25 
26 namespace ark::tooling {
27 
28 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
29 class PtHooksWrapper : public PtHooks {
30 public:
SetHooks(PtHooks * hooks)31     void SetHooks(PtHooks *hooks)
32     {
33         // Atomic with release order reason: data race with hooks_
34         hooks_.store(hooks, std::memory_order_release);
35     }
36 
EnableGlobalHook(PtHookType hookType)37     void EnableGlobalHook(PtHookType hookType)
38     {
39         globalHookTypeInfo_.Enable(hookType);
40     }
41 
DisableGlobalHook(PtHookType hookType)42     void DisableGlobalHook(PtHookType hookType)
43     {
44         globalHookTypeInfo_.Disable(hookType);
45     }
46 
EnableAllGlobalHook()47     void EnableAllGlobalHook()
48     {
49         globalHookTypeInfo_.EnableAll();
50     }
51 
DisableAllGlobalHook()52     void DisableAllGlobalHook()
53     {
54         globalHookTypeInfo_.DisableAll();
55     }
56 
57     // Wrappers for hooks
Breakpoint(PtThread thread,Method * method,const PtLocation & location)58     void Breakpoint(PtThread thread, Method *method, const PtLocation &location) override
59     {
60         // Atomic with acquire order reason: data race with hooks_
61         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
62         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_BREAKPOINT)) {
63             return;
64         }
65         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
66         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
67         loadedHooks->Breakpoint(thread, method, location);
68     }
69 
LoadModule(std::string_view pandaFile)70     void LoadModule(std::string_view pandaFile) override
71     {
72         // Atomic with acquire order reason: data race with hooks_
73         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
74         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_LOAD_MODULE)) {
75             return;
76         }
77         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
78         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
79         loadedHooks->LoadModule(pandaFile);
80     }
81 
Paused(PauseReason reason)82     void Paused(PauseReason reason) override
83     {
84         // Atomic with acquire order reason: data race with hooks_
85         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
86         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_PAUSED)) {
87             return;
88         }
89         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
90         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
91         loadedHooks->Paused(reason);
92     }
93 
94     // CC-OFFNXT(G.FUN.01-CPP) Decreasing the number of arguments will decrease the clarity of the code.
Exception(PtThread thread,Method * method,const PtLocation & location,ObjectHeader * exceptionObject,Method * catchMethod,const PtLocation & catchLocation)95     void Exception(PtThread thread, Method *method, const PtLocation &location, ObjectHeader *exceptionObject,
96                    Method *catchMethod, const PtLocation &catchLocation) override
97     {
98         // Atomic with acquire order reason: data race with hooks_
99         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
100         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXCEPTION)) {
101             return;
102         }
103         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
104         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
105         loadedHooks->Exception(thread, method, location, exceptionObject, catchMethod, catchLocation);
106     }
107 
ExceptionCatch(PtThread thread,Method * method,const PtLocation & location,ObjectHeader * exceptionObject)108     void ExceptionCatch(PtThread thread, Method *method, const PtLocation &location,
109                         ObjectHeader *exceptionObject) override
110     {
111         // Atomic with acquire order reason: data race with hooks_
112         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
113         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXCEPTION_CATCH)) {
114             return;
115         }
116         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
117         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
118         loadedHooks->ExceptionCatch(thread, method, location, exceptionObject);
119     }
120 
PropertyAccess(PtThread thread,Method * method,const PtLocation & location,ObjectHeader * object,PtProperty property)121     void PropertyAccess(PtThread thread, Method *method, const PtLocation &location, ObjectHeader *object,
122                         PtProperty property) override
123     {
124         // Atomic with acquire order reason: data race with hooks_
125         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
126         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_PROPERTY_ACCESS)) {
127             return;
128         }
129         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
130         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
131         loadedHooks->PropertyAccess(thread, method, location, object, property);
132     }
133 
134     // CC-OFFNXT(G.FUN.01-CPP) Decreasing the number of arguments will decrease the clarity of the code.
PropertyModification(PtThread thread,Method * method,const PtLocation & location,ObjectHeader * object,PtProperty property,VRegValue newValue)135     void PropertyModification(PtThread thread, Method *method, const PtLocation &location, ObjectHeader *object,
136                               PtProperty property, VRegValue newValue) override
137     {
138         // Atomic with acquire order reason: data race with hooks_
139         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
140         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_PROPERTY_MODIFICATION)) {
141             return;
142         }
143         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
144         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
145         loadedHooks->PropertyModification(thread, method, location, object, property, newValue);
146     }
147 
ConsoleCall(PtThread thread,ConsoleCallType type,uint64_t timestamp,const PandaVector<TypedValue> & arguments)148     void ConsoleCall(PtThread thread, ConsoleCallType type, uint64_t timestamp,
149                      const PandaVector<TypedValue> &arguments) override
150     {
151         // Atomic with acquire order reason: data race with hooks_
152         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
153         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_CONSOLE_CALL)) {
154             return;
155         }
156         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
157         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
158         loadedHooks->ConsoleCall(thread, type, timestamp, arguments);
159     }
160 
FramePop(PtThread thread,Method * method,bool wasPoppedByException)161     void FramePop(PtThread thread, Method *method, bool wasPoppedByException) override
162     {
163         // Atomic with acquire order reason: data race with hooks_
164         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
165         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_FRAME_POP)) {
166             return;
167         }
168         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
169         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
170         loadedHooks->FramePop(thread, method, wasPoppedByException);
171     }
172 
GarbageCollectionFinish()173     void GarbageCollectionFinish() override
174     {
175         // NOTE(dtrubenkov): Add an assertion when 2125 issue is resolved
176         // ASSERT(ManagedThread::GetCurrent() == nullptr)
177         // Atomic with acquire order reason: data race with hooks_
178         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
179         if (loadedHooks == nullptr || !GlobalHookIsEnabled(PtHookType::PT_HOOK_TYPE_GARBAGE_COLLECTION_FINISH)) {
180             return;
181         }
182         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
183         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
184         // Called in an unmanaged thread
185         loadedHooks->GarbageCollectionFinish();
186     }
187 
GarbageCollectionStart()188     void GarbageCollectionStart() override
189     {
190         // NOTE(dtrubenkov): Add an assertion when 2125 issue is resolved
191         // ASSERT(ManagedThread::GetCurrent() == nullptr)
192         // Atomic with acquire order reason: data race with hooks_
193         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
194         if (loadedHooks == nullptr || !GlobalHookIsEnabled(PtHookType::PT_HOOK_TYPE_GARBAGE_COLLECTION_START)) {
195             return;
196         }
197         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
198         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
199         // Called in an unmanaged thread
200         loadedHooks->GarbageCollectionStart();
201     }
202 
MethodEntry(PtThread thread,Method * method)203     void MethodEntry(PtThread thread, Method *method) override
204     {
205         // Atomic with acquire order reason: data race with hooks_
206         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
207         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_METHOD_ENTRY)) {
208             return;
209         }
210         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
211         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
212         loadedHooks->MethodEntry(thread, method);
213     }
214 
MethodExit(PtThread thread,Method * method,bool wasPoppedByException,VRegValue returnValue)215     void MethodExit(PtThread thread, Method *method, bool wasPoppedByException, VRegValue returnValue) override
216     {
217         // Atomic with acquire order reason: data race with hooks_
218         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
219         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_METHOD_EXIT)) {
220             return;
221         }
222         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
223         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
224         loadedHooks->MethodExit(thread, method, wasPoppedByException, returnValue);
225     }
226 
SingleStep(PtThread thread,Method * method,const PtLocation & location)227     void SingleStep(PtThread thread, Method *method, const PtLocation &location) override
228     {
229         // Atomic with acquire order reason: data race with hooks_
230         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
231         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_SINGLE_STEP)) {
232             return;
233         }
234         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
235         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
236         loadedHooks->SingleStep(thread, method, location);
237     }
238 
ThreadStart(PtThread thread)239     void ThreadStart(PtThread thread) override
240     {
241         // Atomic with acquire order reason: data race with hooks_
242         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
243         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_THREAD_START)) {
244             return;
245         }
246         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
247         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
248         loadedHooks->ThreadStart(thread);
249     }
250 
ThreadEnd(PtThread thread)251     void ThreadEnd(PtThread thread) override
252     {
253         // Atomic with acquire order reason: data race with hooks_
254         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
255         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_THREAD_END)) {
256             return;
257         }
258         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
259         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
260         loadedHooks->ThreadEnd(thread);
261     }
262 
VmStart()263     void VmStart() override
264     {
265         // Atomic with acquire order reason: data race with hooks_
266         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
267         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_VM_START)) {
268             return;
269         }
270         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
271         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
272         loadedHooks->VmStart();
273     }
274 
VmInitialization(PtThread thread)275     void VmInitialization(PtThread thread) override
276     {
277         // Atomic with acquire order reason: data race with hooks_
278         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
279         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_VM_INITIALIZATION)) {
280             return;
281         }
282         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
283         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
284         loadedHooks->VmInitialization(thread);
285     }
286 
VmDeath()287     void VmDeath() override
288     {
289         // Atomic with acquire order reason: data race with hooks_
290         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
291         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_VM_DEATH)) {
292             return;
293         }
294         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
295         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
296 #ifndef NDEBUG
297         // Atomic with release order reason: data race with vmdeath_did_not_happen_
298         vmdeathDidNotHappen_.store(false, std::memory_order_release);
299 #endif
300         loadedHooks->VmDeath();
301         SetHooks(nullptr);
302     }
303 
ExceptionRevoked(ExceptionWrapper reason,ExceptionID exceptionId)304     void ExceptionRevoked(ExceptionWrapper reason, ExceptionID exceptionId) override
305     {
306         // Atomic with acquire order reason: data race with hooks_
307         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
308         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXCEPTION_REVOKED)) {
309             return;
310         }
311         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
312         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
313         loadedHooks->ExceptionRevoked(reason, exceptionId);
314     }
315 
ExecutionContextCreated(ExecutionContextWrapper context)316     void ExecutionContextCreated(ExecutionContextWrapper context) override
317     {
318         // Atomic with acquire order reason: data race with hooks_
319         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
320         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXECUTION_CONTEXT_CREATEED)) {
321             return;
322         }
323         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
324         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
325         loadedHooks->ExecutionContextCreated(context);
326     }
327 
ExecutionContextDestroyed(ExecutionContextWrapper context)328     void ExecutionContextDestroyed(ExecutionContextWrapper context) override
329     {
330         // Atomic with acquire order reason: data race with hooks_
331         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
332         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXECUTION_CONTEXT_DESTROYED)) {
333             return;
334         }
335         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
336         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
337         loadedHooks->ExecutionContextDestroyed(context);
338     }
339 
ExecutionContextsCleared()340     void ExecutionContextsCleared() override
341     {
342         // Atomic with acquire order reason: data race with hooks_
343         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
344         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_EXECUTION_CONTEXTS_CLEARED)) {
345             return;
346         }
347         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
348         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
349         loadedHooks->ExecutionContextsCleared();
350     }
351 
ClassLoad(PtThread thread,BaseClass * klass)352     void ClassLoad(PtThread thread, BaseClass *klass) override
353     {
354         // Atomic with acquire order reason: data race with hooks_
355         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
356         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_CLASS_LOAD)) {
357             return;
358         }
359         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
360         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
361         loadedHooks->ClassLoad(thread, klass);
362     }
363 
ClassPrepare(PtThread thread,BaseClass * klass)364     void ClassPrepare(PtThread thread, BaseClass *klass) override
365     {
366         // Atomic with acquire order reason: data race with hooks_
367         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
368         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_CLASS_PREPARE)) {
369             return;
370         }
371         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
372         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
373         loadedHooks->ClassPrepare(thread, klass);
374     }
375 
MonitorWait(PtThread thread,ObjectHeader * object,int64_t timeout)376     void MonitorWait(PtThread thread, ObjectHeader *object, int64_t timeout) override
377     {
378         // Atomic with acquire order reason: data race with hooks_
379         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
380         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_MONITOR_WAIT)) {
381             return;
382         }
383         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
384         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
385         loadedHooks->MonitorWait(thread, object, timeout);
386     }
387 
MonitorWaited(PtThread thread,ObjectHeader * object,bool timedOut)388     void MonitorWaited(PtThread thread, ObjectHeader *object, bool timedOut) override
389     {
390         // Atomic with acquire order reason: data race with hooks_
391         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
392         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_MONITOR_WAITED)) {
393             return;
394         }
395         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
396         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
397         loadedHooks->MonitorWaited(thread, object, timedOut);
398     }
399 
MonitorContendedEnter(PtThread thread,ObjectHeader * object)400     void MonitorContendedEnter(PtThread thread, ObjectHeader *object) override
401     {
402         // Atomic with acquire order reason: data race with hooks_
403         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
404         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_MONITOR_CONTENDED_ENTER)) {
405             return;
406         }
407         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
408         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
409         loadedHooks->MonitorContendedEnter(thread, object);
410     }
411 
MonitorContendedEntered(PtThread thread,ObjectHeader * object)412     void MonitorContendedEntered(PtThread thread, ObjectHeader *object) override
413     {
414         // Atomic with acquire order reason: data race with hooks_
415         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
416         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_MONITOR_CONTENDED_ENTERED)) {
417             return;
418         }
419         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
420         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
421         loadedHooks->MonitorContendedEntered(thread, object);
422     }
423 
ObjectAlloc(BaseClass * klass,ObjectHeader * object,PtThread thread,size_t size)424     void ObjectAlloc(BaseClass *klass, ObjectHeader *object, PtThread thread, size_t size) override
425     {
426         // Atomic with acquire order reason: data race with hooks_
427         auto *loadedHooks = hooks_.load(std::memory_order_acquire);
428         if (loadedHooks == nullptr || !HookIsEnabled(PtHookType::PT_HOOK_TYPE_OBJECT_ALLOC)) {
429             return;
430         }
431         // Atomic with acquire order reason: data race with vmdeath_did_not_happen_
432         ASSERT(vmdeathDidNotHappen_.load(std::memory_order_acquire));
433         loadedHooks->ObjectAlloc(klass, object, thread, size);
434     }
435 
436 private:
GlobalHookIsEnabled(PtHookType type)437     bool GlobalHookIsEnabled(PtHookType type) const
438     {
439         return globalHookTypeInfo_.IsEnabled(type);
440     }
441 
HookIsEnabled(PtHookType type)442     bool HookIsEnabled(PtHookType type) const
443     {
444         if (GlobalHookIsEnabled(type)) {
445             return true;
446         }
447 
448         ManagedThread *managedThread = ManagedThread::GetCurrent();
449         ASSERT(managedThread != nullptr);
450 
451         // Check local value
452         return managedThread->GetPtThreadInfo()->GetHookTypeInfo().IsEnabled(type);
453     }
454 
455     std::atomic<PtHooks *> hooks_ {nullptr};
456 
457     PtHookTypeInfo globalHookTypeInfo_ {true};
458 
459 #ifndef NDEBUG
460     std::atomic_bool vmdeathDidNotHappen_ {true};
461 #endif
462 };
463 }  // namespace ark::tooling
464 
465 #endif  // PANDA_RUNTIME_TOOLING_PT_HOOKS_WRAPPER_H
466