blob: e7e929921569ad3418e2f38690b60c209e977e64 [file] [log] [blame]
Chris Lattner24943d22010-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 Ingham84cdc152010-06-15 19:49:27 +000015#include "lldb/Interpreter/Args.h"
Chris Lattner24943d22010-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 Clayton54e7afa2010-07-09 20:39:50 +000034size_t
35BreakpointIDList::GetSize()
Chris Lattner24943d22010-06-08 16:52:24 +000036{
37 return m_breakpoint_ids.size();
38}
39
40BreakpointID &
Greg Clayton54e7afa2010-07-09 20:39:50 +000041BreakpointIDList::GetBreakpointIDAtIndex (uint32_t index)
Chris Lattner24943d22010-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 Clayton54e7afa2010-07-09 20:39:50 +000050BreakpointIDList::RemoveBreakpointIDAtIndex (uint32_t index)
Chris Lattner24943d22010-06-08 16:52:24 +000051{
Greg Clayton54e7afa2010-07-09 20:39:50 +000052 if (index >= m_breakpoint_ids.size())
53 return false;
Chris Lattner24943d22010-06-08 16:52:24 +000054
Greg Clayton54e7afa2010-07-09 20:39:50 +000055 m_breakpoint_ids.erase (m_breakpoint_ids.begin() + index);
56 return true;
Chris Lattner24943d22010-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 Clayton54e7afa2010-07-09 20:39:50 +000092BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, uint32_t *position)
Chris Lattner24943d22010-06-08 16:52:24 +000093{
Chris Lattner24943d22010-06-08 16:52:24 +000094 BreakpointIDArray::iterator tmp_pos;
95
Greg Clayton54e7afa2010-07-09 20:39:50 +000096 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i)
Chris Lattner24943d22010-06-08 16:52:24 +000097 {
98 BreakpointID tmp_id = m_breakpoint_ids[i];
99 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID()
100 && tmp_id.GetLocationID() == bp_id.GetLocationID())
101 {
Chris Lattner24943d22010-06-08 16:52:24 +0000102 *position = i;
103 return true;
104 }
105 }
106
107 return false;
108}
109
110bool
Greg Clayton54e7afa2010-07-09 20:39:50 +0000111BreakpointIDList::FindBreakpointID (const char *bp_id_str, uint32_t *position)
Chris Lattner24943d22010-06-08 16:52:24 +0000112{
113 BreakpointID temp_bp_id;
114 break_id_t bp_id;
115 break_id_t loc_id;
116
117 if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id))
118 {
119 temp_bp_id.SetID (bp_id, loc_id);
120 return FindBreakpointID (temp_bp_id, position);
121 }
122 else
123 return false;
124}
125
126void
Greg Clayton54e7afa2010-07-09 20:39:50 +0000127BreakpointIDList::InsertStringArray (const char **string_array, uint32_t array_size, CommandReturnObject &result)
Chris Lattner24943d22010-06-08 16:52:24 +0000128{
129 if (string_array == NULL)
130 return;
131
Greg Clayton54e7afa2010-07-09 20:39:50 +0000132 for (uint32_t i = 0; i < array_size; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000133 {
134 break_id_t bp_id;
135 break_id_t loc_id;
136
137 if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id))
138 {
139 if (bp_id != LLDB_INVALID_BREAK_ID)
140 {
141 BreakpointID temp_bp_id(bp_id, loc_id);
142 m_breakpoint_ids.push_back (temp_bp_id);
143 }
144 else
145 {
146 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]);
147 result.SetStatus (eReturnStatusFailed);
148 return;
149 }
150 }
151 }
152 result.SetStatus (eReturnStatusSuccessFinishNoResult);
153}
154
155
156// This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into
157// an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers.
158// Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS. If any
159// ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to
160// all the current breakpoints and locations in the range are added to NEW_ARGS. When this function is done,
161// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range.
162
163void
164BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result,
165 Args &new_args)
166{
Greg Clayton54e7afa2010-07-09 20:39:50 +0000167 std::string range_start;
Chris Lattner24943d22010-06-08 16:52:24 +0000168 const char *range_end;
169 const char *current_arg;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000170 const size_t num_old_args = old_args.GetArgumentCount();
Chris Lattner24943d22010-06-08 16:52:24 +0000171
Greg Clayton54e7afa2010-07-09 20:39:50 +0000172 for (size_t i = 0; i < num_old_args; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000173 {
174 bool is_range = false;
175 current_arg = old_args.GetArgumentAtIndex (i);
176
Greg Clayton54e7afa2010-07-09 20:39:50 +0000177 uint32_t range_start_len = 0;
178 uint32_t range_end_pos = 0;
Chris Lattner24943d22010-06-08 16:52:24 +0000179 if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
180 {
181 is_range = true;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000182 range_start.assign (current_arg, range_start_len);
Chris Lattner24943d22010-06-08 16:52:24 +0000183 range_end = current_arg + range_end_pos;
184 }
185 else if ((i + 2 < num_old_args)
186 && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
187 && BreakpointID::IsValidIDExpression (current_arg)
188 && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2)))
189 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000190 range_start.assign (current_arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000191 range_end = old_args.GetArgumentAtIndex (i+2);
192 is_range = true;
193 i = i+2;
194 }
Caroline Tice17dce1c2010-09-29 19:42:33 +0000195 else
196 {
197 // See if user has specified id.*
198 std::string tmp_str = old_args.GetArgumentAtIndex (i);
199 size_t pos = tmp_str.find ('.');
200 if (pos != std::string::npos)
201 {
202 std::string bp_id_str = tmp_str.substr (0, pos);
203 if (BreakpointID::IsValidIDExpression (bp_id_str.c_str())
204 && tmp_str[pos+1] == '*'
205 && tmp_str.length() == (pos + 2))
206 {
207 break_id_t bp_id;
208 break_id_t bp_loc_id;
209
210 BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id);
211 BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id);
Johnny Chen8ff5a372010-09-29 21:57:51 +0000212 if (! breakpoint_sp)
213 {
214 new_args.Clear();
215 result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id);
216 result.SetStatus (eReturnStatusFailed);
217 return;
218 }
Caroline Tice17dce1c2010-09-29 19:42:33 +0000219 const size_t num_locations = breakpoint_sp->GetNumLocations();
220 for (size_t j = 0; j < num_locations; ++j)
221 {
222 BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get();
223 StreamString canonical_id_str;
224 BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID());
225 new_args.AppendArgument (canonical_id_str.GetData());
226 }
227 }
228
229 }
230 }
Chris Lattner24943d22010-06-08 16:52:24 +0000231
232 if (is_range)
233 {
234 break_id_t start_bp_id;
235 break_id_t end_bp_id;
236 break_id_t start_loc_id;
237 break_id_t end_loc_id;
238
Greg Clayton54e7afa2010-07-09 20:39:50 +0000239 BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id);
Chris Lattner24943d22010-06-08 16:52:24 +0000240 BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id);
241
242 if ((start_bp_id == LLDB_INVALID_BREAK_ID)
243 || (! target->GetBreakpointByID (start_bp_id)))
244 {
245 new_args.Clear();
Greg Clayton54e7afa2010-07-09 20:39:50 +0000246 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000247 result.SetStatus (eReturnStatusFailed);
248 return;
249 }
250
251 if ((end_bp_id == LLDB_INVALID_BREAK_ID)
252 || (! target->GetBreakpointByID (end_bp_id)))
253 {
254 new_args.Clear();
255 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end);
256 result.SetStatus (eReturnStatusFailed);
257 return;
258 }
Caroline Tice057f7062011-02-02 17:48:16 +0000259
260
261 if (((start_loc_id == LLDB_INVALID_BREAK_ID)
262 && (end_loc_id != LLDB_INVALID_BREAK_ID))
263 || ((start_loc_id != LLDB_INVALID_BREAK_ID)
264 && (end_loc_id == LLDB_INVALID_BREAK_ID)))
265 {
266 new_args.Clear ();
267 result.AppendErrorWithFormat ("Invalid breakpoint id range: Either both ends of range must specify"
268 " a breakpoint location, or neither can specify a breakpoint location.\n");
269 result.SetStatus (eReturnStatusFailed);
270 return;
271 }
Chris Lattner24943d22010-06-08 16:52:24 +0000272
273 // We have valid range starting & ending breakpoint IDs. Go through all the breakpoints in the
274 // target and find all the breakpoints that fit into this range, and add them to new_args.
Caroline Tice17dce1c2010-09-29 19:42:33 +0000275
276 // Next check to see if we have location id's. If so, make sure the start_bp_id and end_bp_id are
277 // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify
278 // bp locations are NOT allowed to cross major bp id numbers.
279
280 if ((start_loc_id != LLDB_INVALID_BREAK_ID)
281 || (end_loc_id != LLDB_INVALID_BREAK_ID))
282 {
283 if (start_bp_id != end_bp_id)
284 {
285 new_args.Clear();
286 result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations"
287 " must be within the same major breakpoint; you specified two"
288 " different major breakpoints, %d and %d.\n",
289 start_bp_id, end_bp_id);
290 result.SetStatus (eReturnStatusFailed);
291 return;
292 }
293 }
Chris Lattner24943d22010-06-08 16:52:24 +0000294
295 const BreakpointList& breakpoints = target->GetBreakpointList();
Greg Clayton54e7afa2010-07-09 20:39:50 +0000296 const size_t num_breakpoints = breakpoints.GetSize();
297 for (size_t j = 0; j < num_breakpoints; ++j)
Chris Lattner24943d22010-06-08 16:52:24 +0000298 {
Greg Claytonc7f5d5c2010-07-23 23:33:17 +0000299 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get();
Chris Lattner24943d22010-06-08 16:52:24 +0000300 break_id_t cur_bp_id = breakpoint->GetID();
301
302 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
303 continue;
304
Greg Clayton54e7afa2010-07-09 20:39:50 +0000305 const size_t num_locations = breakpoint->GetNumLocations();
Chris Lattner24943d22010-06-08 16:52:24 +0000306
307 if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
308 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000309 for (size_t k = 0; k < num_locations; ++k)
Chris Lattner24943d22010-06-08 16:52:24 +0000310 {
311 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
Caroline Tice057f7062011-02-02 17:48:16 +0000312 if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id))
Chris Lattner24943d22010-06-08 16:52:24 +0000313 {
314 StreamString canonical_id_str;
315 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
316 new_args.AppendArgument (canonical_id_str.GetData());
317 }
318 }
319 }
320 else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID))
321 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000322 for (size_t k = 0; k < num_locations; ++k)
Chris Lattner24943d22010-06-08 16:52:24 +0000323 {
324 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
325 if (bp_loc->GetID() <= end_loc_id)
326 {
327 StreamString canonical_id_str;
328 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
329 new_args.AppendArgument (canonical_id_str.GetData());
330 }
331 }
332 }
333 else
334 {
335 StreamString canonical_id_str;
336 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID);
337 new_args.AppendArgument (canonical_id_str.GetData());
338 }
339 }
340 }
341 else // else is_range was false
342 {
343 new_args.AppendArgument (current_arg);
344 }
345 }
346
347 result.SetStatus (eReturnStatusSuccessFinishNoResult);
348 return;
349}
350
Chris Lattner24943d22010-06-08 16:52:24 +0000351bool
Caroline Tice17dce1c2010-09-29 19:42:33 +0000352BreakpointIDList::StringContainsIDRangeExpression (const char *in_string,
353 uint32_t *range_start_len,
354 uint32_t *range_end_pos)
Chris Lattner24943d22010-06-08 16:52:24 +0000355{
356 bool is_range_expression = false;
357 std::string arg_str = in_string;
358 std::string::size_type idx;
359 std::string::size_type start_pos = 0;
360
Chris Lattner24943d22010-06-08 16:52:24 +0000361 *range_start_len = 0;
362 *range_end_pos = 0;
363
364 int specifiers_size = 0;
365 for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i)
366 ++specifiers_size;
367
368 for (int i = 0; i < specifiers_size && !is_range_expression; ++i)
369 {
370 const char *specifier_str = BreakpointID::g_range_specifiers[i];
371 int len = strlen (specifier_str);
372 idx = arg_str.find (BreakpointID::g_range_specifiers[i]);
373 if (idx != std::string::npos)
374 {
375 *range_start_len = idx - start_pos;
376 std::string start_str = arg_str.substr (start_pos, *range_start_len);
377 if (idx + len < arg_str.length())
378 {
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 {
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)
393 {
394 *range_start_len = 0;
395 *range_end_pos = 0;
396 }
397
398 return is_range_expression;
399}