• 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), bcOffset_(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 bcOffset_;
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 bcOffset_;
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         : classId_(classId), fieldId_(fieldId), type_(type)
97     {
98     }
99 
100     ~PropertyWatch() = default;
101 
GetClassId()102     panda_file::File::EntityId GetClassId() const
103     {
104         return classId_;
105     }
106 
GetFieldId()107     panda_file::File::EntityId GetFieldId() const
108     {
109         return fieldId_;
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 classId_;
122     panda_file::File::EntityId fieldId_;
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           propertyWatches_(GetInternalAllocatorAdapter(runtime)),
134           vmStarted_(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 * managedThread)196     void ThreadStart(ManagedThread *managedThread) override
197     {
198         hooks_.ThreadStart(PtThread(managedThread));
199     }
200 
ThreadEnd(ManagedThread * managedThread)201     void ThreadEnd(ManagedThread *managedThread) override
202     {
203         hooks_.ThreadEnd(PtThread(managedThread));
204     }
205 
206     void BytecodePcChanged(ManagedThread *thread, Method *method, uint32_t bcOffset) override;
207 
VmStart()208     void VmStart() override
209     {
210         vmStarted_ = true;
211         hooks_.VmStart();
212     }
213 
VmInitialization(ManagedThread * managedThread)214     void VmInitialization(ManagedThread *managedThread) override
215     {
216         hooks_.VmInitialization(PtThread(managedThread));
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 
ConsoleCall(ManagedThread * thread,ConsoleCallType type,uint64_t timestamp,const PandaVector<TypedValue> & arguments)245     void ConsoleCall(ManagedThread *thread, ConsoleCallType type, uint64_t timestamp,
246                      const PandaVector<TypedValue> &arguments) override
247     {
248         hooks_.ConsoleCall(PtThread(thread), type, timestamp, arguments);
249     }
250 
251     void MethodEntry(ManagedThread *thread, Method *method) override;
252     void MethodExit(ManagedThread *thread, Method *method) override;
253 
254     void ClassLoad(Class *klass) override;
255     void ClassPrepare(Class *klass) override;
256 
257     void MonitorWait(ObjectHeader *object, int64_t timeout) override;
258     void MonitorWaited(ObjectHeader *object, bool timedOut) override;
259     void MonitorContendedEnter(ObjectHeader *object) override;
260     void MonitorContendedEntered(ObjectHeader *object) override;
261 
262     /*
263      * Mock API for debug interphase starts:
264      *
265      * API's function should be revorked and input parameters should be added
266      */
GetThreadList(PandaVector<PtThread> * threadList)267     std::optional<Error> GetThreadList(PandaVector<PtThread> *threadList) const override
268     {
269         runtime_->GetPandaVM()->GetThreadManager()->EnumerateThreads(
270             [threadList](ManagedThread *managedThread) {
271                 ASSERT(managedThread && "thread is null");
272                 threadList->push_back(PtThread(managedThread));
273                 return true;
274             },
275             static_cast<unsigned int>(panda::EnumerationFlag::ALL),
276             static_cast<unsigned int>(panda::EnumerationFlag::VM_THREAD));
277 
278         return {};
279     }
280 
GetThreadInfo(PtThread thread,ThreadInfo * infoPtr)281     std::optional<Error> GetThreadInfo([[maybe_unused]] PtThread thread,
282                                        [[maybe_unused]] ThreadInfo *infoPtr) const override
283     {
284         PT_UNIMPLEMENTED();
285         return {};
286     }
287 
288     std::optional<Error> SuspendThread(PtThread thread) const override;
289 
290     std::optional<Error> ResumeThread(PtThread thread) const override;
291 
SetVariable(PtThread thread,uint32_t frameDepth,int32_t regNumber,const PtValue & value)292     std::optional<Error> SetVariable([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth,
293                                      [[maybe_unused]] int32_t regNumber,
294                                      [[maybe_unused]] const PtValue &value) const override
295     {
296         PT_UNIMPLEMENTED();
297         return {};
298     }
299 
300     std::optional<Error> SetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber,
301                                      const VRegValue &value) const override;
302 
GetVariable(PtThread thread,uint32_t frameDepth,int32_t regNumber,PtValue * result)303     std::optional<Error> GetVariable([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth,
304                                      [[maybe_unused]] int32_t regNumber,
305                                      [[maybe_unused]] PtValue *result) const override
306     {
307         PT_UNIMPLEMENTED();
308         return {};
309     }
310 
311     std::optional<Error> GetVariable(PtThread thread, uint32_t frameDepth, int32_t regNumber,
312                                      VRegValue *result) const override;
313 
GetProperty(PtObject object,PtProperty property,PtValue * value)314     std::optional<Error> GetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property,
315                                      [[maybe_unused]] PtValue *value) const override
316     {
317         PT_UNIMPLEMENTED();
318         return {};
319     }
320 
SetProperty(PtObject object,PtProperty property,const PtValue & value)321     std::optional<Error> SetProperty([[maybe_unused]] PtObject object, [[maybe_unused]] PtProperty property,
322                                      [[maybe_unused]] const PtValue &value) const override
323     {
324         PT_UNIMPLEMENTED();
325         return {};
326     }
327 
EvaluateExpression(PtThread thread,uint32_t frameNumber,ExpressionWrapper expr,PtValue * result)328     std::optional<Error> EvaluateExpression([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameNumber,
329                                             [[maybe_unused]] ExpressionWrapper expr,
330                                             [[maybe_unused]] PtValue *result) const override
331     {
332         PT_UNIMPLEMENTED();
333         return {};
334     }
335 
RetransformClasses(int classCount,const PtClass * classes)336     std::optional<Error> RetransformClasses([[maybe_unused]] int classCount,
337                                             [[maybe_unused]] const PtClass *classes) const override
338     {
339         PT_UNIMPLEMENTED();
340         return {};
341     }
342 
RedefineClasses(int classCount,const PandaClassDefinition * classes)343     std::optional<Error> RedefineClasses([[maybe_unused]] int classCount,
344                                          [[maybe_unused]] const PandaClassDefinition *classes) const override
345     {
346         PT_UNIMPLEMENTED();
347         return {};
348     }
349 
350     std::optional<Error> RestartFrame([[maybe_unused]] PtThread thread,
351                                       [[maybe_unused]] uint32_t frameNumber) const override;
352 
SetAsyncCallStackDepth(uint32_t maxDepth)353     std::optional<Error> SetAsyncCallStackDepth([[maybe_unused]] uint32_t maxDepth) const override
354     {
355         PT_UNIMPLEMENTED();
356         return {};
357     }
358 
AwaitPromise(PtObject promiseObject,PtValue * result)359     std::optional<Error> AwaitPromise([[maybe_unused]] PtObject promiseObject,
360                                       [[maybe_unused]] PtValue *result) const override
361     {
362         PT_UNIMPLEMENTED();
363         return {};
364     }
365 
CallFunctionOn(PtObject object,PtMethod method,const PandaVector<PtValue> & arguments,PtValue * returnValue)366     std::optional<Error> CallFunctionOn([[maybe_unused]] PtObject object, [[maybe_unused]] PtMethod method,
367                                         [[maybe_unused]] const PandaVector<PtValue> &arguments,
368                                         [[maybe_unused]] PtValue *returnValue) const override
369     {
370         PT_UNIMPLEMENTED();
371         return {};
372     }
373 
GetProperties(uint32_t * countPtr,char *** propertyPtr)374     std::optional<Error> GetProperties([[maybe_unused]] uint32_t *countPtr,
375                                        [[maybe_unused]] char ***propertyPtr) const override
376     {
377         PT_UNIMPLEMENTED();
378         return {};
379     }
380 
381     std::optional<Error> NotifyFramePop(PtThread thread, uint32_t depth) const override;
382 
SetPropertyAccessWatch(PtClass klass,PtProperty property)383     std::optional<Error> SetPropertyAccessWatch([[maybe_unused]] PtClass klass,
384                                                 [[maybe_unused]] PtProperty property) override
385     {
386         PT_UNIMPLEMENTED();
387         return {};
388     }
389 
ClearPropertyAccessWatch(PtClass klass,PtProperty property)390     std::optional<Error> ClearPropertyAccessWatch([[maybe_unused]] PtClass klass,
391                                                   [[maybe_unused]] PtProperty property) override
392     {
393         PT_UNIMPLEMENTED();
394         return {};
395     }
396 
SetPropertyModificationWatch(PtClass klass,PtProperty property)397     std::optional<Error> SetPropertyModificationWatch([[maybe_unused]] PtClass klass,
398                                                       [[maybe_unused]] PtProperty property) override
399     {
400         PT_UNIMPLEMENTED();
401         return {};
402     }
403 
ClearPropertyModificationWatch(PtClass klass,PtProperty property)404     std::optional<Error> ClearPropertyModificationWatch([[maybe_unused]] PtClass klass,
405                                                         [[maybe_unused]] PtProperty property) override
406     {
407         PT_UNIMPLEMENTED();
408         return {};
409     }
410 
GetThisVariableByFrame(PtThread thread,uint32_t frameDepth,PtValue * result)411     std::optional<Error> GetThisVariableByFrame([[maybe_unused]] PtThread thread, [[maybe_unused]] uint32_t frameDepth,
412                                                 [[maybe_unused]] PtValue *result) override
413     {
414         PT_UNIMPLEMENTED();
415         return {};
416     }
417     std::optional<Error> GetThisVariableByFrame(PtThread thread, uint32_t frameDepth, ObjectHeader **thisPtr) override;
418 
419     std::optional<Error> SetPropertyAccessWatch(BaseClass *klass, PtProperty property) override;
420 
421     std::optional<Error> ClearPropertyAccessWatch(BaseClass *klass, PtProperty property) override;
422 
423     std::optional<Error> SetPropertyModificationWatch(BaseClass *klass, PtProperty property) override;
424 
425     std::optional<Error> ClearPropertyModificationWatch(BaseClass *klass, PtProperty property) override;
426 
427 private:
428     Expected<interpreter::StaticVRegisterRef, Error> GetVRegByPandaFrame(panda::Frame *frame, int32_t regNumber) const;
429     Expected<interpreter::DynamicVRegisterRef, Error> GetVRegByPandaFrameDyn(panda::Frame *frame,
430                                                                              int32_t regNumber) const;
431     std::optional<Error> CheckLocation(const PtLocation &location);
432     bool IsBreakpoint(const PtLocation &location) const REQUIRES_SHARED(rwlock_);
433     bool EraseBreakpoint(const PtLocation &location);
434 
IsPropertyWatchActive()435     bool IsPropertyWatchActive() const
436     {
437         os::memory::ReadLockHolder rholder(rwlock_);
438         return !propertyWatches_.empty();
439     }
440     const tooling::PropertyWatch *FindPropertyWatch(panda_file::File::EntityId classId,
441                                                     panda_file::File::EntityId fieldId,
442                                                     tooling::PropertyWatch::Type type) const REQUIRES_SHARED(rwlock_);
443     bool RemovePropertyWatch(panda_file::File::EntityId classId, panda_file::File::EntityId fieldId,
444                              tooling::PropertyWatch::Type type);
445 
446     bool HandleBreakpoint(ManagedThread *thread, Method *method, const PtLocation &location);
447     void HandleNotifyFramePop(ManagedThread *thread, Method *method, bool wasPoppedByException);
448     bool HandleStep(ManagedThread *thread, Method *method, const PtLocation &location);
449 
450     bool HandlePropertyAccess(ManagedThread *thread, Method *method, const PtLocation &location);
451     bool HandlePropertyModify(ManagedThread *thread, Method *method, const PtLocation &location);
452 
453     static constexpr uint32_t DEBUG_EVENT_MASK =
454         RuntimeNotificationManager::Event::LOAD_MODULE | RuntimeNotificationManager::Event::THREAD_EVENTS |
455         RuntimeNotificationManager::Event::BYTECODE_PC_CHANGED | RuntimeNotificationManager::Event::EXCEPTION_EVENTS |
456         RuntimeNotificationManager::Event::VM_EVENTS | RuntimeNotificationManager::Event::GARBAGE_COLLECTOR_EVENTS |
457         RuntimeNotificationManager::Event::METHOD_EVENTS | RuntimeNotificationManager::Event::CLASS_EVENTS |
458         RuntimeNotificationManager::Event::MONITOR_EVENTS | RuntimeNotificationManager::Event::ALLOCATION_EVENTS |
459         RuntimeNotificationManager::Event::CONSOLE_EVENTS;
460 
461     const Runtime *runtime_;
462     PtHooksWrapper hooks_;
463 
464     mutable os::memory::RWLock rwlock_;
465     PandaUnorderedSet<PtLocation, HashLocation> breakpoints_ GUARDED_BY(rwlock_);
466     PandaList<PropertyWatch> propertyWatches_ GUARDED_BY(rwlock_);
467     // NOTE(m.strizhak): research how to rework VM start to avoid atomic
468     std::atomic_bool vmStarted_ {false};
469 
470     NO_COPY_SEMANTIC(Debugger);
471     NO_MOVE_SEMANTIC(Debugger);
472 };
473 
474 class PtDebugFrame : public PtFrame {
475 public:
476     explicit PANDA_PUBLIC_API PtDebugFrame(Method *method, Frame *interpreterFrame);
477     ~PtDebugFrame() override = default;
478 
IsInterpreterFrame()479     bool IsInterpreterFrame() const override
480     {
481         return isInterpreterFrame_;
482     }
483 
GetMethod()484     Method *GetMethod() const override
485     {
486         return method_;
487     }
488 
GetVReg(size_t i)489     uint64_t GetVReg(size_t i) const override
490     {
491         if (!isInterpreterFrame_) {
492             return 0;
493         }
494         return vregs_[i];
495     }
496 
GetVRegKind(size_t i)497     RegisterKind GetVRegKind(size_t i) const override
498     {
499         if (!isInterpreterFrame_) {
500             return PtFrame::RegisterKind::PRIMITIVE;
501         }
502         return vregKinds_[i];
503     }
504 
GetVRegNum()505     size_t GetVRegNum() const override
506     {
507         return vregs_.size();
508     }
509 
GetArgument(size_t i)510     uint64_t GetArgument(size_t i) const override
511     {
512         if (!isInterpreterFrame_) {
513             return 0;
514         }
515         return args_[i];
516     }
517 
GetArgumentKind(size_t i)518     RegisterKind GetArgumentKind(size_t i) const override
519     {
520         if (!isInterpreterFrame_) {
521             return PtFrame::RegisterKind::PRIMITIVE;
522         }
523         return argKinds_[i];
524     }
525 
GetArgumentNum()526     size_t GetArgumentNum() const override
527     {
528         return args_.size();
529     }
530 
GetAccumulator()531     uint64_t GetAccumulator() const override
532     {
533         return acc_;
534     }
535 
GetAccumulatorKind()536     RegisterKind GetAccumulatorKind() const override
537     {
538         return accKind_;
539     }
540 
GetMethodId()541     panda_file::File::EntityId GetMethodId() const override
542     {
543         return methodId_;
544     }
545 
GetBytecodeOffset()546     uint32_t GetBytecodeOffset() const override
547     {
548         return bcOffset_;
549     }
550 
GetPandaFile()551     std::string GetPandaFile() const override
552     {
553         return pandaFile_;
554     }
555 
556     // mock API
GetFrameId()557     uint32_t GetFrameId() const override
558     {
559         return 0;
560     }
561 
562 private:
563     NO_COPY_SEMANTIC(PtDebugFrame);
564     NO_MOVE_SEMANTIC(PtDebugFrame);
565 
566     bool isInterpreterFrame_;
567     Method *method_;
568     uint64_t acc_ {0};
569     RegisterKind accKind_ {PtFrame::RegisterKind::PRIMITIVE};
570     PandaVector<uint64_t> vregs_;
571     PandaVector<RegisterKind> vregKinds_;
572     PandaVector<uint64_t> args_;
573     PandaVector<RegisterKind> argKinds_;
574     panda_file::File::EntityId methodId_;
575     uint32_t bcOffset_ {0};
576     std::string pandaFile_;
577 };
578 }  // namespace panda::tooling
579 
580 #endif  // PANDA_RUNTIME_DEBUG_DEBUG_H
581