//===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/Args.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 () { } size_t BreakpointIDList::GetSize() { return m_breakpoint_ids.size(); } BreakpointID & BreakpointIDList::GetBreakpointIDAtIndex (size_t index) { if (index < m_breakpoint_ids.size()) return m_breakpoint_ids[index]; else return 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) { BreakpointID temp_bp_id; break_id_t bp_id; break_id_t loc_id; bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id); if (success) { temp_bp_id.SetID (bp_id, loc_id); m_breakpoint_ids.push_back (temp_bp_id); } return success; } bool BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, size_t *position) { 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) { BreakpointID temp_bp_id; break_id_t bp_id; break_id_t loc_id; if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id)) { temp_bp_id.SetID (bp_id, loc_id); return FindBreakpointID (temp_bp_id, position); } else return false; } void BreakpointIDList::InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result) { if (string_array == NULL) return; for (uint32_t i = 0; i < array_size; ++i) { break_id_t bp_id; break_id_t loc_id; if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id)) { if (bp_id != LLDB_INVALID_BREAK_ID) { BreakpointID temp_bp_id(bp_id, loc_id); m_breakpoint_ids.push_back (temp_bp_id); } else { result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]); result.SetStatus (eReturnStatusFailed); return; } } } 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, CommandReturnObject &result, Args &new_args) { std::string range_start; const char *range_end; const char *current_arg; const size_t num_old_args = old_args.GetArgumentCount(); for (size_t i = 0; i < num_old_args; ++i) { bool is_range = false; current_arg = old_args.GetArgumentAtIndex (i); size_t range_start_len = 0; size_t range_end_pos = 0; if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos)) { is_range = true; range_start.assign (current_arg, range_start_len); range_end = current_arg + range_end_pos; } else if ((i + 2 < num_old_args) && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1)) && BreakpointID::IsValidIDExpression (current_arg) && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2))) { range_start.assign (current_arg); range_end = old_args.GetArgumentAtIndex (i+2); is_range = true; i = i+2; } else { // See if user has specified id.* std::string tmp_str = old_args.GetArgumentAtIndex (i); size_t pos = tmp_str.find ('.'); if (pos != std::string::npos) { std::string bp_id_str = tmp_str.substr (0, pos); if (BreakpointID::IsValidIDExpression (bp_id_str.c_str()) && tmp_str[pos+1] == '*' && tmp_str.length() == (pos + 2)) { break_id_t bp_id; break_id_t bp_loc_id; BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id); BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id); if (! breakpoint_sp) { new_args.Clear(); result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id); 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, bp_loc->GetID()); new_args.AppendArgument (canonical_id_str.GetData()); } } } } if (is_range) { break_id_t start_bp_id; break_id_t end_bp_id; break_id_t start_loc_id; break_id_t end_loc_id; BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id); BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id); if ((start_bp_id == LLDB_INVALID_BREAK_ID) || (! target->GetBreakpointByID (start_bp_id))) { new_args.Clear(); result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str()); result.SetStatus (eReturnStatusFailed); return; } if ((end_bp_id == LLDB_INVALID_BREAK_ID) || (! target->GetBreakpointByID (end_bp_id))) { new_args.Clear(); result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end); result.SetStatus (eReturnStatusFailed); return; } 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.GetData()); } } } 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.GetData()); } } } else { StreamString canonical_id_str; BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID); new_args.AppendArgument (canonical_id_str.GetData()); } } } else // else is_range was false { new_args.AppendArgument (current_arg); } } result.SetStatus (eReturnStatusSuccessFinishNoResult); return; } bool BreakpointIDList::StringContainsIDRangeExpression (const char *in_string, size_t *range_start_len, size_t *range_end_pos) { bool is_range_expression = false; std::string arg_str = in_string; std::string::size_type idx; std::string::size_type start_pos = 0; *range_start_len = 0; *range_end_pos = 0; int specifiers_size = 0; for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i) ++specifiers_size; for (int i = 0; i < specifiers_size && !is_range_expression; ++i) { const char *specifier_str = BreakpointID::g_range_specifiers[i]; size_t len = strlen (specifier_str); idx = arg_str.find (BreakpointID::g_range_specifiers[i]); if (idx != std::string::npos) { *range_start_len = idx - start_pos; std::string start_str = arg_str.substr (start_pos, *range_start_len); if (idx + len < arg_str.length()) { *range_end_pos = idx + len; std::string end_str = arg_str.substr (*range_end_pos); if (BreakpointID::IsValidIDExpression (start_str.c_str()) && BreakpointID::IsValidIDExpression (end_str.c_str())) { is_range_expression = true; //*range_start = start_str; //*range_end = end_str; } } } } if (!is_range_expression) { *range_start_len = 0; *range_end_pos = 0; } return is_range_expression; }