blob: 037b03e1e46afea9007f342f5ded3ad719297df1 [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]);
Zachary Turner0d4f23c2016-10-05 18:40:51 +000099 if (bp_id.hasValue())
Zachary Turner401f55d2016-10-05 17:07:47 +0000100 m_breakpoint_ids.push_back(*bp_id);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000101 }
102 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000103}
104
Kate Stoneb9c1b512016-09-06 20:57:50 +0000105// This function takes OLD_ARGS, which is usually the result of breaking the
106// command string arguments into
107// an array of space-separated strings, and searches through the arguments for
108// any breakpoint ID range specifiers.
109// Any string in the array that is not part of an ID range specifier is copied
110// directly into NEW_ARGS. If any
111// ID range specifiers are found, the range is interpreted and a list of
112// canonical breakpoint IDs corresponding to
113// all the current breakpoints and locations in the range are added to
114// NEW_ARGS. When this function is done,
115// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
116// by the members of the range.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000117
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
119 bool allow_locations,
120 CommandReturnObject &result,
121 Args &new_args) {
Zachary Turner401f55d2016-10-05 17:07:47 +0000122 llvm::StringRef range_from;
123 llvm::StringRef range_to;
124 llvm::StringRef current_arg;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125 std::set<std::string> names_found;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000126
Zachary Turnerd6a24752016-11-22 17:10:15 +0000127 for (size_t i = 0; i < old_args.size(); ++i) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 bool is_range = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000129
Zachary Turnerd6a24752016-11-22 17:10:15 +0000130 current_arg = old_args[i].ref;
Zachary Turner401f55d2016-10-05 17:07:47 +0000131 if (!allow_locations && current_arg.contains('.')) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 result.AppendErrorWithFormat(
Zachary Turner401f55d2016-10-05 17:07:47 +0000133 "Breakpoint locations not allowed, saw location: %s.",
134 current_arg.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135 new_args.Clear();
136 return;
137 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000138
Zachary Turner401f55d2016-10-05 17:07:47 +0000139 llvm::StringRef range_expr;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000140 Error error;
141
Zachary Turner401f55d2016-10-05 17:07:47 +0000142 std::tie(range_from, range_to) =
143 BreakpointIDList::SplitIDRangeExpression(current_arg);
144 if (!range_from.empty() && !range_to.empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000145 is_range = true;
Zachary Turner401f55d2016-10-05 17:07:47 +0000146 } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 if (!error.Success()) {
148 new_args.Clear();
149 result.AppendError(error.AsCString());
150 result.SetStatus(eReturnStatusFailed);
151 return;
152 } else
153 names_found.insert(current_arg);
Zachary Turnerd6a24752016-11-22 17:10:15 +0000154 } else if ((i + 2 < old_args.size()) &&
155 BreakpointID::IsRangeIdentifier(old_args[i + 1].ref) &&
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156 BreakpointID::IsValidIDExpression(current_arg) &&
Zachary Turnerd6a24752016-11-22 17:10:15 +0000157 BreakpointID::IsValidIDExpression(old_args[i + 2].ref)) {
Zachary Turner401f55d2016-10-05 17:07:47 +0000158 range_from = current_arg;
Zachary Turnerd6a24752016-11-22 17:10:15 +0000159 range_to = old_args[i + 2].ref;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000160 is_range = true;
161 i = i + 2;
162 } else {
163 // See if user has specified id.*
Zachary Turnerd6a24752016-11-22 17:10:15 +0000164 llvm::StringRef tmp_str = old_args[i].ref;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165 size_t pos = tmp_str.find('.');
Zachary Turner401f55d2016-10-05 17:07:47 +0000166 if (pos != llvm::StringRef::npos) {
167 llvm::StringRef bp_id_str = tmp_str.substr(0, pos);
168 if (BreakpointID::IsValidIDExpression(bp_id_str) &&
169 tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170
Zachary Turner401f55d2016-10-05 17:07:47 +0000171 BreakpointSP breakpoint_sp;
172 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
173 if (bp_id.hasValue())
174 breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000175 if (!breakpoint_sp) {
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000176 new_args.Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000177 result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
Zachary Turner401f55d2016-10-05 17:07:47 +0000178 bp_id->GetBreakpointID());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179 result.SetStatus(eReturnStatusFailed);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000180 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181 }
182 const size_t num_locations = breakpoint_sp->GetNumLocations();
183 for (size_t j = 0; j < num_locations; ++j) {
184 BreakpointLocation *bp_loc =
185 breakpoint_sp->GetLocationAtIndex(j).get();
186 StreamString canonical_id_str;
Zachary Turner401f55d2016-10-05 17:07:47 +0000187 BreakpointID::GetCanonicalReference(
188 &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000189 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000191 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000193 }
194
Zachary Turner401f55d2016-10-05 17:07:47 +0000195 if (!is_range) {
196 new_args.AppendArgument(current_arg);
197 continue;
198 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000199
Zachary Turner401f55d2016-10-05 17:07:47 +0000200 auto start_bp = BreakpointID::ParseCanonicalReference(range_from);
201 auto end_bp = BreakpointID::ParseCanonicalReference(range_to);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000202
Zachary Turner401f55d2016-10-05 17:07:47 +0000203 if (!start_bp.hasValue() ||
204 !target->GetBreakpointByID(start_bp->GetBreakpointID())) {
205 new_args.Clear();
206 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
207 range_from.str().c_str());
208 result.SetStatus(eReturnStatusFailed);
209 return;
210 }
211
212 if (!end_bp.hasValue() ||
213 !target->GetBreakpointByID(end_bp->GetBreakpointID())) {
214 new_args.Clear();
215 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
216 range_to.str().c_str());
217 result.SetStatus(eReturnStatusFailed);
218 return;
219 }
220 break_id_t start_bp_id = start_bp->GetBreakpointID();
221 break_id_t start_loc_id = start_bp->GetLocationID();
222 break_id_t end_bp_id = end_bp->GetBreakpointID();
223 break_id_t end_loc_id = end_bp->GetLocationID();
Zachary Turner0d4f23c2016-10-05 18:40:51 +0000224 if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
225 (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
Zachary Turner401f55d2016-10-05 17:07:47 +0000226 ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
227 (end_loc_id == LLDB_INVALID_BREAK_ID))) {
228 new_args.Clear();
229 result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
230 "both ends of range must specify"
231 " a breakpoint location, or neither can "
232 "specify a breakpoint location.\n");
233 result.SetStatus(eReturnStatusFailed);
234 return;
235 }
236
237 // We have valid range starting & ending breakpoint IDs. Go through all
238 // the breakpoints in the target and find all the breakpoints that fit
239 // into this range, and add them to new_args.
240
241 // Next check to see if we have location id's. If so, make sure the
242 // start_bp_id and end_bp_id are for the same breakpoint; otherwise we
243 // have an illegal range: breakpoint id ranges that specify bp locations
244 // are NOT allowed to cross major bp id numbers.
245
246 if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
247 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
248 if (start_bp_id != end_bp_id) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000249 new_args.Clear();
Zachary Turner401f55d2016-10-05 17:07:47 +0000250 result.AppendErrorWithFormat(
251 "Invalid range: Ranges that specify particular breakpoint "
252 "locations"
253 " must be within the same major breakpoint; you specified two"
254 " different major breakpoints, %d and %d.\n",
255 start_bp_id, end_bp_id);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000256 result.SetStatus(eReturnStatusFailed);
257 return;
258 }
Zachary Turner401f55d2016-10-05 17:07:47 +0000259 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000260
Zachary Turner401f55d2016-10-05 17:07:47 +0000261 const BreakpointList &breakpoints = target->GetBreakpointList();
262 const size_t num_breakpoints = breakpoints.GetSize();
263 for (size_t j = 0; j < num_breakpoints; ++j) {
264 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
265 break_id_t cur_bp_id = breakpoint->GetID();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000266
Zachary Turner401f55d2016-10-05 17:07:47 +0000267 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
268 continue;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000269
Zachary Turner401f55d2016-10-05 17:07:47 +0000270 const size_t num_locations = breakpoint->GetNumLocations();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000271
Zachary Turner401f55d2016-10-05 17:07:47 +0000272 if ((cur_bp_id == start_bp_id) &&
273 (start_loc_id != LLDB_INVALID_BREAK_ID)) {
274 for (size_t k = 0; k < num_locations; ++k) {
275 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
276 if ((bp_loc->GetID() >= start_loc_id) &&
277 (bp_loc->GetID() <= end_loc_id)) {
278 StreamString canonical_id_str;
279 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
280 bp_loc->GetID());
281 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000282 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000283 }
Zachary Turner401f55d2016-10-05 17:07:47 +0000284 } else if ((cur_bp_id == end_bp_id) &&
285 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
286 for (size_t k = 0; k < num_locations; ++k) {
287 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
288 if (bp_loc->GetID() <= end_loc_id) {
289 StreamString canonical_id_str;
290 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
291 bp_loc->GetID());
292 new_args.AppendArgument(canonical_id_str.GetString());
293 }
294 }
295 } else {
296 StreamString canonical_id_str;
297 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
298 LLDB_INVALID_BREAK_ID);
299 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000300 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000301 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000302 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000303
Kate Stoneb9c1b512016-09-06 20:57:50 +0000304 // Okay, now see if we found any names, and if we did, add them:
305 if (target && names_found.size()) {
306 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
307 for (std::string name : names_found) {
308 if (bkpt_sp->MatchesName(name.c_str())) {
309 StreamString canonical_id_str;
310 BreakpointID::GetCanonicalReference(
311 &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000312 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313 }
314 }
315 }
316 }
317
318 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000319}
320
Zachary Turner401f55d2016-10-05 17:07:47 +0000321std::pair<llvm::StringRef, llvm::StringRef>
322BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {
323 for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {
324 size_t idx = in_string.find(specifier_str);
325 if (idx == llvm::StringRef::npos)
326 continue;
327 llvm::StringRef right1 = in_string.drop_front(idx);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000328
Zachary Turner401f55d2016-10-05 17:07:47 +0000329 llvm::StringRef from = in_string.take_front(idx);
330 llvm::StringRef to = right1.drop_front(specifier_str.size());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000331
Zachary Turner401f55d2016-10-05 17:07:47 +0000332 if (BreakpointID::IsValidIDExpression(from) &&
333 BreakpointID::IsValidIDExpression(to)) {
334 return std::make_pair(from, to);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335 }
336 }
337
Zachary Turner401f55d2016-10-05 17:07:47 +0000338 return std::pair<llvm::StringRef, llvm::StringRef>();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000339}