summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Interpreter/CommandObject.h13
-rw-r--r--lldb/source/Commands/CommandObjectWatchpoint.cpp151
-rw-r--r--lldb/source/Commands/CommandObjectWatchpoint.h31
-rw-r--r--lldb/source/Interpreter/CommandObject.cpp19
-rw-r--r--lldb/source/Interpreter/OptionGroupWatchpoint.cpp4
-rw-r--r--lldb/source/Interpreter/Options.cpp8
-rw-r--r--lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py2
-rw-r--r--lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py2
-rw-r--r--lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchpointSetErrorCases.py10
-rw-r--r--lldb/test/help/TestHelp.py7
10 files changed, 192 insertions, 55 deletions
diff --git a/lldb/include/lldb/Interpreter/CommandObject.h b/lldb/include/lldb/Interpreter/CommandObject.h
index f1f140a8313..66cdf8eae35 100644
--- a/lldb/include/lldb/Interpreter/CommandObject.h
+++ b/lldb/include/lldb/Interpreter/CommandObject.h
@@ -60,6 +60,12 @@ public:
{
lldb::CommandArgumentType arg_type;
ArgumentRepetitionType arg_repetition;
+ uint32_t arg_opt_set_association; // This arg might be associated only with some particular option set(s).
+ CommandArgumentData():
+ arg_type(lldb::eArgTypeNone),
+ arg_repetition(eArgRepeatPlain),
+ arg_opt_set_association(LLDB_OPT_SET_ALL) // By default, the arg associates to all option sets.
+ {}
};
typedef std::vector<CommandArgumentData> CommandArgumentEntry; // Used to build individual command argument lists
@@ -171,8 +177,13 @@ public:
static const char *
GetArgumentName (lldb::CommandArgumentType arg_type);
+ // Generates a nicely formatted command args string for help command output.
+ // By default, all possible args are taken into account, for example,
+ // '<expr | variable-name>'. This can be refined by passing a second arg
+ // specifying which option set(s) we are interested, which could then, for
+ // example, produce either '<expr>' or '<variable-name>'.
void
- GetFormattedCommandArguments (Stream &str);
+ GetFormattedCommandArguments (Stream &str, uint32_t opt_set_mask = LLDB_OPT_SET_ALL);
bool
IsPairType (ArgumentRepetitionType arg_repeat_type);
diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp
index f72a900dbba..bb715d81d79 100644
--- a/lldb/source/Commands/CommandObjectWatchpoint.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp
@@ -853,6 +853,70 @@ CommandObjectWatchpointModify::Execute
}
//-------------------------------------------------------------------------
+// CommandObjectWatchpointSet::CommandOptions
+//-------------------------------------------------------------------------
+#pragma mark Set::CommandOptions
+
+CommandObjectWatchpointSet::CommandOptions::CommandOptions() :
+ OptionGroup()
+{
+}
+
+CommandObjectWatchpointSet::CommandOptions::~CommandOptions ()
+{
+}
+
+OptionDefinition
+CommandObjectWatchpointSet::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, true, "expression", 'e', no_argument, NULL, NULL, eArgTypeNone, "Watch an address with an expression specified at the end."},
+{ LLDB_OPT_SET_2, true, "variable", 'v', no_argument, NULL, NULL, eArgTypeNone, "Watch a variable name specified at the end."}
+};
+
+uint32_t
+CommandObjectWatchpointSet::CommandOptions::GetNumDefinitions ()
+{
+ return sizeof(g_option_table)/sizeof(OptionDefinition);
+}
+
+const OptionDefinition*
+CommandObjectWatchpointSet::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+Error
+CommandObjectWatchpointSet::CommandOptions::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ char short_option = (char) g_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'e':
+ m_do_expression = true;
+ break;
+ case 'v':
+ m_do_variable = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectWatchpointSet::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_do_expression = false;
+ m_do_variable = false;
+}
+
+//-------------------------------------------------------------------------
// CommandObjectWatchpointSet
//-------------------------------------------------------------------------
#pragma mark Set
@@ -861,45 +925,51 @@ CommandObjectWatchpointSet::CommandObjectWatchpointSet (CommandInterpreter &inte
CommandObject (interpreter,
"watchpoint set",
"Set a watchpoint. "
- "You can choose to watch a variable in scope with just the '-w' option. "
- "If you use the '-x' option to specify the byte size, it is implied "
- "that the remaining string is evaluated as an expression with the result "
- "interpreted as an address to watch for, i.e., the pointee is watched. "
+ "You can choose to watch a variable in scope with the '-v' option "
+ "or to watch an address with the '-e' option by supplying an expression. "
+ "Use the '-w' option to specify the type of watchpoint and "
+ "the '-x' option to specify the byte size to watch for. "
"If no '-w' option is specified, it defaults to read_write. "
"Note that hardware resources for watching are often limited.",
NULL,
eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
m_option_group (interpreter),
- m_option_watchpoint()
+ m_option_watchpoint (),
+ m_command_options ()
{
SetHelpLong(
"Examples: \n\
\n\
- watchpoint set -w read_wriate my_global_var \n\
- # Watch my_global_var for read/write access.\n\
+ watchpoint set -w read_wriate -v my_global_var \n\
+ # Watch my_global_var for read/write access, with the region to watch corresponding to the byte size of the data type.\n\
\n\
- watchpoint set -w write -x 1 foo + 32\n\
- # Watch write access for the 1-byte region pointed to by the address 'foo + 32'.\n");
+ watchpoint set -w write -x 1 -e foo + 32\n\
+ # Watch write access for the 1-byte region pointed to by the address 'foo + 32'.\n\
+ # If no '-x' option is specified, byte size defaults to 4.\n");
CommandArgumentEntry arg;
CommandArgumentData var_name_arg, expression_arg;
// Define the first variant of this arg.
- var_name_arg.arg_type = eArgTypeVarName;
- var_name_arg.arg_repetition = eArgRepeatPlain;
-
- // Define the second variant of this arg.
expression_arg.arg_type = eArgTypeExpression;
expression_arg.arg_repetition = eArgRepeatPlain;
+ expression_arg.arg_opt_set_association = LLDB_OPT_SET_1;
+ // Define the second variant of this arg.
+ var_name_arg.arg_type = eArgTypeVarName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+ var_name_arg.arg_opt_set_association = LLDB_OPT_SET_2;
+
// Push the two variants into the argument entry.
- arg.push_back (var_name_arg);
arg.push_back (expression_arg);
+ arg.push_back (var_name_arg);
- // Push the data for the first argument into the m_arguments vector.
+ // Push the data for the only argument into the m_arguments vector.
m_arguments.push_back (arg);
-
- m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+
+ // Absorb the '-w' and '-x' options.
+ m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_1, LLDB_OPT_SET_1|LLDB_OPT_SET_2);
+ m_option_group.Append (&m_command_options);
m_option_group.Finalize();
}
@@ -930,35 +1000,25 @@ CommandObjectWatchpointSet::Execute
return false;
}
- // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList
- // for the thread. So hold onto a shared pointer to the frame so it stays alive.
- bool get_file_globals = true;
- VariableList *variable_list = frame->GetVariableList (get_file_globals);
+ // If no argument is present, issue an error message. There's no way to set a watchpoint.
+ if (command.GetArgumentCount() <= 0)
+ {
+ result.GetErrorStream().Printf("error: required argument missing; specify your program variable ('-v') or an address ('-e') to watch for\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // It's either '-e' to watch an address with expression' or '-v' to watch a variable.
+ bool watch_address = m_command_options.m_do_expression;
- bool watch_address = (m_option_watchpoint.watch_size > 0);
-
// If no '-w' is specified, default to '-w read_write'.
if (!m_option_watchpoint.watch_variable)
{
m_option_watchpoint.watch_variable = true;
m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchReadWrite;
}
- // It's possible to specify an address to watch for with the '-x' option.
- if (!variable_list && !watch_address)
- {
- result.GetErrorStream().Printf("error: no variables found, did you forget to use '-x' option to watch an address?\n");
- result.SetStatus(eReturnStatusFailed);
- return false;
- }
- // If thre's no argument, it is an error.
- if (command.GetArgumentCount() <= 0)
- {
- result.GetErrorStream().Printf("error: specify your target variable (no '-x') or expression (with '-x') to watch for\n");
- result.SetStatus(eReturnStatusFailed);
- return false;
- }
- // We passed the sanity check for the options.
+ // We passed the sanity check for the command.
// Proceed to set the watchpoint now.
lldb::addr_t addr = 0;
size_t size = 0;
@@ -968,6 +1028,7 @@ CommandObjectWatchpointSet::Execute
Stream &output_stream = result.GetOutputStream();
if (watch_address) {
+ // Use expression evaluation to arrive at the address to watch.
std::string expr_str;
command.GetQuotedCommandString(expr_str);
const bool coerce_to_id = true;
@@ -983,6 +1044,7 @@ CommandObjectWatchpointSet::Execute
valobj_sp);
if (expr_result != eExecutionCompleted) {
result.GetErrorStream().Printf("error: expression evaluation of address to watch failed\n");
+ result.GetErrorStream().Printf("expression evaluated: %s\n", expr_str.c_str());
result.SetStatus(eReturnStatusFailed);
}
@@ -993,11 +1055,12 @@ CommandObjectWatchpointSet::Execute
result.SetStatus(eReturnStatusFailed);
return false;
}
- size = m_option_watchpoint.watch_size;
+ size = m_option_watchpoint.watch_size == 0 ? 4 /* Could use a better default size? */
+ : m_option_watchpoint.watch_size;
} else {
// A simple watch variable gesture allows only one argument.
- if (m_option_watchpoint.watch_size == 0 && command.GetArgumentCount() != 1) {
- result.GetErrorStream().Printf("error: specify exactly one variable with the '-w' option, i.e., no '-x'\n");
+ if (command.GetArgumentCount() != 1) {
+ result.GetErrorStream().Printf("error: specify exactly one variable with the '-v' option\n");
result.SetStatus(eReturnStatusFailed);
return false;
}
@@ -1016,7 +1079,8 @@ CommandObjectWatchpointSet::Execute
if (addr_type == eAddressTypeLoad) {
// We're in business.
// Find out the size of this variable.
- size = valobj_sp->GetByteSize();
+ size = m_option_watchpoint.watch_size == 0 ? valobj_sp->GetByteSize()
+ : m_option_watchpoint.watch_size;
}
} else {
const char *error_cstr = error.AsCString(NULL);
@@ -1045,7 +1109,8 @@ CommandObjectWatchpointSet::Execute
output_stream.EOL();
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
- result.AppendErrorWithFormat("Watchpoint creation failed.\n");
+ result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%llx, size=%lu).\n",
+ addr, size);
result.SetStatus(eReturnStatusFailed);
}
diff --git a/lldb/source/Commands/CommandObjectWatchpoint.h b/lldb/source/Commands/CommandObjectWatchpoint.h
index c61ebf44d3a..ff8d613abd2 100644
--- a/lldb/source/Commands/CommandObjectWatchpoint.h
+++ b/lldb/source/Commands/CommandObjectWatchpoint.h
@@ -251,6 +251,36 @@ class CommandObjectWatchpointSet : public CommandObject
{
public:
+ class CommandOptions : public OptionGroup
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ bool m_do_expression;
+ bool m_do_variable;
+ };
+
CommandObjectWatchpointSet (CommandInterpreter &interpreter);
virtual
@@ -266,6 +296,7 @@ public:
private:
OptionGroupOptions m_option_group;
OptionGroupWatchpoint m_option_watchpoint;
+ CommandOptions m_command_options;
};
} // namespace lldb_private
diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp
index 7624e860691..5618b6ccc3f 100644
--- a/lldb/source/Interpreter/CommandObject.cpp
+++ b/lldb/source/Interpreter/CommandObject.cpp
@@ -535,15 +535,30 @@ CommandObject::IsPairType (ArgumentRepetitionType arg_repeat_type)
return false;
}
+static CommandObject::CommandArgumentEntry
+OptSetFiltered(uint32_t opt_set_mask, CommandObject::CommandArgumentEntry &cmd_arg_entry)
+{
+ CommandObject::CommandArgumentEntry ret_val;
+ for (unsigned i = 0; i < cmd_arg_entry.size(); ++i)
+ if (opt_set_mask & cmd_arg_entry[i].arg_opt_set_association)
+ ret_val.push_back(cmd_arg_entry[i]);
+ return ret_val;
+}
+
+// Default parameter value of opt_set_mask is LLDB_OPT_SET_ALL, which means take
+// all the argument data into account. On rare cases where some argument sticks
+// with certain option sets, this function returns the option set filtered args.
void
-CommandObject::GetFormattedCommandArguments (Stream &str)
+CommandObject::GetFormattedCommandArguments (Stream &str, uint32_t opt_set_mask)
{
int num_args = m_arguments.size();
for (int i = 0; i < num_args; ++i)
{
if (i > 0)
str.Printf (" ");
- CommandArgumentEntry arg_entry = m_arguments[i];
+ CommandArgumentEntry arg_entry =
+ opt_set_mask == LLDB_OPT_SET_ALL ? m_arguments[i]
+ : OptSetFiltered(opt_set_mask, m_arguments[i]);
int num_alternatives = arg_entry.size();
if ((num_alternatives == 2)
diff --git a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
index 159d00eea7f..4a6afb44c48 100644
--- a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
+++ b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
@@ -40,8 +40,8 @@ static OptionEnumValueElement g_watch_size[] =
static OptionDefinition
g_option_table[] =
{
- { LLDB_OPT_SET_1, false, "watch", 'w', required_argument, g_watch_type, 0, eArgTypeWatchType, "Determine how to watch a variable; or, with -x option, its pointee."},
- { LLDB_OPT_SET_1, false, "xsize", 'x', required_argument, g_watch_size, 0, eArgTypeByteSize, "Number of bytes to use to watch the pointee."}
+ { LLDB_OPT_SET_1, false, "watch", 'w', required_argument, g_watch_type, 0, eArgTypeWatchType, "Specify the type of watching to perform."},
+ { LLDB_OPT_SET_1, false, "xsize", 'x', required_argument, g_watch_size, 0, eArgTypeByteSize, "Number of bytes to use to watch a region."}
};
diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp
index 09b17a8eb25..daf631f3b05 100644
--- a/lldb/source/Interpreter/Options.cpp
+++ b/lldb/source/Interpreter/Options.cpp
@@ -437,6 +437,10 @@ Options::GenerateOptionUsage
strm.Printf ("\n");
strm.Indent (name);
+ // Different option sets may require different args.
+ StreamString args_str;
+ cmd->GetFormattedCommandArguments(args_str, opt_set_mask);
+
// First go through and print all options that take no arguments as
// a single string. If a command has "-a" "-b" and "-c", this will show
// up as [-abc]
@@ -556,12 +560,12 @@ Options::GenerateOptionUsage
}
}
- if (arguments_str.GetSize() > 0)
+ if (args_str.GetSize() > 0)
{
if (cmd->WantsRawCommandString())
strm.Printf(" --");
- strm.Printf (" %s", arguments_str.GetData());
+ strm.Printf (" %s", args_str.GetData());
}
}
diff --git a/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py b/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
index 30ba801b318..cfc5f60e16e 100644
--- a/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
+++ b/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
@@ -75,7 +75,7 @@ class HelloWatchpointTestCase(TestBase):
substrs = ['Watchpoint created', 'size = 4', 'type = w',
'%s:%d' % (self.source, self.decl)])
else:
- self.expect("watchpoint set -w write global", WATCHPOINT_CREATED,
+ self.expect("watchpoint set -w write -v global", WATCHPOINT_CREATED,
substrs = ['Watchpoint created', 'size = 4', 'type = w',
'%s:%d' % (self.source, self.decl)])
diff --git a/lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py b/lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py
index de9016f5cb3..74fc12a481e 100644
--- a/lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py
+++ b/lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py
@@ -60,7 +60,7 @@ class WatchLocationUsingWatchpointSetTestCase(TestBase):
# with offset as 7.
# The main.cpp, by design, misbehaves by not following the agreed upon
# protocol of only accessing the allowable index range of [0, 6].
- self.expect("watchpoint set -w write -x 1 g_char_ptr + 7", WATCHPOINT_CREATED,
+ self.expect("watchpoint set -w write -x 1 -e g_char_ptr + 7", WATCHPOINT_CREATED,
substrs = ['Watchpoint created', 'size = 1', 'type = w'])
self.runCmd("expr unsigned val = g_char_ptr[7]; val")
self.expect(self.res.GetOutput().splitlines()[0], exe=False,
diff --git a/lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchpointSetErrorCases.py b/lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchpointSetErrorCases.py
index 3ff21478460..299e2aec9b6 100644
--- a/lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchpointSetErrorCases.py
+++ b/lldb/test/functionalities/watchpoint/watchpoint_set_command/TestWatchpointSetErrorCases.py
@@ -51,9 +51,13 @@ class WatchpointSetErrorTestCase(TestBase):
# No argument is an error.
self.expect("watchpoint set", error=True,
- substrs = ['specify your target variable',
- 'or expression',
- 'to watch for'])
+ startstr = 'error: invalid combination of options for the given command')
+ self.runCmd("watchpoint set -v -w read_write", check=False)
+
+ # 'watchpoint set' now takes a mandatory '-v' or '-e' option to
+ # indicate watching for either variable or address.
+ self.expect("watchpoint set -w write global", error=True,
+ startstr = 'error: invalid combination of options for the given command')
# Wrong size parameter is an error.
self.expect("watchpoint set -x -128", error=True,
diff --git a/lldb/test/help/TestHelp.py b/lldb/test/help/TestHelp.py
index 95bf8167a74..4fe0c77e246 100644
--- a/lldb/test/help/TestHelp.py
+++ b/lldb/test/help/TestHelp.py
@@ -121,6 +121,13 @@ class HelpCommandTestCase(TestBase):
self.expect("help watchpt-id-list",
substrs = ['<watchpt-id-list>'])
+ def test_help_watchpoint_set(self):
+ """Test that 'help watchpoint set' prints out <expr> for the '-e' option
+ and <variable-name> for the '-v' option."""
+ self.expect("help watchpoint set",
+ patterns = ['watchpoint set -e.*<expr>',
+ 'watchpoint set -v.*<variable-name>'])
+
if __name__ == '__main__':
import atexit
OpenPOWER on IntegriCloud