1 //===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Breakpoint/BreakpointIDList.h"
12 #include "lldb/Breakpoint/Breakpoint.h"
13 #include "lldb/Breakpoint/BreakpointLocation.h"
14 #include "lldb/Interpreter/CommandReturnObject.h"
15 #include "lldb/Interpreter/Args.h"
16 #include "lldb/Target/Target.h"
19 using namespace lldb_private;
21 //----------------------------------------------------------------------
22 // class BreakpointIDList
23 //----------------------------------------------------------------------
25 BreakpointIDList::BreakpointIDList () :
26 m_invalid_id (LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID)
30 BreakpointIDList::~BreakpointIDList ()
35 BreakpointIDList::GetSize()
37 return m_breakpoint_ids.size();
41 BreakpointIDList::GetBreakpointIDAtIndex (size_t index)
43 if (index < m_breakpoint_ids.size())
44 return m_breakpoint_ids[index];
50 BreakpointIDList::RemoveBreakpointIDAtIndex (size_t index)
52 if (index >= m_breakpoint_ids.size())
55 m_breakpoint_ids.erase (m_breakpoint_ids.begin() + index);
60 BreakpointIDList::Clear()
62 m_breakpoint_ids.clear ();
66 BreakpointIDList::AddBreakpointID (BreakpointID bp_id)
68 m_breakpoint_ids.push_back (bp_id);
70 return true; // We don't do any verification in this function, so always return true.
74 BreakpointIDList::AddBreakpointID (const char *bp_id_str)
76 BreakpointID temp_bp_id;
80 bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id);
84 temp_bp_id.SetID (bp_id, loc_id);
85 m_breakpoint_ids.push_back (temp_bp_id);
92 BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, size_t *position)
94 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i)
96 BreakpointID tmp_id = m_breakpoint_ids[i];
97 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID()
98 && tmp_id.GetLocationID() == bp_id.GetLocationID())
109 BreakpointIDList::FindBreakpointID (const char *bp_id_str, size_t *position)
111 BreakpointID temp_bp_id;
115 if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id))
117 temp_bp_id.SetID (bp_id, loc_id);
118 return FindBreakpointID (temp_bp_id, position);
125 BreakpointIDList::InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result)
127 if (string_array == NULL)
130 for (uint32_t i = 0; i < array_size; ++i)
135 if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id))
137 if (bp_id != LLDB_INVALID_BREAK_ID)
139 BreakpointID temp_bp_id(bp_id, loc_id);
140 m_breakpoint_ids.push_back (temp_bp_id);
144 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]);
145 result.SetStatus (eReturnStatusFailed);
150 result.SetStatus (eReturnStatusSuccessFinishNoResult);
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.
162 BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result,
165 std::string range_start;
166 const char *range_end;
167 const char *current_arg;
168 const size_t num_old_args = old_args.GetArgumentCount();
170 for (size_t i = 0; i < num_old_args; ++i)
172 bool is_range = false;
173 current_arg = old_args.GetArgumentAtIndex (i);
175 size_t range_start_len = 0;
176 size_t range_end_pos = 0;
177 if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos))
180 range_start.assign (current_arg, range_start_len);
181 range_end = current_arg + range_end_pos;
183 else if ((i + 2 < num_old_args)
184 && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
185 && BreakpointID::IsValidIDExpression (current_arg)
186 && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2)))
188 range_start.assign (current_arg);
189 range_end = old_args.GetArgumentAtIndex (i+2);
195 // See if user has specified id.*
196 std::string tmp_str = old_args.GetArgumentAtIndex (i);
197 size_t pos = tmp_str.find ('.');
198 if (pos != std::string::npos)
200 std::string bp_id_str = tmp_str.substr (0, pos);
201 if (BreakpointID::IsValidIDExpression (bp_id_str.c_str())
202 && tmp_str[pos+1] == '*'
203 && tmp_str.length() == (pos + 2))
206 break_id_t bp_loc_id;
208 BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id);
209 BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id);
213 result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id);
214 result.SetStatus (eReturnStatusFailed);
217 const size_t num_locations = breakpoint_sp->GetNumLocations();
218 for (size_t j = 0; j < num_locations; ++j)
220 BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get();
221 StreamString canonical_id_str;
222 BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID());
223 new_args.AppendArgument (canonical_id_str.GetData());
232 break_id_t start_bp_id;
233 break_id_t end_bp_id;
234 break_id_t start_loc_id;
235 break_id_t end_loc_id;
237 BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id);
238 BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id);
240 if ((start_bp_id == LLDB_INVALID_BREAK_ID)
241 || (! target->GetBreakpointByID (start_bp_id)))
244 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str());
245 result.SetStatus (eReturnStatusFailed);
249 if ((end_bp_id == LLDB_INVALID_BREAK_ID)
250 || (! target->GetBreakpointByID (end_bp_id)))
253 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end);
254 result.SetStatus (eReturnStatusFailed);
259 if (((start_loc_id == LLDB_INVALID_BREAK_ID)
260 && (end_loc_id != LLDB_INVALID_BREAK_ID))
261 || ((start_loc_id != LLDB_INVALID_BREAK_ID)
262 && (end_loc_id == LLDB_INVALID_BREAK_ID)))
265 result.AppendErrorWithFormat ("Invalid breakpoint id range: Either both ends of range must specify"
266 " a breakpoint location, or neither can specify a breakpoint location.\n");
267 result.SetStatus (eReturnStatusFailed);
271 // We have valid range starting & ending breakpoint IDs. Go through all the breakpoints in the
272 // target and find all the breakpoints that fit into this range, and add them to new_args.
274 // Next check to see if we have location id's. If so, make sure the start_bp_id and end_bp_id are
275 // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify
276 // bp locations are NOT allowed to cross major bp id numbers.
278 if ((start_loc_id != LLDB_INVALID_BREAK_ID)
279 || (end_loc_id != LLDB_INVALID_BREAK_ID))
281 if (start_bp_id != end_bp_id)
284 result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations"
285 " must be within the same major breakpoint; you specified two"
286 " different major breakpoints, %d and %d.\n",
287 start_bp_id, end_bp_id);
288 result.SetStatus (eReturnStatusFailed);
293 const BreakpointList& breakpoints = target->GetBreakpointList();
294 const size_t num_breakpoints = breakpoints.GetSize();
295 for (size_t j = 0; j < num_breakpoints; ++j)
297 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get();
298 break_id_t cur_bp_id = breakpoint->GetID();
300 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
303 const size_t num_locations = breakpoint->GetNumLocations();
305 if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
307 for (size_t k = 0; k < num_locations; ++k)
309 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
310 if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id))
312 StreamString canonical_id_str;
313 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
314 new_args.AppendArgument (canonical_id_str.GetData());
318 else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID))
320 for (size_t k = 0; k < num_locations; ++k)
322 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
323 if (bp_loc->GetID() <= end_loc_id)
325 StreamString canonical_id_str;
326 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
327 new_args.AppendArgument (canonical_id_str.GetData());
333 StreamString canonical_id_str;
334 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID);
335 new_args.AppendArgument (canonical_id_str.GetData());
339 else // else is_range was false
341 new_args.AppendArgument (current_arg);
345 result.SetStatus (eReturnStatusSuccessFinishNoResult);
350 BreakpointIDList::StringContainsIDRangeExpression (const char *in_string,
351 size_t *range_start_len,
352 size_t *range_end_pos)
354 bool is_range_expression = false;
355 std::string arg_str = in_string;
356 std::string::size_type idx;
357 std::string::size_type start_pos = 0;
359 *range_start_len = 0;
362 int specifiers_size = 0;
363 for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i)
366 for (int i = 0; i < specifiers_size && !is_range_expression; ++i)
368 const char *specifier_str = BreakpointID::g_range_specifiers[i];
369 size_t len = strlen (specifier_str);
370 idx = arg_str.find (BreakpointID::g_range_specifiers[i]);
371 if (idx != std::string::npos)
373 *range_start_len = idx - start_pos;
374 std::string start_str = arg_str.substr (start_pos, *range_start_len);
375 if (idx + len < arg_str.length())
377 *range_end_pos = idx + len;
378 std::string end_str = arg_str.substr (*range_end_pos);
379 if (BreakpointID::IsValidIDExpression (start_str.c_str())
380 && BreakpointID::IsValidIDExpression (end_str.c_str()))
382 is_range_expression = true;
383 //*range_start = start_str;
384 //*range_end = end_str;
390 if (!is_range_expression)
392 *range_start_len = 0;
396 return is_range_expression;