blob: 8fa127209402c175c54a4e19ca4b9b52de121ef8 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Eugene Zelenko16fd7512015-10-30 18:50:12 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
Jim Inghamb842f2e2017-09-14 20:22:49 +000014#include "lldb/lldb-enumerations.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000015#include "lldb/Breakpoint/BreakpointIDList.h"
16
17#include "lldb/Breakpoint/Breakpoint.h"
18#include "lldb/Breakpoint/BreakpointLocation.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000019#include "lldb/Interpreter/CommandReturnObject.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000020#include "lldb/Target/Target.h"
Pavel Labath145d95c2018-04-17 18:53:35 +000021#include "lldb/Utility/Args.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000022
23using namespace lldb;
24using namespace lldb_private;
25
26//----------------------------------------------------------------------
27// class BreakpointIDList
28//----------------------------------------------------------------------
29
Kate Stoneb9c1b512016-09-06 20:57:50 +000030BreakpointIDList::BreakpointIDList()
31 : m_invalid_id(LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000032
Eugene Zelenko16fd7512015-10-30 18:50:12 +000033BreakpointIDList::~BreakpointIDList() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000034
Jim Inghamdb308772016-09-14 19:05:27 +000035size_t BreakpointIDList::GetSize() const { return m_breakpoint_ids.size(); }
Kate Stoneb9c1b512016-09-06 20:57:50 +000036
Jim Inghamdb308772016-09-14 19:05:27 +000037const BreakpointID &
38BreakpointIDList::GetBreakpointIDAtIndex(size_t index) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +000039 return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]
40 : m_invalid_id);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000041}
42
Kate Stoneb9c1b512016-09-06 20:57:50 +000043bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {
44 if (index >= m_breakpoint_ids.size())
45 return false;
46
47 m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);
48 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000049}
50
Kate Stoneb9c1b512016-09-06 20:57:50 +000051void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000052
Kate Stoneb9c1b512016-09-06 20:57:50 +000053bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {
54 m_breakpoint_ids.push_back(bp_id);
55
56 return true; // We don't do any verification in this function, so always
57 // return true.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000058}
59
Kate Stoneb9c1b512016-09-06 20:57:50 +000060bool BreakpointIDList::AddBreakpointID(const char *bp_id_str) {
Zachary Turner401f55d2016-10-05 17:07:47 +000061 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
62 if (!bp_id.hasValue())
63 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +000064
Zachary Turner401f55d2016-10-05 17:07:47 +000065 m_breakpoint_ids.push_back(*bp_id);
66 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000067}
68
Jim Inghamdb308772016-09-14 19:05:27 +000069bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id,
70 size_t *position) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +000071 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()) {
75 *position = i;
76 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000077 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000078 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000079
Kate Stoneb9c1b512016-09-06 20:57:50 +000080 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000081}
82
Kate Stoneb9c1b512016-09-06 20:57:50 +000083bool BreakpointIDList::FindBreakpointID(const char *bp_id_str,
Jim Inghamdb308772016-09-14 19:05:27 +000084 size_t *position) const {
Zachary Turner401f55d2016-10-05 17:07:47 +000085 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
86 if (!bp_id.hasValue())
Chris Lattner30fdc8d2010-06-08 16:52:24 +000087 return false;
Zachary Turner401f55d2016-10-05 17:07:47 +000088
89 return FindBreakpointID(*bp_id, position);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000090}
91
Kate Stoneb9c1b512016-09-06 20:57:50 +000092void BreakpointIDList::InsertStringArray(const char **string_array,
93 size_t array_size,
94 CommandReturnObject &result) {
95 if (string_array == nullptr)
96 return;
97
98 for (uint32_t i = 0; i < array_size; ++i) {
Zachary Turner401f55d2016-10-05 17:07:47 +000099 auto bp_id = BreakpointID::ParseCanonicalReference(string_array[i]);
Zachary Turner0d4f23c2016-10-05 18:40:51 +0000100 if (bp_id.hasValue())
Zachary Turner401f55d2016-10-05 17:07:47 +0000101 m_breakpoint_ids.push_back(*bp_id);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102 }
103 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000104}
105
Kate Stoneb9c1b512016-09-06 20:57:50 +0000106// This function takes OLD_ARGS, which is usually the result of breaking the
107// command string arguments into
108// an array of space-separated strings, and searches through the arguments for
109// any breakpoint ID range specifiers.
110// Any string in the array that is not part of an ID range specifier is copied
111// directly into NEW_ARGS. If any
112// ID range specifiers are found, the range is interpreted and a list of
113// canonical breakpoint IDs corresponding to
114// all the current breakpoints and locations in the range are added to
115// NEW_ARGS. When this function is done,
116// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
117// by the members of the range.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000118
Kate Stoneb9c1b512016-09-06 20:57:50 +0000119void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
120 bool allow_locations,
Jim Inghamb842f2e2017-09-14 20:22:49 +0000121 BreakpointName::Permissions
122 ::PermissionKinds purpose,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000123 CommandReturnObject &result,
124 Args &new_args) {
Zachary Turner401f55d2016-10-05 17:07:47 +0000125 llvm::StringRef range_from;
126 llvm::StringRef range_to;
127 llvm::StringRef current_arg;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 std::set<std::string> names_found;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000129
Zachary Turnerd6a24752016-11-22 17:10:15 +0000130 for (size_t i = 0; i < old_args.size(); ++i) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000131 bool is_range = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000132
Zachary Turnerd6a24752016-11-22 17:10:15 +0000133 current_arg = old_args[i].ref;
Zachary Turner401f55d2016-10-05 17:07:47 +0000134 if (!allow_locations && current_arg.contains('.')) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135 result.AppendErrorWithFormat(
Zachary Turner401f55d2016-10-05 17:07:47 +0000136 "Breakpoint locations not allowed, saw location: %s.",
137 current_arg.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138 new_args.Clear();
139 return;
140 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000141
Zachary Turner97206d52017-05-12 04:51:55 +0000142 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143
Zachary Turner401f55d2016-10-05 17:07:47 +0000144 std::tie(range_from, range_to) =
145 BreakpointIDList::SplitIDRangeExpression(current_arg);
146 if (!range_from.empty() && !range_to.empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 is_range = true;
Zachary Turner401f55d2016-10-05 17:07:47 +0000148 } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 if (!error.Success()) {
150 new_args.Clear();
151 result.AppendError(error.AsCString());
152 result.SetStatus(eReturnStatusFailed);
153 return;
154 } else
155 names_found.insert(current_arg);
Zachary Turnerd6a24752016-11-22 17:10:15 +0000156 } else if ((i + 2 < old_args.size()) &&
157 BreakpointID::IsRangeIdentifier(old_args[i + 1].ref) &&
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158 BreakpointID::IsValidIDExpression(current_arg) &&
Zachary Turnerd6a24752016-11-22 17:10:15 +0000159 BreakpointID::IsValidIDExpression(old_args[i + 2].ref)) {
Zachary Turner401f55d2016-10-05 17:07:47 +0000160 range_from = current_arg;
Zachary Turnerd6a24752016-11-22 17:10:15 +0000161 range_to = old_args[i + 2].ref;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000162 is_range = true;
163 i = i + 2;
164 } else {
165 // See if user has specified id.*
Zachary Turnerd6a24752016-11-22 17:10:15 +0000166 llvm::StringRef tmp_str = old_args[i].ref;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 size_t pos = tmp_str.find('.');
Zachary Turner401f55d2016-10-05 17:07:47 +0000168 if (pos != llvm::StringRef::npos) {
169 llvm::StringRef bp_id_str = tmp_str.substr(0, pos);
170 if (BreakpointID::IsValidIDExpression(bp_id_str) &&
171 tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000172
Zachary Turner401f55d2016-10-05 17:07:47 +0000173 BreakpointSP breakpoint_sp;
174 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
175 if (bp_id.hasValue())
176 breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000177 if (!breakpoint_sp) {
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000178 new_args.Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179 result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
Zachary Turner401f55d2016-10-05 17:07:47 +0000180 bp_id->GetBreakpointID());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181 result.SetStatus(eReturnStatusFailed);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000182 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000183 }
184 const size_t num_locations = breakpoint_sp->GetNumLocations();
185 for (size_t j = 0; j < num_locations; ++j) {
186 BreakpointLocation *bp_loc =
187 breakpoint_sp->GetLocationAtIndex(j).get();
188 StreamString canonical_id_str;
Zachary Turner401f55d2016-10-05 17:07:47 +0000189 BreakpointID::GetCanonicalReference(
190 &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000191 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000193 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000194 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000195 }
196
Zachary Turner401f55d2016-10-05 17:07:47 +0000197 if (!is_range) {
198 new_args.AppendArgument(current_arg);
199 continue;
200 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000201
Zachary Turner401f55d2016-10-05 17:07:47 +0000202 auto start_bp = BreakpointID::ParseCanonicalReference(range_from);
203 auto end_bp = BreakpointID::ParseCanonicalReference(range_to);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000204
Zachary Turner401f55d2016-10-05 17:07:47 +0000205 if (!start_bp.hasValue() ||
206 !target->GetBreakpointByID(start_bp->GetBreakpointID())) {
207 new_args.Clear();
208 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
209 range_from.str().c_str());
210 result.SetStatus(eReturnStatusFailed);
211 return;
212 }
213
214 if (!end_bp.hasValue() ||
215 !target->GetBreakpointByID(end_bp->GetBreakpointID())) {
216 new_args.Clear();
217 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
218 range_to.str().c_str());
219 result.SetStatus(eReturnStatusFailed);
220 return;
221 }
222 break_id_t start_bp_id = start_bp->GetBreakpointID();
223 break_id_t start_loc_id = start_bp->GetLocationID();
224 break_id_t end_bp_id = end_bp->GetBreakpointID();
225 break_id_t end_loc_id = end_bp->GetLocationID();
Zachary Turner0d4f23c2016-10-05 18:40:51 +0000226 if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
227 (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
Zachary Turner401f55d2016-10-05 17:07:47 +0000228 ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
229 (end_loc_id == LLDB_INVALID_BREAK_ID))) {
230 new_args.Clear();
231 result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
232 "both ends of range must specify"
233 " a breakpoint location, or neither can "
234 "specify a breakpoint location.\n");
235 result.SetStatus(eReturnStatusFailed);
236 return;
237 }
238
239 // We have valid range starting & ending breakpoint IDs. Go through all
Adrian Prantl05097242018-04-30 16:49:04 +0000240 // the breakpoints in the target and find all the breakpoints that fit into
241 // this range, and add them to new_args.
Zachary Turner401f55d2016-10-05 17:07:47 +0000242
243 // Next check to see if we have location id's. If so, make sure the
Adrian Prantl05097242018-04-30 16:49:04 +0000244 // start_bp_id and end_bp_id are for the same breakpoint; otherwise we have
245 // an illegal range: breakpoint id ranges that specify bp locations are NOT
246 // allowed to cross major bp id numbers.
Zachary Turner401f55d2016-10-05 17:07:47 +0000247
248 if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
249 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
250 if (start_bp_id != end_bp_id) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000251 new_args.Clear();
Zachary Turner401f55d2016-10-05 17:07:47 +0000252 result.AppendErrorWithFormat(
253 "Invalid range: Ranges that specify particular breakpoint "
254 "locations"
255 " must be within the same major breakpoint; you specified two"
256 " different major breakpoints, %d and %d.\n",
257 start_bp_id, end_bp_id);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000258 result.SetStatus(eReturnStatusFailed);
259 return;
260 }
Zachary Turner401f55d2016-10-05 17:07:47 +0000261 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262
Zachary Turner401f55d2016-10-05 17:07:47 +0000263 const BreakpointList &breakpoints = target->GetBreakpointList();
264 const size_t num_breakpoints = breakpoints.GetSize();
265 for (size_t j = 0; j < num_breakpoints; ++j) {
266 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
267 break_id_t cur_bp_id = breakpoint->GetID();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000268
Zachary Turner401f55d2016-10-05 17:07:47 +0000269 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
270 continue;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000271
Zachary Turner401f55d2016-10-05 17:07:47 +0000272 const size_t num_locations = breakpoint->GetNumLocations();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000273
Zachary Turner401f55d2016-10-05 17:07:47 +0000274 if ((cur_bp_id == start_bp_id) &&
275 (start_loc_id != LLDB_INVALID_BREAK_ID)) {
276 for (size_t k = 0; k < num_locations; ++k) {
277 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
278 if ((bp_loc->GetID() >= start_loc_id) &&
279 (bp_loc->GetID() <= end_loc_id)) {
280 StreamString canonical_id_str;
281 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
282 bp_loc->GetID());
283 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000284 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000285 }
Zachary Turner401f55d2016-10-05 17:07:47 +0000286 } else if ((cur_bp_id == end_bp_id) &&
287 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
288 for (size_t k = 0; k < num_locations; ++k) {
289 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
290 if (bp_loc->GetID() <= end_loc_id) {
291 StreamString canonical_id_str;
292 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
293 bp_loc->GetID());
294 new_args.AppendArgument(canonical_id_str.GetString());
295 }
296 }
297 } else {
298 StreamString canonical_id_str;
299 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
300 LLDB_INVALID_BREAK_ID);
301 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000302 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000303 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000304 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000305
Kate Stoneb9c1b512016-09-06 20:57:50 +0000306 // Okay, now see if we found any names, and if we did, add them:
Jim Inghamb842f2e2017-09-14 20:22:49 +0000307 if (target && !names_found.empty()) {
308 Status error;
309 // Remove any names that aren't visible for this purpose:
310 auto iter = names_found.begin();
311 while (iter != names_found.end()) {
312 BreakpointName *bp_name = target->FindBreakpointName(ConstString(*iter),
313 true,
314 error);
315 if (bp_name && !bp_name->GetPermission(purpose))
316 iter = names_found.erase(iter);
317 else
318 iter++;
319 }
320
321 if (!names_found.empty()) {
322 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
323 for (std::string name : names_found) {
324 if (bkpt_sp->MatchesName(name.c_str())) {
325 StreamString canonical_id_str;
326 BreakpointID::GetCanonicalReference(
327 &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
328 new_args.AppendArgument(canonical_id_str.GetString());
329 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000330 }
331 }
332 }
333 }
334
335 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000336}
337
Zachary Turner401f55d2016-10-05 17:07:47 +0000338std::pair<llvm::StringRef, llvm::StringRef>
339BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {
340 for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {
341 size_t idx = in_string.find(specifier_str);
342 if (idx == llvm::StringRef::npos)
343 continue;
344 llvm::StringRef right1 = in_string.drop_front(idx);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000345
Zachary Turner401f55d2016-10-05 17:07:47 +0000346 llvm::StringRef from = in_string.take_front(idx);
347 llvm::StringRef to = right1.drop_front(specifier_str.size());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348
Zachary Turner401f55d2016-10-05 17:07:47 +0000349 if (BreakpointID::IsValidIDExpression(from) &&
350 BreakpointID::IsValidIDExpression(to)) {
351 return std::make_pair(from, to);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000352 }
353 }
354
Zachary Turner401f55d2016-10-05 17:07:47 +0000355 return std::pair<llvm::StringRef, llvm::StringRef>();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000356}