/* Everything about breakpoints, for GDB.
- Copyright 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
Free Software Foundation, Inc.
This file is part of GDB.
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., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include <ctype.h>
#include "solist.h"
#include "observer.h"
#include "exceptions.h"
+#include "memattr.h"
#include "gdb-events.h"
#include "mi/mi-common.h"
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);
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? */
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;
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;
if (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 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 */
if (!breakpoint_enabled (b->owner))
continue;
+ /* There is no point inserting thread-specific breakpoints if the
+ thread no longer exists. */
+ if (b->owner->thread != -1
+ && !valid_thread_id (b->owner->thread))
+ continue;
+
/* FIXME drow/2003-10-07: This code should be pushed elsewhere when
hardware watchpoints are split into multiple loc breakpoints. */
if ((b->loc_type == bp_loc_hardware_watchpoint
if (b->inserted)
{
remove_breakpoint (b, mark_inserted);
+ /* Note: since we insert a breakpoint right after removing,
+ any decisions about automatically using hardware breakpoints
+ made in insert_bp_location are preserved. */
if (b->loc_type == bp_loc_hardware_breakpoint)
- val = target_insert_hw_breakpoint (b->address, b->shadow_contents);
+ val = target_insert_hw_breakpoint (&b->target_info);
else
- val = target_insert_breakpoint (b->address, b->shadow_contents);
+ val = target_insert_breakpoint (&b->target_info);
/* FIXME drow/2003-10-07: This doesn't handle any other kinds of
breakpoints. It's wrong for watchpoints, for example. */
if (val != 0)
(b->type == bp_catch_vfork) ||
(b->type == bp_catch_fork))
{
- b->loc->address = (CORE_ADDR) NULL;
+ b->loc->address = (CORE_ADDR) 0;
continue;
}
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;
+ b->loc->address = (CORE_ADDR) 0;
}
/* 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);
else
- val = target_remove_breakpoint (b->address,
- b->shadow_contents);
+ val = target_remove_breakpoint (&b->target_info);
}
else
{
&& 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);
&& 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;
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;
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
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
}
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 (b->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->pending)
/* 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;
if (!b->pending && (!overlay_debugging || b->loc->section == section))
{
others--;
- printf_filtered ("%d%s%s ",
- b->number,
+ 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_shlib_disabled ||
b->enable_state == bp_call_disabled)
- ? " (disabled)"
+ ? " (disabled)"
: b->enable_state == bp_permanent
? " (permanent)"
: ""),
struct symtab_and_line sal = sals.sals[i];
if (from_tty)
- describe_other_breakpoints (sal.pc, sal.section);
+ describe_other_breakpoints (sal.pc, sal.section, thread);
b = set_raw_breakpoint (sal, type);
set_breakpoint_count (breakpoint_count + 1);
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)
{
_("another breakpoint was inserted on top of "
"a permanent breakpoint"));
+ memset (&b->loc->target_info, 0, sizeof (b->loc->target_info));
+ b->loc->target_info.placed_address = b->loc->address;
if (b->type == bp_hardware_breakpoint)
- val = target_insert_hw_breakpoint (b->loc->address, b->loc->shadow_contents);
+ val = target_insert_hw_breakpoint (&b->loc->target_info);
else
- val = target_insert_breakpoint (b->loc->address, b->loc->shadow_contents);
+ val = target_insert_breakpoint (&b->loc->target_info);
/* If there was an error in the insert, print a message, then stop execution. */
if (val != 0)
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;
+ }
+}
+
\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\
&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;
}