• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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