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), bc_offset_(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 bc_offset_; 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 bc_offset_; 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 : class_id_(classId), field_id_(fieldId), type_(type) 97 { 98 } 99 100 ~PropertyWatch() = default; 101 GetClassId()102 panda_file::File::EntityId GetClassId() const 103 { 104 return class_id_; 105 } 106 GetFieldId()107 panda_file::File::EntityId GetFieldId() const 108 { 109 return field_id_; 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 class_id_; 122 panda_file::File::EntityId field_id_; 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 property_watches_(GetInternalAllocatorAdapter(runtime)), 134 vm_started_(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 * managed_thread)196 void ThreadStart(ManagedThread *managed_thread) override 197 { 198 hooks_.ThreadStart(PtThread(managed_thread)); 199 } 200 ThreadEnd(ManagedThread * managed_thread)201 void ThreadEnd(ManagedThread *managed_thread) override 202 { 203 hooks_.ThreadEnd(PtThread(managed_thread)); 204 } 205 206 void BytecodePcChanged(ManagedThread *thread, Method *method, uint32_t bcOffset) override; 207 VmStart()208 void VmStart() override 209 { 210 vm_started_ = true; 211 hooks_.VmStart(); 212 } 213 VmInitialization(ManagedThread * managed_thread)214 void VmInitialization(ManagedThread *managed_thread) override 215 { 216 hooks_.VmInitialization(PtThread(managed_thread)); 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 245 void MethodEntry(ManagedThread *thread, Method *method) override; 246 void MethodExit(ManagedThread *thread, Method *method) override; 247 248 void ClassLoad(Class *klass) override; 249 void ClassPrepare(Class *klass) override; 250 251 void MonitorWait(ObjectHeader *object, int64_t timeout) override; 252 void MonitorWaited(ObjectHeader *object, bool timedOut) override; 253 void MonitorContendedEnter(ObjectHeader *object) override; 254 void MonitorContendedEntered(ObjectHeader *object) override; 255 256 /* 257 * Mock API for debug interphase starts: 258 * 259 * API's function should be revorked and input parameters should be added 260 */ GetThreadList(PandaVector<PtThread> * threadList)261 std::optional<Error> GetThreadList(PandaVector<PtThread> *threadList) const override 262 { 263 runtime_->GetPandaVM()->GetThreadManager()->EnumerateThreads( 264 [threadList](MTManagedThread *mt_managed_thread) { 265 ASSERT(mt_managed_thread && "thread is null"); 266 threadList->push_back(PtThread(mt_managed_thread)); 267 return true; 268 }, 269 static_cast<unsigned int>(panda::EnumerationFlag::ALL), 270 static_cast<unsigned int>(panda::EnumerationFlag::VM_THREAD)); 271 272 return {}; 273 } 274 GetThreadInfo(PtThread thread,ThreadInfo * infoPtr)275 std::optional<Error> GetThreadInfo([[maybe_unused]] PtThread thread, 276 [[maybe_unused]] ThreadInfo *infoPtr) const override 277 { 278 PT_UNIMPLEMENTED(); 279 return {}; 280 } 281 282 std::optional<Error> SuspendThread(PtThread thread) const override; 283 284 std::optional<Error> ResumeThread(PtThread thread) const override; 285 SetVariable(PtThread thread,uint32_t frameDepth,int32_t regNumber,const PtValue & value)286 std::optional<Error> SetVariable([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth, 287 [[maybe_unused]] int32_t regNumber, 288 [[maybe_unused]] const PtValue &value) const override 289 { 290 PT_UNIMPLEMENTED(); 291 return {}; 292 } 293 294 std::optional<Error> SetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber, 295 const VRegValue &value) const override; 296 GetVariable(PtThread thread,uint32_t frameDepth,int32_t regNumber,PtValue * result)297 std::optional<Error> GetVariable([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth, 298 [[maybe_unused]] int32_t regNumber, 299 [[maybe_unused]] PtValue *result) const override 300 { 301 PT_UNIMPLEMENTED(); 302 return {}; 303 } 304 305 std::optional<Error> GetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber, 306 VRegValue *result) const override; 307 GetProperty(PtObject object,PtProperty property,PtValue * value)308 std::optional<Error> GetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property, 309 [[maybe_unused]] PtValue *value) const override 310 { 311 PT_UNIMPLEMENTED(); 312 return {}; 313 } 314 SetProperty(PtObject object,PtProperty property,const PtValue & value)315 std::optional<Error> SetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property, 316 [[maybe_unused]] const PtValue &value) const override 317 { 318 PT_UNIMPLEMENTED(); 319 return {}; 320 } 321 EvaluateExpression(PtThread thread,uint32_t frameNumber,ExpressionWrapper expr,PtValue * result)322 std::optional<Error> EvaluateExpression([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameNumber, 323 [[maybe_unused]] ExpressionWrapper expr, 324 [[maybe_unused]] PtValue *result) const override 325 { 326 PT_UNIMPLEMENTED(); 327 return {}; 328 } 329 RetransformClasses(int classCount,const PtClass * classes)330 std::optional<Error> RetransformClasses([[maybe_unused]] int classCount, 331 [[maybe_unused]] const PtClass *classes) const override 332 { 333 PT_UNIMPLEMENTED(); 334 return {}; 335 } 336 RedefineClasses(int classCount,const PandaClassDefinition * classes)337 std::optional<Error> RedefineClasses([[maybe_unused]] int classCount, 338 [[maybe_unused]] const PandaClassDefinition *classes) const override 339 { 340 PT_UNIMPLEMENTED(); 341 return {}; 342 } 343 344 std::optional<Error> RestartFrame([[maybe_unused]] PtThread thread, 345 [[maybe_unused]] uint32_t frameNumber) const override; 346 SetAsyncCallStackDepth(uint32_t maxDepth)347 std::optional<Error> SetAsyncCallStackDepth([[maybe_unused]] uint32_t maxDepth) const override 348 { 349 PT_UNIMPLEMENTED(); 350 return {}; 351 } 352 AwaitPromise(PtObject promiseObject,PtValue * result)353 std::optional<Error> AwaitPromise([[maybe_unused]] PtObject promiseObject, 354 [[maybe_unused]] PtValue *result) const override 355 { 356 PT_UNIMPLEMENTED(); 357 return {}; 358 } 359 CallFunctionOn(PtObject object,PtMethod method,const PandaVector<PtValue> & arguments,PtValue * returnValue)360 std::optional<Error> CallFunctionOn([[maybe_unused]] PtObject object, [[maybe_unused]] PtMethod method, 361 [[maybe_unused]] const PandaVector<PtValue> &arguments, 362 [[maybe_unused]] PtValue *returnValue) const override 363 { 364 PT_UNIMPLEMENTED(); 365 return {}; 366 } 367 GetProperties(uint32_t * countPtr,char *** propertyPtr)368 std::optional<Error> GetProperties([[maybe_unused]] uint32_t *countPtr, 369 [[maybe_unused]] char ***propertyPtr) const override 370 { 371 PT_UNIMPLEMENTED(); 372 return {}; 373 } 374 375 std::optional<Error> NotifyFramePop(PtThread thread, uint32_t depth) const override; 376 SetPropertyAccessWatch(PtClass klass,PtProperty property)377 std::optional<Error> SetPropertyAccessWatch([[maybe_unused]] PtClass klass, 378 [[maybe_unused]] PtProperty property) override 379 { 380 PT_UNIMPLEMENTED(); 381 return {}; 382 } 383 ClearPropertyAccessWatch(PtClass klass,PtProperty property)384 std::optional<Error> ClearPropertyAccessWatch([[maybe_unused]] PtClass klass, 385 [[maybe_unused]] PtProperty property) override 386 { 387 PT_UNIMPLEMENTED(); 388 return {}; 389 } 390 SetPropertyModificationWatch(PtClass klass,PtProperty property)391 std::optional<Error> SetPropertyModificationWatch([[maybe_unused]] PtClass klass, 392 [[maybe_unused]] PtProperty property) override 393 { 394 PT_UNIMPLEMENTED(); 395 return {}; 396 } 397 ClearPropertyModificationWatch(PtClass klass,PtProperty property)398 std::optional<Error> ClearPropertyModificationWatch([[maybe_unused]] PtClass klass, 399 [[maybe_unused]] PtProperty property) override 400 { 401 PT_UNIMPLEMENTED(); 402 return {}; 403 } 404 GetThisVariableByFrame(PtThread thread,uint32_t frameDepth,PtValue * result)405 std::optional<Error> GetThisVariableByFrame([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth, 406 [[maybe_unused]] PtValue *result) override 407 { 408 PT_UNIMPLEMENTED(); 409 return {}; 410 } 411 std::optional<Error> GetThisVariableByFrame(PtThread thread, uint32_t frameDepth, ObjectHeader **thisPtr) override; 412 413 std::optional<Error> SetPropertyAccessWatch(BaseClass *klass, PtProperty property) override; 414 415 std::optional<Error> ClearPropertyAccessWatch(BaseClass *klass, PtProperty property) override; 416 417 std::optional<Error> SetPropertyModificationWatch(BaseClass *klass, PtProperty property) override; 418 419 std::optional<Error> ClearPropertyModificationWatch(BaseClass *klass, PtProperty property) override; 420 421 private: 422 Expected<interpreter::StaticVRegisterRef, Error> GetVRegByPandaFrame(panda::Frame *frame, int32_t regNumber) const; 423 Expected<interpreter::DynamicVRegisterRef, Error> GetVRegByPandaFrameDyn(panda::Frame *frame, 424 int32_t regNumber) const; 425 std::optional<Error> CheckLocation(const PtLocation &location); 426 bool IsBreakpoint(const PtLocation &location) const REQUIRES_SHARED(rwlock_); 427 bool EraseBreakpoint(const PtLocation &location); 428 IsPropertyWatchActive()429 bool IsPropertyWatchActive() const 430 { 431 os::memory::ReadLockHolder rholder(rwlock_); 432 return !property_watches_.empty(); 433 } 434 const tooling::PropertyWatch *FindPropertyWatch(panda_file::File::EntityId classId, 435 panda_file::File::EntityId fieldId, 436 tooling::PropertyWatch::Type type) const REQUIRES_SHARED(rwlock_); 437 bool RemovePropertyWatch(panda_file::File::EntityId classId, panda_file::File::EntityId fieldId, 438 tooling::PropertyWatch::Type type); 439 440 bool HandleBreakpoint(ManagedThread *thread, Method *method, const PtLocation &location); 441 void HandleNotifyFramePop(ManagedThread *thread, Method *method, bool wasPoppedByException); 442 bool HandleStep(ManagedThread *thread, Method *method, const PtLocation &location); 443 444 bool HandlePropertyAccess(ManagedThread *thread, Method *method, const PtLocation &location); 445 bool HandlePropertyModify(ManagedThread *thread, Method *method, const PtLocation &location); 446 447 static constexpr uint32_t DEBUG_EVENT_MASK = 448 RuntimeNotificationManager::Event::LOAD_MODULE | RuntimeNotificationManager::Event::THREAD_EVENTS | 449 RuntimeNotificationManager::Event::BYTECODE_PC_CHANGED | RuntimeNotificationManager::Event::EXCEPTION_EVENTS | 450 RuntimeNotificationManager::Event::VM_EVENTS | RuntimeNotificationManager::Event::GARBAGE_COLLECTOR_EVENTS | 451 RuntimeNotificationManager::Event::METHOD_EVENTS | RuntimeNotificationManager::Event::CLASS_EVENTS | 452 RuntimeNotificationManager::Event::MONITOR_EVENTS | RuntimeNotificationManager::Event::ALLOCATION_EVENTS; 453 454 const Runtime *runtime_; 455 PtHooksWrapper hooks_; 456 457 mutable os::memory::RWLock rwlock_; 458 PandaUnorderedSet<PtLocation, HashLocation> breakpoints_ GUARDED_BY(rwlock_); 459 PandaList<PropertyWatch> property_watches_ GUARDED_BY(rwlock_); 460 // TODO(m.strizhak): research how to rework VM start to avoid atomic 461 std::atomic_bool vm_started_ {false}; 462 463 NO_COPY_SEMANTIC(Debugger); 464 NO_MOVE_SEMANTIC(Debugger); 465 }; 466 467 class PtDebugFrame : public PtFrame { 468 public: 469 explicit PtDebugFrame(Method *method, Frame *interpreterFrame); 470 ~PtDebugFrame() override = default; 471 IsInterpreterFrame()472 bool IsInterpreterFrame() const override 473 { 474 return is_interpreter_frame_; 475 } 476 GetMethod()477 Method *GetMethod() const override 478 { 479 return method_; 480 } 481 GetVReg(size_t i)482 uint64_t GetVReg(size_t i) const override 483 { 484 if (!is_interpreter_frame_) { 485 return 0; 486 } 487 return vregs_[i]; 488 } 489 GetVRegNum()490 size_t GetVRegNum() const override 491 { 492 return vregs_.size(); 493 } 494 GetArgument(size_t i)495 uint64_t GetArgument(size_t i) const override 496 { 497 if (!is_interpreter_frame_) { 498 return 0; 499 } 500 return args_[i]; 501 } 502 GetArgumentNum()503 size_t GetArgumentNum() const override 504 { 505 return args_.size(); 506 } 507 GetAccumulator()508 uint64_t GetAccumulator() const override 509 { 510 return acc_; 511 } 512 GetMethodId()513 panda_file::File::EntityId GetMethodId() const override 514 { 515 return method_id_; 516 } 517 GetBytecodeOffset()518 uint32_t GetBytecodeOffset() const override 519 { 520 return bc_offset_; 521 } 522 GetPandaFile()523 std::string GetPandaFile() const override 524 { 525 return panda_file_; 526 } 527 528 // mock API GetFrameId()529 uint32_t GetFrameId() const override 530 { 531 return 0; 532 } 533 534 private: 535 NO_COPY_SEMANTIC(PtDebugFrame); 536 NO_MOVE_SEMANTIC(PtDebugFrame); 537 538 bool is_interpreter_frame_; 539 Method *method_; 540 uint64_t acc_ {0}; 541 PandaVector<uint64_t> vregs_; 542 PandaVector<uint64_t> args_; 543 panda_file::File::EntityId method_id_; 544 uint32_t bc_offset_ {0}; 545 std::string panda_file_; 546 }; 547 } // namespace panda::tooling 548 549 #endif // PANDA_RUNTIME_DEBUG_DEBUG_H 550