blob: 4c09bd7410bfe526a5924513f564ba7dd9b2e65f [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;
171 } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
172 if (!error.Success()) {
173 new_args.Clear();
174 result.AppendError(error.AsCString());
175 result.SetStatus(eReturnStatusFailed);
176 return;
177 } else
178 names_found.insert(current_arg);
179 } else if ((i + 2 < num_old_args) &&
180 BreakpointID::IsRangeIdentifier(
181 old_args.GetArgumentAtIndex(i + 1)) &&
182 BreakpointID::IsValidIDExpression(current_arg) &&
183 BreakpointID::IsValidIDExpression(
184 old_args.GetArgumentAtIndex(i + 2))) {
185 range_start.assign(current_arg);
186 range_end = old_args.GetArgumentAtIndex(i + 2);
187 is_range = true;
188 i = i + 2;
189 } else {
190 // See if user has specified id.*
191 std::string tmp_str = old_args.GetArgumentAtIndex(i);
192 size_t pos = tmp_str.find('.');
193 if (pos != std::string::npos) {
194 std::string bp_id_str = tmp_str.substr(0, pos);
195 if (BreakpointID::IsValidIDExpression(bp_id_str.c_str()) &&
196 tmp_str[pos + 1] == '*' && tmp_str.length() == (pos + 2)) {
197 break_id_t bp_id;
198 break_id_t bp_loc_id;
199
200 BreakpointID::ParseCanonicalReference(bp_id_str.c_str(), &bp_id,
201 &bp_loc_id);
202 BreakpointSP breakpoint_sp = target->GetBreakpointByID(bp_id);
203 if (!breakpoint_sp) {
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000204 new_args.Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000205 result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
206 bp_id);
207 result.SetStatus(eReturnStatusFailed);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000208 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000209 }
210 const size_t num_locations = breakpoint_sp->GetNumLocations();
211 for (size_t j = 0; j < num_locations; ++j) {
212 BreakpointLocation *bp_loc =
213 breakpoint_sp->GetLocationAtIndex(j).get();
214 StreamString canonical_id_str;
215 BreakpointID::GetCanonicalReference(&canonical_id_str, bp_id,
216 bp_loc->GetID());
217 new_args.AppendArgument(canonical_id_str.GetData());
218 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000219 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000220 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000221 }
222
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223 if (is_range) {
224 break_id_t start_bp_id;
225 break_id_t end_bp_id;
226 break_id_t start_loc_id;
227 break_id_t end_loc_id;
228
229 BreakpointID::ParseCanonicalReference(range_start.c_str(), &start_bp_id,
230 &start_loc_id);
231 BreakpointID::ParseCanonicalReference(range_end, &end_bp_id, &end_loc_id);
232
233 if ((start_bp_id == LLDB_INVALID_BREAK_ID) ||
234 (!target->GetBreakpointByID(start_bp_id))) {
235 new_args.Clear();
236 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
237 range_start.c_str());
238 result.SetStatus(eReturnStatusFailed);
239 return;
240 }
241
242 if ((end_bp_id == LLDB_INVALID_BREAK_ID) ||
243 (!target->GetBreakpointByID(end_bp_id))) {
244 new_args.Clear();
245 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
246 range_end);
247 result.SetStatus(eReturnStatusFailed);
248 return;
249 }
250
251 if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
252 (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
253 ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
254 (end_loc_id == LLDB_INVALID_BREAK_ID))) {
255 new_args.Clear();
256 result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
257 "both ends of range must specify"
258 " a breakpoint location, or neither can "
259 "specify a breakpoint location.\n");
260 result.SetStatus(eReturnStatusFailed);
261 return;
262 }
263
264 // We have valid range starting & ending breakpoint IDs. Go through all
265 // the breakpoints in the
266 // target and find all the breakpoints that fit into this range, and add
267 // them to new_args.
268
269 // Next check to see if we have location id's. If so, make sure the
270 // start_bp_id and end_bp_id are
271 // for the same breakpoint; otherwise we have an illegal range: breakpoint
272 // id ranges that specify
273 // bp locations are NOT allowed to cross major bp id numbers.
274
275 if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
276 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
277 if (start_bp_id != end_bp_id) {
278 new_args.Clear();
279 result.AppendErrorWithFormat(
280 "Invalid range: Ranges that specify particular breakpoint "
281 "locations"
282 " must be within the same major breakpoint; you specified two"
283 " different major breakpoints, %d and %d.\n",
284 start_bp_id, end_bp_id);
285 result.SetStatus(eReturnStatusFailed);
286 return;
287 }
288 }
289
290 const BreakpointList &breakpoints = target->GetBreakpointList();
291 const size_t num_breakpoints = breakpoints.GetSize();
292 for (size_t j = 0; j < num_breakpoints; ++j) {
293 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
294 break_id_t cur_bp_id = breakpoint->GetID();
295
296 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
297 continue;
298
299 const size_t num_locations = breakpoint->GetNumLocations();
300
301 if ((cur_bp_id == start_bp_id) &&
302 (start_loc_id != LLDB_INVALID_BREAK_ID)) {
303 for (size_t k = 0; k < num_locations; ++k) {
304 BreakpointLocation *bp_loc =
305 breakpoint->GetLocationAtIndex(k).get();
306 if ((bp_loc->GetID() >= start_loc_id) &&
307 (bp_loc->GetID() <= end_loc_id)) {
308 StreamString canonical_id_str;
309 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
310 bp_loc->GetID());
311 new_args.AppendArgument(canonical_id_str.GetData());
312 }
313 }
314 } else if ((cur_bp_id == end_bp_id) &&
315 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
316 for (size_t k = 0; k < num_locations; ++k) {
317 BreakpointLocation *bp_loc =
318 breakpoint->GetLocationAtIndex(k).get();
319 if (bp_loc->GetID() <= end_loc_id) {
320 StreamString canonical_id_str;
321 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
322 bp_loc->GetID());
323 new_args.AppendArgument(canonical_id_str.GetData());
324 }
325 }
326 } else {
327 StreamString canonical_id_str;
328 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
329 LLDB_INVALID_BREAK_ID);
330 new_args.AppendArgument(canonical_id_str.GetData());
331 }
332 }
333 } else // else is_range was false
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000334 {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335 new_args.AppendArgument(current_arg);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000336 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000337 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000338
Kate Stoneb9c1b512016-09-06 20:57:50 +0000339 // Okay, now see if we found any names, and if we did, add them:
340 if (target && names_found.size()) {
341 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
342 for (std::string name : names_found) {
343 if (bkpt_sp->MatchesName(name.c_str())) {
344 StreamString canonical_id_str;
345 BreakpointID::GetCanonicalReference(
346 &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
347 new_args.AppendArgument(canonical_id_str.GetData());
348 }
349 }
350 }
351 }
352
353 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000354}
355
Kate Stoneb9c1b512016-09-06 20:57:50 +0000356bool BreakpointIDList::StringContainsIDRangeExpression(const char *in_string,
357 size_t *range_start_len,
358 size_t *range_end_pos) {
359 bool is_range_expression = false;
360 std::string arg_str = in_string;
361 std::string::size_type idx;
362 std::string::size_type start_pos = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000363
Kate Stoneb9c1b512016-09-06 20:57:50 +0000364 *range_start_len = 0;
365 *range_end_pos = 0;
366
367 int specifiers_size = 0;
368 for (int i = 0; BreakpointID::g_range_specifiers[i] != nullptr; ++i)
369 ++specifiers_size;
370
371 for (int i = 0; i < specifiers_size && !is_range_expression; ++i) {
372 const char *specifier_str = BreakpointID::g_range_specifiers[i];
373 size_t len = strlen(specifier_str);
374 idx = arg_str.find(BreakpointID::g_range_specifiers[i]);
375 if (idx != std::string::npos) {
376 *range_start_len = idx - start_pos;
377 std::string start_str = arg_str.substr(start_pos, *range_start_len);
378 if (idx + len < arg_str.length()) {
379 *range_end_pos = idx + len;
380 std::string end_str = arg_str.substr(*range_end_pos);
381 if (BreakpointID::IsValidIDExpression(start_str.c_str()) &&
382 BreakpointID::IsValidIDExpression(end_str.c_str())) {
383 is_range_expression = true;
384 //*range_start = start_str;
385 //*range_end = end_str;
386 }
387 }
388 }
389 }
390
391 if (!is_range_expression) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000392 *range_start_len = 0;
393 *range_end_pos = 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000394 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000395
Kate Stoneb9c1b512016-09-06 20:57:50 +0000396 return is_range_expression;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000397}