/* Everything about breakpoints, for GDB.
- Copyright (C) 1986-2015 Free Software Foundation, Inc.
+ Copyright (C) 1986-2016 Free Software Foundation, Inc.
This file is part of GDB.
#include "interps.h"
#include "format.h"
#include "location.h"
+#include "thread-fsm.h"
+#include "tid-parse.h"
/* readline include files */
#include "readline/readline.h"
static void decode_location_default (struct breakpoint *b,
const struct event_location *location,
+ struct program_space *search_pspace,
struct symtabs_and_lines *sals);
static void clear_command (char *, int);
struct address_space *aspace,
CORE_ADDR addr);
+static int breakpoint_location_address_range_overlap (struct bp_location *,
+ struct address_space *,
+ CORE_ADDR, int);
+
static void breakpoints_info (char *, int);
static void watchpoints_info (char *, int);
static void
do_cleanup_counted_command_line (void *arg)
{
- decref_counted_command_line (arg);
+ decref_counted_command_line ((struct counted_command_line **) arg);
}
/* Create a cleanup that calls decref_counted_command_line on the
static int
bp_location_compare_addrs (const void *ap, const void *bp)
{
- struct bp_location *a = *(void **) ap;
- struct bp_location *b = *(void **) bp;
+ const struct bp_location *a = *(const struct bp_location **) ap;
+ const struct bp_location *b = *(const struct bp_location **) bp;
if (a->address == b->address)
return 0;
dummy_loc.address = address;
/* Find a close match to the first location at ADDRESS. */
- locp_found = bsearch (&dummy_locp, bp_location, bp_location_count,
- sizeof (struct bp_location **),
- bp_location_compare_addrs);
+ locp_found = ((struct bp_location **)
+ bsearch (&dummy_locp, bp_location, bp_location_count,
+ sizeof (struct bp_location **),
+ bp_location_compare_addrs));
/* Nothing was found, nothing left to do. */
if (locp_found == NULL)
void
check_tracepoint_command (char *line, void *closure)
{
- struct breakpoint *b = closure;
+ struct breakpoint *b = (struct breakpoint *) closure;
validate_actionline (line, b);
}
static void
do_map_commands_command (struct breakpoint *b, void *data)
{
- struct commands_info *info = data;
+ struct commands_info *info = (struct commands_info *) data;
if (info->cmd == NULL)
{
return bit_val;
}
+/* Allocate a dummy location and add it to B, which must be a software
+ watchpoint. This is required because even if a software watchpoint
+ is not watching any memory, bpstat_stop_status requires a location
+ to be able to report stops. */
+
+static void
+software_watchpoint_add_no_memory_location (struct breakpoint *b,
+ struct program_space *pspace)
+{
+ gdb_assert (b->type == bp_watchpoint && b->loc == NULL);
+
+ b->loc = allocate_bp_location (b);
+ b->loc->pspace = pspace;
+ b->loc->address = -1;
+ b->loc->length = -1;
+}
+
+/* Returns true if B is a software watchpoint that is not watching any
+ memory (e.g., "watch $pc"). */
+
+static int
+is_no_memory_software_watchpoint (struct breakpoint *b)
+{
+ return (b->type == bp_watchpoint
+ && b->loc != NULL
+ && b->loc->next == NULL
+ && b->loc->address == -1
+ && b->loc->length == -1);
+}
+
/* Assuming that B is a watchpoint:
- Reparse watchpoint expression, if REPARSE is non-zero
- Evaluate expression and store the result in B->val
bpstat_stop_status requires a location to be able to report
stops, so make sure there's at least a dummy one. */
if (b->base.type == bp_watchpoint && b->base.loc == NULL)
- {
- struct breakpoint *base = &b->base;
- base->loc = allocate_bp_location (base);
- base->loc->pspace = frame_pspace;
- base->loc->address = -1;
- base->loc->length = -1;
- base->loc->watchpoint_type = -1;
- }
+ software_watchpoint_add_no_memory_location (&b->base, frame_pspace);
}
else if (!within_current_scope)
{
the thread no longer exists. ALL_BP_LOCATIONS bp_location
has BL->OWNER always non-NULL. */
if (bl->owner->thread != -1
- && !valid_thread_id (bl->owner->thread))
+ && !valid_global_thread_id (bl->owner->thread))
continue;
switch_to_program_space_and_thread (bl->pspace);
ALL_BREAKPOINTS_SAFE (b, b_tmp)
{
- if (b->thread == tp->num && user_breakpoint_p (b))
+ if (b->thread == tp->global_num && user_breakpoint_p (b))
{
b->disposition = disp_del_at_next_stop;
printf_filtered (_("\
-Thread-specific breakpoint %d deleted - thread %d no longer in the thread list.\n"),
- b->number, tp->num);
+Thread-specific breakpoint %d deleted - thread %s no longer in the thread list.\n"),
+ b->number, print_thread_id (tp));
/* Hide it from the user. */
b->number = 0;
{
struct breakpoint_objfile_data *bp_objfile_data;
- bp_objfile_data = objfile_data (objfile, breakpoint_objfile_key);
+ bp_objfile_data = ((struct breakpoint_objfile_data *)
+ objfile_data (objfile, breakpoint_objfile_key));
if (bp_objfile_data == NULL)
{
bp_objfile_data =
static void
free_breakpoint_probes (struct objfile *obj, void *data)
{
- struct breakpoint_objfile_data *bp_objfile_data = data;
+ struct breakpoint_objfile_data *bp_objfile_data
+ = (struct breakpoint_objfile_data *) data;
VEC_free (probe_p, bp_objfile_data->longjmp_probes);
VEC_free (probe_p, bp_objfile_data->exception_probes);
return any_breakpoint_here ? ordinary_breakpoint_here : no_breakpoint_here;
}
+/* See breakpoint.h. */
+
+int
+breakpoint_in_range_p (struct address_space *aspace,
+ CORE_ADDR addr, ULONGEST len)
+{
+ struct bp_location *bl, **blp_tmp;
+
+ ALL_BP_LOCATIONS (bl, blp_tmp)
+ {
+ if (bl->loc_type != bp_loc_software_breakpoint
+ && bl->loc_type != bp_loc_hardware_breakpoint)
+ continue;
+
+ if ((breakpoint_enabled (bl->owner)
+ || bl->permanent)
+ && breakpoint_location_address_range_overlap (bl, aspace,
+ addr, len))
+ {
+ if (overlay_debugging
+ && section_is_overlay (bl->section)
+ && !section_is_mapped (bl->section))
+ {
+ /* Unmapped overlay -- can't be a match. */
+ continue;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/* Return true if there's a moribund breakpoint at PC. */
int
}
}
+/* Print the "Thread ID hit" part of "Thread ID hit Breakpoint N" if
+ debugging multiple threads. */
+
+void
+maybe_print_thread_hit_breakpoint (struct ui_out *uiout)
+{
+ if (ui_out_is_mi_like_p (uiout))
+ return;
+
+ ui_out_text (uiout, "\n");
+
+ if (show_thread_that_caused_stop ())
+ {
+ const char *name;
+ struct thread_info *thr = inferior_thread ();
+
+ ui_out_text (uiout, "Thread ");
+ ui_out_field_fmt (uiout, "thread-id", "%s", print_thread_id (thr));
+
+ name = thr->name != NULL ? thr->name : target_thread_name (thr);
+ if (name != NULL)
+ {
+ ui_out_text (uiout, " \"");
+ ui_out_field_fmt (uiout, "name", "%s", name);
+ ui_out_text (uiout, "\"");
+ }
+
+ ui_out_text (uiout, " hit ");
+ }
+}
+
/* Generic routine for printing messages indicating why we
stopped. The behavior of this function depends on the value
'print_it' in the bpstat structure. Under some circumstances we
/* If this is a thread/task-specific breakpoint, don't waste cpu
evaluating the condition if this isn't the specified
thread/task. */
- if ((b->thread != -1 && b->thread != pid_to_thread_id (ptid))
+ if ((b->thread != -1 && b->thread != ptid_to_global_thread_id (ptid))
|| (b->task != 0 && b->task != ada_get_task_number (ptid)))
{
{
/* FIXME should make an annotation for this. */
ui_out_text (uiout, "\tstop only in thread ");
- ui_out_field_int (uiout, "thread", b->thread);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_int (uiout, "thread", b->thread);
+ else
+ {
+ struct thread_info *thr = find_thread_global_id (b->thread);
+
+ ui_out_field_string (uiout, "thread", print_thread_id (thr));
+ }
ui_out_text (uiout, "\n");
}
int print_address_bits = 0;
struct bp_location *loc;
+ /* Software watchpoints that aren't watching memory don't have an
+ address to print. */
+ if (is_no_memory_software_watchpoint (b))
+ return 0;
+
for (loc = b->loc; loc; loc = loc->next)
{
int addr_bit;
- /* Software watchpoints that aren't watching memory don't have
- an address to print. */
- if (b->type == bp_watchpoint && loc->watchpoint_type == -1)
- continue;
-
addr_bit = gdbarch_addr_bit (loc->gdbarch);
if (addr_bit > print_address_bits)
print_address_bits = addr_bit;
static int
do_captured_breakpoint_query (struct ui_out *uiout, void *data)
{
- struct captured_breakpoint_query_args *args = data;
+ struct captured_breakpoint_query_args *args
+ = (struct captured_breakpoint_query_args *) data;
struct breakpoint *b;
struct bp_location *dummy_loc = NULL;
aspace, addr)));
}
+/* Returns true if the [ADDR,ADDR+LEN) range in ASPACE overlaps
+ breakpoint BL. BL may be a ranged breakpoint. In most targets, a
+ match happens only if ASPACE matches the breakpoint's address
+ space. On targets that have global breakpoints, the address space
+ doesn't really matter. */
+
+static int
+breakpoint_location_address_range_overlap (struct bp_location *bl,
+ struct address_space *aspace,
+ CORE_ADDR addr, int len)
+{
+ if (gdbarch_has_global_breakpoints (target_gdbarch ())
+ || bl->pspace->aspace == aspace)
+ {
+ int bl_len = bl->length != 0 ? bl->length : 1;
+
+ if (mem_ranges_overlap (addr, len, bl->address, bl_len))
+ return 1;
+ }
+ return 0;
+}
+
/* If LOC1 and LOC2's owners are not tracepoints, returns false directly.
Then, if LOC1 and LOC2 represent the same tracepoint location, returns
true, otherwise returns false. */
set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame)
{
struct breakpoint *b, *b_tmp;
- int thread = tp->num;
+ int thread = tp->global_num;
/* To avoid having to rescan all objfile symbols at every step,
we maintain a list of continually-inserted but always disabled
new_b = momentary_breakpoint_from_master (b, bp_longjmp_call_dummy,
&momentary_breakpoint_ops,
1);
- new_b->thread = pid_to_thread_id (inferior_ptid);
+ new_b->thread = ptid_to_global_thread_id (inferior_ptid);
/* Link NEW_B into the chain of RETVAL breakpoints. */
struct breakpoint *b, *b_tmp;
ALL_BREAKPOINTS_SAFE (b, b_tmp)
- if (b->type == bp_longjmp_call_dummy && b->thread == tp->num)
+ if (b->type == bp_longjmp_call_dummy && b->thread == tp->global_num)
{
struct breakpoint *dummy_b = b->related_breakpoint;
b->enable_state = bp_enabled;
/* location has to be used or breakpoint_re_set will delete me. */
- b->location = new_address_location (b->loc->address);
+ b->location = new_address_location (b->loc->address, NULL, 0);
update_global_location_list_nothrow (UGLL_MAY_INSERT);
return b;
}
-void
-remove_thread_event_breakpoints (void)
-{
- struct breakpoint *b, *b_tmp;
-
- ALL_BREAKPOINTS_SAFE (b, b_tmp)
- if (b->type == bp_thread_event
- && b->loc->pspace == current_program_space)
- delete_breakpoint (b);
-}
-
struct lang_and_radix
{
enum language lang;
struct fork_catchpoint *c = (struct fork_catchpoint *) bs->breakpoint_at;
annotate_catchpoint (b->number);
+ maybe_print_thread_hit_breakpoint (uiout);
if (b->disposition == disp_del)
- ui_out_text (uiout, "\nTemporary catchpoint ");
+ ui_out_text (uiout, "Temporary catchpoint ");
else
- ui_out_text (uiout, "\nCatchpoint ");
+ ui_out_text (uiout, "Catchpoint ");
if (ui_out_is_mi_like_p (uiout))
{
ui_out_field_string (uiout, "reason",
struct fork_catchpoint *c = (struct fork_catchpoint *) b;
annotate_catchpoint (b->number);
+ maybe_print_thread_hit_breakpoint (uiout);
if (b->disposition == disp_del)
- ui_out_text (uiout, "\nTemporary catchpoint ");
+ ui_out_text (uiout, "Temporary catchpoint ");
else
- ui_out_text (uiout, "\nCatchpoint ");
+ ui_out_text (uiout, "Catchpoint ");
if (ui_out_is_mi_like_p (uiout))
{
ui_out_field_string (uiout, "reason",
struct ui_out *uiout = current_uiout;
annotate_catchpoint (b->number);
+ maybe_print_thread_hit_breakpoint (uiout);
if (b->disposition == disp_del)
- ui_out_text (uiout, "\nTemporary catchpoint ");
+ ui_out_text (uiout, "Temporary catchpoint ");
else
- ui_out_text (uiout, "\nCatchpoint ");
+ ui_out_text (uiout, "Catchpoint ");
ui_out_field_int (uiout, "bkptno", b->number);
ui_out_text (uiout, "\n");
if (ui_out_is_mi_like_p (uiout))
struct exec_catchpoint *c = (struct exec_catchpoint *) b;
annotate_catchpoint (b->number);
+ maybe_print_thread_hit_breakpoint (uiout);
if (b->disposition == disp_del)
- ui_out_text (uiout, "\nTemporary catchpoint ");
+ ui_out_text (uiout, "Temporary catchpoint ");
else
- ui_out_text (uiout, "\nCatchpoint ");
+ ui_out_text (uiout, "Catchpoint ");
if (ui_out_is_mi_like_p (uiout))
{
ui_out_field_string (uiout, "reason",
momentary breakpoints to be active in only a single thread of
control. */
if (in_thread_list (inferior_ptid))
- b->thread = pid_to_thread_id (inferior_ptid);
+ b->thread = ptid_to_global_thread_id (inferior_ptid);
update_global_location_list_nothrow (UGLL_MAY_INSERT);
if (bpoint == NULL)
return 0;
- target_mem = alloca (len);
+ target_mem = (gdb_byte *) alloca (len);
/* Enable the automatic memory restoration from breakpoints while
we read the memory. Otherwise we could say about our temporary
/* Create a breakpoint with SAL as location. Use LOCATION
as a description of the location, and COND_STRING
- as condition expression. */
+ as condition expression. If LOCATION is NULL then create an
+ "address location" from the address in the SAL. */
static void
init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
if (location != NULL)
b->location = location;
else
- b->location = new_address_location (b->loc->address);
+ {
+ const char *addr_string = NULL;
+ int addr_string_len = 0;
+
+ if (location != NULL)
+ addr_string = event_location_to_string (location);
+ if (addr_string != NULL)
+ addr_string_len = strlen (addr_string);
+
+ b->location = new_address_location (b->loc->address,
+ addr_string, addr_string_len);
+ }
b->filter = filter;
}
&& strchr ("+-", address[0]) != NULL
&& address[1] != '['))
{
- decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
+ decode_line_full (location, DECODE_LINE_FUNFIRSTLINE, NULL,
get_last_displayed_symtab (),
get_last_displayed_line (),
canonical, NULL, NULL);
}
}
- decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
+ decode_line_full (location, DECODE_LINE_FUNFIRSTLINE, NULL,
cursal.symtab, cursal.line, canonical, NULL, NULL);
}
}
}
-/* Issue an invalid thread ID error. */
-
-static void ATTRIBUTE_NORETURN
-invalid_thread_id_error (int id)
-{
- error (_("Unknown thread %d."), id);
-}
-
/* Given TOK, a string specification of condition and thread, as
accepted by the 'break' command, extract the condition
string and thread number and set *COND_STRING and *THREAD.
}
else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
{
- char *tmptok;
+ const char *tmptok;
+ struct thread_info *thr;
tok = end_tok + 1;
- *thread = strtol (tok, &tmptok, 0);
+ thr = parse_thread_id (tok, &tmptok);
if (tok == tmptok)
error (_("Junk after thread keyword."));
- if (!valid_thread_id (*thread))
- invalid_thread_id_error (*thread);
+ *thread = thr->global_num;
tok = tmptok;
}
else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0)
gdb_assert (bl && bl->next == NULL);
annotate_breakpoint (b->number);
+
+ maybe_print_thread_hit_breakpoint (uiout);
+
if (b->disposition == disp_del)
- ui_out_text (uiout, "\nTemporary ranged breakpoint ");
+ ui_out_text (uiout, "Temporary ranged breakpoint ");
else
- ui_out_text (uiout, "\nRanged breakpoint ");
+ ui_out_text (uiout, "Ranged breakpoint ");
if (ui_out_is_mi_like_p (uiout))
{
ui_out_field_string (uiout, "reason",
where +14 means 14 lines from the start location. */
end_location = string_to_event_location (&arg, current_language);
make_cleanup_delete_event_location (end_location);
- decode_line_full (end_location, DECODE_LINE_FUNFIRSTLINE,
+ decode_line_full (end_location, DECODE_LINE_FUNFIRSTLINE, NULL,
sal_start.symtab, sal_start.line,
&canonical_end, NULL, NULL);
stb = mem_fileopen ();
old_chain = make_cleanup_ui_file_delete (stb);
+ annotate_watchpoint (b->number);
+ maybe_print_thread_hit_breakpoint (uiout);
+
switch (b->type)
{
case bp_watchpoint:
case bp_hardware_watchpoint:
- annotate_watchpoint (b->number);
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason",
case bp_access_watchpoint:
if (bs->old_val != NULL)
{
- annotate_watchpoint (b->number);
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason",
/* Masked watchpoints have only one location. */
gdb_assert (b->loc && b->loc->next == NULL);
+ annotate_watchpoint (b->number);
+ maybe_print_thread_hit_breakpoint (uiout);
+
switch (b->type)
{
case bp_hardware_watchpoint:
- annotate_watchpoint (b->number);
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason",
if (toklen == 6 && startswith (tok, "thread"))
{
+ struct thread_info *thr;
/* At this point we've found a "thread" token, which means
the user is trying to set a watchpoint that triggers
only in a specific thread. */
- char *endp;
+ const char *endp;
if (thread != -1)
error(_("You can specify only one thread."));
/* Extract the thread ID from the next token. */
- thread = strtol (value_start, &endp, 0);
+ thr = parse_thread_id (value_start, &endp);
- /* Check if the user provided a valid numeric value for the
- thread ID. */
+ /* Check if the user provided a valid thread ID. */
if (*endp != ' ' && *endp != '\t' && *endp != '\0')
- error (_("Invalid thread ID specification %s."), value_start);
+ invalid_thread_id_error (value_start);
- /* Check if the thread actually exists. */
- if (!valid_thread_id (thread))
- invalid_thread_id_error (thread);
+ thread = thr->global_num;
}
else if (toklen == 4 && startswith (tok, "mask"))
{
}
\f
-/* Helper routines for the until_command routine in infcmd.c. Here
- because it uses the mechanisms of breakpoints. */
+/* Data for the FSM that manages the until(location)/advance commands
+ in infcmd.c. Here because it uses the mechanisms of
+ breakpoints. */
-struct until_break_command_continuation_args
+struct until_break_fsm
{
- struct breakpoint *breakpoint;
- struct breakpoint *breakpoint2;
- int thread_num;
+ /* The base class. */
+ struct thread_fsm thread_fsm;
+
+ /* The thread that as current when the command was executed. */
+ int thread;
+
+ /* The breakpoint set at the destination location. */
+ struct breakpoint *location_breakpoint;
+
+ /* Breakpoint set at the return address in the caller frame. May be
+ NULL. */
+ struct breakpoint *caller_breakpoint;
};
-/* This function is called by fetch_inferior_event via the
- cmd_continuation pointer, to complete the until command. It takes
- care of cleaning up the temporary breakpoints set up by the until
- command. */
+static void until_break_fsm_clean_up (struct thread_fsm *self);
+static int until_break_fsm_should_stop (struct thread_fsm *self);
+static enum async_reply_reason
+ until_break_fsm_async_reply_reason (struct thread_fsm *self);
+
+/* until_break_fsm's vtable. */
+
+static struct thread_fsm_ops until_break_fsm_ops =
+{
+ NULL, /* dtor */
+ until_break_fsm_clean_up,
+ until_break_fsm_should_stop,
+ NULL, /* return_value */
+ until_break_fsm_async_reply_reason,
+};
+
+/* Allocate a new until_break_command_fsm. */
+
+static struct until_break_fsm *
+new_until_break_fsm (int thread,
+ struct breakpoint *location_breakpoint,
+ struct breakpoint *caller_breakpoint)
+{
+ struct until_break_fsm *sm;
+
+ sm = XCNEW (struct until_break_fsm);
+ thread_fsm_ctor (&sm->thread_fsm, &until_break_fsm_ops);
+
+ sm->thread = thread;
+ sm->location_breakpoint = location_breakpoint;
+ sm->caller_breakpoint = caller_breakpoint;
+
+ return sm;
+}
+
+/* Implementation of the 'should_stop' FSM method for the
+ until(location)/advance commands. */
+
+static int
+until_break_fsm_should_stop (struct thread_fsm *self)
+{
+ struct until_break_fsm *sm = (struct until_break_fsm *) self;
+ struct thread_info *tp = inferior_thread ();
+
+ if (bpstat_find_breakpoint (tp->control.stop_bpstat,
+ sm->location_breakpoint) != NULL
+ || (sm->caller_breakpoint != NULL
+ && bpstat_find_breakpoint (tp->control.stop_bpstat,
+ sm->caller_breakpoint) != NULL))
+ thread_fsm_set_finished (self);
+
+ return 1;
+}
+
+/* Implementation of the 'clean_up' FSM method for the
+ until(location)/advance commands. */
+
static void
-until_break_command_continuation (void *arg, int err)
+until_break_fsm_clean_up (struct thread_fsm *self)
{
- struct until_break_command_continuation_args *a = arg;
+ struct until_break_fsm *sm = (struct until_break_fsm *) self;
+
+ /* Clean up our temporary breakpoints. */
+ if (sm->location_breakpoint != NULL)
+ {
+ delete_breakpoint (sm->location_breakpoint);
+ sm->location_breakpoint = NULL;
+ }
+ if (sm->caller_breakpoint != NULL)
+ {
+ delete_breakpoint (sm->caller_breakpoint);
+ sm->caller_breakpoint = NULL;
+ }
+ delete_longjmp_breakpoint (sm->thread);
+}
- delete_breakpoint (a->breakpoint);
- if (a->breakpoint2)
- delete_breakpoint (a->breakpoint2);
- delete_longjmp_breakpoint (a->thread_num);
+/* Implementation of the 'async_reply_reason' FSM method for the
+ until(location)/advance commands. */
+
+static enum async_reply_reason
+until_break_fsm_async_reply_reason (struct thread_fsm *self)
+{
+ return EXEC_ASYNC_LOCATION_REACHED;
}
void
struct gdbarch *frame_gdbarch;
struct frame_id stack_frame_id;
struct frame_id caller_frame_id;
- struct breakpoint *breakpoint;
- struct breakpoint *breakpoint2 = NULL;
+ struct breakpoint *location_breakpoint;
+ struct breakpoint *caller_breakpoint = NULL;
struct cleanup *old_chain, *cleanup;
int thread;
struct thread_info *tp;
struct event_location *location;
+ struct until_break_fsm *sm;
clear_proceed_status (0);
cleanup = make_cleanup_delete_event_location (location);
if (last_displayed_sal_is_valid ())
- sals = decode_line_1 (location, DECODE_LINE_FUNFIRSTLINE,
+ sals = decode_line_1 (location, DECODE_LINE_FUNFIRSTLINE, NULL,
get_last_displayed_symtab (),
get_last_displayed_line ());
else
sals = decode_line_1 (location, DECODE_LINE_FUNFIRSTLINE,
- (struct symtab *) NULL, 0);
+ NULL, (struct symtab *) NULL, 0);
if (sals.nelts != 1)
error (_("Couldn't get information on specified line."));
resolve_sal_pc (&sal);
tp = inferior_thread ();
- thread = tp->num;
+ thread = tp->global_num;
old_chain = make_cleanup (null_cleanup, NULL);
if (frame_id_p (caller_frame_id))
{
struct symtab_and_line sal2;
+ struct gdbarch *caller_gdbarch;
sal2 = find_pc_line (frame_unwind_caller_pc (frame), 0);
sal2.pc = frame_unwind_caller_pc (frame);
- breakpoint2 = set_momentary_breakpoint (frame_unwind_caller_arch (frame),
- sal2,
- caller_frame_id,
- bp_until);
- make_cleanup_delete_breakpoint (breakpoint2);
+ caller_gdbarch = frame_unwind_caller_arch (frame);
+ caller_breakpoint = set_momentary_breakpoint (caller_gdbarch,
+ sal2,
+ caller_frame_id,
+ bp_until);
+ make_cleanup_delete_breakpoint (caller_breakpoint);
set_longjmp_breakpoint (tp, caller_frame_id);
make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
if (anywhere)
/* If the user told us to continue until a specified location,
we don't specify a frame at which we need to stop. */
- breakpoint = set_momentary_breakpoint (frame_gdbarch, sal,
- null_frame_id, bp_until);
+ location_breakpoint = set_momentary_breakpoint (frame_gdbarch, sal,
+ null_frame_id, bp_until);
else
/* Otherwise, specify the selected frame, because we want to stop
only at the very same frame. */
- breakpoint = set_momentary_breakpoint (frame_gdbarch, sal,
- stack_frame_id, bp_until);
- make_cleanup_delete_breakpoint (breakpoint);
-
- proceed (-1, GDB_SIGNAL_DEFAULT);
-
- /* If we are running asynchronously, and proceed call above has
- actually managed to start the target, arrange for breakpoints to
- be deleted when the target stops. Otherwise, we're already
- stopped and delete breakpoints via cleanup chain. */
+ location_breakpoint = set_momentary_breakpoint (frame_gdbarch, sal,
+ stack_frame_id, bp_until);
+ make_cleanup_delete_breakpoint (location_breakpoint);
- if (is_running (inferior_ptid))
- {
- struct until_break_command_continuation_args *args =
- XNEW (struct until_break_command_continuation_args);
+ sm = new_until_break_fsm (tp->global_num,
+ location_breakpoint, caller_breakpoint);
+ tp->thread_fsm = &sm->thread_fsm;
- args->breakpoint = breakpoint;
- args->breakpoint2 = breakpoint2;
- args->thread_num = thread;
+ discard_cleanups (old_chain);
- discard_cleanups (old_chain);
- add_continuation (inferior_thread (),
- until_break_command_continuation, args,
- xfree);
- }
- else
- do_cleanups (old_chain);
+ proceed (-1, GDB_SIGNAL_DEFAULT);
do_cleanups (cleanup);
}
static int
compare_breakpoints (const void *a, const void *b)
{
- const breakpoint_p *ba = a;
+ const breakpoint_p *ba = (const breakpoint_p *) a;
uintptr_t ua = (uintptr_t) *ba;
- const breakpoint_p *bb = b;
+ const breakpoint_p *bb = (const breakpoint_p *) b;
uintptr_t ub = (uintptr_t) *bb;
if ((*ba)->number < (*bb)->number)
static int
bp_location_compare (const void *ap, const void *bp)
{
- struct bp_location *a = *(void **) ap;
- struct bp_location *b = *(void **) bp;
+ const struct bp_location *a = *(const struct bp_location **) ap;
+ const struct bp_location *b = *(const struct bp_location **) bp;
if (a->address != b->address)
return (a->address > b->address) - (a->address < b->address);
{
struct breakpoint *b;
struct cleanup *old_chain;
-
- if (!target_can_download_tracepoint ())
- return;
+ enum tribool can_download_tracepoint = TRIBOOL_UNKNOWN;
old_chain = save_current_space_and_thread ();
: !may_insert_tracepoints))
continue;
+ if (can_download_tracepoint == TRIBOOL_UNKNOWN)
+ {
+ if (target_can_download_tracepoint ())
+ can_download_tracepoint = TRIBOOL_TRUE;
+ else
+ can_download_tracepoint = TRIBOOL_FALSE;
+ }
+
+ if (can_download_tracepoint == TRIBOOL_FALSE)
+ break;
+
for (bl = b->loc; bl; bl = bl->next)
{
/* In tracepoint, locations are _never_ duplicated, so
static int
bpstat_remove_breakpoint_callback (struct thread_info *th, void *data)
{
- struct breakpoint *bpt = data;
+ struct breakpoint *bpt = (struct breakpoint *) data;
bpstat_remove_bp_location (th->control.stop_bpstat, bpt);
return 0;
static void
base_breakpoint_decode_location (struct breakpoint *b,
const struct event_location *location,
+ struct program_space *search_pspace,
struct symtabs_and_lines *sals)
{
internal_error_pure_virtual_called ();
bl->address,
b->number, 1);
annotate_breakpoint (b->number);
+ maybe_print_thread_hit_breakpoint (uiout);
+
if (bp_temp)
- ui_out_text (uiout, "\nTemporary breakpoint ");
+ ui_out_text (uiout, "Temporary breakpoint ");
else
- ui_out_text (uiout, "\nBreakpoint ");
+ ui_out_text (uiout, "Breakpoint ");
if (ui_out_is_mi_like_p (uiout))
{
ui_out_field_string (uiout, "reason",
static void
bkpt_decode_location (struct breakpoint *b,
const struct event_location *location,
+ struct program_space *search_pspace,
struct symtabs_and_lines *sals)
{
- decode_location_default (b, location, sals);
+ decode_location_default (b, location, search_pspace, sals);
}
/* Virtual table for internal breakpoints. */
static enum print_stop_action
momentary_bkpt_print_it (bpstat bs)
{
- struct ui_out *uiout = current_uiout;
-
- if (ui_out_is_mi_like_p (uiout))
- {
- struct breakpoint *b = bs->breakpoint_at;
-
- switch (b->type)
- {
- case bp_until:
- ui_out_field_string
- (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_LOCATION_REACHED));
- break;
- }
- }
-
return PRINT_UNKNOWN;
}
static void
longjmp_bkpt_dtor (struct breakpoint *self)
{
- struct thread_info *tp = find_thread_id (self->thread);
+ struct thread_info *tp = find_thread_global_id (self->thread);
if (tp)
tp->initiating_frame = null_frame_id;
{
struct linespec_sals lsal;
- lsal.sals = parse_probes (location, canonical);
+ lsal.sals = parse_probes (location, NULL, canonical);
lsal.canonical = xstrdup (event_location_to_string (canonical->location));
VEC_safe_push (linespec_sals, canonical->sals, &lsal);
}
static void
bkpt_probe_decode_location (struct breakpoint *b,
const struct event_location *location,
+ struct program_space *search_pspace,
struct symtabs_and_lines *sals)
{
- *sals = parse_probes (location, NULL);
+ *sals = parse_probes (location, search_pspace, NULL);
if (!sals->sals)
error (_("probe not found"));
}
if (self->type == bp_fast_tracepoint)
fprintf_unfiltered (fp, "ftrace");
- if (self->type == bp_static_tracepoint)
+ else if (self->type == bp_static_tracepoint)
fprintf_unfiltered (fp, "strace");
else if (self->type == bp_tracepoint)
fprintf_unfiltered (fp, "trace");
static void
tracepoint_decode_location (struct breakpoint *b,
const struct event_location *location,
+ struct program_space *search_pspace,
struct symtabs_and_lines *sals)
{
- decode_location_default (b, location, sals);
+ decode_location_default (b, location, search_pspace, sals);
}
struct breakpoint_ops tracepoint_breakpoint_ops;
static void
tracepoint_probe_decode_location (struct breakpoint *b,
const struct event_location *location,
+ struct program_space *search_pspace,
struct symtabs_and_lines *sals)
{
/* We use the same method for breakpoint on probes. */
- bkpt_probe_decode_location (b, location, sals);
+ bkpt_probe_decode_location (b, location, search_pspace, sals);
}
static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
static void
strace_marker_decode_location (struct breakpoint *b,
const struct event_location *location,
+ struct program_space *search_pspace,
struct symtabs_and_lines *sals)
{
struct tracepoint *tp = (struct tracepoint *) b;
static void
do_delete_breakpoint_cleanup (void *b)
{
- delete_breakpoint (b);
+ delete_breakpoint ((struct breakpoint *) b);
}
struct cleanup *
map_breakpoint_numbers (arg, do_map_delete_breakpoint, NULL);
}
+/* Return true if all locations of B bound to PSPACE are pending. If
+ PSPACE is NULL, all locations of all program spaces are
+ considered. */
+
static int
-all_locations_are_pending (struct bp_location *loc)
+all_locations_are_pending (struct breakpoint *b, struct program_space *pspace)
{
- for (; loc; loc = loc->next)
- if (!loc->shlib_disabled
+ struct bp_location *loc;
+
+ for (loc = b->loc; loc != NULL; loc = loc->next)
+ if ((pspace == NULL
+ || loc->pspace == pspace)
+ && !loc->shlib_disabled
&& !loc->pspace->executing_startup)
return 0;
return 1;
return 1;
}
-/* Create new breakpoint locations for B (a hardware or software breakpoint)
- based on SALS and SALS_END. If SALS_END.NELTS is not zero, then B is
- a ranged breakpoint. */
+/* Split all locations of B that are bound to PSPACE out of B's
+ location list to a separate list and return that list's head. If
+ PSPACE is NULL, hoist out all locations of B. */
+
+static struct bp_location *
+hoist_existing_locations (struct breakpoint *b, struct program_space *pspace)
+{
+ struct bp_location head;
+ struct bp_location *i = b->loc;
+ struct bp_location **i_link = &b->loc;
+ struct bp_location *hoisted = &head;
+
+ if (pspace == NULL)
+ {
+ i = b->loc;
+ b->loc = NULL;
+ return i;
+ }
+
+ head.next = NULL;
+
+ while (i != NULL)
+ {
+ if (i->pspace == pspace)
+ {
+ *i_link = i->next;
+ i->next = NULL;
+ hoisted->next = i;
+ hoisted = i;
+ }
+ else
+ i_link = &i->next;
+ i = *i_link;
+ }
+
+ return head.next;
+}
+
+/* Create new breakpoint locations for B (a hardware or software
+ breakpoint) based on SALS and SALS_END. If SALS_END.NELTS is not
+ zero, then B is a ranged breakpoint. Only recreates locations for
+ FILTER_PSPACE. Locations of other program spaces are left
+ untouched. */
void
update_breakpoint_locations (struct breakpoint *b,
+ struct program_space *filter_pspace,
struct symtabs_and_lines sals,
struct symtabs_and_lines sals_end)
{
int i;
- struct bp_location *existing_locations = b->loc;
+ struct bp_location *existing_locations;
if (sals_end.nelts != 0 && (sals.nelts != 1 || sals_end.nelts != 1))
{
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)
+ if (all_locations_are_pending (b, filter_pspace) && sals.nelts == 0)
return;
- b->loc = NULL;
+ existing_locations = hoist_existing_locations (b, filter_pspace);
for (i = 0; i < sals.nelts; ++i)
{
static struct symtabs_and_lines
location_to_sals (struct breakpoint *b, struct event_location *location,
- int *found)
+ struct program_space *search_pspace, int *found)
{
struct symtabs_and_lines sals = {0};
struct gdb_exception exception = exception_none;
TRY
{
- b->ops->decode_location (b, location, &sals);
+ b->ops->decode_location (b, location, search_pspace, &sals);
}
CATCH (e, RETURN_MASK_ERROR)
{
breakpoint being disabled, and don't want to see more
errors. */
if (e.error == NOT_FOUND_ERROR
- && (b->condition_not_parsed
+ && (b->condition_not_parsed
+ || (b->loc != NULL
+ && search_pspace != NULL
+ && b->loc->pspace != search_pspace)
|| (b->loc && b->loc->shlib_disabled)
|| (b->loc && b->loc->pspace->executing_startup)
|| b->enable_state == bp_disabled))
struct symtabs_and_lines sals, sals_end;
struct symtabs_and_lines expanded = {0};
struct symtabs_and_lines expanded_end = {0};
+ struct program_space *filter_pspace = current_program_space;
- sals = location_to_sals (b, b->location, &found);
+ sals = location_to_sals (b, b->location, filter_pspace, &found);
if (found)
{
make_cleanup (xfree, sals.sals);
if (b->location_range_end != NULL)
{
- sals_end = location_to_sals (b, b->location_range_end, &found);
+ sals_end = location_to_sals (b, b->location_range_end,
+ filter_pspace, &found);
if (found)
{
make_cleanup (xfree, sals_end.sals);
}
}
- update_breakpoint_locations (b, expanded, expanded_end);
+ update_breakpoint_locations (b, filter_pspace, expanded, expanded_end);
}
/* Default method for creating SALs from an address string. It basically
static void
decode_location_default (struct breakpoint *b,
const struct event_location *location,
+ struct program_space *search_pspace,
struct symtabs_and_lines *sals)
{
struct linespec_result canonical;
init_linespec_result (&canonical);
- decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
+ decode_line_full (location, DECODE_LINE_FUNFIRSTLINE, search_pspace,
(struct symtab *) NULL, 0,
&canonical, multiple_symbols_all,
b->filter);
static struct cleanup *
prepare_re_set_context (struct breakpoint *b)
{
- struct cleanup *cleanups;
-
input_radix = b->input_radix;
- cleanups = save_current_space_and_thread ();
- if (b->pspace != NULL)
- switch_to_program_space_and_thread (b->pspace);
set_language (b->language);
- return cleanups;
+ return make_cleanup (null_cleanup, NULL);
}
/* Reset a breakpoint given it's struct breakpoint * BINT.
return 0;
}
-/* Re-set all breakpoints after symbols have been re-loaded. */
+/* Re-set breakpoint locations for the current program space.
+ Locations bound to other program spaces are left untouched. */
+
void
breakpoint_re_set (void)
{
save_language = current_language->la_language;
save_input_radix = input_radix;
- old_chain = save_current_program_space ();
+ old_chain = save_current_space_and_thread ();
ALL_BREAKPOINTS_SAFE (b, b_tmp)
{
if (b->thread != -1)
{
if (in_thread_list (inferior_ptid))
- b->thread = pid_to_thread_id (inferior_ptid);
+ b->thread = ptid_to_global_thread_id (inferior_ptid);
/* We're being called after following a fork. The new fork is
selected as current, and unless this was a vfork will have a
if (tp->control.single_step_breakpoints == NULL)
{
tp->control.single_step_breakpoints
- = new_single_step_breakpoint (tp->num, gdbarch);
+ = new_single_step_breakpoint (tp->global_num, gdbarch);
}
sal = find_pc_line (pc, 0);