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