• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2022-2024 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 "runtime/tooling/inspector/debuggable_thread.h"
17 
18 namespace ark::tooling::inspector {
DebuggableThread(ManagedThread * thread,SuspensionCallbacks && callbacks)19 DebuggableThread::DebuggableThread(ManagedThread *thread, SuspensionCallbacks &&callbacks)
20     : thread_(thread), callbacks_(std::move(callbacks))
21 {
22     ASSERT(thread);
23 }
24 
Reset()25 void DebuggableThread::Reset()
26 {
27     os::memory::LockHolder lock(mutex_);
28     state_.Reset();
29 }
30 
BreakOnStart()31 void DebuggableThread::BreakOnStart()
32 {
33     os::memory::LockHolder lock(mutex_);
34     state_.BreakOnStart();
35 }
36 
Continue()37 void DebuggableThread::Continue()
38 {
39     os::memory::LockHolder lock(mutex_);
40     state_.Continue();
41     Resume();
42 }
43 
ContinueTo(std::unordered_set<PtLocation,HashLocation> locations)44 void DebuggableThread::ContinueTo(std::unordered_set<PtLocation, HashLocation> locations)
45 {
46     os::memory::LockHolder lock(mutex_);
47     state_.ContinueTo(std::move(locations));
48     Resume();
49 }
50 
StepInto(std::unordered_set<PtLocation,HashLocation> locations)51 void DebuggableThread::StepInto(std::unordered_set<PtLocation, HashLocation> locations)
52 {
53     os::memory::LockHolder lock(mutex_);
54     state_.StepInto(std::move(locations));
55     Resume();
56 }
57 
StepOver(std::unordered_set<PtLocation,HashLocation> locations)58 void DebuggableThread::StepOver(std::unordered_set<PtLocation, HashLocation> locations)
59 {
60     os::memory::LockHolder lock(mutex_);
61     state_.StepOver(std::move(locations));
62     Resume();
63 }
64 
StepOut()65 void DebuggableThread::StepOut()
66 {
67     os::memory::LockHolder lock(mutex_);
68     state_.StepOut();
69     Resume();
70 }
71 
Touch()72 void DebuggableThread::Touch()
73 {
74     os::memory::LockHolder lock(mutex_);
75     Resume();
76 }
77 
Pause()78 void DebuggableThread::Pause()
79 {
80     os::memory::LockHolder lock(mutex_);
81     state_.Pause();
82 }
83 
SetBreakpointsActive(bool active)84 void DebuggableThread::SetBreakpointsActive(bool active)
85 {
86     os::memory::LockHolder lock(mutex_);
87     state_.SetBreakpointsActive(active);
88 }
89 
SetBreakpoint(const std::vector<PtLocation> & locations)90 BreakpointId DebuggableThread::SetBreakpoint(const std::vector<PtLocation> &locations)
91 {
92     os::memory::LockHolder lock(mutex_);
93     return state_.SetBreakpoint(locations);
94 }
95 
RemoveBreakpoint(BreakpointId id)96 void DebuggableThread::RemoveBreakpoint(BreakpointId id)
97 {
98     os::memory::LockHolder lock(mutex_);
99     state_.RemoveBreakpoint(id);
100 }
101 
SetPauseOnExceptions(PauseOnExceptionsState state)102 void DebuggableThread::SetPauseOnExceptions(PauseOnExceptionsState state)
103 {
104     os::memory::LockHolder lock(mutex_);
105     state_.SetPauseOnExceptions(state);
106 }
107 
RequestToObjectRepository(std::function<void (ObjectRepository &)> request)108 bool DebuggableThread::RequestToObjectRepository(std::function<void(ObjectRepository &)> request)
109 {
110     os::memory::LockHolder lock(mutex_);
111 
112     ASSERT(!request_.has_value());
113 
114     if (!suspended_) {
115         return false;
116     }
117 
118     ASSERT(thread_->IsSuspended());
119 
120     request_ = std::move(request);
121     thread_->Resume();
122 
123     while (request_) {
124         requestDone_.Wait(&mutex_);
125     }
126 
127     ASSERT(suspended_);
128     ASSERT(thread_->IsSuspended());
129 
130     return true;
131 }
132 
OnException(bool uncaught)133 void DebuggableThread::OnException(bool uncaught)
134 {
135     os::memory::LockHolder lock(mutex_);
136     state_.OnException(uncaught);
137     while (state_.IsPaused()) {
138         ObjectRepository objectRepository;
139         Suspend(objectRepository, {}, thread_->GetException());
140     }
141 }
142 
OnFramePop()143 void DebuggableThread::OnFramePop()
144 {
145     os::memory::LockHolder lock(mutex_);
146     state_.OnFramePop();
147 }
148 
OnMethodEntry()149 bool DebuggableThread::OnMethodEntry()
150 {
151     os::memory::LockHolder lock(mutex_);
152     return state_.OnMethodEntry();
153 }
154 
OnSingleStep(const PtLocation & location)155 void DebuggableThread::OnSingleStep(const PtLocation &location)
156 {
157     os::memory::LockHolder lock(mutex_);
158     state_.OnSingleStep(location);
159     while (state_.IsPaused()) {
160         ObjectRepository objectRepository;
161         auto hitBreakpoints = state_.GetBreakpointsByLocation(location);
162         Suspend(objectRepository, hitBreakpoints, {});
163     }
164 }
165 
OnConsoleCall(const PandaVector<TypedValue> & arguments)166 std::vector<RemoteObject> DebuggableThread::OnConsoleCall(const PandaVector<TypedValue> &arguments)
167 {
168     std::vector<RemoteObject> result;
169 
170     ObjectRepository objectRepository;
171     std::transform(arguments.begin(), arguments.end(), std::back_inserter(result),
172                    [&objectRepository](auto value) { return objectRepository.CreateObject(value); });
173 
174     return result;
175 }
176 
Suspend(ObjectRepository & objectRepository,const std::vector<BreakpointId> & hitBreakpoints,ObjectHeader * exception)177 void DebuggableThread::Suspend(ObjectRepository &objectRepository, const std::vector<BreakpointId> &hitBreakpoints,
178                                ObjectHeader *exception)
179 {
180     ASSERT(ManagedThread::GetCurrent() == thread_);
181 
182     ASSERT(!suspended_);
183     ASSERT(!request_.has_value());
184 
185     callbacks_.preSuspend(objectRepository, hitBreakpoints, exception);
186 
187     suspended_ = true;
188     thread_->Suspend();
189 
190     callbacks_.postSuspend(objectRepository, hitBreakpoints, exception);
191 
192     while (suspended_) {
193         mutex_.Unlock();
194 
195         callbacks_.preWaitSuspension();
196         thread_->WaitSuspension();
197         callbacks_.postWaitSuspension();
198 
199         mutex_.Lock();
200 
201         // We have three levels of suspension:
202         // - state_.IsPaused() - tells if the thread is paused on breakpoint or step;
203         // - suspended_ - tells if the thread generally sleeps (but could execute object repository requests);
204         // - thread_->IsSuspended() - tells if the thread is actually sleeping
205         //
206         // If we are here, then the latter is false (thread waked up). The following variants are possible:
207         // - not paused and not suspended - e.g. continue / stepping action was performed;
208         // - not paused and suspended - invalid;
209         // - paused and not suspended - touch was performed, resume and sleep back
210         //     (used to notify about the state on `runIfWaitingForDebugger`);
211         // - paused and suspended - object repository request was made.
212 
213         ASSERT(suspended_ == request_.has_value());
214 
215         if (request_) {
216             (*request_)(objectRepository);
217 
218             request_.reset();
219             thread_->Suspend();
220 
221             requestDone_.Signal();
222         }
223     }
224 }
225 
Resume()226 void DebuggableThread::Resume()
227 {
228     ASSERT(!request_.has_value());
229 
230     if (!suspended_) {
231         return;
232     }
233 
234     ASSERT(thread_->IsSuspended());
235 
236     callbacks_.preResume();
237 
238     suspended_ = false;
239     thread_->Resume();
240 
241     callbacks_.postResume();
242 }
243 }  // namespace ark::tooling::inspector
244