forked from OSchip/llvm-project
440 lines
16 KiB
C++
440 lines
16 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.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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,
|
|
bool allow_locations,
|
|
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();
|
|
std::set<std::string> names_found;
|
|
|
|
for (size_t i = 0; i < num_old_args; ++i)
|
|
{
|
|
bool is_range = false;
|
|
|
|
current_arg = old_args.GetArgumentAtIndex (i);
|
|
if (!allow_locations && strchr(current_arg, '.') != nullptr)
|
|
{
|
|
result.AppendErrorWithFormat ("Breakpoint locations not allowed, saw location: %s.", current_arg);
|
|
new_args.Clear();
|
|
return;
|
|
}
|
|
|
|
size_t range_start_len = 0;
|
|
size_t range_end_pos = 0;
|
|
Error error;
|
|
|
|
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 (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 < 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);
|
|
}
|
|
}
|
|
|
|
// 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.GetData());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|