• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2022-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 "thread_state.h"
17 
18 #include <memory>
19 #include <optional>
20 #include <sstream>
21 
22 #include "include/tooling/pt_location.h"
23 #include "macros.h"
24 #include "breakpoint.h"
25 #include "error.h"
26 #include "types/numeric_id.h"
27 
28 #include "../../hybrid_step/debug_step_flags.h"
29 namespace ark::tooling::inspector {
30 
Reset()31 void ThreadState::Reset()
32 {
33     stepKind_ = StepKind::BREAK_ON_START;
34     stepLocations_.clear();
35     methodEntered_ = false;
36     skipAllPauses_ = false;
37     mixedDebugEnabled_ = false;
38     pauseOnExceptionsState_ = PauseOnExceptionsState::NONE;
39 }
40 
BreakOnStart()41 void ThreadState::BreakOnStart()
42 {
43     if (!paused_) {
44         stepKind_ = StepKind::BREAK_ON_START;
45     }
46     breakOnStart_ = true;
47 }
48 
Continue()49 void ThreadState::Continue()
50 {
51     stepKind_ = StepKind::NONE;
52     paused_ = false;
53     pauseReason_ = PauseReason::OTHER;
54 }
55 
ContinueTo(std::unordered_set<PtLocation,HashLocation> locations)56 void ThreadState::ContinueTo(std::unordered_set<PtLocation, HashLocation> locations)
57 {
58     stepKind_ = StepKind::CONTINUE_TO;
59     stepLocations_ = std::move(locations);
60     paused_ = false;
61     pauseReason_ = PauseReason::OTHER;
62 }
63 
StepInto(std::unordered_set<PtLocation,HashLocation> locations)64 void ThreadState::StepInto(std::unordered_set<PtLocation, HashLocation> locations)
65 {
66     stepKind_ = StepKind::STEP_INTO;
67     methodEntered_ = false;
68     stepLocations_ = std::move(locations);
69     paused_ = false;
70     pauseReason_ = PauseReason::STEP;
71 }
72 
StepOver(std::unordered_set<PtLocation,HashLocation> locations)73 void ThreadState::StepOver(std::unordered_set<PtLocation, HashLocation> locations)
74 {
75     stepKind_ = StepKind::STEP_OVER;
76     methodEntered_ = false;
77     stepLocations_ = std::move(locations);
78     paused_ = false;
79     pauseReason_ = PauseReason::STEP;
80 }
81 
StepOut()82 void ThreadState::StepOut()
83 {
84     stepKind_ = StepKind::STEP_OUT;
85     methodEntered_ = true;
86     paused_ = false;
87     pauseReason_ = PauseReason::STEP;
88 }
89 
Pause()90 void ThreadState::Pause()
91 {
92     if (!paused_ && !skipAllPauses_) {
93         stepKind_ = StepKind::PAUSE;
94     }
95 }
96 
SetSkipAllPauses(bool skip)97 void ThreadState::SetSkipAllPauses(bool skip)
98 {
99     skipAllPauses_ = skip;
100 }
101 
102 // NOTE(fangting, #25108): implement "NativeOut" events when in mixed debug mode
SetMixedDebugEnabled(bool mixedDebugEnabled)103 void ThreadState::SetMixedDebugEnabled(bool mixedDebugEnabled)
104 {
105     mixedDebugEnabled_ = mixedDebugEnabled;
106 }
107 
SetPauseOnExceptions(PauseOnExceptionsState state)108 void ThreadState::SetPauseOnExceptions(PauseOnExceptionsState state)
109 {
110     pauseOnExceptionsState_ = state;
111 }
112 
OnException(bool uncaught)113 void ThreadState::OnException(bool uncaught)
114 {
115     ASSERT(!paused_);
116     if (skipAllPauses_) {
117         return;
118     }
119     switch (pauseOnExceptionsState_) {
120         case PauseOnExceptionsState::NONE:
121             break;
122         case PauseOnExceptionsState::CAUGHT:
123             paused_ = !uncaught;
124             break;
125         case PauseOnExceptionsState::UNCAUGHT:
126             paused_ = uncaught;
127             break;
128         case PauseOnExceptionsState::ALL:
129             paused_ = true;
130             break;
131     }
132     if (paused_) {
133         pauseReason_ = PauseReason::EXCEPTION;
134     }
135 }
136 
OnFramePop()137 void ThreadState::OnFramePop()
138 {
139     ASSERT(!paused_);
140     switch (stepKind_) {
141         case StepKind::NONE:
142         case StepKind::BREAK_ON_START:
143         case StepKind::CONTINUE_TO:
144         case StepKind::PAUSE:
145         case StepKind::STEP_INTO: {
146             break;
147         }
148 
149         case StepKind::STEP_OUT:
150         case StepKind::STEP_OVER: {
151             methodEntered_ = false;
152             break;
153         }
154     }
155 }
156 
OnMethodEntry()157 bool ThreadState::OnMethodEntry()
158 {
159     ASSERT(!paused_);
160     switch (stepKind_) {
161         case StepKind::NONE:
162         case StepKind::BREAK_ON_START:
163         case StepKind::CONTINUE_TO:
164         case StepKind::PAUSE:
165         case StepKind::STEP_INTO: {
166             return false;
167         }
168 
169         case StepKind::STEP_OUT:
170         case StepKind::STEP_OVER: {
171             return !std::exchange(methodEntered_, true);
172         }
173     }
174 
175     UNREACHABLE();
176 }
177 
OnSingleStep(const PtLocation & location,const char * sourceFile)178 void ThreadState::OnSingleStep(const PtLocation &location, const char *sourceFile)
179 {
180     ASSERT(!paused_);
181     DebugStepFlags::Get().SetStat2DynInto(true);
182     if (DebugStepFlags::Get().GetDyn2StatInto()) {
183         LOG(DEBUG, DEBUGGER) << "SingleStep from Dynamic";
184         paused_ = true;
185         DebugStepFlags::Get().SetDyn2StatInto(false);
186         return;
187     }
188 
189     if (breakOnStart_) {
190         std::string_view file = sourceFile;
191         if (sourceFiles_.find(file) == sourceFiles_.end()) {
192             sourceFiles_.emplace(file);
193             stepKind_ = StepKind::BREAK_ON_START;
194             paused_ = true;
195             pauseReason_ = PauseReason::BREAK_ON_START;
196             return;
197         }
198     }
199 
200     if (ShouldStopAtBreakpoint(location)) {
201         paused_ = true;
202         return;
203     }
204 
205     switch (stepKind_) {
206         case StepKind::NONE: {
207             paused_ = false;
208             break;
209         }
210 
211         case StepKind::BREAK_ON_START: {
212             paused_ = true;
213             break;
214         }
215 
216         case StepKind::CONTINUE_TO: {
217             paused_ = stepLocations_.find(location) != stepLocations_.end();
218             break;
219         }
220 
221         case StepKind::PAUSE: {
222             paused_ = true;
223             break;
224         }
225 
226         case StepKind::STEP_INTO: {
227             paused_ = stepLocations_.find(location) == stepLocations_.end();
228             break;
229         }
230 
231         case StepKind::STEP_OUT: {
232             paused_ = !methodEntered_;
233             break;
234         }
235 
236         case StepKind::STEP_OVER: {
237             paused_ = !methodEntered_ && stepLocations_.find(location) == stepLocations_.end();
238             break;
239         }
240     }
241 }
242 
ShouldStopAtBreakpoint(const PtLocation & location)243 bool ThreadState::ShouldStopAtBreakpoint(const PtLocation &location)
244 {
245     if (skipAllPauses_) {
246         return false;
247     }
248     return bpStorage_.ShouldStopAtBreakpoint(location, engine_);
249 }
250 
GetBreakpointsByLocation(const PtLocation & location) const251 std::vector<BreakpointId> ThreadState::GetBreakpointsByLocation(const PtLocation &location) const
252 {
253     return bpStorage_.GetBreakpointsByLocation(location);
254 }
255 }  // namespace ark::tooling::inspector
256