/* Everything about breakpoints, for GDB.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- Free Software Foundation, Inc.
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ 2008 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include <ctype.h>
+#include "hashtab.h"
#include "symtab.h"
#include "frame.h"
#include "breakpoint.h"
#include "memattr.h"
#include "ada-lang.h"
#include "top.h"
+#include "wrapper.h"
#include "gdb-events.h"
#include "mi/mi-common.h"
static int can_use_hardware_watchpoint (struct value *);
-static int break_command_1 (char *, int, int, struct breakpoint *);
+static void break_command_1 (char *, int, int);
static void mention (struct breakpoint *);
static void breakpoint_1 (int, int);
-static bpstat bpstat_alloc (struct bp_location *, bpstat);
+static bpstat bpstat_alloc (const struct bp_location *, bpstat);
static int breakpoint_cond_eval (void *);
static int watchpoint_check (void *);
-static int cover_target_enable_exception_callback (void *);
-
static void maintenance_info_breakpoints (char *, int);
static void create_longjmp_breakpoint (char *);
static void free_bp_location (struct bp_location *loc);
+static void mark_breakpoints_out (void);
+
+static struct bp_location *
+allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type);
+
+static void
+unlink_locations_from_global_list (struct breakpoint *bpt);
+
+static int
+is_hardware_watchpoint (struct breakpoint *bpt);
+
/* Prototypes for exported functions. */
/* If FALSE, gdb will not use hardware support for watchpoints, even
error (_("No breakpoint number %d."), bnum);
}
\f
-/* Like target_read_memory() but if breakpoints are inserted, return
- the shadow contents instead of the breakpoints themselves.
+/* Update BUF, which is LEN bytes read from the target address MEMADDR,
+ by replacing any memory breakpoints with their shadowed contents. */
- Read "memory data" from whatever target or inferior we have.
- Returns zero if successful, errno value if not. EIO is used
- for address out of bounds. If breakpoints are inserted, returns
- shadow contents, not the breakpoints themselves. From breakpoint.c. */
-
-int
-read_memory_nobpt (CORE_ADDR memaddr, gdb_byte *myaddr, unsigned len)
+void
+breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr, LONGEST len)
{
- int status;
struct bp_location *b;
CORE_ADDR bp_addr = 0;
int bp_size = 0;
-
- if (gdbarch_breakpoint_from_pc (current_gdbarch, &bp_addr, &bp_size) == NULL)
- /* No breakpoints on this machine. */
- return target_read_memory (memaddr, myaddr, len);
+ int bptoffset = 0;
ALL_BP_LOCATIONS (b)
{
if (bp_size == 0)
/* bp isn't valid, or doesn't shadow memory. */
continue;
+
if (bp_addr + bp_size <= memaddr)
/* The breakpoint is entirely before the chunk of memory we
are reading. */
continue;
+
if (bp_addr >= memaddr + len)
/* The breakpoint is entirely after the chunk of memory we are
reading. */
continue;
- /* Copy the breakpoint from the shadow contents, and recurse for
- the things before and after. */
- {
- /* Offset within shadow_contents. */
- int bptoffset = 0;
-
- if (bp_addr < memaddr)
- {
- /* Only copy the second part of the breakpoint. */
- bp_size -= memaddr - bp_addr;
- bptoffset = memaddr - bp_addr;
- bp_addr = memaddr;
- }
-
- if (bp_addr + bp_size > memaddr + len)
- {
- /* Only copy the first part of the breakpoint. */
- bp_size -= (bp_addr + bp_size) - (memaddr + len);
- }
- memcpy (myaddr + bp_addr - memaddr,
- b->target_info.shadow_contents + bptoffset, bp_size);
+ /* Offset within shadow_contents. */
+ if (bp_addr < memaddr)
+ {
+ /* Only copy the second part of the breakpoint. */
+ bp_size -= memaddr - bp_addr;
+ bptoffset = memaddr - bp_addr;
+ bp_addr = memaddr;
+ }
- if (bp_addr > memaddr)
- {
- /* Copy the section of memory before the breakpoint. */
- status = read_memory_nobpt (memaddr, myaddr, bp_addr - memaddr);
- if (status != 0)
- return status;
- }
+ if (bp_addr + bp_size > memaddr + len)
+ {
+ /* Only copy the first part of the breakpoint. */
+ bp_size -= (bp_addr + bp_size) - (memaddr + len);
+ }
- if (bp_addr + bp_size < memaddr + len)
- {
- /* Copy the section of memory after the breakpoint. */
- status = read_memory_nobpt (bp_addr + bp_size,
- myaddr + bp_addr + bp_size - memaddr,
- memaddr + len - (bp_addr + bp_size));
- if (status != 0)
- return status;
- }
- return 0;
- }
+ memcpy (buf + bp_addr - memaddr,
+ b->target_info.shadow_contents + bptoffset, bp_size);
}
- /* Nothing overlaps. Just call read_memory_noerr. */
- return target_read_memory (memaddr, myaddr, len);
}
\f
}
}
-/* Helper routine: free the value chain for a breakpoint (watchpoint). */
+static int
+is_hardware_watchpoint (struct breakpoint *bpt)
+{
+ return (bpt->type == bp_hardware_watchpoint
+ || bpt->type == bp_read_watchpoint
+ || bpt->type == bp_access_watchpoint);
+}
+
+/* Find the current value of a watchpoint on EXP. Return the value in
+ *VALP and *RESULTP and the chain of intermediate and final values
+ in *VAL_CHAIN. RESULTP and VAL_CHAIN may be NULL if the caller does
+ not need them.
+
+ If an error occurs while evaluating the expression, *RESULTP will
+ be set to NULL. *RESULTP may be a lazy value, if the result could
+ not be read from memory. It is used to determine whether a value
+ is user-specified (we should watch the whole value) or intermediate
+ (we should watch only the bit used to locate the final value).
+
+ If the final value, or any intermediate value, could not be read
+ from memory, *VALP will be set to NULL. *VAL_CHAIN will still be
+ set to any referenced values. *VALP will never be a lazy value.
+ This is the value which we store in struct breakpoint.
+
+ If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
+ value chain. The caller must free the values individually. If
+ VAL_CHAIN is NULL, all generated values will be left on the value
+ chain. */
+
+static void
+fetch_watchpoint_value (struct expression *exp, struct value **valp,
+ struct value **resultp, struct value **val_chain)
+{
+ struct value *mark, *new_mark, *result;
+
+ *valp = NULL;
+ if (resultp)
+ *resultp = NULL;
+ if (val_chain)
+ *val_chain = NULL;
+
+ /* Evaluate the expression. */
+ mark = value_mark ();
+ result = NULL;
+ gdb_evaluate_expression (exp, &result);
+ new_mark = value_mark ();
+ if (mark == new_mark)
+ return;
+ if (resultp)
+ *resultp = result;
+
+ /* Make sure it's not lazy, so that after the target stops again we
+ have a non-lazy previous value to compare with. */
+ if (result != NULL
+ && (!value_lazy (result) || gdb_value_fetch_lazy (result)))
+ *valp = result;
+
+ if (val_chain)
+ {
+ /* Return the chain of intermediate values. We use this to
+ decide which addresses to watch. */
+ *val_chain = new_mark;
+ value_release_to_mark (mark);
+ }
+}
+
+/* Assuming that B is a hardware watchpoint:
+ - Reparse watchpoint expression, is REPARSE is non-zero
+ - Evaluate expression and store the result in B->val
+ - Update the list of values that must be watched in B->loc.
+ If the watchpoint is disabled, do nothing. If this is
+ local watchpoint that is out of scope, delete it. */
static void
-free_valchain (struct bp_location *b)
+update_watchpoint (struct breakpoint *b, int reparse)
{
- struct value *v;
- struct value *n;
+ int within_current_scope;
+ struct frame_id saved_frame_id;
+ struct bp_location *loc;
+ bpstat bs;
+
+ unlink_locations_from_global_list (b);
+ for (loc = b->loc; loc;)
+ {
+ struct bp_location *loc_next = loc->next;
+ remove_breakpoint (loc, mark_uninserted);
+ xfree (loc);
+ loc = loc_next;
+ }
+ b->loc = NULL;
+
+ if (b->disposition == disp_del_at_next_stop)
+ return;
+
+ /* Save the current frame's ID so we can restore it after
+ evaluating the watchpoint expression on its own frame. */
+ /* FIXME drow/2003-09-09: It would be nice if evaluate_expression
+ took a frame parameter, so that we didn't have to change the
+ selected frame. */
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+
+ /* Determine if the watchpoint is within scope. */
+ if (b->exp_valid_block == NULL)
+ within_current_scope = 1;
+ else
+ {
+ struct frame_info *fi;
+ fi = frame_find_by_id (b->watchpoint_frame);
+ within_current_scope = (fi != NULL);
+ if (within_current_scope)
+ select_frame (fi);
+ }
+
+ if (within_current_scope && reparse)
+ {
+ char *s;
+ if (b->exp)
+ {
+ xfree (b->exp);
+ b->exp = NULL;
+ }
+ s = b->exp_string;
+ b->exp = parse_exp_1 (&s, b->exp_valid_block, 0);
+ /* If the meaning of expression itself changed, the old value is
+ no longer relevant. We don't want to report a watchpoint hit
+ to the user when the old value and the new value may actually
+ be completely different objects. */
+ value_free (b->val);
+ b->val = NULL;
+ b->val_valid = 0;
+ }
+
+ /* If we failed to parse the expression, for example because
+ it refers to a global variable in a not-yet-loaded shared library,
+ don't try to insert watchpoint. We don't automatically delete
+ such watchpoint, though, since failure to parse expression
+ is different from out-of-scope watchpoint. */
+ if (within_current_scope && b->exp)
+ {
+ struct value *val_chain, *v, *result, *next;
+
+ fetch_watchpoint_value (b->exp, &v, &result, &val_chain);
+
+ /* Avoid setting b->val if it's already set. The meaning of
+ b->val is 'the last value' user saw, and we should update
+ it only if we reported that last value to user. As it
+ happens, the code that reports it updates b->val directly. */
+ if (!b->val_valid)
+ {
+ b->val = v;
+ b->val_valid = 1;
+ }
+
+ /* Look at each value on the value chain. */
+ for (v = val_chain; v; v = next)
+ {
+ /* If it's a memory location, and GDB actually needed
+ its contents to evaluate the expression, then we
+ must watch it. If the first value returned is
+ still lazy, that means an error occurred reading it;
+ watch it anyway in case it becomes readable. */
+ if (VALUE_LVAL (v) == lval_memory
+ && (v == val_chain || ! value_lazy (v)))
+ {
+ struct type *vtype = check_typedef (value_type (v));
+
+ /* We only watch structs and arrays if user asked
+ for it explicitly, never if they just happen to
+ appear in the middle of some value chain. */
+ if (v == result
+ || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+ && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+ {
+ CORE_ADDR addr;
+ int len, type;
+ struct bp_location *loc, **tmp;
+
+ addr = VALUE_ADDRESS (v) + value_offset (v);
+ len = TYPE_LENGTH (value_type (v));
+ type = hw_write;
+ if (b->type == bp_read_watchpoint)
+ type = hw_read;
+ else if (b->type == bp_access_watchpoint)
+ type = hw_access;
+
+ loc = allocate_bp_location (b, bp_hardware_watchpoint);
+ for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
+ ;
+ *tmp = loc;
+ loc->address = addr;
+ loc->length = len;
+ loc->watchpoint_type = type;
+ }
+ }
+
+ next = value_next (v);
+ if (v != b->val)
+ value_free (v);
+ }
- /* Free the saved value chain. We will construct a new one
- the next time the watchpoint is inserted. */
- for (v = b->owner->val_chain; v; v = n)
+ if (reparse && b->cond_string != NULL)
+ {
+ char *s = b->cond_string;
+ if (b->loc->cond)
+ {
+ xfree (b->loc->cond);
+ b->loc->cond = NULL;
+ }
+ b->loc->cond = parse_exp_1 (&s, b->exp_valid_block, 0);
+ }
+ }
+ else if (!within_current_scope)
{
- n = value_next (v);
- value_free (v);
+ printf_filtered (_("\
+Hardware watchpoint %d deleted because the program has left the block \n\
+in which its expression is valid.\n"),
+ b->number);
+ if (b->related_breakpoint)
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->disposition = disp_del_at_next_stop;
}
- b->owner->val_chain = NULL;
+
+ /* Restore the selected frame. */
+ select_frame (frame_find_by_id (saved_frame_id));
}
+
/* Insert a low-level "breakpoint" of some type. BPT is the breakpoint.
Any error messages are printed to TMP_ERROR_STREAM; and DISABLED_BREAKS,
PROCESS_WARNING, and HW_BREAKPOINT_ERROR are used to report problems.
{
int val = 0;
- /* Permanent breakpoints cannot be inserted or removed. Disabled
- breakpoints should not be inserted. */
if (!breakpoint_enabled (bpt->owner))
return 0;
bpt->owner->number);
fprintf_filtered (tmp_error_stream,
"Error accessing memory address ");
- deprecated_print_address_numeric (bpt->address, 1, tmp_error_stream);
+ fputs_filtered (paddress (bpt->address), tmp_error_stream);
fprintf_filtered (tmp_error_stream, ": %s.\n",
safe_strerror (val));
}
watchpoints. It's not clear that it's necessary... */
&& bpt->owner->disposition != disp_del_at_next_stop)
{
- /* FIXME drow/2003-09-08: This code sets multiple hardware watchpoints
- based on the expression. Ideally this should happen at a higher level,
- and there should be one bp_location for each computed address we
- must watch. As soon as a many-to-one mapping is available I'll
- convert this. */
-
- int within_current_scope;
- struct value *mark = value_mark ();
- struct value *v;
- struct frame_id saved_frame_id;
-
- /* Save the current frame's ID so we can restore it after
- evaluating the watchpoint expression on its own frame. */
- /* FIXME drow/2003-09-09: It would be nice if evaluate_expression
- took a frame parameter, so that we didn't have to change the
- selected frame. */
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
-
- /* Determine if the watchpoint is within scope. */
- if (bpt->owner->exp_valid_block == NULL)
- within_current_scope = 1;
- else
- {
- struct frame_info *fi;
- fi = frame_find_by_id (bpt->owner->watchpoint_frame);
- within_current_scope = (fi != NULL);
- if (within_current_scope)
- select_frame (fi);
- }
-
- if (within_current_scope)
- {
- free_valchain (bpt);
-
- /* Evaluate the expression and cut the chain of values
- produced off from the value chain.
-
- Make sure the value returned isn't lazy; we use
- laziness to determine what memory GDB actually needed
- in order to compute the value of the expression. */
- v = evaluate_expression (bpt->owner->exp);
- value_contents (v);
- value_release_to_mark (mark);
-
- bpt->owner->val_chain = v;
- bpt->inserted = 1;
-
- /* Look at each value on the value chain. */
- for (; v; v = value_next (v))
- {
- /* If it's a memory location, and GDB actually needed
- its contents to evaluate the expression, then we
- must watch it. */
- if (VALUE_LVAL (v) == lval_memory
- && ! value_lazy (v))
- {
- struct type *vtype = check_typedef (value_type (v));
-
- /* We only watch structs and arrays if user asked
- for it explicitly, never if they just happen to
- appear in the middle of some value chain. */
- if (v == bpt->owner->val_chain
- || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
- && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
- {
- CORE_ADDR addr;
- int len, type;
-
- addr = VALUE_ADDRESS (v) + value_offset (v);
- len = TYPE_LENGTH (value_type (v));
- type = hw_write;
- if (bpt->owner->type == bp_read_watchpoint)
- type = hw_read;
- else if (bpt->owner->type == bp_access_watchpoint)
- type = hw_access;
-
- val = target_insert_watchpoint (addr, len, type);
- if (val == -1)
- {
- /* Don't exit the loop, try to insert
- every value on the value chain. That's
- because we will be removing all the
- watches below, and removing a
- watchpoint we didn't insert could have
- adverse effects. */
- bpt->inserted = 0;
- }
- val = 0;
- }
- }
- }
- /* Failure to insert a watchpoint on any memory value in the
- value chain brings us here. */
- if (!bpt->inserted)
- {
- remove_breakpoint (bpt, mark_uninserted);
- *hw_breakpoint_error = 1;
- fprintf_unfiltered (tmp_error_stream,
- "Could not insert hardware watchpoint %d.\n",
- bpt->owner->number);
- val = -1;
- }
- }
- else
- {
- printf_filtered (_("\
-Hardware watchpoint %d deleted because the program has left the block \n\
-in which its expression is valid.\n"),
- bpt->owner->number);
- if (bpt->owner->related_breakpoint)
- bpt->owner->related_breakpoint->disposition = disp_del_at_next_stop;
- bpt->owner->disposition = disp_del_at_next_stop;
- }
-
- /* Restore the selected frame. */
- select_frame (frame_find_by_id (saved_frame_id));
-
- return val;
- }
-
- else if (ep_is_exception_catchpoint (bpt->owner))
- {
- /* FIXME drow/2003-09-09: This code sets both a catchpoint and a
- breakpoint. Once again, it would be better if this was represented
- as two bp_locations. */
-
- /* If we get here, we must have a callback mechanism for exception
- events -- with g++ style embedded label support, we insert
- ordinary breakpoints and not catchpoints. */
- val = target_insert_breakpoint (&bpt->target_info);
- if (val)
- {
- /* Couldn't set breakpoint for some reason */
- fprintf_unfiltered (tmp_error_stream,
- "Cannot insert catchpoint %d; disabling it.\n",
- bpt->owner->number);
- fprintf_filtered (tmp_error_stream,
- "Error accessing memory address ");
- deprecated_print_address_numeric (bpt->address, 1, tmp_error_stream);
- fprintf_filtered (tmp_error_stream, ": %s.\n",
- safe_strerror (val));
- bpt->owner->enable_state = bp_disabled;
- }
- else
- {
- /* Bp set, now make sure callbacks are enabled */
- /* Format possible error msg */
- char *message = xstrprintf ("Error inserting catchpoint %d:\n",
- bpt->owner->number);
- struct cleanup *cleanups = make_cleanup (xfree, message);
- int val;
- args_for_catchpoint_enable args;
- args.kind = bpt->owner->type == bp_catch_catch ?
- EX_EVENT_CATCH : EX_EVENT_THROW;
- args.enable_p = 1;
- val = catch_errors (cover_target_enable_exception_callback,
- &args, message, RETURN_MASK_ALL);
- do_cleanups (cleanups);
- if (val != 0 && val != -1)
- bpt->inserted = 1;
-
- /* Check if something went wrong; val == 0 can be ignored */
- if (val == -1)
- {
- /* something went wrong */
- fprintf_unfiltered (tmp_error_stream,
- "Cannot insert catchpoint %d; disabling it.\n",
- bpt->owner->number);
- bpt->owner->enable_state = bp_disabled;
- }
- }
-
- return val;
+ val = target_insert_watchpoint (bpt->address,
+ bpt->length,
+ bpt->watchpoint_type);
+ bpt->inserted = (val != -1);
}
else if (bpt->owner->type == bp_catch_fork
Both return zero if successful,
or an `errno' value if could not write the inferior. */
-int
+void
insert_breakpoints (void)
{
+ struct breakpoint *bpt;
struct bp_location *b, *temp;
- int return_val = 0; /* return success code. */
+ int error = 0;
int val = 0;
int disabled_breaks = 0;
int hw_breakpoint_error = 0;
there was an error. */
fprintf_unfiltered (tmp_error_stream, "Warning:\n");
+ ALL_BREAKPOINTS (bpt)
+ if (is_hardware_watchpoint (bpt))
+ update_watchpoint (bpt, 0 /* don't reparse */);
+
ALL_BP_LOCATIONS_SAFE (b, temp)
{
- /* Permanent breakpoints cannot be inserted or removed. Disabled
- breakpoints should not be inserted. */
if (!breakpoint_enabled (b->owner))
continue;
&& !valid_thread_id (b->owner->thread))
continue;
- /* FIXME drow/2003-10-07: This code should be pushed elsewhere when
- hardware watchpoints are split into multiple loc breakpoints. */
- if ((b->loc_type == bp_loc_hardware_watchpoint
- || b->owner->type == bp_watchpoint) && !b->owner->val)
- {
- struct value *val;
- val = evaluate_expression (b->owner->exp);
- release_value (val);
- if (value_lazy (val))
- value_fetch_lazy (val);
- b->owner->val = val;
- }
-
val = insert_bp_location (b, tmp_error_stream,
&disabled_breaks, &process_warning,
&hw_breakpoint_error);
if (val)
- return_val = val;
+ error = val;
+ }
+
+ /* If we failed to insert all locations of a watchpoint,
+ remove them, as half-inserted watchpoint is of limited use. */
+ ALL_BREAKPOINTS (bpt)
+ {
+ int some_failed = 0;
+ struct bp_location *loc;
+
+ if (!is_hardware_watchpoint (bpt))
+ continue;
+
+ if (bpt->enable_state != bp_enabled)
+ continue;
+
+ for (loc = bpt->loc; loc; loc = loc->next)
+ if (!loc->inserted)
+ {
+ some_failed = 1;
+ break;
+ }
+ if (some_failed)
+ {
+ for (loc = bpt->loc; loc; loc = loc->next)
+ if (loc->inserted)
+ remove_breakpoint (loc, mark_uninserted);
+
+ hw_breakpoint_error = 1;
+ fprintf_unfiltered (tmp_error_stream,
+ "Could not insert hardware watchpoint %d.\n",
+ bpt->number);
+ error = -1;
+ }
}
- if (return_val)
+ if (error)
{
/* If a hardware breakpoint or watchpoint was inserted, add a
message about possibly exhausted resources. */
target_terminal_ours_for_output ();
error_stream (tmp_error_stream);
}
- return return_val;
}
int
continue;
}
- /* Ditto the exception-handling catchpoints. */
- if ((b->type == bp_catch_catch) || (b->type == bp_catch_throw))
- {
- delete_breakpoint (b);
- continue;
- }
-
/* Don't delete an exec catchpoint, because else the inferior
won't stop when it ought!
return val;
b->inserted = (is == mark_inserted);
}
- else if (b->loc_type == bp_loc_hardware_watchpoint
- && breakpoint_enabled (b->owner)
- && !b->duplicate)
+ else if (b->loc_type == bp_loc_hardware_watchpoint)
{
struct value *v;
struct value *n;
b->inserted = (is == mark_inserted);
- /* Walk down the saved value chain. */
- for (v = b->owner->val_chain; v; v = value_next (v))
- {
- /* For each memory reference remove the watchpoint
- at that address. */
- if (VALUE_LVAL (v) == lval_memory
- && ! value_lazy (v))
- {
- struct type *vtype = check_typedef (value_type (v));
-
- if (v == b->owner->val_chain
- || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
- && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
- {
- CORE_ADDR addr;
- int len, type;
-
- addr = VALUE_ADDRESS (v) + value_offset (v);
- len = TYPE_LENGTH (value_type (v));
- type = hw_write;
- if (b->owner->type == bp_read_watchpoint)
- type = hw_read;
- else if (b->owner->type == bp_access_watchpoint)
- type = hw_access;
+ val = target_remove_watchpoint (b->address, b->length,
+ b->watchpoint_type);
- val = target_remove_watchpoint (addr, len, type);
- if (val == -1)
- b->inserted = 1;
- val = 0;
- }
- }
- }
/* Failure to remove any of the hardware watchpoints comes here. */
if ((is == mark_uninserted) && (b->inserted))
warning (_("Could not remove hardware watchpoint %d."),
return val;
b->inserted = (is == mark_inserted);
}
- else if ((b->owner->type == bp_catch_catch ||
- b->owner->type == bp_catch_throw)
- && breakpoint_enabled (b->owner)
- && !b->duplicate)
- {
- val = target_remove_breakpoint (&b->target_info);
- if (val)
- return val;
- b->inserted = (is == mark_inserted);
- }
return 0;
}
/* Clear the "inserted" flag in all breakpoints. */
-void
+static void
mark_breakpoints_out (void)
{
struct bp_location *bpt;
if (b->val)
value_free (b->val);
b->val = NULL;
+ b->val_valid = 0;
}
break;
default:
enum breakpoint_here
breakpoint_here_p (CORE_ADDR pc)
{
- struct bp_location *bpt;
+ const struct bp_location *bpt;
int any_breakpoint_here = 0;
ALL_BP_LOCATIONS (bpt)
}
-/* breakpoint_inserted_here_p (PC) is just like breakpoint_here_p(),
- but it only returns true if there is actually a breakpoint inserted
- at PC. */
+/* Returns non-zero if there's a breakpoint inserted at PC, which is
+ inserted using regular breakpoint_chain/bp_location_chain mechanism.
+ This does not check for single-step breakpoints, which are
+ inserted and removed using direct target manipulation. */
int
-breakpoint_inserted_here_p (CORE_ADDR pc)
+regular_breakpoint_inserted_here_p (CORE_ADDR pc)
{
- struct bp_location *bpt;
+ const struct bp_location *bpt;
ALL_BP_LOCATIONS (bpt)
{
return 1;
}
}
+ return 0;
+}
+
+/* Returns non-zero iff there's either regular breakpoint
+ or a single step breakpoint inserted at PC. */
+
+int
+breakpoint_inserted_here_p (CORE_ADDR pc)
+{
+ if (regular_breakpoint_inserted_here_p (pc))
+ return 1;
- /* Also check for software single-step breakpoints. */
if (single_step_breakpoint_inserted_here_p (pc))
return 1;
int
software_breakpoint_inserted_here_p (CORE_ADDR pc)
{
- struct bp_location *bpt;
+ const struct bp_location *bpt;
int any_breakpoint_here = 0;
ALL_BP_LOCATIONS (bpt)
int
breakpoint_thread_match (CORE_ADDR pc, ptid_t ptid)
{
- struct bp_location *bpt;
+ const struct bp_location *bpt;
int thread;
thread = pid_to_thread_id (ptid);
|| (ep->type == bp_catch_unload)
|| (ep->type == bp_catch_fork)
|| (ep->type == bp_catch_vfork)
- || (ep->type == bp_catch_exec)
- || (ep->type == bp_catch_catch)
- || (ep->type == bp_catch_throw);
+ || (ep->type == bp_catch_exec);
/* ??rehrauer: Add more kinds here, as are implemented... */
}
|| (ep->type == bp_catch_unload);
}
-int
-ep_is_exception_catchpoint (struct breakpoint *ep)
-{
- return
- (ep->type == bp_catch_catch)
- || (ep->type == bp_catch_throw);
-}
-
void
bpstat_free (bpstat bs)
{
do_cleanups (old_chain);
}
+/* Print out the (old or new) value associated with a watchpoint. */
+
+static void
+watchpoint_value_print (struct value *val, struct ui_file *stream)
+{
+ if (val == NULL)
+ fprintf_unfiltered (stream, _("<unreadable>"));
+ else
+ value_print (val, stream, 0, Val_pretty_default);
+}
+
/* This is the normal print function for a bpstat. In the future,
much of this logic could (should?) be moved to bpstat_stop_status,
by having it set different print_it values.
{
struct cleanup *old_chain, *ui_out_chain;
struct breakpoint *b;
- struct bp_location *bl;
+ const struct bp_location *bl;
struct ui_stream *stb;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
return PRINT_SRC_AND_LOC;
break;
- case bp_catch_catch:
- if (current_exception_event &&
- (CURRENT_EXCEPTION_KIND == EX_EVENT_CATCH))
- {
- annotate_catchpoint (b->number);
- printf_filtered (_("\nCatchpoint %d (exception caught), "),
- b->number);
- if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
- printf_filtered (_("throw location %s:%d, "),
- CURRENT_EXCEPTION_THROW_FILE,
- CURRENT_EXCEPTION_THROW_LINE);
- else
- printf_filtered (_("throw location unknown, "));
-
- if (CURRENT_EXCEPTION_CATCH_PC && CURRENT_EXCEPTION_CATCH_LINE)
- printf_filtered (_("catch location %s:%d\n"),
- CURRENT_EXCEPTION_CATCH_FILE,
- CURRENT_EXCEPTION_CATCH_LINE);
- else
- printf_filtered (_("catch location unknown\n"));
-
- /* don't bother to print location frame info */
- return PRINT_SRC_ONLY;
- }
- else
- {
- /* really throw, some other bpstat will handle it */
- return PRINT_UNKNOWN;
- }
- break;
-
- case bp_catch_throw:
- if (current_exception_event &&
- (CURRENT_EXCEPTION_KIND == EX_EVENT_THROW))
- {
- annotate_catchpoint (b->number);
- printf_filtered (_("\nCatchpoint %d (exception thrown), "),
- b->number);
- if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
- printf_filtered (_("throw location %s:%d, "),
- CURRENT_EXCEPTION_THROW_FILE,
- CURRENT_EXCEPTION_THROW_LINE);
- else
- printf_filtered (_("throw location unknown, "));
-
- if (CURRENT_EXCEPTION_CATCH_PC && CURRENT_EXCEPTION_CATCH_LINE)
- printf_filtered (_("catch location %s:%d\n"),
- CURRENT_EXCEPTION_CATCH_FILE,
- CURRENT_EXCEPTION_CATCH_LINE);
- else
- printf_filtered (_("catch location unknown\n"));
-
- /* don't bother to print location frame info */
- return PRINT_SRC_ONLY;
- }
- else
- {
- /* really catch, some other bpstat will handle it */
- return PRINT_UNKNOWN;
- }
- break;
-
case bp_watchpoint:
case bp_hardware_watchpoint:
- if (bs->old_val != NULL)
- {
- annotate_watchpoint (b->number);
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
- mention (b);
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nOld value = ");
- value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
- ui_out_field_stream (uiout, "old", stb);
- ui_out_text (uiout, "\nNew value = ");
- value_print (b->val, stb->stream, 0, Val_pretty_default);
- ui_out_field_stream (uiout, "new", stb);
- do_cleanups (ui_out_chain);
- ui_out_text (uiout, "\n");
- value_free (bs->old_val);
- bs->old_val = NULL;
- }
+ annotate_watchpoint (b->number);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+ mention (b);
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nOld value = ");
+ watchpoint_value_print (bs->old_val, stb->stream);
+ ui_out_field_stream (uiout, "old", stb);
+ ui_out_text (uiout, "\nNew value = ");
+ watchpoint_value_print (b->val, stb->stream);
+ ui_out_field_stream (uiout, "new", stb);
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, "\n");
/* More than one watchpoint may have been triggered. */
return PRINT_UNKNOWN;
break;
mention (b);
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nValue = ");
- value_print (b->val, stb->stream, 0, Val_pretty_default);
+ watchpoint_value_print (b->val, stb->stream);
ui_out_field_stream (uiout, "value", stb);
do_cleanups (ui_out_chain);
ui_out_text (uiout, "\n");
break;
case bp_access_watchpoint:
- if (bs->old_val != NULL)
+ if (bs->old_val != NULL)
{
annotate_watchpoint (b->number);
if (ui_out_is_mi_like_p (uiout))
mention (b);
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nOld value = ");
- value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
+ watchpoint_value_print (bs->old_val, stb->stream);
ui_out_field_stream (uiout, "old", stb);
- value_free (bs->old_val);
- bs->old_val = NULL;
ui_out_text (uiout, "\nNew value = ");
}
else
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nValue = ");
}
- value_print (b->val, stb->stream, 0,Val_pretty_default);
+ watchpoint_value_print (b->val, stb->stream);
ui_out_field_stream (uiout, "new", stb);
do_cleanups (ui_out_chain);
ui_out_text (uiout, "\n");
case print_it_normal:
{
- struct bp_location *bl = bs->breakpoint_at;
+ const struct bp_location *bl = bs->breakpoint_at;
struct breakpoint *b = bl ? bl->owner : NULL;
/* Normal case. Call the breakpoint's print_it method, or
/* Allocate a new bpstat and chain it to the current one. */
static bpstat
-bpstat_alloc (struct bp_location *bl, bpstat cbs /* Current "bs" value */ )
+bpstat_alloc (const struct bp_location *bl, bpstat cbs /* Current "bs" value */ )
{
bpstat bs;
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint)
{
+ struct bp_location *loc;
struct value *v;
b->watchpoint_triggered = watch_triggered_no;
- for (v = b->val_chain; v; v = value_next (v))
- {
- if (VALUE_LVAL (v) == lval_memory && ! value_lazy (v))
- {
- struct type *vtype = check_typedef (value_type (v));
-
- if (v == b->val_chain
- || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
- && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
- {
- CORE_ADDR vaddr;
-
- vaddr = VALUE_ADDRESS (v) + value_offset (v);
- /* Exact match not required. Within range is
- sufficient. */
- if (addr >= vaddr
- && addr < vaddr + TYPE_LENGTH (value_type (v)))
- {
- b->watchpoint_triggered = watch_triggered_yes;
- break;
- }
- }
- }
- }
+ for (loc = b->loc; loc; loc = loc->next)
+ /* Exact match not required. Within range is
+ sufficient. */
+ if (addr >= loc->address
+ && addr < loc->address + loc->length)
+ {
+ b->watchpoint_triggered = watch_triggered_yes;
+ break;
+ }
}
return 1;
we might be in the middle of evaluating a function call. */
struct value *mark = value_mark ();
- struct value *new_val = evaluate_expression (b->exp);
- if (!value_equal (b->val, new_val))
+ struct value *new_val;
+
+ fetch_watchpoint_value (b->exp, &new_val, NULL, NULL);
+ if ((b->val != NULL) != (new_val != NULL)
+ || (b->val != NULL && !value_equal (b->val, new_val)))
{
- release_value (new_val);
- value_free_to_mark (mark);
+ if (new_val != NULL)
+ {
+ release_value (new_val);
+ value_free_to_mark (mark);
+ }
bs->old_val = b->val;
b->val = new_val;
+ b->val_valid = 1;
/* We will stop here */
return WP_VALUE_CHANGED;
}
bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
{
struct breakpoint *b = NULL;
- struct bp_location *bl;
- /* True if we've hit a breakpoint (as opposed to a watchpoint). */
- int real_breakpoint = 0;
+ const struct bp_location *bl;
/* Root of the chain of bpstat's */
struct bpstats root_bs[1];
/* Pointer to the last thing in the chain currently. */
&& b->type != bp_hardware_breakpoint
&& b->type != bp_catch_fork
&& b->type != bp_catch_vfork
- && b->type != bp_catch_exec
- && b->type != bp_catch_catch
- && b->type != bp_catch_throw) /* a non-watchpoint bp */
+ && b->type != bp_catch_exec) /* a non-watchpoint bp */
{
if (bl->address != bp_addr) /* address doesn't match */
continue;
&& !inferior_has_execd (PIDGET (inferior_ptid), &b->exec_pathname))
continue;
- if (ep_is_exception_catchpoint (b) &&
- !(current_exception_event = target_get_current_exception_event ()))
+ /* For hardware watchpoints, we look only at the first location.
+ The watchpoint_check function will work on entire expression,
+ not the individual locations. For read watchopints, the
+ watchpoints_triggered function have checked all locations
+ alrea
+ */
+ if (b->type == bp_hardware_watchpoint && bl != b->loc)
continue;
/* Come here if it's a watchpoint, or if the break address matches */
/* By definition, an encountered breakpoint is a triggered
breakpoint. */
++(b->hit_count);
-
- real_breakpoint = 1;
}
if (frame_id_p (b->frame_id)
if (b->type == bp_watchpoint_scope)
b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
- if (bl->cond)
+ if (bl->cond && bl->owner->disposition != disp_del_at_next_stop)
{
/* Need to select the frame, with all that implies
so that the conditions will have the right context. */
|| bs->breakpoint_at->owner->type == bp_read_watchpoint
|| bs->breakpoint_at->owner->type == bp_access_watchpoint))
{
+ /* remove/insert can invalidate bs->breakpoint_at, if this
+ location is no longer used by the watchpoint. Prevent
+ further code from trying to use it. */
+ bs->breakpoint_at = NULL;
remove_breakpoints ();
insert_breakpoints ();
break;
This requires no further action. */
bs_class = no_effect;
break;
- case bp_catch_catch:
- if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_CATCH)
- bs_class = bp_nostop;
- else if (bs->stop)
- bs_class = bs->print ? bp_noisy : bp_silent;
- break;
- case bp_catch_throw:
- if (!bs->stop || CURRENT_EXCEPTION_KIND != EX_EVENT_THROW)
- bs_class = bp_nostop;
- else if (bs->stop)
- bs_class = bs->print ? bp_noisy : bp_silent;
- break;
case bp_call_dummy:
/* Make sure the action is stop (silent or noisy),
so infrun.c pops the dummy frame. */
return 0;
}
-/* Nonzero if there are enabled hardware watchpoints. */
-int
-bpstat_have_active_hw_watchpoints (void)
-{
- struct bp_location *bpt;
- ALL_BP_LOCATIONS (bpt)
- if (breakpoint_enabled (bpt->owner)
- && bpt->inserted
- && bpt->loc_type == bp_loc_hardware_watchpoint)
- return 1;
- return 0;
-}
\f
/* Given a bpstat that records zero or more triggered eventpoints, this
if (ep == NULL)
break;
if ((ep->type != bp_catch_load) &&
- (ep->type != bp_catch_unload) &&
- (ep->type != bp_catch_catch) &&
- (ep->type != bp_catch_throw))
+ (ep->type != bp_catch_unload))
/* pai: (temp) ADD fork/vfork here!! */
continue;
{bp_catch_unload, "catch unload"},
{bp_catch_fork, "catch fork"},
{bp_catch_vfork, "catch vfork"},
- {bp_catch_exec, "catch exec"},
- {bp_catch_catch, "catch catch"},
- {bp_catch_throw, "catch throw"}
+ {bp_catch_exec, "catch exec"}
};
static char *bpdisps[] =
/* 4 */
annotate_field (3);
if (part_of_multiple)
- ui_out_field_string (uiout, "enabled",
- loc->shlib_disabled
- ? (loc->enabled ? "y(p)" : "n(p)")
- : (loc->enabled ? "y" : "n"));
+ ui_out_field_string (uiout, "enabled", loc->enabled ? "y" : "n");
else
- {
- int pending = (b->loc == NULL || b->loc->shlib_disabled);
- /* For header of multiple, there's no point showing pending
- state -- it will be apparent from the locations. */
- if (header_of_multiple)
- pending = 0;
- ui_out_field_fmt (uiout, "enabled", "%c%s",
- bpenables[(int) b->enable_state],
- pending ? "(p)" : "");
- if (!pending)
- ui_out_spaces (uiout, 3);
- }
+ ui_out_field_fmt (uiout, "enabled", "%c",
+ bpenables[(int) b->enable_state]);
+ ui_out_spaces (uiout, 2);
/* 5 and 6 */
}
break;
- case bp_catch_catch:
- /* Field 4, the address, is omitted (which makes the columns
- not line up too nicely with the headers, but the effect
- is relatively readable). */
- if (addressprint)
- ui_out_field_skip (uiout, "addr");
- annotate_field (5);
- ui_out_field_string (uiout, "what", "exception catch");
- ui_out_spaces (uiout, 1);
- break;
-
- case bp_catch_throw:
- /* Field 4, the address, is omitted (which makes the columns
- not line up too nicely with the headers, but the effect
- is relatively readable). */
- if (addressprint)
- ui_out_field_skip (uiout, "addr");
- annotate_field (5);
- ui_out_field_string (uiout, "what", "exception throw");
- ui_out_spaces (uiout, 1);
- break;
-
case bp_breakpoint:
case bp_hardware_breakpoint:
case bp_until:
if (addressprint)
{
annotate_field (4);
- if (b->loc == NULL)
- ui_out_field_string (uiout, "addr", "<PENDING>");
- else if (header_of_multiple)
+ if (header_of_multiple)
ui_out_field_string (uiout, "addr", "<MULTIPLE>");
+ if (b->loc == NULL || loc->shlib_disabled)
+ ui_out_field_string (uiout, "addr", "<PENDING>");
else
ui_out_field_core_addr (uiout, "addr", loc->address);
}
disabled, we print it as if it had
several locations, since otherwise it's hard to
represent "breakpoint enabled, location disabled"
- situation. */
+ situation.
+ Note that while hardware watchpoints have
+ several locations internally, that's no a property
+ exposed to user. */
if (b->loc
+ && !is_hardware_watchpoint (b)
&& (b->loc->next || !b->loc->enabled)
- && !ui_out_is_mi_like_p (uiout))
+ && !ui_out_is_mi_like_p (uiout))
{
struct bp_location *loc;
int n = 1;
|| b->type == bp_catch_fork
|| b->type == bp_catch_vfork
|| b->type == bp_catch_exec
- || b->type == bp_catch_catch
- || b->type == bp_catch_throw
|| b->type == bp_hardware_breakpoint
|| b->type == bp_watchpoint
|| b->type == bp_read_watchpoint
ui_out_table_header (uiout, 4, ui_left, "disp", "Disp"); /* 3 */
if (nr_printable_breakpoints > 0)
annotate_field (3);
- ui_out_table_header (uiout, 4, ui_left, "enabled", "Enb"); /* 4 */
+ ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb"); /* 4 */
if (addressprint)
{
if (nr_printable_breakpoints > 0)
: ((others == 1) ? " and" : ""));
}
printf_filtered (_("also set at pc "));
- deprecated_print_address_numeric (pc, 1, gdb_stdout);
+ fputs_filtered (paddress (pc), gdb_stdout);
printf_filtered (".\n");
}
}
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
- case bp_catch_catch:
- case bp_catch_throw:
loc->loc_type = bp_loc_other;
break;
default:
/* Helper to set_raw_breakpoint below. Creates a breakpoint
that has type BPTYPE and has no locations as yet. */
-struct breakpoint *
+static struct breakpoint *
set_raw_breakpoint_without_location (enum bptype bptype)
{
struct breakpoint *b, *b1;
/* Adjust the breakpoint's address prior to allocating a location.
Once we call allocate_bp_location(), that mostly uninitialized
location will be placed on the location chain. Adjustment of the
- breakpoint may cause read_memory_nobpt() to be called and we do
+ breakpoint may cause target_read_memory() to be called and we do
not want its scan of the location chain to find a breakpoint and
location that's only been partially initialized. */
adjusted_address = adjust_breakpoint_address (sal.pc, bptype);
/* Disable any breakpoints that are in in an unloaded shared library. Only
apply to enabled breakpoints, disabled ones can just stay disabled. */
-void
+static void
disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
{
struct bp_location *loc;
if (((b->type == bp_watchpoint)
|| (b->type == bp_hardware_watchpoint)
|| (b->type == bp_read_watchpoint)
- || (b->type == bp_access_watchpoint)
- || ep_is_exception_catchpoint (b))
+ || (b->type == bp_access_watchpoint))
&& breakpoint_enabled (b))
{
b->enable_state = bp_call_disabled;
if (((b->type == bp_watchpoint)
|| (b->type == bp_hardware_watchpoint)
|| (b->type == bp_read_watchpoint)
- || (b->type == bp_access_watchpoint)
- || ep_is_exception_catchpoint (b))
+ || (b->type == bp_access_watchpoint))
&& (b->enable_state == bp_call_disabled))
{
b->enable_state = bp_enabled;
printf_filtered (_("Catchpoint %d (exec)"),
b->number);
break;
- case bp_catch_catch:
- case bp_catch_throw:
- printf_filtered (_("Catchpoint %d (%s)"),
- b->number,
- (b->type == bp_catch_catch) ? "catch" : "throw");
- break;
case bp_until:
case bp_finish:
if (addressprint || b->source_file == NULL)
{
printf_filtered (" at ");
- deprecated_print_address_numeric (b->loc->address, 1, gdb_stdout);
+ fputs_filtered (paddress (b->loc->address), gdb_stdout);
}
if (b->source_file)
printf_filtered (": file %s, line %d.",
/* Create a breakpoint with SAL as location. Use ADDR_STRING
as textual description of the location, and COND_STRING
- as condition expression.
-
- The paramter PENDING_BP is same as for the
- create_breakpoints function. */
+ as condition expression. */
static void
create_breakpoint (struct symtabs_and_lines sals, char *addr_string,
char *cond_string,
enum bptype type, enum bpdisp disposition,
- int thread, int ignore_count, int from_tty,
- struct breakpoint *pending_bp)
+ int thread, int ignore_count, int from_tty)
{
struct breakpoint *b = NULL;
int i;
char *arg = b->cond_string;
loc->cond = parse_exp_1 (&arg, block_for_pc (loc->address), 0);
if (*arg)
- {
- if (pending_bp)
- error (_("Junk at end of pending breakpoint condition expression"));
- else
- error (_("Garbage %s follows condition"), arg);
- }
+ error (_("Garbage %s follows condition"), arg);
}
}
separate conditions for different overloaded functions, so
we take just a single condition string.
- The parameter PENDING_BP points to a pending breakpoint that is
- the basis of the breakpoints currently being created. The pending
- breakpoint may contain a separate condition string or commands
- that were added after the initial pending breakpoint was created.
-
NOTE: If the function succeeds, the caller is expected to cleanup
the arrays ADDR_STRING, COND_STRING, and SALS (but not the
array contents). If the function fails (error() is called), the
create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
char *cond_string,
enum bptype type, enum bpdisp disposition,
- int thread, int ignore_count, int from_tty,
- struct breakpoint *pending_bp)
+ int thread, int ignore_count, int from_tty)
{
int i;
for (i = 0; i < sals.nelts; ++i)
create_breakpoint (expanded, addr_string[i],
cond_string, type, disposition,
- thread, ignore_count, from_tty,
- pending_bp);
+ thread, ignore_count, from_tty);
}
}
}
}
-/* Set a breakpoint according to ARG (function, linenum or *address)
- flag: first bit : 0 non-temporary, 1 temporary.
- second bit : 0 normal breakpoint, 1 hardware breakpoint.
+/* Set a breakpoint. This function is shared between
+ CLI and MI functions for setting a breakpoint.
+ This function has two major modes of operations,
+ selected by the PARSE_CONDITION_AND_THREAD parameter.
+ If non-zero, the function will parse arg, extracting
+ breakpoint location, address and thread. Otherwise,
+ ARG is just the location of breakpoint, with condition
+ and thread specified by the COND_STRING and THREAD
+ parameters. */
- PENDING_BP is non-NULL when this function is being called to resolve
- a pending breakpoint. */
-
-static int
-break_command_1 (char *arg, int flag, int from_tty, struct breakpoint *pending_bp)
+static void
+break_command_really (char *arg, char *cond_string, int thread,
+ int parse_condition_and_thread,
+ int tempflag, int hardwareflag,
+ int ignore_count,
+ enum auto_boolean pending_break_support,
+ int from_tty)
{
struct gdb_exception e;
- int tempflag, hardwareflag;
struct symtabs_and_lines sals;
struct symtab_and_line pending_sal;
- char *cond_string = NULL;
char *copy_arg;
char *err_msg;
char *addr_start = arg;
struct captured_parse_breakpoint_args parse_args;
int i;
int pending = 0;
- int thread = -1;
- int ignore_count = 0;
int not_found = 0;
- hardwareflag = flag & BP_HARDWAREFLAG;
- tempflag = flag & BP_TEMPFLAG;
-
sals.sals = NULL;
sals.nelts = 0;
addr_string = NULL;
switch (e.reason)
{
case RETURN_QUIT:
- exception_print (gdb_stderr, e);
- return e.reason;
+ throw_exception (e);
case RETURN_ERROR:
switch (e.error)
{
case NOT_FOUND_ERROR:
- /* If called to resolve pending breakpoint, just return
- error code. */
- if (pending_bp)
- return e.reason;
-
- exception_print (gdb_stderr, e);
/* If pending breakpoint support is turned off, throw
error. */
if (pending_break_support == AUTO_BOOLEAN_FALSE)
- deprecated_throw_reason (RETURN_ERROR);
+ throw_exception (e);
+
+ exception_print (gdb_stderr, e);
/* If pending breakpoint support is auto query and the user
selects no, then simply return the error code. */
if (pending_break_support == AUTO_BOOLEAN_AUTO &&
!nquery ("Make breakpoint pending on future shared library load? "))
- return e.reason;
+ return;
/* At this point, either the user was queried about setting
a pending breakpoint and selected yes, or pending
pending = 1;
break;
default:
- exception_print (gdb_stderr, e);
- return e.reason;
+ throw_exception (e);
}
default:
if (!sals.nelts)
- return GDB_RC_FAIL;
+ return;
}
/* Create a chain of things that always need to be cleaned up. */
breakpoint. */
if (!pending)
{
- /* Here we only parse 'arg' to separate condition
- from thread number, so parsing in context of first
- sal is OK. When setting the breakpoint we'll
- re-parse it in context of each sal. */
- find_condition_and_thread (arg, sals.sals[0].pc, &cond_string, &thread);
- if (cond_string)
- make_cleanup (xfree, cond_string);
+ if (parse_condition_and_thread)
+ {
+ /* Here we only parse 'arg' to separate condition
+ from thread number, so parsing in context of first
+ sal is OK. When setting the breakpoint we'll
+ re-parse it in context of each sal. */
+ cond_string = NULL;
+ thread = -1;
+ find_condition_and_thread (arg, sals.sals[0].pc, &cond_string, &thread);
+ if (cond_string)
+ make_cleanup (xfree, cond_string);
+ }
+ else
+ {
+ /* Create a private copy of condition string. */
+ if (cond_string)
+ {
+ cond_string = xstrdup (cond_string);
+ make_cleanup (xfree, cond_string);
+ }
+ }
create_breakpoints (sals, addr_string, cond_string,
hardwareflag ? bp_hardware_breakpoint
: bp_breakpoint,
tempflag ? disp_del : disp_donttouch,
- thread, ignore_count, from_tty,
- pending_bp);
+ thread, ignore_count, from_tty);
}
else
{
: bp_breakpoint);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
- b->thread = thread;
+ b->thread = -1;
b->addr_string = addr_string[0];
- b->cond_string = cond_string;
+ b->cond_string = NULL;
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
- b->from_tty = from_tty;
- b->flag = flag;
b->condition_not_parsed = 1;
mention (b);
}
discard_cleanups (breakpoint_chain);
/* But cleanup everything else. */
do_cleanups (old_chain);
-
- return GDB_RC_OK;
}
-/* Set a breakpoint of TYPE/DISPOSITION according to ARG (function,
- linenum or *address) with COND and IGNORE_COUNT. */
-
-struct captured_breakpoint_args
- {
- char *address;
- char *condition;
- int hardwareflag;
- int tempflag;
- int thread;
- int ignore_count;
- };
-
-static int
-do_captured_breakpoint (struct ui_out *uiout, void *data)
+/* Set a breakpoint.
+ ARG is a string describing breakpoint address,
+ condition, and thread.
+ FLAG specifies if a breakpoint is hardware on,
+ and if breakpoint is temporary, using BP_HARDWARE_FLAG
+ and BP_TEMPFLAG. */
+
+static void
+break_command_1 (char *arg, int flag, int from_tty)
{
- struct captured_breakpoint_args *args = data;
- struct symtabs_and_lines sals;
- struct expression **cond;
- struct cleanup *old_chain;
- struct cleanup *breakpoint_chain = NULL;
- int i;
- char **addr_string;
- char *cond_string = 0;
-
- char *address_end;
-
- /* Parse the source and lines spec. Delay check that the expression
- didn't contain trailing garbage until after cleanups are in
- place. */
- sals.sals = NULL;
- sals.nelts = 0;
- address_end = args->address;
- addr_string = NULL;
- parse_breakpoint_sals (&address_end, &sals, &addr_string, 0);
-
- if (!sals.nelts)
- return GDB_RC_NONE;
-
- /* Create a chain of things at always need to be cleaned up. */
- old_chain = make_cleanup (null_cleanup, 0);
-
- /* Always have a addr_string array, even if it is empty. */
- make_cleanup (xfree, addr_string);
-
- /* Make sure that all storage allocated to SALS gets freed. */
- make_cleanup (xfree, sals.sals);
+ int hardwareflag = flag & BP_HARDWAREFLAG;
+ int tempflag = flag & BP_TEMPFLAG;
- /* Allocate space for all the cond expressions. */
- cond = xcalloc (sals.nelts, sizeof (struct expression *));
- make_cleanup (xfree, cond);
-
- /* ----------------------------- SNIP -----------------------------
- Anything added to the cleanup chain beyond this point is assumed
- to be part of a breakpoint. If the breakpoint create goes
- through then that memory is not cleaned up. */
- breakpoint_chain = make_cleanup (null_cleanup, 0);
+ break_command_really (arg,
+ NULL, 0, 1 /* parse arg */,
+ tempflag, hardwareflag,
+ 0 /* Ignore count */,
+ pending_break_support, from_tty);
+}
- /* Mark the contents of the addr_string for cleanup. These go on
- the breakpoint_chain and only occure if the breakpoint create
- fails. */
- for (i = 0; i < sals.nelts; i++)
- {
- if (addr_string[i] != NULL)
- make_cleanup (xfree, addr_string[i]);
- }
- /* Wait until now before checking for garbage at the end of the
- address. That way cleanups can take care of freeing any
- memory. */
- if (*address_end != '\0')
- error (_("Garbage %s following breakpoint address"), address_end);
+void
+set_breakpoint (char *address, char *condition,
+ int hardwareflag, int tempflag,
+ int thread, int ignore_count,
+ int pending)
+{
+ break_command_really (address, condition, thread,
+ 0 /* condition and thread are valid. */,
+ tempflag, hardwareflag,
+ ignore_count,
+ pending
+ ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
+ 0);
+}
- /* Resolve all line numbers to PC's. */
- breakpoint_sals_to_pc (&sals, args->address);
+/* Adjust SAL to the first instruction past the function prologue.
+ The end of the prologue is determined using the line table from
+ the debugging information.
- if (args->condition != NULL)
- {
- cond_string = xstrdup (args->condition);
- make_cleanup (xfree, cond_string);
- }
+ If SAL is already past the prologue, then do nothing. */
- create_breakpoints (sals, addr_string, args->condition,
- args->hardwareflag ? bp_hardware_breakpoint : bp_breakpoint,
- args->tempflag ? disp_del : disp_donttouch,
- args->thread, args->ignore_count, 0/*from-tty*/,
- NULL/*pending_bp*/);
+static void
+skip_prologue_sal (struct symtab_and_line *sal)
+{
+ struct symbol *sym = find_pc_function (sal->pc);
+ struct symtab_and_line start_sal;
- /* That's it. Discard the cleanups for data inserted into the
- breakpoint. */
- discard_cleanups (breakpoint_chain);
- /* But cleanup everything else. */
- do_cleanups (old_chain);
- return GDB_RC_OK;
-}
+ if (sym == NULL)
+ return;
-enum gdb_rc
-gdb_breakpoint (char *address, char *condition,
- int hardwareflag, int tempflag,
- int thread, int ignore_count,
- char **error_message)
-{
- struct captured_breakpoint_args args;
- args.address = address;
- args.condition = condition;
- args.hardwareflag = hardwareflag;
- args.tempflag = tempflag;
- args.thread = thread;
- args.ignore_count = ignore_count;
- if (catch_exceptions_with_msg (uiout, do_captured_breakpoint, &args,
- error_message, RETURN_MASK_ALL) < 0)
- return GDB_RC_FAIL;
- else
- return GDB_RC_OK;
+ start_sal = find_function_start_sal (sym, 1);
+ if (sal->pc < start_sal.pc)
+ *sal = start_sal;
}
-
/* Helper function for break_command_1 and disassemble_command. */
void
error (_("No line %d in file \"%s\"."),
sal->line, sal->symtab->filename);
sal->pc = pc;
+
+ /* If this SAL corresponds to a breakpoint inserted using
+ a line number, then skip the function prologue if necessary. */
+ if (sal->explicit_line)
+ skip_prologue_sal (sal);
}
if (sal->section == 0 && sal->symtab != NULL)
struct blockvector *bv;
struct block *b;
struct symbol *sym;
- int index;
- bv = blockvector_for_pc_sect (sal->pc, 0, &index, sal->symtab);
+ bv = blockvector_for_pc_sect (sal->pc, 0, &b, sal->symtab);
if (bv != NULL)
{
- b = BLOCKVECTOR_BLOCK (bv, index);
sym = block_function (b);
if (sym != NULL)
{
void
break_command (char *arg, int from_tty)
{
- break_command_1 (arg, 0, from_tty, NULL);
+ break_command_1 (arg, 0, from_tty);
}
void
tbreak_command (char *arg, int from_tty)
{
- break_command_1 (arg, BP_TEMPFLAG, from_tty, NULL);
+ break_command_1 (arg, BP_TEMPFLAG, from_tty);
}
static void
hbreak_command (char *arg, int from_tty)
{
- break_command_1 (arg, BP_HARDWAREFLAG, from_tty, NULL);
+ break_command_1 (arg, BP_HARDWAREFLAG, from_tty);
}
static void
thbreak_command (char *arg, int from_tty)
{
- break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty, NULL);
+ break_command_1 (arg, (BP_TEMPFLAG | BP_HARDWAREFLAG), from_tty);
}
static void
if (badInput)
printf_filtered (_("Usage: stop in <function | address>\n"));
else
- break_command_1 (arg, 0, from_tty, NULL);
+ break_command_1 (arg, 0, from_tty);
}
static void
if (badInput)
printf_filtered (_("Usage: stop at <line>\n"));
else
- break_command_1 (arg, 0, from_tty, NULL);
+ break_command_1 (arg, 0, from_tty);
}
/* accessflag: hw_write: watch write,
struct frame_info *prev_frame = NULL;
char *exp_start = NULL;
char *exp_end = NULL;
- char *tok, *end_tok;
+ char *tok, *id_tok_start, *end_tok;
int toklen;
char *cond_start = NULL;
char *cond_end = NULL;
int i, other_type_used, target_resources_ok = 0;
enum bptype bp_type;
int mem_cnt = 0;
+ int thread = -1;
init_sal (&sal); /* initialize to zeroes */
- /* Parse arguments. */
+ /* Make sure that we actually have parameters to parse. */
+ if (arg != NULL && arg[0] != '\0')
+ {
+ toklen = strlen (arg); /* Size of argument list. */
+
+ /* Points tok to the end of the argument list. */
+ tok = arg + toklen - 1;
+
+ /* Go backwards in the parameters list. Skip the last parameter.
+ If we're expecting a 'thread <thread_num>' parameter, this should
+ be the thread identifier. */
+ while (tok > arg && (*tok == ' ' || *tok == '\t'))
+ tok--;
+ while (tok > arg && (*tok != ' ' && *tok != '\t'))
+ tok--;
+
+ /* Points end_tok to the beginning of the last token. */
+ id_tok_start = tok + 1;
+
+ /* Go backwards in the parameters list. Skip one more parameter.
+ If we're expecting a 'thread <thread_num>' parameter, we should
+ reach a "thread" token. */
+ while (tok > arg && (*tok == ' ' || *tok == '\t'))
+ tok--;
+
+ end_tok = tok;
+
+ while (tok > arg && (*tok != ' ' && *tok != '\t'))
+ tok--;
+
+ /* Move the pointer forward to skip the whitespace and
+ calculate the length of the token. */
+ tok++;
+ toklen = end_tok - tok;
+
+ if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+ {
+ /* At this point we've found a "thread" token, which means
+ the user is trying to set a watchpoint that triggers
+ only in a specific thread. */
+ char *endp;
+
+ /* Extract the thread ID from the next token. */
+ thread = strtol (id_tok_start, &endp, 0);
+
+ /* Check if the user provided a valid numeric value for the
+ thread ID. */
+ if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+ error (_("Invalid thread ID specification %s."), id_tok_start);
+
+ /* Check if the thread actually exists. */
+ if (!valid_thread_id (thread))
+ error (_("Unknown thread %d."), thread);
+
+ /* Truncate the string and get rid of the thread <thread_num>
+ parameter before the parameter list is parsed by the
+ evaluate_expression() function. */
+ *tok = '\0';
+ }
+ }
+
+ /* Parse the rest of the arguments. */
innermost_block = NULL;
exp_start = arg;
exp = parse_exp_1 (&arg, 0, 0);
exp_end = arg;
exp_valid_block = innermost_block;
mark = value_mark ();
- val = evaluate_expression (exp);
- release_value (val);
- if (value_lazy (val))
- value_fetch_lazy (val);
+ fetch_watchpoint_value (exp, &val, NULL, NULL);
+ if (val != NULL)
+ release_value (val);
tok = arg;
while (*tok == ' ' || *tok == '\t')
b = set_raw_breakpoint (sal, bp_type);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
+ b->thread = thread;
b->disposition = disp_donttouch;
b->exp = exp;
b->exp_valid_block = exp_valid_block;
b->exp_string = savestring (exp_start, exp_end - exp_start);
b->val = val;
+ b->val_valid = 1;
b->loc->cond = cond;
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
if (frame)
b->watchpoint_frame = get_frame_id (frame);
else
- memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
+ b->watchpoint_frame = null_frame_id;
if (scope_breakpoint != NULL)
{
dll_pathname, cond_string);
}
-/* Commands to deal with catching exceptions. */
-
-/* Set a breakpoint at the specified callback routine for an
- exception event callback */
-
-static void
-create_exception_catchpoint (int tempflag, char *cond_string,
- enum exception_event_kind ex_event,
- struct symtab_and_line *sal)
-{
- struct breakpoint *b;
- int thread = -1; /* All threads. */
- enum bptype bptype;
-
- if (!sal) /* no exception support? */
- return;
-
- switch (ex_event)
- {
- case EX_EVENT_THROW:
- bptype = bp_catch_throw;
- break;
- case EX_EVENT_CATCH:
- bptype = bp_catch_catch;
- break;
- default: /* error condition */
- error (_("Internal error -- invalid catchpoint kind"));
- }
-
- b = set_raw_breakpoint (*sal, bptype);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
- b->cond_string = (cond_string == NULL) ?
- NULL : savestring (cond_string, strlen (cond_string));
- b->thread = thread;
- b->addr_string = NULL;
- b->enable_state = bp_enabled;
- b->disposition = tempflag ? disp_del : disp_donttouch;
- mention (b);
-}
-
static enum print_stop_action
print_exception_catchpoint (struct breakpoint *b)
{
if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
return;
- /* See if we can find a callback routine */
- sal = target_enable_exception_callback (ex_event, 1);
-
- if (sal)
- {
- /* We have callbacks from the runtime system for exceptions.
- Set a breakpoint on the sal found, if no errors */
- if (sal != (struct symtab_and_line *) -1)
- create_exception_catchpoint (tempflag, cond_string, ex_event, sal);
- else
- return; /* something went wrong with setting up callbacks */
- }
-
warning (_("Unsupported with this platform/compiler combination."));
}
b->exp_string = exp_string;
b->thread = -1;
b->ops = ops;
- b->from_tty = from_tty;
mention (b);
}
tempflag, from_tty);
}
-/* Cover routine to allow wrapping target_enable_exception_catchpoints
- inside a catch_errors */
-
-static int
-cover_target_enable_exception_callback (void *arg)
-{
- args_for_catchpoint_enable *args = arg;
- struct symtab_and_line *sal;
- sal = target_enable_exception_callback (args->kind, args->enable_p);
- if (sal == NULL)
- return 0;
- else if (sal == (struct symtab_and_line *) -1)
- return -1;
- else
- return 1; /*is valid */
-}
-
static void
catch_command_1 (char *arg, int tempflag, int from_tty)
{
static void
clear_command (char *arg, int from_tty)
{
- struct breakpoint *b, *tmp, *prev, *found;
+ struct breakpoint *b;
+ VEC(breakpoint_p) *found = 0;
+ int ix;
int default_match;
struct symtabs_and_lines sals;
struct symtab_and_line sal;
1 0 <can't happen> */
sal = sals.sals[i];
- prev = NULL;
- /* Find all matching breakpoints, remove them from the
- breakpoint chain, and add them to the 'found' chain. */
- ALL_BREAKPOINTS_SAFE (b, tmp)
+ /* Find all matching breakpoints and add them to
+ 'found'. */
+ ALL_BREAKPOINTS (b)
{
int match = 0;
/* Are we going to delete b? */
}
if (match)
- {
- /* Remove it from breakpoint_chain... */
- if (b == breakpoint_chain)
- {
- /* b is at the head of the list */
- breakpoint_chain = b->next;
- }
- else
- {
- prev->next = b->next;
- }
- /* And add it to 'found' chain. */
- b->next = found;
- found = b;
- }
- else
- {
- /* Keep b, and keep a pointer to it. */
- prev = b;
- }
+ VEC_safe_push(breakpoint_p, found, b);
}
}
/* Now go thru the 'found' chain and delete them. */
- if (found == 0)
+ if (VEC_empty(breakpoint_p, found))
{
if (arg)
error (_("No breakpoint at %s."), arg);
error (_("No breakpoint at this line."));
}
- if (found->next)
+ if (VEC_length(breakpoint_p, found) > 1)
from_tty = 1; /* Always report if deleted more than one */
if (from_tty)
{
- if (!found->next)
+ if (VEC_length(breakpoint_p, found) == 1)
printf_unfiltered (_("Deleted breakpoint "));
else
printf_unfiltered (_("Deleted breakpoints "));
}
breakpoints_changed ();
- while (found)
+
+ for (ix = 0; VEC_iterate(breakpoint_p, found, ix, b); ix++)
{
if (from_tty)
- printf_unfiltered ("%d ", found->number);
- tmp = found->next;
- delete_breakpoint (found);
- found = tmp;
+ printf_unfiltered ("%d ", b->number);
+ delete_breakpoint (b);
}
if (from_tty)
putchar_unfiltered ('\n');
{
if (loc->inserted)
remove_breakpoint (loc, mark_inserted);
-
- free_valchain (loc);
-
+
if (loc->cond)
xfree (loc->cond);
if (breakpoint_chain == bpt)
breakpoint_chain = bpt->next;
- /* If we have callback-style exception catchpoints, don't go through
- the adjustments to the C++ runtime library etc. if the inferior
- isn't actually running. target_enable_exception_callback for a
- null target ops vector gives an undesirable error message, so we
- check here and avoid it. Since currently (1997-09-17) only HP-UX aCC's
- exceptions are supported in this way, it's OK for now. FIXME */
- if (ep_is_exception_catchpoint (bpt) && target_has_execution)
- {
- /* Format possible error msg */
- char *message = xstrprintf ("Error in deleting catchpoint %d:\n",
- bpt->number);
- struct cleanup *cleanups = make_cleanup (xfree, message);
- args_for_catchpoint_enable args;
- args.kind = bpt->type == bp_catch_catch ?
- EX_EVENT_CATCH : EX_EVENT_THROW;
- args.enable_p = 0;
- catch_errors (cover_target_enable_exception_callback, &args,
- message, RETURN_MASK_ALL);
- do_cleanups (cleanups);
- }
-
-
ALL_BREAKPOINTS (b)
if (b->next == bpt)
{
{
fprintf_unfiltered (tmp_error_stream, "Cannot insert breakpoint %d.\n", b->number);
fprintf_filtered (tmp_error_stream, "Error accessing memory address ");
- deprecated_print_address_numeric (loc2->address, 1, tmp_error_stream);
+ fputs_filtered (paddress (loc2->address),
+ tmp_error_stream);
fprintf_filtered (tmp_error_stream, ": %s.\n",
safe_strerror (val));
}
return 1;
}
+/* Subroutine of update_breakpoint_locations to simplify it.
+ Return non-zero if multiple fns in list LOC have the same name.
+ Null names are ignored. */
+
+static int
+ambiguous_names_p (struct bp_location *loc)
+{
+ struct bp_location *l;
+ htab_t htab = htab_create_alloc (13, htab_hash_string,
+ (int (*) (const void *, const void *)) streq,
+ NULL, xcalloc, xfree);
+
+ for (l = loc; l != NULL; l = l->next)
+ {
+ const char **slot;
+ const char *name = l->function_name;
+
+ /* Allow for some names to be NULL, ignore them. */
+ if (name == NULL)
+ continue;
+
+ slot = (const char **) htab_find_slot (htab, (const void *) name,
+ INSERT);
+ /* NOTE: We can assume slot != NULL here because xcalloc never returns
+ NULL. */
+ if (*slot != NULL)
+ {
+ htab_delete (htab);
+ return 1;
+ }
+ *slot = name;
+ }
+
+ htab_delete (htab);
+ return 0;
+}
+
static void
update_breakpoint_locations (struct breakpoint *b,
struct symtabs_and_lines sals)
/* If possible, carry over 'disable' status from existing breakpoints. */
{
struct bp_location *e = existing_locations;
+ /* If there are multiple breakpoints with the same function name,
+ e.g. for inline functions, comparing function names won't work.
+ Instead compare pc addresses; this is just a heuristic as things
+ may have moved, but in practice it gives the correct answer
+ often enough until a better solution is found. */
+ int have_ambiguous_names = ambiguous_names_p (b->loc);
+
for (; e; e = e->next)
{
if (!e->enabled && e->function_name)
{
struct bp_location *l = b->loc;
- for (; l; l = l->next)
- if (l->function_name
- && strcmp (e->function_name, l->function_name) == 0)
- {
- l->enabled = 0;
- break;
- }
+ if (have_ambiguous_names)
+ {
+ for (; l; l = l->next)
+ if (e->address == l->address)
+ {
+ l->enabled = 0;
+ break;
+ }
+ }
+ else
+ {
+ for (; l; l = l->next)
+ if (l->function_name
+ && strcmp (e->function_name, l->function_name) == 0)
+ {
+ l->enabled = 0;
+ break;
+ }
+ }
}
}
}
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
- innermost_block = NULL;
- /* The issue arises of what context to evaluate this in. The
- same one as when it was set, but what does that mean when
- symbols have been re-read? We could save the filename and
- functionname, but if the context is more local than that, the
- best we could do would be something like how many levels deep
- and which index at that particular level, but that's going to
- be less stable than filenames or function names. */
-
- /* So for now, just use a global context. */
- if (b->exp)
- {
- xfree (b->exp);
- /* Avoid re-freeing b->exp if an error during the call to
- parse_expression. */
- b->exp = NULL;
- }
- b->exp = parse_expression (b->exp_string);
- b->exp_valid_block = innermost_block;
- mark = value_mark ();
- if (b->val)
- {
- value_free (b->val);
- /* Avoid re-freeing b->val if an error during the call to
- evaluate_expression. */
- b->val = NULL;
- }
- b->val = evaluate_expression (b->exp);
- release_value (b->val);
- if (value_lazy (b->val) && breakpoint_enabled (b))
- value_fetch_lazy (b->val);
-
- if (b->cond_string != NULL)
- {
- s = b->cond_string;
- if (b->loc->cond)
- {
- xfree (b->loc->cond);
- /* Avoid re-freeing b->exp if an error during the call
- to parse_exp_1. */
- b->loc->cond = NULL;
- }
- b->loc->cond = parse_exp_1 (&s, (struct block *) 0, 0);
- }
- if (breakpoint_enabled (b))
- mention (b);
- value_free_to_mark (mark);
- break;
- case bp_catch_catch:
- case bp_catch_throw:
+ /* Watchpoint can be either on expression using entirely global variables,
+ or it can be on local variables.
+
+ Watchpoints of the first kind are never auto-deleted, and even persist
+ across program restarts. Since they can use variables from shared
+ libraries, we need to reparse expression as libraries are loaded
+ and unloaded.
+
+ Watchpoints on local variables can also change meaning as result
+ of solib event. For example, if a watchpoint uses both a local and
+ a global variables in expression, it's a local watchpoint, but
+ unloading of a shared library will make the expression invalid.
+ This is not a very common use case, but we still re-evaluate
+ expression, to avoid surprises to the user.
+
+ Note that for local watchpoints, we re-evaluate it only if
+ watchpoints frame id is still valid. If it's not, it means
+ the watchpoint is out of scope and will be deleted soon. In fact,
+ I'm not sure we'll ever be called in this case.
+
+ If a local watchpoint's frame id is still valid, then
+ b->exp_valid_block is likewise valid, and we can safely use it.
+
+ Don't do anything about disabled watchpoints, since they will
+ be reevaluated again when enabled. */
+ update_watchpoint (b, 1 /* reparse */);
break;
/* We needn't really do anything to reset these, since the mask
that requests them is unaffected by e.g., new libraries being
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
- case bp_catch_catch:
- case bp_catch_throw:
case bp_hardware_breakpoint:
case bp_watchpoint:
case bp_hardware_watchpoint:
if (bpt->val)
value_free (bpt->val);
mark = value_mark ();
- bpt->val = evaluate_expression (bpt->exp);
- release_value (bpt->val);
- if (value_lazy (bpt->val))
- value_fetch_lazy (bpt->val);
-
+ fetch_watchpoint_value (bpt->exp, &bpt->val, NULL, NULL);
+ if (bpt->val)
+ release_value (bpt->val);
+ bpt->val_valid = 1;
+
if (bpt->type == bp_hardware_watchpoint ||
bpt->type == bp_read_watchpoint ||
bpt->type == bp_access_watchpoint)
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
- case bp_catch_catch:
- case bp_catch_throw:
case bp_hardware_breakpoint:
case bp_watchpoint:
case bp_hardware_watchpoint: