1 /** 2 * Copyright (c) 2021-2025 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_INCLUDE_TOOLING_DEBUG_INTERFACE_H 16 #define PANDA_RUNTIME_INCLUDE_TOOLING_DEBUG_INTERFACE_H 17 18 #include <cstdint> 19 #include <list> 20 #include <optional> 21 #include <string> 22 #include <string_view> 23 #include <vector> 24 25 #include "libpandabase/macros.h" 26 #include "libpandabase/utils/expected.h" 27 #include "libpandafile/file.h" 28 #include "runtime/include/console_call_type.h" 29 #include "runtime/include/coretypes/tagged_value.h" 30 #include "runtime/include/mem/panda_containers.h" 31 #include "runtime/include/thread.h" 32 #include "runtime/include/tooling/pt_location.h" 33 #include "runtime/include/tooling/pt_macros.h" 34 #include "runtime/include/tooling/pt_property.h" 35 #include "runtime/include/tooling/pt_thread.h" 36 #include "runtime/include/tooling/vreg_value.h" 37 #include "runtime/include/typed_value.h" 38 #include "runtime/interpreter/frame.h" 39 40 namespace ark::tooling { 41 class Error { 42 public: 43 enum class Type { 44 BREAKPOINT_NOT_FOUND, 45 BREAKPOINT_ALREADY_EXISTS, 46 ENTRY_POINT_RESOLVE_ERROR, 47 FRAME_NOT_FOUND, 48 NO_MORE_FRAMES, 49 OPAQUE_FRAME, 50 INVALID_BREAKPOINT, 51 INVALID_ENTRY_POINT, 52 METHOD_NOT_FOUND, 53 PANDA_FILE_LOAD_ERROR, 54 THREAD_NOT_FOUND, 55 THREAD_NOT_SUSPENDED, 56 INVALID_REGISTER, 57 INVALID_VALUE, 58 INVALID_EXPRESSION, 59 PROPERTY_ACCESS_WATCH_NOT_FOUND, 60 INVALID_PROPERTY_ACCESS_WATCH, 61 PROPERTY_MODIFY_WATCH_NOT_FOUND, 62 INVALID_PROPERTY_MODIFY_WATCH, 63 DEPRECATED, 64 }; 65 Error(Type type,std::string msg)66 Error(Type type, std::string msg) : type_(type), msg_(std::move(msg)) {} 67 GetType()68 Type GetType() const 69 { 70 return type_; 71 } 72 GetMessage()73 std::string GetMessage() const 74 { 75 return msg_; 76 } 77 78 ~Error() = default; 79 80 DEFAULT_COPY_SEMANTIC(Error); 81 DEFAULT_MOVE_SEMANTIC(Error); 82 83 private: 84 Type type_; 85 std::string msg_; 86 }; 87 88 class PtFrame { 89 public: 90 enum class RegisterKind { PRIMITIVE, REFERENCE, TAGGED }; 91 92 PtFrame() = default; 93 94 virtual bool IsInterpreterFrame() const = 0; 95 96 virtual Method *GetMethod() const = 0; 97 98 virtual uint64_t GetVReg(size_t i) const = 0; 99 100 virtual RegisterKind GetVRegKind(size_t i) const = 0; 101 102 virtual size_t GetVRegNum() const = 0; 103 104 virtual uint64_t GetArgument(size_t i) const = 0; 105 106 virtual RegisterKind GetArgumentKind(size_t i) const = 0; 107 108 virtual size_t GetArgumentNum() const = 0; 109 110 virtual uint64_t GetAccumulator() const = 0; 111 112 virtual RegisterKind GetAccumulatorKind() const = 0; 113 114 virtual panda_file::File::EntityId GetMethodId() const = 0; 115 116 virtual uint32_t GetBytecodeOffset() const = 0; 117 118 virtual std::string GetPandaFile() const = 0; 119 120 // mock API 121 virtual uint32_t GetFrameId() const = 0; 122 123 virtual ~PtFrame() = default; 124 125 NO_COPY_SEMANTIC(PtFrame); 126 NO_MOVE_SEMANTIC(PtFrame); 127 }; 128 129 struct PtStepRange { 130 uint32_t startBcOffset {0}; 131 uint32_t endBcOffset {0}; 132 }; 133 134 // * * * * * 135 // Mock API helpers 136 // NOTE(maksenov): cleanup 137 // * * * * * 138 139 using ExceptionID = panda_file::File::EntityId; 140 using ExecutionContextId = panda_file::File::EntityId; 141 using ThreadGroup = uint32_t; 142 143 using ExpressionWrapper = std::string; 144 using ExceptionWrapper = std::string; 145 146 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) 147 struct ThreadInfo { 148 char *name; 149 size_t nameLength; 150 int32_t priority; 151 bool isDaemon; 152 ThreadGroup threadGroup; 153 }; 154 155 enum PauseReason { 156 AMBIGUOUS, 157 ASSERT, 158 DEBUGCOMMAND, 159 DOM, 160 EVENTLISTENER, 161 EXCEPTION, 162 INSTRUMENTATION, 163 OOM, 164 OTHER, 165 PROMISEREJECTION, 166 XHR, 167 BREAK_ON_START, 168 STEP 169 }; 170 171 struct ExecutionContextWrapper { 172 ExecutionContextId id; 173 std::string origin; 174 std::string name; 175 }; 176 177 enum class PtHookType { 178 PT_HOOK_TYPE_BREAKPOINT, 179 PT_HOOK_TYPE_LOAD_MODULE, 180 PT_HOOK_TYPE_PAUSED, 181 PT_HOOK_TYPE_EXCEPTION, 182 PT_HOOK_TYPE_EXCEPTION_CATCH, 183 PT_HOOK_TYPE_PROPERTY_ACCESS, 184 PT_HOOK_TYPE_PROPERTY_MODIFICATION, 185 PT_HOOK_TYPE_CONSOLE_CALL, 186 PT_HOOK_TYPE_FRAME_POP, 187 PT_HOOK_TYPE_GARBAGE_COLLECTION_START, 188 PT_HOOK_TYPE_GARBAGE_COLLECTION_FINISH, 189 PT_HOOK_TYPE_METHOD_ENTRY, 190 PT_HOOK_TYPE_METHOD_EXIT, 191 PT_HOOK_TYPE_SINGLE_STEP, 192 PT_HOOK_TYPE_THREAD_START, 193 PT_HOOK_TYPE_THREAD_END, 194 PT_HOOK_TYPE_VM_DEATH, 195 PT_HOOK_TYPE_VM_INITIALIZATION, 196 PT_HOOK_TYPE_VM_START, 197 PT_HOOK_TYPE_EXCEPTION_REVOKED, 198 PT_HOOK_TYPE_EXECUTION_CONTEXT_CREATEED, 199 PT_HOOK_TYPE_EXECUTION_CONTEXT_DESTROYED, 200 PT_HOOK_TYPE_EXECUTION_CONTEXTS_CLEARED, 201 PT_HOOK_TYPE_INSPECT_REQUESTED, 202 PT_HOOK_TYPE_CLASS_LOAD, 203 PT_HOOK_TYPE_CLASS_PREPARE, 204 PT_HOOK_TYPE_MONITOR_WAIT, 205 PT_HOOK_TYPE_MONITOR_WAITED, 206 PT_HOOK_TYPE_MONITOR_CONTENDED_ENTER, 207 PT_HOOK_TYPE_MONITOR_CONTENDED_ENTERED, 208 PT_HOOK_TYPE_OBJECT_ALLOC, 209 // The count of hooks. Don't move 210 PT_HOOK_TYPE_COUNT 211 }; 212 213 // * * * * * 214 // Mock API helpers ends 215 // * * * * * 216 217 class PtHooks { 218 public: 219 PtHooks() = default; 220 221 /** 222 * @brief Method is called by the runtime when breakpoint hits. Thread where breakpoint hits is stopped until 223 * continue or step event will be received 224 * @param thread Identifier of the thread where breakpoint hits. Now the callback is called in the same 225 * thread 226 * @param method Method 227 * @param location Breakpoint location 228 */ Breakpoint(PtThread,Method *,const PtLocation &)229 virtual void Breakpoint(PtThread /* thread */, Method * /* method */, const PtLocation & /* location */) {} 230 231 /** 232 * @brief Method is called by the runtime when panda file is loaded 233 * @param pandaFileName Path to panda file that is loaded 234 */ LoadModule(std::string_view)235 virtual void LoadModule(std::string_view /* pandaFileName */) {} 236 237 /** 238 * @brief Method is called by the runtime when managed thread is attached to it 239 * @param thread The attached thread 240 */ ThreadStart(PtThread)241 virtual void ThreadStart(PtThread /* thread */) {} 242 243 /** 244 * @brief Method is called by the runtime when managed thread is detached 245 * @param thread The detached thread 246 */ ThreadEnd(PtThread)247 virtual void ThreadEnd(PtThread /* thread */) {} 248 249 /// @brief Method is called by the runtime when virtual machine start initialization VmStart()250 virtual void VmStart() {} 251 252 /** 253 * @brief Method is called by the runtime when virtual machine finish initialization 254 * @param thread The initial thread 255 */ VmInitialization(PtThread)256 virtual void VmInitialization(PtThread /* thread */) {} 257 258 /// @brief Method is called by the runtime when virtual machine death VmDeath()259 virtual void VmDeath() {} 260 261 /** 262 * @brief Method is called by the runtime when a class is first loaded 263 * @param thread Thread loading the class 264 * @param klass Class being loaded 265 */ ClassLoad(PtThread,BaseClass *)266 virtual void ClassLoad(PtThread /* thread */, BaseClass * /* klass */) {} 267 268 /** 269 * @brief Method is called by the runtime when class preparation is complete 270 * @param thread Thread generating the class prepare 271 * @param klass Class being prepared 272 */ ClassPrepare(PtThread,BaseClass *)273 virtual void ClassPrepare(PtThread /* thread */, BaseClass * /* klass */) {} 274 275 /** 276 * @brief Method is called by the runtime when a thread is about to wait on an object 277 * @param thread The thread about to wait 278 * @param object Reference to the monitor 279 * @param timeout The number of milliseconds the thread will wait 280 */ MonitorWait(PtThread,ObjectHeader *,int64_t)281 virtual void MonitorWait(PtThread /* thread */, ObjectHeader * /* object */, int64_t /* timeout */) {} 282 283 /** 284 * @brief Method is called by the runtime when a thread finishes waiting on an object 285 * @param thread The thread about to wait 286 * @param object Reference to the monitor 287 * @param timedOut True if the monitor timed out 288 */ MonitorWaited(PtThread,ObjectHeader *,bool)289 virtual void MonitorWaited(PtThread /* thread */, ObjectHeader * /* object */, bool /* timedOut */) {} 290 291 /** 292 * @brief Method is called by the runtime when a thread is attempting to enter a monitor already acquired by another 293 * thread 294 * @param thread The thread about to wait 295 * @param object Reference to the monitor 296 */ MonitorContendedEnter(PtThread,ObjectHeader *)297 virtual void MonitorContendedEnter(PtThread /* thread */, ObjectHeader * /* object */) {} 298 299 /** 300 * @brief Method is called by the runtime when a thread enters a monitor after waiting for it to be released by 301 * another thread 302 * @param thread The thread about to wait 303 * @param object Reference to the monitor 304 */ MonitorContendedEntered(PtThread,ObjectHeader *)305 virtual void MonitorContendedEntered(PtThread /* thread */, ObjectHeader * /* object */) {} 306 Exception(PtThread,Method *,const PtLocation &,ObjectHeader *,Method *,const PtLocation &)307 virtual void Exception(PtThread /* thread */, Method * /* method */, const PtLocation & /* location */, 308 ObjectHeader * /* exceptionObject */, Method * /* catchMethod */, 309 const PtLocation & /* catchLocation */) 310 { 311 } 312 ExceptionCatch(PtThread,Method *,const PtLocation &,ObjectHeader *)313 virtual void ExceptionCatch(PtThread /* thread */, Method * /* catchMethod */, const PtLocation & /* location */, 314 ObjectHeader * /* exceptionObject */) 315 { 316 } 317 PropertyAccess(PtThread,Method *,const PtLocation &,ObjectHeader *,PtProperty)318 virtual void PropertyAccess(PtThread /* thread */, Method * /* catchMethod */, const PtLocation & /* location */, 319 ObjectHeader * /* object */, PtProperty /* property */) 320 { 321 } 322 PropertyModification(PtThread,Method *,const PtLocation &,ObjectHeader *,PtProperty,VRegValue)323 virtual void PropertyModification(PtThread /* thread */, Method * /* method */, const PtLocation & /* location */, 324 ObjectHeader * /* object */, PtProperty /* property */, VRegValue /* newValue */) 325 { 326 } 327 ConsoleCall(PtThread,ConsoleCallType,uint64_t,const PandaVector<TypedValue> &)328 virtual void ConsoleCall(PtThread /* thread */, ConsoleCallType /* type */, uint64_t /* timestamp */, 329 const PandaVector<TypedValue> & /* arguments */) 330 { 331 } 332 FramePop(PtThread,Method *,bool)333 virtual void FramePop(PtThread /* thread */, Method * /* method */, bool /* wasPoppedByException */) {} 334 GarbageCollectionFinish()335 virtual void GarbageCollectionFinish() {} 336 GarbageCollectionStart()337 virtual void GarbageCollectionStart() {} 338 ObjectAlloc(BaseClass *,ObjectHeader *,PtThread,size_t)339 virtual void ObjectAlloc(BaseClass * /* klass */, ObjectHeader * /* object */, PtThread /* thread */, 340 size_t /* size */) 341 { 342 } 343 MethodEntry(PtThread,Method *)344 virtual void MethodEntry(PtThread /* thread */, Method * /* method */) {} 345 MethodExit(PtThread,Method *,bool,VRegValue)346 virtual void MethodExit(PtThread /* thread */, Method * /* method */, bool /* wasPoppedByException */, 347 VRegValue /* returnValue */) 348 { 349 } 350 SingleStep(PtThread,Method *,const PtLocation &)351 virtual void SingleStep(PtThread /* thread */, Method * /* method */, const PtLocation & /* location */) {} 352 353 // * * * * * 354 // Deprecated hooks 355 // * * * * * 356 Paused(PauseReason)357 virtual void Paused(PauseReason /* reason */) {} Breakpoint(PtThread,const PtLocation &)358 virtual void Breakpoint(PtThread /* thread */, const PtLocation & /* location */) {} SingleStep(PtThread,const PtLocation &)359 virtual void SingleStep(PtThread /* thread */, const PtLocation & /* location */) {} 360 361 // NOLINTNEXTLINE(performance-unnecessary-value-param) ExceptionRevoked(ExceptionWrapper,ExceptionID)362 virtual void ExceptionRevoked(ExceptionWrapper /* reason */, ExceptionID /* exceptionId */) {} 363 364 // NOLINTNEXTLINE(performance-unnecessary-value-param) ExecutionContextCreated(ExecutionContextWrapper)365 virtual void ExecutionContextCreated(ExecutionContextWrapper /* context */) {} 366 367 // NOLINTNEXTLINE(performance-unnecessary-value-param) ExecutionContextDestroyed(ExecutionContextWrapper)368 virtual void ExecutionContextDestroyed(ExecutionContextWrapper /* context */) {} 369 ExecutionContextsCleared()370 virtual void ExecutionContextsCleared() {} 371 372 // * * * * * 373 // Deprecated hooks end 374 // * * * * * 375 376 virtual ~PtHooks() = default; 377 378 NO_COPY_SEMANTIC(PtHooks); 379 NO_MOVE_SEMANTIC(PtHooks); 380 }; 381 382 class DebugInterface { 383 public: 384 DebugInterface() = default; 385 386 /** 387 * @brief Register debug hooks in the runtime 388 * @param hooks Pointer to object that implements PtHooks interface 389 * @return Error if any errors occur 390 */ 391 virtual std::optional<Error> RegisterHooks(PtHooks *hooks) = 0; 392 393 /** 394 * @brief Unregister debug hooks in the runtime 395 * @return Error if any errors occur 396 */ 397 virtual std::optional<Error> UnregisterHooks() = 0; 398 399 /** 400 * @brief Enable all debug hooks in the runtime 401 * @return Error if any errors occur 402 */ 403 virtual std::optional<Error> EnableAllGlobalHook() = 0; 404 405 /** 406 * @brief Disable all debug hooks in the runtime 407 * @return Error if any errors occur 408 */ 409 virtual std::optional<Error> DisableAllGlobalHook() = 0; 410 411 /** 412 * @brief Set notification to hook (enable/disable). 413 * @param thread If thread is NONE, the notification is enabled or disabled globally 414 * @param enable Enable or disable notifications (true - enable, false - disable) 415 * @param hook_type Type of hook that must be enabled or disabled 416 * @return Error if any errors occur 417 */ 418 virtual std::optional<Error> SetNotification(PtThread thread, bool enable, PtHookType hookType) = 0; 419 420 /** 421 * @brief Set breakpoint to @param location 422 * @param location Breakpoint location 423 * @return Error if any errors occur 424 */ 425 virtual std::optional<Error> SetBreakpoint(const PtLocation &location) = 0; 426 427 /** 428 * @brief Remove breakpoint from @param location 429 * @param location Breakpoint location 430 * @return Error if any errors occur 431 */ 432 virtual std::optional<Error> RemoveBreakpoint(const PtLocation &location) = 0; 433 434 /** 435 * @brief Get Frame 436 * @param thread Identifier of the thread 437 * @return Frame object that implements PtFrame or Error if any errors occur 438 */ 439 virtual Expected<std::unique_ptr<PtFrame>, Error> GetCurrentFrame(PtThread thread) const = 0; 440 441 /** 442 * @brief Enumerates managed frames in the thread @param threadId 443 * @param thread Identifier of the thread 444 * @param callback Callback that is called for each frame. Should return true to continue and false to stop 445 * enumerating 446 * @return Error if any errors occur 447 */ 448 virtual std::optional<Error> EnumerateFrames(PtThread thread, 449 std::function<bool(const PtFrame &)> callback) const = 0; 450 451 /** 452 * @brief Suspend thread 453 * @param thread Identifier of the thread 454 * @return Error if any errors occur 455 */ 456 virtual std::optional<Error> SuspendThread(PtThread thread) const = 0; 457 458 /** 459 * @brief Resume thread 460 * @param thread Identifier of the thread 461 * @return Error if any errors occur 462 */ 463 virtual std::optional<Error> ResumeThread(PtThread thread) const = 0; 464 465 virtual ~DebugInterface() = default; 466 467 virtual std::optional<Error> GetThreadList(PandaVector<PtThread> *threadList) const = 0; 468 SetVariable(PtThread,uint32_t,int32_t,const VRegValue &)469 virtual std::optional<Error> SetVariable(PtThread /* thread */, uint32_t /* frameDepth */, int32_t /* regNumber */, 470 const VRegValue & /* value */) const 471 { 472 return {}; 473 } 474 GetVariable(PtThread,uint32_t,int32_t,VRegValue *)475 virtual std::optional<Error> GetVariable(PtThread /* thread */, uint32_t /* frameDepth */, int32_t /* regNumber */, 476 VRegValue * /* value */) const 477 { 478 return {}; 479 } 480 481 virtual std::optional<Error> EvaluateExpression(PtThread thread, uint32_t frameNumber, 482 const ExpressionWrapper &expr, Method **method, 483 VRegValue *result) const = 0; 484 485 virtual std::optional<Error> EvaluateExpression(PtThread thread, uint32_t frameNumber, Method *method, 486 VRegValue *result) const = 0; 487 488 virtual std::optional<Error> GetThreadInfo(PtThread thread, ThreadInfo *infoPtr) const = 0; 489 490 virtual std::optional<Error> RestartFrame(PtThread thread, uint32_t frameNumber) const = 0; 491 492 virtual std::optional<Error> SetAsyncCallStackDepth(uint32_t maxDepth) const = 0; 493 494 virtual std::optional<Error> GetProperties(uint32_t *countPtr, char ***propertyPtr) const = 0; 495 496 virtual std::optional<Error> NotifyFramePop(PtThread thread, uint32_t depth) const = 0; 497 GetThisVariableByFrame(PtThread,uint32_t,ObjectHeader **)498 virtual std::optional<Error> GetThisVariableByFrame(PtThread /* thread */, uint32_t /* frameDepth */, 499 ObjectHeader ** /* this_ptr */) 500 { 501 return {}; 502 } 503 SetPropertyAccessWatch(BaseClass *,PtProperty)504 virtual std::optional<Error> SetPropertyAccessWatch(BaseClass * /* klass */, PtProperty /* property */) 505 { 506 return {}; 507 } 508 ClearPropertyAccessWatch(BaseClass *,PtProperty)509 virtual std::optional<Error> ClearPropertyAccessWatch(BaseClass * /* klass */, PtProperty /* property */) 510 { 511 return {}; 512 } 513 SetPropertyModificationWatch(BaseClass *,PtProperty)514 virtual std::optional<Error> SetPropertyModificationWatch(BaseClass * /* klass */, PtProperty /* property */) 515 { 516 return {}; 517 } 518 ClearPropertyModificationWatch(BaseClass *,PtProperty)519 virtual std::optional<Error> ClearPropertyModificationWatch(BaseClass * /* klass */, PtProperty /* property */) 520 { 521 return {}; 522 } 523 524 NO_COPY_SEMANTIC(DebugInterface); 525 NO_MOVE_SEMANTIC(DebugInterface); 526 }; 527 } // namespace ark::tooling 528 529 #endif // PANDA_RUNTIME_INCLUDE_TOOLING_DEBUG_INTERFACE_H 530