blob: 8485dcd4eb5867bd3e7bef03d4478142fae48698 [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
Jim Inghamdb308772016-09-14 19:05:27 +000034size_t BreakpointIDList::GetSize() const { return m_breakpoint_ids.size(); }
Kate Stoneb9c1b512016-09-06 20:57:50 +000035
Jim Inghamdb308772016-09-14 19:05:27 +000036const BreakpointID &
37BreakpointIDList::GetBreakpointIDAtIndex(size_t index) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +000038 return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]
39 : m_invalid_id);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000040}
41
Kate Stoneb9c1b512016-09-06 20:57:50 +000042bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {
43 if (index >= m_breakpoint_ids.size())
44 return false;
45
46 m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);
47 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000048}
49
Kate Stoneb9c1b512016-09-06 20:57:50 +000050void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000051
Kate Stoneb9c1b512016-09-06 20:57:50 +000052bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {
53 m_breakpoint_ids.push_back(bp_id);
54
55 return true; // We don't do any verification in this function, so always
56 // return true.
Chris Lattner30fdc8d2010-06-08 16:52:24 +000057}
58
Kate Stoneb9c1b512016-09-06 20:57:50 +000059bool BreakpointIDList::AddBreakpointID(const char *bp_id_str) {
Zachary Turner401f55d2016-10-05 17:07:47 +000060 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
61 if (!bp_id.hasValue())
62 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +000063
Zachary Turner401f55d2016-10-05 17:07:47 +000064 m_breakpoint_ids.push_back(*bp_id);
65 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000066}
67
Jim Inghamdb308772016-09-14 19:05:27 +000068bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id,
69 size_t *position) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +000070 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) {
71 BreakpointID tmp_id = m_breakpoint_ids[i];
72 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() &&
73 tmp_id.GetLocationID() == bp_id.GetLocationID()) {
74 *position = i;
75 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000076 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000077 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000078
Kate Stoneb9c1b512016-09-06 20:57:50 +000079 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000080}
81
Kate Stoneb9c1b512016-09-06 20:57:50 +000082bool BreakpointIDList::FindBreakpointID(const char *bp_id_str,
Jim Inghamdb308772016-09-14 19:05:27 +000083 size_t *position) const {
Zachary Turner401f55d2016-10-05 17:07:47 +000084 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
85 if (!bp_id.hasValue())
Chris Lattner30fdc8d2010-06-08 16:52:24 +000086 return false;
Zachary Turner401f55d2016-10-05 17:07:47 +000087
88 return FindBreakpointID(*bp_id, position);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000089}
90
Kate Stoneb9c1b512016-09-06 20:57:50 +000091void BreakpointIDList::InsertStringArray(const char **string_array,
92 size_t array_size,
93 CommandReturnObject &result) {
94 if (string_array == nullptr)
95 return;
96
97 for (uint32_t i = 0; i < array_size; ++i) {
Zachary Turner401f55d2016-10-05 17:07:47 +000098 auto bp_id = BreakpointID::ParseCanonicalReference(string_array[i]);
99 if (bp_id.hasValue()) {
100 m_breakpoint_ids.push_back(*bp_id);
101 } else {
102 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
103 string_array[i]);
104 result.SetStatus(eReturnStatusFailed);
105 return;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000106 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107 }
108 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109}
110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111// This function takes OLD_ARGS, which is usually the result of breaking the
112// command string arguments into
113// an array of space-separated strings, and searches through the arguments for
114// any breakpoint ID range specifiers.
115// Any string in the array that is not part of an ID range specifier is copied
116// directly into NEW_ARGS. If any
117// ID range specifiers are found, the range is interpreted and a list of
118// canonical breakpoint IDs corresponding to
119// all the current breakpoints and locations in the range are added to
120// NEW_ARGS. When this function is done,
121// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
122// by the members of the range.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000123
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
125 bool allow_locations,
126 CommandReturnObject &result,
127 Args &new_args) {
Zachary Turner401f55d2016-10-05 17:07:47 +0000128 llvm::StringRef range_from;
129 llvm::StringRef range_to;
130 llvm::StringRef current_arg;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000131 const size_t num_old_args = old_args.GetArgumentCount();
132 std::set<std::string> names_found;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000133
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134 for (size_t i = 0; i < num_old_args; ++i) {
135 bool is_range = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000136
Kate Stoneb9c1b512016-09-06 20:57:50 +0000137 current_arg = old_args.GetArgumentAtIndex(i);
Zachary Turner401f55d2016-10-05 17:07:47 +0000138 if (!allow_locations && current_arg.contains('.')) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139 result.AppendErrorWithFormat(
Zachary Turner401f55d2016-10-05 17:07:47 +0000140 "Breakpoint locations not allowed, saw location: %s.",
141 current_arg.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000142 new_args.Clear();
143 return;
144 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000145
Zachary Turner401f55d2016-10-05 17:07:47 +0000146 llvm::StringRef range_expr;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 Error error;
148
Zachary Turner401f55d2016-10-05 17:07:47 +0000149 std::tie(range_from, range_to) =
150 BreakpointIDList::SplitIDRangeExpression(current_arg);
151 if (!range_from.empty() && !range_to.empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152 is_range = true;
Zachary Turner401f55d2016-10-05 17:07:47 +0000153 } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 if (!error.Success()) {
155 new_args.Clear();
156 result.AppendError(error.AsCString());
157 result.SetStatus(eReturnStatusFailed);
158 return;
159 } else
160 names_found.insert(current_arg);
161 } else if ((i + 2 < num_old_args) &&
162 BreakpointID::IsRangeIdentifier(
163 old_args.GetArgumentAtIndex(i + 1)) &&
164 BreakpointID::IsValidIDExpression(current_arg) &&
165 BreakpointID::IsValidIDExpression(
166 old_args.GetArgumentAtIndex(i + 2))) {
Zachary Turner401f55d2016-10-05 17:07:47 +0000167 range_from = current_arg;
168 range_to = old_args.GetArgumentAtIndex(i + 2);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000169 is_range = true;
170 i = i + 2;
171 } else {
172 // See if user has specified id.*
Zachary Turner401f55d2016-10-05 17:07:47 +0000173 llvm::StringRef tmp_str = old_args.GetArgumentAtIndex(i);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000174 size_t pos = tmp_str.find('.');
Zachary Turner401f55d2016-10-05 17:07:47 +0000175 if (pos != llvm::StringRef::npos) {
176 llvm::StringRef bp_id_str = tmp_str.substr(0, pos);
177 if (BreakpointID::IsValidIDExpression(bp_id_str) &&
178 tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179
Zachary Turner401f55d2016-10-05 17:07:47 +0000180 BreakpointSP breakpoint_sp;
181 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
182 if (bp_id.hasValue())
183 breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000184 if (!breakpoint_sp) {
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000185 new_args.Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000186 result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
Zachary Turner401f55d2016-10-05 17:07:47 +0000187 bp_id->GetBreakpointID());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000188 result.SetStatus(eReturnStatusFailed);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000189 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190 }
191 const size_t num_locations = breakpoint_sp->GetNumLocations();
192 for (size_t j = 0; j < num_locations; ++j) {
193 BreakpointLocation *bp_loc =
194 breakpoint_sp->GetLocationAtIndex(j).get();
195 StreamString canonical_id_str;
Zachary Turner401f55d2016-10-05 17:07:47 +0000196 BreakpointID::GetCanonicalReference(
197 &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000198 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000199 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000200 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000201 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000202 }
203
Zachary Turner401f55d2016-10-05 17:07:47 +0000204 if (!is_range) {
205 new_args.AppendArgument(current_arg);
206 continue;
207 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000208
Zachary Turner401f55d2016-10-05 17:07:47 +0000209 auto start_bp = BreakpointID::ParseCanonicalReference(range_from);
210 auto end_bp = BreakpointID::ParseCanonicalReference(range_to);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000211
Zachary Turner401f55d2016-10-05 17:07:47 +0000212 if (!start_bp.hasValue() ||
213 !target->GetBreakpointByID(start_bp->GetBreakpointID())) {
214 new_args.Clear();
215 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
216 range_from.str().c_str());
217 result.SetStatus(eReturnStatusFailed);
218 return;
219 }
220
221 if (!end_bp.hasValue() ||
222 !target->GetBreakpointByID(end_bp->GetBreakpointID())) {
223 new_args.Clear();
224 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
225 range_to.str().c_str());
226 result.SetStatus(eReturnStatusFailed);
227 return;
228 }
229 break_id_t start_bp_id = start_bp->GetBreakpointID();
230 break_id_t start_loc_id = start_bp->GetLocationID();
231 break_id_t end_bp_id = end_bp->GetBreakpointID();
232 break_id_t end_loc_id = end_bp->GetLocationID();
233 if (((start_bp_id == LLDB_INVALID_BREAK_ID) &&
234 (end_bp_id != LLDB_INVALID_BREAK_ID)) ||
235 ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
236 (end_loc_id == LLDB_INVALID_BREAK_ID))) {
237 new_args.Clear();
238 result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
239 "both ends of range must specify"
240 " a breakpoint location, or neither can "
241 "specify a breakpoint location.\n");
242 result.SetStatus(eReturnStatusFailed);
243 return;
244 }
245
246 // We have valid range starting & ending breakpoint IDs. Go through all
247 // the breakpoints in the target and find all the breakpoints that fit
248 // into this range, and add them to new_args.
249
250 // Next check to see if we have location id's. If so, make sure the
251 // start_bp_id and end_bp_id are for the same breakpoint; otherwise we
252 // have an illegal range: breakpoint id ranges that specify bp locations
253 // are NOT allowed to cross major bp id numbers.
254
255 if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
256 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
257 if (start_bp_id != end_bp_id) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000258 new_args.Clear();
Zachary Turner401f55d2016-10-05 17:07:47 +0000259 result.AppendErrorWithFormat(
260 "Invalid range: Ranges that specify particular breakpoint "
261 "locations"
262 " must be within the same major breakpoint; you specified two"
263 " different major breakpoints, %d and %d.\n",
264 start_bp_id, end_bp_id);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000265 result.SetStatus(eReturnStatusFailed);
266 return;
267 }
Zachary Turner401f55d2016-10-05 17:07:47 +0000268 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000269
Zachary Turner401f55d2016-10-05 17:07:47 +0000270 const BreakpointList &breakpoints = target->GetBreakpointList();
271 const size_t num_breakpoints = breakpoints.GetSize();
272 for (size_t j = 0; j < num_breakpoints; ++j) {
273 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
274 break_id_t cur_bp_id = breakpoint->GetID();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000275
Zachary Turner401f55d2016-10-05 17:07:47 +0000276 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
277 continue;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000278
Zachary Turner401f55d2016-10-05 17:07:47 +0000279 const size_t num_locations = breakpoint->GetNumLocations();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000280
Zachary Turner401f55d2016-10-05 17:07:47 +0000281 if ((cur_bp_id == start_bp_id) &&
282 (start_loc_id != LLDB_INVALID_BREAK_ID)) {
283 for (size_t k = 0; k < num_locations; ++k) {
284 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
285 if ((bp_loc->GetID() >= start_loc_id) &&
286 (bp_loc->GetID() <= end_loc_id)) {
287 StreamString canonical_id_str;
288 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
289 bp_loc->GetID());
290 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000291 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000292 }
Zachary Turner401f55d2016-10-05 17:07:47 +0000293 } else if ((cur_bp_id == end_bp_id) &&
294 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
295 for (size_t k = 0; k < num_locations; ++k) {
296 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
297 if (bp_loc->GetID() <= end_loc_id) {
298 StreamString canonical_id_str;
299 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
300 bp_loc->GetID());
301 new_args.AppendArgument(canonical_id_str.GetString());
302 }
303 }
304 } else {
305 StreamString canonical_id_str;
306 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
307 LLDB_INVALID_BREAK_ID);
308 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000309 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000310 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000311 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000312
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313 // Okay, now see if we found any names, and if we did, add them:
314 if (target && names_found.size()) {
315 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
316 for (std::string name : names_found) {
317 if (bkpt_sp->MatchesName(name.c_str())) {
318 StreamString canonical_id_str;
319 BreakpointID::GetCanonicalReference(
320 &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000321 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000322 }
323 }
324 }
325 }
326
327 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000328}
329
Zachary Turner401f55d2016-10-05 17:07:47 +0000330std::pair<llvm::StringRef, llvm::StringRef>
331BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {
332 for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {
333 size_t idx = in_string.find(specifier_str);
334 if (idx == llvm::StringRef::npos)
335 continue;
336 llvm::StringRef right1 = in_string.drop_front(idx);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000337
Zachary Turner401f55d2016-10-05 17:07:47 +0000338 llvm::StringRef from = in_string.take_front(idx);
339 llvm::StringRef to = right1.drop_front(specifier_str.size());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000340
Zachary Turner401f55d2016-10-05 17:07:47 +0000341 if (BreakpointID::IsValidIDExpression(from) &&
342 BreakpointID::IsValidIDExpression(to)) {
343 return std::make_pair(from, to);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000344 }
345 }
346
Zachary Turner401f55d2016-10-05 17:07:47 +0000347 return std::pair<llvm::StringRef, llvm::StringRef>();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000348}