blob: d7bf191b2e7ca845b87eec0a732367848ec63426 [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
Chris Lattner30fdc8d2010-06-08 16:52:24 +000014#include "lldb/Breakpoint/BreakpointIDList.h"
15
16#include "lldb/Breakpoint/Breakpoint.h"
17#include "lldb/Breakpoint/BreakpointLocation.h"
Jim Ingham40af72e2010-06-15 19:49:27 +000018#include "lldb/Interpreter/Args.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"
21
22using namespace lldb;
23using namespace lldb_private;
24
25//----------------------------------------------------------------------
26// class BreakpointIDList
27//----------------------------------------------------------------------
28
Kate Stoneb9c1b512016-09-06 20:57:50 +000029BreakpointIDList::BreakpointIDList()
30 : m_invalid_id(LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000031
Eugene Zelenko16fd7512015-10-30 18:50:12 +000032BreakpointIDList::~BreakpointIDList() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000033
Jim Inghamdb308772016-09-14 19:05:27 +000034size_t BreakpointIDList::GetSize() const { return m_breakpoint_ids.size(); }
Kate Stoneb9c1b512016-09-06 20:57:50 +000035
Jim Inghamdb308772016-09-14 19:05:27 +000036const BreakpointID &
37BreakpointIDList::GetBreakpointIDAtIndex(size_t index) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +000038 return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]
39 : m_invalid_id);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000040}
41
Kate Stoneb9c1b512016-09-06 20:57:50 +000042bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {
43 if (index >= m_breakpoint_ids.size())
44 return false;
45
46 m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);
47 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000048}
49
Kate Stoneb9c1b512016-09-06 20:57:50 +000050void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000051
Kate Stoneb9c1b512016-09-06 20:57:50 +000052bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {
53 m_breakpoint_ids.push_back(bp_id);
54
55 return true; // We don't do any verification in this function, so always
56 // return true.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000057}
58
Kate Stoneb9c1b512016-09-06 20:57:50 +000059bool BreakpointIDList::AddBreakpointID(const char *bp_id_str) {
60 BreakpointID temp_bp_id;
61 break_id_t bp_id;
62 break_id_t loc_id;
63
64 bool success =
65 BreakpointID::ParseCanonicalReference(bp_id_str, &bp_id, &loc_id);
66
67 if (success) {
68 temp_bp_id.SetID(bp_id, loc_id);
69 m_breakpoint_ids.push_back(temp_bp_id);
70 }
71
72 return success;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000073}
74
Jim Inghamdb308772016-09-14 19:05:27 +000075bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id,
76 size_t *position) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +000077 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) {
78 BreakpointID tmp_id = m_breakpoint_ids[i];
79 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() &&
80 tmp_id.GetLocationID() == bp_id.GetLocationID()) {
81 *position = i;
82 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000083 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000084 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000085
Kate Stoneb9c1b512016-09-06 20:57:50 +000086 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000087}
88
Kate Stoneb9c1b512016-09-06 20:57:50 +000089bool BreakpointIDList::FindBreakpointID(const char *bp_id_str,
Jim Inghamdb308772016-09-14 19:05:27 +000090 size_t *position) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +000091 BreakpointID temp_bp_id;
92 break_id_t bp_id;
93 break_id_t loc_id;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000094
Kate Stoneb9c1b512016-09-06 20:57:50 +000095 if (BreakpointID::ParseCanonicalReference(bp_id_str, &bp_id, &loc_id)) {
96 temp_bp_id.SetID(bp_id, loc_id);
97 return FindBreakpointID(temp_bp_id, position);
98 } else
Chris Lattner30fdc8d2010-06-08 16:52:24 +000099 return false;
100}
101
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102void BreakpointIDList::InsertStringArray(const char **string_array,
103 size_t array_size,
104 CommandReturnObject &result) {
105 if (string_array == nullptr)
106 return;
107
108 for (uint32_t i = 0; i < array_size; ++i) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109 break_id_t bp_id;
110 break_id_t loc_id;
111
Kate Stoneb9c1b512016-09-06 20:57:50 +0000112 if (BreakpointID::ParseCanonicalReference(string_array[i], &bp_id,
113 &loc_id)) {
114 if (bp_id != LLDB_INVALID_BREAK_ID) {
115 BreakpointID temp_bp_id(bp_id, loc_id);
116 m_breakpoint_ids.push_back(temp_bp_id);
117 } else {
118 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
119 string_array[i]);
120 result.SetStatus(eReturnStatusFailed);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000121 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000122 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000123 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124 }
125 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000126}
127
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128// This function takes OLD_ARGS, which is usually the result of breaking the
129// command string arguments into
130// an array of space-separated strings, and searches through the arguments for
131// any breakpoint ID range specifiers.
132// Any string in the array that is not part of an ID range specifier is copied
133// directly into NEW_ARGS. If any
134// ID range specifiers are found, the range is interpreted and a list of
135// canonical breakpoint IDs corresponding to
136// all the current breakpoints and locations in the range are added to
137// NEW_ARGS. When this function is done,
138// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
139// by the members of the range.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000140
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
142 bool allow_locations,
143 CommandReturnObject &result,
144 Args &new_args) {
145 std::string range_start;
146 const char *range_end;
147 const char *current_arg;
148 const size_t num_old_args = old_args.GetArgumentCount();
149 std::set<std::string> names_found;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000150
Kate Stoneb9c1b512016-09-06 20:57:50 +0000151 for (size_t i = 0; i < num_old_args; ++i) {
152 bool is_range = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 current_arg = old_args.GetArgumentAtIndex(i);
155 if (!allow_locations && strchr(current_arg, '.') != nullptr) {
156 result.AppendErrorWithFormat(
157 "Breakpoint locations not allowed, saw location: %s.", current_arg);
158 new_args.Clear();
159 return;
160 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000161
Kate Stoneb9c1b512016-09-06 20:57:50 +0000162 size_t range_start_len = 0;
163 size_t range_end_pos = 0;
164 Error error;
165
166 if (BreakpointIDList::StringContainsIDRangeExpression(
167 current_arg, &range_start_len, &range_end_pos)) {
168 is_range = true;
169 range_start.assign(current_arg, range_start_len);
170 range_end = current_arg + range_end_pos;
Zachary Turner6fa7681b2016-09-17 02:00:02 +0000171 } else if (BreakpointID::StringIsBreakpointName(
172 llvm::StringRef(current_arg), error)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000173 if (!error.Success()) {
174 new_args.Clear();
175 result.AppendError(error.AsCString());
176 result.SetStatus(eReturnStatusFailed);
177 return;
178 } else
179 names_found.insert(current_arg);
180 } else if ((i + 2 < num_old_args) &&
181 BreakpointID::IsRangeIdentifier(
182 old_args.GetArgumentAtIndex(i + 1)) &&
183 BreakpointID::IsValidIDExpression(current_arg) &&
184 BreakpointID::IsValidIDExpression(
185 old_args.GetArgumentAtIndex(i + 2))) {
186 range_start.assign(current_arg);
187 range_end = old_args.GetArgumentAtIndex(i + 2);
188 is_range = true;
189 i = i + 2;
190 } else {
191 // See if user has specified id.*
192 std::string tmp_str = old_args.GetArgumentAtIndex(i);
193 size_t pos = tmp_str.find('.');
194 if (pos != std::string::npos) {
195 std::string bp_id_str = tmp_str.substr(0, pos);
196 if (BreakpointID::IsValidIDExpression(bp_id_str.c_str()) &&
197 tmp_str[pos + 1] == '*' && tmp_str.length() == (pos + 2)) {
198 break_id_t bp_id;
199 break_id_t bp_loc_id;
200
201 BreakpointID::ParseCanonicalReference(bp_id_str.c_str(), &bp_id,
202 &bp_loc_id);
203 BreakpointSP breakpoint_sp = target->GetBreakpointByID(bp_id);
204 if (!breakpoint_sp) {
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000205 new_args.Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000206 result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
207 bp_id);
208 result.SetStatus(eReturnStatusFailed);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000209 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210 }
211 const size_t num_locations = breakpoint_sp->GetNumLocations();
212 for (size_t j = 0; j < num_locations; ++j) {
213 BreakpointLocation *bp_loc =
214 breakpoint_sp->GetLocationAtIndex(j).get();
215 StreamString canonical_id_str;
216 BreakpointID::GetCanonicalReference(&canonical_id_str, bp_id,
217 bp_loc->GetID());
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000218 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000219 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000220 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000221 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000222 }
223
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224 if (is_range) {
225 break_id_t start_bp_id;
226 break_id_t end_bp_id;
227 break_id_t start_loc_id;
228 break_id_t end_loc_id;
229
230 BreakpointID::ParseCanonicalReference(range_start.c_str(), &start_bp_id,
231 &start_loc_id);
232 BreakpointID::ParseCanonicalReference(range_end, &end_bp_id, &end_loc_id);
233
234 if ((start_bp_id == LLDB_INVALID_BREAK_ID) ||
235 (!target->GetBreakpointByID(start_bp_id))) {
236 new_args.Clear();
237 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
238 range_start.c_str());
239 result.SetStatus(eReturnStatusFailed);
240 return;
241 }
242
243 if ((end_bp_id == LLDB_INVALID_BREAK_ID) ||
244 (!target->GetBreakpointByID(end_bp_id))) {
245 new_args.Clear();
246 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
247 range_end);
248 result.SetStatus(eReturnStatusFailed);
249 return;
250 }
251
252 if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
253 (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
254 ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
255 (end_loc_id == LLDB_INVALID_BREAK_ID))) {
256 new_args.Clear();
257 result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
258 "both ends of range must specify"
259 " a breakpoint location, or neither can "
260 "specify a breakpoint location.\n");
261 result.SetStatus(eReturnStatusFailed);
262 return;
263 }
264
265 // We have valid range starting & ending breakpoint IDs. Go through all
266 // the breakpoints in the
267 // target and find all the breakpoints that fit into this range, and add
268 // them to new_args.
269
270 // Next check to see if we have location id's. If so, make sure the
271 // start_bp_id and end_bp_id are
272 // for the same breakpoint; otherwise we have an illegal range: breakpoint
273 // id ranges that specify
274 // bp locations are NOT allowed to cross major bp id numbers.
275
276 if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
277 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
278 if (start_bp_id != end_bp_id) {
279 new_args.Clear();
280 result.AppendErrorWithFormat(
281 "Invalid range: Ranges that specify particular breakpoint "
282 "locations"
283 " must be within the same major breakpoint; you specified two"
284 " different major breakpoints, %d and %d.\n",
285 start_bp_id, end_bp_id);
286 result.SetStatus(eReturnStatusFailed);
287 return;
288 }
289 }
290
291 const BreakpointList &breakpoints = target->GetBreakpointList();
292 const size_t num_breakpoints = breakpoints.GetSize();
293 for (size_t j = 0; j < num_breakpoints; ++j) {
294 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
295 break_id_t cur_bp_id = breakpoint->GetID();
296
297 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
298 continue;
299
300 const size_t num_locations = breakpoint->GetNumLocations();
301
302 if ((cur_bp_id == start_bp_id) &&
303 (start_loc_id != LLDB_INVALID_BREAK_ID)) {
304 for (size_t k = 0; k < num_locations; ++k) {
305 BreakpointLocation *bp_loc =
306 breakpoint->GetLocationAtIndex(k).get();
307 if ((bp_loc->GetID() >= start_loc_id) &&
308 (bp_loc->GetID() <= end_loc_id)) {
309 StreamString canonical_id_str;
310 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
311 bp_loc->GetID());
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000312 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313 }
314 }
315 } else if ((cur_bp_id == end_bp_id) &&
316 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
317 for (size_t k = 0; k < num_locations; ++k) {
318 BreakpointLocation *bp_loc =
319 breakpoint->GetLocationAtIndex(k).get();
320 if (bp_loc->GetID() <= end_loc_id) {
321 StreamString canonical_id_str;
322 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
323 bp_loc->GetID());
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000324 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000325 }
326 }
327 } else {
328 StreamString canonical_id_str;
329 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
330 LLDB_INVALID_BREAK_ID);
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000331 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000332 }
333 }
334 } else // else is_range was false
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000335 {
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000336 new_args.AppendArgument(llvm::StringRef::withNullAsEmpty(current_arg));
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000337 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000339
Kate Stoneb9c1b512016-09-06 20:57:50 +0000340 // Okay, now see if we found any names, and if we did, add them:
341 if (target && names_found.size()) {
342 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
343 for (std::string name : names_found) {
344 if (bkpt_sp->MatchesName(name.c_str())) {
345 StreamString canonical_id_str;
346 BreakpointID::GetCanonicalReference(
347 &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000348 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000349 }
350 }
351 }
352 }
353
354 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000355}
356
Kate Stoneb9c1b512016-09-06 20:57:50 +0000357bool BreakpointIDList::StringContainsIDRangeExpression(const char *in_string,
358 size_t *range_start_len,
359 size_t *range_end_pos) {
360 bool is_range_expression = false;
361 std::string arg_str = in_string;
362 std::string::size_type idx;
363 std::string::size_type start_pos = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000364
Kate Stoneb9c1b512016-09-06 20:57:50 +0000365 *range_start_len = 0;
366 *range_end_pos = 0;
367
368 int specifiers_size = 0;
369 for (int i = 0; BreakpointID::g_range_specifiers[i] != nullptr; ++i)
370 ++specifiers_size;
371
372 for (int i = 0; i < specifiers_size && !is_range_expression; ++i) {
373 const char *specifier_str = BreakpointID::g_range_specifiers[i];
374 size_t len = strlen(specifier_str);
375 idx = arg_str.find(BreakpointID::g_range_specifiers[i]);
376 if (idx != std::string::npos) {
377 *range_start_len = idx - start_pos;
378 std::string start_str = arg_str.substr(start_pos, *range_start_len);
379 if (idx + len < arg_str.length()) {
380 *range_end_pos = idx + len;
381 std::string end_str = arg_str.substr(*range_end_pos);
382 if (BreakpointID::IsValidIDExpression(start_str.c_str()) &&
383 BreakpointID::IsValidIDExpression(end_str.c_str())) {
384 is_range_expression = true;
385 //*range_start = start_str;
386 //*range_end = end_str;
387 }
388 }
389 }
390 }
391
392 if (!is_range_expression) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000393 *range_start_len = 0;
394 *range_end_pos = 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000395 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000396
Kate Stoneb9c1b512016-09-06 20:57:50 +0000397 return is_range_expression;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000398}