• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_TOOLING_DEBUGGER_H_
17 #define PANDA_RUNTIME_TOOLING_DEBUGGER_H_
18 
19 #include <atomic>
20 #include <functional>
21 #include <memory>
22 #include <string_view>
23 
24 #include "include/method.h"
25 #include "include/runtime.h"
26 #include "pt_hooks_wrapper.h"
27 #include "include/mem/panda_smart_pointers.h"
28 #include "include/mem/panda_containers.h"
29 #include "include/runtime_notification.h"
30 #include "include/tooling/debug_interface.h"
31 #include "libpandabase/utils/span.h"
32 #include "runtime/include/mem/panda_containers.h"
33 #include "runtime/include/method.h"
34 #include "runtime/include/runtime.h"
35 #include "runtime/include/panda_vm.h"
36 #include "runtime/include/tooling/debug_interface.h"
37 #include "runtime/thread_manager.h"
38 #include "pt_hooks_wrapper.h"
39 
40 namespace panda::tooling {
41 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
42 class Breakpoint {
43 public:
44     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
Breakpoint(Method * method,uint32_t bcOffset)45     Breakpoint(Method *method, uint32_t bcOffset) : method_(method), bc_offset_(bcOffset) {}
46     ~Breakpoint() = default;
47 
GetMethod()48     Method *GetMethod() const
49     {
50         return method_;
51     }
52 
GetBytecodeOffset()53     uint32_t GetBytecodeOffset() const
54     {
55         return bc_offset_;
56     }
57 
58     bool operator==(const Breakpoint &bpoint) const
59     {
60         return GetMethod() == bpoint.GetMethod() && GetBytecodeOffset() == bpoint.GetBytecodeOffset();
61     }
62 
63     DEFAULT_COPY_SEMANTIC(Breakpoint);
64     DEFAULT_MOVE_SEMANTIC(Breakpoint);
65 
66 private:
67     Method *method_;
68     uint32_t bc_offset_;
69 };
70 
71 class HashBreakpoint {
72 public:
operator()73     size_t operator()(const Breakpoint &bpoint) const
74     {
75         return (std::hash<Method *>()(bpoint.GetMethod())) ^ (std::hash<uint32_t>()(bpoint.GetBytecodeOffset()));
76     }
77 };
78 
79 class PropertyWatch {
80 public:
81     enum class Type { ACCESS, MODIFY };
82 
83     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
PropertyWatch(panda_file::File::EntityId classId,panda_file::File::EntityId fieldId,Type type)84     PropertyWatch(panda_file::File::EntityId classId, panda_file::File::EntityId fieldId, Type type)
85         : class_id_(classId), field_id_(fieldId), type_(type)
86     {
87     }
88 
89     ~PropertyWatch() = default;
90 
GetClassId()91     panda_file::File::EntityId GetClassId() const
92     {
93         return class_id_;
94     }
95 
GetFieldId()96     panda_file::File::EntityId GetFieldId() const
97     {
98         return field_id_;
99     }
100 
GetType()101     Type GetType() const
102     {
103         return type_;
104     }
105 
106 private:
107     NO_COPY_SEMANTIC(PropertyWatch);
108     NO_MOVE_SEMANTIC(PropertyWatch);
109 
110     panda_file::File::EntityId class_id_;
111     panda_file::File::EntityId field_id_;
112     Type type_;
113 };
114 
115 class Debugger : public DebugInterface, RuntimeListener {
116 public:
117     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
Debugger(const Runtime * runtime)118     explicit Debugger(const Runtime *runtime)
119         : runtime_(runtime),
120           breakpoints_(GetInternalAllocatorAdapter(runtime)),
121           property_watches_(GetInternalAllocatorAdapter(runtime)),
122           vm_started_(runtime->IsInitialized())
123     {
124         runtime_->GetNotificationManager()->AddListener(this, DEBUG_EVENT_MASK);
125     }
126 
~Debugger()127     ~Debugger() override
128     {
129         runtime_->GetNotificationManager()->RemoveListener(this, DEBUG_EVENT_MASK);
130     }
131 
GetLangExtension()132     PtLangExt *GetLangExtension() const override
133     {
134         return runtime_->GetPtLangExt();
135     }
136 
137     Expected<PtMethod, Error> GetPtMethod(const PtLocation &location) const override;
138 
RegisterHooks(PtHooks * hooks)139     std::optional<Error> RegisterHooks(PtHooks *hooks) override
140     {
141         hooks_.SetHooks(hooks);
142         return {};
143     }
144 
UnregisterHooks()145     std::optional<Error> UnregisterHooks() override
146     {
147         hooks_.SetHooks(nullptr);
148         return {};
149     }
150 
EnableAllGlobalHook()151     std::optional<Error> EnableAllGlobalHook() override
152     {
153         hooks_.EnableAllGlobalHook();
154         return {};
155     }
156 
DisableAllGlobalHook()157     std::optional<Error> DisableAllGlobalHook() override
158     {
159         hooks_.DisableAllGlobalHook();
160         return {};
161     }
162 
163     std::optional<Error> SetNotification(PtThread thread, bool enable, PtHookType hookType) override;
164     std::optional<Error> SetBreakpoint(const PtLocation &location) override;
165 
166     std::optional<Error> RemoveBreakpoint(const PtLocation &location) override;
167 
168     Expected<std::unique_ptr<PtFrame>, Error> GetCurrentFrame(PtThread thread) const override;
169 
170     std::optional<Error> EnumerateFrames(PtThread thread, std::function<bool(const PtFrame &)> callback) const override;
171 
172     // RuntimeListener methods
173 
LoadModule(std::string_view filename)174     void LoadModule(std::string_view filename) override
175     {
176         hooks_.LoadModule(filename);
177     }
178 
ThreadStart(ManagedThread::ThreadId threadId)179     void ThreadStart(ManagedThread::ThreadId threadId) override
180     {
181         hooks_.ThreadStart(PtThread(threadId));
182     }
183 
ThreadEnd(ManagedThread::ThreadId threadId)184     void ThreadEnd(ManagedThread::ThreadId threadId) override
185     {
186         hooks_.ThreadEnd(PtThread(threadId));
187     }
188 
189     void BytecodePcChanged(ManagedThread *thread, Method *method, uint32_t bcOffset) override;
190 
VmStart()191     void VmStart() override
192     {
193         vm_started_ = true;
194         hooks_.VmStart();
195     }
196 
VmInitialization(ManagedThread::ThreadId threadId)197     void VmInitialization(ManagedThread::ThreadId threadId) override
198     {
199         hooks_.VmInitialization(PtThread(threadId));
200     }
201 
VmDeath()202     void VmDeath() override
203     {
204         hooks_.VmDeath();
205     }
206 
GarbageCollectorStart()207     void GarbageCollectorStart() override
208     {
209         hooks_.GarbageCollectionStart();
210     }
211 
GarbageCollectorFinish()212     void GarbageCollectorFinish() override
213     {
214         hooks_.GarbageCollectionFinish();
215     }
216 
217     void ObjectAlloc(BaseClass *klass, ObjectHeader *object, ManagedThread *thread, size_t size) override;
218 
219     void ExceptionCatch(const ManagedThread *thread, const Method *method, uint32_t bcOffset) override;
220 
221     void MethodEntry(ManagedThread *thread, Method *method) override;
222     void MethodExit(ManagedThread *thread, Method *method) override;
223 
224     void ClassLoad(Class *klass) override;
225     void ClassPrepare(Class *klass) override;
226 
227     void MonitorWait(ObjectHeader *object, int64_t timeout) override;
228     void MonitorWaited(ObjectHeader *object, bool timedOut) override;
229     void MonitorContendedEnter(ObjectHeader *object) override;
230     void MonitorContendedEntered(ObjectHeader *object) override;
231 
232     /*
233      * Mock API for debug interphase starts:
234      *
235      * API's function should be revorked and input parameters should be added
236      */
GetThreadList(PandaVector<PtThread> * threadList)237     std::optional<Error> GetThreadList(PandaVector<PtThread> *threadList) const override
238     {
239         runtime_->GetPandaVM()->GetThreadManager()->EnumerateThreads(
240             [threadList](MTManagedThread *mt_managed_thread) {
241                 ASSERT(mt_managed_thread && "thread is null");
242                 threadList->push_back(PtThread(mt_managed_thread->GetId()));
243                 return true;
244             },
245             static_cast<unsigned int>(panda::EnumerationFlag::ALL),
246             static_cast<unsigned int>(panda::EnumerationFlag::VM_THREAD));
247 
248         return {};
249     }
250 
GetThreadInfo(PtThread thread,ThreadInfo * infoPtr)251     std::optional<Error> GetThreadInfo(PtThread thread, ThreadInfo *infoPtr) const override
252     {
253         MTManagedThread *mt_managed_thread = GetManagedThreadByPtThread(thread);
254 
255         if (mt_managed_thread == nullptr) {
256             return Error(Error::Type::THREAD_NOT_FOUND,
257                          std::string("Thread ") + std::to_string(thread.GetId()) + " not found");
258         }
259 
260         infoPtr->is_daemon = mt_managed_thread->IsDaemon();
261         infoPtr->priority = mt_managed_thread->GetThreadPriority();
262         /* fields that didn't still implemented (we don't support it):
263          * infoPtr->thread_group
264          * infoPtr->context_class_loader
265          */
266         return {};
267     }
268 
269     std::optional<Error> SuspendThread(PtThread thread) const override;
270 
271     std::optional<Error> ResumeThread(PtThread thread) const override;
272 
273     std::optional<Error> SetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber,
274                                      const PtValue &value) const override;
275 
276     std::optional<Error> GetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber,
277                                      PtValue *result) const override;
278 
GetProperty(PtObject object,PtProperty property,PtValue * value)279     std::optional<Error> GetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property,
280                                      PtValue *value) const override
281     {
282         std::cout << "GetProperty called " << std::endl;
283         const int64_t anydata = 0x123456789;
284         value->SetValue(anydata);
285         return {};
286     }
287 
SetProperty(PtObject object,PtProperty property,const PtValue & value)288     std::optional<Error> SetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property,
289                                      [[maybe_unused]] const PtValue &value) const override
290     {
291         std::cout << "SetProperty called " << std::endl;
292         return {};
293     }
294 
EvaluateExpression(PtThread thread,uint32_t frameNumber,ExpressionWrapper expr,PtValue * result)295     std::optional<Error> EvaluateExpression([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameNumber,
296                                             ExpressionWrapper expr, PtValue *result) const override
297     {
298         std::cout << "EvaluateExpression called " << std::endl;
299         if (expr.empty()) {
300             return Error(Error::Type::INVALID_EXPRESSION, "invalid expression");
301         }
302         const int64_t anydata = 0x123456789;
303         result->SetValue(anydata);
304         return {};
305     }
306 
RetransformClasses(int classCount,const PtClass * classes)307     std::optional<Error> RetransformClasses([[maybe_unused]] int classCount,
308                                             [[maybe_unused]] const PtClass *classes) const override
309     {
310         std::cout << "RetransformClasses called " << std::endl;
311         return {};
312     }
313 
RedefineClasses(int classCount,const PandaClassDefinition * classes)314     std::optional<Error> RedefineClasses([[maybe_unused]] int classCount,
315                                          [[maybe_unused]] const PandaClassDefinition *classes) const override
316     {
317         std::cout << "RedefineClasses called " << std::endl;
318         return {};
319     }
320 
321     std::optional<Error> RestartFrame([[maybe_unused]] PtThread thread,
322                                       [[maybe_unused]] uint32_t frameNumber) const override;
323 
SetAsyncCallStackDepth(uint32_t maxDepth)324     std::optional<Error> SetAsyncCallStackDepth([[maybe_unused]] uint32_t maxDepth) const override
325     {
326         std::cout << "SetAsyncCallStackDepth called " << std::endl;
327         return {};
328     }
329 
AwaitPromise(PtObject promiseObject,PtValue * result)330     std::optional<Error> AwaitPromise([[maybe_unused]] PtObject promiseObject, PtValue *result) const override
331     {
332         const uint32_t anyobj = 123456789;
333         result->SetValue(anyobj);
334 
335         std::cout << "AwaitPromise called " << std::endl;
336         return {};
337     }
338 
CallFunctionOn(PtObject object,PtMethod method,const PandaVector<PtValue> & arguments,PtValue * returnValue)339     std::optional<Error> CallFunctionOn([[maybe_unused]] PtObject object, [[maybe_unused]] PtMethod method,
340                                         [[maybe_unused]] const PandaVector<PtValue> &arguments,
341                                         PtValue *returnValue) const override
342     {
343         const int64_t anydata = 0x123456789;
344         returnValue->SetValue(anydata);
345         std::cout << "CallFunctionOn called " << std::endl;
346         return {};
347     }
348 
GetProperties(uint32_t * countPtr,char *** propertyPtr)349     std::optional<Error> GetProperties(uint32_t *countPtr, [[maybe_unused]] char ***propertyPtr) const override
350     {
351         *countPtr = 0;
352         std::cout << "GetProperties called " << std::endl;
353         return {};
354     }
355 
356     std::optional<Error> NotifyFramePop(PtThread thread, uint32_t depth) const override;
357 
358     std::optional<Error> SetPropertyAccessWatch(PtClass klass, PtProperty property) override;
359 
360     std::optional<Error> ClearPropertyAccessWatch(PtClass klass, PtProperty property) override;
361 
362     std::optional<Error> SetPropertyModificationWatch(PtClass klass, PtProperty property) override;
363 
364     std::optional<Error> ClearPropertyModificationWatch(PtClass klass, PtProperty property) override;
365 
366     std::optional<Error> GetThisVariableByFrame(PtThread thread, uint32_t frameDepth, PtValue *result) override;
367 
368 private:
369     Expected<panda::Frame::VRegister *, Error> GetVRegByPtThread(PtThread thread, uint32_t frameDepth,
370                                                                  int32_t regNumber) const;
371     const tooling::Breakpoint *FindBreakpoint(const Method *method, uint32_t bcOffset) const;
372     bool RemoveBreakpoint(Method *method, uint32_t bcOffset);
373 
374     MTManagedThread *GetManagedThreadByPtThread(PtThread thread) const;
375 
IsPropertyWatchActive()376     bool IsPropertyWatchActive() const
377     {
378         return !property_watches_.empty();
379     }
380     const tooling::PropertyWatch *FindPropertyWatch(panda_file::File::EntityId classId,
381                                                     panda_file::File::EntityId fieldId,
382                                                     tooling::PropertyWatch::Type type) const;
383     bool RemovePropertyWatch(panda_file::File::EntityId classId, panda_file::File::EntityId fieldId,
384                              tooling::PropertyWatch::Type type);
385 
386     bool HandleBreakpoint(const ManagedThread *thread, const Method *method, uint32_t bcOffset);
387     void HandleNotifyFramePop(ManagedThread *thread, Method *method, bool wasPoppedByException);
388     void HandleExceptionThrowEvent(ManagedThread *thread, Method *method, uint32_t bcOffset);
389     bool HandleStep(const ManagedThread *thread, const Method *method, uint32_t bcOffset);
390 
391     bool HandlePropertyAccess(const ManagedThread *thread, const Method *method, uint32_t bcOffset);
392     bool HandlePropertyModify(const ManagedThread *thread, const Method *method, uint32_t bcOffset);
393 
394     static constexpr uint32_t DEBUG_EVENT_MASK =
395         RuntimeNotificationManager::Event::LOAD_MODULE | RuntimeNotificationManager::Event::THREAD_EVENTS |
396         RuntimeNotificationManager::Event::BYTECODE_PC_CHANGED | RuntimeNotificationManager::Event::EXCEPTION_EVENTS |
397         RuntimeNotificationManager::Event::VM_EVENTS | RuntimeNotificationManager::Event::GARBAGE_COLLECTOR_EVENTS |
398         RuntimeNotificationManager::Event::METHOD_EVENTS | RuntimeNotificationManager::Event::CLASS_EVENTS |
399         RuntimeNotificationManager::Event::MONITOR_EVENTS | RuntimeNotificationManager::Event::ALLOCATION_EVENTS;
400 
401     const Runtime *runtime_;
402     PtHooksWrapper hooks_;
403 
404     PandaUnorderedSet<tooling::Breakpoint, tooling::HashBreakpoint> breakpoints_;
405     PandaList<tooling::PropertyWatch> property_watches_;
406     bool vm_started_ {false};
407 
408     NO_COPY_SEMANTIC(Debugger);
409     NO_MOVE_SEMANTIC(Debugger);
410 };
411 
412 class PtDebugFrame : public PtFrame {
413 public:
414     explicit PtDebugFrame(Method *method, const Frame *interpreterFrame);
415     ~PtDebugFrame() override = default;
416 
IsInterpreterFrame()417     bool IsInterpreterFrame() const override
418     {
419         return is_interpreter_frame_;
420     }
421 
GetPtMethod()422     PtMethod GetPtMethod() const override
423     {
424         return method_;
425     }
426 
GetVReg(size_t i)427     uint64_t GetVReg(size_t i) const override
428     {
429         if (!is_interpreter_frame_) {
430             return 0;
431         }
432         return vregs_[i];
433     }
434 
GetVRegNum()435     size_t GetVRegNum() const override
436     {
437         return vregs_.size();
438     }
439 
GetArgument(size_t i)440     uint64_t GetArgument(size_t i) const override
441     {
442         if (!is_interpreter_frame_) {
443             return 0;
444         }
445         return args_[i];
446     }
447 
GetArgumentNum()448     size_t GetArgumentNum() const override
449     {
450         return args_.size();
451     }
452 
GetAccumulator()453     uint64_t GetAccumulator() const override
454     {
455         return acc_;
456     }
457 
GetMethodId()458     panda_file::File::EntityId GetMethodId() const override
459     {
460         return method_id_;
461     }
462 
GetBytecodeOffset()463     uint32_t GetBytecodeOffset() const override
464     {
465         return bc_offset_;
466     }
467 
GetPandaFile()468     std::string GetPandaFile() const override
469     {
470         return panda_file_;
471     }
472 
473     // mock API
GetFrameId()474     uint32_t GetFrameId() const override
475     {
476         return 0;
477     }
478 
479 private:
480     NO_COPY_SEMANTIC(PtDebugFrame);
481     NO_MOVE_SEMANTIC(PtDebugFrame);
482 
483     bool is_interpreter_frame_;
484     PtMethod method_;
485     uint64_t acc_ {0};
486     PandaVector<uint64_t> vregs_;
487     PandaVector<uint64_t> args_;
488     panda_file::File::EntityId method_id_;
489     uint32_t bc_offset_ {0};
490     std::string panda_file_;
491 };
492 
493 }  // namespace panda::tooling
494 
495 #endif  // PANDA_RUNTIME_TOOLING_DEBUGGER_H_
496