blob: 4871105def7fd0cb3de2f4380abe260beaf25423 [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
Kate Stoneb9c1b512016-09-06 20:57:50 +000034size_t BreakpointIDList::GetSize() { return m_breakpoint_ids.size(); }
35
36BreakpointID &BreakpointIDList::GetBreakpointIDAtIndex(size_t index) {
37 return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]
38 : m_invalid_id);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000039}
40
Kate Stoneb9c1b512016-09-06 20:57:50 +000041bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {
42 if (index >= m_breakpoint_ids.size())
43 return false;
44
45 m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);
46 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000047}
48
Kate Stoneb9c1b512016-09-06 20:57:50 +000049void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000050
Kate Stoneb9c1b512016-09-06 20:57:50 +000051bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {
52 m_breakpoint_ids.push_back(bp_id);
53
54 return true; // We don't do any verification in this function, so always
55 // return true.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000056}
57
Kate Stoneb9c1b512016-09-06 20:57:50 +000058bool BreakpointIDList::AddBreakpointID(const char *bp_id_str) {
59 BreakpointID temp_bp_id;
60 break_id_t bp_id;
61 break_id_t loc_id;
62
63 bool success =
64 BreakpointID::ParseCanonicalReference(bp_id_str, &bp_id, &loc_id);
65
66 if (success) {
67 temp_bp_id.SetID(bp_id, loc_id);
68 m_breakpoint_ids.push_back(temp_bp_id);
69 }
70
71 return success;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000072}
73
Kate Stoneb9c1b512016-09-06 20:57:50 +000074bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id, size_t *position) {
75 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) {
76 BreakpointID tmp_id = m_breakpoint_ids[i];
77 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() &&
78 tmp_id.GetLocationID() == bp_id.GetLocationID()) {
79 *position = i;
80 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000081 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000082 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000083
Kate Stoneb9c1b512016-09-06 20:57:50 +000084 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000085}
86
Kate Stoneb9c1b512016-09-06 20:57:50 +000087bool BreakpointIDList::FindBreakpointID(const char *bp_id_str,
88 size_t *position) {
89 BreakpointID temp_bp_id;
90 break_id_t bp_id;
91 break_id_t loc_id;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000092
Kate Stoneb9c1b512016-09-06 20:57:50 +000093 if (BreakpointID::ParseCanonicalReference(bp_id_str, &bp_id, &loc_id)) {
94 temp_bp_id.SetID(bp_id, loc_id);
95 return FindBreakpointID(temp_bp_id, position);
96 } else
Chris Lattner30fdc8d2010-06-08 16:52:24 +000097 return false;
98}
99
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100void BreakpointIDList::InsertStringArray(const char **string_array,
101 size_t array_size,
102 CommandReturnObject &result) {
103 if (string_array == nullptr)
104 return;
105
106 for (uint32_t i = 0; i < array_size; ++i) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000107 break_id_t bp_id;
108 break_id_t loc_id;
109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 if (BreakpointID::ParseCanonicalReference(string_array[i], &bp_id,
111 &loc_id)) {
112 if (bp_id != LLDB_INVALID_BREAK_ID) {
113 BreakpointID temp_bp_id(bp_id, loc_id);
114 m_breakpoint_ids.push_back(temp_bp_id);
115 } else {
116 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
117 string_array[i]);
118 result.SetStatus(eReturnStatusFailed);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000119 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000121 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000122 }
123 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000124}
125
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126// This function takes OLD_ARGS, which is usually the result of breaking the
127// command string arguments into
128// an array of space-separated strings, and searches through the arguments for
129// any breakpoint ID range specifiers.
130// Any string in the array that is not part of an ID range specifier is copied
131// directly into NEW_ARGS. If any
132// ID range specifiers are found, the range is interpreted and a list of
133// canonical breakpoint IDs corresponding to
134// all the current breakpoints and locations in the range are added to
135// NEW_ARGS. When this function is done,
136// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
137// by the members of the range.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000138
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
140 bool allow_locations,
141 CommandReturnObject &result,
142 Args &new_args) {
143 std::string range_start;
144 const char *range_end;
145 const char *current_arg;
146 const size_t num_old_args = old_args.GetArgumentCount();
147 std::set<std::string> names_found;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000148
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 for (size_t i = 0; i < num_old_args; ++i) {
150 bool is_range = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000151
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152 current_arg = old_args.GetArgumentAtIndex(i);
153 if (!allow_locations && strchr(current_arg, '.') != nullptr) {
154 result.AppendErrorWithFormat(
155 "Breakpoint locations not allowed, saw location: %s.", current_arg);
156 new_args.Clear();
157 return;
158 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000159
Kate Stoneb9c1b512016-09-06 20:57:50 +0000160 size_t range_start_len = 0;
161 size_t range_end_pos = 0;
162 Error error;
163
164 if (BreakpointIDList::StringContainsIDRangeExpression(
165 current_arg, &range_start_len, &range_end_pos)) {
166 is_range = true;
167 range_start.assign(current_arg, range_start_len);
168 range_end = current_arg + range_end_pos;
169 } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
170 if (!error.Success()) {
171 new_args.Clear();
172 result.AppendError(error.AsCString());
173 result.SetStatus(eReturnStatusFailed);
174 return;
175 } else
176 names_found.insert(current_arg);
177 } else if ((i + 2 < num_old_args) &&
178 BreakpointID::IsRangeIdentifier(
179 old_args.GetArgumentAtIndex(i + 1)) &&
180 BreakpointID::IsValidIDExpression(current_arg) &&
181 BreakpointID::IsValidIDExpression(
182 old_args.GetArgumentAtIndex(i + 2))) {
183 range_start.assign(current_arg);
184 range_end = old_args.GetArgumentAtIndex(i + 2);
185 is_range = true;
186 i = i + 2;
187 } else {
188 // See if user has specified id.*
189 std::string tmp_str = old_args.GetArgumentAtIndex(i);
190 size_t pos = tmp_str.find('.');
191 if (pos != std::string::npos) {
192 std::string bp_id_str = tmp_str.substr(0, pos);
193 if (BreakpointID::IsValidIDExpression(bp_id_str.c_str()) &&
194 tmp_str[pos + 1] == '*' && tmp_str.length() == (pos + 2)) {
195 break_id_t bp_id;
196 break_id_t bp_loc_id;
197
198 BreakpointID::ParseCanonicalReference(bp_id_str.c_str(), &bp_id,
199 &bp_loc_id);
200 BreakpointSP breakpoint_sp = target->GetBreakpointByID(bp_id);
201 if (!breakpoint_sp) {
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000202 new_args.Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
204 bp_id);
205 result.SetStatus(eReturnStatusFailed);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000206 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000207 }
208 const size_t num_locations = breakpoint_sp->GetNumLocations();
209 for (size_t j = 0; j < num_locations; ++j) {
210 BreakpointLocation *bp_loc =
211 breakpoint_sp->GetLocationAtIndex(j).get();
212 StreamString canonical_id_str;
213 BreakpointID::GetCanonicalReference(&canonical_id_str, bp_id,
214 bp_loc->GetID());
215 new_args.AppendArgument(canonical_id_str.GetData());
216 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000217 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000219 }
220
Kate Stoneb9c1b512016-09-06 20:57:50 +0000221 if (is_range) {
222 break_id_t start_bp_id;
223 break_id_t end_bp_id;
224 break_id_t start_loc_id;
225 break_id_t end_loc_id;
226
227 BreakpointID::ParseCanonicalReference(range_start.c_str(), &start_bp_id,
228 &start_loc_id);
229 BreakpointID::ParseCanonicalReference(range_end, &end_bp_id, &end_loc_id);
230
231 if ((start_bp_id == LLDB_INVALID_BREAK_ID) ||
232 (!target->GetBreakpointByID(start_bp_id))) {
233 new_args.Clear();
234 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
235 range_start.c_str());
236 result.SetStatus(eReturnStatusFailed);
237 return;
238 }
239
240 if ((end_bp_id == LLDB_INVALID_BREAK_ID) ||
241 (!target->GetBreakpointByID(end_bp_id))) {
242 new_args.Clear();
243 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
244 range_end);
245 result.SetStatus(eReturnStatusFailed);
246 return;
247 }
248
249 if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
250 (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
251 ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
252 (end_loc_id == LLDB_INVALID_BREAK_ID))) {
253 new_args.Clear();
254 result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
255 "both ends of range must specify"
256 " a breakpoint location, or neither can "
257 "specify a breakpoint location.\n");
258 result.SetStatus(eReturnStatusFailed);
259 return;
260 }
261
262 // We have valid range starting & ending breakpoint IDs. Go through all
263 // the breakpoints in the
264 // target and find all the breakpoints that fit into this range, and add
265 // them to new_args.
266
267 // Next check to see if we have location id's. If so, make sure the
268 // start_bp_id and end_bp_id are
269 // for the same breakpoint; otherwise we have an illegal range: breakpoint
270 // id ranges that specify
271 // bp locations are NOT allowed to cross major bp id numbers.
272
273 if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
274 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
275 if (start_bp_id != end_bp_id) {
276 new_args.Clear();
277 result.AppendErrorWithFormat(
278 "Invalid range: Ranges that specify particular breakpoint "
279 "locations"
280 " must be within the same major breakpoint; you specified two"
281 " different major breakpoints, %d and %d.\n",
282 start_bp_id, end_bp_id);
283 result.SetStatus(eReturnStatusFailed);
284 return;
285 }
286 }
287
288 const BreakpointList &breakpoints = target->GetBreakpointList();
289 const size_t num_breakpoints = breakpoints.GetSize();
290 for (size_t j = 0; j < num_breakpoints; ++j) {
291 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
292 break_id_t cur_bp_id = breakpoint->GetID();
293
294 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
295 continue;
296
297 const size_t num_locations = breakpoint->GetNumLocations();
298
299 if ((cur_bp_id == start_bp_id) &&
300 (start_loc_id != LLDB_INVALID_BREAK_ID)) {
301 for (size_t k = 0; k < num_locations; ++k) {
302 BreakpointLocation *bp_loc =
303 breakpoint->GetLocationAtIndex(k).get();
304 if ((bp_loc->GetID() >= start_loc_id) &&
305 (bp_loc->GetID() <= end_loc_id)) {
306 StreamString canonical_id_str;
307 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
308 bp_loc->GetID());
309 new_args.AppendArgument(canonical_id_str.GetData());
310 }
311 }
312 } else if ((cur_bp_id == end_bp_id) &&
313 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
314 for (size_t k = 0; k < num_locations; ++k) {
315 BreakpointLocation *bp_loc =
316 breakpoint->GetLocationAtIndex(k).get();
317 if (bp_loc->GetID() <= end_loc_id) {
318 StreamString canonical_id_str;
319 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
320 bp_loc->GetID());
321 new_args.AppendArgument(canonical_id_str.GetData());
322 }
323 }
324 } else {
325 StreamString canonical_id_str;
326 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
327 LLDB_INVALID_BREAK_ID);
328 new_args.AppendArgument(canonical_id_str.GetData());
329 }
330 }
331 } else // else is_range was false
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000332 {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000333 new_args.AppendArgument(current_arg);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000334 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000336
Kate Stoneb9c1b512016-09-06 20:57:50 +0000337 // Okay, now see if we found any names, and if we did, add them:
338 if (target && names_found.size()) {
339 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
340 for (std::string name : names_found) {
341 if (bkpt_sp->MatchesName(name.c_str())) {
342 StreamString canonical_id_str;
343 BreakpointID::GetCanonicalReference(
344 &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
345 new_args.AppendArgument(canonical_id_str.GetData());
346 }
347 }
348 }
349 }
350
351 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000352}
353
Kate Stoneb9c1b512016-09-06 20:57:50 +0000354bool BreakpointIDList::StringContainsIDRangeExpression(const char *in_string,
355 size_t *range_start_len,
356 size_t *range_end_pos) {
357 bool is_range_expression = false;
358 std::string arg_str = in_string;
359 std::string::size_type idx;
360 std::string::size_type start_pos = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000361
Kate Stoneb9c1b512016-09-06 20:57:50 +0000362 *range_start_len = 0;
363 *range_end_pos = 0;
364
365 int specifiers_size = 0;
366 for (int i = 0; BreakpointID::g_range_specifiers[i] != nullptr; ++i)
367 ++specifiers_size;
368
369 for (int i = 0; i < specifiers_size && !is_range_expression; ++i) {
370 const char *specifier_str = BreakpointID::g_range_specifiers[i];
371 size_t len = strlen(specifier_str);
372 idx = arg_str.find(BreakpointID::g_range_specifiers[i]);
373 if (idx != std::string::npos) {
374 *range_start_len = idx - start_pos;
375 std::string start_str = arg_str.substr(start_pos, *range_start_len);
376 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())) {
381 is_range_expression = true;
382 //*range_start = start_str;
383 //*range_end = end_str;
384 }
385 }
386 }
387 }
388
389 if (!is_range_expression) {
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000390 *range_start_len = 0;
391 *range_end_pos = 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000392 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000393
Kate Stoneb9c1b512016-09-06 20:57:50 +0000394 return is_range_expression;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000395}