1 /**
2 * Copyright (c) 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 "breakpoint_storage.h"
17
18 #include "breakpoint.h"
19 #include "conditional_breakpoint.h"
20 #include "os/mutex.h"
21
22 namespace ark::tooling::inspector {
23
ShouldStopAtBreakpoint(const PtLocation & location,EvaluationEngine & engine)24 bool BreakpointStorage::ShouldStopAtBreakpoint(const PtLocation &location, EvaluationEngine &engine)
25 {
26 os::memory::ReadLockHolder lock(lock_);
27
28 if (!breakpointsActive_) {
29 return false;
30 }
31
32 auto rng = breakpointLocations_.equal_range(location);
33
34 for (auto iter = rng.first; iter != rng.second; ++iter) {
35 BreakpointId bpId = iter->second;
36 bool shouldStop = breakpointStorage_[bpId]->ShouldStopAt(location, engine);
37 if (shouldStop) {
38 return true;
39 }
40 }
41 return false;
42 }
43
ResolveBreakpoints(const panda_file::File & file,const panda_file::DebugInfoExtractor * debugInfoCache)44 void BreakpointStorage::ResolveBreakpoints(const panda_file::File &file,
45 const panda_file::DebugInfoExtractor *debugInfoCache)
46 {
47 os::memory::ReadLockHolder lock(lock_);
48
49 for (auto &[_, bp] : breakpointStorage_) {
50 bp->TryResolve(file, debugInfoCache, breakpointLocations_);
51 // if bp resolved add locations
52 }
53 }
54
RemoveBreakpoint(BreakpointId id)55 void BreakpointStorage::RemoveBreakpoint(BreakpointId id)
56 {
57 os::memory::WriteLockHolder lock(lock_);
58
59 for (auto it = breakpointLocations_.begin(); it != breakpointLocations_.end();) {
60 if (it->second == id) {
61 it = breakpointLocations_.erase(it);
62 } else {
63 ++it;
64 }
65 }
66 breakpointStorage_.erase(id);
67 }
68
SetBreakpoint(SourceFileFilter && sourceFilesFilter,size_t lineNumber,std::set<std::string_view> & sourceFiles,const std::string * condition,const DebugInfoCache & debugCache)69 std::optional<BreakpointId> BreakpointStorage::SetBreakpoint(SourceFileFilter &&sourceFilesFilter, size_t lineNumber,
70 std::set<std::string_view> &sourceFiles,
71 const std::string *condition,
72 const DebugInfoCache &debugCache)
73 {
74 os::memory::WriteLockHolder lock(lock_);
75
76 auto id = nextBreakpointId_;
77 std::unique_ptr<BreakpointBase> bbp;
78
79 if (condition == nullptr) {
80 bbp = std::make_unique<Breakpoint>(id, std::move(sourceFilesFilter), lineNumber, true);
81 } else {
82 bbp = std::make_unique<ConditionalBreakpoint>(id, std::move(sourceFilesFilter), lineNumber, condition);
83 }
84
85 if (!bbp->SetLocations(sourceFiles, debugCache, breakpointLocations_)) {
86 // Only if many locations for conditional bp, it will be destroyed, no need to increase id.
87 return std::nullopt;
88 }
89 // bp with correct locations, or pending with no locations
90 ++nextBreakpointId_;
91 breakpointStorage_[id] = std::move(bbp);
92 return id;
93 }
94
Reset()95 void BreakpointStorage::Reset()
96 {
97 os::memory::WriteLockHolder lock(lock_);
98
99 breakpointsActive_ = true;
100 nextBreakpointId_ = 0;
101 breakpointLocations_.clear();
102 breakpointStorage_.clear();
103 }
104
SetBreakpointsActive(bool active)105 void BreakpointStorage::SetBreakpointsActive(bool active)
106 {
107 os::memory::WriteLockHolder lock(lock_);
108
109 breakpointsActive_ = active;
110 }
111
GetBreakpointsByLocation(const PtLocation & location) const112 std::vector<BreakpointId> BreakpointStorage::GetBreakpointsByLocation(const PtLocation &location) const
113 {
114 os::memory::ReadLockHolder lock(lock_);
115
116 std::vector<BreakpointId> hitBreakpoints;
117
118 auto range = breakpointLocations_.equal_range(location);
119 std::transform(range.first, range.second, std::back_inserter(hitBreakpoints), [](auto &p) { return p.second; });
120
121 return hitBreakpoints;
122 }
123
RemoveBreakpoints(const std::function<bool (const PtLocation & loc)> & filter)124 void BreakpointStorage::RemoveBreakpoints(const std::function<bool(const PtLocation &loc)> &filter)
125 {
126 os::memory::WriteLockHolder lock(lock_);
127
128 std::vector<BreakpointId> breakpointsToRemove;
129 for (const auto &[loc, id] : breakpointLocations_) {
130 if (filter(loc)) {
131 breakpointsToRemove.emplace_back(id);
132 }
133 }
134
135 for (auto id : breakpointsToRemove) {
136 for (auto it = breakpointLocations_.begin(); it != breakpointLocations_.end();) {
137 if (it->second == id) {
138 it = breakpointLocations_.erase(it);
139 } else {
140 ++it;
141 }
142 }
143 breakpointStorage_.erase(id);
144 }
145 }
146
147 } // namespace ark::tooling::inspector
148