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
16 #include "backend/js_pt_hooks.h"
17 #include "agent/debugger_impl.h"
18 #include "../hybrid_step/debug_step_flags.h"
19
20 namespace panda::ecmascript::tooling {
DebuggerStmt(const JSPtLocation & location)21 void JSPtHooks::DebuggerStmt([[maybe_unused]] const JSPtLocation &location)
22 {
23 LOG_DEBUGGER(DEBUG) << "JSPHooks: Debugger Statement";
24 [[maybe_unused]] LocalScope scope(debugger_->vm_);
25 debugger_->NotifyPaused({}, DEBUGGERSTMT);
26 }
27
Breakpoint(const JSPtLocation & location)28 void JSPtHooks::Breakpoint(const JSPtLocation &location)
29 {
30 LOG_DEBUGGER(DEBUG) << "JSPtHooks: Breakpoint => " << location.GetMethodId() << ": "
31 << location.GetBytecodeOffset();
32
33 [[maybe_unused]] LocalScope scope(debugger_->vm_);
34 debugger_->NotifyPaused(location, OTHER);
35 }
36
Exception(const JSPtLocation & location)37 void JSPtHooks::Exception([[maybe_unused]] const JSPtLocation &location)
38 {
39 LOG_DEBUGGER(DEBUG) << "JSPtHooks: Exception";
40 [[maybe_unused]] LocalScope scope(debugger_->vm_);
41
42 debugger_->NotifyPaused({}, EXCEPTION);
43 }
44
SingleStep(const JSPtLocation & location)45 bool JSPtHooks::SingleStep(const JSPtLocation &location)
46 {
47 [[maybe_unused]] LocalScope scope(debugger_->vm_);
48
49 DebugStepFlags::Get().SetDyn2StatInto(true);
50 if (DebugStepFlags::Get().GetStat2DynInto()) {
51 LOG_DEBUGGER(DEBUG) << "SingleStep from Static";
52 debugger_->NotifyPaused({}, OTHER);
53 DebugStepFlags::Get().SetStat2DynInto(false);
54 return false;
55 }
56 if (UNLIKELY(firstTime_)) {
57 firstTime_ = false;
58
59 debugger_->NotifyPaused({}, BREAK_ON_START);
60 return false;
61 }
62
63 // pause or step complete
64 if (debugger_->NotifySingleStep(location)) {
65 // pause for symbol breakpoint
66 if (breakOnSymbol_) {
67 debugger_->NotifyPaused({}, SYMBOL);
68 breakOnSymbol_ = false;
69 return true;
70 }
71 debugger_->NotifyPaused({}, OTHER);
72 return true;
73 }
74
75 // temporary "safepoint" to handle possible protocol command
76 debugger_->NotifyHandleProtocolCommand();
77
78 return false;
79 }
80
NativeOut()81 bool JSPtHooks::NativeOut()
82 {
83 [[maybe_unused]] LocalScope scope(debugger_->vm_);
84 if (debugger_->NotifyNativeOut()) {
85 debugger_->NotifyPaused({}, NATIVE_OUT);
86 return true;
87 }
88
89 return false;
90 }
91
LoadModule(std::string_view pandaFileName,std::string_view entryPoint)92 void JSPtHooks::LoadModule(std::string_view pandaFileName, std::string_view entryPoint)
93 {
94 LOG_DEBUGGER(DEBUG) << "JSPtHooks: LoadModule: " << pandaFileName;
95
96 [[maybe_unused]] LocalScope scope(debugger_->vm_);
97
98 if (debugger_->NotifyScriptParsed(pandaFileName.data(), entryPoint)) {
99 if (!debugger_->IsLaunchAccelerateMode()) {
100 firstTime_ = true;
101 }
102 }
103 }
104
NativeCalling(const void * nativeAddress)105 void JSPtHooks::NativeCalling(const void *nativeAddress)
106 {
107 LOG_DEBUGGER(DEBUG) << "JSPtHooks: NativeCalling, addr = " << nativeAddress;
108
109 [[maybe_unused]] LocalScope scope(debugger_->vm_);
110
111 debugger_->NotifyNativeCalling(nativeAddress);
112 }
113
NativeReturn(const void * nativeAddress)114 void JSPtHooks::NativeReturn(const void *nativeAddress)
115 {
116 [[maybe_unused]] LocalScope scope(debugger_->vm_);
117
118 debugger_->NotifyNativeReturn(nativeAddress);
119 }
120
SendableMethodEntry(JSHandle<Method> method)121 void JSPtHooks::SendableMethodEntry(JSHandle<Method> method)
122 {
123 LOG_DEBUGGER(DEBUG) << "JSPtHooks: MethodEntry";
124
125 [[maybe_unused]] LocalScope scope(debugger_->vm_);
126
127 if (debugger_->NotifyScriptParsedBySendable(method)) {
128 if (!debugger_->IsLaunchAccelerateMode()) {
129 firstTime_ = true;
130 }
131 }
132 }
133
DisableFirstTimeFlag()134 void JSPtHooks::DisableFirstTimeFlag()
135 {
136 firstTime_ = false;
137 }
138
GenerateAsyncFrames(std::shared_ptr<AsyncStack> asyncStack,bool skipTopFrame)139 void JSPtHooks::GenerateAsyncFrames(std::shared_ptr<AsyncStack> asyncStack, bool skipTopFrame)
140 {
141 [[maybe_unused]] LocalScope scope(debugger_->vm_);
142
143 debugger_->GenerateAsyncFrames(asyncStack, skipTopFrame);
144 }
145
HitSymbolicBreakpoint()146 void JSPtHooks::HitSymbolicBreakpoint()
147 {
148 LOG_DEBUGGER(DEBUG) << "JSPtHooks: HitSymbolicBreakpoint";
149
150 breakOnSymbol_ = true;
151
152 debugger_->SetPauseOnNextByteCode(true);
153 }
154
GetAllRecordNames() const155 const std::unordered_set<std::string> &JSPtHooks::GetAllRecordNames() const
156 {
157 return debugger_->GetAllRecordNames();
158 }
159 } // namespace panda::ecmascript::tooling
160