340 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			340 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| // C Includes
 | |
| // C++ Includes
 | |
| // Other libraries and framework includes
 | |
| // Project includes
 | |
| #include "lldb/Breakpoint/BreakpointIDList.h"
 | |
| 
 | |
| #include "lldb/Breakpoint/Breakpoint.h"
 | |
| #include "lldb/Breakpoint/BreakpointLocation.h"
 | |
| #include "lldb/Interpreter/Args.h"
 | |
| #include "lldb/Interpreter/CommandReturnObject.h"
 | |
| #include "lldb/Target/Target.h"
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // class BreakpointIDList
 | |
| //----------------------------------------------------------------------
 | |
| 
 | |
| BreakpointIDList::BreakpointIDList()
 | |
|     : m_invalid_id(LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID) {}
 | |
| 
 | |
| BreakpointIDList::~BreakpointIDList() = default;
 | |
| 
 | |
| size_t BreakpointIDList::GetSize() const { return m_breakpoint_ids.size(); }
 | |
| 
 | |
| const BreakpointID &
 | |
| BreakpointIDList::GetBreakpointIDAtIndex(size_t index) const {
 | |
|   return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]
 | |
|                                             : m_invalid_id);
 | |
| }
 | |
| 
 | |
| bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {
 | |
|   if (index >= m_breakpoint_ids.size())
 | |
|     return false;
 | |
| 
 | |
|   m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }
 | |
| 
 | |
| bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {
 | |
|   m_breakpoint_ids.push_back(bp_id);
 | |
| 
 | |
|   return true; // We don't do any verification in this function, so always
 | |
|                // return true.
 | |
| }
 | |
| 
 | |
