1 /** 2 * Copyright (c) 2021-2022 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 #ifndef PANDA_RUNTIME_DEBUG_DEBUG_H 16 #define PANDA_RUNTIME_DEBUG_DEBUG_H 17 18 #include <atomic> 19 #include <functional> 20 #include <memory> 21 #include <string_view> 22 23 #include "include/method.h" 24 #include "include/runtime.h" 25 #include "pt_hooks_wrapper.h" 26 #include "include/mem/panda_smart_pointers.h" 27 #include "include/mem/panda_containers.h" 28 #include "include/runtime_notification.h" 29 #include "include/tooling/debug_interface.h" 30 #include "libpandabase/os/mutex.h" 31 #include "libpandabase/utils/span.h" 32 #include "runtime/include/mem/panda_containers.h" 33 #include "runtime/include/method.h" 34 #include "runtime/include/runtime.h" 35 #include "runtime/include/panda_vm.h" 36 #include "runtime/include/tooling/debug_interface.h" 37 #include "runtime/thread_manager.h" 38 39 namespace panda::tooling { 40 // Deprecated API 41 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) 42 class Breakpoint { 43 public: 44 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) Breakpoint(Method * method,uint32_t bcOffset)45 Breakpoint(Method *method, uint32_t bcOffset) : method_(method), bcOffset_(bcOffset) {} 46 ~Breakpoint() = default; 47 GetMethod()48 Method *GetMethod() const 49 { 50 return method_; 51 } 52 GetBytecodeOffset()53 uint32_t GetBytecodeOffset() const 54 { 55 return bcOffset_; 56 } 57 58 bool operator==(const Breakpoint &bpoint) const 59 { 60 return GetMethod() == bpoint.GetMethod() && GetBytecodeOffset() == bpoint.GetBytecodeOffset(); 61 } 62 63 DEFAULT_COPY_SEMANTIC(Breakpoint); 64 DEFAULT_MOVE_SEMANTIC(Breakpoint); 65 66 private: 67 Method *method_; 68 uint32_t bcOffset_; 69 }; 70 71 // Deprecated API 72 class HashBreakpoint { 73 public: operator()74 size_t operator()(const Breakpoint &bpoint) const 75 { 76 return (std::hash<Method *>()(bpoint.GetMethod())) ^ (std::hash<uint32_t>()(bpoint.GetBytecodeOffset())); 77 } 78 }; 79 80 class HashLocation { 81 public: operator()82 size_t operator()(const PtLocation &location) const 83 { 84 return std::hash<std::string>()(location.GetPandaFile()) ^ 85 std::hash<uint32_t>()(location.GetMethodId().GetOffset()) ^ // CODECHECK-NOLINT(C_RULE_ID_INDENT_CHECK) 86 std::hash<uint32_t>()(location.GetBytecodeOffset()); // CODECHECK-NOLINT(C_RULE_ID_INDENT_CHECK) 87 } 88 }; 89 90 class PropertyWatch { 91 public: 92 enum class Type { ACCESS, MODIFY }; 93 94 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) PropertyWatch(panda_file::File::EntityId classId,panda_file::File::EntityId fieldId,Type type)95 PropertyWatch(panda_file::File::EntityId classId, panda_file::File::EntityId fieldId, Type type) 96 : classId_(classId), fieldId_(fieldId), type_(type) 97 { 98 } 99 100 ~PropertyWatch() = default; 101 GetClassId()102 panda_file::File::EntityId GetClassId() const 103 { 104 return classId_; 105 } 106 GetFieldId()107 panda_file::File::EntityId GetFieldId() const 108 { 109 return fieldId_; 110 } 111 GetType()112 Type GetType() const 113 { 114 return type_; 115 } 116 117 private: 118 NO_COPY_SEMANTIC(PropertyWatch); 119 NO_MOVE_SEMANTIC(PropertyWatch); 120 121 panda_file::File::EntityId classId_; 122 panda_file::File::EntityId fieldId_; 123 Type type_; 124 }; 125 126 // NOLINTNEXTLINE(fuchsia-multiple-inheritance) 127 class Debugger : public DebugInterface, RuntimeListener { 128 public: 129 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) Debugger(const Runtime * runtime)130 explicit Debugger(const Runtime *runtime) 131 : runtime_(runtime), 132 breakpoints_(GetInternalAllocatorAdapter(runtime)), 133 propertyWatches_(GetInternalAllocatorAdapter(runtime)), 134 vmStarted_(runtime->IsInitialized()) 135 { 136 runtime_->GetNotificationManager()->AddListener(this, DEBUG_EVENT_MASK); 137 } 138 ~Debugger()139 ~Debugger() override 140 { 141 runtime_->GetNotificationManager()->RemoveListener(this, DEBUG_EVENT_MASK); 142 } 143 GetLangExtension()144 PtLangExt *GetLangExtension() const override 145 { 146 PT_UNIMPLEMENTED(); 147 return nullptr; 148 } 149 GetPtMethod(const PtLocation &)150 Expected<PtMethod, Error> GetPtMethod(const PtLocation & /* location */) const override 151 { 152 PT_DEPRECATED(); 153 return Unexpected(Error(Error::Type::DEPRECATED, "Method is deprecated")); 154 } 155 RegisterHooks(PtHooks * hooks)156 std::optional<Error> RegisterHooks(PtHooks *hooks) override 157 { 158 hooks_.SetHooks(hooks); 159 return {}; 160 } 161 UnregisterHooks()162 std::optional<Error> UnregisterHooks() override 163 { 164 hooks_.SetHooks(nullptr); 165 return {}; 166 } 167 EnableAllGlobalHook()168 std::optional<Error> EnableAllGlobalHook() override 169 { 170 hooks_.EnableAllGlobalHook(); 171 return {}; 172 } 173 DisableAllGlobalHook()174 std::optional<Error> DisableAllGlobalHook() override 175 { 176 hooks_.DisableAllGlobalHook(); 177 return {}; 178 } 179 180 std::optional<Error> SetNotification(PtThread thread, bool enable, PtHookType hookType) override; 181 std::optional<Error> SetBreakpoint(const PtLocation &location) override; 182 183 std::optional<Error> RemoveBreakpoint(const PtLocation &location) override; 184 185 Expected<std::unique_ptr<PtFrame>, Error> GetCurrentFrame(PtThread thread) const override; 186 187 std::optional<Error> EnumerateFrames(PtThread thread, std::function<bool(const PtFrame &)> callback) const override; 188 189 // RuntimeListener methods 190 LoadModule(std::string_view filename)191 void LoadModule(std::string_view filename) override 192 { 193 hooks_.LoadModule(filename); 194 } 195 ThreadStart(ManagedThread * managedThread)196 void ThreadStart(ManagedThread *managedThread) override 197 { 198 hooks_.ThreadStart(PtThread(managedThread)); 199 } 200 ThreadEnd(ManagedThread * managedThread)201 void ThreadEnd(ManagedThread *managedThread) override 202 { 203 hooks_.ThreadEnd(PtThread(managedThread)); 204 } 205 206 void BytecodePcChanged(ManagedThread *thread, Method *method, uint32_t bcOffset) override; 207 VmStart()208 void VmStart() override 209 { 210 vmStarted_ = true; 211 hooks_.VmStart(); 212 } 213 VmInitialization(ManagedThread * managedThread)214 void VmInitialization(ManagedThread *managedThread) override 215 { 216 hooks_.VmInitialization(PtThread(managedThread)); 217 } 218 VmDeath()219 void VmDeath() override 220 { 221 hooks_.VmDeath(); 222 } 223 GarbageCollectorStart()224 void GarbageCollectorStart() override 225 { 226 hooks_.GarbageCollectionStart(); 227 } 228 GarbageCollectorFinish()229 void GarbageCollectorFinish() override 230 { 231 panda::MTManagedThread *self = panda::MTManagedThread::GetCurrent(); 232 if (self == nullptr) { 233 return; 234 } 235 hooks_.GarbageCollectionFinish(); 236 } 237 238 void ObjectAlloc(BaseClass *klass, ObjectHeader *object, ManagedThread *thread, size_t size) override; 239 240 void ExceptionThrow(ManagedThread *thread, Method *method, ObjectHeader *exceptionObject, 241 uint32_t bcOffset) override; 242 void ExceptionCatch(ManagedThread *thread, Method *method, ObjectHeader *exceptionObject, 243 uint32_t bcOffset) override; 244 ConsoleCall(ManagedThread * thread,ConsoleCallType type,uint64_t timestamp,const PandaVector<TypedValue> & arguments)245 void ConsoleCall(ManagedThread *thread, ConsoleCallType type, uint64_t timestamp, 246 const PandaVector<TypedValue> &arguments) override 247 { 248 hooks_.ConsoleCall(PtThread(thread), type, timestamp, arguments); 249 } 250 251 void MethodEntry(ManagedThread *thread, Method *method) override; 252 void MethodExit(ManagedThread *thread, Method *method) override; 253 254 void ClassLoad(Class *klass) override; 255 void ClassPrepare(Class *klass) override; 256 257 void MonitorWait(ObjectHeader *object, int64_t timeout) override; 258 void MonitorWaited(ObjectHeader *object, bool timedOut) override; 259 void MonitorContendedEnter(ObjectHeader *object) override; 260 void MonitorContendedEntered(ObjectHeader *object) override; 261 262 /* 263 * Mock API for debug interphase starts: 264 * 265 * API's function should be revorked and input parameters should be added 266 */ GetThreadList(PandaVector<PtThread> * threadList)267 std::optional<Error> GetThreadList(PandaVector<PtThread> *threadList) const override 268 { 269 runtime_->GetPandaVM()->GetThreadManager()->EnumerateThreads( 270 [threadList](ManagedThread *managedThread) { 271 ASSERT(managedThread && "thread is null"); 272 threadList->push_back(PtThread(managedThread)); 273 return true; 274 }, 275 static_cast<unsigned int>(panda::EnumerationFlag::ALL), 276 static_cast<unsigned int>(panda::EnumerationFlag::VM_THREAD)); 277 278 return {}; 279 } 280 GetThreadInfo(PtThread thread,ThreadInfo * infoPtr)281 std::optional<Error> GetThreadInfo([[maybe_unused]] PtThread thread, 282 [[maybe_unused]] ThreadInfo *infoPtr) const override 283 { 284 PT_UNIMPLEMENTED(); 285 return {}; 286 } 287 288 std::optional<Error> SuspendThread(PtThread thread) const override; 289 290 std::optional<Error> ResumeThread(PtThread thread) const override; 291 SetVariable(PtThread thread,uint32_t frameDepth,int32_t regNumber,const PtValue & value)292 std::optional<Error> SetVariable([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth, 293 [[maybe_unused]] int32_t regNumber, 294 [[maybe_unused]] const PtValue &value) const override 295 { 296 PT_UNIMPLEMENTED(); 297 return {}; 298 } 299 300 std::optional<Error> SetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber, 301 const VRegValue &value) const override; 302 GetVariable(PtThread thread,uint32_t frameDepth,int32_t regNumber,PtValue * result)303 std::optional<Error> GetVariable([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth, 304 [[maybe_unused]] int32_t regNumber, 305 [[maybe_unused]] PtValue *result) const override 306 { 307 PT_UNIMPLEMENTED(); 308 return {}; 309 } 310 311 std::optional<Error> GetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber, 312 VRegValue *result) const override; 313 GetProperty(PtObject object,PtProperty property,PtValue * value)314 std::optional<Error> GetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property, 315 [[maybe_unused]] PtValue *value) const override 316 { 317 PT_UNIMPLEMENTED(); 318 return {}; 319 } 320 SetProperty(PtObject object,PtProperty property,const PtValue & value)321 std::optional<Error> SetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property, 322 [[maybe_unused]] const PtValue &value) const override 323 { 324 PT_UNIMPLEMENTED(); 325 return {}; 326 } 327 EvaluateExpression(PtThread thread,uint32_t frameNumber,ExpressionWrapper expr,PtValue * result)328 std::optional<Error> EvaluateExpression([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameNumber, 329 [[maybe_unused]] ExpressionWrapper expr, 330 [[maybe_unused]] PtValue *result) const override 331 { 332 PT_UNIMPLEMENTED(); 333 return {}; 334 } 335 RetransformClasses(int classCount,const PtClass * classes)336 std::optional<Error> RetransformClasses([[maybe_unused]] int classCount, 337 [[maybe_unused]] const PtClass *classes) const override 338 { 339 PT_UNIMPLEMENTED(); 340 return {}; 341 } 342 RedefineClasses(int classCount,const PandaClassDefinition * classes)343 std::optional<Error> RedefineClasses([[maybe_unused]] int classCount, 344 [[maybe_unused]] const PandaClassDefinition *classes) const override 345 { 346 PT_UNIMPLEMENTED(); 347 return {}; 348 } 349 350 std::optional<Error> RestartFrame([[maybe_unused]] PtThread thread, 351 [[maybe_unused]] uint32_t frameNumber) const override; 352 SetAsyncCallStackDepth(uint32_t maxDepth)353 std::optional<Error> SetAsyncCallStackDepth([[maybe_unused]] uint32_t maxDepth) const override 354 { 355 PT_UNIMPLEMENTED(); 356 return {}; 357 } 358 AwaitPromise(PtObject promiseObject,PtValue * result)359 std::optional<Error> AwaitPromise([[maybe_unused]] PtObject promiseObject, 360 [[maybe_unused]] PtValue *result) const override 361 { 362 PT_UNIMPLEMENTED(); 363 return {}; 364 } 365 CallFunctionOn(PtObject object,PtMethod method,const PandaVector<PtValue> & arguments,PtValue * returnValue)366 std::optional<Error> CallFunctionOn([[maybe_unused]] PtObject object, [[maybe_unused]] PtMethod method, 367 [[maybe_unused]] const PandaVector<PtValue> &arguments, 368 [[maybe_unused]] PtValue *returnValue) const override 369 { 370 PT_UNIMPLEMENTED(); 371 return {}; 372 } 373 GetProperties(uint32_t * countPtr,char *** propertyPtr)374 std::optional<Error> GetProperties([[maybe_unused]] uint32_t *countPtr, 375 [[maybe_unused]] char ***propertyPtr) const override 376 { 377 PT_UNIMPLEMENTED(); 378 return {}; 379 } 380 381 std::optional<Error> NotifyFramePop(PtThread thread, uint32_t depth) const override; 382 SetPropertyAccessWatch(PtClass klass,PtProperty property)383 std::optional<Error> SetPropertyAccessWatch([[maybe_unused]] PtClass klass, 384 [[maybe_unused]] PtProperty property) override 385 { 386 PT_UNIMPLEMENTED(); 387 return {}; 388 } 389 ClearPropertyAccessWatch(PtClass klass,PtProperty property)390 std::optional<Error> ClearPropertyAccessWatch([[maybe_unused]] PtClass klass, 391 [[maybe_unused]] PtProperty property) override 392 { 393 PT_UNIMPLEMENTED(); 394 return {}; 395 } 396 SetPropertyModificationWatch(PtClass klass,PtProperty property)397 std::optional<Error> SetPropertyModificationWatch([[maybe_unused]] PtClass klass, 398 [[maybe_unused]] PtProperty property) override 399 { 400 PT_UNIMPLEMENTED(); 401 return {}; 402 } 403 ClearPropertyModificationWatch(PtClass klass,PtProperty property)404 std::optional<Error> ClearPropertyModificationWatch([[maybe_unused]] PtClass klass, 405 [[maybe_unused]] PtProperty property) override 406 { 407 PT_UNIMPLEMENTED(); 408 return {}; 409 } 410 GetThisVariableByFrame(PtThread thread,uint32_t frameDepth,PtValue * result)411 std::optional<Error> GetThisVariableByFrame([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth, 412 [[maybe_unused]] PtValue *result) override 413 { 414 PT_UNIMPLEMENTED(); 415 return {}; 416 } 417 std::optional<Error> GetThisVariableByFrame(PtThread thread, uint32_t frameDepth, ObjectHeader **thisPtr) override; 418 419 std::optional<Error> SetPropertyAccessWatch(BaseClass *klass, PtProperty property) override; 420 421 std::optional<Error> ClearPropertyAccessWatch(BaseClass *klass, PtProperty property) override; 422 423 std::optional<Error> SetPropertyModificationWatch(BaseClass *klass, PtProperty property) override; 424 425 std::optional<Error> ClearPropertyModificationWatch(BaseClass *klass, PtProperty property) override; 426 427 private: 428 Expected<interpreter::StaticVRegisterRef, Error> GetVRegByPandaFrame(panda::Frame *frame, int32_t regNumber) const; 429 Expected<interpreter::DynamicVRegisterRef, Error> GetVRegByPandaFrameDyn(panda::Frame *frame, 430 int32_t regNumber) const; 431 std::optional<Error> CheckLocation(const PtLocation &location); 432 bool IsBreakpoint(const PtLocation &location) const REQUIRES_SHARED(rwlock_); 433 bool EraseBreakpoint(const PtLocation &location); 434 IsPropertyWatchActive()435 bool IsPropertyWatchActive() const 436 { 437 os::memory::ReadLockHolder rholder(rwlock_); 438 return !propertyWatches_.empty(); 439 } 440 const tooling::PropertyWatch *FindPropertyWatch(panda_file::File::EntityId classId, 441 panda_file::File::EntityId fieldId, 442 tooling::PropertyWatch::Type type) const REQUIRES_SHARED(rwlock_); 443 bool RemovePropertyWatch(panda_file::File::EntityId classId, panda_file::File::EntityId fieldId, 444 tooling::PropertyWatch::Type type); 445 446 bool HandleBreakpoint(ManagedThread *thread, Method *method, const PtLocation &location); 447 void HandleNotifyFramePop(ManagedThread *thread, Method *method, bool wasPoppedByException); 448 bool HandleStep(ManagedThread *thread, Method *method, const PtLocation &location); 449 450 bool HandlePropertyAccess(ManagedThread *thread, Method *method, const PtLocation &location); 451 bool HandlePropertyModify(ManagedThread *thread, Method *method, const PtLocation &location); 452 453 static constexpr uint32_t DEBUG_EVENT_MASK = 454 RuntimeNotificationManager::Event::LOAD_MODULE | RuntimeNotificationManager::Event::THREAD_EVENTS | 455 RuntimeNotificationManager::Event::BYTECODE_PC_CHANGED | RuntimeNotificationManager::Event::EXCEPTION_EVENTS | 456 RuntimeNotificationManager::Event::VM_EVENTS | RuntimeNotificationManager::Event::GARBAGE_COLLECTOR_EVENTS | 457 RuntimeNotificationManager::Event::METHOD_EVENTS | RuntimeNotificationManager::Event::CLASS_EVENTS | 458 RuntimeNotificationManager::Event::MONITOR_EVENTS | RuntimeNotificationManager::Event::ALLOCATION_EVENTS | 459 RuntimeNotificationManager::Event::CONSOLE_EVENTS; 460 461 const Runtime *runtime_; 462 PtHooksWrapper hooks_; 463 464 mutable os::memory::RWLock rwlock_; 465 PandaUnorderedSet<PtLocation, HashLocation> breakpoints_ GUARDED_BY(rwlock_); 466 PandaList<PropertyWatch> propertyWatches_ GUARDED_BY(rwlock_); 467 // NOTE(m.strizhak): research how to rework VM start to avoid atomic 468 std::atomic_bool vmStarted_ {false}; 469 470 NO_COPY_SEMANTIC(Debugger); 471 NO_MOVE_SEMANTIC(Debugger); 472 }; 473 474 class PtDebugFrame : public PtFrame { 475 public: 476 explicit PANDA_PUBLIC_API PtDebugFrame(Method *method, Frame *interpreterFrame); 477 ~PtDebugFrame() override = default; 478 IsInterpreterFrame()479 bool IsInterpreterFrame() const override 480 { 481 return isInterpreterFrame_; 482 } 483 GetMethod()484 Method *GetMethod() const override 485 { 486 return method_; 487 } 488 GetVReg(size_t i)489 uint64_t GetVReg(size_t i) const override 490 { 491 if (!isInterpreterFrame_) { 492 return 0; 493 } 494 return vregs_[i]; 495 } 496 GetVRegKind(size_t i)497 RegisterKind GetVRegKind(size_t i) const override 498 { 499 if (!isInterpreterFrame_) { 500 return PtFrame::RegisterKind::PRIMITIVE; 501 } 502 return vregKinds_[i]; 503 } 504 GetVRegNum()505 size_t GetVRegNum() const override 506 { 507 return vregs_.size(); 508 } 509 GetArgument(size_t i)510 uint64_t GetArgument(size_t i) const override 511 { 512 if (!isInterpreterFrame_) { 513 return 0; 514 } 515 return args_[i]; 516 } 517 GetArgumentKind(size_t i)518 RegisterKind GetArgumentKind(size_t i) const override 519 { 520 if (!isInterpreterFrame_) { 521 return PtFrame::RegisterKind::PRIMITIVE; 522 } 523 return argKinds_[i]; 524 } 525 GetArgumentNum()526 size_t GetArgumentNum() const override 527 { 528 return args_.size(); 529 } 530 GetAccumulator()531 uint64_t GetAccumulator() const override 532 { 533 return acc_; 534 } 535 GetAccumulatorKind()536 RegisterKind GetAccumulatorKind() const override 537 { 538 return accKind_; 539 } 540 GetMethodId()541 panda_file::File::EntityId GetMethodId() const override 542 { 543 return methodId_; 544 } 545 GetBytecodeOffset()546 uint32_t GetBytecodeOffset() const override 547 { 548 return bcOffset_; 549 } 550 GetPandaFile()551 std::string GetPandaFile() const override 552 { 553 return pandaFile_; 554 } 555 556 // mock API GetFrameId()557 uint32_t GetFrameId() const override 558 { 559 return 0; 560 } 561 562 private: 563 NO_COPY_SEMANTIC(PtDebugFrame); 564 NO_MOVE_SEMANTIC(PtDebugFrame); 565 566 bool isInterpreterFrame_; 567 Method *method_; 568 uint64_t acc_ {0}; 569 RegisterKind accKind_ {PtFrame::RegisterKind::PRIMITIVE}; 570 PandaVector<uint64_t> vregs_; 571 PandaVector<RegisterKind> vregKinds_; 572 PandaVector<uint64_t> args_; 573 PandaVector<RegisterKind> argKinds_; 574 panda_file::File::EntityId methodId_; 575 uint32_t bcOffset_ {0}; 576 std::string pandaFile_; 577 }; 578 } // namespace panda::tooling 579 580 #endif // PANDA_RUNTIME_DEBUG_DEBUG_H 581