• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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_DEBUG_DEBUG_H
16 #define PANDA_RUNTIME_DEBUG_DEBUG_H
17 
18 #include <atomic>
19 #include <functional>
20 #include <memory>
21 #include <string_view>
22 
23 #include "include/method.h"
24 #include "include/runtime.h"
25 #include "pt_hooks_wrapper.h"
26 #include "include/mem/panda_smart_pointers.h"
27 #include "include/mem/panda_containers.h"
28 #include "include/runtime_notification.h"
29 #include "include/tooling/debug_interface.h"
30 #include "libpandabase/os/mutex.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 
39 namespace panda::tooling {
40 // Deprecated API
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 // Deprecated API
72 class HashBreakpoint {
73 public:
operator()74     size_t operator()(const Breakpoint &bpoint) const
75     {
76         return (std::hash<Method *>()(bpoint.GetMethod())) ^ (std::hash<uint32_t>()(bpoint.GetBytecodeOffset()));
77     }
78 };
79 
80 class HashLocation {
81 public:
operator()82     size_t operator()(const PtLocation &location) const
83     {
84         return std::hash<std::string>()(location.GetPandaFile()) ^
85                std::hash<uint32_t>()(location.GetMethodId().GetOffset()) ^  // CODECHECK-NOLINT(C_RULE_ID_INDENT_CHECK)
86                std::hash<uint32_t>()(location.GetBytecodeOffset());         // CODECHECK-NOLINT(C_RULE_ID_INDENT_CHECK)
87     }
88 };
89 
90 class PropertyWatch {
91 public:
92     enum class Type { ACCESS, MODIFY };
93 
94     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
PropertyWatch(panda_file::File::EntityId classId,panda_file::File::EntityId fieldId,Type type)95     PropertyWatch(panda_file::File::EntityId classId, panda_file::File::EntityId fieldId, Type type)
96         : class_id_(classId), field_id_(fieldId), type_(type)
97     {
98     }
99 
100     ~PropertyWatch() = default;
101 
GetClassId()102     panda_file::File::EntityId GetClassId() const
103     {
104         return class_id_;
105     }
106 
GetFieldId()107     panda_file::File::EntityId GetFieldId() const
108     {
109         return field_id_;
110     }
111 
GetType()112     Type GetType() const
113     {
114         return type_;
115     }
116 
117 private:
118     NO_COPY_SEMANTIC(PropertyWatch);
119     NO_MOVE_SEMANTIC(PropertyWatch);
120 
121     panda_file::File::EntityId class_id_;
122     panda_file::File::EntityId field_id_;
123     Type type_;
124 };
125 
126 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
127 class Debugger : public DebugInterface, RuntimeListener {
128 public:
129     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
Debugger(const Runtime * runtime)130     explicit Debugger(const Runtime *runtime)
131         : runtime_(runtime),
132           breakpoints_(GetInternalAllocatorAdapter(runtime)),
133           property_watches_(GetInternalAllocatorAdapter(runtime)),
134           vm_started_(runtime->IsInitialized())
135     {
136         runtime_->GetNotificationManager()->AddListener(this, DEBUG_EVENT_MASK);
137     }
138 
~Debugger()139     ~Debugger() override
140     {
141         runtime_->GetNotificationManager()->RemoveListener(this, DEBUG_EVENT_MASK);
142     }
143 
GetLangExtension()144     PtLangExt *GetLangExtension() const override
145     {
146         PT_UNIMPLEMENTED();
147         return nullptr;
148     }
149 
GetPtMethod(const PtLocation &)150     Expected<PtMethod, Error> GetPtMethod(const PtLocation & /* location */) const override
151     {
152         PT_DEPRECATED();
153         return Unexpected(Error(Error::Type::DEPRECATED, "Method is deprecated"));
154     }
155 
RegisterHooks(PtHooks * hooks)156     std::optional<Error> RegisterHooks(PtHooks *hooks) override
157     {
158         hooks_.SetHooks(hooks);
159         return {};
160     }
161 
UnregisterHooks()162     std::optional<Error> UnregisterHooks() override
163     {
164         hooks_.SetHooks(nullptr);
165         return {};
166     }
167 
EnableAllGlobalHook()168     std::optional<Error> EnableAllGlobalHook() override
169     {
170         hooks_.EnableAllGlobalHook();
171         return {};
172     }
173 
DisableAllGlobalHook()174     std::optional<Error> DisableAllGlobalHook() override
175     {
176         hooks_.DisableAllGlobalHook();
177         return {};
178     }
179 
180     std::optional<Error> SetNotification(PtThread thread, bool enable, PtHookType hookType) override;
181     std::optional<Error> SetBreakpoint(const PtLocation &location) override;
182 
183     std::optional<Error> RemoveBreakpoint(const PtLocation &location) override;
184 
185     Expected<std::unique_ptr<PtFrame>, Error> GetCurrentFrame(PtThread thread) const override;
186 
187     std::optional<Error> EnumerateFrames(PtThread thread, std::function<bool(const PtFrame &)> callback) const override;
188 
189     // RuntimeListener methods
190 
LoadModule(std::string_view filename)191     void LoadModule(std::string_view filename) override
192     {
193         hooks_.LoadModule(filename);
194     }
195 
ThreadStart(ManagedThread * managed_thread)196     void ThreadStart(ManagedThread *managed_thread) override
197     {
198         hooks_.ThreadStart(PtThread(managed_thread));
199     }
200 
ThreadEnd(ManagedThread * managed_thread)201     void ThreadEnd(ManagedThread *managed_thread) override
202     {
203         hooks_.ThreadEnd(PtThread(managed_thread));
204     }
205 
206     void BytecodePcChanged(ManagedThread *thread, Method *method, uint32_t bcOffset) override;
207 
VmStart()208     void VmStart() override
209     {
210         vm_started_ = true;
211         hooks_.VmStart();
212     }
213 
VmInitialization(ManagedThread * managed_thread)214     void VmInitialization(ManagedThread *managed_thread) override
215     {
216         hooks_.VmInitialization(PtThread(managed_thread));
217     }
218 
VmDeath()219     void VmDeath() override
220     {
221         hooks_.VmDeath();
222     }
223 
GarbageCollectorStart()224     void GarbageCollectorStart() override
225     {
226         hooks_.GarbageCollectionStart();
227     }
228 
GarbageCollectorFinish()229     void GarbageCollectorFinish() override
230     {
231         panda::MTManagedThread *self = panda::MTManagedThread::GetCurrent();
232         if (self == nullptr) {
233             return;
234         }
235         hooks_.GarbageCollectionFinish();
236     }
237 
238     void ObjectAlloc(BaseClass *klass, ObjectHeader *object, ManagedThread *thread, size_t size) override;
239 
240     void ExceptionThrow(ManagedThread *thread, Method *method, ObjectHeader *exceptionObject,
241                         uint32_t bcOffset) override;
242     void ExceptionCatch(ManagedThread *thread, Method *method, ObjectHeader *exceptionObject,
243                         uint32_t bcOffset) override;
244 
245     void MethodEntry(ManagedThread *thread, Method *method) override;
246     void MethodExit(ManagedThread *thread, Method *method) override;
247 
248     void ClassLoad(Class *klass) override;
249     void ClassPrepare(Class *klass) override;
250 
251     void MonitorWait(ObjectHeader *object, int64_t timeout) override;
252     void MonitorWaited(ObjectHeader *object, bool timedOut) override;
253     void MonitorContendedEnter(ObjectHeader *object) override;
254     void MonitorContendedEntered(ObjectHeader *object) override;
255 
256     /*
257      * Mock API for debug interphase starts:
258      *
259      * API's function should be revorked and input parameters should be added
260      */
GetThreadList(PandaVector<PtThread> * threadList)261     std::optional<Error> GetThreadList(PandaVector<PtThread> *threadList) const override
262     {
263         runtime_->GetPandaVM()->GetThreadManager()->EnumerateThreads(
264             [threadList](MTManagedThread *mt_managed_thread) {
265                 ASSERT(mt_managed_thread && "thread is null");
266                 threadList->push_back(PtThread(mt_managed_thread));
267                 return true;
268             },
269             static_cast<unsigned int>(panda::EnumerationFlag::ALL),
270             static_cast<unsigned int>(panda::EnumerationFlag::VM_THREAD));
271 
272         return {};
273     }
274 
GetThreadInfo(PtThread thread,ThreadInfo * infoPtr)275     std::optional<Error> GetThreadInfo([[maybe_unused]] PtThread thread,
276                                        [[maybe_unused]] ThreadInfo *infoPtr) const override
277     {
278         PT_UNIMPLEMENTED();
279         return {};
280     }
281 
282     std::optional<Error> SuspendThread(PtThread thread) const override;
283 
284     std::optional<Error> ResumeThread(PtThread thread) const override;
285 
SetVariable(PtThread thread,uint32_t frameDepth,int32_t regNumber,const PtValue & value)286     std::optional<Error> SetVariable([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth,
287                                      [[maybe_unused]] int32_t regNumber,
288                                      [[maybe_unused]] const PtValue &value) const override
289     {
290         PT_UNIMPLEMENTED();
291         return {};
292     }
293 
294     std::optional<Error> SetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber,
295                                      const VRegValue &value) const override;
296 
GetVariable(PtThread thread,uint32_t frameDepth,int32_t regNumber,PtValue * result)297     std::optional<Error> GetVariable([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth,
298                                      [[maybe_unused]] int32_t regNumber,
299                                      [[maybe_unused]] PtValue *result) const override
300     {
301         PT_UNIMPLEMENTED();
302         return {};
303     }
304 
305     std::optional<Error> GetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber,
306                                      VRegValue *result) const override;
307 
GetProperty(PtObject object,PtProperty property,PtValue * value)308     std::optional<Error> GetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property,
309                                      [[maybe_unused]] PtValue *value) const override
310     {
311         PT_UNIMPLEMENTED();
312         return {};
313     }
314 
SetProperty(PtObject object,PtProperty property,const PtValue & value)315     std::optional<Error> SetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property,
316                                      [[maybe_unused]] const PtValue &value) const override
317     {
318         PT_UNIMPLEMENTED();
319         return {};
320     }
321 
EvaluateExpression(PtThread thread,uint32_t frameNumber,ExpressionWrapper expr,PtValue * result)322     std::optional<Error> EvaluateExpression([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameNumber,
323                                             [[maybe_unused]] ExpressionWrapper expr,
324                                             [[maybe_unused]] PtValue *result) const override
325     {
326         PT_UNIMPLEMENTED();
327         return {};
328     }
329 
RetransformClasses(int classCount,const PtClass * classes)330     std::optional<Error> RetransformClasses([[maybe_unused]] int classCount,
331                                             [[maybe_unused]] const PtClass *classes) const override
332     {
333         PT_UNIMPLEMENTED();
334         return {};
335     }
336 
RedefineClasses(int classCount,const PandaClassDefinition * classes)337     std::optional<Error> RedefineClasses([[maybe_unused]] int classCount,
338                                          [[maybe_unused]] const PandaClassDefinition *classes) const override
339     {
340         PT_UNIMPLEMENTED();
341         return {};
342     }
343 
344     std::optional<Error> RestartFrame([[maybe_unused]] PtThread thread,
345                                       [[maybe_unused]] uint32_t frameNumber) const override;
346 
SetAsyncCallStackDepth(uint32_t maxDepth)347     std::optional<Error> SetAsyncCallStackDepth([[maybe_unused]] uint32_t maxDepth) const override
348     {
349         PT_UNIMPLEMENTED();
350         return {};
351     }
352 
AwaitPromise(PtObject promiseObject,PtValue * result)353     std::optional<Error> AwaitPromise([[maybe_unused]] PtObject promiseObject,
354                                       [[maybe_unused]] PtValue *result) const override
355     {
356         PT_UNIMPLEMENTED();
357         return {};
358     }
359 
CallFunctionOn(PtObject object,PtMethod method,const PandaVector<PtValue> & arguments,PtValue * returnValue)360     std::optional<Error> CallFunctionOn([[maybe_unused]] PtObject object, [[maybe_unused]] PtMethod method,
361                                         [[maybe_unused]] const PandaVector<PtValue> &arguments,
362                                         [[maybe_unused]] PtValue *returnValue) const override
363     {
364         PT_UNIMPLEMENTED();
365         return {};
366     }
367 
GetProperties(uint32_t * countPtr,char *** propertyPtr)368     std::optional<Error> GetProperties([[maybe_unused]] uint32_t *countPtr,
369                                        [[maybe_unused]] char ***propertyPtr) const override
370     {
371         PT_UNIMPLEMENTED();
372         return {};
373     }
374 
375     std::optional<Error> NotifyFramePop(PtThread thread, uint32_t depth) const override;
376 
SetPropertyAccessWatch(PtClass klass,PtProperty property)377     std::optional<Error> SetPropertyAccessWatch([[maybe_unused]] PtClass klass,
378                                                 [[maybe_unused]] PtProperty property) override
379     {
380         PT_UNIMPLEMENTED();
381         return {};
382     }
383 
ClearPropertyAccessWatch(PtClass klass,PtProperty property)384     std::optional<Error> ClearPropertyAccessWatch([[maybe_unused]] PtClass klass,
385                                                   [[maybe_unused]] PtProperty property) override
386     {
387         PT_UNIMPLEMENTED();
388         return {};
389     }
390 
SetPropertyModificationWatch(PtClass klass,PtProperty property)391     std::optional<Error> SetPropertyModificationWatch([[maybe_unused]] PtClass klass,
392                                                       [[maybe_unused]] PtProperty property) override
393     {
394         PT_UNIMPLEMENTED();
395         return {};
396     }
397 
ClearPropertyModificationWatch(PtClass klass,PtProperty property)398     std::optional<Error> ClearPropertyModificationWatch([[maybe_unused]] PtClass klass,
399                                                         [[maybe_unused]] PtProperty property) override
400     {
401         PT_UNIMPLEMENTED();
402         return {};
403     }
404 
GetThisVariableByFrame(PtThread thread,uint32_t frameDepth,PtValue * result)405     std::optional<Error> GetThisVariableByFrame([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth,
406                                                 [[maybe_unused]] PtValue *result) override
407     {
408         PT_UNIMPLEMENTED();
409         return {};
410     }
411     std::optional<Error> GetThisVariableByFrame(PtThread thread, uint32_t frameDepth, ObjectHeader **thisPtr) override;
412 
413     std::optional<Error> SetPropertyAccessWatch(BaseClass *klass, PtProperty property) override;
414 
415     std::optional<Error> ClearPropertyAccessWatch(BaseClass *klass, PtProperty property) override;
416 
417     std::optional<Error> SetPropertyModificationWatch(BaseClass *klass, PtProperty property) override;
418 
419     std::optional<Error> ClearPropertyModificationWatch(BaseClass *klass, PtProperty property) override;
420 
421 private:
422     Expected<interpreter::StaticVRegisterRef, Error> GetVRegByPandaFrame(panda::Frame *frame, int32_t regNumber) const;
423     Expected<interpreter::DynamicVRegisterRef, Error> GetVRegByPandaFrameDyn(panda::Frame *frame,
424                                                                              int32_t regNumber) const;
425     std::optional<Error> CheckLocation(const PtLocation &location);
426     bool IsBreakpoint(const PtLocation &location) const REQUIRES_SHARED(rwlock_);
427     bool EraseBreakpoint(const PtLocation &location);
428 
IsPropertyWatchActive()429     bool IsPropertyWatchActive() const
430     {
431         os::memory::ReadLockHolder rholder(rwlock_);
432         return !property_watches_.empty();
433     }
434     const tooling::PropertyWatch *FindPropertyWatch(panda_file::File::EntityId classId,
435                                                     panda_file::File::EntityId fieldId,
436                                                     tooling::PropertyWatch::Type type) const REQUIRES_SHARED(rwlock_);
437     bool RemovePropertyWatch(panda_file::File::EntityId classId, panda_file::File::EntityId fieldId,
438                              tooling::PropertyWatch::Type type);
439 
440     bool HandleBreakpoint(ManagedThread *thread, Method *method, const PtLocation &location);
441     void HandleNotifyFramePop(ManagedThread *thread, Method *method, bool wasPoppedByException);
442     bool HandleStep(ManagedThread *thread, Method *method, const PtLocation &location);
443 
444     bool HandlePropertyAccess(ManagedThread *thread, Method *method, const PtLocation &location);
445     bool HandlePropertyModify(ManagedThread *thread, Method *method, const PtLocation &location);
446 
447     static constexpr uint32_t DEBUG_EVENT_MASK =
448         RuntimeNotificationManager::Event::LOAD_MODULE | RuntimeNotificationManager::Event::THREAD_EVENTS |
449         RuntimeNotificationManager::Event::BYTECODE_PC_CHANGED | RuntimeNotificationManager::Event::EXCEPTION_EVENTS |
450         RuntimeNotificationManager::Event::VM_EVENTS | RuntimeNotificationManager::Event::GARBAGE_COLLECTOR_EVENTS |
451         RuntimeNotificationManager::Event::METHOD_EVENTS | RuntimeNotificationManager::Event::CLASS_EVENTS |
452         RuntimeNotificationManager::Event::MONITOR_EVENTS | RuntimeNotificationManager::Event::ALLOCATION_EVENTS;
453 
454     const Runtime *runtime_;
455     PtHooksWrapper hooks_;
456 
457     mutable os::memory::RWLock rwlock_;
458     PandaUnorderedSet<PtLocation, HashLocation> breakpoints_ GUARDED_BY(rwlock_);
459     PandaList<PropertyWatch> property_watches_ GUARDED_BY(rwlock_);
460     // TODO(m.strizhak): research how to rework VM start to avoid atomic
461     std::atomic_bool vm_started_ {false};
462 
463     NO_COPY_SEMANTIC(Debugger);
464     NO_MOVE_SEMANTIC(Debugger);
465 };
466 
467 class PtDebugFrame : public PtFrame {
468 public:
469     explicit PtDebugFrame(Method *method, Frame *interpreterFrame);
470     ~PtDebugFrame() override = default;
471 
IsInterpreterFrame()472     bool IsInterpreterFrame() const override
473     {
474         return is_interpreter_frame_;
475     }
476 
GetMethod()477     Method *GetMethod() const override
478     {
479         return method_;
480     }
481 
GetVReg(size_t i)482     uint64_t GetVReg(size_t i) const override
483     {
484         if (!is_interpreter_frame_) {
485             return 0;
486         }
487         return vregs_[i];
488     }
489 
GetVRegNum()490     size_t GetVRegNum() const override
491     {
492         return vregs_.size();
493     }
494 
GetArgument(size_t i)495     uint64_t GetArgument(size_t i) const override
496     {
497         if (!is_interpreter_frame_) {
498             return 0;
499         }
500         return args_[i];
501     }
502 
GetArgumentNum()503     size_t GetArgumentNum() const override
504     {
505         return args_.size();
506     }
507 
GetAccumulator()508     uint64_t GetAccumulator() const override
509     {
510         return acc_;
511     }
512 
GetMethodId()513     panda_file::File::EntityId GetMethodId() const override
514     {
515         return method_id_;
516     }
517 
GetBytecodeOffset()518     uint32_t GetBytecodeOffset() const override
519     {
520         return bc_offset_;
521     }
522 
GetPandaFile()523     std::string GetPandaFile() const override
524     {
525         return panda_file_;
526     }
527 
528     // mock API
GetFrameId()529     uint32_t GetFrameId() const override
530     {
531         return 0;
532     }
533 
534 private:
535     NO_COPY_SEMANTIC(PtDebugFrame);
536     NO_MOVE_SEMANTIC(PtDebugFrame);
537 
538     bool is_interpreter_frame_;
539     Method *method_;
540     uint64_t acc_ {0};
541     PandaVector<uint64_t> vregs_;
542     PandaVector<uint64_t> args_;
543     panda_file::File::EntityId method_id_;
544     uint32_t bc_offset_ {0};
545     std::string panda_file_;
546 };
547 }  // namespace panda::tooling
548 
549 #endif  // PANDA_RUNTIME_DEBUG_DEBUG_H
550