| bool BreakpointIDList::AddBreakpointID(const char *bp_id_str) {
 | |
|   auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
 | |
|   if (!bp_id.hasValue())
 | |
|     return false;
 | |
| 
 | |
|   m_breakpoint_ids.push_back(*bp_id);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id,
 | |
|                                         size_t *position) const {
 | |
|   for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) {
 | |
|     BreakpointID tmp_id = m_breakpoint_ids[i];
 | |
|     if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() &&
 | |
|         tmp_id.GetLocationID() == bp_id.GetLocationID()) {
 | |
|       *position = i;
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool BreakpointIDList::FindBreakpointID(const char *bp_id_str,
 | |
|                                         size_t *position) const {
 | |
|   auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
 | |
|   if (!bp_id.hasValue())
 | |
|     return false;
 | |
| 
 | |
|   return FindBreakpointID(*bp_id, position);
 | |
| }
 | |
| 
 | |
| void BreakpointIDList::InsertStringArray(const char **string_array,
 | |
|                                          size_t array_size,
 | |
|                                          CommandReturnObject &result) {
 | |
|   if (string_array == nullptr)
 | |
|     return;
 | |
| 
 | |
|   for (uint32_t i = 0; i < array_size; ++i) {
 | |
|     auto bp_id = BreakpointID::ParseCanonicalReference(string_array[i]);
 | |
|     if (bp_id.hasValue())
 | |
|       m_breakpoint_ids.push_back(*bp_id);
 | |
|   }
 | |
|   result.SetStatus(eReturnStatusSuccessFinishNoResult);
 | |
| }
 | |
| 
 | |
| //  This function takes OLD_ARGS, which is usually the result of breaking the
 | |
| //  command string arguments into
 | |
| //  an array of space-separated strings, and searches through the arguments for
 | |
| //  any breakpoint ID range specifiers.
 | |
| //  Any string in the array that is not part of an ID range specifier is copied
 | |
| //  directly into NEW_ARGS.  If any
 | |
| //  ID range specifiers are found, the range is interpreted and a list of
 | |
| //  canonical breakpoint IDs corresponding to
 | |
| //  all the current breakpoints and locations in the range are added to
 | |
| //  NEW_ARGS.  When this function is done,
 | |
| //  NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
 | |
| //  by the members of the range.
 | |
| 
 | |
| void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
 | |
|                                               bool allow_locations,
 | |
|                                               CommandReturnObject &result,
 | |
|                                               Args &new_args) {
 | |
|   llvm::StringRef range_from;
 | |
|   llvm::StringRef range_to;
 | |
|   llvm::StringRef current_arg;
 | |
|   std::set<std::string> names_found;
 | |
| 
 | |
|   for (size_t i = 0; i < old_args.size(); ++i) {
 | |
|     bool is_range = false;
 | |
| 
 | |
|     current_arg = old_args[i].ref;
 | |
|     if (!allow_locations && current_arg.contains('.')) {
 | |
|       result.AppendErrorWithFormat(
 | |
|           "Breakpoint locations not allowed, saw location: %s.",
 | |
|           current_arg.str().c_str());
 | |
|       new_args.Clear();
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     llvm::StringRef range_expr;
 | |
|     Status error;
 | |
| 
 | |
|     std::tie(range_from, range_to) =
 | |
|         BreakpointIDList::SplitIDRangeExpression(current_arg);
 | |
|     if (!range_from.empty() && !range_to.empty()) {
 | |
|       is_range = true;
 | |
|     } else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
 | |
|       if (!error.Success()) {
 | |
|         new_args.Clear();
 | |
|         result.AppendError(error.AsCString());
 | |
|         result.SetStatus(eReturnStatusFailed);
 | |
|         return;
 | |
|       } else
 | |
|         names_found.insert(current_arg);
 | |
|     } else if ((i + 2 < old_args.size()) &&
 | |
|                BreakpointID::IsRangeIdentifier(old_args[i + 1].ref) &&
 | |
|                BreakpointID::IsValidIDExpression(current_arg) &&
 | |
|                BreakpointID::IsValidIDExpression(old_args[i + 2].ref)) {
 | |
|       range_from = current_arg;
 | |
|       range_to = old_args[i + 2].ref;
 | |
|       is_range = true;
 | |
|       i = i + 2;
 | |
|     } else {
 | |
|       // See if user has specified id.*
 | |
|       llvm::StringRef tmp_str = old_args[i].ref;
 | |
|       size_t pos = tmp_str.find('.');
 | |
|       if (pos != llvm::StringRef::npos) {
 | |
|         llvm::StringRef bp_id_str = tmp_str.substr(0, pos);
 | |
|         if (BreakpointID::IsValidIDExpression(bp_id_str) &&
 | |
|             tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) {
 | |
| 
 | |
|           BreakpointSP breakpoint_sp;
 | |
|           auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
 | |
|           if (bp_id.hasValue())
 | |
|             breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());
 | |
|           if (!breakpoint_sp) {
 | |
|             new_args.Clear();
 | |
|             result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
 | |
|                                          bp_id->GetBreakpointID());
 | |
|             result.SetStatus(eReturnStatusFailed);
 | |
|             return;
 | |
|           }
 | |
|           const size_t num_locations = breakpoint_sp->GetNumLocations();
 | |
|           for (size_t j = 0; j < num_locations; ++j) {
 | |
|             BreakpointLocation *bp_loc =
 | |
|                 breakpoint_sp->GetLocationAtIndex(j).get();
 | |
|             StreamString canonical_id_str;
 | |
|             BreakpointID::GetCanonicalReference(
 | |
|                 &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());
 | |
|             new_args.AppendArgument(canonical_id_str.GetString());
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (!is_range) {
 | |
|       new_args.AppendArgument(current_arg);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     auto start_bp = BreakpointID::ParseCanonicalReference(range_from);
 | |
|     auto end_bp = BreakpointID::ParseCanonicalReference(range_to);
 | |
| 
 | |
|     if (!start_bp.hasValue() ||
 | |
|         !target->GetBreakpointByID(start_bp->GetBreakpointID())) {
 | |
|       new_args.Clear();
 | |
|       result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
 | |
|                                    range_from.str().c_str());
 | |
|       result.SetStatus(eReturnStatusFailed);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (!end_bp.hasValue() ||
 | |
|         !target->GetBreakpointByID(end_bp->GetBreakpointID())) {
 | |
|       new_args.Clear();
 | |
|       result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
 | |
|                                    range_to.str().c_str());
 | |
|       result.SetStatus(eReturnStatusFailed);
 | |
|       return;
 | |
|     }
 | |
|     break_id_t start_bp_id = start_bp->GetBreakpointID();
 | |
|     break_id_t start_loc_id = start_bp->GetLocationID();
 | |
|     break_id_t end_bp_id = end_bp->GetBreakpointID();
 | |
|     break_id_t end_loc_id = end_bp->GetLocationID();
 | |
|     if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
 | |
|             (end_loc_id != LLDB_INVALID_BREAK_ID)) ||
 | |
|         ((start_loc_id != LLDB_INVALID_BREAK_ID) &&
 | |
|          (end_loc_id == LLDB_INVALID_BREAK_ID))) {
 | |
|       new_args.Clear();
 | |
|       result.AppendErrorWithFormat("Invalid breakpoint id range:  Either "
 | |
|                                    "both ends of range must specify"
 | |
|                                    " a breakpoint location, or neither can "
 | |
|                                    "specify a breakpoint location.\n");
 | |
|       result.SetStatus(eReturnStatusFailed);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // We have valid range starting & ending breakpoint IDs.  Go through all
 | |
|     // the breakpoints in the target and find all the breakpoints that fit
 | |
|     // into this range, and add them to new_args.
 | |
| 
 | |
|     // Next check to see if we have location id's.  If so, make sure the
 | |
|     // start_bp_id and end_bp_id are for the same breakpoint; otherwise we
 | |
|     // have an illegal range: breakpoint id ranges that specify bp locations
 | |
|     // are NOT allowed to cross major bp id numbers.
 | |
| 
 | |
|     if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
 | |
|         (end_loc_id != LLDB_INVALID_BREAK_ID)) {
 | |
|       if (start_bp_id != end_bp_id) {
 | |
|         new_args.Clear();
 | |
|         result.AppendErrorWithFormat(
 | |
|             "Invalid range: Ranges that specify particular breakpoint "
 | |
|             "locations"
 | |
|             " must be within the same major breakpoint; you specified two"
 | |
|             " different major breakpoints, %d and %d.\n",
 | |
|             start_bp_id, end_bp_id);
 | |
|         result.SetStatus(eReturnStatusFailed);
 | |
|         return;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     const BreakpointList &breakpoints = target->GetBreakpointList();
 | |
|     const size_t num_breakpoints = breakpoints.GetSize();
 | |
|     for (size_t j = 0; j < num_breakpoints; ++j) {
 | |
|       Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
 | |
|       break_id_t cur_bp_id = breakpoint->GetID();
 | |
| 
 | |
|       if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
 | |
|         continue;
 | |
| 
 | |
|       const size_t num_locations = breakpoint->GetNumLocations();
 | |
| 
 | |
|       if ((cur_bp_id == start_bp_id) &&
 | |
|           (start_loc_id != LLDB_INVALID_BREAK_ID)) {
 | |
|         for (size_t k = 0; k < num_locations; ++k) {
 | |
|           BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
 | |
|           if ((bp_loc->GetID() >= start_loc_id) &&
 | |
|               (bp_loc->GetID() <= end_loc_id)) {
 | |
|             StreamString canonical_id_str;
 | |
|             BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
 | |
|                                                 bp_loc->GetID());
 | |
|             new_args.AppendArgument(canonical_id_str.GetString());
 | |
|           }
 | |
|         }
 | |
|       } else if ((cur_bp_id == end_bp_id) &&
 | |
|                  (end_loc_id != LLDB_INVALID_BREAK_ID)) {
 | |
|         for (size_t k = 0; k < num_locations; ++k) {
 | |
|           BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
 | |
|           if (bp_loc->GetID() <= end_loc_id) {
 | |
|             StreamString canonical_id_str;
 | |
|             BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
 | |
|                                                 bp_loc->GetID());
 | |
|             new_args.AppendArgument(canonical_id_str.GetString());
 | |
|           }
 | |
|         }
 | |
|       } else {
 | |
|         StreamString canonical_id_str;
 | |
|         BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
 | |
|                                             LLDB_INVALID_BREAK_ID);
 | |
|         new_args.AppendArgument(canonical_id_str.GetString());
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Okay, now see if we found any names, and if we did, add them:
 | |
|   if (target && names_found.size()) {
 | |
|     for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
 | |
|       for (std::string name : names_found) {
 | |
|         if (bkpt_sp->MatchesName(name.c_str())) {
 | |
|           StreamString canonical_id_str;
 | |
|           BreakpointID::GetCanonicalReference(
 | |
|               &canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
 | |
|           new_args.AppendArgument(canonical_id_str.GetString());
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   result.SetStatus(eReturnStatusSuccessFinishNoResult);
 | |
| }
 | |
| 
 | |
| std::pair<llvm::StringRef, llvm::StringRef>
 | |
| BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {
 | |
|   for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {
 | |
|     size_t idx = in_string.find(specifier_str);
 | |
|     if (idx == llvm::StringRef::npos)
 | |
|       continue;
 | |
|     llvm::StringRef right1 = in_string.drop_front(idx);
 | |
| 
 | |
|     llvm::StringRef from = in_string.take_front(idx);
 | |
|     llvm::StringRef to = right1.drop_front(specifier_str.size());
 | |
| 
 | |
|     if (BreakpointID::IsValidIDExpression(from) &&
 | |
|         BreakpointID::IsValidIDExpression(to)) {
 | |
|       return std::make_pair(from, to);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return std::pair<llvm::StringRef, llvm::StringRef>();
 | |
| }
 |