1 //===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 // Other libraries and framework includes
14 #include "lldb/lldb-enumerations.h"
15 #include "lldb/Breakpoint/BreakpointIDList.h"
17 #include "lldb/Breakpoint/Breakpoint.h"
18 #include "lldb/Breakpoint/BreakpointLocation.h"
19 #include "lldb/Interpreter/CommandReturnObject.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Utility/Args.h"
24 using namespace lldb_private;
26 //----------------------------------------------------------------------
27 // class BreakpointIDList
28 //----------------------------------------------------------------------
30 BreakpointIDList::BreakpointIDList()
31 : m_invalid_id(LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID) {}
33 BreakpointIDList::~BreakpointIDList() = default;
35 size_t BreakpointIDList::GetSize() const { return m_breakpoint_ids.size(); }
38 BreakpointIDList::GetBreakpointIDAtIndex(size_t index) const {
39 return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]
43 bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {
44 if (index >= m_breakpoint_ids.size())
47 m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);
51 void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }
53 bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {
54 m_breakpoint_ids.push_back(bp_id);
56 return true; // We don't do any verification in this function, so always
60 bool BreakpointIDList::AddBreakpointID(const char *bp_id_str) {
61 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
62 if (!bp_id.hasValue())
65 m_breakpoint_ids.push_back(*bp_id);
69 bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id,
70 size_t *position) const {
71 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) {
72 BreakpointID tmp_id = m_breakpoint_ids[i];
73 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() &&
74 tmp_id.GetLocationID() == bp_id.GetLocationID()) {
83 bool BreakpointIDList::FindBreakpointID(const char *bp_id_str,
84 size_t *position) const {
85 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
86 if (!bp_id.hasValue())
89 return FindBreakpointID(*bp_id, position);
92 void BreakpointIDList::InsertStringArray(
93 llvm::ArrayRef<const char *> string_array, CommandReturnObject &result) {
94 if(string_array.empty())
97 for (const char *str : string_array) {
98 auto bp_id = BreakpointID::ParseCanonicalReference(str);
100 m_breakpoint_ids.push_back(*bp_id);
102 result.SetStatus(eReturnStatusSuccessFinishNoResult);
105 // This function takes OLD_ARGS, which is usually the result of breaking the
106 // command string arguments into
107 // an array of space-separated strings, and searches through the arguments for
108 // any breakpoint ID range specifiers.
109 // Any string in the array that is not part of an ID range specifier is copied
110 // directly into NEW_ARGS. If any
111 // ID range specifiers are found, the range is interpreted and a list of
112 // canonical breakpoint IDs corresponding to
113 // all the current breakpoints and locations in the range are added to
114 // NEW_ARGS. When this function is done,
115 // NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
116 // by the members of the range.
118 void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
119 bool allow_locations,
120 BreakpointName::Permissions
121 ::PermissionKinds purpose,
122 CommandReturnObject &result,
124 llvm::StringRef range_from;
125 llvm::StringRef range_to;
126 llvm::StringRef current_arg;
127 std::set<std::string> names_found;
129 for (size_t i = 0; i < old_args.size(); ++i) {
130 bool is_range = false;
132 current_arg = old_args[i].ref;
133 if (!allow_locations && current_arg.contains('.')) {
134 result.AppendErrorWithFormat(
135 "Breakpoint locations not allowed, saw location: %s.",
136 current_arg.str().c_str());
143 std::tie(range_from, range_to) =
144 BreakpointIDList::SplitIDRangeExpression(current_arg);
145 if (!range_from.empty() && !range_to.empty()) {
147 } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
148 if (!error.Success()) {
150 result.AppendError(error.AsCString());
151 result.SetStatus(eReturnStatusFailed);
154 names_found.insert(current_arg);
155 } else if ((i + 2 < old_args.size()) &&
156 BreakpointID::IsRangeIdentifier(old_args[i + 1].ref) &&
157 BreakpointID::IsValidIDExpression(current_arg) &&
158 BreakpointID::IsValidIDExpression(old_args[i + 2].ref)) {
159 range_from = current_arg;
160 range_to = old_args[i + 2].ref;
164 // See if user has specified id.*
165 llvm::StringRef tmp_str = old_args[i].ref;
166 size_t pos = tmp_str.find('.');
167 if (pos != llvm::StringRef::npos) {
168 llvm::StringRef bp_id_str = tmp_str.substr(0, pos);
169 if (BreakpointID::IsValidIDExpression(bp_id_str) &&
170 tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) {
172 BreakpointSP breakpoint_sp;
173 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
174 if (bp_id.hasValue())
175 breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());
176 if (!breakpoint_sp) {
178 result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
179 bp_id->GetBreakpointID());
180 result.SetStatus(eReturnStatusFailed);
183 const size_t num_locations = breakpoint_sp->GetNumLocations();
184 for (size_t j = 0; j < num_locations; ++j) {
185 BreakpointLocation *bp_loc =
186 breakpoint_sp->GetLocationAtIndex(j).get();
187 StreamString canonical_id_str;
188 BreakpointID::GetCanonicalReference(
189 &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());
190 new_args.AppendArgument(canonical_id_str.GetString());
197 new_args.AppendArgument(current_arg);
201 auto start_bp = BreakpointID::ParseCanonicalReference(range_from);
202 auto end_bp = BreakpointID::ParseCanonicalReference(range_to);
204 if (!start_bp.hasValue() ||
205 !target->GetBreakpointByID(start_bp->GetBreakpointID())) {
207 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
208 range_from.str().c_str());
209 result.SetStatus(eReturnStatusFailed);
213 if (!end_bp.hasValue() ||
214 !target->GetBreakpointByID(end_bp->GetBreakpointID())) {
216 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
217 range_to.str().c_str());
218 result.SetStatus(eReturnStatusFailed);
221 break_id_t start_bp_id = start_bp->GetBreakpointID();
222 break_id_t start_loc_id = start_bp->GetLocationID();
223 break_id_t end_bp_id = end_bp->GetBreakpointID();
224 break_id_t end_loc_id = end_bp->GetLocationID();
225 if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
226 (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
227 ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
228 (end_loc_id == LLDB_INVALID_BREAK_ID))) {
230 result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
231 "both ends of range must specify"
232 " a breakpoint location, or neither can "
233 "specify a breakpoint location.\n");
234 result.SetStatus(eReturnStatusFailed);
238 // We have valid range starting & ending breakpoint IDs. Go through all
239 // the breakpoints in the target and find all the breakpoints that fit into
240 // this range, and add them to new_args.
242 // Next check to see if we have location id's. If so, make sure the
243 // start_bp_id and end_bp_id are for the same breakpoint; otherwise we have
244 // an illegal range: breakpoint id ranges that specify bp locations are NOT
245 // allowed to cross major bp id numbers.
247 if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
248 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
249 if (start_bp_id != end_bp_id) {
251 result.AppendErrorWithFormat(
252 "Invalid range: Ranges that specify particular breakpoint "
254 " must be within the same major breakpoint; you specified two"
255 " different major breakpoints, %d and %d.\n",
256 start_bp_id, end_bp_id);
257 result.SetStatus(eReturnStatusFailed);
262 const BreakpointList &breakpoints = target->GetBreakpointList();
263 const size_t num_breakpoints = breakpoints.GetSize();
264 for (size_t j = 0; j < num_breakpoints; ++j) {
265 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
266 break_id_t cur_bp_id = breakpoint->GetID();
268 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
271 const size_t num_locations = breakpoint->GetNumLocations();
273 if ((cur_bp_id == start_bp_id) &&
274 (start_loc_id != LLDB_INVALID_BREAK_ID)) {
275 for (size_t k = 0; k < num_locations; ++k) {
276 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
277 if ((bp_loc->GetID() >= start_loc_id) &&
278 (bp_loc->GetID() <= end_loc_id)) {
279 StreamString canonical_id_str;
280 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
282 new_args.AppendArgument(canonical_id_str.GetString());
285 } else if ((cur_bp_id == end_bp_id) &&
286 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
287 for (size_t k = 0; k < num_locations; ++k) {
288 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
289 if (bp_loc->GetID() <= end_loc_id) {
290 StreamString canonical_id_str;
291 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
293 new_args.AppendArgument(canonical_id_str.GetString());
297 StreamString canonical_id_str;
298 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
299 LLDB_INVALID_BREAK_ID);
300 new_args.AppendArgument(canonical_id_str.GetString());
305 // Okay, now see if we found any names, and if we did, add them:
306 if (target && !names_found.empty()) {
308 // Remove any names that aren't visible for this purpose:
309 auto iter = names_found.begin();
310 while (iter != names_found.end()) {
311 BreakpointName *bp_name = target->FindBreakpointName(ConstString(*iter),
314 if (bp_name && !bp_name->GetPermission(purpose))
315 iter = names_found.erase(iter);
320 if (!names_found.empty()) {
321 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
322 for (std::string name : names_found) {
323 if (bkpt_sp->MatchesName(name.c_str())) {
324 StreamString canonical_id_str;
325 BreakpointID::GetCanonicalReference(
326 &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
327 new_args.AppendArgument(canonical_id_str.GetString());
334 result.SetStatus(eReturnStatusSuccessFinishNoResult);
337 std::pair<llvm::StringRef, llvm::StringRef>
338 BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {
339 for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {
340 size_t idx = in_string.find(specifier_str);
341 if (idx == llvm::StringRef::npos)
343 llvm::StringRef right1 = in_string.drop_front(idx);
345 llvm::StringRef from = in_string.take_front(idx);
346 llvm::StringRef to = right1.drop_front(specifier_str.size());
348 if (BreakpointID::IsValidIDExpression(from) &&
349 BreakpointID::IsValidIDExpression(to)) {
350 return std::make_pair(from, to);
354 return std::pair<llvm::StringRef, llvm::StringRef>();