180814287SRaphael Isemann //===-- BreakpointIDList.cpp ----------------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner
9b842f2ecSJim Ingham #include "lldb/lldb-enumerations.h"
1030fdc8d8SChris Lattner #include "lldb/Breakpoint/BreakpointIDList.h"
1130fdc8d8SChris Lattner
1230fdc8d8SChris Lattner #include "lldb/Breakpoint/Breakpoint.h"
1330fdc8d8SChris Lattner #include "lldb/Breakpoint/BreakpointLocation.h"
14b9c1b51eSKate Stone #include "lldb/Interpreter/CommandReturnObject.h"
1530fdc8d8SChris Lattner #include "lldb/Target/Target.h"
16145d95c9SPavel Labath #include "lldb/Utility/Args.h"
1730fdc8d8SChris Lattner
1830fdc8d8SChris Lattner using namespace lldb;
1930fdc8d8SChris Lattner using namespace lldb_private;
2030fdc8d8SChris Lattner
2130fdc8d8SChris Lattner // class BreakpointIDList
2230fdc8d8SChris Lattner
BreakpointIDList()23b9c1b51eSKate Stone BreakpointIDList::BreakpointIDList()
24b9c1b51eSKate Stone : m_invalid_id(LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID) {}
2530fdc8d8SChris Lattner
2616fd7511SEugene Zelenko BreakpointIDList::~BreakpointIDList() = default;
2730fdc8d8SChris Lattner
GetSize() const28db308774SJim Ingham size_t BreakpointIDList::GetSize() const { return m_breakpoint_ids.size(); }
29b9c1b51eSKate Stone
30db308774SJim Ingham const BreakpointID &
GetBreakpointIDAtIndex(size_t index) const31db308774SJim Ingham BreakpointIDList::GetBreakpointIDAtIndex(size_t index) const {
32b9c1b51eSKate Stone return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]
33b9c1b51eSKate Stone : m_invalid_id);
3430fdc8d8SChris Lattner }
3530fdc8d8SChris Lattner
RemoveBreakpointIDAtIndex(size_t index)36b9c1b51eSKate Stone bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {
37c982c768SGreg Clayton if (index >= m_breakpoint_ids.size())
38c982c768SGreg Clayton return false;
3930fdc8d8SChris Lattner
40c982c768SGreg Clayton m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);
41c982c768SGreg Clayton return true;
4230fdc8d8SChris Lattner }
4330fdc8d8SChris Lattner
Clear()44b9c1b51eSKate Stone void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }
4530fdc8d8SChris Lattner
AddBreakpointID(BreakpointID bp_id)46b9c1b51eSKate Stone bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {
4730fdc8d8SChris Lattner m_breakpoint_ids.push_back(bp_id);
4830fdc8d8SChris Lattner
49b9c1b51eSKate Stone return true; // We don't do any verification in this function, so always
50b9c1b51eSKate Stone // return true.
5130fdc8d8SChris Lattner }
5230fdc8d8SChris Lattner
AddBreakpointID(const char * bp_id_str)53b9c1b51eSKate Stone bool BreakpointIDList::AddBreakpointID(const char *bp_id_str) {
54401f55dfSZachary Turner auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
555413bf1bSKazu Hirata if (!bp_id)
56401f55dfSZachary Turner return false;
5730fdc8d8SChris Lattner
58401f55dfSZachary Turner m_breakpoint_ids.push_back(*bp_id);
59401f55dfSZachary Turner return true;
6030fdc8d8SChris Lattner }
6130fdc8d8SChris Lattner
FindBreakpointID(BreakpointID & bp_id,size_t * position) const62db308774SJim Ingham bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id,
63db308774SJim Ingham size_t *position) const {
64b9c1b51eSKate Stone for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) {
6530fdc8d8SChris Lattner BreakpointID tmp_id = m_breakpoint_ids[i];
66b9c1b51eSKate Stone if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() &&
67b9c1b51eSKate Stone tmp_id.GetLocationID() == bp_id.GetLocationID()) {
6830fdc8d8SChris Lattner *position = i;
6930fdc8d8SChris Lattner return true;
7030fdc8d8SChris Lattner }
7130fdc8d8SChris Lattner }
7230fdc8d8SChris Lattner
7330fdc8d8SChris Lattner return false;
7430fdc8d8SChris Lattner }
7530fdc8d8SChris Lattner
FindBreakpointID(const char * bp_id_str,size_t * position) const76b9c1b51eSKate Stone bool BreakpointIDList::FindBreakpointID(const char *bp_id_str,
77db308774SJim Ingham size_t *position) const {
78401f55dfSZachary Turner auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
795413bf1bSKazu Hirata if (!bp_id)
8030fdc8d8SChris Lattner return false;
81401f55dfSZachary Turner
82401f55dfSZachary Turner return FindBreakpointID(*bp_id, position);
8330fdc8d8SChris Lattner }
8430fdc8d8SChris Lattner
InsertStringArray(llvm::ArrayRef<const char * > string_array,CommandReturnObject & result)8516662f3cSPavel Labath void BreakpointIDList::InsertStringArray(
8616662f3cSPavel Labath llvm::ArrayRef<const char *> string_array, CommandReturnObject &result) {
8716662f3cSPavel Labath if(string_array.empty())
8830fdc8d8SChris Lattner return;
8930fdc8d8SChris Lattner
9016662f3cSPavel Labath for (const char *str : string_array) {
9116662f3cSPavel Labath auto bp_id = BreakpointID::ParseCanonicalReference(str);
925413bf1bSKazu Hirata if (bp_id)
93401f55dfSZachary Turner m_breakpoint_ids.push_back(*bp_id);
9430fdc8d8SChris Lattner }
9530fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishNoResult);
9630fdc8d8SChris Lattner }
9730fdc8d8SChris Lattner
98b9c1b51eSKate Stone // This function takes OLD_ARGS, which is usually the result of breaking the
99b9c1b51eSKate Stone // command string arguments into
100b9c1b51eSKate Stone // an array of space-separated strings, and searches through the arguments for
101b9c1b51eSKate Stone // any breakpoint ID range specifiers.
102b9c1b51eSKate Stone // Any string in the array that is not part of an ID range specifier is copied
103b9c1b51eSKate Stone // directly into NEW_ARGS. If any
104b9c1b51eSKate Stone // ID range specifiers are found, the range is interpreted and a list of
105b9c1b51eSKate Stone // canonical breakpoint IDs corresponding to
106b9c1b51eSKate Stone // all the current breakpoints and locations in the range are added to
107b9c1b51eSKate Stone // NEW_ARGS. When this function is done,
108b9c1b51eSKate Stone // NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
109b9c1b51eSKate Stone // by the members of the range.
11030fdc8d8SChris Lattner
FindAndReplaceIDRanges(Args & old_args,Target * target,bool allow_locations,BreakpointName::Permissions::PermissionKinds purpose,CommandReturnObject & result,Args & new_args)111b9c1b51eSKate Stone void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
1125e09c8c3SJim Ingham bool allow_locations,
113b842f2ecSJim Ingham BreakpointName::Permissions
114b842f2ecSJim Ingham ::PermissionKinds purpose,
1155e09c8c3SJim Ingham CommandReturnObject &result,
116b9c1b51eSKate Stone Args &new_args) {
117401f55dfSZachary Turner llvm::StringRef range_from;
118401f55dfSZachary Turner llvm::StringRef range_to;
119401f55dfSZachary Turner llvm::StringRef current_arg;
1205e09c8c3SJim Ingham std::set<std::string> names_found;
12130fdc8d8SChris Lattner
122d6a24757SZachary Turner for (size_t i = 0; i < old_args.size(); ++i) {
12330fdc8d8SChris Lattner bool is_range = false;
1245e09c8c3SJim Ingham
1250d9a201eSRaphael Isemann current_arg = old_args[i].ref();
126401f55dfSZachary Turner if (!allow_locations && current_arg.contains('.')) {
127b9c1b51eSKate Stone result.AppendErrorWithFormat(
128401f55dfSZachary Turner "Breakpoint locations not allowed, saw location: %s.",
129401f55dfSZachary Turner current_arg.str().c_str());
1305e09c8c3SJim Ingham new_args.Clear();
1315e09c8c3SJim Ingham return;
1325e09c8c3SJim Ingham }
13330fdc8d8SChris Lattner
13497206d57SZachary Turner Status error;
1355e09c8c3SJim Ingham
136401f55dfSZachary Turner std::tie(range_from, range_to) =
137401f55dfSZachary Turner BreakpointIDList::SplitIDRangeExpression(current_arg);
138401f55dfSZachary Turner if (!range_from.empty() && !range_to.empty()) {
13930fdc8d8SChris Lattner is_range = true;
140401f55dfSZachary Turner } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
141b9c1b51eSKate Stone if (!error.Success()) {
1425e09c8c3SJim Ingham new_args.Clear();
1435e09c8c3SJim Ingham result.AppendError(error.AsCString());
1445e09c8c3SJim Ingham return;
145b9c1b51eSKate Stone } else
146adcd0268SBenjamin Kramer names_found.insert(std::string(current_arg));
147d6a24757SZachary Turner } else if ((i + 2 < old_args.size()) &&
1480d9a201eSRaphael Isemann BreakpointID::IsRangeIdentifier(old_args[i + 1].ref()) &&
149b9c1b51eSKate Stone BreakpointID::IsValidIDExpression(current_arg) &&
1500d9a201eSRaphael Isemann BreakpointID::IsValidIDExpression(old_args[i + 2].ref())) {
151401f55dfSZachary Turner range_from = current_arg;
1520d9a201eSRaphael Isemann range_to = old_args[i + 2].ref();
15330fdc8d8SChris Lattner is_range = true;
15430fdc8d8SChris Lattner i = i + 2;
155b9c1b51eSKate Stone } else {
1569068d794SCaroline Tice // See if user has specified id.*
1570d9a201eSRaphael Isemann llvm::StringRef tmp_str = old_args[i].ref();
1589068d794SCaroline Tice size_t pos = tmp_str.find('.');
159401f55dfSZachary Turner if (pos != llvm::StringRef::npos) {
160401f55dfSZachary Turner llvm::StringRef bp_id_str = tmp_str.substr(0, pos);
161401f55dfSZachary Turner if (BreakpointID::IsValidIDExpression(bp_id_str) &&
162401f55dfSZachary Turner tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) {
1639068d794SCaroline Tice
164401f55dfSZachary Turner BreakpointSP breakpoint_sp;
165401f55dfSZachary Turner auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
1665413bf1bSKazu Hirata if (bp_id)
167401f55dfSZachary Turner breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());
168b9c1b51eSKate Stone if (!breakpoint_sp) {
169eb1db1c5SJohnny Chen new_args.Clear();
170b9c1b51eSKate Stone result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
171401f55dfSZachary Turner bp_id->GetBreakpointID());
172eb1db1c5SJohnny Chen return;
173eb1db1c5SJohnny Chen }
1749068d794SCaroline Tice const size_t num_locations = breakpoint_sp->GetNumLocations();
175b9c1b51eSKate Stone for (size_t j = 0; j < num_locations; ++j) {
176b9c1b51eSKate Stone BreakpointLocation *bp_loc =
177b9c1b51eSKate Stone breakpoint_sp->GetLocationAtIndex(j).get();
1789068d794SCaroline Tice StreamString canonical_id_str;
179401f55dfSZachary Turner BreakpointID::GetCanonicalReference(
180401f55dfSZachary Turner &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());
181ecbb0bb1SZachary Turner new_args.AppendArgument(canonical_id_str.GetString());
1829068d794SCaroline Tice }
1839068d794SCaroline Tice }
1849068d794SCaroline Tice }
1859068d794SCaroline Tice }
18630fdc8d8SChris Lattner
187401f55dfSZachary Turner if (!is_range) {
188401f55dfSZachary Turner new_args.AppendArgument(current_arg);
189401f55dfSZachary Turner continue;
190401f55dfSZachary Turner }
19130fdc8d8SChris Lattner
192401f55dfSZachary Turner auto start_bp = BreakpointID::ParseCanonicalReference(range_from);
193401f55dfSZachary Turner auto end_bp = BreakpointID::ParseCanonicalReference(range_to);
19430fdc8d8SChris Lattner
195*96d1b4ddSKazu Hirata if (!start_bp ||
1963b7c3a65SKazu Hirata !target->GetBreakpointByID(start_bp->GetBreakpointID())) {
19730fdc8d8SChris Lattner new_args.Clear();
198b9c1b51eSKate Stone result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
199401f55dfSZachary Turner range_from.str().c_str());
20030fdc8d8SChris Lattner return;
20130fdc8d8SChris Lattner }
20230fdc8d8SChris Lattner
203*96d1b4ddSKazu Hirata if (!end_bp ||
2043b7c3a65SKazu Hirata !target->GetBreakpointByID(end_bp->GetBreakpointID())) {
20530fdc8d8SChris Lattner new_args.Clear();
206b9c1b51eSKate Stone result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
207401f55dfSZachary Turner range_to.str().c_str());
20830fdc8d8SChris Lattner return;
20930fdc8d8SChris Lattner }
210401f55dfSZachary Turner break_id_t start_bp_id = start_bp->GetBreakpointID();
211401f55dfSZachary Turner break_id_t start_loc_id = start_bp->GetLocationID();
212401f55dfSZachary Turner break_id_t end_bp_id = end_bp->GetBreakpointID();
213401f55dfSZachary Turner break_id_t end_loc_id = end_bp->GetLocationID();
2140d4f23c5SZachary Turner if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
2150d4f23c5SZachary Turner (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
216b9c1b51eSKate Stone ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
217b9c1b51eSKate Stone (end_loc_id == LLDB_INVALID_BREAK_ID))) {
2182bf67986SCaroline Tice new_args.Clear();
21989533764SJonas Devlieghere result.AppendError("Invalid breakpoint id range: Either "
220b9c1b51eSKate Stone "both ends of range must specify"
221b9c1b51eSKate Stone " a breakpoint location, or neither can "
2227926143fSJonas Devlieghere "specify a breakpoint location.");
2232bf67986SCaroline Tice return;
2242bf67986SCaroline Tice }
2252bf67986SCaroline Tice
226b9c1b51eSKate Stone // We have valid range starting & ending breakpoint IDs. Go through all
22705097246SAdrian Prantl // the breakpoints in the target and find all the breakpoints that fit into
22805097246SAdrian Prantl // this range, and add them to new_args.
22930fdc8d8SChris Lattner
230b9c1b51eSKate Stone // Next check to see if we have location id's. If so, make sure the
23105097246SAdrian Prantl // start_bp_id and end_bp_id are for the same breakpoint; otherwise we have
23205097246SAdrian Prantl // an illegal range: breakpoint id ranges that specify bp locations are NOT
23305097246SAdrian Prantl // allowed to cross major bp id numbers.
2349068d794SCaroline Tice
235b9c1b51eSKate Stone if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
236b9c1b51eSKate Stone (end_loc_id != LLDB_INVALID_BREAK_ID)) {
237b9c1b51eSKate Stone if (start_bp_id != end_bp_id) {
2389068d794SCaroline Tice new_args.Clear();
239b9c1b51eSKate Stone result.AppendErrorWithFormat(
240b9c1b51eSKate Stone "Invalid range: Ranges that specify particular breakpoint "
241b9c1b51eSKate Stone "locations"
2429068d794SCaroline Tice " must be within the same major breakpoint; you specified two"
2439068d794SCaroline Tice " different major breakpoints, %d and %d.\n",
2449068d794SCaroline Tice start_bp_id, end_bp_id);
2459068d794SCaroline Tice return;
2469068d794SCaroline Tice }
2479068d794SCaroline Tice }
2489068d794SCaroline Tice
24930fdc8d8SChris Lattner const BreakpointList &breakpoints = target->GetBreakpointList();
250c982c768SGreg Clayton const size_t num_breakpoints = breakpoints.GetSize();
251b9c1b51eSKate Stone for (size_t j = 0; j < num_breakpoints; ++j) {
2529fed0d85SGreg Clayton Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
25330fdc8d8SChris Lattner break_id_t cur_bp_id = breakpoint->GetID();
25430fdc8d8SChris Lattner
25530fdc8d8SChris Lattner if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
25630fdc8d8SChris Lattner continue;
25730fdc8d8SChris Lattner
258c982c768SGreg Clayton const size_t num_locations = breakpoint->GetNumLocations();
25930fdc8d8SChris Lattner
260b9c1b51eSKate Stone if ((cur_bp_id == start_bp_id) &&
261b9c1b51eSKate Stone (start_loc_id != LLDB_INVALID_BREAK_ID)) {
262b9c1b51eSKate Stone for (size_t k = 0; k < num_locations; ++k) {
263401f55dfSZachary Turner BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
264b9c1b51eSKate Stone if ((bp_loc->GetID() >= start_loc_id) &&
265b9c1b51eSKate Stone (bp_loc->GetID() <= end_loc_id)) {
26630fdc8d8SChris Lattner StreamString canonical_id_str;
267b9c1b51eSKate Stone BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
268b9c1b51eSKate Stone bp_loc->GetID());
269ecbb0bb1SZachary Turner new_args.AppendArgument(canonical_id_str.GetString());
27030fdc8d8SChris Lattner }
27130fdc8d8SChris Lattner }
272b9c1b51eSKate Stone } else if ((cur_bp_id == end_bp_id) &&
273b9c1b51eSKate Stone (end_loc_id != LLDB_INVALID_BREAK_ID)) {
274b9c1b51eSKate Stone for (size_t k = 0; k < num_locations; ++k) {
275401f55dfSZachary Turner BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
276b9c1b51eSKate Stone if (bp_loc->GetID() <= end_loc_id) {
27730fdc8d8SChris Lattner StreamString canonical_id_str;
278b9c1b51eSKate Stone BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
279b9c1b51eSKate Stone bp_loc->GetID());
280ecbb0bb1SZachary Turner new_args.AppendArgument(canonical_id_str.GetString());
28130fdc8d8SChris Lattner }
28230fdc8d8SChris Lattner }
283b9c1b51eSKate Stone } else {
28430fdc8d8SChris Lattner StreamString canonical_id_str;
285b9c1b51eSKate Stone BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
286b9c1b51eSKate Stone LLDB_INVALID_BREAK_ID);
287ecbb0bb1SZachary Turner new_args.AppendArgument(canonical_id_str.GetString());
28830fdc8d8SChris Lattner }
28930fdc8d8SChris Lattner }
29030fdc8d8SChris Lattner }
29130fdc8d8SChris Lattner
2925e09c8c3SJim Ingham // Okay, now see if we found any names, and if we did, add them:
293b842f2ecSJim Ingham if (target && !names_found.empty()) {
294b842f2ecSJim Ingham Status error;
295b842f2ecSJim Ingham // Remove any names that aren't visible for this purpose:
296b842f2ecSJim Ingham auto iter = names_found.begin();
297b842f2ecSJim Ingham while (iter != names_found.end()) {
298b842f2ecSJim Ingham BreakpointName *bp_name = target->FindBreakpointName(ConstString(*iter),
299b842f2ecSJim Ingham true,
300b842f2ecSJim Ingham error);
301b842f2ecSJim Ingham if (bp_name && !bp_name->GetPermission(purpose))
302b842f2ecSJim Ingham iter = names_found.erase(iter);
303b842f2ecSJim Ingham else
304b842f2ecSJim Ingham iter++;
305b842f2ecSJim Ingham }
306b842f2ecSJim Ingham
307b842f2ecSJim Ingham if (!names_found.empty()) {
308b9c1b51eSKate Stone for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
309b9c1b51eSKate Stone for (std::string name : names_found) {
310b9c1b51eSKate Stone if (bkpt_sp->MatchesName(name.c_str())) {
3115e09c8c3SJim Ingham StreamString canonical_id_str;
312b9c1b51eSKate Stone BreakpointID::GetCanonicalReference(
313b9c1b51eSKate Stone &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
314ecbb0bb1SZachary Turner new_args.AppendArgument(canonical_id_str.GetString());
3155e09c8c3SJim Ingham }
3165e09c8c3SJim Ingham }
3175e09c8c3SJim Ingham }
3185e09c8c3SJim Ingham }
319b842f2ecSJim Ingham }
3205e09c8c3SJim Ingham
32130fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishNoResult);
32230fdc8d8SChris Lattner }
32330fdc8d8SChris Lattner
324401f55dfSZachary Turner std::pair<llvm::StringRef, llvm::StringRef>
SplitIDRangeExpression(llvm::StringRef in_string)325401f55dfSZachary Turner BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {
326401f55dfSZachary Turner for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {
327401f55dfSZachary Turner size_t idx = in_string.find(specifier_str);
328401f55dfSZachary Turner if (idx == llvm::StringRef::npos)
329401f55dfSZachary Turner continue;
330401f55dfSZachary Turner llvm::StringRef right1 = in_string.drop_front(idx);
33130fdc8d8SChris Lattner
332401f55dfSZachary Turner llvm::StringRef from = in_string.take_front(idx);
333401f55dfSZachary Turner llvm::StringRef to = right1.drop_front(specifier_str.size());
33430fdc8d8SChris Lattner
335401f55dfSZachary Turner if (BreakpointID::IsValidIDExpression(from) &&
336401f55dfSZachary Turner BreakpointID::IsValidIDExpression(to)) {
337401f55dfSZachary Turner return std::make_pair(from, to);
33830fdc8d8SChris Lattner }
33930fdc8d8SChris Lattner }
34030fdc8d8SChris Lattner
341401f55dfSZachary Turner return std::pair<llvm::StringRef, llvm::StringRef>();
34230fdc8d8SChris Lattner }
343