blob: b8b506750b34813073da89d17b88374a514bde8d [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
10#include "lldb/Breakpoint/BreakpointIDList.h"
11
12#include "lldb/Breakpoint/Breakpoint.h"
13#include "lldb/Breakpoint/BreakpointLocation.h"
14#include "lldb/Interpreter/CommandReturnObject.h"
Jim Ingham40af72e2010-06-15 19:49:27 +000015#include "lldb/Interpreter/Args.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000016#include "lldb/Target/Target.h"
17
18using namespace lldb;
19using namespace lldb_private;
20
21//----------------------------------------------------------------------
22// class BreakpointIDList
23//----------------------------------------------------------------------
24
25BreakpointIDList::BreakpointIDList () :
26m_invalid_id (LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID)
27{
28}
29
30BreakpointIDList::~BreakpointIDList ()
31{
32}
33
Greg Claytonc982c762010-07-09 20:39:50 +000034size_t
35BreakpointIDList::GetSize()
Chris Lattner30fdc8d2010-06-08 16:52:24 +000036{
37 return m_breakpoint_ids.size();
38}
39
40BreakpointID &
Greg Claytonc7bece562013-01-25 18:06:21 +000041BreakpointIDList::GetBreakpointIDAtIndex (size_t index)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000042{
43 if (index < m_breakpoint_ids.size())
44 return m_breakpoint_ids[index];
45 else
46 return m_invalid_id;
47}
48
49bool
Greg Claytonc7bece562013-01-25 18:06:21 +000050BreakpointIDList::RemoveBreakpointIDAtIndex (size_t index)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000051{
Greg Claytonc982c762010-07-09 20:39:50 +000052 if (index >= m_breakpoint_ids.size())
53 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000054
Greg Claytonc982c762010-07-09 20:39:50 +000055 m_breakpoint_ids.erase (m_breakpoint_ids.begin() + index);
56 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000057}
58
59void
60BreakpointIDList::Clear()
61{
62 m_breakpoint_ids.clear ();
63}
64
65bool
66BreakpointIDList::AddBreakpointID (BreakpointID bp_id)
67{
68 m_breakpoint_ids.push_back (bp_id);
69
70 return true; // We don't do any verification in this function, so always return true.
71}
72
73bool
74BreakpointIDList::AddBreakpointID (const char *bp_id_str)
75{
76 BreakpointID temp_bp_id;
77 break_id_t bp_id;
78 break_id_t loc_id;
79
80 bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id);
81
82 if (success)
83 {
84 temp_bp_id.SetID (bp_id, loc_id);
85 m_breakpoint_ids.push_back (temp_bp_id);
86 }
87
88 return success;
89}
90
91bool
Greg Claytonc7bece562013-01-25 18:06:21 +000092BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, size_t *position)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000093{
Greg Claytonc982c762010-07-09 20:39:50 +000094 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000095 {
96 BreakpointID tmp_id = m_breakpoint_ids[i];
97 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID()
98 && tmp_id.GetLocationID() == bp_id.GetLocationID())
99 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000100 *position = i;
101 return true;
102 }
103 }
104
105 return false;
106}
107
108bool
Greg Claytonc7bece562013-01-25 18:06:21 +0000109BreakpointIDList::FindBreakpointID (const char *bp_id_str, size_t *position)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000110{
111 BreakpointID temp_bp_id;
112 break_id_t bp_id;
113 break_id_t loc_id;
114
115 if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id))
116 {
117 temp_bp_id.SetID (bp_id, loc_id);
118 return FindBreakpointID (temp_bp_id, position);
119 }
120 else
121 return false;
122}
123
124void
Greg Claytonc7bece562013-01-25 18:06:21 +0000125BreakpointIDList::InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000126{
127 if (string_array == NULL)
128 return;
129
Greg Claytonc982c762010-07-09 20:39:50 +0000130 for (uint32_t i = 0; i < array_size; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000131 {
132 break_id_t bp_id;
133 break_id_t loc_id;
134
135 if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id))
136 {
137 if (bp_id != LLDB_INVALID_BREAK_ID)
138 {
139 BreakpointID temp_bp_id(bp_id, loc_id);
140 m_breakpoint_ids.push_back (temp_bp_id);
141 }
142 else
143 {
144 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]);
145 result.SetStatus (eReturnStatusFailed);
146 return;
147 }
148 }
149 }
150 result.SetStatus (eReturnStatusSuccessFinishNoResult);
151}
152
153
154// This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into
155// an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers.
156// Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS. If any
157// ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to
158// all the current breakpoints and locations in the range are added to NEW_ARGS. When this function is done,
159// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range.
160
161void
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000162BreakpointIDList::FindAndReplaceIDRanges (Args &old_args,
163 Target *target,
164 bool allow_locations,
165 CommandReturnObject &result,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000166 Args &new_args)
167{
Greg Claytonc982c762010-07-09 20:39:50 +0000168 std::string range_start;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000169 const char *range_end;
170 const char *current_arg;
Greg Claytonc982c762010-07-09 20:39:50 +0000171 const size_t num_old_args = old_args.GetArgumentCount();
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000172 std::set<std::string> names_found;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000173
Greg Claytonc982c762010-07-09 20:39:50 +0000174 for (size_t i = 0; i < num_old_args; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000175 {
176 bool is_range = false;
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000177
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000178 current_arg = old_args.GetArgumentAtIndex (i);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000179 if (!allow_locations && strchr(current_arg, '.') != nullptr)
180 {
181 result.AppendErrorWithFormat ("Breakpoint locations not allowed, saw location: %s.", current_arg);
182 new_args.Clear();
183 return;
184 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000185
Greg Claytonc7bece562013-01-25 18:06:21 +0000186 size_t range_start_len = 0;
187 size_t range_end_pos = 0;
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000188 Error error;
189
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000190 if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
191 {
192 is_range = true;
Greg Claytonc982c762010-07-09 20:39:50 +0000193 range_start.assign (current_arg, range_start_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000194 range_end = current_arg + range_end_pos;
195 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000196 else if (BreakpointID::StringIsBreakpointName(current_arg, error))
197 {
198 if (!error.Success())
199 {
200 new_args.Clear();
201 result.AppendError (error.AsCString());
202 result.SetStatus (eReturnStatusFailed);
203 return;
204 }
205 else
206 names_found.insert(current_arg);
207 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000208 else if ((i + 2 < num_old_args)
209 && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
210 && BreakpointID::IsValidIDExpression (current_arg)
211 && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2)))
212 {
Greg Claytonc982c762010-07-09 20:39:50 +0000213 range_start.assign (current_arg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000214 range_end = old_args.GetArgumentAtIndex (i+2);
215 is_range = true;
216 i = i+2;
217 }
Caroline Tice9068d792010-09-29 19:42:33 +0000218 else
219 {
220 // See if user has specified id.*
221 std::string tmp_str = old_args.GetArgumentAtIndex (i);
222 size_t pos = tmp_str.find ('.');
223 if (pos != std::string::npos)
224 {
225 std::string bp_id_str = tmp_str.substr (0, pos);
226 if (BreakpointID::IsValidIDExpression (bp_id_str.c_str())
227 && tmp_str[pos+1] == '*'
228 && tmp_str.length() == (pos + 2))
229 {
230 break_id_t bp_id;
231 break_id_t bp_loc_id;
232
233 BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id);
234 BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id);
Johnny Cheneb1db1c2010-09-29 21:57:51 +0000235 if (! breakpoint_sp)
236 {
237 new_args.Clear();
238 result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id);
239 result.SetStatus (eReturnStatusFailed);
240 return;
241 }
Caroline Tice9068d792010-09-29 19:42:33 +0000242 const size_t num_locations = breakpoint_sp->GetNumLocations();
243 for (size_t j = 0; j < num_locations; ++j)
244 {
245 BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get();
246 StreamString canonical_id_str;
247 BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID());
248 new_args.AppendArgument (canonical_id_str.GetData());
249 }
250 }
251
252 }
253 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000254
255 if (is_range)
256 {
257 break_id_t start_bp_id;
258 break_id_t end_bp_id;
259 break_id_t start_loc_id;
260 break_id_t end_loc_id;
261
Greg Claytonc982c762010-07-09 20:39:50 +0000262 BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000263 BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id);
264
265 if ((start_bp_id == LLDB_INVALID_BREAK_ID)
266 || (! target->GetBreakpointByID (start_bp_id)))
267 {
268 new_args.Clear();
Greg Claytonc982c762010-07-09 20:39:50 +0000269 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000270 result.SetStatus (eReturnStatusFailed);
271 return;
272 }
273
274 if ((end_bp_id == LLDB_INVALID_BREAK_ID)
275 || (! target->GetBreakpointByID (end_bp_id)))
276 {
277 new_args.Clear();
278 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end);
279 result.SetStatus (eReturnStatusFailed);
280 return;
281 }
Caroline Tice2bf67982011-02-02 17:48:16 +0000282
283
284 if (((start_loc_id == LLDB_INVALID_BREAK_ID)
285 && (end_loc_id != LLDB_INVALID_BREAK_ID))
286 || ((start_loc_id != LLDB_INVALID_BREAK_ID)
287 && (end_loc_id == LLDB_INVALID_BREAK_ID)))
288 {
289 new_args.Clear ();
290 result.AppendErrorWithFormat ("Invalid breakpoint id range: Either both ends of range must specify"
291 " a breakpoint location, or neither can specify a breakpoint location.\n");
292 result.SetStatus (eReturnStatusFailed);
293 return;
294 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000295
296 // We have valid range starting & ending breakpoint IDs. Go through all the breakpoints in the
297 // target and find all the breakpoints that fit into this range, and add them to new_args.
Caroline Tice9068d792010-09-29 19:42:33 +0000298
299 // Next check to see if we have location id's. If so, make sure the start_bp_id and end_bp_id are
300 // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify
301 // bp locations are NOT allowed to cross major bp id numbers.
302
303 if ((start_loc_id != LLDB_INVALID_BREAK_ID)
304 || (end_loc_id != LLDB_INVALID_BREAK_ID))
305 {
306 if (start_bp_id != end_bp_id)
307 {
308 new_args.Clear();
309 result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations"
310 " must be within the same major breakpoint; you specified two"
311 " different major breakpoints, %d and %d.\n",
312 start_bp_id, end_bp_id);
313 result.SetStatus (eReturnStatusFailed);
314 return;
315 }
316 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000317
318 const BreakpointList& breakpoints = target->GetBreakpointList();
Greg Claytonc982c762010-07-09 20:39:50 +0000319 const size_t num_breakpoints = breakpoints.GetSize();
320 for (size_t j = 0; j < num_breakpoints; ++j)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000321 {
Greg Clayton9fed0d82010-07-23 23:33:17 +0000322 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000323 break_id_t cur_bp_id = breakpoint->GetID();
324
325 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
326 continue;
327
Greg Claytonc982c762010-07-09 20:39:50 +0000328 const size_t num_locations = breakpoint->GetNumLocations();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000329
330 if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
331 {
Greg Claytonc982c762010-07-09 20:39:50 +0000332 for (size_t k = 0; k < num_locations; ++k)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000333 {
334 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
Caroline Tice2bf67982011-02-02 17:48:16 +0000335 if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000336 {
337 StreamString canonical_id_str;
338 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
339 new_args.AppendArgument (canonical_id_str.GetData());
340 }
341 }
342 }
343 else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID))
344 {
Greg Claytonc982c762010-07-09 20:39:50 +0000345 for (size_t k = 0; k < num_locations; ++k)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000346 {
347 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
348 if (bp_loc->GetID() <= end_loc_id)
349 {
350 StreamString canonical_id_str;
351 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
352 new_args.AppendArgument (canonical_id_str.GetData());
353 }
354 }
355 }
356 else
357 {
358 StreamString canonical_id_str;
359 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID);
360 new_args.AppendArgument (canonical_id_str.GetData());
361 }
362 }
363 }
364 else // else is_range was false
365 {
366 new_args.AppendArgument (current_arg);
367 }
368 }
369
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000370 // Okay, now see if we found any names, and if we did, add them:
371 if (target && names_found.size())
372 {
373 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints())
374 {
375 for (std::string name : names_found)
376 {
377 if (bkpt_sp->MatchesName(name.c_str()))
378 {
379 StreamString canonical_id_str;
380 BreakpointID::GetCanonicalReference (&canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
381 new_args.AppendArgument (canonical_id_str.GetData());
382 }
383 }
384 }
385 }
386
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000387 result.SetStatus (eReturnStatusSuccessFinishNoResult);
388 return;
389}
390
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000391bool
Caroline Tice9068d792010-09-29 19:42:33 +0000392BreakpointIDList::StringContainsIDRangeExpression (const char *in_string,
Greg Claytonc7bece562013-01-25 18:06:21 +0000393 size_t *range_start_len,
394 size_t *range_end_pos)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000395{
396 bool is_range_expression = false;
397 std::string arg_str = in_string;
398 std::string::size_type idx;
399 std::string::size_type start_pos = 0;
400
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000401 *range_start_len = 0;
402 *range_end_pos = 0;
403
404 int specifiers_size = 0;
405 for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i)
406 ++specifiers_size;
407
408 for (int i = 0; i < specifiers_size && !is_range_expression; ++i)
409 {
410 const char *specifier_str = BreakpointID::g_range_specifiers[i];
Greg Claytonc7bece562013-01-25 18:06:21 +0000411 size_t len = strlen (specifier_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000412 idx = arg_str.find (BreakpointID::g_range_specifiers[i]);
413 if (idx != std::string::npos)
414 {
415 *range_start_len = idx - start_pos;
416 std::string start_str = arg_str.substr (start_pos, *range_start_len);
417 if (idx + len < arg_str.length())
418 {
419 *range_end_pos = idx + len;
420 std::string end_str = arg_str.substr (*range_end_pos);
421 if (BreakpointID::IsValidIDExpression (start_str.c_str())
422 && BreakpointID::IsValidIDExpression (end_str.c_str()))
423 {
424 is_range_expression = true;
425 //*range_start = start_str;
426 //*range_end = end_str;
427 }
428 }
429 }
430 }
431
432 if (!is_range_expression)
433 {
434 *range_start_len = 0;
435 *range_end_pos = 0;
436 }
437
438 return is_range_expression;
439}