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 void breakpoint_1 (int, int);
-static bpstat bpstat_alloc (struct bp_location *, bpstat);
+static bpstat bpstat_alloc (const struct bp_location *, bpstat);
static int breakpoint_cond_eval (void *);
static 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 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
/* 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. */
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. */
if (b->number == bnum)
{
struct bp_location *loc = b->loc;
- if (loc->cond)
+ for (; loc; loc = loc->next)
{
- xfree (loc->cond);
- loc->cond = 0;
+ if (loc->cond)
+ {
+ xfree (loc->cond);
+ loc->cond = 0;
+ }
}
if (b->cond_string != NULL)
xfree (b->cond_string);
/* 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->loc->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"));
}
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;
{
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. */
{
/* 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,
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;
/* Clear the "inserted" flag in all breakpoints. */
-void
+static void
mark_breakpoints_out (void)
{
struct bp_location *bpt;
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)
int
breakpoint_inserted_here_p (CORE_ADDR pc)
{
- struct bp_location *bpt;
+ const struct bp_location *bpt;
ALL_BP_LOCATIONS (bpt)
{
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
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);
{
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;
- b = bs->breakpoint_at->owner;
+ bl = bs->breakpoint_at;
+ b = bl->owner;
switch (b->type)
{
case bp_breakpoint:
case bp_hardware_breakpoint:
- if (b->loc->address != b->loc->requested_address)
- breakpoint_adjustment_warning (b->loc->requested_address,
- b->loc->address,
+ 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 ");
case print_it_normal:
{
- struct bp_location *bl = bs->breakpoint_at;
+ const struct bp_location *bl = bs->breakpoint_at;
struct breakpoint *b = bl ? bl->owner : NULL;
/* Normal case. Call the breakpoint's print_it method, or
/* Allocate a new bpstat and chain it to the current one. */
static bpstat
-bpstat_alloc (struct bp_location *bl, bpstat cbs /* Current "bs" value */ )
+bpstat_alloc (const struct bp_location *bl, bpstat cbs /* Current "bs" value */ )
{
bpstat bs;
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. */
}
/* 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->loc, 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->loc->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->loc->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->loc->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->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 ();
- }
- 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. */
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
*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;
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);
+ 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 (((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)
+ 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 (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)
{
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, ":");
-
- 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)
- {
- 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->loc->cond && !ada_exception_catchpoint_p (b))
+ 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 ");
- print_expression (b->loc->cond, stb->stream);
- ui_out_field_stream (uiout, "cond", stb);
- ui_out_text (uiout, "\n");
- }
-
- if (b->pending && b->cond_string)
- {
- 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;
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)
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
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", 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)"
- : 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)
loc->owner = bpt;
loc->cond = NULL;
+ loc->shlib_disabled = 0;
+ loc->enabled = 1;
switch (bp_type)
{
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;
- CORE_ADDR adjusted_address;
b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
memset (b, 0, sizeof (*b));
- /* 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->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;
}
-
- check_duplicates (b);
- breakpoints_changed ();
-
return b;
}
-
-/* Note that the breakpoint object B describes a permanent breakpoint
- instruction, hard-wired into the inferior's code. */
-void
-make_breakpoint_permanent (struct breakpoint *b)
+/* Initialize loc->function_name. */
+static void
+set_breakpoint_location_function (struct bp_location *loc)
{
- b->enable_state = bp_permanent;
-
- /* By definition, permanent breakpoints are already present in the code. */
- b->loc->inserted = 1;
+ 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);
+ }
}
-static struct breakpoint *
-create_internal_breakpoint (CORE_ADDR address, enum bptype type)
-{
- static int internal_breakpoint_number = -1;
- struct symtab_and_line sal;
- struct breakpoint *b;
+/* 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 ();
+
+ return b;
+}
+
+
+/* Note that the breakpoint object B describes a permanent breakpoint
+ instruction, hard-wired into the inferior's code. */
+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.
+ 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 *
+create_internal_breakpoint (CORE_ADDR address, enum bptype type)
+{
+ static int internal_breakpoint_number = -1;
+ struct symtab_and_line sal;
+ struct breakpoint *b;
init_sal (&sal); /* initialize to zeroes */
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)
void
disable_breakpoints_in_shlibs (void)
{
- struct breakpoint *b;
+ struct bp_location *loc;
int disabled_shlib_breaks = 0;
- 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;
+ {
+ 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;
- 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_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)
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;
{
/* 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
+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;
+
+ 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;
+
+ 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.
-
- The paramter PENDING_BP is same as for the
- create_breakpoints function. */
+ as condition expression. */
static void
-create_breakpoint (struct symtab_and_line sal, char *addr_string,
+create_breakpoint (struct symtabs_and_lines sals, char *addr_string,
char *cond_string,
enum bptype type, enum bpdisp disposition,
- int thread, int ignore_count, int from_tty,
- struct breakpoint *pending_bp)
+ int thread, int ignore_count, int from_tty)
{
- struct breakpoint *b;
+ struct breakpoint *b = NULL;
+ int i;
if (type == bp_hardware_breakpoint)
{
error (_("Hardware breakpoints used exceeds limit."));
}
- if (from_tty)
- describe_other_breakpoints (sal.pc, sal.section, thread);
-
- b = set_raw_breakpoint (sal, type);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
- b->thread = thread;
+ 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, 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;
- /* 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 (pending_bp->cond_string)
- b->cond_string = savestring (pending_bp->cond_string,
- strlen (pending_bp->cond_string));
-
- /* 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;
- }
+ b->cond_string = cond_string;
+ b->ignore_count = ignore_count;
+ b->enable_state = bp_enabled;
+ b->disposition = disposition;
- if (b->cond_string)
- {
- char *arg = b->cond_string;
- b->loc->cond = parse_exp_1 (&arg, block_for_pc (b->loc->address), 0);
- if (*arg)
+ loc = b->loc;
+ }
+ else
{
- if (pending_bp)
- error (_("Junk at end of pending breakpoint condition expression"));
- else
- error (_("Garbage %s follows condition"), arg);
+ 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;
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)
+ {
+ found = 1;
+ break;
+ }
+ 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
separate conditions for different overloaded functions, so
we take just a single condition string.
- The parameter PENDING_BP points to a pending breakpoint that is
- the basis of the breakpoints currently being created. The pending
- breakpoint may contain a separate condition string or commands
- that were added after the initial pending breakpoint was created.
-
NOTE: If the function succeeds, the caller is expected to cleanup
the arrays ADDR_STRING, COND_STRING, and SALS (but not the
array contents). If the function fails (error() is called), the
create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
char *cond_string,
enum bptype type, enum bpdisp disposition,
- int thread, int ignore_count, int from_tty,
- struct breakpoint *pending_bp)
+ int thread, int ignore_count, int from_tty)
{
int i;
for (i = 0; i < sals.nelts; ++i)
{
- create_breakpoint (sals.sals[i], addr_string[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,
- pending_bp);
+ thread, ignore_count, from_tty);
}
}
{
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
/* 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;
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);
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->loc->cond = NULL;
b->thread = thread;
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
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. */
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;
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);
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));
- }
+ memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
- /* 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);
}
b->exp_string = exp_string;
b->thread = -1;
b->ops = ops;
- b->from_tty = from_tty;
mention (b);
}
}
}
-/* 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->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)
+ struct bp_location *loc = b->loc;
+ for (; loc; loc = loc->next)
{
- /* b is at the head of the list */
- breakpoint_chain = b->next;
- }
- else
- {
- 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');
}
}
+/* 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);
+
+ if (loc->cond)
+ xfree (loc->cond);
- free_valchain (bpt->loc);
+ 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"));
-
- 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->target_info);
- else
- 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)
- {
- 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_string != NULL)
bp, we mark it as deleted before freeing its storage. */
bpt->type = bp_none;
- if (bpt->loc->cond)
- xfree (bpt->loc->cond);
- xfree (bpt->loc);
+ for (loc = bpt->loc; loc;)
+ {
+ struct bp_location *loc_next = loc->next;
+ xfree (loc);
+ loc = loc_next;
+ }
xfree (bpt);
}
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->loc->cond)
- {
- xfree (b->loc->cond);
- /* Avoid re-freeing b->exp if an error during the call
- to parse_exp_1. */
- b->loc->cond = NULL;
- }
- b->loc->cond = parse_exp_1 (&s, 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;
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);
}
}
+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, (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)
- {
- 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);
}