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 #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 }; 169 170 struct ExecutionContextWrapper { 171 ExecutionContextId id; 172 std::string origin; 173 std::string name; 174 }; 175 176 enum class PtHookType { 177 PT_HOOK_TYPE_BREAKPOINT, 178 PT_HOOK_TYPE_LOAD_MODULE, 179 PT_HOOK_TYPE_PAUSED, 180 PT_HOOK_TYPE_EXCEPTION, 181 PT_HOOK_TYPE_EXCEPTION_CATCH, 182 PT_HOOK_TYPE_PROPERTY_ACCESS, 183 PT_HOOK_TYPE_PROPERTY_MODIFICATION, 184 PT_HOOK_TYPE_CONSOLE_CALL, 185 PT_HOOK_TYPE_FRAME_POP, 186 PT_HOOK_TYPE_GARBAGE_COLLECTION_START, 187 PT_HOOK_TYPE_GARBAGE_COLLECTION_FINISH, 188 PT_HOOK_TYPE_METHOD_ENTRY, 189 PT_HOOK_TYPE_METHOD_EXIT, 190 PT_HOOK_TYPE_SINGLE_STEP, 191 PT_HOOK_TYPE_THREAD_START, 192 PT_HOOK_TYPE_THREAD_END, 193 PT_HOOK_TYPE_VM_DEATH, 194 PT_HOOK_TYPE_VM_INITIALIZATION, 195 PT_HOOK_TYPE_VM_START, 196 PT_HOOK_TYPE_EXCEPTION_REVOKED, 197 PT_HOOK_TYPE_EXECUTION_CONTEXT_CREATEED, 198 PT_HOOK_TYPE_EXECUTION_CONTEXT_DESTROYED, 199 PT_HOOK_TYPE_EXECUTION_CONTEXTS_CLEARED, 200 PT_HOOK_TYPE_INSPECT_REQUESTED, 201 PT_HOOK_TYPE_CLASS_LOAD, 202 PT_HOOK_TYPE_CLASS_PREPARE, 203 PT_HOOK_TYPE_MONITOR_WAIT, 204 PT_HOOK_TYPE_MONITOR_WAITED, 205 PT_HOOK_TYPE_MONITOR_CONTENDED_ENTER, 206 PT_HOOK_TYPE_MONITOR_CONTENDED_ENTERED, 207 PT_HOOK_TYPE_OBJECT_ALLOC, 208 // The count of hooks. Don't move 209 PT_HOOK_TYPE_COUNT 210 }; 211 212 // * * * * * 213 // Mock API helpers ends 214 // * * * * * 215 216 class PtHooks { 217 public: 218 PtHooks() = default; 219 220 /** 221 * @brief Method is called by the runtime when breakpoint hits. Thread where breakpoint hits is stopped until 222 * continue or step event will be received 223 * @param thread Identifier of the thread where breakpoint hits. Now the callback is called in the same 224 * thread 225 * @param method Method 226 * @param location Breakpoint location 227 */ Breakpoint(PtThread,Method *,const PtLocation &)228 virtual void Breakpoint(PtThread /* thread */, Method * /* method */, const PtLocation & /* location */) {} 229 230 /** 231 * @brief Method is called by the runtime when panda file is loaded 232 * @param pandaFileName Path to panda file that is loaded 233 */ LoadModule(std::string_view)234 virtual void LoadModule(std::string_view /* pandaFileName */) {} 235 236 /** 237 * @brief Method is called by the runtime when managed thread is attached to it 238 * @param thread The attached thread 239 */ ThreadStart(PtThread)240 virtual void ThreadStart(PtThread /* thread */) {} 241 242 /** 243 * @brief Method is called by the runtime when managed thread is detached 244 * @param thread The detached thread 245 */ ThreadEnd(PtThread)246 virtual void ThreadEnd(PtThread /* thread */) {} 247 248 /// @brief Method is called by the runtime when virtual machine start initialization VmStart()249 virtual void VmStart() {} 250 251 /** 252 * @brief Method is called by the runtime when virtual machine finish initialization 253 * @param thread The initial thread 254 */ VmInitialization(PtThread)255 virtual void VmInitialization(PtThread /* thread */) {} 256 257 /// @brief Method is called by the runtime when virtual machine death VmDeath()258 virtual void VmDeath() {} 259 260 /** 261 * @brief Method is called by the runtime when a class is first loaded 262 * @param thread Thread loading the class 263 * @param klass Class being loaded 264 */ ClassLoad(PtThread,BaseClass *)265 virtual void ClassLoad(PtThread /* thread */, BaseClass * /* klass */) {} 266 267 /** 268 * @brief Method is called by the runtime when class preparation is complete 269 * @param thread Thread generating the class prepare 270 * @param klass Class being prepared 271 */ ClassPrepare(PtThread,BaseClass *)272 virtual void ClassPrepare(PtThread /* thread */, BaseClass * /* klass */) {} 273 274 /** 275 * @brief Method is called by the runtime when a thread is about to wait on an object 276 * @param thread The thread about to wait 277 * @param object Reference to the monitor 278 * @param timeout The number of milliseconds the thread will wait 279 */ MonitorWait(PtThread,ObjectHeader *,int64_t)280 virtual void MonitorWait(PtThread /* thread */, ObjectHeader * /* object */, int64_t /* timeout */) {} 281 282 /** 283 * @brief Method is called by the runtime when a thread finishes waiting on an object 284 * @param thread The thread about to wait 285 * @param object Reference to the monitor 286 * @param timedOut True if the monitor timed out 287 */ MonitorWaited(PtThread,ObjectHeader *,bool)288 virtual void MonitorWaited(PtThread /* thread */, ObjectHeader * /* object */, bool /* timedOut */) {} 289 290 /** 291 * @brief Method is called by the runtime when a thread is attempting to enter a monitor already acquired by another 292 * thread 293 * @param thread The thread about to wait 294 * @param object Reference to the monitor 295 */ MonitorContendedEnter(PtThread,ObjectHeader *)296 virtual void MonitorContendedEnter(PtThread /* thread */, ObjectHeader * /* object */) {} 297 298 /** 299 * @brief Method is called by the runtime when a thread enters a monitor after waiting for it to be released by 300 * another thread 301 * @param thread The thread about to wait 302 * @param object Reference to the monitor 303 */ MonitorContendedEntered(PtThread,ObjectHeader *)304 virtual void MonitorContendedEntered(PtThread /* thread */, ObjectHeader * /* object */) {} 305 Exception(PtThread,Method *,const PtLocation &,ObjectHeader *,Method *,const PtLocation &)306 virtual void Exception(PtThread /* thread */, Method * /* method */, const PtLocation & /* location */, 307 ObjectHeader * /* exceptionObject */, Method * /* catchMethod */, 308 const PtLocation & /* catchLocation */) 309 { 310 } 311 ExceptionCatch(PtThread,Method *,const PtLocation &,ObjectHeader *)312 virtual void ExceptionCatch(PtThread /* thread */, Method * /* catchMethod */, const PtLocation & /* location */, 313 ObjectHeader * /* exceptionObject */) 314 { 315 } 316 PropertyAccess(PtThread,Method *,const PtLocation &,ObjectHeader *,PtProperty)317 virtual void PropertyAccess(PtThread /* thread */, Method * /* catchMethod */, const PtLocation & /* location */, 318 ObjectHeader * /* object */, PtProperty /* property */) 319 { 320 } 321 PropertyModification(PtThread,Method *,const PtLocation &,ObjectHeader *,PtProperty,VRegValue)322 virtual void PropertyModification(PtThread /* thread */, Method * /* method */, const PtLocation & /* location */, 323 ObjectHeader * /* object */, PtProperty /* property */, VRegValue /* newValue */) 324 { 325 } 326 ConsoleCall(PtThread,ConsoleCallType,uint64_t,const PandaVector<TypedValue> &)327 virtual void ConsoleCall(PtThread /* thread */, ConsoleCallType /* type */, uint64_t /* timestamp */, 328 const PandaVector<TypedValue> & /* arguments */) 329 { 330 } 331 FramePop(PtThread,Method *,bool)332 virtual void FramePop(PtThread /* thread */, Method * /* method */, bool /* wasPoppedByException */) {} 333 GarbageCollectionFinish()334 virtual void GarbageCollectionFinish() {} 335 GarbageCollectionStart()336 virtual void GarbageCollectionStart() {} 337 ObjectAlloc(BaseClass *,ObjectHeader *,PtThread,size_t)338 virtual void ObjectAlloc(BaseClass * /* klass */, ObjectHeader * /* object */, PtThread /* thread */, 339 size_t /* size */) 340 { 341 } 342 MethodEntry(PtThread,Method *)343 virtual void MethodEntry(PtThread /* thread */, Method * /* method */) {} 344 MethodExit(PtThread,Method *,bool,VRegValue)345 virtual void MethodExit(PtThread /* thread */, Method * /* method */, bool /* wasPoppedByException */, 346 VRegValue /* returnValue */) 347 { 348 } 349 SingleStep(PtThread,Method *,const PtLocation &)350 virtual void SingleStep(PtThread /* thread */, Method * /* method */, const PtLocation & /* location */) {} 351 352 // * * * * * 353 // Deprecated hooks 354 // * * * * * 355 Paused(PauseReason)356 virtual void Paused(PauseReason /* reason */) {} Breakpoint(PtThread,const PtLocation &)357 virtual void Breakpoint(PtThread /* thread */, const PtLocation & /* location */) {} SingleStep(PtThread,const PtLocation &)358 virtual void SingleStep(PtThread /* thread */, const PtLocation & /* location */) {} 359 360 // NOLINTNEXTLINE(performance-unnecessary-value-param) ExceptionRevoked(ExceptionWrapper,ExceptionID)361 virtual void ExceptionRevoked(ExceptionWrapper /* reason */, ExceptionID /* exceptionId */) {} 362 363 // NOLINTNEXTLINE(performance-unnecessary-value-param) ExecutionContextCreated(ExecutionContextWrapper)364 virtual void ExecutionContextCreated(ExecutionContextWrapper /* context */) {} 365 366 // NOLINTNEXTLINE(performance-unnecessary-value-param) ExecutionContextDestroyed(ExecutionContextWrapper)367 virtual void ExecutionContextDestroyed(ExecutionContextWrapper /* context */) {} 368 ExecutionContextsCleared()369 virtual void ExecutionContextsCleared() {} 370 371 // * * * * * 372 // Deprecated hooks end 373 // * * * * * 374 375 virtual ~PtHooks() = default; 376 377 NO_COPY_SEMANTIC(PtHooks); 378 NO_MOVE_SEMANTIC(PtHooks); 379 }; 380 381 class DebugInterface { 382 public: 383 DebugInterface() = default; 384 385 /** 386 * @brief Register debug hooks in the runtime 387 * @param hooks Pointer to object that implements PtHooks interface 388 * @return Error if any errors occur 389 */ 390 virtual std::optional<Error> RegisterHooks(PtHooks *hooks) = 0; 391 392 /** 393 * @brief Unregister debug hooks in the runtime 394 * @return Error if any errors occur 395 */ 396 virtual std::optional<Error> UnregisterHooks() = 0; 397 398 /** 399 * @brief Enable all debug hooks in the runtime 400 * @return Error if any errors occur 401 */ 402 virtual std::optional<Error> EnableAllGlobalHook() = 0; 403 404 /** 405 * @brief Disable all debug hooks in the runtime 406 * @return Error if any errors occur 407 */ 408 virtual std::optional<Error> DisableAllGlobalHook() = 0; 409 410 /** 411 * @brief Set notification to hook (enable/disable). 412 * @param thread If thread is NONE, the notification is enabled or disabled globally 413 * @param enable Enable or disable notifications (true - enable, false - disable) 414 * @param hook_type Type of hook that must be enabled or disabled 415 * @return Error if any errors occur 416 */ 417 virtual std::optional<Error> SetNotification(PtThread thread, bool enable, PtHookType hookType) = 0; 418 419 /** 420 * @brief Set breakpoint to @param location 421 * @param location Breakpoint location 422 * @return Error if any errors occur 423 */ 424 virtual std::optional<Error> SetBreakpoint(const PtLocation &location) = 0; 425 426 /** 427 * @brief Remove breakpoint from @param location 428 * @param location Breakpoint location 429 * @return Error if any errors occur 430 */ 431 virtual std::optional<Error> RemoveBreakpoint(const PtLocation &location) = 0; 432 433 /** 434 * @brief Get Frame 435 * @param thread Identifier of the thread 436 * @return Frame object that implements PtFrame or Error if any errors occur 437 */ 438 virtual Expected<std::unique_ptr<PtFrame>, Error> GetCurrentFrame(PtThread thread) const = 0; 439 440 /** 441 * @brief Enumerates managed frames in the thread @param threadId 442 * @param thread Identifier of the thread 443 * @param callback Callback that is called for each frame. Should return true to continue and false to stop 444 * enumerating 445 * @return Error if any errors occur 446 */ 447 virtual std::optional<Error> EnumerateFrames(PtThread thread, 448 std::function<bool(const PtFrame &)> callback) const = 0; 449 450 /** 451 * @brief Suspend thread 452 * @param thread Identifier of the thread 453 * @return Error if any errors occur 454 */ 455 virtual std::optional<Error> SuspendThread(PtThread thread) const = 0; 456 457 /** 458 * @brief Resume thread 459 * @param thread Identifier of the thread 460 * @return Error if any errors occur 461 */ 462 virtual std::optional<Error> ResumeThread(PtThread thread) const = 0; 463 464 virtual ~DebugInterface() = default; 465 466 virtual std::optional<Error> GetThreadList(PandaVector<PtThread> *threadList) const = 0; 467 SetVariable(PtThread,uint32_t,int32_t,const VRegValue &)468 virtual std::optional<Error> SetVariable(PtThread /* thread */, uint32_t /* frameDepth */, int32_t /* regNumber */, 469 const VRegValue & /* value */) const 470 { 471 return {}; 472 } 473 GetVariable(PtThread,uint32_t,int32_t,VRegValue *)474 virtual std::optional<Error> GetVariable(PtThread /* thread */, uint32_t /* frameDepth */, int32_t /* regNumber */, 475 VRegValue * /* value */) const 476 { 477 return {}; 478 } 479 480 virtual std::optional<Error> EvaluateExpression(PtThread thread, uint32_t frameNumber, 481 const ExpressionWrapper &expr, Method **method, 482 VRegValue *result) const = 0; 483 484 virtual std::optional<Error> EvaluateExpression(PtThread thread, uint32_t frameNumber, Method *method, 485 VRegValue *result) const = 0; 486 487 virtual std::optional<Error> GetThreadInfo(PtThread thread, ThreadInfo *infoPtr) const = 0; 488 489 virtual std::optional<Error> RestartFrame(PtThread thread, uint32_t frameNumber) const = 0; 490 491 virtual std::optional<Error> SetAsyncCallStackDepth(uint32_t maxDepth) const = 0; 492 493 virtual std::optional<Error> GetProperties(uint32_t *countPtr, char ***propertyPtr) const = 0; 494 495 virtual std::optional<Error> NotifyFramePop(PtThread thread, uint32_t depth) const = 0; 496 GetThisVariableByFrame(PtThread,uint32_t,ObjectHeader **)497 virtual std::optional<Error> GetThisVariableByFrame(PtThread /* thread */, uint32_t /* frameDepth */, 498 ObjectHeader ** /* this_ptr */) 499 { 500 return {}; 501 } 502 SetPropertyAccessWatch(BaseClass *,PtProperty)503 virtual std::optional<Error> SetPropertyAccessWatch(BaseClass * /* klass */, PtProperty /* property */) 504 { 505 return {}; 506 } 507 ClearPropertyAccessWatch(BaseClass *,PtProperty)508 virtual std::optional<Error> ClearPropertyAccessWatch(BaseClass * /* klass */, PtProperty /* property */) 509 { 510 return {}; 511 } 512 SetPropertyModificationWatch(BaseClass *,PtProperty)513 virtual std::optional<Error> SetPropertyModificationWatch(BaseClass * /* klass */, PtProperty /* property */) 514 { 515 return {}; 516 } 517 ClearPropertyModificationWatch(BaseClass *,PtProperty)518 virtual std::optional<Error> ClearPropertyModificationWatch(BaseClass * /* klass */, PtProperty /* property */) 519 { 520 return {}; 521 } 522 523 NO_COPY_SEMANTIC(DebugInterface); 524 NO_MOVE_SEMANTIC(DebugInterface); 525 }; 526 } // namespace ark::tooling 527 528 #endif // PANDA_RUNTIME_INCLUDE_TOOLING_DEBUG_INTERFACE_H 529