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