forked from OSchip/llvm-project
Add the ability to tag one or more breakpoints with a name. These
names can then be used in place of breakpoint id's or breakpoint id ranges in all the commands that operate on breakpoints. <rdar://problem/10103959> llvm-svn: 224392
This commit is contained in:
parent
aa1bade7b4
commit
5e09c8c32c
|
@ -123,6 +123,18 @@ public:
|
|||
|
||||
SBError
|
||||
SetScriptCallbackBody (const char *script_body_text);
|
||||
|
||||
bool
|
||||
AddName (const char *new_name);
|
||||
|
||||
void
|
||||
RemoveName (const char *name_to_remove);
|
||||
|
||||
bool
|
||||
MatchesName (const char *name);
|
||||
|
||||
void
|
||||
GetNames (SBStringList &names);
|
||||
|
||||
size_t
|
||||
GetNumResolvedLocations() const;
|
||||
|
|
|
@ -12,8 +12,11 @@
|
|||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
#include <unordered_set>
|
||||
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Breakpoint/BreakpointID.h"
|
||||
#include "lldb/Breakpoint/BreakpointLocationList.h"
|
||||
#include "lldb/Breakpoint/BreakpointOptions.h"
|
||||
#include "lldb/Breakpoint/BreakpointLocationCollection.h"
|
||||
|
@ -636,6 +639,32 @@ public:
|
|||
return m_filter_sp;
|
||||
}
|
||||
|
||||
bool
|
||||
AddName (const char *new_name, Error &error);
|
||||
|
||||
void
|
||||
RemoveName (const char *name_to_remove)
|
||||
{
|
||||
if (name_to_remove)
|
||||
m_name_list.erase(name_to_remove);
|
||||
}
|
||||
|
||||
bool
|
||||
MatchesName (const char *name)
|
||||
{
|
||||
return m_name_list.find(name) != m_name_list.end();
|
||||
}
|
||||
|
||||
void
|
||||
GetNames (std::vector<std::string> &names)
|
||||
{
|
||||
names.clear();
|
||||
for (auto name : m_name_list)
|
||||
{
|
||||
names.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class Target;
|
||||
//------------------------------------------------------------------
|
||||
|
@ -697,6 +726,7 @@ private:
|
|||
bool m_being_created;
|
||||
bool m_hardware; // If this breakpoint is required to use a hardware breakpoint
|
||||
Target &m_target; // The target that holds this breakpoint.
|
||||
std::unordered_set<std::string> m_name_list; // If not empty, this is the name of this breakpoint (many breakpoints can share the same name.)
|
||||
lldb::SearchFilterSP m_filter_sp; // The filter that constrains the breakpoint's domain.
|
||||
lldb::BreakpointResolverSP m_resolver_sp; // The resolver that defines this breakpoint.
|
||||
BreakpointOptions m_options; // Settable breakpoint options
|
||||
|
|
|
@ -92,6 +92,21 @@ public:
|
|||
ParseCanonicalReference (const char *input, lldb::break_id_t *break_id, lldb::break_id_t *break_loc_id);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Takes an input string and checks to see whether it is a breakpoint name.
|
||||
/// If it is a mal-formed breakpoint name, error will be set to an appropriate
|
||||
/// error string.
|
||||
///
|
||||
/// @param[in] input
|
||||
/// A string containing JUST the breakpoint description.
|
||||
/// @param[out] error
|
||||
/// If the name is a well-formed breakpoint name, set to success, otherwise set to an error.
|
||||
/// @return
|
||||
/// \b true if the name is a breakpoint name (as opposed to an ID or range) false otherwise.
|
||||
//------------------------------------------------------------------
|
||||
static bool
|
||||
StringIsBreakpointName (const char *name, Error &error);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Takes a breakpoint ID and the breakpoint location id and returns
|
||||
/// a string containing the canonical description for the breakpoint
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
StringContainsIDRangeExpression (const char *in_string, size_t *range_start_len, size_t *range_end_pos);
|
||||
|
||||
static void
|
||||
FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result, Args &new_args);
|
||||
FindAndReplaceIDRanges (Args &old_args, Target *target, bool allow_locations, CommandReturnObject &result, Args &new_args);
|
||||
|
||||
private:
|
||||
BreakpointIDArray m_breakpoint_ids;
|
||||
|
|
|
@ -420,6 +420,7 @@ namespace lldb {
|
|||
eArgTypeBoolean,
|
||||
eArgTypeBreakpointID,
|
||||
eArgTypeBreakpointIDRange,
|
||||
eArgTypeBreakpointName,
|
||||
eArgTypeByteSize,
|
||||
eArgTypeClassName,
|
||||
eArgTypeCommandName,
|
||||
|
|
|
@ -84,14 +84,16 @@
|
|||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "1"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
customWorkingDirectory = "/Volumes/work/gclayton/Documents/devb/attach"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "YES"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "26F5C26910F3D9A4009D5894"
|
||||
|
@ -147,7 +149,8 @@
|
|||
buildConfiguration = "Release"
|
||||
ignoresPersistentStateOnLaunch = "YES"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "26F5C26910F3D9A4009D5894"
|
||||
|
|
|
@ -200,6 +200,18 @@ public:
|
|||
SBError
|
||||
SetScriptCallbackBody (const char *script_body_text);
|
||||
|
||||
bool
|
||||
AddName (const char *new_name);
|
||||
|
||||
void
|
||||
RemoveName (const char *name_to_remove);
|
||||
|
||||
bool
|
||||
MatchesName (const char *name);
|
||||
|
||||
void
|
||||
GetNames (SBStringList &names);
|
||||
|
||||
size_t
|
||||
GetNumResolvedLocations() const;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "lldb/API/SBEvent.h"
|
||||
#include "lldb/API/SBProcess.h"
|
||||
#include "lldb/API/SBStream.h"
|
||||
#include "lldb/API/SBStringList.h"
|
||||
#include "lldb/API/SBThread.h"
|
||||
|
||||
#include "lldb/Breakpoint/Breakpoint.h"
|
||||
|
@ -653,6 +654,83 @@ SBBreakpoint::SetScriptCallbackBody (const char *callback_body_text)
|
|||
return sb_error;
|
||||
}
|
||||
|
||||
bool
|
||||
SBBreakpoint::AddName (const char *new_name)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
|
||||
if (log)
|
||||
log->Printf ("SBBreakpoint(%p)::AddName (name=%s)",
|
||||
static_cast<void*>(m_opaque_sp.get()),
|
||||
new_name);
|
||||
|
||||
if (m_opaque_sp)
|
||||
{
|
||||
Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
|
||||
Error error; // Think I'm just going to swallow the error here, it's probably more annoying to have to provide it.
|
||||
return m_opaque_sp->AddName(new_name, error);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SBBreakpoint::RemoveName (const char *name_to_remove)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
|
||||
if (log)
|
||||
log->Printf ("SBBreakpoint(%p)::RemoveName (name=%s)",
|
||||
static_cast<void*>(m_opaque_sp.get()),
|
||||
name_to_remove);
|
||||
|
||||
if (m_opaque_sp)
|
||||
{
|
||||
Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
|
||||
m_opaque_sp->RemoveName(name_to_remove);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SBBreakpoint::MatchesName (const char *name)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
|
||||
if (log)
|
||||
log->Printf ("SBBreakpoint(%p)::MatchesName (name=%s)",
|
||||
static_cast<void*>(m_opaque_sp.get()),
|
||||
name);
|
||||
|
||||
if (m_opaque_sp)
|
||||
{
|
||||
Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
|
||||
return m_opaque_sp->MatchesName(name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SBBreakpoint::GetNames (SBStringList &names)
|
||||
{
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
|
||||
|
||||
if (log)
|
||||
log->Printf ("SBBreakpoint(%p)::GetNames ()",
|
||||
static_cast<void*>(m_opaque_sp.get()));
|
||||
|
||||
if (m_opaque_sp)
|
||||
{
|
||||
Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
|
||||
std::vector<std::string> names_vec;
|
||||
m_opaque_sp->GetNames(names_vec);
|
||||
for (std::string name : names_vec)
|
||||
{
|
||||
names.AppendString (name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lldb_private::Breakpoint *
|
||||
SBBreakpoint::operator->() const
|
||||
{
|
||||
|
|
|
@ -71,7 +71,8 @@ Breakpoint::Breakpoint (Target &new_target, Breakpoint &source_bp) :
|
|||
m_target(new_target),
|
||||
m_options (source_bp.m_options),
|
||||
m_locations(*this),
|
||||
m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols)
|
||||
m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols),
|
||||
m_name_list (source_bp.m_name_list)
|
||||
{
|
||||
// Now go through and copy the filter & resolver:
|
||||
m_resolver_sp = source_bp.m_resolver_sp->CopyForBreakpoint(*this);
|
||||
|
@ -782,6 +783,23 @@ Breakpoint::GetNumLocations() const
|
|||
return m_locations.GetSize();
|
||||
}
|
||||
|
||||
bool
|
||||
Breakpoint::AddName (const char *new_name, Error &error)
|
||||
{
|
||||
if (!new_name)
|
||||
return false;
|
||||
if (!BreakpointID::StringIsBreakpointName(new_name, error))
|
||||
{
|
||||
error.SetErrorStringWithFormat("input name \"%s\" not a breakpoint name.", new_name);
|
||||
return false;
|
||||
}
|
||||
if (!error.Success())
|
||||
return false;
|
||||
|
||||
m_name_list.insert(new_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_locations)
|
||||
{
|
||||
|
@ -832,6 +850,20 @@ Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_l
|
|||
|
||||
if (level == lldb::eDescriptionLevelFull)
|
||||
{
|
||||
if (!m_name_list.empty())
|
||||
{
|
||||
s->EOL();
|
||||
s->Indent();
|
||||
s->Printf ("Names:");
|
||||
s->EOL();
|
||||
s->IndentMore();
|
||||
for (std::string name : m_name_list)
|
||||
{
|
||||
s->Indent();
|
||||
s->Printf("%s\n", name.c_str());
|
||||
}
|
||||
s->IndentLess();
|
||||
}
|
||||
s->IndentLess();
|
||||
s->EOL();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "lldb/Breakpoint/BreakpointID.h"
|
||||
#include "lldb/Breakpoint/Breakpoint.h"
|
||||
#include "lldb/Core/Stream.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
@ -121,3 +122,19 @@ BreakpointID::ParseCanonicalReference (const char *input, break_id_t *break_id_p
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BreakpointID::StringIsBreakpointName(const char *name, Error &error)
|
||||
{
|
||||
error.Clear();
|
||||
|
||||
if (name && (name[0] >= 'A' && name[0] <= 'z'))
|
||||
{
|
||||
if (strcspn(name, ".- ") != strlen(name))
|
||||
{
|
||||
error.SetErrorStringWithFormat("invalid breakpoint name: \"%s\"", name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -159,27 +159,52 @@ BreakpointIDList::InsertStringArray (const char **string_array, size_t array_siz
|
|||
// 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,
|
||||
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)
|
||||
|
@ -342,6 +367,23 @@ BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, Comman
|
|||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -237,8 +237,7 @@ BreakpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) cons
|
|||
|
||||
if (m_thread_spec_ap.get())
|
||||
m_thread_spec_ap->GetDescription (s, level);
|
||||
else if (level == eDescriptionLevelBrief)
|
||||
s->PutCString ("thread spec: no ");
|
||||
|
||||
if (level == lldb::eDescriptionLevelFull)
|
||||
{
|
||||
s->IndentLess();
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "lldb/Breakpoint/BreakpointIDList.h"
|
||||
#include "lldb/Breakpoint/BreakpointLocation.h"
|
||||
#include "lldb/Interpreter/Options.h"
|
||||
#include "lldb/Interpreter/OptionValueString.h"
|
||||
#include "lldb/Interpreter/OptionValueUInt64.h"
|
||||
#include "lldb/Core/RegularExpression.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
|
@ -240,6 +242,13 @@ public:
|
|||
m_func_name_type_mask |= eFunctionNameTypeAuto;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
if (BreakpointID::StringIsBreakpointName(option_arg, error))
|
||||
m_breakpoint_names.push_back (option_arg);
|
||||
else
|
||||
error.SetErrorStringWithFormat(error.AsCString());
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
m_one_shot = true;
|
||||
break;
|
||||
|
@ -329,6 +338,7 @@ public:
|
|||
m_skip_prologue = eLazyBoolCalculate;
|
||||
m_one_shot = false;
|
||||
m_use_dummy = false;
|
||||
m_breakpoint_names.clear();
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
|
@ -348,6 +358,7 @@ public:
|
|||
uint32_t m_line_num;
|
||||
uint32_t m_column;
|
||||
std::vector<std::string> m_func_names;
|
||||
std::vector<std::string> m_breakpoint_names;
|
||||
uint32_t m_func_name_type_mask;
|
||||
std::string m_func_regexp;
|
||||
std::string m_source_text_regexp;
|
||||
|
@ -558,6 +569,13 @@ protected:
|
|||
|
||||
if (!m_options.m_condition.empty())
|
||||
bp->GetOptions()->SetCondition(m_options.m_condition.c_str());
|
||||
|
||||
if (!m_options.m_breakpoint_names.empty())
|
||||
{
|
||||
Error error; // We don't need to check the error here, since the option parser checked it...
|
||||
for (auto name : m_options.m_breakpoint_names)
|
||||
bp->AddName(name.c_str(), error);
|
||||
}
|
||||
|
||||
bp->SetOneShot (m_options.m_one_shot);
|
||||
}
|
||||
|
@ -719,6 +737,9 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
|
|||
{ LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
|
||||
"Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
|
||||
|
||||
{ LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName,
|
||||
"Adds this to the list of names for this breakopint."},
|
||||
|
||||
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
|
@ -954,7 +975,7 @@ protected:
|
|||
|
||||
BreakpointIDList valid_bp_ids;
|
||||
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
|
@ -1106,7 +1127,7 @@ protected:
|
|||
{
|
||||
// Particular breakpoint selected; enable that breakpoint.
|
||||
BreakpointIDList valid_bp_ids;
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
|
@ -1226,7 +1247,7 @@ protected:
|
|||
// Particular breakpoint selected; disable that breakpoint.
|
||||
BreakpointIDList valid_bp_ids;
|
||||
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
|
@ -1419,7 +1440,7 @@ protected:
|
|||
{
|
||||
// Particular breakpoints selected; show info about that breakpoint.
|
||||
BreakpointIDList valid_bp_ids;
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
|
@ -1806,7 +1827,7 @@ protected:
|
|||
{
|
||||
// Particular breakpoint selected; disable that breakpoint.
|
||||
BreakpointIDList valid_bp_ids;
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
|
@ -1860,6 +1881,401 @@ CommandObjectBreakpointDelete::CommandOptions::g_option_table[] =
|
|||
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectBreakpointName
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static OptionDefinition
|
||||
g_breakpoint_name_options[] =
|
||||
{
|
||||
{ LLDB_OPT_SET_1, false, "name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."},
|
||||
{ LLDB_OPT_SET_2, false, "breakpoint-id", 'B', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointID, "Specify a breakpoint id to use."},
|
||||
{ LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
|
||||
"Operate on Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
|
||||
};
|
||||
class BreakpointNameOptionGroup : public OptionGroup
|
||||
{
|
||||
public:
|
||||
BreakpointNameOptionGroup() :
|
||||
OptionGroup(),
|
||||
m_breakpoint(LLDB_INVALID_BREAK_ID),
|
||||
m_use_dummy (false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual
|
||||
~BreakpointNameOptionGroup ()
|
||||
{
|
||||
}
|
||||
|
||||
virtual uint32_t
|
||||
GetNumDefinitions ()
|
||||
{
|
||||
return sizeof (g_breakpoint_name_options) / sizeof (OptionDefinition);
|
||||
}
|
||||
|
||||
virtual const OptionDefinition*
|
||||
GetDefinitions ()
|
||||
{
|
||||
return g_breakpoint_name_options;
|
||||
}
|
||||
|
||||
virtual Error
|
||||
SetOptionValue (CommandInterpreter &interpreter,
|
||||
uint32_t option_idx,
|
||||
const char *option_value)
|
||||
{
|
||||
Error error;
|
||||
const int short_option = g_breakpoint_name_options[option_idx].short_option;
|
||||
|
||||
switch (short_option)
|
||||
{
|
||||
case 'N':
|
||||
if (BreakpointID::StringIsBreakpointName(option_value, error) && error.Success())
|
||||
m_name.SetValueFromCString(option_value);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
if (m_breakpoint.SetValueFromCString(option_value).Fail())
|
||||
error.SetErrorStringWithFormat ("unrecognized value \"%s\" for breakpoint", option_value);
|
||||
break;
|
||||
case 'D':
|
||||
if (m_use_dummy.SetValueFromCString(option_value).Fail())
|
||||
error.SetErrorStringWithFormat ("unrecognized value \"%s\" for use-dummy", option_value);
|
||||
break;
|
||||
|
||||
default:
|
||||
error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
|
||||
break;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
virtual void
|
||||
OptionParsingStarting (CommandInterpreter &interpreter)
|
||||
{
|
||||
m_name.Clear();
|
||||
m_breakpoint.Clear();
|
||||
m_use_dummy.Clear();
|
||||
m_use_dummy.SetDefaultValue(false);
|
||||
}
|
||||
|
||||
OptionValueString m_name;
|
||||
OptionValueUInt64 m_breakpoint;
|
||||
OptionValueBoolean m_use_dummy;
|
||||
};
|
||||
|
||||
|
||||
class CommandObjectBreakpointNameAdd : public CommandObjectParsed
|
||||
{
|
||||
public:
|
||||
CommandObjectBreakpointNameAdd (CommandInterpreter &interpreter) :
|
||||
CommandObjectParsed (interpreter,
|
||||
"add",
|
||||
"Add a name to the breakpoints provided.",
|
||||
"breakpoint name add <command-options> <breakpoint-id-list>"),
|
||||
m_name_options(),
|
||||
m_option_group(interpreter)
|
||||
{
|
||||
// Create the first variant for the first (and only) argument for this command.
|
||||
CommandArgumentEntry arg1;
|
||||
CommandArgumentData id_arg;
|
||||
id_arg.arg_type = eArgTypeBreakpointID;
|
||||
id_arg.arg_repetition = eArgRepeatOptional;
|
||||
arg1.push_back(id_arg);
|
||||
m_arguments.push_back (arg1);
|
||||
|
||||
m_option_group.Append (&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
|
||||
m_option_group.Finalize();
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandObjectBreakpointNameAdd () {}
|
||||
|
||||
Options *
|
||||
GetOptions ()
|
||||
{
|
||||
return &m_option_group;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool
|
||||
DoExecute (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
if (!m_name_options.m_name.OptionWasSet())
|
||||
{
|
||||
result.SetError("No name option provided.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
|
||||
|
||||
if (target == NULL)
|
||||
{
|
||||
result.AppendError ("Invalid target. No existing target or breakpoints.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
Mutex::Locker locker;
|
||||
target->GetBreakpointList().GetListMutex(locker);
|
||||
|
||||
const BreakpointList &breakpoints = target->GetBreakpointList();
|
||||
|
||||
size_t num_breakpoints = breakpoints.GetSize();
|
||||
if (num_breakpoints == 0)
|
||||
{
|
||||
result.SetError("No breakpoints, cannot add names.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Particular breakpoint selected; disable that breakpoint.
|
||||
BreakpointIDList valid_bp_ids;
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
if (valid_bp_ids.GetSize() == 0)
|
||||
{
|
||||
result.SetError("No breakpoints specified, cannot add names.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
size_t num_valid_ids = valid_bp_ids.GetSize();
|
||||
for (size_t index = 0; index < num_valid_ids; index++)
|
||||
{
|
||||
lldb::break_id_t bp_id = valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
|
||||
BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
|
||||
Error error; // We don't need to check the error here, since the option parser checked it...
|
||||
bp_sp->AddName(m_name_options.m_name.GetCurrentValue(), error);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
BreakpointNameOptionGroup m_name_options;
|
||||
OptionGroupOptions m_option_group;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CommandObjectBreakpointNameDelete : public CommandObjectParsed
|
||||
{
|
||||
public:
|
||||
CommandObjectBreakpointNameDelete (CommandInterpreter &interpreter) :
|
||||
CommandObjectParsed (interpreter,
|
||||
"delete",
|
||||
"Delete a name from the breakpoints provided.",
|
||||
"breakpoint name delete <command-options> <breakpoint-id-list>"),
|
||||
m_name_options(),
|
||||
m_option_group(interpreter)
|
||||
{
|
||||
// Create the first variant for the first (and only) argument for this command.
|
||||
CommandArgumentEntry arg1;
|
||||
CommandArgumentData id_arg;
|
||||
id_arg.arg_type = eArgTypeBreakpointID;
|
||||
id_arg.arg_repetition = eArgRepeatOptional;
|
||||
arg1.push_back(id_arg);
|
||||
m_arguments.push_back (arg1);
|
||||
|
||||
m_option_group.Append (&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
|
||||
m_option_group.Finalize();
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandObjectBreakpointNameDelete () {}
|
||||
|
||||
Options *
|
||||
GetOptions ()
|
||||
{
|
||||
return &m_option_group;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool
|
||||
DoExecute (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
if (!m_name_options.m_name.OptionWasSet())
|
||||
{
|
||||
result.SetError("No name option provided.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
|
||||
|
||||
if (target == NULL)
|
||||
{
|
||||
result.AppendError ("Invalid target. No existing target or breakpoints.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
Mutex::Locker locker;
|
||||
target->GetBreakpointList().GetListMutex(locker);
|
||||
|
||||
const BreakpointList &breakpoints = target->GetBreakpointList();
|
||||
|
||||
size_t num_breakpoints = breakpoints.GetSize();
|
||||
if (num_breakpoints == 0)
|
||||
{
|
||||
result.SetError("No breakpoints, cannot delete names.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Particular breakpoint selected; disable that breakpoint.
|
||||
BreakpointIDList valid_bp_ids;
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
if (valid_bp_ids.GetSize() == 0)
|
||||
{
|
||||
result.SetError("No breakpoints specified, cannot delete names.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
size_t num_valid_ids = valid_bp_ids.GetSize();
|
||||
for (size_t index = 0; index < num_valid_ids; index++)
|
||||
{
|
||||
lldb::break_id_t bp_id = valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
|
||||
BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
|
||||
bp_sp->RemoveName(m_name_options.m_name.GetCurrentValue());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
BreakpointNameOptionGroup m_name_options;
|
||||
OptionGroupOptions m_option_group;
|
||||
};
|
||||
|
||||
class CommandObjectBreakpointNameList : public CommandObjectParsed
|
||||
{
|
||||
public:
|
||||
CommandObjectBreakpointNameList (CommandInterpreter &interpreter) :
|
||||
CommandObjectParsed (interpreter,
|
||||
"list",
|
||||
"List either the names for a breakpoint or the breakpoints for a given name.",
|
||||
"breakpoint name list <command-options>"),
|
||||
m_name_options(),
|
||||
m_option_group(interpreter)
|
||||
{
|
||||
m_option_group.Append (&m_name_options);
|
||||
m_option_group.Finalize();
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandObjectBreakpointNameList () {}
|
||||
|
||||
Options *
|
||||
GetOptions ()
|
||||
{
|
||||
return &m_option_group;
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
virtual bool
|
||||
DoExecute (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
|
||||
|
||||
if (target == NULL)
|
||||
{
|
||||
result.AppendError ("Invalid target. No existing target or breakpoints.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_name_options.m_name.OptionWasSet())
|
||||
{
|
||||
const char *name = m_name_options.m_name.GetCurrentValue();
|
||||
Mutex::Locker locker;
|
||||
target->GetBreakpointList().GetListMutex(locker);
|
||||
|
||||
BreakpointList &breakpoints = target->GetBreakpointList();
|
||||
for (BreakpointSP bp_sp : breakpoints.Breakpoints())
|
||||
{
|
||||
if (bp_sp->MatchesName(name))
|
||||
{
|
||||
StreamString s;
|
||||
bp_sp->GetDescription(&s, eDescriptionLevelBrief);
|
||||
s.EOL();
|
||||
result.AppendMessage(s.GetData());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (m_name_options.m_breakpoint.OptionWasSet())
|
||||
{
|
||||
BreakpointSP bp_sp = target->GetBreakpointList().FindBreakpointByID(m_name_options.m_breakpoint.GetCurrentValue());
|
||||
if (bp_sp)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
bp_sp->GetNames (names);
|
||||
result.AppendMessage ("Names:");
|
||||
for (auto name : names)
|
||||
result.AppendMessageWithFormat (" %s\n", name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
result.AppendErrorWithFormat ("Could not find breakpoint %" PRId64 ".\n",
|
||||
m_name_options.m_breakpoint.GetCurrentValue());
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.SetError ("Must specify -N or -B option to list.");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
BreakpointNameOptionGroup m_name_options;
|
||||
OptionGroupOptions m_option_group;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectMultiwordBreakpoint
|
||||
//-------------------------------------------------------------------------
|
||||
class CommandObjectBreakpointName : public CommandObjectMultiword
|
||||
{
|
||||
public:
|
||||
CommandObjectBreakpointName (CommandInterpreter &interpreter) :
|
||||
CommandObjectMultiword(interpreter,
|
||||
"name",
|
||||
"A set of commands to manage name tags for breakpoints",
|
||||
"breakpoint name <command> [<command-options>]")
|
||||
{
|
||||
CommandObjectSP add_command_object (new CommandObjectBreakpointNameAdd (interpreter));
|
||||
CommandObjectSP delete_command_object (new CommandObjectBreakpointNameDelete (interpreter));
|
||||
CommandObjectSP list_command_object (new CommandObjectBreakpointNameList (interpreter));
|
||||
|
||||
LoadSubCommand ("add", add_command_object);
|
||||
LoadSubCommand ("delete", delete_command_object);
|
||||
LoadSubCommand ("list", list_command_object);
|
||||
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandObjectBreakpointName ()
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectMultiwordBreakpoint
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -1879,6 +2295,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter
|
|||
CommandObjectSP set_command_object (new CommandObjectBreakpointSet (interpreter));
|
||||
CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter));
|
||||
CommandObjectSP modify_command_object (new CommandObjectBreakpointModify(interpreter));
|
||||
CommandObjectSP name_command_object (new CommandObjectBreakpointName(interpreter));
|
||||
|
||||
list_command_object->SetCommandName ("breakpoint list");
|
||||
enable_command_object->SetCommandName("breakpoint enable");
|
||||
|
@ -1888,6 +2305,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter
|
|||
set_command_object->SetCommandName("breakpoint set");
|
||||
command_command_object->SetCommandName ("breakpoint command");
|
||||
modify_command_object->SetCommandName ("breakpoint modify");
|
||||
name_command_object->SetCommandName ("breakpoint name");
|
||||
|
||||
LoadSubCommand ("list", list_command_object);
|
||||
LoadSubCommand ("enable", enable_command_object);
|
||||
|
@ -1897,6 +2315,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter
|
|||
LoadSubCommand ("set", set_command_object);
|
||||
LoadSubCommand ("command", command_command_object);
|
||||
LoadSubCommand ("modify", modify_command_object);
|
||||
LoadSubCommand ("name", name_command_object);
|
||||
}
|
||||
|
||||
CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint ()
|
||||
|
@ -1904,13 +2323,17 @@ CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint ()
|
|||
}
|
||||
|
||||
void
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result,
|
||||
BreakpointIDList *valid_ids)
|
||||
CommandObjectMultiwordBreakpoint::VerifyIDs (Args &args,
|
||||
Target *target,
|
||||
bool allow_locations,
|
||||
CommandReturnObject &result,
|
||||
BreakpointIDList *valid_ids)
|
||||
{
|
||||
// args can be strings representing 1). integers (for breakpoint ids)
|
||||
// 2). the full breakpoint & location canonical representation
|
||||
// 3). the word "to" or a hyphen, representing a range (in which case there
|
||||
// had *better* be an entry both before & after of one of the first two types.
|
||||
// 4). A breakpoint name
|
||||
// If args is empty, we will use the last created breakpoint (if there is one.)
|
||||
|
||||
Args temp_args;
|
||||
|
@ -1934,7 +2357,7 @@ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *targe
|
|||
// the new TEMP_ARGS. Do not copy breakpoint id range strings over; instead generate a list of strings for
|
||||
// all the breakpoint ids in the range, and shove all of those breakpoint id strings into TEMP_ARGS.
|
||||
|
||||
BreakpointIDList::FindAndReplaceIDRanges (args, target, result, temp_args);
|
||||
BreakpointIDList::FindAndReplaceIDRanges (args, target, allow_locations, result, temp_args);
|
||||
|
||||
// NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList:
|
||||
|
||||
|
|
|
@ -38,8 +38,20 @@ public:
|
|||
~CommandObjectMultiwordBreakpoint ();
|
||||
|
||||
static void
|
||||
VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids);
|
||||
VerifyBreakpointOrLocationIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids)
|
||||
{
|
||||
VerifyIDs (args, target, true, result, valid_ids);
|
||||
}
|
||||
|
||||
static void
|
||||
VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids)
|
||||
{
|
||||
VerifyIDs (args, target, false, result, valid_ids);
|
||||
}
|
||||
|
||||
private:
|
||||
static void
|
||||
VerifyIDs (Args &args, Target *target, bool allow_locations, CommandReturnObject &result, BreakpointIDList *valid_ids);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
|
|
@ -467,7 +467,7 @@ protected:
|
|||
}
|
||||
|
||||
BreakpointIDList valid_bp_ids;
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
m_bp_options_vec.clear();
|
||||
|
||||
|
@ -714,7 +714,7 @@ protected:
|
|||
}
|
||||
|
||||
BreakpointIDList valid_bp_ids;
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
|
@ -824,7 +824,7 @@ protected:
|
|||
}
|
||||
|
||||
BreakpointIDList valid_bp_ids;
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
|
||||
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids);
|
||||
|
||||
if (result.Succeeded())
|
||||
{
|
||||
|
|
|
@ -747,6 +747,22 @@ BreakpointIDRangeHelpTextCallback ()
|
|||
" is legal; 2 - 5 is legal; but 3.2 - 4.4 is not legal.";
|
||||
}
|
||||
|
||||
static const char *
|
||||
BreakpointNameHelpTextCallback ()
|
||||
{
|
||||
return "A name that can be added to a breakpoint when it is created, or later "
|
||||
"on with the \"breakpoint name add\" command. "
|
||||
"Breakpoint names can be used to specify breakpoints in all the places breakpoint ID's "
|
||||
"and breakpoint ID ranges can be used. As such they provide a convenient way to group breakpoints, "
|
||||
"and to operate on breakpoints you create without having to track the breakpoint number. "
|
||||
"Note, the attributes you set when using a breakpoint name in a breakpoint command don't "
|
||||
"adhere to the name, but instead are set individually on all the breakpoints currently tagged with that name. Future breakpoints "
|
||||
"tagged with that name will not pick up the attributes previously given using that name. "
|
||||
"In order to distinguish breakpoint names from breakpoint ID's and ranges, "
|
||||
"names must start with a letter from a-z or A-Z and cannot contain spaces, \".\" or \"-\". "
|
||||
"Also, breakpoint names can only be applied to breakpoints, not to breakpoint locations.";
|
||||
}
|
||||
|
||||
static const char *
|
||||
GDBFormatHelpTextCallback ()
|
||||
{
|
||||
|
@ -1112,6 +1128,7 @@ CommandObject::g_arguments_data[] =
|
|||
{ eArgTypeBoolean, "boolean", CommandCompletions::eNoCompletion, { nullptr, false }, "A Boolean value: 'true' or 'false'" },
|
||||
{ eArgTypeBreakpointID, "breakpt-id", CommandCompletions::eNoCompletion, { BreakpointIDHelpTextCallback, false }, nullptr },
|
||||
{ eArgTypeBreakpointIDRange, "breakpt-id-list", CommandCompletions::eNoCompletion, { BreakpointIDRangeHelpTextCallback, false }, nullptr },
|
||||
{ eArgTypeBreakpointName, "breakpoint-name", CommandCompletions::eNoCompletion, { BreakpointNameHelpTextCallback, false }, nullptr },
|
||||
{ eArgTypeByteSize, "byte-size", CommandCompletions::eNoCompletion, { nullptr, false }, "Number of bytes to use." },
|
||||
{ eArgTypeClassName, "class-name", CommandCompletions::eNoCompletion, { nullptr, false }, "Then name of a class from the debug information in the program." },
|
||||
{ eArgTypeCommandName, "cmd-name", CommandCompletions::eNoCompletion, { nullptr, false }, "A debugger command (may be multiple words), without any options or arguments." },
|
||||
|
|
Loading…
Reference in New Issue