+2020-07-30 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
+
+ * breakpoint.c (set_breakpoint_condition): Update the condition
+ expressions after checking that the input condition string parses
+ successfully and does not contain junk at the end.
+
2020-07-30 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
* breakpoint.c (set_breakpoint_condition): Update the
set_breakpoint_condition (struct breakpoint *b, const char *exp,
int from_tty)
{
- if (is_watchpoint (b))
- {
- struct watchpoint *w = (struct watchpoint *) b;
-
- w->cond_exp.reset ();
- }
- else
+ if (*exp == 0)
{
- struct bp_location *loc;
+ xfree (b->cond_string);
+ b->cond_string = nullptr;
- for (loc = b->loc; loc; loc = loc->next)
+ if (is_watchpoint (b))
{
- loc->cond.reset ();
+ struct watchpoint *w = (struct watchpoint *) b;
- /* No need to free the condition agent expression
- bytecode (if we have one). We will handle this
- when we go through update_global_location_list. */
+ w->cond_exp.reset ();
}
- }
+ else
+ {
+ struct bp_location *loc;
- if (*exp == 0)
- {
- xfree (b->cond_string);
- b->cond_string = nullptr;
+ for (loc = b->loc; loc; loc = loc->next)
+ {
+ loc->cond.reset ();
+
+ /* No need to free the condition agent expression
+ bytecode (if we have one). We will handle this
+ when we go through update_global_location_list. */
+ }
+ }
if (from_tty)
printf_filtered (_("Breakpoint %d now unconditional.\n"), b->number);
innermost_block_tracker tracker;
arg = exp;
- w->cond_exp = parse_exp_1 (&arg, 0, 0, 0, &tracker);
+ expression_up new_exp = parse_exp_1 (&arg, 0, 0, 0, &tracker);
if (*arg)
error (_("Junk at end of expression"));
+ w->cond_exp = std::move (new_exp);
w->cond_exp_valid_block = tracker.block ();
}
else
{
struct bp_location *loc;
+ /* Parse and set condition expressions. We make two passes.
+ In the first, we parse the condition string to see if it
+ is valid in all locations. If so, the condition would be
+ accepted. So we go ahead and set the locations'
+ conditions. In case a failing case is found, we throw
+ the error and the condition string will be rejected.
+ This two-pass approach is taken to avoid setting the
+ state of locations in case of a reject. */
+ for (loc = b->loc; loc; loc = loc->next)
+ {
+ arg = exp;
+ parse_exp_1 (&arg, loc->address,
+ block_for_pc (loc->address), 0);
+ if (*arg != 0)
+ error (_("Junk at end of expression"));
+ }
+
+ /* If we reach here, the condition is valid at all locations. */
for (loc = b->loc; loc; loc = loc->next)
{
arg = exp;
loc->cond =
parse_exp_1 (&arg, loc->address,
block_for_pc (loc->address), 0);
- if (*arg)
- error (_("Junk at end of expression"));
}
}
+2020-07-30 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
+
+ * gdb.base/condbreak-bad.exp: Extend the test with scenarios
+ that attempt to overwrite an existing condition with a condition
+ that fails parsing and also with a condition that parses fine
+ but contains junk at the end.
+
2020-07-30 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
* gdb.base/condbreak-bad.c: New test.
"${decimal}${fill}breakpoint${fill}keep y${fill}:${bp_location}"] \
"breakpoint is unconditional"
+# Now define a valid condition. Attempt to override that with a 'bad'
+# condition again. The condition should be preserved.
+with_test_prefix "with run" {
+ gdb_test_no_output "cond $bpnum a == 10"
+
+ gdb_test "cond $bpnum gibberish" \
+ "No symbol \"gibberish\" in current context." \
+ "attempt a bad condition"
+
+ gdb_test "info break" \
+ [multi_line \
+ "Num${fill}What" \
+ "${decimal}${fill}breakpoint${fill}keep y${fill}:${bp_location}" \
+ "${fill}stop only if a == 10${fill}"] \
+ "breakpoint condition is preserved"
+
+ # Run the code. We should hit the breakpoint, because the
+ # condition evaluates to true.
+
+ gdb_run_cmd
+ gdb_test "" ".*reakpoint .*, main .*${srcfile}.*" "run to the bp"
+}
+
+# Restart. Repeat the test above after the program has started.
+# This is needed to check a scenario where the breakpoints are no
+# longer re-inserted due to solib events. Note that runto_main
+# deletes the breakpoints.
+with_test_prefix "with continue 1" {
+ if {![runto_main]} {
+ fail "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint "$bp_location"
+ set bpnum [get_integer_valueof "\$bpnum" 0 "get bpnum"]
+
+ gdb_test_no_output "cond $bpnum a == 10"
+
+ gdb_test "cond $bpnum gibberish" \
+ "No symbol \"gibberish\" in current context." \
+ "attempt a bad condition"
+
+ # Resume. We should hit the breakpoint, because the
+ # condition evaluates to true.
+ gdb_continue_to_breakpoint "${srcfile}:${bp_location}"
+}
+
+# Repeat with a condition that evaluates to false.
+with_test_prefix "with continue 2" {
+ if {![runto_main]} {
+ fail "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint "$bp_location"
+ set bpnum [get_integer_valueof "\$bpnum" 0 "get bpnum"]
+
+ gdb_test_no_output "cond $bpnum a == 999"
+
+ gdb_test "cond $bpnum gibberish" \
+ "No symbol \"gibberish\" in current context." \
+ "attempt a bad condition"
+
+ # Resume. We should *not* hit the breakpoint, because the
+ # condition evaluates to false.
+ gdb_continue_to_end
+}
+
+# Repeat with a condition that contains junk at the end.
+with_test_prefix "with junk" {
+ if {![runto_main]} {
+ fail "could not run to main"
+ return -1
+ }
+
+ gdb_breakpoint "$bp_location"
+ set bpnum [get_integer_valueof "\$bpnum" 0 "get bpnum"]
+
+ gdb_test_no_output "cond $bpnum a == 999"
+
+ gdb_test "cond $bpnum a == 10 if" \
+ "Junk at end of expression" \
+ "attempt a bad condition"
+
+ # Resume. We should *not* hit the breakpoint, because the
+ # condition evaluates to false.
+ gdb_continue_to_end
+}