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