blob: 0f8a027b030b3738e2d2f240abf18fa9d4be0f5a [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;
Omair Javaid99a318e2016-11-22 09:47:00 +0000125 const size_t num_old_args = old_args.GetArgumentCount();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126 std::set<std::string> names_found;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000127
Omair Javaid99a318e2016-11-22 09:47:00 +0000128 for (size_t i = 0; i < num_old_args; ++i) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129 bool is_range = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000130
Omair Javaid99a318e2016-11-22 09:47:00 +0000131 current_arg = old_args.GetArgumentAtIndex(i);
Zachary Turner401f55d2016-10-05 17:07:47 +0000132 if (!allow_locations && current_arg.contains('.')) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133 result.AppendErrorWithFormat(
Zachary Turner401f55d2016-10-05 17:07:47 +0000134 "Breakpoint locations not allowed, saw location: %s.",
135 current_arg.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000136 new_args.Clear();
137 return;
138 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000139
Zachary Turner401f55d2016-10-05 17:07:47 +0000140 llvm::StringRef range_expr;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141 Error error;
142
Zachary Turner401f55d2016-10-05 17:07:47 +0000143 std::tie(range_from, range_to) =
144 BreakpointIDList::SplitIDRangeExpression(current_arg);
145 if (!range_from.empty() && !range_to.empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000146 is_range = true;
Zachary Turner401f55d2016-10-05 17:07:47 +0000147 } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 if (!error.Success()) {
149 new_args.Clear();
150 result.AppendError(error.AsCString());
151 result.SetStatus(eReturnStatusFailed);
152 return;
153 } else
154 names_found.insert(current_arg);
Omair Javaid99a318e2016-11-22 09:47:00 +0000155 } else if ((i + 2 < num_old_args) &&
156 BreakpointID::IsRangeIdentifier(
157 old_args.GetArgumentAtIndex(i + 1)) &&
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158 BreakpointID::IsValidIDExpression(current_arg) &&
Omair Javaid99a318e2016-11-22 09:47:00 +0000159 BreakpointID::IsValidIDExpression(
160 old_args.GetArgumentAtIndex(i + 2))) {
Zachary Turner401f55d2016-10-05 17:07:47 +0000161 range_from = current_arg;
Omair Javaid99a318e2016-11-22 09:47:00 +0000162 range_to = old_args.GetArgumentAtIndex(i + 2);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000163 is_range = true;
164 i = i + 2;
165 } else {
166 // See if user has specified id.*
Omair Javaid99a318e2016-11-22 09:47:00 +0000167 llvm::StringRef tmp_str = old_args.GetArgumentAtIndex(i);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000168 size_t pos = tmp_str.find('.');
Zachary Turner401f55d2016-10-05 17:07:47 +0000169 if (pos != llvm::StringRef::npos) {
170 llvm::StringRef bp_id_str = tmp_str.substr(0, pos);
171 if (BreakpointID::IsValidIDExpression(bp_id_str) &&
172 tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000173
Zachary Turner401f55d2016-10-05 17:07:47 +0000174 BreakpointSP breakpoint_sp;
175 auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
176 if (bp_id.hasValue())
177 breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178 if (!breakpoint_sp) {
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000179 new_args.Clear();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000180 result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
Zachary Turner401f55d2016-10-05 17:07:47 +0000181 bp_id->GetBreakpointID());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000182 result.SetStatus(eReturnStatusFailed);
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000183 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000184 }
185 const size_t num_locations = breakpoint_sp->GetNumLocations();
186 for (size_t j = 0; j < num_locations; ++j) {
187 BreakpointLocation *bp_loc =
188 breakpoint_sp->GetLocationAtIndex(j).get();
189 StreamString canonical_id_str;
Zachary Turner401f55d2016-10-05 17:07:47 +0000190 BreakpointID::GetCanonicalReference(
191 &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000192 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000193 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000194 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000195 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000196 }
197
Zachary Turner401f55d2016-10-05 17:07:47 +0000198 if (!is_range) {
199 new_args.AppendArgument(current_arg);
200 continue;
201 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000202
Zachary Turner401f55d2016-10-05 17:07:47 +0000203 auto start_bp = BreakpointID::ParseCanonicalReference(range_from);
204 auto end_bp = BreakpointID::ParseCanonicalReference(range_to);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000205
Zachary Turner401f55d2016-10-05 17:07:47 +0000206 if (!start_bp.hasValue() ||
207 !target->GetBreakpointByID(start_bp->GetBreakpointID())) {
208 new_args.Clear();
209 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
210 range_from.str().c_str());
211 result.SetStatus(eReturnStatusFailed);
212 return;
213 }
214
215 if (!end_bp.hasValue() ||
216 !target->GetBreakpointByID(end_bp->GetBreakpointID())) {
217 new_args.Clear();
218 result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
219 range_to.str().c_str());
220 result.SetStatus(eReturnStatusFailed);
221 return;
222 }
223 break_id_t start_bp_id = start_bp->GetBreakpointID();
224 break_id_t start_loc_id = start_bp->GetLocationID();
225 break_id_t end_bp_id = end_bp->GetBreakpointID();
226 break_id_t end_loc_id = end_bp->GetLocationID();
Zachary Turner0d4f23c2016-10-05 18:40:51 +0000227 if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
228 (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
Zachary Turner401f55d2016-10-05 17:07:47 +0000229 ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
230 (end_loc_id == LLDB_INVALID_BREAK_ID))) {
231 new_args.Clear();
232 result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
233 "both ends of range must specify"
234 " a breakpoint location, or neither can "
235 "specify a breakpoint location.\n");
236 result.SetStatus(eReturnStatusFailed);
237 return;
238 }
239
240 // We have valid range starting & ending breakpoint IDs. Go through all
241 // the breakpoints in the target and find all the breakpoints that fit
242 // into this range, and add them to new_args.
243
244 // Next check to see if we have location id's. If so, make sure the
245 // start_bp_id and end_bp_id are for the same breakpoint; otherwise we
246 // have an illegal range: breakpoint id ranges that specify bp locations
247 // are NOT allowed to cross major bp id numbers.
248
249 if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
250 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
251 if (start_bp_id != end_bp_id) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000252 new_args.Clear();
Zachary Turner401f55d2016-10-05 17:07:47 +0000253 result.AppendErrorWithFormat(
254 "Invalid range: Ranges that specify particular breakpoint "
255 "locations"
256 " must be within the same major breakpoint; you specified two"
257 " different major breakpoints, %d and %d.\n",
258 start_bp_id, end_bp_id);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000259 result.SetStatus(eReturnStatusFailed);
260 return;
261 }
Zachary Turner401f55d2016-10-05 17:07:47 +0000262 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000263
Zachary Turner401f55d2016-10-05 17:07:47 +0000264 const BreakpointList &breakpoints = target->GetBreakpointList();
265 const size_t num_breakpoints = breakpoints.GetSize();
266 for (size_t j = 0; j < num_breakpoints; ++j) {
267 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
268 break_id_t cur_bp_id = breakpoint->GetID();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000269
Zachary Turner401f55d2016-10-05 17:07:47 +0000270 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
271 continue;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000272
Zachary Turner401f55d2016-10-05 17:07:47 +0000273 const size_t num_locations = breakpoint->GetNumLocations();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000274
Zachary Turner401f55d2016-10-05 17:07:47 +0000275 if ((cur_bp_id == start_bp_id) &&
276 (start_loc_id != LLDB_INVALID_BREAK_ID)) {
277 for (size_t k = 0; k < num_locations; ++k) {
278 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
279 if ((bp_loc->GetID() >= start_loc_id) &&
280 (bp_loc->GetID() <= end_loc_id)) {
281 StreamString canonical_id_str;
282 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
283 bp_loc->GetID());
284 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000285 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000286 }
Zachary Turner401f55d2016-10-05 17:07:47 +0000287 } else if ((cur_bp_id == end_bp_id) &&
288 (end_loc_id != LLDB_INVALID_BREAK_ID)) {
289 for (size_t k = 0; k < num_locations; ++k) {
290 BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
291 if (bp_loc->GetID() <= end_loc_id) {
292 StreamString canonical_id_str;
293 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
294 bp_loc->GetID());
295 new_args.AppendArgument(canonical_id_str.GetString());
296 }
297 }
298 } else {
299 StreamString canonical_id_str;
300 BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
301 LLDB_INVALID_BREAK_ID);
302 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000303 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000304 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000305 }
Jim Ingham5e09c8c2014-12-16 23:40:14 +0000306
Kate Stoneb9c1b512016-09-06 20:57:50 +0000307 // Okay, now see if we found any names, and if we did, add them:
308 if (target && names_found.size()) {
309 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
310 for (std::string name : names_found) {
311 if (bkpt_sp->MatchesName(name.c_str())) {
312 StreamString canonical_id_str;
313 BreakpointID::GetCanonicalReference(
314 &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
Zachary Turnerecbb0bb2016-09-19 17:54:06 +0000315 new_args.AppendArgument(canonical_id_str.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000316 }
317 }
318 }
319 }
320
321 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000322}
323
Zachary Turner401f55d2016-10-05 17:07:47 +0000324std::pair<llvm::StringRef, llvm::StringRef>
325BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {
326 for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {
327 size_t idx = in_string.find(specifier_str);
328 if (idx == llvm::StringRef::npos)
329 continue;
330 llvm::StringRef right1 = in_string.drop_front(idx);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000331
Zachary Turner401f55d2016-10-05 17:07:47 +0000332 llvm::StringRef from = in_string.take_front(idx);
333 llvm::StringRef to = right1.drop_front(specifier_str.size());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000334
Zachary Turner401f55d2016-10-05 17:07:47 +0000335 if (BreakpointID::IsValidIDExpression(from) &&
336 BreakpointID::IsValidIDExpression(to)) {
337 return std::make_pair(from, to);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338 }
339 }
340
Zachary Turner401f55d2016-10-05 17:07:47 +0000341 return std::pair<llvm::StringRef, llvm::StringRef>();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000342}