blob: ebf0697c271ba914a8aa3d36fec1328a26d707db [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"
18#include "lldb/Interpreter/CommandReturnObject.h"
Jim Ingham40af72e2010-06-15 19:49:27 +000019#include "lldb/Interpreter/Args.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
29BreakpointIDList::BreakpointIDList () :
30m_invalid_id (LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID)
31{
32}
33
Eugene Zelenko16fd7512015-10-30 18:50:12 +000034BreakpointIDList::~BreakpointIDList() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000035
Greg Claytonc982c762010-07-09 20:39:50 +000036size_t
37BreakpointIDList::GetSize()
Chris Lattner30fdc8d2010-06-08 16:52:24 +000038{
39 return m_breakpoint_ids.size();
40}
41
42BreakpointID &
Eugene Zelenko16fd7512015-10-30 18:50:12 +000043BreakpointIDList::GetBreakpointIDAtIndex(size_t index)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000044{
Eugene Zelenko16fd7512015-10-30 18:50:12 +000045 return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index] : m_invalid_id);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000046}
47
48bool
Greg Claytonc7bece562013-01-25 18:06:21 +000049BreakpointIDList::RemoveBreakpointIDAtIndex (size_t index)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000050{
Greg Claytonc982c762010-07-09 20:39:50 +000051 if (index >= m_breakpoint_ids.size())
52 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000053
Greg Claytonc982c762010-07-09 20:39:50 +000054 m_breakpoint_ids.erase (m_breakpoint_ids.begin() + index);
55 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000056}
57
58void
59BreakpointIDList::Clear()
60{
61 m_breakpoint_ids.clear ();
62}
63
64bool
65BreakpointIDList::AddBreakpointID (BreakpointID bp_id)
66{
67 m_breakpoint_ids.push_back (bp_id);
68
69 return true; // We don't do any verification in this function, so always return true.
70}
71
72bool
73BreakpointIDList::AddBreakpointID (const char *bp_id_str)
74{
75 BreakpointID temp_bp_id;
76 break_id_t bp_id;
77 break_id_t loc_id;
78
79 bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id);
80
81 if (success)
82 {
83 temp_bp_id.SetID (bp_id, loc_id);
84 m_breakpoint_ids.push_back (temp_bp_id);
85 }
86
87 return success;
88}
89
90bool
Greg Claytonc7bece562013-01-25 18:06:21 +000091BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, size_t *position)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000092{
Greg Claytonc982c762010-07-09 20:39:50 +000093 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000094 {
95 BreakpointID tmp_id = m_breakpoint_ids[i];
96 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID()
97 && tmp_id.GetLocationID() == bp_id.GetLocationID())
98 {
Chris Lattner30fdc8d2010-06-08 16:52:24 +000099 *position = i;
100 return true;
101 }
102 }
103
104 return false;
105}
106
107bool
Greg Claytonc7bece562013-01-25 18:06:21 +0000108BreakpointIDList::FindBreakpointID (const char *bp_id_str, size_t *position)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109{
110 BreakpointID temp_bp_id;
111 break_id_t bp_id;
112 break_id_t loc_id;
113
114 if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id))
115 {
116 temp_bp_id.SetID (bp_id, loc_id);
117 return FindBreakpointID (temp_bp_id, position);
118 }
119 else
120 return false;
121}
122
123void
Greg Claytonc7bece562013-01-25 18:06:21 +0000124BreakpointIDList::InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000125{
Eugene Zelenko16fd7512015-10-30 18:50:12 +0000126 if (string_array == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000127 return;
128
Greg Claytonc982c762010-07-09 20:39:50 +0000129 for (uint32_t i = 0; i < array_size; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000130 {
131 break_id_t bp_id;
132 break_id_t loc_id;
133
134 if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id))
135 {
136 if (bp_id != LLDB_INVALID_BREAK_ID)
137 {
138 BreakpointID temp_bp_id(bp_id, loc_id);
139 m_breakpoint_ids.push_back (temp_bp_id);
140 }
141 else
142 {
143 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]);
144 result.SetStatus (eReturnStatusFailed);
145 return;
146 }
147 }
148 }
149 result.SetStatus (eReturnStatusSuccessFinishNoResult);
150}
151
152
153// This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into
154// an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers.
155// Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS. If any
156// ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to
157// all the current breakpoints and locations in the range are added to NEW_ARGS. When this function is done,
158// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range.
159
160void
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000161BreakpointIDList::FindAndReplaceIDRanges (Args &old_args,
162 Target *target,
163 bool allow_locations,
164 CommandReturnObject &result,
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000165 Args &new_args)
166{
Greg Claytonc982c762010-07-09 20:39:50 +0000167 std::string range_start;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000168 const char *range_end;
169 const char *current_arg;
Greg Claytonc982c762010-07-09 20:39:50 +0000170 const size_t num_old_args = old_args.GetArgumentCount();
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000171 std::set<std::string> names_found;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000172
Greg Claytonc982c762010-07-09 20:39:50 +0000173 for (size_t i = 0; i < num_old_args; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000174 {
175 bool is_range = false;
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000176
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000177 current_arg = old_args.GetArgumentAtIndex (i);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000178 if (!allow_locations && strchr(current_arg, '.') != nullptr)
179 {
180 result.AppendErrorWithFormat ("Breakpoint locations not allowed, saw location: %s.", current_arg);
181 new_args.Clear();
182 return;
183 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000184
Greg Claytonc7bece562013-01-25 18:06:21 +0000185 size_t range_start_len = 0;
186 size_t range_end_pos = 0;
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000187 Error error;
188
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000189 if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
190 {
191 is_range = true;
Greg Claytonc982c762010-07-09 20:39:50 +0000192 range_start.assign (current_arg, range_start_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000193 range_end = current_arg + range_end_pos;
194 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000195 else if (BreakpointID::StringIsBreakpointName(current_arg, error))
196 {
197 if (!error.Success())
198 {
199 new_args.Clear();
200 result.AppendError (error.AsCString());
201 result.SetStatus (eReturnStatusFailed);
202 return;
203 }
204 else
205 names_found.insert(current_arg);
206 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000207 else if ((i + 2 < num_old_args)
208 && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
209 && BreakpointID::IsValidIDExpression (current_arg)
210 && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2)))
211 {
Greg Claytonc982c762010-07-09 20:39:50 +0000212 range_start.assign (current_arg);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000213 range_end = old_args.GetArgumentAtIndex (i+2);
214 is_range = true;
215 i = i+2;
216 }
Caroline Tice9068d792010-09-29 19:42:33 +0000217 else
218 {
219 // See if user has specified id.*
220 std::string tmp_str = old_args.GetArgumentAtIndex (i);
221 size_t pos = tmp_str.find ('.');
222 if (pos != std::string::npos)
223 {
224 std::string bp_id_str = tmp_str.substr (0, pos);
225 if (BreakpointID::IsValidIDExpression (bp_id_str.c_str())
226 && tmp_str[pos+1] == '*'
227 && tmp_str.length() == (pos + 2))
228 {
229 break_id_t bp_id;
230 break_id_t bp_loc_id;
231
232 BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id);
233 BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id);
Johnny Cheneb1db1c2010-09-29 21:57:51 +0000234 if (! breakpoint_sp)
235 {
236 new_args.Clear();
237 result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id);
238 result.SetStatus (eReturnStatusFailed);
239 return;
240 }
Caroline Tice9068d792010-09-29 19:42:33 +0000241 const size_t num_locations = breakpoint_sp->GetNumLocations();
242 for (size_t j = 0; j < num_locations; ++j)
243 {
244 BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get();
245 StreamString canonical_id_str;
246 BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID());
247 new_args.AppendArgument (canonical_id_str.GetData());
248 }
249 }
250
251 }
252 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000253
254 if (is_range)
255 {
256 break_id_t start_bp_id;
257 break_id_t end_bp_id;
258 break_id_t start_loc_id;
259 break_id_t end_loc_id;
260
Greg Claytonc982c762010-07-09 20:39:50 +0000261 BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000262 BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id);
263
264 if ((start_bp_id == LLDB_INVALID_BREAK_ID)
265 || (! target->GetBreakpointByID (start_bp_id)))
266 {
267 new_args.Clear();
Greg Claytonc982c762010-07-09 20:39:50 +0000268 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000269 result.SetStatus (eReturnStatusFailed);
270 return;
271 }
272
273 if ((end_bp_id == LLDB_INVALID_BREAK_ID)
274 || (! target->GetBreakpointByID (end_bp_id)))
275 {
276 new_args.Clear();
277 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end);
278 result.SetStatus (eReturnStatusFailed);
279 return;
280 }
Caroline Tice2bf67982011-02-02 17:48:16 +0000281
282
283 if (((start_loc_id == LLDB_INVALID_BREAK_ID)
284 && (end_loc_id != LLDB_INVALID_BREAK_ID))
285 || ((start_loc_id != LLDB_INVALID_BREAK_ID)
286 && (end_loc_id == LLDB_INVALID_BREAK_ID)))
287 {
288 new_args.Clear ();
289 result.AppendErrorWithFormat ("Invalid breakpoint id range: Either both ends of range must specify"
290 " a breakpoint location, or neither can specify a breakpoint location.\n");
291 result.SetStatus (eReturnStatusFailed);
292 return;
293 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000294
295 // We have valid range starting & ending breakpoint IDs. Go through all the breakpoints in the
296 // target and find all the breakpoints that fit into this range, and add them to new_args.
Caroline Tice9068d792010-09-29 19:42:33 +0000297
298 // Next check to see if we have location id's. If so, make sure the start_bp_id and end_bp_id are
299 // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify
300 // bp locations are NOT allowed to cross major bp id numbers.
301
302 if ((start_loc_id != LLDB_INVALID_BREAK_ID)
303 || (end_loc_id != LLDB_INVALID_BREAK_ID))
304 {
305 if (start_bp_id != end_bp_id)
306 {
307 new_args.Clear();
308 result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations"
309 " must be within the same major breakpoint; you specified two"
310 " different major breakpoints, %d and %d.\n",
311 start_bp_id, end_bp_id);
312 result.SetStatus (eReturnStatusFailed);
313 return;
314 }
315 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000316
317 const BreakpointList& breakpoints = target->GetBreakpointList();
Greg Claytonc982c762010-07-09 20:39:50 +0000318 const size_t num_breakpoints = breakpoints.GetSize();
319 for (size_t j = 0; j < num_breakpoints; ++j)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000320 {
Greg Clayton9fed0d82010-07-23 23:33:17 +0000321 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000322 break_id_t cur_bp_id = breakpoint->GetID();
323
324 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
325 continue;
326
Greg Claytonc982c762010-07-09 20:39:50 +0000327 const size_t num_locations = breakpoint->GetNumLocations();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000328
329 if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
330 {
Greg Claytonc982c762010-07-09 20:39:50 +0000331 for (size_t k = 0; k < num_locations; ++k)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000332 {
333 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
Caroline Tice2bf67982011-02-02 17:48:16 +0000334 if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000335 {
336 StreamString canonical_id_str;
337 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
338 new_args.AppendArgument (canonical_id_str.GetData());
339 }
340 }
341 }
342 else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID))
343 {
Greg Claytonc982c762010-07-09 20:39:50 +0000344 for (size_t k = 0; k < num_locations; ++k)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000345 {
346 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
347 if (bp_loc->GetID() <= end_loc_id)
348 {
349 StreamString canonical_id_str;
350 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
351 new_args.AppendArgument (canonical_id_str.GetData());
352 }
353 }
354 }
355 else
356 {
357 StreamString canonical_id_str;
358 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID);
359 new_args.AppendArgument (canonical_id_str.GetData());
360 }
361 }
362 }
363 else // else is_range was false
364 {
365 new_args.AppendArgument (current_arg);
366 }
367 }
368
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000369 // Okay, now see if we found any names, and if we did, add them:
370 if (target && names_found.size())
371 {
372 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints())
373 {
374 for (std::string name : names_found)
375 {
376 if (bkpt_sp->MatchesName(name.c_str()))
377 {
378 StreamString canonical_id_str;
379 BreakpointID::GetCanonicalReference (&canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
380 new_args.AppendArgument (canonical_id_str.GetData());
381 }
382 }
383 }
384 }
385
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000386 result.SetStatus (eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000387}
388
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000389bool
Caroline Tice9068d792010-09-29 19:42:33 +0000390BreakpointIDList::StringContainsIDRangeExpression (const char *in_string,
Greg Claytonc7bece562013-01-25 18:06:21 +0000391 size_t *range_start_len,
392 size_t *range_end_pos)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000393{
394 bool is_range_expression = false;
395 std::string arg_str = in_string;
396 std::string::size_type idx;
397 std::string::size_type start_pos = 0;
398
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000399 *range_start_len = 0;
400 *range_end_pos = 0;
401
402 int specifiers_size = 0;
Eugene Zelenko16fd7512015-10-30 18:50:12 +0000403 for (int i = 0; BreakpointID::g_range_specifiers[i] != nullptr; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000404 ++specifiers_size;
405
406 for (int i = 0; i < specifiers_size && !is_range_expression; ++i)
407 {
408 const char *specifier_str = BreakpointID::g_range_specifiers[i];
Greg Claytonc7bece562013-01-25 18:06:21 +0000409 size_t len = strlen (specifier_str);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000410 idx = arg_str.find (BreakpointID::g_range_specifiers[i]);
411 if (idx != std::string::npos)
412 {
413 *range_start_len = idx - start_pos;
414 std::string start_str = arg_str.substr (start_pos, *range_start_len);
415 if (idx + len < arg_str.length())
416 {
417 *range_end_pos = idx + len;
418 std::string end_str = arg_str.substr (*range_end_pos);
419 if (BreakpointID::IsValidIDExpression (start_str.c_str())
420 && BreakpointID::IsValidIDExpression (end_str.c_str()))
421 {
422 is_range_expression = true;
423 //*range_start = start_str;
424 //*range_end = end_str;
425 }
426 }
427 }
428 }
429
430 if (!is_range_expression)
431 {
432 *range_start_len = 0;
433 *range_end_pos = 0;
434 }
435
436 return is_range_expression;
437}