Path: blob/main/contrib/llvm-project/lldb/source/Breakpoint/BreakpointIDList.cpp
39587 views
//===-- BreakpointIDList.cpp ----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/lldb-enumerations.h"9#include "lldb/Breakpoint/BreakpointIDList.h"1011#include "lldb/Breakpoint/Breakpoint.h"12#include "lldb/Breakpoint/BreakpointLocation.h"13#include "lldb/Target/Target.h"14#include "lldb/Utility/Args.h"15#include "lldb/Utility/StreamString.h"1617#include "llvm/ADT/STLExtras.h"18#include "llvm/ADT/StringRef.h"1920using namespace lldb;21using namespace lldb_private;2223// class BreakpointIDList2425BreakpointIDList::BreakpointIDList() : m_breakpoint_ids() {}2627BreakpointIDList::~BreakpointIDList() = default;2829size_t BreakpointIDList::GetSize() const { return m_breakpoint_ids.size(); }3031BreakpointID BreakpointIDList::GetBreakpointIDAtIndex(size_t index) const {32return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]33: BreakpointID());34}3536bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {37if (index >= m_breakpoint_ids.size())38return false;3940m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);41return true;42}4344void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }4546bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {47m_breakpoint_ids.push_back(bp_id);4849return true; // We don't do any verification in this function, so always50// return true.51}5253bool BreakpointIDList::Contains(BreakpointID bp_id) const {54return llvm::is_contained(m_breakpoint_ids, bp_id);55}5657// This function takes OLD_ARGS, which is usually the result of breaking the58// command string arguments into59// an array of space-separated strings, and searches through the arguments for60// any breakpoint ID range specifiers.61// Any string in the array that is not part of an ID range specifier is copied62// directly into NEW_ARGS. If any63// ID range specifiers are found, the range is interpreted and a list of64// canonical breakpoint IDs corresponding to65// all the current breakpoints and locations in the range are added to66// NEW_ARGS. When this function is done,67// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced68// by the members of the range.6970llvm::Error BreakpointIDList::FindAndReplaceIDRanges(71Args &old_args, Target *target, bool allow_locations,72BreakpointName::Permissions ::PermissionKinds purpose, Args &new_args) {73llvm::StringRef range_from;74llvm::StringRef range_to;75llvm::StringRef current_arg;76std::set<std::string> names_found;7778for (size_t i = 0; i < old_args.size(); ++i) {79bool is_range = false;8081current_arg = old_args[i].ref();82if (!allow_locations && current_arg.contains('.')) {83new_args.Clear();84return llvm::createStringError(85llvm::inconvertibleErrorCode(),86"Breakpoint locations not allowed, saw location: %s.",87current_arg.str().c_str());88}8990Status error;9192std::tie(range_from, range_to) =93BreakpointIDList::SplitIDRangeExpression(current_arg);94if (!range_from.empty() && !range_to.empty()) {95is_range = true;96} else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {97if (!error.Success()) {98new_args.Clear();99return llvm::createStringError(llvm::inconvertibleErrorCode(),100error.AsCString());101} else102names_found.insert(std::string(current_arg));103} else if ((i + 2 < old_args.size()) &&104BreakpointID::IsRangeIdentifier(old_args[i + 1].ref()) &&105BreakpointID::IsValidIDExpression(current_arg) &&106BreakpointID::IsValidIDExpression(old_args[i + 2].ref())) {107range_from = current_arg;108range_to = old_args[i + 2].ref();109is_range = true;110i = i + 2;111} else {112// See if user has specified id.*113llvm::StringRef tmp_str = old_args[i].ref();114auto [prefix, suffix] = tmp_str.split('.');115if (suffix == "*" && BreakpointID::IsValidIDExpression(prefix)) {116117BreakpointSP breakpoint_sp;118auto bp_id = BreakpointID::ParseCanonicalReference(prefix);119if (bp_id)120breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());121if (!breakpoint_sp) {122new_args.Clear();123return llvm::createStringError(llvm::inconvertibleErrorCode(),124"'%d' is not a valid breakpoint ID.\n",125bp_id->GetBreakpointID());126}127const size_t num_locations = breakpoint_sp->GetNumLocations();128for (size_t j = 0; j < num_locations; ++j) {129BreakpointLocation *bp_loc =130breakpoint_sp->GetLocationAtIndex(j).get();131StreamString canonical_id_str;132BreakpointID::GetCanonicalReference(133&canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());134new_args.AppendArgument(canonical_id_str.GetString());135}136}137}138139if (!is_range) {140new_args.AppendArgument(current_arg);141continue;142}143144auto start_bp = BreakpointID::ParseCanonicalReference(range_from);145auto end_bp = BreakpointID::ParseCanonicalReference(range_to);146147if (!start_bp ||148!target->GetBreakpointByID(start_bp->GetBreakpointID())) {149new_args.Clear();150return llvm::createStringError(llvm::inconvertibleErrorCode(),151"'%s' is not a valid breakpoint ID.\n",152range_from.str().c_str());153}154155if (!end_bp ||156!target->GetBreakpointByID(end_bp->GetBreakpointID())) {157new_args.Clear();158return llvm::createStringError(llvm::inconvertibleErrorCode(),159"'%s' is not a valid breakpoint ID.\n",160range_to.str().c_str());161}162break_id_t start_bp_id = start_bp->GetBreakpointID();163break_id_t start_loc_id = start_bp->GetLocationID();164break_id_t end_bp_id = end_bp->GetBreakpointID();165break_id_t end_loc_id = end_bp->GetLocationID();166if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&167(end_loc_id != LLDB_INVALID_BREAK_ID)) ||168((start_loc_id != LLDB_INVALID_BREAK_ID) &&169(end_loc_id == LLDB_INVALID_BREAK_ID))) {170new_args.Clear();171return llvm::createStringError(llvm::inconvertibleErrorCode(),172"Invalid breakpoint id range: Either "173"both ends of range must specify"174" a breakpoint location, or neither can "175"specify a breakpoint location.");176}177178// We have valid range starting & ending breakpoint IDs. Go through all179// the breakpoints in the target and find all the breakpoints that fit into180// this range, and add them to new_args.181182// Next check to see if we have location id's. If so, make sure the183// start_bp_id and end_bp_id are for the same breakpoint; otherwise we have184// an illegal range: breakpoint id ranges that specify bp locations are NOT185// allowed to cross major bp id numbers.186187if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||188(end_loc_id != LLDB_INVALID_BREAK_ID)) {189if (start_bp_id != end_bp_id) {190new_args.Clear();191return llvm::createStringError(192llvm::inconvertibleErrorCode(),193"Invalid range: Ranges that specify particular breakpoint "194"locations"195" must be within the same major breakpoint; you specified two"196" different major breakpoints, %d and %d.\n",197start_bp_id, end_bp_id);198}199}200201const BreakpointList &breakpoints = target->GetBreakpointList();202const size_t num_breakpoints = breakpoints.GetSize();203for (size_t j = 0; j < num_breakpoints; ++j) {204Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();205break_id_t cur_bp_id = breakpoint->GetID();206207if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))208continue;209210const size_t num_locations = breakpoint->GetNumLocations();211212if ((cur_bp_id == start_bp_id) &&213(start_loc_id != LLDB_INVALID_BREAK_ID)) {214for (size_t k = 0; k < num_locations; ++k) {215BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();216if ((bp_loc->GetID() >= start_loc_id) &&217(bp_loc->GetID() <= end_loc_id)) {218StreamString canonical_id_str;219BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,220bp_loc->GetID());221new_args.AppendArgument(canonical_id_str.GetString());222}223}224} else if ((cur_bp_id == end_bp_id) &&225(end_loc_id != LLDB_INVALID_BREAK_ID)) {226for (size_t k = 0; k < num_locations; ++k) {227BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();228if (bp_loc->GetID() <= end_loc_id) {229StreamString canonical_id_str;230BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,231bp_loc->GetID());232new_args.AppendArgument(canonical_id_str.GetString());233}234}235} else {236StreamString canonical_id_str;237BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,238LLDB_INVALID_BREAK_ID);239new_args.AppendArgument(canonical_id_str.GetString());240}241}242}243244// Okay, now see if we found any names, and if we did, add them:245if (target && !names_found.empty()) {246Status error;247// Remove any names that aren't visible for this purpose:248auto iter = names_found.begin();249while (iter != names_found.end()) {250BreakpointName *bp_name = target->FindBreakpointName(ConstString(*iter),251true,252error);253if (bp_name && !bp_name->GetPermission(purpose))254iter = names_found.erase(iter);255else256iter++;257}258259if (!names_found.empty()) {260for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {261for (const std::string &name : names_found) {262if (bkpt_sp->MatchesName(name.c_str())) {263StreamString canonical_id_str;264BreakpointID::GetCanonicalReference(265&canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);266new_args.AppendArgument(canonical_id_str.GetString());267}268}269}270}271}272return llvm::Error::success();273}274275std::pair<llvm::StringRef, llvm::StringRef>276BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {277for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {278size_t idx = in_string.find(specifier_str);279if (idx == llvm::StringRef::npos)280continue;281llvm::StringRef right1 = in_string.drop_front(idx);282283llvm::StringRef from = in_string.take_front(idx);284llvm::StringRef to = right1.drop_front(specifier_str.size());285286if (BreakpointID::IsValidIDExpression(from) &&287BreakpointID::IsValidIDExpression(to)) {288return std::make_pair(from, to);289}290}291292return std::pair<llvm::StringRef, llvm::StringRef>();293}294295296