/* 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
+ 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.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include <ctype.h>
#include "solist.h"
#include "observer.h"
#include "exceptions.h"
+#include "memattr.h"
+#include "ada-lang.h"
+#include "top.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 int break_command_1 (char *, int, int);
static void mention (struct breakpoint *);
static CORE_ADDR adjust_breakpoint_address (CORE_ADDR bpaddr,
enum bptype bptype);
-static void describe_other_breakpoints (CORE_ADDR, asection *);
+static void describe_other_breakpoints (CORE_ADDR, asection *, int);
static void breakpoints_info (char *, int);
static void breakpoint_1 (int, int);
-static bpstat bpstat_alloc (struct breakpoint *, bpstat);
+static bpstat bpstat_alloc (const struct bp_location *, bpstat);
static int breakpoint_cond_eval (void *);
static void do_enable_breakpoint (struct breakpoint *, enum bpdisp);
-static void solib_load_unload_1 (char *hookname,
- int tempflag,
- char *dll_pathname,
- char *cond_string, enum bptype bp_kind);
-
static void create_fork_vfork_event_catchpoint (int tempflag,
char *cond_string,
enum bptype bp_kind);
static void ep_skip_leading_whitespace (char **s);
+static int single_step_breakpoint_inserted_here_p (CORE_ADDR pc);
+
+static void free_bp_location (struct bp_location *loc);
+
+static void mark_breakpoints_out (void);
+
/* Prototypes for exported functions. */
/* If FALSE, gdb will not use hardware support for watchpoints, even
value);
}
+/* If 1, gdb will automatically use hardware breakpoints for breakpoints
+ set with "break" but falling in read-only memory.
+ If 0, gdb will warn about such breakpoints, but won't automatically
+ use hardware breakpoints. */
+static int automatic_hardware_breakpoints;
+static void
+show_automatic_hardware_breakpoints (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ fprintf_filtered (file, _("\
+Automatic usage of hardware breakpoints is %s.\n"),
+ value);
+}
+
+
void _initialize_breakpoint (void);
extern int addressprint; /* Print machine addresses? */
/* Similar iterators for the low-level breakpoints. */
-#define ALL_BP_LOCATIONS(B) for (B = bp_location_chain; B; B = B->next)
+#define ALL_BP_LOCATIONS(B) for (B = bp_location_chain; B; B = B->global_next)
#define ALL_BP_LOCATIONS_SAFE(B,TMP) \
for (B = bp_location_chain; \
- B ? (TMP=B->next, 1): 0; \
+ B ? (TMP=B->global_next, 1): 0; \
B = TMP)
/* True if breakpoint hit counts should be displayed in breakpoint info. */
/* Pointer to current exception event record */
static struct exception_event_record *current_exception_event;
-/* Indicator of whether exception catchpoints should be nuked between
- runs of a program. */
-int deprecated_exception_catchpoints_are_fragile = 0;
-
-/* Indicator of when exception catchpoints set-up should be
- reinitialized -- e.g. when program is re-run. */
-int deprecated_exception_support_initialized = 0;
-
/* This function returns a pointer to the string representation of the
pathname of the dynamically-linked library that has just been
loaded.
static int
breakpoint_enabled (struct breakpoint *b)
{
- return (b->enable_state == bp_enabled && !b->pending);
+ return (b->enable_state == bp_enabled);
}
/* Set breakpoint count to NUM. */
Currently the string can either be a number or "$" followed by the name
of a convenience variable. Making it an expression wouldn't work well
for map_breakpoint_numbers (e.g. "4 + 5 + 6").
+
+ If the string is a NULL pointer, that denotes the last breakpoint.
TRAILER is a character which can be found after the number; most
commonly this is `-'. If you don't want a trailer, use \0. */
ALL_BREAKPOINTS (b)
if (b->number == bnum)
{
- if (b->cond)
+ struct bp_location *loc = b->loc;
+ for (; loc; loc = loc->next)
{
- xfree (b->cond);
- b->cond = 0;
+ if (loc->cond)
+ {
+ xfree (loc->cond);
+ loc->cond = 0;
+ }
}
if (b->cond_string != NULL)
xfree (b->cond_string);
if (*p == 0)
{
- b->cond = 0;
b->cond_string = NULL;
if (from_tty)
printf_filtered (_("Breakpoint %d now unconditional.\n"), bnum);
/* I don't know if it matters whether this is the string the user
typed in or the decompiled expression. */
b->cond_string = savestring (arg, strlen (arg));
- if (!b->pending)
+ b->condition_not_parsed = 0;
+ for (loc = b->loc; loc; loc = loc->next)
{
- b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
+ arg = p;
+ loc->cond = parse_exp_1 (&arg, block_for_pc (loc->address), 0);
if (*arg)
error (_("Junk at end of expression"));
}
}
error (_("No breakpoint number %d."), bnum);
}
+
+/* Like commands_command, but instead of reading the commands from
+ input stream, takes them from an already parsed command structure.
+
+ This is used by cli-script.c to DTRT with breakpoint commands
+ that are part of if and while bodies. */
+enum command_control_type
+commands_from_control_command (char *arg, struct command_line *cmd)
+{
+ struct breakpoint *b;
+ char *p;
+ int bnum;
+
+ /* If we allowed this, we would have problems with when to
+ free the storage, if we change the commands currently
+ being read from. */
+
+ if (executing_breakpoint_commands)
+ error (_("Can't use the \"commands\" command among a breakpoint's commands."));
+
+ /* An empty string for the breakpoint number means the last
+ breakpoint, but get_number expects a NULL pointer. */
+ if (arg && !*arg)
+ p = NULL;
+ else
+ p = arg;
+ bnum = get_number (&p);
+
+ if (p && *p)
+ error (_("Unexpected extra arguments following breakpoint number."));
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bnum)
+ {
+ free_command_lines (&b->commands);
+ if (cmd->body_count != 1)
+ error (_("Invalid \"commands\" block structure."));
+ /* We need to copy the commands because if/while will free the
+ list after it finishes execution. */
+ b->commands = copy_command_lines (cmd->body_list[0]);
+ breakpoints_changed ();
+ breakpoint_modify_event (b->number);
+ return simple_control;
+ }
+ 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.
shadow contents, not the breakpoints themselves. From breakpoint.c. */
int
-deprecated_read_memory_nobpt (CORE_ADDR memaddr, gdb_byte *myaddr,
- unsigned len)
+read_memory_nobpt (CORE_ADDR memaddr, gdb_byte *myaddr, unsigned len)
{
int status;
- struct bp_location *b;
+ const struct bp_location *b;
CORE_ADDR bp_addr = 0;
int bp_size = 0;
- if (BREAKPOINT_FROM_PC (&bp_addr, &bp_size) == NULL)
+ if (gdbarch_breakpoint_from_pc (current_gdbarch, &bp_addr, &bp_size) == NULL)
/* No breakpoints on this machine. */
return target_read_memory (memaddr, myaddr, len);
continue;
/* Addresses and length of the part of the breakpoint that
we need to copy. */
- /* XXXX The m68k, sh and h8300 have different local and remote
- breakpoint values. BREAKPOINT_FROM_PC still manages to
- correctly determine the breakpoints memory address and size
- for these targets. */
- bp_addr = b->address;
- bp_size = 0;
- if (BREAKPOINT_FROM_PC (&bp_addr, &bp_size) == NULL)
- continue;
+ bp_addr = b->target_info.placed_address;
+ bp_size = b->target_info.shadow_len;
if (bp_size == 0)
- /* bp isn't valid */
+ /* 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
}
memcpy (myaddr + bp_addr - memaddr,
- b->shadow_contents + bptoffset, bp_size);
+ b->target_info.shadow_contents + bptoffset, bp_size);
if (bp_addr > memaddr)
{
/* Copy the section of memory before the breakpoint. */
- status = deprecated_read_memory_nobpt (memaddr, myaddr, bp_addr - memaddr);
+ status = read_memory_nobpt (memaddr, myaddr, bp_addr - memaddr);
if (status != 0)
return status;
}
if (bp_addr + bp_size < memaddr + len)
{
/* Copy the section of memory after the breakpoint. */
- status = deprecated_read_memory_nobpt (bp_addr + bp_size,
+ status = read_memory_nobpt (bp_addr + bp_size,
myaddr + bp_addr + bp_size - memaddr,
memaddr + len - (bp_addr + bp_size));
if (status != 0)
/* Helper routine: free the value chain for a breakpoint (watchpoint). */
-static void free_valchain (struct bp_location *b)
+static void
+free_valchain (struct bp_location *b)
{
struct value *v;
struct value *n;
{
int val = 0;
- /* Permanent breakpoints cannot be inserted or removed. Disabled
- breakpoints should not be inserted. */
if (!breakpoint_enabled (bpt->owner))
return 0;
- if (bpt->inserted || bpt->duplicate)
+ if (!bpt->enabled || bpt->shlib_disabled || bpt->inserted || bpt->duplicate)
return 0;
+ /* Initialize the target-specific information. */
+ memset (&bpt->target_info, 0, sizeof (bpt->target_info));
+ bpt->target_info.placed_address = bpt->address;
+
if (bpt->loc_type == bp_loc_software_breakpoint
|| bpt->loc_type == bp_loc_hardware_breakpoint)
{
+ if (bpt->owner->type != bp_hardware_breakpoint)
+ {
+ /* If the explicitly specified breakpoint type
+ is not hardware breakpoint, check the memory map to see
+ if the breakpoint address is in read only memory or not.
+ Two important cases are:
+ - location type is not hardware breakpoint, memory
+ is readonly. We change the type of the location to
+ hardware breakpoint.
+ - location type is hardware breakpoint, memory is read-write.
+ This means we've previously made the location hardware one, but
+ then the memory map changed, so we undo.
+
+ When breakpoints are removed, remove_breakpoints will
+ use location types we've just set here, the only possible
+ problem is that memory map has changed during running program,
+ but it's not going to work anyway with current gdb. */
+ struct mem_region *mr
+ = lookup_mem_region (bpt->target_info.placed_address);
+
+ if (mr)
+ {
+ if (automatic_hardware_breakpoints)
+ {
+ int changed = 0;
+ enum bp_loc_type new_type;
+
+ if (mr->attrib.mode != MEM_RW)
+ new_type = bp_loc_hardware_breakpoint;
+ else
+ new_type = bp_loc_software_breakpoint;
+
+ if (new_type != bpt->loc_type)
+ {
+ static int said = 0;
+ bpt->loc_type = new_type;
+ if (!said)
+ {
+ fprintf_filtered (gdb_stdout, _("\
+Note: automatically using hardware breakpoints for read-only addresses.\n"));
+ said = 1;
+ }
+ }
+ }
+ else if (bpt->loc_type == bp_loc_software_breakpoint
+ && mr->attrib.mode != MEM_RW)
+ warning (_("cannot set software breakpoint at readonly address %s"),
+ paddr (bpt->address));
+ }
+ }
+
/* First check to see if we have to handle an overlay. */
if (overlay_debugging == ovly_off
|| bpt->section == NULL
/* No overlay handling: just set the breakpoint. */
if (bpt->loc_type == bp_loc_hardware_breakpoint)
- val = target_insert_hw_breakpoint (bpt->address,
- bpt->shadow_contents);
+ val = target_insert_hw_breakpoint (&bpt->target_info);
else
- val = target_insert_breakpoint (bpt->address,
- bpt->shadow_contents);
+ val = target_insert_breakpoint (&bpt->target_info);
}
else
{
CORE_ADDR addr = overlay_unmapped_address (bpt->address,
bpt->section);
/* Set a software (trap) breakpoint at the LMA. */
- val = target_insert_breakpoint (addr, bpt->shadow_contents);
+ bpt->overlay_target_info = bpt->target_info;
+ bpt->overlay_target_info.placed_address = addr;
+ val = target_insert_breakpoint (&bpt->overlay_target_info);
if (val != 0)
fprintf_unfiltered (tmp_error_stream,
"Overlay breakpoint %d failed: in ROM?",
{
/* Yes. This overlay section is mapped into memory. */
if (bpt->loc_type == bp_loc_hardware_breakpoint)
- val = target_insert_hw_breakpoint (bpt->address,
- bpt->shadow_contents);
+ val = target_insert_hw_breakpoint (&bpt->target_info);
else
- val = target_insert_breakpoint (bpt->address,
- bpt->shadow_contents);
+ val = target_insert_breakpoint (&bpt->target_info);
}
else
{
if (val)
{
/* Can't set the breakpoint. */
- if (
-#if defined (DISABLE_UNSETTABLE_BREAK)
- DISABLE_UNSETTABLE_BREAK (bpt->address)
-#else
- solib_address (bpt->address)
-#endif
- )
+ if (solib_address (bpt->address))
{
/* See also: disable_breakpoints_in_shlibs. */
val = 0;
- bpt->owner->enable_state = bp_shlib_disabled;
+ bpt->shlib_disabled = 1;
if (!*disabled_breaks)
{
fprintf_unfiltered (tmp_error_stream,
/* 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 (deprecated_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)
/* 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->address, bpt->shadow_contents);
+ val = target_insert_breakpoint (&bpt->target_info);
if (val)
{
/* Couldn't set breakpoint for some reason */
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;
struct bp_location *b;
int val;
struct cleanup *old_chain = save_inferior_ptid ();
+ struct ui_file *tmp_error_stream = mem_fileopen ();
+ int dummy1 = 0, dummy2 = 0, dummy3 = 0;
+
+ make_cleanup_ui_file_delete (tmp_error_stream);
- /* Set inferior_ptid; remove_breakpoint uses this global. */
inferior_ptid = pid_to_ptid (pid);
ALL_BP_LOCATIONS (b)
{
if (b->inserted)
{
- remove_breakpoint (b, mark_inserted);
- if (b->loc_type == bp_loc_hardware_breakpoint)
- val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
- else
- val = target_insert_breakpoint (b->address, b->shadow_contents);
- /* FIXME drow/2003-10-07: This doesn't handle any other kinds of
- breakpoints. It's wrong for watchpoints, for example. */
+ b->inserted = 0;
+ val = insert_bp_location (b, tmp_error_stream,
+ &dummy1, &dummy2, &dummy3);
if (val != 0)
{
do_cleanups (old_chain);
continue;
}
- /* Ditto the sigtramp handler breakpoints. */
- if (b->type == bp_through_sigtramp)
- {
- delete_breakpoint (b);
- continue;
- }
-
/* Ditto the exception-handling catchpoints. */
if ((b->type == bp_catch_catch) || (b->type == bp_catch_throw))
{
on this target, we may not be able to stop when the vfork is
seen, but only when the subsequent exec is seen. (And because
deleting fork catchpoints here but not vfork catchpoints will
- seem mysterious to users, keep those too.)
-
- ??rehrauer: Let's hope that merely clearing out this catchpoint's
- target address field, if any, is sufficient to have it be reset
- automagically. Certainly on HP-UX that's true.
-
- valid code address on some platforms (like the mn10300
- simulators). We shouldn't assign any special interpretation to
- a breakpoint with a zero address. And in fact, GDB doesn't ---
- I can't see what that comment above is talking about. As far
- as I can tell, setting the address of a
- bp_catch_exec/bp_catch_vfork/bp_catch_fork breakpoint to zero
- is meaningless, since those are implemented with HP-UX kernel
- hackery, not by storing breakpoint instructions somewhere. */
+ seem mysterious to users, keep those too.) */
if ((b->type == bp_catch_exec) ||
(b->type == bp_catch_vfork) ||
(b->type == bp_catch_fork))
{
- b->loc->address = (CORE_ADDR) NULL;
continue;
}
delete_breakpoint (b);
continue;
}
-
- /* If this breakpoint has survived the above battery of checks, then
- it must have a symbolic address. Be sure that it gets reevaluated
- to a target address, rather than reusing the old evaluation.
-
- for bp_catch_exec and friends, I'm pretty sure this is entirely
- unnecessary. A call to breakpoint_re_set_one always recomputes
- the breakpoint's address from scratch, or deletes it if it can't.
- So I think this assignment could be deleted without effect. */
- b->loc->address = (CORE_ADDR) NULL;
}
/* FIXME what about longjmp breakpoints? Re-create them here? */
create_overlay_event_breakpoint ("_ovly_debug_event");
/* No overlay handling: just remove the breakpoint. */
if (b->loc_type == bp_loc_hardware_breakpoint)
- val = target_remove_hw_breakpoint (b->address,
- b->shadow_contents);
+ val = target_remove_hw_breakpoint (&b->target_info);
else
- val = target_remove_breakpoint (b->address, b->shadow_contents);
+ val = target_remove_breakpoint (&b->target_info);
}
else
{
/* Yes -- overlay event support is not active, so we
should have set a breakpoint at the LMA. Remove it.
*/
- CORE_ADDR addr = overlay_unmapped_address (b->address,
- b->section);
/* Ignore any failures: if the LMA is in ROM, we will
have already warned when we failed to insert it. */
if (b->loc_type == bp_loc_hardware_breakpoint)
- target_remove_hw_breakpoint (addr, b->shadow_contents);
+ target_remove_hw_breakpoint (&b->overlay_target_info);
else
- target_remove_breakpoint (addr, b->shadow_contents);
+ target_remove_breakpoint (&b->overlay_target_info);
}
/* Did we set a breakpoint at the VMA?
If so, we will have marked the breakpoint 'inserted'. */
unmapped, but let's not rely on that being safe. We
don't know what the overlay manager might do. */
if (b->loc_type == bp_loc_hardware_breakpoint)
- val = target_remove_hw_breakpoint (b->address,
- b->shadow_contents);
+ val = target_remove_hw_breakpoint (&b->target_info);
+
+ /* However, we should remove *software* breakpoints only
+ if the section is still mapped, or else we overwrite
+ wrong code with the saved shadow contents. */
+ else if (section_is_mapped (b->section))
+ val = target_remove_breakpoint (&b->target_info);
else
- val = target_remove_breakpoint (b->address,
- b->shadow_contents);
+ val = 0;
}
else
{
&& breakpoint_enabled (b->owner)
&& !b->duplicate)
{
-
- val = target_remove_breakpoint (b->address, b->shadow_contents);
- if (val)
- return val;
- b->inserted = (is == mark_inserted);
- }
- else if (ep_is_exception_catchpoint (b->owner)
- && b->inserted /* sometimes previous insert doesn't happen */
- && breakpoint_enabled (b->owner)
- && !b->duplicate)
- {
-
- val = target_remove_breakpoint (b->address, b->shadow_contents);
+ val = target_remove_breakpoint (&b->target_info);
if (val)
return val;
-
b->inserted = (is == mark_inserted);
}
/* Clear the "inserted" flag in all breakpoints. */
-void
+static void
mark_breakpoints_out (void)
{
struct bp_location *bpt;
{
struct breakpoint *b, *temp;
struct bp_location *bpt;
- static int warning_needed = 0;
ALL_BP_LOCATIONS (bpt)
bpt->inserted = 0;
/* Likewise for watchpoints on local expressions. */
if (b->exp_valid_block != NULL)
delete_breakpoint (b);
- if (context == inf_starting)
+ else if (context == inf_starting)
{
/* Reset val field to force reread of starting value
in insert_breakpoints. */
}
break;
default:
- /* Likewise for exception catchpoints in dynamic-linked
- executables where required */
- if (ep_is_exception_catchpoint (b)
- && deprecated_exception_catchpoints_are_fragile)
- {
- warning_needed = 1;
- delete_breakpoint (b);
- }
break;
}
}
-
- if (deprecated_exception_catchpoints_are_fragile)
- deprecated_exception_support_initialized = 0;
-
- /* Don't issue the warning unless it's really needed... */
- if (warning_needed && (context != inf_exited))
- {
- warning (_("Exception catchpoints from last run were deleted.\n"
- "You must reinsert them explicitly."));
- warning_needed = 0;
- }
}
/* breakpoint_here_p (PC) returns non-zero if an enabled breakpoint
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;
+
+ if (single_step_breakpoint_inserted_here_p (pc))
+ return 1;
return 0;
}
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)
if (bpt->loc_type != bp_loc_software_breakpoint)
continue;
- if ((breakpoint_enabled (bpt->owner)
- || bpt->owner->enable_state == bp_permanent)
- && bpt->inserted
+ if (bpt->inserted
&& bpt->address == pc) /* bp is enabled and matches pc */
{
if (overlay_debugging
}
}
+ /* Also check for software single-step breakpoints. */
+ if (single_step_breakpoint_inserted_here_p (pc))
+ return 1;
+
return 0;
}
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_throw);
}
+void
+bpstat_free (bpstat bs)
+{
+ if (bs->old_val != NULL)
+ value_free (bs->old_val);
+ free_command_lines (&bs->commands);
+ xfree (bs);
+}
+
/* Clear a bpstat so that it says we are not at any breakpoint.
Also free any storage that is part of a bpstat. */
while (p != NULL)
{
q = p->next;
- if (p->old_val != NULL)
- value_free (p->old_val);
- free_command_lines (&p->commands);
- xfree (p);
+ bpstat_free (p);
p = q;
}
*bsp = NULL;
for (; bsp != NULL; bsp = bsp->next)
{
- if (bsp->breakpoint_at == breakpoint)
+ if (bsp->breakpoint_at && bsp->breakpoint_at->owner == breakpoint)
return bsp;
}
return NULL;
for (; bsp != NULL; bsp = bsp->next)
{
if ((bsp->breakpoint_at != NULL) &&
- (bsp->breakpoint_at->type == bp_step_resume) &&
- (bsp->breakpoint_at->thread == current_thread ||
- bsp->breakpoint_at->thread == -1))
- return bsp->breakpoint_at;
+ (bsp->breakpoint_at->owner->type == bp_step_resume) &&
+ (bsp->breakpoint_at->owner->thread == current_thread ||
+ bsp->breakpoint_at->owner->thread == -1))
+ return bsp->breakpoint_at->owner;
}
internal_error (__FILE__, __LINE__, _("No step_resume breakpoint found."));
}
-/* Return the breakpoint number of the first breakpoint we are stopped
+/* Put in *NUM the breakpoint number of the first breakpoint we are stopped
at. *BSP upon return is a bpstat which points to the remaining
breakpoints stopped at (but which is not guaranteed to be good for
anything but further calls to bpstat_num).
- Return 0 if passed a bpstat which does not indicate any breakpoints. */
+ Return 0 if passed a bpstat which does not indicate any breakpoints.
+ Return -1 if stopped at a breakpoint that has been deleted since
+ we set it.
+ Return 1 otherwise. */
int
-bpstat_num (bpstat *bsp)
+bpstat_num (bpstat *bsp, int *num)
{
struct breakpoint *b;
if ((*bsp) == NULL)
return 0; /* No more breakpoint values */
- else
- {
- b = (*bsp)->breakpoint_at;
- *bsp = (*bsp)->next;
- if (b == NULL)
- return -1; /* breakpoint that's been deleted since */
- else
- return b->number; /* We have its number */
- }
+
+ /* We assume we'll never have several bpstats that
+ correspond to a single breakpoint -- otherwise,
+ this function might return the same number more
+ than once and this will look ugly. */
+ b = (*bsp)->breakpoint_at ? (*bsp)->breakpoint_at->owner : NULL;
+ *bsp = (*bsp)->next;
+ if (b == NULL)
+ return -1; /* breakpoint that's been deleted since */
+
+ *num = b->number; /* We have its number */
+ return 1;
}
/* Modify BS so that the actions will not be performed. */
print_it_typical (bpstat bs)
{
struct cleanup *old_chain, *ui_out_chain;
+ struct breakpoint *b;
+ const struct bp_location *bl;
struct ui_stream *stb;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
which has since been deleted. */
if (bs->breakpoint_at == NULL)
return PRINT_UNKNOWN;
+ bl = bs->breakpoint_at;
+ b = bl->owner;
- switch (bs->breakpoint_at->type)
+ switch (b->type)
{
case bp_breakpoint:
case bp_hardware_breakpoint:
- if (bs->breakpoint_at->loc->address != bs->breakpoint_at->loc->requested_address)
- breakpoint_adjustment_warning (bs->breakpoint_at->loc->requested_address,
- bs->breakpoint_at->loc->address,
- bs->breakpoint_at->number, 1);
- annotate_breakpoint (bs->breakpoint_at->number);
+ if (bl->address != bl->requested_address)
+ breakpoint_adjustment_warning (bl->requested_address,
+ bl->address,
+ b->number, 1);
+ annotate_breakpoint (b->number);
ui_out_text (uiout, "\nBreakpoint ");
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "reason",
async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
- ui_out_field_int (uiout, "bkptno", bs->breakpoint_at->number);
+ ui_out_field_int (uiout, "bkptno", b->number);
ui_out_text (uiout, ", ");
return PRINT_SRC_AND_LOC;
break;
break;
case bp_catch_load:
- annotate_catchpoint (bs->breakpoint_at->number);
+ annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (loaded %s), "),
- bs->breakpoint_at->number,
- bs->breakpoint_at->triggered_dll_pathname);
+ b->number,
+ b->triggered_dll_pathname);
return PRINT_SRC_AND_LOC;
break;
case bp_catch_unload:
- annotate_catchpoint (bs->breakpoint_at->number);
+ annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (unloaded %s), "),
- bs->breakpoint_at->number,
- bs->breakpoint_at->triggered_dll_pathname);
+ b->number,
+ b->triggered_dll_pathname);
return PRINT_SRC_AND_LOC;
break;
case bp_catch_fork:
- annotate_catchpoint (bs->breakpoint_at->number);
+ annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (forked process %d), "),
- bs->breakpoint_at->number,
- bs->breakpoint_at->forked_inferior_pid);
+ b->number,
+ b->forked_inferior_pid);
return PRINT_SRC_AND_LOC;
break;
case bp_catch_vfork:
- annotate_catchpoint (bs->breakpoint_at->number);
+ annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
- bs->breakpoint_at->number,
- bs->breakpoint_at->forked_inferior_pid);
+ b->number,
+ b->forked_inferior_pid);
return PRINT_SRC_AND_LOC;
break;
case bp_catch_exec:
- annotate_catchpoint (bs->breakpoint_at->number);
+ annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (exec'd %s), "),
- bs->breakpoint_at->number,
- bs->breakpoint_at->exec_pathname);
+ b->number,
+ b->exec_pathname);
return PRINT_SRC_AND_LOC;
break;
if (current_exception_event &&
(CURRENT_EXCEPTION_KIND == EX_EVENT_CATCH))
{
- annotate_catchpoint (bs->breakpoint_at->number);
+ annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (exception caught), "),
- bs->breakpoint_at->number);
+ b->number);
if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
printf_filtered (_("throw location %s:%d, "),
CURRENT_EXCEPTION_THROW_FILE,
if (current_exception_event &&
(CURRENT_EXCEPTION_KIND == EX_EVENT_THROW))
{
- annotate_catchpoint (bs->breakpoint_at->number);
+ annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (exception thrown), "),
- bs->breakpoint_at->number);
+ b->number);
if (CURRENT_EXCEPTION_THROW_PC && CURRENT_EXCEPTION_THROW_LINE)
printf_filtered (_("throw location %s:%d, "),
CURRENT_EXCEPTION_THROW_FILE,
case bp_hardware_watchpoint:
if (bs->old_val != NULL)
{
- annotate_watchpoint (bs->breakpoint_at->number);
+ 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 (bs->breakpoint_at);
+ 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 (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
+ 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");
ui_out_field_string
(uiout, "reason",
async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
- mention (bs->breakpoint_at);
+ mention (b);
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nValue = ");
- value_print (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
+ value_print (b->val, stb->stream, 0, Val_pretty_default);
ui_out_field_stream (uiout, "value", stb);
do_cleanups (ui_out_chain);
ui_out_text (uiout, "\n");
case bp_access_watchpoint:
if (bs->old_val != NULL)
{
- annotate_watchpoint (bs->breakpoint_at->number);
+ annotate_watchpoint (b->number);
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason",
async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
- mention (bs->breakpoint_at);
+ 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);
}
else
{
- mention (bs->breakpoint_at);
+ mention (b);
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason",
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nValue = ");
}
- value_print (bs->breakpoint_at->val, stb->stream, 0,Val_pretty_default);
+ 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");
case bp_until:
if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string (uiout, "reason", "location-reached");
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_LOCATION_REACHED));
return PRINT_UNKNOWN;
break;
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
- case bp_through_sigtramp:
case bp_watchpoint_scope:
case bp_call_dummy:
default:
break;
case print_it_normal:
- /* Normal case. Call the breakpoint's print_it method, or
- print_it_typical. */
- if (bs->breakpoint_at != NULL && bs->breakpoint_at->ops != NULL
- && bs->breakpoint_at->ops->print_it != NULL)
- return bs->breakpoint_at->ops->print_it (bs->breakpoint_at);
- else
- return print_it_typical (bs);
- break;
+ {
+ 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
+ print_it_typical. */
+ /* FIXME: how breakpoint can ever be NULL here? */
+ if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
+ return b->ops->print_it (b);
+ else
+ return print_it_typical (bs);
+ }
+ break;
default:
internal_error (__FILE__, __LINE__,
/* Allocate a new bpstat and chain it to the current one. */
static bpstat
-bpstat_alloc (struct breakpoint *b, bpstat cbs /* Current "bs" value */ )
+bpstat_alloc (const struct bp_location *bl, bpstat cbs /* Current "bs" value */ )
{
bpstat bs;
bs = (bpstat) xmalloc (sizeof (*bs));
cbs->next = bs;
- bs->breakpoint_at = b;
+ bs->breakpoint_at = bl;
/* If the condition is false, etc., don't do the commands. */
bs->commands = NULL;
bs->old_val = NULL;
return bs;
}
\f
+/* The target has stopped with waitstatus WS. Check if any hardware
+ watchpoints have triggered, according to the target. */
+
+int
+watchpoints_triggered (struct target_waitstatus *ws)
+{
+ int stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (*ws);
+ CORE_ADDR addr;
+ struct breakpoint *b;
+
+ if (!stopped_by_watchpoint)
+ {
+ /* We were not stopped by a watchpoint. Mark all watchpoints
+ as not triggered. */
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ b->watchpoint_triggered = watch_triggered_no;
+
+ return 0;
+ }
+
+ if (!target_stopped_data_address (¤t_target, &addr))
+ {
+ /* We were stopped by a watchpoint, but we don't know where.
+ Mark all watchpoints as unknown. */
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ b->watchpoint_triggered = watch_triggered_unknown;
+
+ return stopped_by_watchpoint;
+ }
+
+ /* The target could report the data address. Mark watchpoints
+ affected by this data address as triggered, and all others as not
+ triggered. */
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint)
+ {
+ 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;
+ }
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
/* Possible return values for watchpoint_check (this can't be an enum
because of check_errors). */
/* The watchpoint has been deleted. */
struct frame_info *fr;
int within_current_scope;
- b = bs->breakpoint_at;
+ b = bs->breakpoint_at->owner;
if (b->exp_valid_block == NULL)
within_current_scope = 1;
reinit_frame_cache ();
fr = frame_find_by_id (b->watchpoint_frame);
within_current_scope = (fr != NULL);
+
+ /* If we've gotten confused in the unwinder, we might have
+ returned a frame that can't describe this variable. */
+ if (within_current_scope
+ && block_function (b->exp_valid_block) != get_frame_function (fr))
+ within_current_scope = 0;
+
/* in_function_epilogue_p() returns a non-zero value if we're still
in the function but the stack frame has already been invalidated.
Since we can't rely on the values of local variables after the
we might be in the middle of evaluating a function call. */
struct value *mark = value_mark ();
- struct value *new_val = evaluate_expression (bs->breakpoint_at->exp);
+ struct value *new_val = evaluate_expression (b->exp);
if (!value_equal (b->val, new_val))
{
release_value (new_val);
ui_out_field_string
(uiout, "reason", async_reason_lookup (EXEC_ASYNC_WATCHPOINT_SCOPE));
ui_out_text (uiout, "\nWatchpoint ");
- ui_out_field_int (uiout, "wpnum", bs->breakpoint_at->number);
+ ui_out_field_int (uiout, "wpnum", b->number);
ui_out_text (uiout, " deleted because the program has left the block in\n\
which its expression is valid.\n");
}
/* Get a bpstat associated with having just stopped at address
- BP_ADDR in thread PTID. STOPPED_BY_WATCHPOINT is 1 if the
- target thinks we stopped due to a hardware watchpoint, 0 if we
- know we did not trigger a hardware watchpoint, and -1 if we do not know. */
+ BP_ADDR in thread PTID.
-/* Determine whether we stopped at a breakpoint, etc, or whether we
+ Determine whether we stopped at a breakpoint, etc, or whether we
don't understand this stop. Result is a chain of bpstat's such that:
if we don't understand the stop, the result is a null pointer.
commands, FIXME??? fields. */
bpstat
-bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid, int stopped_by_watchpoint)
+bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
{
- struct breakpoint *b, *temp;
+ struct breakpoint *b = NULL;
+ const struct bp_location *bl;
/* True if we've hit a breakpoint (as opposed to a watchpoint). */
int real_breakpoint = 0;
/* Root of the chain of bpstat's */
bpstat bs = root_bs;
int thread_id = pid_to_thread_id (ptid);
- ALL_BREAKPOINTS_SAFE (b, temp)
+ ALL_BP_LOCATIONS (bl)
{
+ b = bl->owner;
+ gdb_assert (b);
if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
continue;
&& b->type != bp_catch_catch
&& b->type != bp_catch_throw) /* a non-watchpoint bp */
{
- if (b->loc->address != bp_addr) /* address doesn't match */
+ if (bl->address != bp_addr) /* address doesn't match */
continue;
if (overlay_debugging /* unmapped overlay section */
- && section_is_overlay (b->loc->section)
- && !section_is_mapped (b->loc->section))
+ && section_is_overlay (bl->section)
+ && !section_is_mapped (bl->section))
continue;
}
- /* Continuable hardware watchpoints are treated as non-existent if the
- reason we stopped wasn't a hardware watchpoint (we didn't stop on
- some data address). Otherwise gdb won't stop on a break instruction
- in the code (not from a breakpoint) when a hardware watchpoint has
- been defined. */
+ /* Continuable hardware watchpoints are treated as non-existent if the
+ reason we stopped wasn't a hardware watchpoint (we didn't stop on
+ some data address). Otherwise gdb won't stop on a break instruction
+ in the code (not from a breakpoint) when a hardware watchpoint has
+ been defined. Also skip watchpoints which we know did not trigger
+ (did not match the data address). */
if ((b->type == bp_hardware_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint)
- && !stopped_by_watchpoint)
+ && b->watchpoint_triggered == watch_triggered_no)
continue;
if (b->type == bp_hardware_breakpoint)
{
- if (b->loc->address != bp_addr)
+ if (bl->address != bp_addr)
continue;
if (overlay_debugging /* unmapped overlay section */
- && section_is_overlay (b->loc->section)
- && !section_is_mapped (b->loc->section))
+ && section_is_overlay (bl->section)
+ && !section_is_mapped (bl->section))
continue;
}
/* Come here if it's a watchpoint, or if the break address matches */
- bs = bpstat_alloc (b, bs); /* Alloc a bpstat to explain stop */
+ bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
/* Watchpoints may change this, if not found to have triggered. */
bs->stop = 1;
bs->print = 1;
- if (b->type == bp_watchpoint ||
- b->type == bp_hardware_watchpoint)
- {
- char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
- b->number);
- struct cleanup *cleanups = make_cleanup (xfree, message);
- int e = catch_errors (watchpoint_check, bs, message,
- RETURN_MASK_ALL);
- do_cleanups (cleanups);
- switch (e)
- {
- case WP_DELETED:
- /* We've already printed what needs to be printed. */
- /* Actually this is superfluous, because by the time we
- call print_it_typical() the wp will be already deleted,
- and the function will return immediately. */
- bs->print_it = print_it_done;
- /* Stop. */
- break;
- case WP_VALUE_CHANGED:
- /* Stop. */
- ++(b->hit_count);
- break;
- case WP_VALUE_NOT_CHANGED:
- /* Don't stop. */
- bs->print_it = print_it_noop;
- bs->stop = 0;
- continue;
- default:
- /* Can't happen. */
- /* FALLTHROUGH */
- case 0:
- /* Error from catch_errors. */
- printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
- if (b->related_breakpoint)
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->disposition = disp_del_at_next_stop;
- /* We've already printed what needs to be printed. */
- bs->print_it = print_it_done;
-
- /* Stop. */
- break;
- }
- }
- else if (b->type == bp_read_watchpoint ||
- b->type == bp_access_watchpoint)
+ if (b->type == bp_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint
+ || b->type == bp_hardware_watchpoint)
{
CORE_ADDR addr;
struct value *v;
- int found = 0;
-
- if (!target_stopped_data_address (¤t_target, &addr))
- continue;
- 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)))
- found = 1;
- }
- }
- }
- if (found)
+ int must_check_value = 0;
+
+ if (b->type == bp_watchpoint)
+ /* For a software watchpoint, we must always check the
+ watched value. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_yes)
+ /* We have a hardware watchpoint (read, write, or access)
+ and the target earlier reported an address watched by
+ this watchpoint. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_unknown
+ && b->type == bp_hardware_watchpoint)
+ /* We were stopped by a hardware watchpoint, but the target could
+ not report the data address. We must check the watchpoint's
+ value. Access and read watchpoints are out of luck; without
+ a data address, we can't figure it out. */
+ must_check_value = 1;
+
+ if (must_check_value)
{
char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
b->number);
++(b->hit_count);
break;
case WP_VALUE_NOT_CHANGED:
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_watchpoint)
+ {
+ /* Don't stop: write watchpoints shouldn't fire if
+ the value hasn't changed. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
/* Stop. */
++(b->hit_count);
break;
break;
}
}
- else /* found == 0 */
+ else /* must_check_value == 0 */
{
- /* This is a case where some watchpoint(s) triggered,
- but not at the address of this watchpoint (FOUND
- was left zero). So don't print anything for this
- watchpoint. */
+ /* This is a case where some watchpoint(s) triggered, but
+ not at the address of this watchpoint, or else no
+ watchpoint triggered after all. So don't print
+ anything for this watchpoint. */
bs->print_it = print_it_noop;
bs->stop = 0;
continue;
{
int value_is_zero = 0;
- if (b->cond)
+ /* If this is a scope breakpoint, mark the associated
+ watchpoint as triggered so that we will handle the
+ out-of-scope event. We'll get to the watchpoint next
+ iteration. */
+ if (b->type == bp_watchpoint_scope)
+ b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
+
+ if (bl->cond)
{
/* Need to select the frame, with all that implies
so that the conditions will have the right context. */
select_frame (get_current_frame ());
value_is_zero
- = catch_errors (breakpoint_cond_eval, (b->cond),
+ = catch_errors (breakpoint_cond_eval, (bl->cond),
"Error in testing breakpoint condition:\n",
RETURN_MASK_ALL);
/* FIXME-someday, should give breakpoint # */
free_all_values ();
}
- if (b->cond && value_is_zero)
+ if (bl->cond && value_is_zero)
{
bs->stop = 0;
/* Don't consider this a hit. */
annotate_ignore_count_change ();
bs->stop = 0;
}
+ else if (b->type == bp_thread_event || b->type == bp_overlay_event)
+ /* We do not stop for these. */
+ bs->stop = 0;
else
{
/* We will stop here */
bs->next = NULL; /* Terminate the chain */
bs = root_bs->next; /* Re-grab the head of the chain */
- /* The value of a hardware watchpoint hasn't changed, but the
- intermediate memory locations we are watching may have. */
- if (bs && !bs->stop &&
- (bs->breakpoint_at->type == bp_hardware_watchpoint ||
- bs->breakpoint_at->type == bp_read_watchpoint ||
- bs->breakpoint_at->type == bp_access_watchpoint))
- {
- remove_breakpoints ();
- insert_breakpoints ();
- }
- return bs;
+ /* If we aren't stopping, the value of some hardware watchpoint may
+ not have changed, but the intermediate memory locations we are
+ watching may have. Don't bother if we're stopping; this will get
+ done later. */
+ for (bs = root_bs->next; bs != NULL; bs = bs->next)
+ if (bs->stop)
+ break;
+
+ if (bs == NULL)
+ for (bs = root_bs->next; bs != NULL; bs = bs->next)
+ if (!bs->stop
+ && (bs->breakpoint_at->owner->type == bp_hardware_watchpoint
+ || bs->breakpoint_at->owner->type == bp_read_watchpoint
+ || bs->breakpoint_at->owner->type == bp_access_watchpoint))
+ {
+ remove_breakpoints ();
+ insert_breakpoints ();
+ break;
+ }
+
+ return root_bs->next;
}
\f
/* Tell what to do about this bpstat. */
/* We hit the step_resume breakpoint. */
step_resume,
- /* We hit the through_sigtramp breakpoint. */
- through_sig,
-
/* We hit the shared library event breakpoint. */
shlib_event,
#define clr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME
#define clrs BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE
#define sr BPSTAT_WHAT_STEP_RESUME
-#define ts BPSTAT_WHAT_THROUGH_SIGTRAMP
#define shl BPSTAT_WHAT_CHECK_SHLIBS
#define shlr BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK
back and decide something of a lower priority is better. The
ordering is:
- kc < clr sgl shl shlr slr sn sr ss ts
- sgl < clrs shl shlr slr sn sr ss ts
- slr < err shl shlr sn sr ss ts
- clr < clrs err shl shlr sn sr ss ts
- clrs < err shl shlr sn sr ss ts
- ss < shl shlr sn sr ts
- sn < shl shlr sr ts
- sr < shl shlr ts
- shl < shlr
- ts <
- shlr <
+ kc < clr sgl shl shlr slr sn sr ss
+ sgl < clrs shl shlr slr sn sr ss
+ slr < err shl shlr sn sr ss
+ clr < clrs err shl shlr sn sr ss
+ clrs < err shl shlr sn sr ss
+ ss < shl shlr sn sr
+ sn < shl shlr sr
+ shl < shlr sr
+ shlr < sr
+ sr <
What I think this means is that we don't need a damned table
here. If you just put the rows and columns in the right order,
/* step_resume entries: a step resume breakpoint overrides another
breakpoint of signal handling (see comment in wait_for_inferior
at where we set the step_resume breakpoint). */
- /* We handle the through_sigtramp_breakpoint the same way; having both
- one of those and a step_resume_breakpoint is probably very rare (?). */
static const enum bpstat_what_main_action
table[(int) class_last][(int) BPSTAT_WHAT_LAST] =
{
/* old action */
- /* kc ss sn sgl slr clr clrs sr ts shl shlr
+ /* kc ss sn sgl slr clr clrs sr shl shlr
*/
/*no_effect */
- {kc, ss, sn, sgl, slr, clr, clrs, sr, ts, shl, shlr},
+ {kc, ss, sn, sgl, slr, clr, clrs, sr, shl, shlr},
/*wp_silent */
- {ss, ss, sn, ss, ss, ss, ss, sr, ts, shl, shlr},
+ {ss, ss, sn, ss, ss, ss, ss, sr, shl, shlr},
/*wp_noisy */
- {sn, sn, sn, sn, sn, sn, sn, sr, ts, shl, shlr},
+ {sn, sn, sn, sn, sn, sn, sn, sr, shl, shlr},
/*bp_nostop */
- {sgl, ss, sn, sgl, slr, clrs, clrs, sr, ts, shl, shlr},
+ {sgl, ss, sn, sgl, slr, clrs, clrs, sr, shl, shlr},
/*bp_silent */
- {ss, ss, sn, ss, ss, ss, ss, sr, ts, shl, shlr},
+ {ss, ss, sn, ss, ss, ss, ss, sr, shl, shlr},
/*bp_noisy */
- {sn, sn, sn, sn, sn, sn, sn, sr, ts, shl, shlr},
+ {sn, sn, sn, sn, sn, sn, sn, sr, shl, shlr},
/*long_jump */
- {slr, ss, sn, slr, slr, err, err, sr, ts, shl, shlr},
+ {slr, ss, sn, slr, slr, err, err, sr, shl, shlr},
/*long_resume */
- {clr, ss, sn, clrs, err, err, err, sr, ts, shl, shlr},
+ {clr, ss, sn, clrs, err, err, err, sr, shl, shlr},
/*step_resume */
- {sr, sr, sr, sr, sr, sr, sr, sr, ts, shl, shlr},
-/*through_sig */
- {ts, ts, ts, ts, ts, ts, ts, ts, ts, shl, shlr},
+ {sr, sr, sr, sr, sr, sr, sr, sr, sr, sr},
/*shlib */
- {shl, shl, shl, shl, shl, shl, shl, shl, ts, shl, shlr},
+ {shl, shl, shl, shl, shl, shl, shl, sr, shl, shlr},
/*catch_shlib */
- {shlr, shlr, shlr, shlr, shlr, shlr, shlr, shlr, ts, shlr, shlr}
+ {shlr, shlr, shlr, shlr, shlr, shlr, shlr, sr, shlr, shlr}
};
#undef kc
/* I suspect this can happen if it was a momentary breakpoint
which has since been deleted. */
continue;
- switch (bs->breakpoint_at->type)
+ switch (bs->breakpoint_at->owner->type)
{
case bp_none:
continue;
/* It is for the wrong frame. */
bs_class = bp_nostop;
break;
- case bp_through_sigtramp:
- bs_class = through_sig;
- break;
case bp_watchpoint_scope:
bs_class = bp_nostop;
break;
int
bpstat_have_active_hw_watchpoints (void)
{
- struct bp_location *bpt;
+ const struct bp_location *bpt;
ALL_BP_LOCATIONS (bpt)
if (breakpoint_enabled (bpt->owner)
&& bpt->inserted
for (; ep_list != NULL; ep_list = ep_list->next)
{
/* Is this eventpoint a catchpoint? If not, ignore it. */
- ep = ep_list->breakpoint_at;
+ ep = ep_list->breakpoint_at->owner;
if (ep == NULL)
break;
if ((ep->type != bp_catch_load) &&
continue;
/* Yes; add it to the list. */
- bs = bpstat_alloc (ep, bs);
+ bs = bpstat_alloc (ep_list->breakpoint_at, bs);
*bs = *ep_list;
bs->next = NULL;
bs = root_bs->next;
*cp_list = bs;
}
+static void print_breakpoint_location (struct breakpoint *b,
+ struct bp_location *loc,
+ char *wrap_indent,
+ struct ui_stream *stb)
+{
+ if (b->source_file)
+ {
+ struct symbol *sym
+ = find_pc_sect_function (loc->address, loc->section);
+ if (sym)
+ {
+ ui_out_text (uiout, "in ");
+ ui_out_field_string (uiout, "func",
+ SYMBOL_PRINT_NAME (sym));
+ ui_out_wrap_hint (uiout, wrap_indent);
+ ui_out_text (uiout, " at ");
+ }
+ ui_out_field_string (uiout, "file", b->source_file);
+ ui_out_text (uiout, ":");
+
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ struct symtab_and_line sal = find_pc_line (loc->address, 0);
+ char *fullname = symtab_to_fullname (sal.symtab);
+
+ if (fullname)
+ ui_out_field_string (uiout, "fullname", fullname);
+ }
+
+ ui_out_field_int (uiout, "line", b->line_number);
+ }
+ else if (!b->loc)
+ {
+ ui_out_field_string (uiout, "pending", b->addr_string);
+ }
+ else
+ {
+ print_address_symbolic (loc->address, stb->stream, demangle, "");
+ ui_out_field_stream (uiout, "at", stb);
+ }
+}
+
/* Print B to gdb_stdout. */
static void
-print_one_breakpoint (struct breakpoint *b,
- CORE_ADDR *last_addr)
+print_one_breakpoint_location (struct breakpoint *b,
+ struct bp_location *loc,
+ int loc_number,
+ CORE_ADDR *last_addr)
{
struct command_line *l;
struct symbol *sym;
{bp_longjmp, "longjmp"},
{bp_longjmp_resume, "longjmp resume"},
{bp_step_resume, "step resume"},
- {bp_through_sigtramp, "sigtramp"},
{bp_watchpoint_scope, "watchpoint scope"},
{bp_call_dummy, "call dummy"},
{bp_shlib_event, "shlib events"},
struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
struct cleanup *bkpt_chain;
+ int header_of_multiple = 0;
+ int part_of_multiple = (loc != NULL);
+
+ gdb_assert (!loc || loc_number != 0);
+ /* See comment in print_one_breakpoint concerning
+ treatment of breakpoints with single disabled
+ location. */
+ if (loc == NULL
+ && (b->loc != NULL
+ && (b->loc->next != NULL || !b->loc->enabled)))
+ header_of_multiple = 1;
+ if (loc == NULL)
+ loc = b->loc;
+
annotate_record ();
bkpt_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "bkpt");
/* 1 */
annotate_field (0);
- ui_out_field_int (uiout, "number", b->number);
-
- /* 2 */
- annotate_field (1);
- if (((int) b->type > (sizeof (bptypes) / sizeof (bptypes[0])))
- || ((int) b->type != bptypes[(int) b->type].type))
- internal_error (__FILE__, __LINE__,
- _("bptypes table does not describe type #%d."),
- (int) b->type);
- ui_out_field_string (uiout, "type", bptypes[(int) b->type].description);
-
+ if (part_of_multiple)
+ {
+ char *formatted;
+ formatted = xstrprintf ("%d.%d", b->number, loc_number);
+ ui_out_field_string (uiout, "number", formatted);
+ xfree (formatted);
+ }
+ else
+ {
+ ui_out_field_int (uiout, "number", b->number);
+ }
+
+ /* 2 */
+ annotate_field (1);
+ if (part_of_multiple)
+ ui_out_field_skip (uiout, "type");
+ else
+ {
+ if (((int) b->type >= (sizeof (bptypes) / sizeof (bptypes[0])))
+ || ((int) b->type != bptypes[(int) b->type].type))
+ internal_error (__FILE__, __LINE__,
+ _("bptypes table does not describe type #%d."),
+ (int) b->type);
+ ui_out_field_string (uiout, "type", bptypes[(int) b->type].description);
+ }
+
/* 3 */
annotate_field (2);
- ui_out_field_string (uiout, "disp", bpdisps[(int) b->disposition]);
+ if (part_of_multiple)
+ ui_out_field_skip (uiout, "disp");
+ else
+ ui_out_field_string (uiout, "disp", bpdisps[(int) b->disposition]);
+
/* 4 */
annotate_field (3);
- ui_out_field_fmt (uiout, "enabled", "%c", bpenables[(int) b->enable_state]);
- ui_out_spaces (uiout, 2);
+ if (part_of_multiple)
+ ui_out_field_string (uiout, "enabled",
+ loc->shlib_disabled
+ ? (loc->enabled ? "y(p)" : "n(p)")
+ : (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);
+ }
+
/* 5 and 6 */
strcpy (wrap_indent, " ");
if (addressprint)
{
- if (TARGET_ADDR_BIT <= 32)
+ if (gdbarch_addr_bit (current_gdbarch) <= 32)
strcat (wrap_indent, " ");
else
strcat (wrap_indent, " ");
}
if (b->ops != NULL && b->ops->print_one != NULL)
- b->ops->print_one (b, last_addr);
+ {
+ /* Although the print_one can possibly print
+ all locations, calling it here is not likely
+ to get any nice result. So, make sure there's
+ just one location. */
+ gdb_assert (b->loc == NULL || b->loc->next == NULL);
+ b->ops->print_one (b, last_addr);
+ }
else
switch (b->type)
{
ui_out_field_int (uiout, "what", b->forked_inferior_pid);
ui_out_spaces (uiout, 1);
}
+ break;
case bp_catch_exec:
/* Field 4, the address, is omitted (which makes the columns
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
- case bp_through_sigtramp:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_shlib_event:
if (addressprint)
{
annotate_field (4);
- if (b->pending)
+ if (b->loc == NULL)
ui_out_field_string (uiout, "addr", "<PENDING>");
+ else if (header_of_multiple)
+ ui_out_field_string (uiout, "addr", "<MULTIPLE>");
else
- ui_out_field_core_addr (uiout, "addr", b->loc->address);
+ ui_out_field_core_addr (uiout, "addr", loc->address);
}
annotate_field (5);
- *last_addr = b->loc->address;
- if (b->source_file)
- {
- sym = find_pc_sect_function (b->loc->address, b->loc->section);
- if (sym)
- {
- ui_out_text (uiout, "in ");
- ui_out_field_string (uiout, "func",
- SYMBOL_PRINT_NAME (sym));
- ui_out_wrap_hint (uiout, wrap_indent);
- ui_out_text (uiout, " at ");
- }
- ui_out_field_string (uiout, "file", b->source_file);
- ui_out_text (uiout, ":");
- ui_out_field_int (uiout, "line", b->line_number);
- }
- else if (b->pending)
- {
- ui_out_field_string (uiout, "pending", b->addr_string);
- }
- else
- {
- print_address_symbolic (b->loc->address, stb->stream, demangle, "");
- ui_out_field_stream (uiout, "at", stb);
- }
+ if (!header_of_multiple)
+ print_breakpoint_location (b, loc, wrap_indent, stb);
+ if (b->loc)
+ *last_addr = b->loc->address;
break;
}
- if (b->thread != -1)
+ if (!part_of_multiple && b->thread != -1)
{
/* FIXME: This seems to be redundant and lost here; see the
"stop only in" line a little further down. */
ui_out_text (uiout, "\n");
- if (frame_id_p (b->frame_id))
+ if (part_of_multiple && frame_id_p (b->frame_id))
{
annotate_field (6);
ui_out_text (uiout, "\tstop only in stack frame at ");
ui_out_text (uiout, "\n");
}
- if (b->cond)
- {
- annotate_field (7);
- ui_out_text (uiout, "\tstop only if ");
- print_expression (b->cond, stb->stream);
- ui_out_field_stream (uiout, "cond", stb);
- ui_out_text (uiout, "\n");
- }
-
- if (b->pending && b->cond_string)
+ if (!part_of_multiple && b->cond_string && !ada_exception_catchpoint_p (b))
{
+ /* We do not print the condition for Ada exception catchpoints
+ because the condition is an internal implementation detail
+ that we do not want to expose to the user. */
annotate_field (7);
ui_out_text (uiout, "\tstop only if ");
ui_out_field_string (uiout, "cond", b->cond_string);
ui_out_text (uiout, "\n");
}
- if (b->thread != -1)
+ if (!part_of_multiple && b->thread != -1)
{
/* FIXME should make an annotation for this */
ui_out_text (uiout, "\tstop only in thread ");
ui_out_text (uiout, "\n");
}
- if (show_breakpoint_hit_counts && b->hit_count)
+ if (!part_of_multiple && show_breakpoint_hit_counts && b->hit_count)
{
/* FIXME should make an annotation for this */
if (ep_is_catchpoint (b))
/* Output the count also if it is zero, but only if this is
mi. FIXME: Should have a better test for this. */
if (ui_out_is_mi_like_p (uiout))
- if (show_breakpoint_hit_counts && b->hit_count == 0)
+ if (!part_of_multiple && show_breakpoint_hit_counts && b->hit_count == 0)
ui_out_field_int (uiout, "times", b->hit_count);
- if (b->ignore_count)
+ if (!part_of_multiple && b->ignore_count)
{
annotate_field (8);
ui_out_text (uiout, "\tignore next ");
ui_out_text (uiout, " hits\n");
}
- if ((l = b->commands))
+ if (!part_of_multiple && (l = b->commands))
{
struct cleanup *script_chain;
do_cleanups (old_chain);
}
+static void
+print_one_breakpoint (struct breakpoint *b,
+ CORE_ADDR *last_addr)
+{
+ print_one_breakpoint_location (b, NULL, 0, last_addr);
+
+ /* If this breakpoint has custom print function,
+ it's already printed. Otherwise, print individual
+ locations, if any. */
+ if (b->ops == NULL || b->ops->print_one == NULL)
+ {
+ /* If breakpoint has a single location that is
+ disabled, we print it as if it had
+ several locations, since otherwise it's hard to
+ represent "breakpoint enabled, location disabled"
+ situation. */
+ if (b->loc
+ && (b->loc->next || !b->loc->enabled)
+ && !ui_out_is_mi_like_p (uiout))
+ {
+ struct bp_location *loc;
+ int n = 1;
+ for (loc = b->loc; loc; loc = loc->next, ++n)
+ print_one_breakpoint_location (b, loc, n, last_addr);
+ }
+ }
+}
+
+
struct captured_breakpoint_query_args
{
int bnum;
args.bnum = bnum;
/* For the moment we don't trust print_one_breakpoint() to not throw
an error. */
- return catch_exceptions_with_msg (uiout, do_captured_breakpoint_query, &args,
- error_message, RETURN_MASK_ALL);
+ if (catch_exceptions_with_msg (uiout, do_captured_breakpoint_query, &args,
+ error_message, RETURN_MASK_ALL) < 0)
+ return GDB_RC_FAIL;
+ else
+ return GDB_RC_OK;
}
/* Return non-zero if B is user settable (breakpoints, watchpoints,
annotate_breakpoints_headers ();
if (nr_printable_breakpoints > 0)
annotate_field (0);
- ui_out_table_header (uiout, 3, ui_left, "number", "Num"); /* 1 */
+ ui_out_table_header (uiout, 7, ui_left, "number", "Num"); /* 1 */
if (nr_printable_breakpoints > 0)
annotate_field (1);
ui_out_table_header (uiout, 14, ui_left, "type", "Type"); /* 2 */
ui_out_table_header (uiout, 4, ui_left, "disp", "Disp"); /* 3 */
if (nr_printable_breakpoints > 0)
annotate_field (3);
- ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb"); /* 4 */
+ ui_out_table_header (uiout, 4, ui_left, "enabled", "Enb"); /* 4 */
if (addressprint)
{
if (nr_printable_breakpoints > 0)
annotate_field (4);
- if (TARGET_ADDR_BIT <= 32)
+ if (gdbarch_addr_bit (current_gdbarch) <= 32)
ui_out_table_header (uiout, 10, ui_left, "addr", "Address");/* 5 */
else
ui_out_table_header (uiout, 18, ui_left, "addr", "Address");/* 5 */
{
/* Compare against (CORE_ADDR)-1 in case some compiler decides
that a comparison of an unsigned with -1 is always false. */
- if (last_addr != (CORE_ADDR) -1)
+ if (last_addr != (CORE_ADDR) -1 && !server_command)
set_next_address (last_addr);
}
breakpoint_1 (bnum, 1);
}
+static int
+breakpoint_has_pc (struct breakpoint *b, CORE_ADDR pc, asection *section)
+{
+ struct bp_location *bl = b->loc;
+ for (; bl; bl = bl->next)
+ {
+ if (bl->address == pc
+ && (!overlay_debugging || bl->section == section))
+ return 1;
+ }
+ return 0;
+}
+
/* Print a message describing any breakpoints set at PC. */
static void
-describe_other_breakpoints (CORE_ADDR pc, asection *section)
+describe_other_breakpoints (CORE_ADDR pc, asection *section, int thread)
{
int others = 0;
struct breakpoint *b;
ALL_BREAKPOINTS (b)
- if (b->loc->address == pc) /* address match / overlay match */
- if (!b->pending && (!overlay_debugging || b->loc->section == section))
- others++;
+ others += breakpoint_has_pc (b, pc, section);
if (others > 0)
{
if (others == 1)
else /* if (others == ???) */
printf_filtered (_("Note: breakpoints "));
ALL_BREAKPOINTS (b)
- if (b->loc->address == pc) /* address match / overlay match */
- if (!b->pending && (!overlay_debugging || b->loc->section == section))
- {
- others--;
- printf_filtered ("%d%s%s ",
- b->number,
- ((b->enable_state == bp_disabled ||
- b->enable_state == bp_shlib_disabled ||
- b->enable_state == bp_call_disabled)
- ? " (disabled)"
- : b->enable_state == bp_permanent
- ? " (permanent)"
- : ""),
- (others > 1) ? ","
- : ((others == 1) ? " and" : ""));
- }
+ if (breakpoint_has_pc (b, pc, section))
+ {
+ others--;
+ printf_filtered ("%d", b->number);
+ if (b->thread == -1 && thread != -1)
+ printf_filtered (" (all threads)");
+ else if (b->thread != -1)
+ printf_filtered (" (thread %d)", b->thread);
+ printf_filtered ("%s%s ",
+ ((b->enable_state == bp_disabled ||
+ b->enable_state == bp_call_disabled)
+ ? " (disabled)"
+ : b->enable_state == bp_permanent
+ ? " (permanent)"
+ : ""),
+ (others > 1) ? ","
+ : ((others == 1) ? " and" : ""));
+ }
printf_filtered (_("also set at pc "));
deprecated_print_address_numeric (pc, 1, gdb_stdout);
printf_filtered (".\n");
that one the official one, and the rest as duplicates. */
static void
-check_duplicates (struct breakpoint *bpt)
+check_duplicates_for (CORE_ADDR address, asection *section)
{
struct bp_location *b;
int count = 0;
struct bp_location *perm_bp = 0;
- CORE_ADDR address = bpt->loc->address;
- asection *section = bpt->loc->section;
-
- if (! breakpoint_address_is_meaningful (bpt))
- return;
ALL_BP_LOCATIONS (b)
if (b->owner->enable_state != bp_disabled
- && b->owner->enable_state != bp_shlib_disabled
- && !b->owner->pending
&& b->owner->enable_state != bp_call_disabled
+ && b->enabled
+ && !b->shlib_disabled
&& b->address == address /* address / overlay match */
&& (!overlay_debugging || b->section == section)
&& breakpoint_address_is_meaningful (b->owner))
if (b != perm_bp)
{
if (b->owner->enable_state != bp_disabled
- && b->owner->enable_state != bp_shlib_disabled
- && !b->owner->pending
&& b->owner->enable_state != bp_call_disabled
+ && b->enabled && !b->shlib_disabled
&& b->address == address /* address / overlay match */
&& (!overlay_debugging || b->section == section)
&& breakpoint_address_is_meaningful (b->owner))
}
}
+static void
+check_duplicates (struct breakpoint *bpt)
+{
+ struct bp_location *bl = bpt->loc;
+
+ if (! breakpoint_address_is_meaningful (bpt))
+ return;
+
+ for (; bl; bl = bl->next)
+ check_duplicates_for (bl->address, bl->section);
+}
+
static void
breakpoint_adjustment_warning (CORE_ADDR from_addr, CORE_ADDR to_addr,
int bnum, int have_bnum)
memset (loc, 0, sizeof (*loc));
loc->owner = bpt;
+ loc->cond = NULL;
+ loc->shlib_disabled = 0;
+ loc->enabled = 1;
switch (bp_type)
{
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
- case bp_through_sigtramp:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_shlib_event:
bp_location_chain = loc;
else
{
- while (loc_p->next)
- loc_p = loc_p->next;
- loc_p->next = loc;
+ while (loc_p->global_next)
+ loc_p = loc_p->global_next;
+ loc_p->global_next = loc;
}
return loc;
}
-/* set_raw_breakpoint() is a low level routine for allocating and
- partially initializing a breakpoint of type BPTYPE. The newly
- created breakpoint's address, section, source file name, and line
- number are provided by SAL. The newly created and partially
- initialized breakpoint is added to the breakpoint chain and
- is also returned as the value of this function.
+static void free_bp_location (struct bp_location *loc)
+{
+ if (loc->cond)
+ xfree (loc->cond);
+ xfree (loc);
+}
- It is expected that the caller will complete the initialization of
- the newly created breakpoint struct as well as output any status
- information regarding the creation of a new breakpoint. In
- particular, set_raw_breakpoint() does NOT set the breakpoint
- number! Care should be taken to not allow an error() to occur
- prior to completing the initialization of the breakpoint. If this
- should happen, a bogus breakpoint will be left on the chain. */
+/* Helper to set_raw_breakpoint below. Creates a breakpoint
+ that has type BPTYPE and has no locations as yet. */
-struct breakpoint *
-set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
+static struct breakpoint *
+set_raw_breakpoint_without_location (enum bptype bptype)
{
struct breakpoint *b, *b1;
b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
memset (b, 0, sizeof (*b));
- b->loc = allocate_bp_location (b, bptype);
- b->loc->requested_address = sal.pc;
- b->loc->address = adjust_breakpoint_address (b->loc->requested_address,
- bptype);
- if (sal.symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = savestring (sal.symtab->filename,
- strlen (sal.symtab->filename));
- b->loc->section = sal.section;
+
b->type = bptype;
b->language = current_language->la_language;
b->input_radix = input_radix;
b->thread = -1;
- b->line_number = sal.line;
b->enable_state = bp_enabled;
b->next = 0;
b->silent = 0;
b->forked_inferior_pid = 0;
b->exec_pathname = NULL;
b->ops = NULL;
- b->pending = 0;
+ b->condition_not_parsed = 0;
/* Add this breakpoint to the end of the chain
so that a list of breakpoints will come out in order
b1 = b1->next;
b1->next = b;
}
+ return b;
+}
+
+/* Initialize loc->function_name. */
+static void
+set_breakpoint_location_function (struct bp_location *loc)
+{
+ if (loc->owner->type == bp_breakpoint
+ || loc->owner->type == bp_hardware_breakpoint)
+ {
+ find_pc_partial_function (loc->address, &(loc->function_name),
+ NULL, NULL);
+ if (loc->function_name)
+ loc->function_name = xstrdup (loc->function_name);
+ }
+}
+
+/* set_raw_breakpoint is a low level routine for allocating and
+ partially initializing a breakpoint of type BPTYPE. The newly
+ created breakpoint's address, section, source file name, and line
+ number are provided by SAL. The newly created and partially
+ initialized breakpoint is added to the breakpoint chain and
+ is also returned as the value of this function.
+
+ It is expected that the caller will complete the initialization of
+ the newly created breakpoint struct as well as output any status
+ information regarding the creation of a new breakpoint. In
+ particular, set_raw_breakpoint does NOT set the breakpoint
+ number! Care should be taken to not allow an error to occur
+ prior to completing the initialization of the breakpoint. If this
+ should happen, a bogus breakpoint will be left on the chain. */
+
+struct breakpoint *
+set_raw_breakpoint (struct symtab_and_line sal, enum bptype bptype)
+{
+ struct breakpoint *b = set_raw_breakpoint_without_location (bptype);
+ CORE_ADDR adjusted_address;
+
+ /* 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
+ 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);
+
+ b->loc = allocate_bp_location (b, bptype);
+ b->loc->requested_address = sal.pc;
+ b->loc->address = adjusted_address;
+
+ if (sal.symtab == NULL)
+ b->source_file = NULL;
+ else
+ b->source_file = savestring (sal.symtab->filename,
+ strlen (sal.symtab->filename));
+ b->loc->section = sal.section;
+ b->line_number = sal.line;
+
+ set_breakpoint_location_function (b->loc);
check_duplicates (b);
breakpoints_changed ();
void
make_breakpoint_permanent (struct breakpoint *b)
{
+ struct bp_location *bl;
b->enable_state = bp_permanent;
- /* By definition, permanent breakpoints are already present in the code. */
- b->loc->inserted = 1;
+ /* By definition, permanent breakpoints are already present in the code.
+ Mark all locations as inserted. For now, make_breakpoint_permanent
+ is called in just one place, so it's hard to say if it's reasonable
+ to have permanent breakpoint with multiple locations or not,
+ but it's easy to implmement. */
+ for (bl = b->loc; bl; bl = bl->next)
+ bl->inserted = 1;
}
static struct breakpoint *
int radix;
};
-/* Cleanup helper routine to restore the current language and
- input radix. */
-static void
-do_restore_lang_radix_cleanup (void *old)
-{
- struct lang_and_radix *p = old;
- set_language (p->lang);
- input_radix = p->radix;
-}
-
-/* Try and resolve a pending breakpoint. */
-static int
-resolve_pending_breakpoint (struct breakpoint *b)
-{
- /* Try and reparse the breakpoint in case the shared library
- is now loaded. */
- struct symtabs_and_lines sals;
- struct symtab_and_line pending_sal;
- char **cond_string = (char **) NULL;
- char *copy_arg = b->addr_string;
- char **addr_string;
- char *errmsg;
- int rc;
- int not_found = 0;
- struct ui_file *old_gdb_stderr;
- struct lang_and_radix old_lr;
- struct cleanup *old_chain;
-
- /* Set language, input-radix, then reissue breakpoint command.
- Ensure the language and input-radix are restored afterwards. */
- old_lr.lang = current_language->la_language;
- old_lr.radix = input_radix;
- old_chain = make_cleanup (do_restore_lang_radix_cleanup, &old_lr);
-
- set_language (b->language);
- input_radix = b->input_radix;
- rc = break_command_1 (b->addr_string, b->flag, b->from_tty, b);
-
- if (rc == GDB_RC_OK)
- /* Pending breakpoint has been resolved. */
- printf_filtered (_("Pending breakpoint \"%s\" resolved\n"), b->addr_string);
-
- do_cleanups (old_chain);
- return rc;
-}
void
remove_solib_event_breakpoints (void)
apply to enabled breakpoints, disabled ones can just stay disabled. */
void
-disable_breakpoints_in_shlibs (int silent)
+disable_breakpoints_in_shlibs (void)
{
- struct breakpoint *b;
+ struct bp_location *loc;
int disabled_shlib_breaks = 0;
- /* See also: insert_breakpoints, under DISABLE_UNSETTABLE_BREAK. */
- ALL_BREAKPOINTS (b)
+ ALL_BP_LOCATIONS (loc)
{
+ struct breakpoint *b = loc->owner;
+ /* We apply the check to all breakpoints, including disabled
+ for those with loc->duplicate set. This is so that when breakpoint
+ becomes enabled, or the duplicate is removed, gdb will try to insert
+ all breakpoints. If we don't set shlib_disabled here, we'll try
+ to insert those breakpoints and fail. */
if (((b->type == bp_breakpoint) || (b->type == bp_hardware_breakpoint))
- && breakpoint_enabled (b) && !b->loc->duplicate
+ && !loc->shlib_disabled
#ifdef PC_SOLIB
- && PC_SOLIB (b->loc->address)
+ && PC_SOLIB (loc->address)
#else
- && solib_address (b->loc->address)
+ && solib_address (loc->address)
#endif
)
{
- b->enable_state = bp_shlib_disabled;
- if (!silent)
- {
- if (!disabled_shlib_breaks)
- {
- target_terminal_ours_for_output ();
- warning (_("Temporarily disabling shared library breakpoints:"));
- }
- disabled_shlib_breaks = 1;
- warning (_("breakpoint #%d "), b->number);
- }
+ loc->shlib_disabled = 1;
}
}
}
/* 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 breakpoint *b;
+ struct bp_location *loc;
int disabled_shlib_breaks = 0;
- /* See also: insert_breakpoints, under DISABLE_UNSETTABLE_BREAK. */
- ALL_BREAKPOINTS (b)
+ ALL_BP_LOCATIONS (loc)
{
- if ((b->loc->loc_type == bp_loc_hardware_breakpoint
- || b->loc->loc_type == bp_loc_software_breakpoint)
- && breakpoint_enabled (b) && !b->loc->duplicate)
+ struct breakpoint *b = loc->owner;
+ if ((loc->loc_type == bp_loc_hardware_breakpoint
+ || loc->loc_type == bp_loc_software_breakpoint)
+ && !loc->shlib_disabled)
{
#ifdef PC_SOLIB
- char *so_name = PC_SOLIB (b->loc->address);
+ char *so_name = PC_SOLIB (loc->address);
#else
- char *so_name = solib_address (b->loc->address);
+ char *so_name = solib_address (loc->address);
#endif
if (so_name && !strcmp (so_name, solib->so_name))
{
- b->enable_state = bp_shlib_disabled;
+ loc->shlib_disabled = 1;
/* At this point, we cannot rely on remove_breakpoint
succeeding so we must mark the breakpoint as not inserted
to prevent future errors occurring in remove_breakpoints. */
- b->loc->inserted = 0;
+ loc->inserted = 0;
if (!disabled_shlib_breaks)
{
target_terminal_ours_for_output ();
}
}
-/* Try to reenable any breakpoints in shared libraries. */
-void
-re_enable_breakpoints_in_shlibs (void)
-{
- struct breakpoint *b, *tmp;
-
- ALL_BREAKPOINTS_SAFE (b, tmp)
- {
- if (b->enable_state == bp_shlib_disabled)
- {
- gdb_byte buf[1];
- char *lib;
-
- /* Do not reenable the breakpoint if the shared library is
- still not mapped in. */
-#ifdef PC_SOLIB
- lib = PC_SOLIB (b->loc->address);
-#else
- lib = solib_address (b->loc->address);
-#endif
- if (lib != NULL && target_read_memory (b->loc->address, buf, 1) == 0)
- b->enable_state = bp_enabled;
- }
- else if (b->pending && (b->enable_state == bp_enabled))
- {
- if (resolve_pending_breakpoint (b) == GDB_RC_OK)
- delete_breakpoint (b);
- }
- }
-}
-
-static void
-solib_load_unload_1 (char *hookname, int tempflag, char *dll_pathname,
- char *cond_string, enum bptype bp_kind)
-{
- struct breakpoint *b;
- struct symtabs_and_lines sals;
- struct cleanup *old_chain;
- struct cleanup *canonical_strings_chain = NULL;
- char *addr_start = hookname;
- char *addr_end = NULL;
- char **canonical = (char **) NULL;
- int thread = -1; /* All threads. */
-
- /* Set a breakpoint on the specified hook. */
- sals = decode_line_1 (&hookname, 1, (struct symtab *) NULL,
- 0, &canonical, NULL);
- addr_end = hookname;
-
- if (sals.nelts == 0)
- {
- warning (_("Unable to set a breakpoint on dynamic linker callback.\n"
- "Suggest linking with /opt/langtools/lib/end.o.\n"
- "GDB will be unable to track shl_load/shl_unload calls."));
- return;
- }
- if (sals.nelts != 1)
- {
- warning (_("Unable to set unique breakpoint on dynamic linker callback.\n"
- "GDB will be unable to track shl_load/shl_unload calls."));
- return;
- }
-
- /* Make sure that all storage allocated in decode_line_1 gets freed
- in case the following errors out. */
- old_chain = make_cleanup (xfree, sals.sals);
- if (canonical != (char **) NULL)
- {
- make_cleanup (xfree, canonical);
- canonical_strings_chain = make_cleanup (null_cleanup, 0);
- if (canonical[0] != NULL)
- make_cleanup (xfree, canonical[0]);
- }
-
- resolve_sal_pc (&sals.sals[0]);
-
- /* Remove the canonical strings from the cleanup, they are needed below. */
- if (canonical != (char **) NULL)
- discard_cleanups (canonical_strings_chain);
-
- b = set_raw_breakpoint (sals.sals[0], bp_kind);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
- b->cond = NULL;
- b->cond_string = (cond_string == NULL) ?
- NULL : savestring (cond_string, strlen (cond_string));
- b->thread = thread;
-
- if (canonical != (char **) NULL && canonical[0] != NULL)
- b->addr_string = canonical[0];
- else if (addr_start)
- b->addr_string = savestring (addr_start, addr_end - addr_start);
-
- b->enable_state = bp_enabled;
- b->disposition = tempflag ? disp_del : disp_donttouch;
-
- if (dll_pathname == NULL)
- b->dll_pathname = NULL;
- else
- {
- b->dll_pathname = (char *) xmalloc (strlen (dll_pathname) + 1);
- strcpy (b->dll_pathname, dll_pathname);
- }
-
- mention (b);
- do_cleanups (old_chain);
-}
-
-void
-create_solib_load_event_breakpoint (char *hookname, int tempflag,
- char *dll_pathname, char *cond_string)
-{
- solib_load_unload_1 (hookname, tempflag, dll_pathname,
- cond_string, bp_catch_load);
-}
-
-void
-create_solib_unload_event_breakpoint (char *hookname, int tempflag,
- char *dll_pathname, char *cond_string)
-{
- solib_load_unload_1 (hookname, tempflag, dll_pathname,
- cond_string, bp_catch_unload);
-}
-
static void
create_fork_vfork_event_catchpoint (int tempflag, char *cond_string,
enum bptype bp_kind)
b = set_raw_breakpoint (sal, bp_kind);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
- b->cond = NULL;
b->cond_string = (cond_string == NULL) ?
NULL : savestring (cond_string, strlen (cond_string));
b->thread = thread;
mention (b);
}
-void
+static void
create_fork_event_catchpoint (int tempflag, char *cond_string)
{
create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_fork);
}
-void
+static void
create_vfork_event_catchpoint (int tempflag, char *cond_string)
{
create_fork_vfork_event_catchpoint (tempflag, cond_string, bp_catch_vfork);
}
-void
+static void
create_exec_event_catchpoint (int tempflag, char *cond_string)
{
struct symtab_and_line sal;
b = set_raw_breakpoint (sal, bp_catch_exec);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
- b->cond = NULL;
b->cond_string = (cond_string == NULL) ?
NULL : savestring (cond_string, strlen (cond_string));
b->thread = thread;
case bp_longjmp:
case bp_longjmp_resume:
case bp_step_resume:
- case bp_through_sigtramp:
case bp_call_dummy:
case bp_watchpoint_scope:
case bp_shlib_event:
{
/* i18n: cagney/2005-02-11: Below needs to be merged into a
single string. */
- if (b->pending)
+ if (b->loc == NULL)
{
printf_filtered (_(" (%s) pending."), b->addr_string);
}
if (b->source_file)
printf_filtered (": file %s, line %d.",
b->source_file, b->line_number);
+
+ if (b->loc->next)
+ {
+ struct bp_location *loc = b->loc;
+ int n = 0;
+ for (; loc; loc = loc->next)
+ ++n;
+ printf_filtered (" (%d locations)", n);
+ }
+
}
}
do_cleanups (old_chain);
}
\f
-/* Add SALS.nelts breakpoints to the breakpoint table. For each
- SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i],
- COND[i] and COND_STRING[i] values.
+static struct bp_location *
+add_location_to_breakpoint (struct breakpoint *b, enum bptype bptype,
+ const struct symtab_and_line *sal)
+{
+ struct bp_location *loc, **tmp;
- 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.
+ loc = allocate_bp_location (b, bptype);
+ for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
+ ;
+ *tmp = loc;
+ loc->requested_address = sal->pc;
+ loc->address = adjust_breakpoint_address (loc->requested_address,
+ bptype);
+ loc->section = sal->section;
- NOTE: If the function succeeds, the caller is expected to cleanup
- the arrays ADDR_STRING, COND_STRING, COND and SALS (but not the
- array contents). If the function fails (error() is called), the
- caller is expected to cleanups both the ADDR_STRING, COND_STRING,
- COND and SALS arrays and each of those arrays contents. */
+ set_breakpoint_location_function (loc);
+ return loc;
+}
+
+/* Create a breakpoint with SAL as location. Use ADDR_STRING
+ as textual description of the location, and COND_STRING
+ as condition expression. */
static void
-create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
- struct expression **cond, char **cond_string,
- enum bptype type, enum bpdisp disposition,
- int thread, int ignore_count, int from_tty,
- struct breakpoint *pending_bp)
+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 *b = NULL;
+ int i;
+
if (type == bp_hardware_breakpoint)
{
int i = hw_breakpoint_used_count ();
int target_resources_ok =
TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_hardware_breakpoint,
- i + sals.nelts, 0);
+ i + 1, 0);
if (target_resources_ok == 0)
error (_("No hardware breakpoint support in the target."));
else if (target_resources_ok < 0)
error (_("Hardware breakpoints used exceeds limit."));
}
- /* Now set all the breakpoints. */
- {
- int i;
- for (i = 0; i < sals.nelts; i++)
- {
- struct breakpoint *b;
- struct symtab_and_line sal = sals.sals[i];
+ for (i = 0; i < sals.nelts; ++i)
+ {
+ struct symtab_and_line sal = sals.sals[i];
+ struct bp_location *loc;
- if (from_tty)
- describe_other_breakpoints (sal.pc, sal.section);
-
- b = set_raw_breakpoint (sal, type);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
- b->cond = cond[i];
- b->thread = thread;
- if (addr_string[i])
- b->addr_string = addr_string[i];
- else
- /* addr_string has to be used or breakpoint_re_set will delete
- me. */
- b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
- b->cond_string = cond_string[i];
- b->ignore_count = ignore_count;
- b->enable_state = bp_enabled;
- b->disposition = disposition;
- /* If resolving a pending breakpoint, a check must be made to see if
- the user has specified a new condition or commands for the
- breakpoint. A new condition will override any condition that was
- initially specified with the initial breakpoint command. */
- if (pending_bp)
+ if (from_tty)
+ describe_other_breakpoints (sal.pc, sal.section, thread);
+
+ if (i == 0)
+ {
+ b = set_raw_breakpoint (sal, type);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->thread = thread;
+
+ b->cond_string = cond_string;
+ b->ignore_count = ignore_count;
+ b->enable_state = bp_enabled;
+ b->disposition = disposition;
+
+ loc = b->loc;
+ }
+ else
+ {
+ loc = add_location_to_breakpoint (b, type, &sal);
+ }
+
+ if (b->cond_string)
+ {
+ char *arg = b->cond_string;
+ loc->cond = parse_exp_1 (&arg, block_for_pc (loc->address), 0);
+ if (*arg)
+ error (_("Garbage %s follows condition"), arg);
+ }
+ }
+
+ if (addr_string)
+ b->addr_string = addr_string;
+ else
+ /* addr_string has to be used or breakpoint_re_set will delete
+ me. */
+ b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
+
+ mention (b);
+}
+
+/* Remove element at INDEX_TO_REMOVE from SAL, shifting other
+ elements to fill the void space. */
+static void remove_sal (struct symtabs_and_lines *sal, int index_to_remove)
+{
+ int i = index_to_remove+1;
+ int last_index = sal->nelts-1;
+
+ for (;i <= last_index; ++i)
+ sal->sals[i-1] = sal->sals[i];
+
+ --(sal->nelts);
+}
+
+/* If appropriate, obtains all sals that correspond
+ to the same file and line as SAL. This is done
+ only if SAL does not have explicit PC and has
+ line and file information. If we got just a single
+ expanded sal, return the original.
+
+ Otherwise, if SAL.explicit_line is not set, filter out
+ all sals for which the name of enclosing function
+ is different from SAL. This makes sure that if we have
+ breakpoint originally set in template instantiation, say
+ foo<int>(), we won't expand SAL to locations at the same
+ line in all existing instantiations of 'foo'.
+
+*/
+struct symtabs_and_lines
+expand_line_sal_maybe (struct symtab_and_line sal)
+{
+ struct symtabs_and_lines expanded;
+ CORE_ADDR original_pc = sal.pc;
+ char *original_function = NULL;
+ int found;
+ int i;
+
+ /* If we have explicit pc, don't expand.
+ If we have no line number, we can't expand. */
+ if (sal.explicit_pc || sal.line == 0 || sal.symtab == NULL)
+ {
+ expanded.nelts = 1;
+ expanded.sals = xmalloc (sizeof (struct symtab_and_line));
+ expanded.sals[0] = sal;
+ return expanded;
+ }
+
+ sal.pc = 0;
+ find_pc_partial_function (original_pc, &original_function, NULL, NULL);
+
+ expanded = expand_line_sal (sal);
+ if (expanded.nelts == 1)
+ {
+ /* We had one sal, we got one sal. Without futher
+ processing, just return the original sal. */
+ xfree (expanded.sals);
+ expanded.nelts = 1;
+ expanded.sals = xmalloc (sizeof (struct symtab_and_line));
+ sal.pc = original_pc;
+ expanded.sals[0] = sal;
+ return expanded;
+ }
+
+ if (!sal.explicit_line)
+ {
+ CORE_ADDR func_addr, func_end;
+ for (i = 0; i < expanded.nelts; ++i)
+ {
+ CORE_ADDR pc = expanded.sals[i].pc;
+ char *this_function;
+ if (find_pc_partial_function (pc, &this_function,
+ &func_addr, &func_end))
+ {
+ if (this_function &&
+ strcmp (this_function, original_function) != 0)
+ {
+ remove_sal (&expanded, i);
+ --i;
+ }
+ else if (func_addr == pc)
+ {
+ /* We're at beginning of a function, and should
+ skip prologue. */
+ struct symbol *sym = find_pc_function (pc);
+ if (sym)
+ expanded.sals[i] = find_function_start_sal (sym, 1);
+ else
+ expanded.sals[i].pc
+ = gdbarch_skip_prologue (current_gdbarch, pc);
+ }
+ }
+ }
+ }
+
+
+ if (expanded.nelts <= 1)
+ {
+ /* This is un ugly workaround. If we get zero
+ expanded sals then something is really wrong.
+ Fix that by returnign the original sal. */
+ xfree (expanded.sals);
+ expanded.nelts = 1;
+ expanded.sals = xmalloc (sizeof (struct symtab_and_line));
+ sal.pc = original_pc;
+ expanded.sals[0] = sal;
+ return expanded;
+ }
+
+ if (original_pc)
+ {
+ found = 0;
+ for (i = 0; i < expanded.nelts; ++i)
+ if (expanded.sals[i].pc == original_pc)
{
- char *arg;
- if (pending_bp->cond_string)
- {
- arg = pending_bp->cond_string;
- b->cond_string = savestring (arg, strlen (arg));
- b->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
- if (*arg)
- error (_("Junk at end of pending breakpoint condition expression"));
- }
- /* If there are commands associated with the breakpoint, they should
- be copied too. */
- if (pending_bp->commands)
- b->commands = copy_command_lines (pending_bp->commands);
-
- /* We have to copy over the ignore_count and thread as well. */
- b->ignore_count = pending_bp->ignore_count;
- b->thread = pending_bp->thread;
+ found = 1;
+ break;
}
- mention (b);
- }
- }
+ gdb_assert (found);
+ }
+
+ return expanded;
+}
+
+/* Add SALS.nelts breakpoints to the breakpoint table. For each
+ SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i]
+ value. COND_STRING, if not NULL, specified the condition to be
+ used for all breakpoints. Essentially the only case where
+ SALS.nelts is not 1 is when we set a breakpoint on an overloaded
+ function. In that case, it's still not possible to specify
+ separate conditions for different overloaded functions, so
+ we take just a single condition string.
+
+ 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
+ caller is expected to cleanups both the ADDR_STRING, COND_STRING,
+ COND and SALS arrays and each of those arrays contents. */
+
+static void
+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)
+{
+ int i;
+ for (i = 0; i < sals.nelts; ++i)
+ {
+ struct symtabs_and_lines expanded =
+ expand_line_sal_maybe (sals.sals[i]);
+
+ create_breakpoint (expanded, addr_string[i],
+ cond_string, type, disposition,
+ thread, ignore_count, from_tty);
+ }
}
/* Parse ARG which is assumed to be a SAL specification possibly
{
int i;
for (i = 0; i < sals->nelts; i++)
- {
- resolve_sal_pc (&sals->sals[i]);
-
- /* It's possible for the PC to be nonzero, but still an illegal
- value on some targets.
-
- For example, on HP-UX if you start gdb, and before running the
- inferior you try to set a breakpoint on a shared library function
- "foo" where the inferior doesn't call "foo" directly but does
- pass its address to another function call, then we do find a
- minimal symbol for the "foo", but it's address is invalid.
- (Appears to be an index into a table that the loader sets up
- when the inferior is run.)
-
- Give the target a chance to bless sals.sals[i].pc before we
- try to make a breakpoint for it. */
-#ifdef DEPRECATED_PC_REQUIRES_RUN_BEFORE_USE
- if (DEPRECATED_PC_REQUIRES_RUN_BEFORE_USE (sals->sals[i].pc))
- {
- if (address == NULL)
- error (_("Cannot break without a running program."));
- else
- error (_("Cannot break on %s without a running program."),
- address);
- }
-#endif
- }
+ resolve_sal_pc (&sals->sals[i]);
}
static void
args->not_found_ptr);
}
+/* Given TOK, a string specification of condition and thread, as
+ accepted by the 'break' command, extract the condition
+ string and thread number and set *COND_STRING and *THREAD.
+ PC identifies the context at which the condition should be parsed.
+ If no condition is found, *COND_STRING is set to NULL.
+ If no thread is found, *THREAD is set to -1. */
+static void
+find_condition_and_thread (char *tok, CORE_ADDR pc,
+ char **cond_string, int *thread)
+{
+ *cond_string = NULL;
+ *thread = -1;
+ while (tok && *tok)
+ {
+ char *end_tok;
+ int toklen;
+ char *cond_start = NULL;
+ char *cond_end = NULL;
+ while (*tok == ' ' || *tok == '\t')
+ tok++;
+
+ end_tok = tok;
+
+ while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
+ end_tok++;
+
+ toklen = end_tok - tok;
+
+ if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
+ {
+ tok = cond_start = end_tok + 1;
+ parse_exp_1 (&tok, block_for_pc (pc), 0);
+ cond_end = tok;
+ *cond_string = savestring (cond_start,
+ cond_end - cond_start);
+ }
+ else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+ {
+ char *tmptok;
+
+ tok = end_tok + 1;
+ tmptok = tok;
+ *thread = strtol (tok, &tok, 0);
+ if (tok == tmptok)
+ error (_("Junk after thread keyword."));
+ if (!valid_thread_id (*thread))
+ error (_("Unknown thread %d."), *thread);
+ }
+ else
+ error (_("Junk at end of arguments."));
+ }
+}
+
/* 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.
-
- PENDING_BP is non-NULL when this function is being called to resolve
- a pending breakpoint. */
+ second bit : 0 normal breakpoint, 1 hardware breakpoint. */
static int
-break_command_1 (char *arg, int flag, int from_tty, struct breakpoint *pending_bp)
+break_command_1 (char *arg, int flag, int from_tty)
{
struct gdb_exception e;
int tempflag, hardwareflag;
struct symtabs_and_lines sals;
- struct expression **cond = 0;
struct symtab_and_line pending_sal;
- char **cond_string = (char **) NULL;
+ char *cond_string = NULL;
char *copy_arg;
char *err_msg;
char *addr_start = arg;
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);
make_cleanup (xfree, addr_string);
}
- /* Allocate space for all the cond expressions. */
- cond = xcalloc (sals.nelts, sizeof (struct expression *));
- make_cleanup (xfree, cond);
-
- /* Allocate space for all the cond strings. */
- cond_string = xcalloc (sals.nelts, sizeof (char **));
- make_cleanup (xfree, cond_string);
-
/* ----------------------------- SNIP -----------------------------
Anything added to the cleanup chain beyond this point is assumed
to be part of a breakpoint. If the breakpoint create succeeds
/* Verify that condition can be parsed, before setting any
breakpoints. Allocate a separate condition expression for each
breakpoint. */
- thread = -1; /* No specific thread yet */
if (!pending)
{
- for (i = 0; i < sals.nelts; i++)
- {
- char *tok = arg;
- while (tok && *tok)
- {
- char *end_tok;
- int toklen;
- char *cond_start = NULL;
- char *cond_end = NULL;
- while (*tok == ' ' || *tok == '\t')
- tok++;
-
- end_tok = tok;
-
- while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
- end_tok++;
-
- toklen = end_tok - tok;
-
- if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
- {
- tok = cond_start = end_tok + 1;
- cond[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc),
- 0);
- make_cleanup (xfree, cond[i]);
- cond_end = tok;
- cond_string[i] = savestring (cond_start,
- cond_end - cond_start);
- make_cleanup (xfree, cond_string[i]);
- }
- else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
- {
- char *tmptok;
-
- tok = end_tok + 1;
- tmptok = tok;
- thread = strtol (tok, &tok, 0);
- if (tok == tmptok)
- error (_("Junk after thread keyword."));
- if (!valid_thread_id (thread))
- error (_("Unknown thread %d."), thread);
- }
- else
- error (_("Junk at end of arguments."));
- }
- }
- create_breakpoints (sals, addr_string, cond, cond_string,
+ /* 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);
+ 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
{
- struct symtab_and_line sal;
+ struct symtab_and_line sal = {0};
struct breakpoint *b;
- sal.symtab = NULL;
- sal.pc = 0;
-
make_cleanup (xfree, copy_arg);
- b = set_raw_breakpoint (sal, hardwareflag ? bp_hardware_breakpoint
- : bp_breakpoint);
+ b = set_raw_breakpoint_without_location (hardwareflag
+ ? bp_hardware_breakpoint
+ : bp_breakpoint);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
- b->cond = *cond;
b->thread = thread;
- b->addr_string = *addr_string;
- b->cond_string = *cond_string;
+ b->addr_string = addr_string[0];
+ b->cond_string = cond_string;
b->ignore_count = ignore_count;
- b->pending = 1;
b->disposition = tempflag ? disp_del : disp_donttouch;
- b->from_tty = from_tty;
- b->flag = flag;
+ b->condition_not_parsed = 1;
mention (b);
}
struct cleanup *breakpoint_chain = NULL;
int i;
char **addr_string;
- char **cond_string;
+ char *cond_string = 0;
char *address_end;
cond = xcalloc (sals.nelts, sizeof (struct expression *));
make_cleanup (xfree, cond);
- /* Allocate space for all the cond strings. */
- cond_string = xcalloc (sals.nelts, sizeof (char **));
- make_cleanup (xfree, cond_string);
-
/* ----------------------------- SNIP -----------------------------
Anything added to the cleanup chain beyond this point is assumed
to be part of a breakpoint. If the breakpoint create goes
/* Resolve all line numbers to PC's. */
breakpoint_sals_to_pc (&sals, args->address);
- /* Verify that conditions can be parsed, before setting any
- breakpoints. */
- for (i = 0; i < sals.nelts; i++)
+ if (args->condition != NULL)
{
- if (args->condition != NULL)
- {
- char *tok = args->condition;
- cond[i] = parse_exp_1 (&tok, block_for_pc (sals.sals[i].pc), 0);
- if (*tok != '\0')
- error (_("Garbage %s follows condition"), tok);
- make_cleanup (xfree, cond[i]);
- cond_string[i] = xstrdup (args->condition);
- }
+ cond_string = xstrdup (args->condition);
+ make_cleanup (xfree, cond_string);
}
- create_breakpoints (sals, addr_string, cond, cond_string,
+ 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*/);
+ args->thread, args->ignore_count, 0/*from-tty*/);
/* That's it. Discard the cleanups for data inserted into the
breakpoint. */
args.tempflag = tempflag;
args.thread = thread;
args.ignore_count = ignore_count;
- return catch_exceptions_with_msg (uiout, do_captured_breakpoint, &args,
- error_message, RETURN_MASK_ALL);
+ 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;
}
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,
static void
watch_command_1 (char *arg, int accessflag, int from_tty)
{
- struct breakpoint *b;
+ struct breakpoint *b, *scope_breakpoint = NULL;
struct symtab_and_line sal;
struct expression *exp;
struct block *exp_valid_block;
error (_("Target can only support one kind of HW watchpoint at a time."));
}
-#if defined(HPUXHPPA)
- /* On HP-UX if you set a h/w
- watchpoint before the "run" command, the inferior dies with a e.g.,
- SIGILL once you start it. I initially believed this was due to a
- bad interaction between page protection traps and the initial
- startup sequence by the dynamic linker.
-
- However, I tried avoiding that by having HP-UX's implementation of
- TARGET_CAN_USE_HW_WATCHPOINT return FALSE if there was no inferior_ptid
- yet, which forced slow watches before a "run" or "attach", and it
- still fails somewhere in the startup code.
-
- Until I figure out what's happening, I'm disallowing watches altogether
- before the "run" or "attach" command. We'll tell the user they must
- set watches after getting the program started. */
- if (!target_has_execution)
- {
- warning (_("can't do that without a running program; try \"break main\"), \"run\" first");
- return;
- }
-#endif /* HPUXHPPA */
-
/* Change the type of breakpoint to an ordinary watchpoint if a hardware
watchpoint could not be set. */
if (!mem_cnt || target_resources_ok <= 0)
bp_type = bp_watchpoint;
+ frame = block_innermost_frame (exp_valid_block);
+ if (frame)
+ prev_frame = get_prev_frame (frame);
+ else
+ prev_frame = NULL;
+
+ /* If the expression is "local", then set up a "watchpoint scope"
+ breakpoint at the point where we've left the scope of the watchpoint
+ expression. Create the scope breakpoint before the watchpoint, so
+ that we will encounter it first in bpstat_stop_status. */
+ if (innermost_block && prev_frame)
+ {
+ scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
+ bp_watchpoint_scope);
+
+ scope_breakpoint->enable_state = bp_enabled;
+
+ /* Automatically delete the breakpoint when it hits. */
+ scope_breakpoint->disposition = disp_del;
+
+ /* Only break in the proper frame (help with recursion). */
+ scope_breakpoint->frame_id = get_frame_id (prev_frame);
+
+ /* Set the address at which we will stop. */
+ scope_breakpoint->loc->requested_address
+ = get_frame_pc (prev_frame);
+ scope_breakpoint->loc->address
+ = adjust_breakpoint_address (scope_breakpoint->loc->requested_address,
+ scope_breakpoint->type);
+ }
+
/* Now set up the breakpoint. */
b = set_raw_breakpoint (sal, bp_type);
set_breakpoint_count (breakpoint_count + 1);
b->exp_valid_block = exp_valid_block;
b->exp_string = savestring (exp_start, exp_end - exp_start);
b->val = val;
- b->cond = cond;
+ b->loc->cond = cond;
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
else
b->cond_string = 0;
- frame = block_innermost_frame (exp_valid_block);
if (frame)
- {
- prev_frame = get_prev_frame (frame);
- b->watchpoint_frame = get_frame_id (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 the expression is "local", then set up a "watchpoint scope"
- breakpoint at the point where we've left the scope of the watchpoint
- expression. */
- if (innermost_block)
+ if (scope_breakpoint != NULL)
{
- if (prev_frame)
- {
- struct breakpoint *scope_breakpoint;
- scope_breakpoint = create_internal_breakpoint (get_frame_pc (prev_frame),
- bp_watchpoint_scope);
-
- scope_breakpoint->enable_state = bp_enabled;
-
- /* Automatically delete the breakpoint when it hits. */
- scope_breakpoint->disposition = disp_del;
-
- /* Only break in the proper frame (help with recursion). */
- scope_breakpoint->frame_id = get_frame_id (prev_frame);
-
- /* Set the address at which we will stop. */
- scope_breakpoint->loc->requested_address
- = get_frame_pc (prev_frame);
- scope_breakpoint->loc->address
- = adjust_breakpoint_address (scope_breakpoint->loc->requested_address,
- scope_breakpoint->type);
-
- /* The scope breakpoint is related to the watchpoint. We
- will need to act on them together. */
- b->related_breakpoint = scope_breakpoint;
- }
+ /* The scope breakpoint is related to the watchpoint. We will
+ need to act on them together. */
+ b->related_breakpoint = scope_breakpoint;
+ scope_breakpoint->related_breakpoint = b;
}
+
value_free_to_mark (mark);
mention (b);
}
in hardware. If the watchpoint can not be handled
in hardware return zero. */
-#if !defined(TARGET_REGION_OK_FOR_HW_WATCHPOINT)
-#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(ADDR,LEN) \
- (TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(LEN))
-#endif
-
static int
can_use_hardware_watchpoint (struct value *v)
{
{
struct symtabs_and_lines sals;
struct symtab_and_line sal;
- struct frame_info *prev_frame = get_prev_frame (deprecated_selected_frame);
+ struct frame_info *frame = get_selected_frame (NULL);
+ struct frame_info *prev_frame = get_prev_frame (frame);
struct breakpoint *breakpoint;
struct cleanup *old_chain;
struct continuation_arg *arg1;
else
/* Otherwise, specify the current frame, because we want to stop only
at the very same frame. */
- breakpoint = set_momentary_breakpoint (sal,
- get_frame_id (deprecated_selected_frame),
+ breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame),
bp_until);
if (!target_can_async_p ())
b = set_raw_breakpoint (*sal, bptype);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
- b->cond = NULL;
b->cond_string = (cond_string == NULL) ?
NULL : savestring (cond_string, strlen (cond_string));
b->thread = thread;
b = set_raw_breakpoint (sals.sals[0], bp_breakpoint);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
- b->cond = NULL;
b->cond_string = (cond_string == NULL) ?
NULL : savestring (cond_string, strlen (cond_string));
b->thread = -1;
warning (_("Unsupported with this platform/compiler combination."));
}
+/* Create a breakpoint struct for Ada exception catchpoints. */
+
+static void
+create_ada_exception_breakpoint (struct symtab_and_line sal,
+ char *addr_string,
+ char *exp_string,
+ char *cond_string,
+ struct expression *cond,
+ struct breakpoint_ops *ops,
+ int tempflag,
+ int from_tty)
+{
+ struct breakpoint *b;
+
+ if (from_tty)
+ {
+ describe_other_breakpoints (sal.pc, sal.section, -1);
+ /* FIXME: brobecker/2006-12-28: Actually, re-implement a special
+ version for exception catchpoints, because two catchpoints
+ used for different exception names will use the same address.
+ In this case, a "breakpoint ... also set at..." warning is
+ unproductive. Besides. the warning phrasing is also a bit
+ inapropriate, we should use the word catchpoint, and tell
+ the user what type of catchpoint it is. The above is good
+ enough for now, though. */
+ }
+
+ b = set_raw_breakpoint (sal, bp_breakpoint);
+ set_breakpoint_count (breakpoint_count + 1);
+
+ b->enable_state = bp_enabled;
+ b->disposition = tempflag ? disp_del : disp_donttouch;
+ b->number = breakpoint_count;
+ b->ignore_count = 0;
+ b->loc->cond = cond;
+ b->addr_string = addr_string;
+ b->language = language_ada;
+ b->cond_string = cond_string;
+ b->exp_string = exp_string;
+ b->thread = -1;
+ b->ops = ops;
+
+ mention (b);
+}
+
+/* Implement the "catch exception" command. */
+
+static void
+catch_ada_exception_command (char *arg, int tempflag, int from_tty)
+{
+ struct symtab_and_line sal;
+ enum bptype type;
+ char *addr_string = NULL;
+ char *exp_string = NULL;
+ char *cond_string = NULL;
+ struct expression *cond = NULL;
+ struct breakpoint_ops *ops = NULL;
+
+ sal = ada_decode_exception_location (arg, &addr_string, &exp_string,
+ &cond_string, &cond, &ops);
+ create_ada_exception_breakpoint (sal, addr_string, exp_string,
+ cond_string, cond, ops, tempflag,
+ from_tty);
+}
+
+/* Implement the "catch assert" command. */
+
+static void
+catch_assert_command (char *arg, int tempflag, int from_tty)
+{
+ struct symtab_and_line sal;
+ char *addr_string = NULL;
+ struct breakpoint_ops *ops = NULL;
+
+ sal = ada_decode_assert_location (arg, &addr_string, &ops);
+ create_ada_exception_breakpoint (sal, addr_string, NULL, NULL, NULL, ops,
+ tempflag, from_tty);
+}
+
/* Cover routine to allow wrapping target_enable_exception_catchpoints
inside a catch_errors */
{
error (_("Catch of stop not yet implemented"));
}
+ else if (strncmp (arg1_start, "exception", arg1_length) == 0)
+ {
+ catch_ada_exception_command (arg1_end + 1, tempflag, from_tty);
+ }
+
+ else if (strncmp (arg1_start, "assert", arg1_length) == 0)
+ {
+ catch_assert_command (arg1_end + 1, tempflag, from_tty);
+ }
/* This doesn't appear to be an event name */
}
}
-/* Used by the gui, could be made a worker for other things. */
-
-struct breakpoint *
-set_breakpoint_sal (struct symtab_and_line sal)
-{
- struct breakpoint *b;
- b = set_raw_breakpoint (sal, bp_breakpoint);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
- b->cond = 0;
- b->thread = -1;
- return b;
-}
-
static void
catch_command (char *arg, 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;
default_match = 1;
}
+ /* We don't call resolve_sal_pc here. That's not
+ as bad as it seems, because all existing breakpoints
+ typically have both file/line and pc set. So, if
+ clear is given file/line, we can match this to existing
+ breakpoint without obtaining pc at all.
+
+ We only support clearing given the address explicitly
+ present in breakpoint table. Say, we've set breakpoint
+ at file:line. There were several PC values for that file:line,
+ due to optimization, all in one block.
+ We've picked one PC value. If "clear" is issued with another
+ PC corresponding to the same file:line, the breakpoint won't
+ be cleared. We probably can still clear the breakpoint, but
+ since the other PC value is never presented to user, user
+ can only find it by guessing, and it does not seem important
+ to support that. */
+
/* For each line spec given, delete bps which correspond
to it. Do it in two passes, solely to preserve the current
behavior that from_tty is forced true if we delete more than
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 (b->type != bp_none
&& b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->type != bp_read_watchpoint
- && b->type != bp_access_watchpoint
- /* Not if b is a watchpoint of any sort... */
- && (((sal.pc && (b->loc->address == sal.pc))
- && (!section_is_overlay (b->loc->section)
- || b->loc->section == sal.section))
- /* Yes, if sal.pc matches b (modulo overlays). */
- || ((default_match || (0 == sal.pc))
- && b->source_file != NULL
- && sal.symtab != NULL
- && strcmp (b->source_file, sal.symtab->filename) == 0
- && b->line_number == sal.line)))
- /* Yes, if sal source file and line matches b. */
+ && b->type != bp_access_watchpoint)
{
- /* Remove it from breakpoint_chain... */
- if (b == breakpoint_chain)
- {
- /* b is at the head of the list */
- breakpoint_chain = b->next;
- }
- else
+ struct bp_location *loc = b->loc;
+ for (; loc; loc = loc->next)
{
- prev->next = b->next;
+ int pc_match = sal.pc
+ && (loc->address == sal.pc)
+ && (!section_is_overlay (loc->section)
+ || loc->section == sal.section);
+ int line_match = ((default_match || (0 == sal.pc))
+ && b->source_file != NULL
+ && sal.symtab != NULL
+ && strcmp (b->source_file, sal.symtab->filename) == 0
+ && b->line_number == sal.line);
+ if (pc_match || line_match)
+ {
+ match = 1;
+ break;
+ }
}
- /* And add it to 'found' chain. */
- b->next = found;
- found = b;
- }
- else
- {
- /* Keep b, and keep a pointer to it. */
- prev = b;
}
+
+ if (match)
+ 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');
struct breakpoint *b, *temp;
for (; bs; bs = bs->next)
- if (bs->breakpoint_at && bs->breakpoint_at->disposition == disp_del
+ if (bs->breakpoint_at && bs->breakpoint_at->owner->disposition == disp_del
&& bs->stop)
- delete_breakpoint (bs->breakpoint_at);
+ delete_breakpoint (bs->breakpoint_at->owner);
ALL_BREAKPOINTS_SAFE (b, temp)
{
}
}
+/* Remove locations of breakpoint BPT from
+ the global list of breakpoint locations. */
+
+static void
+unlink_locations_from_global_list (struct breakpoint *bpt)
+{
+ /* This code assumes that the locations
+ of a breakpoint are found in the global list
+ in the same order, but not necessary adjacent. */
+ struct bp_location **tmp = &bp_location_chain;
+ struct bp_location *here = bpt->loc;
+
+ if (here == NULL)
+ return;
+
+ for (; *tmp && here;)
+ {
+ if (*tmp == here)
+ {
+ *tmp = here->global_next;
+ here = here->next;
+ }
+ else
+ {
+ tmp = &((*tmp)->global_next);
+ }
+ }
+}
+
/* Delete a breakpoint and clean up all traces of it in the data
structures. */
deprecated_delete_breakpoint_hook (bpt);
breakpoint_delete_event (bpt->number);
- if (bpt->loc->inserted)
- remove_breakpoint (bpt->loc, mark_inserted);
+ for (loc = bpt->loc; loc; loc = loc->next)
+ {
+ if (loc->inserted)
+ remove_breakpoint (loc, mark_inserted);
+
+ free_valchain (loc);
- free_valchain (bpt->loc);
+ if (loc->cond)
+ xfree (loc->cond);
+
+ if (loc->function_name)
+ xfree (loc->function_name);
+ }
if (breakpoint_chain == bpt)
breakpoint_chain = bpt->next;
- if (bp_location_chain == bpt->loc)
- bp_location_chain = bpt->loc->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
break;
}
- ALL_BP_LOCATIONS (loc)
- if (loc->next == bpt->loc)
- {
- loc->next = bpt->loc->next;
- break;
- }
+ unlink_locations_from_global_list (bpt);
check_duplicates (bpt);
- /* If this breakpoint was inserted, and there is another breakpoint
- at the same address, we need to insert the other breakpoint. */
- if (bpt->loc->inserted
- && bpt->type != bp_hardware_watchpoint
+
+ if (bpt->type != bp_hardware_watchpoint
&& bpt->type != bp_read_watchpoint
&& bpt->type != bp_access_watchpoint
&& bpt->type != bp_catch_fork
&& bpt->type != bp_catch_vfork
&& bpt->type != bp_catch_exec)
- {
- ALL_BREAKPOINTS (b)
- if (b->loc->address == bpt->loc->address
- && b->loc->section == bpt->loc->section
- && !b->loc->duplicate
- && b->enable_state != bp_disabled
- && b->enable_state != bp_shlib_disabled
- && !b->pending
- && b->enable_state != bp_call_disabled)
- {
- int val;
-
- /* We should never reach this point if there is a permanent
- breakpoint at the same address as the one being deleted.
- If there is a permanent breakpoint somewhere, it should
- always be the only one inserted. */
- if (b->enable_state == bp_permanent)
- internal_error (__FILE__, __LINE__,
- _("another breakpoint was inserted on top of "
- "a permanent breakpoint"));
-
- if (b->type == bp_hardware_breakpoint)
- val = target_insert_hw_breakpoint (b->loc->address, b->loc->shadow_contents);
- else
- val = target_insert_breakpoint (b->loc->address, b->loc->shadow_contents);
-
- /* If there was an error in the insert, print a message, then stop execution. */
- if (val != 0)
- {
- struct ui_file *tmp_error_stream = mem_fileopen ();
- make_cleanup_ui_file_delete (tmp_error_stream);
-
-
- if (b->type == bp_hardware_breakpoint)
+ for (loc = bpt->loc; loc; loc = loc->next)
+ {
+ /* If this breakpoint location was inserted, and there is
+ another breakpoint at the same address, we need to
+ insert the other breakpoint. */
+ if (loc->inserted)
+ {
+ struct bp_location *loc2;
+ ALL_BP_LOCATIONS (loc2)
+ if (loc2->address == loc->address
+ && loc2->section == loc->section
+ && !loc->duplicate
+ && loc2->owner->enable_state != bp_disabled
+ && loc2->enabled
+ && !loc2->shlib_disabled
+ && loc2->owner->enable_state != bp_call_disabled)
{
- fprintf_unfiltered (tmp_error_stream,
- "Cannot insert hardware breakpoint %d.\n"
- "You may have requested too many hardware breakpoints.\n",
- b->number);
- }
- else
- {
- 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 (b->loc->address, 1, tmp_error_stream);
- fprintf_filtered (tmp_error_stream, ": %s.\n",
- safe_strerror (val));
- }
-
- fprintf_unfiltered (tmp_error_stream,"The same program may be running in another process.");
- target_terminal_ours_for_output ();
- error_stream(tmp_error_stream);
- }
- else
- b->loc->inserted = 1;
- }
- }
+ int val;
+
+ /* We should never reach this point if there is a permanent
+ breakpoint at the same address as the one being deleted.
+ If there is a permanent breakpoint somewhere, it should
+ always be the only one inserted. */
+ if (loc2->owner->enable_state == bp_permanent)
+ internal_error (__FILE__, __LINE__,
+ _("another breakpoint was inserted on top of "
+ "a permanent breakpoint"));
+
+ memset (&loc2->target_info, 0, sizeof (loc2->target_info));
+ loc2->target_info.placed_address = loc2->address;
+ if (b->type == bp_hardware_breakpoint)
+ val = target_insert_hw_breakpoint (&loc2->target_info);
+ else
+ val = target_insert_breakpoint (&loc2->target_info);
+
+ /* If there was an error in the insert, print a message, then stop execution. */
+ if (val != 0)
+ {
+ struct ui_file *tmp_error_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (tmp_error_stream);
+
+
+ if (b->type == bp_hardware_breakpoint)
+ {
+ fprintf_unfiltered (tmp_error_stream,
+ "Cannot insert hardware breakpoint %d.\n"
+ "You may have requested too many hardware breakpoints.\n",
+ b->number);
+ }
+ else
+ {
+ 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);
+ fprintf_filtered (tmp_error_stream, ": %s.\n",
+ safe_strerror (val));
+ }
+
+ fprintf_unfiltered (tmp_error_stream,"The same program may be running in another process.");
+ target_terminal_ours_for_output ();
+ error_stream(tmp_error_stream);
+ }
+ else
+ loc2->inserted = 1;
+ }
+ }
+ }
free_command_lines (&bpt->commands);
- if (bpt->cond)
- xfree (bpt->cond);
if (bpt->cond_string != NULL)
xfree (bpt->cond_string);
if (bpt->addr_string != NULL)
/* Be sure no bpstat's are pointing at it after it's been freed. */
/* FIXME, how can we find all bpstat's?
- We just check stop_bpstat for now. */
+ We just check stop_bpstat for now. Note that we cannot just
+ remove bpstats pointing at bpt from the stop_bpstat list
+ entirely, as breakpoint commands are associated with the bpstat;
+ if we remove it here, then the later call to
+ bpstat_do_actions (&stop_bpstat);
+ in event-top.c won't do anything, and temporary breakpoints
+ with commands won't work. */
for (bs = stop_bpstat; bs; bs = bs->next)
- if (bs->breakpoint_at == bpt)
+ if (bs->breakpoint_at && bs->breakpoint_at->owner == bpt)
{
bs->breakpoint_at = NULL;
bs->old_val = NULL;
bp, we mark it as deleted before freeing its storage. */
bpt->type = bp_none;
- xfree (bpt->loc);
+ for (loc = bpt->loc; loc;)
+ {
+ struct bp_location *loc_next = loc->next;
+ xfree (loc);
+ loc = loc_next;
+ }
xfree (bpt);
}
b->type != bp_thread_event &&
b->type != bp_overlay_event &&
b->number >= 0)
- breaks_to_delete = 1;
+ {
+ breaks_to_delete = 1;
+ break;
+ }
}
/* Ask user only if there are some breakpoints to delete. */
map_breakpoint_numbers (arg, delete_breakpoint);
}
+static int
+all_locations_are_pending (struct bp_location *loc)
+{
+ for (; loc; loc = loc->next)
+ if (!loc->shlib_disabled)
+ return 0;
+ return 1;
+}
+
+static void
+update_breakpoint_locations (struct breakpoint *b,
+ struct symtabs_and_lines sals)
+{
+ int i;
+ char *s;
+ struct bp_location *existing_locations = b->loc;
+
+ /* If there's no new locations, and all existing locations
+ are pending, don't do anything. This optimizes
+ the common case where all locations are in the same
+ shared library, that was unloaded. We'd like to
+ retain the location, so that when the library
+ is loaded again, we don't loose the enabled/disabled
+ status of the individual locations. */
+ if (all_locations_are_pending (existing_locations) && sals.nelts == 0)
+ return;
+
+ unlink_locations_from_global_list (b);
+ b->loc = NULL;
+
+ for (i = 0; i < sals.nelts; ++i)
+ {
+ struct bp_location *new_loc =
+ add_location_to_breakpoint (b, b->type, &(sals.sals[i]));
+
+ /* Reparse conditions, they might contain references to the
+ old symtab. */
+ if (b->cond_string != NULL)
+ {
+ struct gdb_exception e;
+
+ s = b->cond_string;
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ new_loc->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc),
+ 0);
+ }
+ if (e.reason < 0)
+ {
+ warning (_("failed to reevaluate condition for breakpoint %d: %s"),
+ b->number, e.message);
+ new_loc->enabled = 0;
+ }
+ }
+
+ if (b->source_file != NULL)
+ xfree (b->source_file);
+ if (sals.sals[i].symtab == NULL)
+ b->source_file = NULL;
+ else
+ b->source_file =
+ savestring (sals.sals[i].symtab->filename,
+ strlen (sals.sals[i].symtab->filename));
+
+ if (b->line_number == 0)
+ b->line_number = sals.sals[i].line;
+ }
+
+ /* If possible, carry over 'disable' status from existing breakpoints. */
+ {
+ struct bp_location *e = existing_locations;
+ 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;
+ }
+ }
+ }
+ }
+
+ while (existing_locations)
+ {
+ struct bp_location *next = existing_locations->next;
+ free_bp_location (existing_locations);
+ existing_locations = next;
+ }
+}
+
+
/* Reset a breakpoint given it's struct breakpoint * BINT.
The value we return ends up being the return value from catch_errors.
Unused in this case. */
struct breakpoint *b = (struct breakpoint *) bint;
struct value *mark;
int i;
- int not_found;
- int *not_found_ptr = NULL;
- struct symtabs_and_lines sals;
+ int not_found = 0;
+ int *not_found_ptr = ¬_found;
+ struct symtabs_and_lines sals = {};
+ struct symtabs_and_lines expanded;
char *s;
enum enable_state save_enable;
+ struct gdb_exception e;
+
switch (b->type)
{
delete_breakpoint (b);
return 0;
}
- /* HACK: cagney/2001-11-11: kettenis/2001-11-11: MarkK wrote:
-
- ``And a hack it is, although Apple's Darwin version of GDB
- contains an almost identical hack to implement a "future
- break" command. It seems to work in many real world cases,
- but it is easy to come up with a test case where the patch
- doesn't help at all.''
-
- ``It seems that the way GDB implements breakpoints - in -
- shared - libraries was designed for a.out shared library
- systems (SunOS 4) where shared libraries were loaded at a
- fixed address in memory. Since ELF shared libraries can (and
- will) be loaded at any address in memory, things break.
- Fixing this is not trivial. Therefore, I'm not sure whether
- we should add this hack to the branch only. I cannot
- guarantee that things will be fixed on the trunk in the near
- future.''
-
- In case we have a problem, disable this breakpoint. We'll
- restore its status if we succeed. Don't disable a
- shlib_disabled breakpoint though. There's a fair chance we
- can't re-set it if the shared library it's in hasn't been
- loaded yet. */
-
- if (b->pending)
- break;
-
- save_enable = b->enable_state;
- if (b->enable_state != bp_shlib_disabled)
- b->enable_state = bp_disabled;
- else
- /* If resetting a shlib-disabled breakpoint, we don't want to
- see an error message if it is not found since we will expect
- this to occur until the shared library is finally reloaded.
- We accomplish this by giving decode_line_1 a pointer to use
- for silent notification that the symbol is not found. */
- not_found_ptr = ¬_found;
set_language (b->language);
input_radix = b->input_radix;
s = b->addr_string;
- sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL,
- not_found_ptr);
- for (i = 0; i < sals.nelts; i++)
+ TRY_CATCH (e, RETURN_MASK_ERROR)
{
- resolve_sal_pc (&sals.sals[i]);
-
- /* Reparse conditions, they might contain references to the
- old symtab. */
- if (b->cond_string != NULL)
- {
- s = b->cond_string;
- if (b->cond)
- {
- xfree (b->cond);
- /* Avoid re-freeing b->exp if an error during the call
- to parse_exp_1. */
- b->cond = NULL;
- }
- b->cond = parse_exp_1 (&s, block_for_pc (sals.sals[i].pc), 0);
- }
-
- /* We need to re-set the breakpoint if the address changes... */
- if (b->loc->address != sals.sals[i].pc
- /* ...or new and old breakpoints both have source files, and
- the source file name or the line number changes... */
- || (b->source_file != NULL
- && sals.sals[i].symtab != NULL
- && (strcmp (b->source_file, sals.sals[i].symtab->filename) != 0
- || b->line_number != sals.sals[i].line)
- )
- /* ...or we switch between having a source file and not having
- one. */
- || ((b->source_file == NULL) != (sals.sals[i].symtab == NULL))
- )
+ sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL,
+ not_found_ptr);
+ }
+ if (e.reason < 0)
+ {
+ int not_found_and_ok = 0;
+ /* For pending breakpoints, it's expected that parsing
+ will fail until the right shared library is loaded.
+ User has already told to create pending breakpoints and
+ don't need extra messages. If breakpoint is in bp_shlib_disabled
+ state, then user already saw the message about that breakpoint
+ being disabled, and don't want to see more errors. */
+ if (not_found
+ && (b->condition_not_parsed
+ || (b->loc && b->loc->shlib_disabled)
+ || b->enable_state == bp_disabled))
+ not_found_and_ok = 1;
+
+ if (!not_found_and_ok)
{
- if (b->source_file != NULL)
- xfree (b->source_file);
- if (sals.sals[i].symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file =
- savestring (sals.sals[i].symtab->filename,
- strlen (sals.sals[i].symtab->filename));
- b->line_number = sals.sals[i].line;
- b->loc->requested_address = sals.sals[i].pc;
- b->loc->address
- = adjust_breakpoint_address (b->loc->requested_address,
- b->type);
-
- /* Used to check for duplicates here, but that can
- cause trouble, as it doesn't check for disabled
- breakpoints. */
-
- mention (b);
-
- /* Might be better to do this just once per breakpoint_re_set,
- rather than once for every breakpoint. */
- breakpoints_changed ();
+ /* We surely don't want to warn about the same breakpoint
+ 10 times. One solution, implemented here, is disable
+ the breakpoint on error. Another solution would be to
+ have separate 'warning emitted' flag. Since this
+ happens only when a binary has changed, I don't know
+ which approach is better. */
+ b->enable_state = bp_disabled;
+ throw_exception (e);
}
- b->loc->section = sals.sals[i].section;
- b->enable_state = save_enable; /* Restore it, this worked. */
+ }
+ if (not_found)
+ break;
+
+ gdb_assert (sals.nelts == 1);
+ resolve_sal_pc (&sals.sals[0]);
+ if (b->condition_not_parsed && s && s[0])
+ {
+ char *cond_string = 0;
+ int thread = -1;
+ find_condition_and_thread (s, sals.sals[0].pc,
+ &cond_string, &thread);
+ if (cond_string)
+ b->cond_string = cond_string;
+ b->thread = thread;
+ b->condition_not_parsed = 0;
+ }
+ expanded = expand_line_sal_maybe (sals.sals[0]);
+ update_breakpoint_locations (b, expanded);
- /* Now that this is re-enabled, check_duplicates
- can be used. */
- check_duplicates (b);
+ /* Now that this is re-enabled, check_duplicates
+ can be used. */
+ check_duplicates (b);
- }
xfree (sals.sals);
break;
if (b->cond_string != NULL)
{
s = b->cond_string;
- if (b->cond)
+ if (b->loc->cond)
{
- xfree (b->cond);
+ xfree (b->loc->cond);
/* Avoid re-freeing b->exp if an error during the call
to parse_exp_1. */
- b->cond = NULL;
+ b->loc->cond = NULL;
}
- b->cond = parse_exp_1 (&s, (struct block *) 0, 0);
+ b->loc->cond = parse_exp_1 (&s, (struct block *) 0, 0);
}
if (breakpoint_enabled (b))
mention (b);
ALL_BREAKPOINTS_SAFE (b, temp)
{
/* Format possible error msg */
- char *message = xstrprintf ("Error in re-setting breakpoint %d:\n",
+ char *message = xstrprintf ("Error in re-setting breakpoint %d: ",
b->number);
struct cleanup *cleanups = make_cleanup (xfree, message);
catch_errors (breakpoint_re_set_one, b, message, RETURN_MASK_ALL);
set_language (save_language);
input_radix = save_input_radix;
- if (GET_LONGJMP_TARGET_P ())
+ if (gdbarch_get_longjmp_target_p (current_gdbarch))
{
create_longjmp_breakpoint ("longjmp");
create_longjmp_breakpoint ("_longjmp");
}
}
+static struct bp_location *
+find_location_by_number (char *number)
+{
+ char *dot = strchr (number, '.');
+ char *p1;
+ int bp_num;
+ int loc_num;
+ struct breakpoint *b;
+ struct bp_location *loc;
+
+ *dot = '\0';
+
+ p1 = number;
+ bp_num = get_number_or_range (&p1);
+ if (bp_num == 0)
+ error (_("Bad breakpoint number '%s'"), number);
+
+ ALL_BREAKPOINTS (b)
+ if (b->number == bp_num)
+ {
+ break;
+ }
+
+ if (!b || b->number != bp_num)
+ error (_("Bad breakpoint number '%s'"), number);
+
+ p1 = dot+1;
+ loc_num = get_number_or_range (&p1);
+ if (loc_num == 0)
+ error (_("Bad breakpoint location number '%s'"), number);
+
+ --loc_num;
+ loc = b->loc;
+ for (;loc_num && loc; --loc_num, loc = loc->next)
+ ;
+ if (!loc)
+ error (_("Bad breakpoint location number '%s'"), dot+1);
+
+ return loc;
+}
+
+
/* Set ignore-count of breakpoint number BPTNUM to COUNT.
If from_tty is nonzero, it prints a message to that effect,
which ends with a period (no newline). */
default:
continue;
}
+ else if (strchr (args, '.'))
+ {
+ struct bp_location *loc = find_location_by_number (args);
+ if (loc)
+ loc->enabled = 0;
+ check_duplicates (loc->owner);
+ }
else
map_breakpoint_numbers (args, disable_breakpoint);
}
error (_("Hardware breakpoints used exceeds limit."));
}
- if (bpt->pending)
+ if (bpt->type == bp_watchpoint ||
+ bpt->type == bp_hardware_watchpoint ||
+ bpt->type == bp_read_watchpoint ||
+ bpt->type == bp_access_watchpoint)
{
- if (bpt->enable_state != bp_enabled)
+ struct frame_id saved_frame_id;
+
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ if (bpt->exp_valid_block != NULL)
{
- /* When enabling a pending breakpoint, we need to check if the breakpoint
- is resolvable since shared libraries could have been loaded
- after the breakpoint was disabled. */
- breakpoints_changed ();
- if (resolve_pending_breakpoint (bpt) == GDB_RC_OK)
+ struct frame_info *fr =
+ fr = frame_find_by_id (bpt->watchpoint_frame);
+ if (fr == NULL)
{
- delete_breakpoint (bpt);
+ printf_filtered (_("\
+Cannot enable watchpoint %d because the block in which its expression\n\
+is valid is not currently in scope.\n"), bpt->number);
return;
}
- bpt->enable_state = bp_enabled;
- bpt->disposition = disposition;
+ select_frame (fr);
}
- }
- else /* Not a pending breakpoint. */
- {
- if (bpt->enable_state != bp_permanent)
- bpt->enable_state = bp_enabled;
- bpt->disposition = disposition;
- check_duplicates (bpt);
- breakpoints_changed ();
- if (bpt->type == bp_watchpoint ||
- bpt->type == bp_hardware_watchpoint ||
- bpt->type == bp_read_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);
+
+ if (bpt->type == bp_hardware_watchpoint ||
+ bpt->type == bp_read_watchpoint ||
bpt->type == bp_access_watchpoint)
{
- struct frame_id saved_frame_id;
-
- saved_frame_id = get_frame_id (get_selected_frame (NULL));
- if (bpt->exp_valid_block != NULL)
- {
- struct frame_info *fr =
- fr = frame_find_by_id (bpt->watchpoint_frame);
- if (fr == NULL)
- {
- printf_filtered (_("\
-Cannot enable watchpoint %d because the block in which its expression\n\
-is valid is not currently in scope.\n"), bpt->number);
- bpt->enable_state = bp_disabled;
- return;
- }
- select_frame (fr);
- }
+ int i = hw_watchpoint_used_count (bpt->type, &other_type_used);
+ int mem_cnt = can_use_hardware_watchpoint (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);
-
- if (bpt->type == bp_hardware_watchpoint ||
- bpt->type == bp_read_watchpoint ||
- bpt->type == bp_access_watchpoint)
+ /* Hack around 'unused var' error for some targets here */
+ (void) mem_cnt, (void) i;
+ target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT (
+ bpt->type, i + mem_cnt, other_type_used);
+ /* we can consider of type is bp_hardware_watchpoint, convert to
+ bp_watchpoint in the following condition */
+ if (target_resources_ok < 0)
{
- int i = hw_watchpoint_used_count (bpt->type, &other_type_used);
- int mem_cnt = can_use_hardware_watchpoint (bpt->val);
-
- /* Hack around 'unused var' error for some targets here */
- (void) mem_cnt, i;
- target_resources_ok = TARGET_CAN_USE_HARDWARE_WATCHPOINT (
- bpt->type, i + mem_cnt, other_type_used);
- /* we can consider of type is bp_hardware_watchpoint, convert to
- bp_watchpoint in the following condition */
- if (target_resources_ok < 0)
- {
- printf_filtered (_("\
+ printf_filtered (_("\
Cannot enable watchpoint %d because target watch resources\n\
have been allocated for other watchpoints.\n"), bpt->number);
- bpt->enable_state = bp_disabled;
- value_free_to_mark (mark);
- return;
- }
+ value_free_to_mark (mark);
+ return;
}
-
- select_frame (frame_find_by_id (saved_frame_id));
- value_free_to_mark (mark);
}
+
+ select_frame (frame_find_by_id (saved_frame_id));
+ value_free_to_mark (mark);
}
+ if (bpt->enable_state != bp_permanent)
+ bpt->enable_state = bp_enabled;
+ bpt->disposition = disposition;
+ check_duplicates (bpt);
+ breakpoints_changed ();
+
if (deprecated_modify_breakpoint_hook)
deprecated_modify_breakpoint_hook (bpt);
breakpoint_modify_event (bpt->number);
}
+
void
enable_breakpoint (struct breakpoint *bpt)
{
default:
continue;
}
+ else if (strchr (args, '.'))
+ {
+ struct bp_location *loc = find_location_by_number (args);
+ if (loc)
+ loc->enabled = 1;
+ check_duplicates (loc->owner);
+ }
else
map_breakpoint_numbers (args, enable_breakpoint);
}
error (_("Junk at end of line specification: %s"), string);
return sals;
}
+
+/* Create and insert a raw software breakpoint at PC. Return an
+ identifier, which should be used to remove the breakpoint later.
+ In general, places which call this should be using something on the
+ breakpoint chain instead; this function should be eliminated
+ someday. */
+
+void *
+deprecated_insert_raw_breakpoint (CORE_ADDR pc)
+{
+ struct bp_target_info *bp_tgt;
+
+ bp_tgt = xmalloc (sizeof (struct bp_target_info));
+ memset (bp_tgt, 0, sizeof (struct bp_target_info));
+
+ bp_tgt->placed_address = pc;
+ if (target_insert_breakpoint (bp_tgt) != 0)
+ {
+ /* Could not insert the breakpoint. */
+ xfree (bp_tgt);
+ return NULL;
+ }
+
+ return bp_tgt;
+}
+
+/* Remove a breakpoint BP inserted by deprecated_insert_raw_breakpoint. */
+
+int
+deprecated_remove_raw_breakpoint (void *bp)
+{
+ struct bp_target_info *bp_tgt = bp;
+ int ret;
+
+ ret = target_remove_breakpoint (bp_tgt);
+ xfree (bp_tgt);
+
+ return ret;
+}
+
+/* One (or perhaps two) breakpoints used for software single stepping. */
+
+static void *single_step_breakpoints[2];
+
+/* Create and insert a breakpoint for software single step. */
+
+void
+insert_single_step_breakpoint (CORE_ADDR next_pc)
+{
+ void **bpt_p;
+
+ if (single_step_breakpoints[0] == NULL)
+ bpt_p = &single_step_breakpoints[0];
+ else
+ {
+ gdb_assert (single_step_breakpoints[1] == NULL);
+ bpt_p = &single_step_breakpoints[1];
+ }
+
+ /* NOTE drow/2006-04-11: A future improvement to this function would be
+ to only create the breakpoints once, and actually put them on the
+ breakpoint chain. That would let us use set_raw_breakpoint. We could
+ adjust the addresses each time they were needed. Doing this requires
+ corresponding changes elsewhere where single step breakpoints are
+ handled, however. So, for now, we use this. */
+
+ *bpt_p = deprecated_insert_raw_breakpoint (next_pc);
+ if (*bpt_p == NULL)
+ error (_("Could not insert single-step breakpoint at 0x%s"),
+ paddr_nz (next_pc));
+}
+
+/* Remove and delete any breakpoints used for software single step. */
+
+void
+remove_single_step_breakpoints (void)
+{
+ gdb_assert (single_step_breakpoints[0] != NULL);
+
+ /* See insert_single_step_breakpoint for more about this deprecated
+ call. */
+ deprecated_remove_raw_breakpoint (single_step_breakpoints[0]);
+ single_step_breakpoints[0] = NULL;
+
+ if (single_step_breakpoints[1] != NULL)
+ {
+ deprecated_remove_raw_breakpoint (single_step_breakpoints[1]);
+ single_step_breakpoints[1] = NULL;
+ }
+}
+
+/* Check whether a software single-step breakpoint is inserted at PC. */
+
+static int
+single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ struct bp_target_info *bp_tgt = single_step_breakpoints[i];
+ if (bp_tgt && bp_tgt->placed_address == pc)
+ return 1;
+ }
+
+ return 0;
+}
+
\f
/* This help string is used for the break, hbreak, tbreak and thbreak commands.
It is defined as a macro to prevent duplication.
The \"unset\" command is also an alias for \"delete\"."),
&deletelist, "delete ", 1, &cmdlist);
add_com_alias ("d", "delete", class_breakpoint, 1);
+ add_com_alias ("del", "delete", class_breakpoint, 1);
if (xdb_commands)
add_com ("db", class_breakpoint, delete_command, _("\
Delete some breakpoints.\n\
address and file/line number respectively.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
-are set to the address of the last breakpoint listed.\n\n\
+are set to the address of the last breakpoint listed unless the command\n\
+is prefixed with \"server \".\n\n\
Convenience variable \"$bpnum\" contains the number of the last\n\
breakpoint set."));
}
address and file/line number respectively.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
-are set to the address of the last breakpoint listed.\n\n\
+are set to the address of the last breakpoint listed unless the command\n\
+is prefixed with \"server \".\n\n\
Convenience variable \"$bpnum\" contains the number of the last\n\
breakpoint set."));
address and file/line number respectively.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
-are set to the address of the last breakpoint listed.\n\n\
+are set to the address of the last breakpoint listed unless the command\n\
+is prefixed with \"server \".\n\n\
Convenience variable \"$bpnum\" contains the number of the last\n\
breakpoint set."));
address and file/line number respectively.\n\
\n\
Convenience variable \"$_\" and default examine address for \"x\"\n\
-are set to the address of the last breakpoint listed.\n\
-\n\
+are set to the address of the last breakpoint listed unless the command\n\
+is prefixed with \"server \".\n\n\
Convenience variable \"$bpnum\" contains the number of the last\n\
breakpoint set."),
&maintenanceinfolist);
C++ exceptions may be caught:\n\
\tcatch throw - all exceptions, when thrown\n\
\tcatch catch - all exceptions, when caught\n\
+Ada exceptions may be caught:\n\
+\tcatch exception - all exceptions, when raised\n\
+\tcatch exception <name> - a particular exception, when raised\n\
+\tcatch exception unhandled - all unhandled exceptions, when raised\n\
+\tcatch assert - all failed assertions, when raised\n\
\n\
Do \"help set follow-fork-mode\" for info on debugging your program\n\
after a fork or vfork is caught.\n\n\
&breakpoint_show_cmdlist);
pending_break_support = AUTO_BOOLEAN_AUTO;
+
+ add_setshow_boolean_cmd ("auto-hw", no_class,
+ &automatic_hardware_breakpoints, _("\
+Set automatic usage of hardware breakpoints."), _("\
+Show automatic usage of hardware breakpoints."), _("\
+If set, the debugger will automatically use hardware breakpoints for\n\
+breakpoints set with \"break\" but falling in read-only memory. If not set,\n\
+a warning will be emitted for such breakpoints."),
+ NULL,
+ show_automatic_hardware_breakpoints,
+ &breakpoint_set_cmdlist,
+ &breakpoint_show_cmdlist);
+
+ automatic_hardware_breakpoints = 1;
}