#include "language.h"
#include "gdb_string.h"
#include "demangle.h"
+#include "filenames.h"
#include "annotate.h"
#include "symfile.h"
#include "objfiles.h"
#include "jit.h"
#include "xml-syscall.h"
#include "parser-defs.h"
+#include "cli/cli-utils.h"
/* readline include files */
#include "readline/readline.h"
#undef savestring
#include "mi/mi-common.h"
+#include "python/python.h"
/* Arguments to pass as context to some catch command handlers. */
#define CATCH_PERMANENT ((void *) (uintptr_t) 0)
static void catch_command (char *, int);
-static int can_use_hardware_watchpoint (struct value *);
+static int can_use_hardware_watchpoint (struct value *, int);
static void break_command_1 (char *, int, int);
static int watchpoint_locations_match (struct bp_location *loc1,
struct bp_location *loc2);
+static int breakpoint_location_address_match (struct bp_location *bl,
+ struct address_space *aspace,
+ CORE_ADDR addr);
+
static void breakpoints_info (char *, int);
static void watchpoints_info (char *, int);
-static int breakpoint_1 (int, int, int (*) (const struct breakpoint *));
+static int breakpoint_1 (char *, int,
+ int (*) (const struct breakpoint *));
static int breakpoint_cond_eval (void *);
static void condition_command (char *, int);
-static int get_number_trailer (char **, int);
-
typedef enum
{
mark_inserted,
static void tcatch_command (char *arg, int from_tty);
-static void ep_skip_leading_whitespace (char **s);
-
static void detach_single_step_breakpoints (void);
static int single_step_breakpoint_inserted_here_p (struct address_space *,
static int breakpoint_proceeded;
-static const char *
+const char *
bpdisp_text (enum bpdisp disp)
{
/* NOTE: the following values are a part of MI protocol and
/* Are overlay event breakpoints enabled? */
static int overlay_events_enabled;
+/* See description in breakpoint.h. */
+int target_exact_watchpoints = 0;
+
/* Walk the following statement or block through all breakpoints.
ALL_BREAKPOINTS_SAFE does so even if the statment deletes the
current breakpoint. */
struct program_space *default_breakpoint_pspace;
\f
-/* *PP is a string denoting a breakpoint. Get the number of the
- breakpoint. Advance *PP after the string and any trailing
- whitespace.
-
- Currently the string can either be a number or "$" followed by the
- name of a convenience variable. Making it an expression wouldn't
- work well for map_breakpoint_numbers (e.g. "4 + 5 + 6").
-
- If the string is a NULL pointer, that denotes the last breakpoint.
-
- TRAILER is a character which can be found after the number; most
- commonly this is `-'. If you don't want a trailer, use \0. */
-
-static int
-get_number_trailer (char **pp, int trailer)
-{
- int retval = 0; /* default */
- char *p = *pp;
-
- if (p == NULL)
- /* Empty line means refer to the last breakpoint. */
- return breakpoint_count;
- else if (*p == '$')
- {
- /* Make a copy of the name, so we can null-terminate it
- to pass to lookup_internalvar(). */
- char *varname;
- char *start = ++p;
- LONGEST val;
-
- while (isalnum (*p) || *p == '_')
- p++;
- varname = (char *) alloca (p - start + 1);
- strncpy (varname, start, p - start);
- varname[p - start] = '\0';
- if (get_internalvar_integer (lookup_internalvar (varname), &val))
- retval = (int) val;
- else
- {
- printf_filtered (_("Convenience variable must "
- "have integer value.\n"));
- retval = 0;
- }
- }
- else
- {
- if (*p == '-')
- ++p;
- while (*p >= '0' && *p <= '9')
- ++p;
- if (p == *pp)
- /* There is no number here. (e.g. "cond a == b"). */
- {
- /* Skip non-numeric token. */
- while (*p && !isspace((int) *p))
- ++p;
- /* Return zero, which caller must interpret as error. */
- retval = 0;
- }
- else
- retval = atoi (*pp);
- }
- if (!(isspace (*p) || *p == '\0' || *p == trailer))
- {
- /* Trailing junk: return 0 and let caller print error msg. */
- while (!(isspace (*p) || *p == '\0' || *p == trailer))
- ++p;
- retval = 0;
- }
- while (isspace (*p))
- p++;
- *pp = p;
- return retval;
-}
-
-
-/* Like get_number_trailer, but don't allow a trailer. */
-int
-get_number (char **pp)
-{
- return get_number_trailer (pp, '\0');
-}
-
-/* Parse a number or a range.
- A number will be of the form handled by get_number.
- A range will be of the form <number1> - <number2>, and
- will represent all the integers between number1 and number2,
- inclusive.
-
- While processing a range, this fuction is called iteratively;
- At each call it will return the next value in the range.
-
- At the beginning of parsing a range, the char pointer PP will
- be advanced past <number1> and left pointing at the '-' token.
- Subsequent calls will not advance the pointer until the range
- is completed. The call that completes the range will advance
- pointer PP past <number2>. */
-
-int
-get_number_or_range (char **pp)
-{
- static int last_retval, end_value;
- static char *end_ptr;
- static int in_range = 0;
-
- if (**pp != '-')
- {
- /* Default case: pp is pointing either to a solo number,
- or to the first number of a range. */
- last_retval = get_number_trailer (pp, '-');
- if (**pp == '-')
- {
- char **temp;
-
- /* This is the start of a range (<number1> - <number2>).
- Skip the '-', parse and remember the second number,
- and also remember the end of the final token. */
-
- temp = &end_ptr;
- end_ptr = *pp + 1;
- while (isspace ((int) *end_ptr))
- end_ptr++; /* skip white space */
- end_value = get_number (temp);
- if (end_value < last_retval)
- {
- error (_("inverted range"));
- }
- else if (end_value == last_retval)
- {
- /* Degenerate range (number1 == number2). Advance the
- token pointer so that the range will be treated as a
- single number. */
- *pp = end_ptr;
- }
- else
- in_range = 1;
- }
- }
- else if (! in_range)
- error (_("negative value"));
- else
- {
- /* pp points to the '-' that betokens a range. All
- number-parsing has already been done. Return the next
- integer value (one greater than the saved previous value).
- Do not advance the token pointer 'pp' until the end of range
- is reached. */
-
- if (++last_retval == end_value)
- {
- /* End of range reached; advance token pointer. */
- *pp = end_ptr;
- in_range = 0;
- }
- }
- return last_retval;
-}
-
/* Return the breakpoint with the specified number, or NULL
if the number does not refer to an existing breakpoint. */
ALL_BREAKPOINTS (b)
if (b->number == bnum)
{
+ /* Check if this breakpoint has a Python object assigned to
+ it, and if it has a definition of the "stop"
+ method. This method and conditions entered into GDB from
+ the CLI are mutually exclusive. */
+ if (b->py_bp_object
+ && gdbpy_breakpoint_has_py_cond (b->py_bp_object))
+ error (_("Cannot set a condition where a Python 'stop' "
+ "method has been defined in the breakpoint."));
set_breakpoint_condition (b, p, from_tty);
return;
}
observer_notify_breakpoint_modified (b->number);
}
+/* Set the internal `silent' flag on the breakpoint. Note that this
+ is not the same as the "silent" that may appear in the breakpoint's
+ commands. */
+
+void
+breakpoint_set_silent (struct breakpoint *b, int silent)
+{
+ int old_silent = b->silent;
+
+ b->silent = silent;
+ if (old_silent != silent)
+ observer_notify_breakpoint_modified (b->number);
+}
+
+/* Set the thread for this breakpoint. If THREAD is -1, make the
+ breakpoint work for any thread. */
+
+void
+breakpoint_set_thread (struct breakpoint *b, int thread)
+{
+ int old_thread = b->thread;
+
+ b->thread = thread;
+ if (old_thread != thread)
+ observer_notify_breakpoint_modified (b->number);
+}
+
+/* Set the task for this breakpoint. If TASK is 0, make the
+ breakpoint work for any task. */
+
+void
+breakpoint_set_task (struct breakpoint *b, int task)
+{
+ int old_task = b->task;
+
+ b->task = task;
+ if (old_task != task)
+ observer_notify_breakpoint_modified (b->number);
+}
+
void
check_tracepoint_command (char *line, void *closure)
{
}
\f
-/* A wrapper function for inserting catchpoints. */
-static void
-insert_catchpoint (struct ui_out *uo, void *args)
-{
- struct breakpoint *b = (struct breakpoint *) args;
-
- gdb_assert (b->type == bp_catchpoint);
- gdb_assert (b->ops != NULL && b->ops->insert != NULL);
-
- b->ops->insert (b);
-}
-
/* Return true if BPT is of any hardware watchpoint kind. */
static int
&& !is_executing (inferior_ptid)));
}
+/* Set watchpoint B to disp_del_at_next_stop, even including its possible
+ associated bp_watchpoint_scope breakpoint. */
+
+static void
+watchpoint_del_at_next_stop (struct breakpoint *b)
+{
+ gdb_assert (is_watchpoint (b));
+
+ if (b->related_breakpoint != b)
+ {
+ gdb_assert (b->related_breakpoint->type == bp_watchpoint_scope);
+ gdb_assert (b->related_breakpoint->related_breakpoint == b);
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->related_breakpoint->related_breakpoint = b->related_breakpoint;
+ b->related_breakpoint = b;
+ }
+ b->disposition = disp_del_at_next_stop;
+}
+
/* Assuming that B is a watchpoint:
- Reparse watchpoint expression, if REPARSE is non-zero
- Evaluate expression and store the result in B->val
struct frame_id saved_frame_id;
int frame_saved;
+ gdb_assert (is_watchpoint (b));
+
/* If this is a local watchpoint, we only want to check if the
watchpoint frame is in scope if the current thread is the thread
that was used to create the watchpoint. */
if (!watchpoint_in_thread_scope (b))
return;
- /* We don't free locations. They are stored in bp_location array
- and update_global_locations will eventually delete them and
- remove breakpoints if needed. */
- b->loc = NULL;
-
if (b->disposition == disp_del_at_next_stop)
return;
within_current_scope = 1;
else
{
- struct frame_info *fi;
+ struct frame_info *fi = get_current_frame ();
+ struct gdbarch *frame_arch = get_frame_arch (fi);
+ CORE_ADDR frame_pc = get_frame_pc (fi);
+
+ /* If we're in a function epilogue, unwinding may not work
+ properly, so do not attempt to recreate locations at this
+ point. See similar comments in watchpoint_check. */
+ if (gdbarch_in_function_epilogue_p (frame_arch, frame_pc))
+ return;
/* Save the current frame's ID so we can restore it after
evaluating the watchpoint expression on its own frame. */
select_frame (fi);
}
+ /* We don't free locations. They are stored in the bp_location array
+ and update_global_location_list will eventually delete them and
+ remove breakpoints if needed. */
+ b->loc = NULL;
+
if (within_current_scope && reparse)
{
char *s;
b->val_valid = 1;
}
- /* Change the type of breakpoint between hardware assisted or
- an ordinary watchpoint depending on the hardware support
- and free hardware slots. REPARSE is set when the inferior
- is started. */
- if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
- && reparse)
- {
- int i, mem_cnt, other_type_used;
-
- /* We need to determine how many resources are already
- used for all other hardware watchpoints to see if we
- still have enough resources to also fit this watchpoint
- in as well. To avoid the hw_watchpoint_used_count call
- below from counting this watchpoint, make sure that it
- is marked as a software watchpoint. */
- b->type = bp_watchpoint;
- i = hw_watchpoint_used_count (bp_hardware_watchpoint,
- &other_type_used);
- mem_cnt = can_use_hardware_watchpoint (val_chain);
-
- if (!mem_cnt)
- b->type = bp_watchpoint;
- else
- {
- int target_resources_ok = target_can_use_hardware_watchpoint
- (bp_hardware_watchpoint, i + mem_cnt, other_type_used);
- if (target_resources_ok <= 0)
- b->type = bp_watchpoint;
- else
- b->type = bp_hardware_watchpoint;
- }
- }
-
frame_pspace = get_frame_program_space (get_selected_frame (NULL));
/* Look at each value on the value chain. */
- for (v = val_chain; v; v = next)
+ for (v = val_chain; v; v = value_next (v))
{
/* If it's a memory location, and GDB actually needed
its contents to evaluate the expression, then we
loc->watchpoint_type = type;
}
}
+ }
+
+ /* Change the type of breakpoint between hardware assisted or
+ an ordinary watchpoint depending on the hardware support
+ and free hardware slots. REPARSE is set when the inferior
+ is started. */
+ if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
+ && reparse)
+ {
+ int reg_cnt;
+ enum bp_loc_type loc_type;
+ struct bp_location *bl;
+
+ reg_cnt = can_use_hardware_watchpoint (val_chain, b->exact);
+
+ if (reg_cnt)
+ {
+ int i, target_resources_ok, other_type_used;
+ enum enable_state orig_enable_state;
+
+ /* We need to determine how many resources are already
+ used for all other hardware watchpoints plus this one
+ to see if we still have enough resources to also fit
+ this watchpoint in as well. To guarantee the
+ hw_watchpoint_used_count call below counts this
+ watchpoint, make sure that it is marked as a hardware
+ watchpoint. */
+ b->type = bp_hardware_watchpoint;
+
+ /* hw_watchpoint_used_count ignores disabled watchpoints,
+ and b might be disabled if we're being called from
+ do_enable_breakpoint. */
+ orig_enable_state = b->enable_state;
+ b->enable_state = bp_enabled;
+
+ i = hw_watchpoint_used_count (bp_hardware_watchpoint,
+ &other_type_used);
+
+ b->enable_state = orig_enable_state;
+
+ target_resources_ok = target_can_use_hardware_watchpoint
+ (bp_hardware_watchpoint, i, other_type_used);
+ if (target_resources_ok <= 0)
+ b->type = bp_watchpoint;
+ }
+ else
+ b->type = bp_watchpoint;
+
+ loc_type = (b->type == bp_watchpoint? bp_loc_other
+ : bp_loc_hardware_watchpoint);
+ for (bl = b->loc; bl; bl = bl->next)
+ bl->loc_type = loc_type;
+ }
+ for (v = val_chain; v; v = next)
+ {
next = value_next (v);
if (v != b->val)
value_free (v);
}
else if (!within_current_scope)
{
- printf_filtered (_("Watchpoint %d deleted because "
- "the program has left the block\n"
- "in which its expression is valid.\n"),
+ printf_filtered (_("\
+Watchpoint %d deleted because the program has left the block\n\
+in which its expression is valid.\n"),
b->number);
- if (b->related_breakpoint)
- {
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->related_breakpoint->related_breakpoint = NULL;
- b->related_breakpoint= NULL;
- }
- b->disposition = disp_del_at_next_stop;
+ watchpoint_del_at_next_stop (b);
}
/* Restore the selected frame. */
memset (&bl->target_info, 0, sizeof (bl->target_info));
bl->target_info.placed_address = bl->address;
bl->target_info.placed_address_space = bl->pspace->aspace;
+ bl->target_info.length = bl->length;
if (bl->loc_type == bp_loc_software_breakpoint
|| bl->loc_type == bp_loc_hardware_breakpoint)
watchpoints. It's not clear that it's necessary... */
&& bl->owner->disposition != disp_del_at_next_stop)
{
- val = target_insert_watchpoint (bl->address,
- bl->length,
- bl->watchpoint_type,
- bl->owner->cond_exp);
+ gdb_assert (bl->owner->ops != NULL
+ && bl->owner->ops->insert_location != NULL);
+
+ val = bl->owner->ops->insert_location (bl);
/* If trying to set a read-watchpoint, and it turns out it's not
supported, try emulating one with an access watchpoint. */
if (val == 1)
{
- val = target_insert_watchpoint (bl->address,
- bl->length,
- hw_access,
- bl->owner->cond_exp);
- if (val == 0)
- bl->watchpoint_type = hw_access;
+ bl->watchpoint_type = hw_access;
+ val = bl->owner->ops->insert_location (bl);
+
+ if (val)
+ /* Back to the original value. */
+ bl->watchpoint_type = hw_read;
}
}
else if (bl->owner->type == bp_catchpoint)
{
- struct gdb_exception e = catch_exception (uiout, insert_catchpoint,
- bl->owner, RETURN_MASK_ERROR);
- exception_fprintf (gdb_stderr, e, "warning: inserting catchpoint %d: ",
- bl->owner->number);
- if (e.reason < 0)
- bl->owner->enable_state = bp_disabled;
- else
- bl->inserted = 1;
+ gdb_assert (bl->owner->ops != NULL
+ && bl->owner->ops->insert_location != NULL);
+
+ val = bl->owner->ops->insert_location (bl);
+ if (val)
+ {
+ bl->owner->enable_state = bp_disabled;
+
+ if (val == 1)
+ warning (_("\
+Error inserting catchpoint %d: Your system does not support this type\n\
+of catchpoint."), bl->owner->number);
+ else
+ warning (_("Error inserting catchpoint %d."), bl->owner->number);
+ }
+
+ bl->inserted = (val == 0);
/* We've already printed an error message if there was a problem
inserting this catchpoint, and we've disabled the catchpoint,
struct cleanup *old_chain;
struct bp_location *bl, **blp_tmp;
int val;
- struct ui_file *tmp_error_stream = mem_fileopen ();
+ struct ui_file *tmp_error_stream;
int dummy1 = 0, dummy2 = 0;
struct inferior *inf;
struct thread_info *tp;
inferior_ptid = tp->ptid;
+ tmp_error_stream = mem_fileopen ();
make_cleanup_ui_file_delete (tmp_error_stream);
ALL_BP_LOCATIONS (bl, blp_tmp)
return b;
}
+static const char *const longjmp_names[] =
+ {
+ "longjmp", "_longjmp", "siglongjmp", "_siglongjmp"
+ };
+#define NUM_LONGJMP_NAMES ARRAY_SIZE(longjmp_names)
+
+/* Per-objfile data private to breakpoint.c. */
+struct breakpoint_objfile_data
+{
+ /* Minimal symbol for "_ovly_debug_event" (if any). */
+ struct minimal_symbol *overlay_msym;
+
+ /* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any). */
+ struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES];
+
+ /* Minimal symbol for "std::terminate()" (if any). */
+ struct minimal_symbol *terminate_msym;
+
+ /* Minimal symbol for "_Unwind_DebugHook" (if any). */
+ struct minimal_symbol *exception_msym;
+};
+
+static const struct objfile_data *breakpoint_objfile_key;
+
+/* Minimal symbol not found sentinel. */
+static struct minimal_symbol msym_not_found;
+
+/* Returns TRUE if MSYM point to the "not found" sentinel. */
+
+static int
+msym_not_found_p (const struct minimal_symbol *msym)
+{
+ return msym == &msym_not_found;
+}
+
+/* Return per-objfile data needed by breakpoint.c.
+ Allocate the data if necessary. */
+
+static struct breakpoint_objfile_data *
+get_breakpoint_objfile_data (struct objfile *objfile)
+{
+ struct breakpoint_objfile_data *bp_objfile_data;
+
+ bp_objfile_data = objfile_data (objfile, breakpoint_objfile_key);
+ if (bp_objfile_data == NULL)
+ {
+ bp_objfile_data = obstack_alloc (&objfile->objfile_obstack,
+ sizeof (*bp_objfile_data));
+
+ memset (bp_objfile_data, 0, sizeof (*bp_objfile_data));
+ set_objfile_data (objfile, breakpoint_objfile_key, bp_objfile_data);
+ }
+ return bp_objfile_data;
+}
+
static void
-create_overlay_event_breakpoint (char *func_name)
+create_overlay_event_breakpoint (void)
{
struct objfile *objfile;
+ const char *const func_name = "_ovly_debug_event";
ALL_OBJFILES (objfile)
{
struct breakpoint *b;
- struct minimal_symbol *m;
+ struct breakpoint_objfile_data *bp_objfile_data;
+ CORE_ADDR addr;
- m = lookup_minimal_symbol_text (func_name, objfile);
- if (m == NULL)
- continue;
+ bp_objfile_data = get_breakpoint_objfile_data (objfile);
+
+ if (msym_not_found_p (bp_objfile_data->overlay_msym))
+ continue;
+
+ if (bp_objfile_data->overlay_msym == NULL)
+ {
+ struct minimal_symbol *m;
+
+ m = lookup_minimal_symbol_text (func_name, objfile);
+ if (m == NULL)
+ {
+ /* Avoid future lookups in this objfile. */
+ bp_objfile_data->overlay_msym = &msym_not_found;
+ continue;
+ }
+ bp_objfile_data->overlay_msym = m;
+ }
- b = create_internal_breakpoint (get_objfile_arch (objfile),
- SYMBOL_VALUE_ADDRESS (m),
+ addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->overlay_msym);
+ b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
bp_overlay_event);
b->addr_string = xstrdup (func_name);
}
static void
-create_longjmp_master_breakpoint (char *func_name)
+create_longjmp_master_breakpoint (void)
{
struct program_space *pspace;
- struct objfile *objfile;
struct cleanup *old_chain;
old_chain = save_current_program_space ();
ALL_PSPACES (pspace)
- ALL_OBJFILES (objfile)
+ {
+ struct objfile *objfile;
+
+ set_current_program_space (pspace);
+
+ ALL_OBJFILES (objfile)
{
- struct breakpoint *b;
- struct minimal_symbol *m;
+ int i;
+ struct gdbarch *gdbarch;
+ struct breakpoint_objfile_data *bp_objfile_data;
- if (!gdbarch_get_longjmp_target_p (get_objfile_arch (objfile)))
+ gdbarch = get_objfile_arch (objfile);
+ if (!gdbarch_get_longjmp_target_p (gdbarch))
continue;
- set_current_program_space (pspace);
+ bp_objfile_data = get_breakpoint_objfile_data (objfile);
- m = lookup_minimal_symbol_text (func_name, objfile);
- if (m == NULL)
- continue;
+ for (i = 0; i < NUM_LONGJMP_NAMES; i++)
+ {
+ struct breakpoint *b;
+ const char *func_name;
+ CORE_ADDR addr;
- b = create_internal_breakpoint (get_objfile_arch (objfile),
- SYMBOL_VALUE_ADDRESS (m),
- bp_longjmp_master);
- b->addr_string = xstrdup (func_name);
- b->enable_state = bp_disabled;
+ if (msym_not_found_p (bp_objfile_data->longjmp_msym[i]))
+ continue;
+
+ func_name = longjmp_names[i];
+ if (bp_objfile_data->longjmp_msym[i] == NULL)
+ {
+ struct minimal_symbol *m;
+
+ m = lookup_minimal_symbol_text (func_name, objfile);
+ if (m == NULL)
+ {
+ /* Prevent future lookups in this objfile. */
+ bp_objfile_data->longjmp_msym[i] = &msym_not_found;
+ continue;
+ }
+ bp_objfile_data->longjmp_msym[i] = m;
+ }
+
+ addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
+ b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master);
+ b->addr_string = xstrdup (func_name);
+ b->enable_state = bp_disabled;
+ }
}
+ }
update_global_location_list (1);
do_cleanups (old_chain);
}
-/* Create a master std::terminate breakpoint. The actual function
- looked for is named FUNC_NAME. */
+/* Create a master std::terminate breakpoint. */
static void
-create_std_terminate_master_breakpoint (const char *func_name)
+create_std_terminate_master_breakpoint (void)
{
struct program_space *pspace;
- struct objfile *objfile;
struct cleanup *old_chain;
+ const char *const func_name = "std::terminate()";
old_chain = save_current_program_space ();
ALL_PSPACES (pspace)
+ {
+ struct objfile *objfile;
+ CORE_ADDR addr;
+
+ set_current_program_space (pspace);
+
ALL_OBJFILES (objfile)
{
struct breakpoint *b;
- struct minimal_symbol *m;
+ struct breakpoint_objfile_data *bp_objfile_data;
- set_current_program_space (pspace);
+ bp_objfile_data = get_breakpoint_objfile_data (objfile);
- m = lookup_minimal_symbol (func_name, NULL, objfile);
- if (m == NULL || (MSYMBOL_TYPE (m) != mst_text
- && MSYMBOL_TYPE (m) != mst_file_text))
- continue;
+ if (msym_not_found_p (bp_objfile_data->terminate_msym))
+ continue;
- b = create_internal_breakpoint (get_objfile_arch (objfile),
- SYMBOL_VALUE_ADDRESS (m),
+ if (bp_objfile_data->terminate_msym == NULL)
+ {
+ struct minimal_symbol *m;
+
+ m = lookup_minimal_symbol (func_name, NULL, objfile);
+ if (m == NULL || (MSYMBOL_TYPE (m) != mst_text
+ && MSYMBOL_TYPE (m) != mst_file_text))
+ {
+ /* Prevent future lookups in this objfile. */
+ bp_objfile_data->terminate_msym = &msym_not_found;
+ continue;
+ }
+ bp_objfile_data->terminate_msym = m;
+ }
+
+ addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->terminate_msym);
+ b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
bp_std_terminate_master);
b->addr_string = xstrdup (func_name);
b->enable_state = bp_disabled;
}
+ }
+
update_global_location_list (1);
do_cleanups (old_chain);
create_exception_master_breakpoint (void)
{
struct objfile *objfile;
+ const char *const func_name = "_Unwind_DebugHook";
ALL_OBJFILES (objfile)
{
- struct minimal_symbol *debug_hook;
+ struct breakpoint *b;
+ struct gdbarch *gdbarch;
+ struct breakpoint_objfile_data *bp_objfile_data;
+ CORE_ADDR addr;
+
+ bp_objfile_data = get_breakpoint_objfile_data (objfile);
+
+ if (msym_not_found_p (bp_objfile_data->exception_msym))
+ continue;
- debug_hook = lookup_minimal_symbol ("_Unwind_DebugHook", NULL, objfile);
- if (debug_hook != NULL)
+ gdbarch = get_objfile_arch (objfile);
+
+ if (bp_objfile_data->exception_msym == NULL)
{
- struct breakpoint *b;
- CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (debug_hook);
- struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ struct minimal_symbol *debug_hook;
- addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
- ¤t_target);
- b = create_internal_breakpoint (gdbarch, addr, bp_exception_master);
- b->addr_string = xstrdup ("_Unwind_DebugHook");
- b->enable_state = bp_disabled;
+ debug_hook = lookup_minimal_symbol (func_name, NULL, objfile);
+ if (debug_hook == NULL)
+ {
+ bp_objfile_data->exception_msym = &msym_not_found;
+ continue;
+ }
+
+ bp_objfile_data->exception_msym = debug_hook;
}
+
+ addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->exception_msym);
+ addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
+ ¤t_target);
+ b = create_internal_breakpoint (gdbarch, addr, bp_exception_master);
+ b->addr_string = xstrdup (func_name);
+ b->enable_state = bp_disabled;
}
update_global_location_list (1);
}
}
/* FIXME what about longjmp breakpoints? Re-create them here? */
- create_overlay_event_breakpoint ("_ovly_debug_event");
- create_longjmp_master_breakpoint ("longjmp");
- create_longjmp_master_breakpoint ("_longjmp");
- create_longjmp_master_breakpoint ("siglongjmp");
- create_longjmp_master_breakpoint ("_siglongjmp");
- create_std_terminate_master_breakpoint ("std::terminate()");
+ create_overlay_event_breakpoint ();
+ create_longjmp_master_breakpoint ();
+ create_std_terminate_master_breakpoint ();
create_exception_master_breakpoint ();
}
}
else if (bl->loc_type == bp_loc_hardware_watchpoint)
{
+ gdb_assert (bl->owner->ops != NULL
+ && bl->owner->ops->remove_location != NULL);
+
bl->inserted = (is == mark_inserted);
- val = target_remove_watchpoint (bl->address, bl->length,
- bl->watchpoint_type,
- bl->owner->cond_exp);
+ bl->owner->ops->remove_location (bl);
/* Failure to remove any of the hardware watchpoints comes here. */
if ((is == mark_uninserted) && (bl->inserted))
&& breakpoint_enabled (bl->owner)
&& !bl->duplicate)
{
- gdb_assert (bl->owner->ops != NULL && bl->owner->ops->remove != NULL);
+ gdb_assert (bl->owner->ops != NULL
+ && bl->owner->ops->remove_location != NULL);
- val = bl->owner->ops->remove (bl->owner);
+ val = bl->owner->ops->remove_location (bl);
if (val)
return val;
+
bl->inserted = (is == mark_inserted);
}
&& bl->loc_type != bp_loc_hardware_breakpoint)
continue;
- /* ALL_BP_LOCATIONS bp_location has bl->OWNER always non-NULL. */
+ /* ALL_BP_LOCATIONS bp_location has BL->OWNER always non-NULL. */
if ((breakpoint_enabled (bl->owner)
|| bl->owner->enable_state == bp_permanent)
- && breakpoint_address_match (bl->pspace->aspace, bl->address,
- aspace, pc))
+ && breakpoint_location_address_match (bl, aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bl->section)
int ix;
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
- if (breakpoint_address_match (loc->pspace->aspace, loc->address,
- aspace, pc))
+ if (breakpoint_location_address_match (loc, aspace, pc))
return 1;
return 0;
continue;
if (bl->inserted
- && breakpoint_address_match (bl->pspace->aspace, bl->address,
- aspace, pc))
+ && breakpoint_location_address_match (bl, aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bl->section)
&& bl->owner->enable_state != bp_permanent)
continue;
- if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
- aspace, pc))
+ if (!breakpoint_location_address_match (bl, aspace, pc))
continue;
if (bl->owner->thread != -1)
int bp_temp = 0;
enum print_stop_action result;
- /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
- which has since been deleted. */
- if (bs->breakpoint_at == NULL)
- return PRINT_UNKNOWN;
-
gdb_assert (bs->bp_location_at != NULL);
bl = bs->bp_location_at;
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_jit_event:
+ case bp_gnu_ifunc_resolver:
+ case bp_gnu_ifunc_resolver_return:
default:
result = PRINT_UNKNOWN;
break;
{
struct breakpoint *b = bs->breakpoint_at;
+ /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
+ which has since been deleted. */
+ if (b == NULL)
+ return PRINT_UNKNOWN;
+
/* Normal case. Call the breakpoint's print_it method, or
print_it_typical. */
- /* FIXME: how breakpoint can ever be NULL here? */
- if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
+ if (b->ops != NULL && b->ops->print_it != NULL)
return b->ops->print_it (b);
else
return print_it_typical (bs);
gdb_assert (bs->breakpoint_at != NULL);
b = bs->breakpoint_at;
+ gdb_assert (is_watchpoint (b));
+
/* If this is a local watchpoint, we only want to check if the
watchpoint frame is in scope if the current thread is the thread
that was used to create the watchpoint. */
" deleted because the program has left the block in\n\
which its expression is valid.\n");
- if (b->related_breakpoint)
- {
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->related_breakpoint->related_breakpoint = NULL;
- b->related_breakpoint = NULL;
- }
- b->disposition = disp_del_at_next_stop;
+ watchpoint_del_at_next_stop (b);
return WP_DELETED;
}
/* BL is from existing struct breakpoint. */
gdb_assert (b != NULL);
+ if (b->ops && b->ops->breakpoint_hit)
+ return b->ops->breakpoint_hit (bl, aspace, bp_addr);
+
/* By definition, the inferior does not report stops at
tracepoints. */
if (is_tracepoint (b))
if (is_hardware_watchpoint (b)
&& b->watchpoint_triggered == watch_triggered_no)
return 0;
-
+
if (b->type == bp_hardware_breakpoint)
{
if (bl->address != bp_addr)
return 0;
}
- if (b->type == bp_catchpoint)
- {
- gdb_assert (b->ops != NULL && b->ops->breakpoint_hit != NULL);
- if (!b->ops->breakpoint_hit (b))
- return 0;
- }
-
return 1;
}
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;
+ watchpoint_del_at_next_stop (b);
/* We've already printed what needs to be printed. */
bs->print_it = print_it_done;
break;
int value_is_zero = 0;
struct expression *cond;
+ /* Evaluate Python breakpoints that have a "stop"
+ method implemented. */
+ if (b->py_bp_object)
+ bs->stop = gdbpy_should_stop (b->py_bp_object);
+
if (is_watchpoint (b))
cond = b->cond_exp;
else
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)
+ if (b->type == bp_watchpoint_scope && b->related_breakpoint != b)
b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
}
}
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
{
- if (breakpoint_address_match (loc->pspace->aspace, loc->address,
- aspace, bp_addr))
+ if (breakpoint_location_address_match (loc, aspace, bp_addr))
{
bs = bpstat_alloc (loc, &bs_link);
/* For hits of moribund locations, we should just proceed. */
/* Decide what infrun needs to do with this bpstat. */
struct bpstat_what
-bpstat_what (bpstat bs)
+bpstat_what (bpstat bs_head)
{
struct bpstat_what retval;
/* We need to defer calling `solib_add', as adding new symbols
and hence may clear unprocessed entries in the BS chain. */
int shlib_event = 0;
int jit_event = 0;
+ bpstat bs;
retval.main_action = BPSTAT_WHAT_KEEP_CHECKING;
retval.call_dummy = STOP_NONE;
retval.is_longjmp = 0;
- for (; bs != NULL; bs = bs->next)
+ for (bs = bs_head; bs != NULL; bs = bs->next)
{
/* Extract this BS's action. After processing each BS, we check
if its action overrides all we've seem so far. */
out already. */
internal_error (__FILE__, __LINE__,
_("bpstat_what: tracepoint encountered"));
+ break;
+ case bp_gnu_ifunc_resolver:
+ /* Step over it (and insert bp_gnu_ifunc_resolver_return). */
+ this_action = BPSTAT_WHAT_SINGLE;
+ break;
+ case bp_gnu_ifunc_resolver_return:
+ /* The breakpoint will be removed, execution will restart from the
+ PC of the former breakpoint. */
+ this_action = BPSTAT_WHAT_KEEP_CHECKING;
+ break;
default:
internal_error (__FILE__, __LINE__,
_("bpstat_what: unhandled bptype %d"), (int) bptype);
retval.main_action = max (retval.main_action, this_action);
}
+ /* These operations may affect the bs->breakpoint_at state so they are
+ delayed after MAIN_ACTION is decided above. */
+
if (shlib_event)
{
if (debug_infrun)
handle_jit_event ();
}
- return retval;
-}
+ for (bs = bs_head; bs != NULL; bs = bs->next)
+ {
+ struct breakpoint *b = bs->breakpoint_at;
-/* Nonzero if we should step constantly (e.g. watchpoints on machines
- without hardware support). This isn't related to a specific bpstat,
- just to things like whether watchpoints are set. */
+ if (b == NULL)
+ continue;
+ switch (b->type)
+ {
+ case bp_gnu_ifunc_resolver:
+ gnu_ifunc_resolver_stop (b);
+ break;
+ case bp_gnu_ifunc_resolver_return:
+ gnu_ifunc_resolver_return_stop (b);
+ break;
+ }
+ }
+
+ return retval;
+}
+
+/* Nonzero if we should step constantly (e.g. watchpoints on machines
+ without hardware support). This isn't related to a specific bpstat,
+ just to things like whether watchpoints are set. */
int
bpstat_should_step (void)
\f
+/* Compute a string of spaces suitable to indent the next line
+ so it starts at the position corresponding to the table column
+ named COL_NAME in the currently active table of UIOUT. */
+
+static char *
+wrap_indent_at_field (struct ui_out *uiout, const char *col_name)
+{
+ static char wrap_indent[80];
+ int i, total_width, width, align;
+ char *text;
+
+ total_width = 0;
+ for (i = 1; ui_out_query_field (uiout, i, &width, &align, &text); i++)
+ {
+ if (strcmp (text, col_name) == 0)
+ {
+ gdb_assert (total_width < sizeof wrap_indent);
+ memset (wrap_indent, ' ', total_width);
+ wrap_indent[total_width] = 0;
+
+ return wrap_indent;
+ }
+
+ total_width += width + 1;
+ }
+
+ return NULL;
+}
+
/* Print the LOC location out of the list of B->LOC locations. */
-static void print_breakpoint_location (struct breakpoint *b,
- struct bp_location *loc,
- char *wrap_indent,
- struct ui_stream *stb)
+static void
+print_breakpoint_location (struct breakpoint *b,
+ struct bp_location *loc)
{
struct cleanup *old_chain = save_current_program_space ();
if (loc != NULL)
set_current_program_space (loc->pspace);
- if (b->source_file && loc)
+ if (b->display_canonical)
+ ui_out_field_string (uiout, "what", b->addr_string);
+ else if (b->source_file && loc)
{
struct symbol *sym
= find_pc_sect_function (loc->address, loc->section);
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_text (uiout, " ");
+ ui_out_wrap_hint (uiout, wrap_indent_at_field (uiout, "what"));
+ ui_out_text (uiout, "at ");
}
ui_out_field_string (uiout, "file", b->source_file);
ui_out_text (uiout, ":");
}
else if (loc)
{
+ struct ui_stream *stb = ui_out_stream_new (uiout);
+ struct cleanup *stb_chain = make_cleanup_ui_out_stream_delete (stb);
+
print_address_symbolic (loc->gdbarch, loc->address, stb->stream,
demangle, "");
ui_out_field_stream (uiout, "at", stb);
+
+ do_cleanups (stb_chain);
}
else
ui_out_field_string (uiout, "pending", b->addr_string);
{bp_fast_tracepoint, "fast tracepoint"},
{bp_static_tracepoint, "static tracepoint"},
{bp_jit_event, "jit events"},
+ {bp_gnu_ifunc_resolver, "STT_GNU_IFUNC resolver"},
+ {bp_gnu_ifunc_resolver_return, "STT_GNU_IFUNC resolver return"},
};
if (((int) type >= (sizeof (bptypes) / sizeof (bptypes[0])))
struct bp_location *loc,
int loc_number,
struct bp_location **last_loc,
- int print_address_bits,
int allflag)
{
struct command_line *l;
static char bpenables[] = "nynny";
- char wrap_indent[80];
- struct ui_stream *stb = ui_out_stream_new (uiout);
- struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
struct cleanup *bkpt_chain;
int header_of_multiple = 0;
/* 5 and 6 */
- strcpy (wrap_indent, " ");
- if (opts.addressprint)
- {
- if (print_address_bits <= 32)
- strcat (wrap_indent, " ");
- else
- strcat (wrap_indent, " ");
- }
-
if (b->ops != NULL && b->ops->print_one != NULL)
{
/* Although the print_one can possibly print all locations,
case bp_fast_tracepoint:
case bp_static_tracepoint:
case bp_jit_event:
+ case bp_gnu_ifunc_resolver:
+ case bp_gnu_ifunc_resolver_return:
if (opts.addressprint)
{
annotate_field (4);
}
annotate_field (5);
if (!header_of_multiple)
- print_breakpoint_location (b, loc, wrap_indent, stb);
+ print_breakpoint_location (b, loc);
if (b->loc)
*last_loc = b->loc;
break;
ui_out_field_int (uiout, "task", b->task);
}
}
-
+
ui_out_text (uiout, "\n");
-
+
+ if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+ b->ops->print_one_detail (b, uiout);
+
if (!part_of_multiple && b->static_trace_marker_id)
{
gdb_assert (b->type == bp_static_tracepoint);
}
do_cleanups (bkpt_chain);
- do_cleanups (old_chain);
}
static void
print_one_breakpoint (struct breakpoint *b,
struct bp_location **last_loc,
- int print_address_bits,
int allflag)
{
- print_one_breakpoint_location (b, NULL, 0, last_loc,
- print_address_bits, allflag);
+ print_one_breakpoint_location (b, NULL, 0, last_loc, allflag);
/* If this breakpoint has custom print function,
it's already printed. Otherwise, print individual
situation.
Note that while hardware watchpoints have several locations
- internally, that's no a property exposed to user. */
+ internally, that's not a property exposed to user. */
if (b->loc
&& !is_hardware_watchpoint (b)
&& (b->loc->next || !b->loc->enabled)
struct bp_location *loc;
int n = 1;
for (loc = b->loc; loc; loc = loc->next, ++n)
- print_one_breakpoint_location (b, loc, n, last_loc,
- print_address_bits, allflag);
+ print_one_breakpoint_location (b, loc, n, last_loc, allflag);
}
}
}
{
if (args->bnum == b->number)
{
- int print_address_bits = breakpoint_address_bits (b);
-
- print_one_breakpoint (b, &dummy_loc, print_address_bits, 0);
+ print_one_breakpoint (b, &dummy_loc, 0);
return GDB_RC_OK;
}
}
|| b->type == bp_catchpoint
|| b->type == bp_hardware_breakpoint
|| is_tracepoint (b)
- || is_watchpoint (b));
+ || is_watchpoint (b)
+ || b->type == bp_gnu_ifunc_resolver);
+}
+
+/* Return true if this breakpoint was set by the user, false if it is
+ internal or momentary. */
+
+int
+user_breakpoint_p (struct breakpoint *b)
+{
+ return user_settable_breakpoint (b) && b->number > 0;
}
/* Print information on user settable breakpoint (watchpoint, etc)
breakpoints listed. */
static int
-breakpoint_1 (int bnum, int allflag,
+breakpoint_1 (char *args, int allflag,
int (*filter) (const struct breakpoint *))
{
struct breakpoint *b;
required for address fields. */
nr_printable_breakpoints = 0;
ALL_BREAKPOINTS (b)
- if (bnum == -1
- || bnum == b->number)
- {
- /* If we have a filter, only list the breakpoints it accepts. */
- if (filter && !filter (b))
- continue;
-
- if (allflag || (user_settable_breakpoint (b)
- && b->number > 0))
- {
- int addr_bit, type_len;
+ {
+ /* If we have a filter, only list the breakpoints it accepts. */
+ if (filter && !filter (b))
+ continue;
- addr_bit = breakpoint_address_bits (b);
- if (addr_bit > print_address_bits)
- print_address_bits = addr_bit;
+ /* If we have an "args" string, it is a list of breakpoints to
+ accept. Skip the others. */
+ if (args != NULL && *args != '\0')
+ {
+ if (allflag && parse_and_eval_long (args) != b->number)
+ continue;
+ if (!allflag && !number_is_in_list (args, b->number))
+ continue;
+ }
- type_len = strlen (bptype_string (b->type));
- if (type_len > print_type_col_width)
- print_type_col_width = type_len;
+ if (allflag || user_breakpoint_p (b))
+ {
+ int addr_bit, type_len;
- nr_printable_breakpoints++;
- }
- }
+ addr_bit = breakpoint_address_bits (b);
+ if (addr_bit > print_address_bits)
+ print_address_bits = addr_bit;
+
+ type_len = strlen (bptype_string (b->type));
+ if (type_len > print_type_col_width)
+ print_type_col_width = type_len;
+
+ nr_printable_breakpoints++;
+ }
+ }
if (opts.addressprint)
bkpttbl_chain
annotate_field (3);
ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb"); /* 4 */
if (opts.addressprint)
- {
- if (nr_printable_breakpoints > 0)
- annotate_field (4);
- if (print_address_bits <= 32)
- ui_out_table_header (uiout, 10, ui_left,
- "addr", "Address"); /* 5 */
- else
- ui_out_table_header (uiout, 18, ui_left,
- "addr", "Address"); /* 5 */
- }
+ {
+ if (nr_printable_breakpoints > 0)
+ annotate_field (4);
+ if (print_address_bits <= 32)
+ ui_out_table_header (uiout, 10, ui_left,
+ "addr", "Address"); /* 5 */
+ else
+ ui_out_table_header (uiout, 18, ui_left,
+ "addr", "Address"); /* 5 */
+ }
if (nr_printable_breakpoints > 0)
annotate_field (5);
ui_out_table_header (uiout, 40, ui_noalign, "what", "What"); /* 6 */
annotate_breakpoints_table ();
ALL_BREAKPOINTS (b)
- {
- QUIT;
- if (bnum == -1
- || bnum == b->number)
- {
- /* If we have a filter, only list the breakpoints it accepts. */
- if (filter && !filter (b))
- continue;
-
- /* We only print out user settable breakpoints unless the
- allflag is set. */
- if (allflag || (user_settable_breakpoint (b)
- && b->number > 0))
- print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
- }
- }
-
+ {
+ QUIT;
+ /* If we have a filter, only list the breakpoints it accepts. */
+ if (filter && !filter (b))
+ continue;
+
+ /* If we have an "args" string, it is a list of breakpoints to
+ accept. Skip the others. */
+
+ if (args != NULL && *args != '\0')
+ {
+ if (allflag) /* maintenance info breakpoint */
+ {
+ if (parse_and_eval_long (args) != b->number)
+ continue;
+ }
+ else /* all others */
+ {
+ if (!number_is_in_list (args, b->number))
+ continue;
+ }
+ }
+ /* We only print out user settable breakpoints unless the
+ allflag is set. */
+ if (allflag || user_breakpoint_p (b))
+ print_one_breakpoint (b, &last_loc, allflag);
+ }
+
do_cleanups (bkpttbl_chain);
if (nr_printable_breakpoints == 0)
empty list. */
if (!filter)
{
- if (bnum == -1)
+ if (args == NULL || *args == '\0')
ui_out_message (uiout, 0, "No breakpoints or watchpoints.\n");
else
ui_out_message (uiout, 0,
- "No breakpoint or watchpoint number %d.\n",
- bnum);
+ "No breakpoint or watchpoint matching '%s'.\n",
+ args);
}
}
else
}
static void
-breakpoints_info (char *bnum_exp, int from_tty)
+breakpoints_info (char *args, int from_tty)
{
- int bnum = -1;
-
- if (bnum_exp)
- bnum = parse_and_eval_long (bnum_exp);
-
- breakpoint_1 (bnum, 0, NULL);
+ breakpoint_1 (args, 0, NULL);
default_collect_info ();
}
static void
-watchpoints_info (char *wpnum_exp, int from_tty)
+watchpoints_info (char *args, int from_tty)
{
- int wpnum = -1, num_printed;
-
- if (wpnum_exp)
- wpnum = parse_and_eval_long (wpnum_exp);
-
- num_printed = breakpoint_1 (wpnum, 0, is_watchpoint);
+ int num_printed = breakpoint_1 (args, 0, is_watchpoint);
if (num_printed == 0)
{
- if (wpnum == -1)
+ if (args == NULL || *args == '\0')
ui_out_message (uiout, 0, "No watchpoints.\n");
else
- ui_out_message (uiout, 0, "No watchpoint number %d.\n", wpnum);
+ ui_out_message (uiout, 0, "No watchpoint matching '%s'.\n", args);
}
}
static void
-maintenance_info_breakpoints (char *bnum_exp, int from_tty)
+maintenance_info_breakpoints (char *args, int from_tty)
{
- int bnum = -1;
-
- if (bnum_exp)
- bnum = parse_and_eval_long (bnum_exp);
-
- breakpoint_1 (bnum, 1, NULL);
+ breakpoint_1 (args, 1, NULL);
default_collect_info ();
}
&& addr1 == addr2);
}
+/* Returns true if {ASPACE2,ADDR2} falls within the range determined by
+ {ASPACE1,ADDR1,LEN1}. In most targets, this can only be true if ASPACE1
+ matches ASPACE2. On targets that have global breakpoints, the address
+ space doesn't really matter. */
+
+static int
+breakpoint_address_match_range (struct address_space *aspace1, CORE_ADDR addr1,
+ int len1, struct address_space *aspace2,
+ CORE_ADDR addr2)
+{
+ return ((gdbarch_has_global_breakpoints (target_gdbarch)
+ || aspace1 == aspace2)
+ && addr2 >= addr1 && addr2 < addr1 + len1);
+}
+
+/* Returns true if {ASPACE,ADDR} matches the 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_match (struct bp_location *bl,
+ struct address_space *aspace,
+ CORE_ADDR addr)
+{
+ return (breakpoint_address_match (bl->pspace->aspace, bl->address,
+ aspace, addr)
+ || (bl->length
+ && breakpoint_address_match_range (bl->pspace->aspace,
+ bl->address, bl->length,
+ aspace, addr)));
+}
+
/* Assuming LOC1 and LOC2's types' have meaningful target addresses
(breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
represent the same location. */
else if (hw_point1)
return watchpoint_locations_match (loc1, loc2);
else
- return breakpoint_address_match (loc1->pspace->aspace, loc1->address,
- loc2->pspace->aspace, loc2->address);
+ /* We compare bp_location.length in order to cover ranged breakpoints. */
+ return (breakpoint_address_match (loc1->pspace->aspace, loc1->address,
+ loc2->pspace->aspace, loc2->address)
+ && loc1->length == loc2->length);
}
static void
breakpoint_adjustment_warning (CORE_ADDR from_addr, CORE_ADDR to_addr,
int bnum, int have_bnum)
{
- char astr1[40];
- char astr2[40];
+ /* The longest string possibly returned by hex_string_custom
+ is 50 chars. These must be at least that big for safety. */
+ char astr1[64];
+ char astr2[64];
strcpy (astr1, hex_string_custom ((unsigned long) from_addr, 8));
strcpy (astr2, hex_string_custom ((unsigned long) to_addr, 8));
case bp_longjmp_master:
case bp_std_terminate_master:
case bp_exception_master:
+ case bp_gnu_ifunc_resolver:
+ case bp_gnu_ifunc_resolver_return:
loc->loc_type = bp_loc_software_breakpoint;
break;
case bp_hardware_breakpoint:
b->ops = NULL;
b->condition_not_parsed = 0;
b->py_bp_object = NULL;
+ b->related_breakpoint = b;
/* Add this breakpoint to the end of the chain so that a list of
breakpoints will come out in order of increasing numbers. */
return b;
}
-/* Initialize loc->function_name. */
+/* Initialize loc->function_name. EXPLICIT_LOC says no indirect function
+ resolutions should be made as the user specified the location explicitly
+ enough. */
+
static void
-set_breakpoint_location_function (struct bp_location *loc)
+set_breakpoint_location_function (struct bp_location *loc, int explicit_loc)
{
gdb_assert (loc->owner != NULL);
|| loc->owner->type == bp_hardware_breakpoint
|| is_tracepoint (loc->owner))
{
- find_pc_partial_function (loc->address, &(loc->function_name),
- NULL, NULL);
+ int is_gnu_ifunc;
+
+ find_pc_partial_function_gnu_ifunc (loc->address, &loc->function_name,
+ NULL, NULL, &is_gnu_ifunc);
+
+ if (is_gnu_ifunc && !explicit_loc)
+ {
+ struct breakpoint *b = loc->owner;
+
+ gdb_assert (loc->pspace == current_program_space);
+ if (gnu_ifunc_resolve_name (loc->function_name,
+ &loc->requested_address))
+ {
+ /* Recalculate ADDRESS based on new REQUESTED_ADDRESS. */
+ loc->address = adjust_breakpoint_address (loc->gdbarch,
+ loc->requested_address,
+ b->type);
+ }
+ else if (b->type == bp_breakpoint && b->loc == loc
+ && loc->next == NULL && b->related_breakpoint == b)
+ {
+ /* Create only the whole new breakpoint of this type but do not
+ mess more complicated breakpoints with multiple locations. */
+ b->type = bp_gnu_ifunc_resolver;
+ }
+ }
+
if (loc->function_name)
loc->function_name = xstrdup (loc->function_name);
}
b->loc->section = sal.section;
b->line_number = sal.line;
- set_breakpoint_location_function (b->loc);
+ set_breakpoint_location_function (b->loc,
+ sal.explicit_pc || sal.explicit_line);
breakpoints_changed ();
delete_breakpoint (b);
}
-struct captured_parse_breakpoint_args
- {
- char **arg_p;
- struct symtabs_and_lines *sals_p;
- char ***addr_string_p;
- int *not_found_ptr;
- };
-
struct lang_and_radix
{
enum language lang;
return b;
}
+/* Remove JIT code registration and unregistration breakpoint(s). */
+
+void
+remove_jit_event_breakpoints (void)
+{
+ struct breakpoint *b, *b_tmp;
+
+ ALL_BREAKPOINTS_SAFE (b, b_tmp)
+ if (b->type == bp_jit_event
+ && b->loc->pspace == current_program_space)
+ delete_breakpoint (b);
+}
+
void
remove_solib_event_breakpoints (void)
{
}
}
-/* Disable any breakpoints that are in in an unloaded shared library.
+/* Disable any breakpoints that are in an unloaded shared library.
Only apply to enabled breakpoints, disabled ones can just stay
disabled. */
/* Implement the "insert" breakpoint_ops method for fork
catchpoints. */
-static void
-insert_catch_fork (struct breakpoint *b)
+static int
+insert_catch_fork (struct bp_location *bl)
{
- target_insert_fork_catchpoint (PIDGET (inferior_ptid));
+ return target_insert_fork_catchpoint (PIDGET (inferior_ptid));
}
/* Implement the "remove" breakpoint_ops method for fork
catchpoints. */
static int
-remove_catch_fork (struct breakpoint *b)
+remove_catch_fork (struct bp_location *bl)
{
return target_remove_fork_catchpoint (PIDGET (inferior_ptid));
}
catchpoints. */
static int
-breakpoint_hit_catch_fork (struct breakpoint *b)
+breakpoint_hit_catch_fork (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
- return inferior_has_forked (inferior_ptid, &b->forked_inferior_pid);
+ return inferior_has_forked (inferior_ptid, &bl->owner->forked_inferior_pid);
}
/* Implement the "print_it" breakpoint_ops method for fork
insert_catch_fork,
remove_catch_fork,
breakpoint_hit_catch_fork,
+ NULL, /* resources_needed */
print_it_catch_fork,
print_one_catch_fork,
+ NULL, /* print_one_detail */
print_mention_catch_fork,
print_recreate_catch_fork
};
/* Implement the "insert" breakpoint_ops method for vfork
catchpoints. */
-static void
-insert_catch_vfork (struct breakpoint *b)
+static int
+insert_catch_vfork (struct bp_location *bl)
{
- target_insert_vfork_catchpoint (PIDGET (inferior_ptid));
+ return target_insert_vfork_catchpoint (PIDGET (inferior_ptid));
}
/* Implement the "remove" breakpoint_ops method for vfork
catchpoints. */
static int
-remove_catch_vfork (struct breakpoint *b)
+remove_catch_vfork (struct bp_location *bl)
{
return target_remove_vfork_catchpoint (PIDGET (inferior_ptid));
}
catchpoints. */
static int
-breakpoint_hit_catch_vfork (struct breakpoint *b)
+breakpoint_hit_catch_vfork (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
- return inferior_has_vforked (inferior_ptid, &b->forked_inferior_pid);
+ return inferior_has_vforked (inferior_ptid, &bl->owner->forked_inferior_pid);
}
/* Implement the "print_it" breakpoint_ops method for vfork
insert_catch_vfork,
remove_catch_vfork,
breakpoint_hit_catch_vfork,
+ NULL, /* resources_needed */
print_it_catch_vfork,
print_one_catch_vfork,
+ NULL, /* print_one_detail */
print_mention_catch_vfork,
print_recreate_catch_vfork
};
/* Implement the "insert" breakpoint_ops method for syscall
catchpoints. */
-static void
-insert_catch_syscall (struct breakpoint *b)
+static int
+insert_catch_syscall (struct bp_location *bl)
{
struct inferior *inf = current_inferior ();
++inf->total_syscalls_count;
- if (!b->syscalls_to_be_caught)
+ if (!bl->owner->syscalls_to_be_caught)
++inf->any_syscall_count;
else
{
int i, iter;
for (i = 0;
- VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ VEC_iterate (int, bl->owner->syscalls_to_be_caught, i, iter);
i++)
{
int elem;
}
}
- target_set_syscall_catchpoint (PIDGET (inferior_ptid),
- inf->total_syscalls_count != 0,
- inf->any_syscall_count,
- VEC_length (int, inf->syscalls_counts),
- VEC_address (int, inf->syscalls_counts));
+ return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ inf->total_syscalls_count != 0,
+ inf->any_syscall_count,
+ VEC_length (int, inf->syscalls_counts),
+ VEC_address (int, inf->syscalls_counts));
}
/* Implement the "remove" breakpoint_ops method for syscall
catchpoints. */
static int
-remove_catch_syscall (struct breakpoint *b)
+remove_catch_syscall (struct bp_location *bl)
{
struct inferior *inf = current_inferior ();
--inf->total_syscalls_count;
- if (!b->syscalls_to_be_caught)
+ if (!bl->owner->syscalls_to_be_caught)
--inf->any_syscall_count;
else
{
int i, iter;
for (i = 0;
- VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ VEC_iterate (int, bl->owner->syscalls_to_be_caught, i, iter);
i++)
{
int elem;
catchpoints. */
static int
-breakpoint_hit_catch_syscall (struct breakpoint *b)
+breakpoint_hit_catch_syscall (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
/* We must check if we are catching specific syscalls in this
breakpoint. If we are, then we must guarantee that the called
syscall is the same syscall we are catching. */
int syscall_number = 0;
+ const struct breakpoint *b = bl->owner;
if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
return 0;
static void
print_one_catch_syscall (struct breakpoint *b,
- struct bp_location **last_loc)
+ struct bp_location **last_loc)
{
struct value_print_options opts;
insert_catch_syscall,
remove_catch_syscall,
breakpoint_hit_catch_syscall,
+ NULL, /* resources_needed */
print_it_catch_syscall,
print_one_catch_syscall,
+ NULL, /* print_one_detail */
print_mention_catch_syscall,
print_recreate_catch_syscall
};
/* Exec catchpoints. */
-static void
-insert_catch_exec (struct breakpoint *b)
+static int
+insert_catch_exec (struct bp_location *bl)
{
- target_insert_exec_catchpoint (PIDGET (inferior_ptid));
+ return target_insert_exec_catchpoint (PIDGET (inferior_ptid));
}
static int
-remove_catch_exec (struct breakpoint *b)
+remove_catch_exec (struct bp_location *bl)
{
return target_remove_exec_catchpoint (PIDGET (inferior_ptid));
}
static int
-breakpoint_hit_catch_exec (struct breakpoint *b)
+breakpoint_hit_catch_exec (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
- return inferior_has_execd (inferior_ptid, &b->exec_pathname);
+ return inferior_has_execd (inferior_ptid, &bl->owner->exec_pathname);
}
static enum print_stop_action
insert_catch_exec,
remove_catch_exec,
breakpoint_hit_catch_exec,
+ NULL, /* resources_needed */
print_it_catch_exec,
print_one_catch_exec,
+ NULL, /* print_one_detail */
print_mention_catch_exec,
print_recreate_catch_exec
};
static int
hw_breakpoint_used_count (void)
{
- struct breakpoint *b;
int i = 0;
+ struct breakpoint *b;
+ struct bp_location *bl;
ALL_BREAKPOINTS (b)
{
if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b))
- i++;
+ for (bl = b->loc; bl; bl = bl->next)
+ {
+ /* Special types of hardware breakpoints may use more than
+ one register. */
+ if (b->ops && b->ops->resources_needed)
+ i += b->ops->resources_needed (bl);
+ else
+ i++;
+ }
}
return i;
static int
hw_watchpoint_used_count (enum bptype type, int *other_type_used)
{
- struct breakpoint *b;
int i = 0;
+ struct breakpoint *b;
+ struct bp_location *bl;
*other_type_used = 0;
ALL_BREAKPOINTS (b)
- {
- if (breakpoint_enabled (b))
- {
+ {
+ if (!breakpoint_enabled (b))
+ continue;
+
if (b->type == type)
- i++;
+ for (bl = b->loc; bl; bl = bl->next)
+ {
+ /* Special types of hardware watchpoints may use more than
+ one register. */
+ if (b->ops && b->ops->resources_needed)
+ i += b->ops->resources_needed (bl);
+ else
+ i++;
+ }
else if (is_hardware_watchpoint (b))
*other_type_used = 1;
- }
- }
+ }
+
return i;
}
copy = set_raw_breakpoint_without_location (orig->gdbarch, orig->type);
copy->loc = allocate_bp_location (copy);
- set_breakpoint_location_function (copy->loc);
+ set_breakpoint_location_function (copy->loc, 1);
copy->loc->gdbarch = orig->loc->gdbarch;
copy->loc->requested_address = orig->loc->requested_address;
do_cleanups (ui_out_chain);
break;
case bp_breakpoint:
+ case bp_gnu_ifunc_resolver:
if (ui_out_is_mi_like_p (uiout))
{
say_where = 0;
else
printf_filtered (_("Breakpoint"));
printf_filtered (_(" %d"), b->number);
+ if (b->type == bp_gnu_ifunc_resolver)
+ printf_filtered (_(" at gnu-indirect-function resolver"));
say_where = 1;
break;
case bp_hardware_breakpoint:
case bp_longjmp_master:
case bp_std_terminate_master:
case bp_exception_master:
+ case bp_gnu_ifunc_resolver_return:
break;
}
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
- set_breakpoint_location_function (loc);
+ set_breakpoint_location_function (loc,
+ sal->explicit_pc || sal->explicit_line);
return loc;
}
\f
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
struct breakpoint_ops *ops, int from_tty,
- int enabled, int internal)
+ int enabled, int internal, int display_canonical)
{
struct breakpoint *b = NULL;
int i;
char *marker_str;
int i;
- while (*p == ' ' || *p == '\t')
- p++;
+ p = skip_spaces (p);
- endp = p;
- while (*endp != ' ' && *endp != '\t' && *endp != '\0')
- endp++;
+ endp = skip_to_space (p);
marker_str = savestring (p, endp - p);
b->static_trace_marker_id = marker_str;
}
}
+ b->display_canonical = display_canonical;
if (addr_string)
b->addr_string = addr_string;
else
static void
create_breakpoints_sal (struct gdbarch *gdbarch,
- struct symtabs_and_lines sals, char **addr_string,
+ struct symtabs_and_lines sals,
+ struct linespec_result *canonical,
char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
struct symtabs_and_lines expanded =
expand_line_sal_maybe (sals.sals[i]);
- create_breakpoint_sal (gdbarch, expanded, addr_string[i],
+ create_breakpoint_sal (gdbarch, expanded, canonical->canonical[i],
cond_string, type, disposition,
thread, task, ignore_count, ops,
- from_tty, enabled, internal);
+ from_tty, enabled, internal,
+ canonical->special_display);
}
}
-/* Parse ARG which is assumed to be a SAL specification possibly
+/* Parse ADDRESS which is assumed to be a SAL specification possibly
followed by conditionals. On return, SALS contains an array of SAL
addresses found. ADDR_STRING contains a vector of (canonical)
- address strings. ARG points to the end of the SAL. */
+ address strings. ADDRESS points to the end of the SAL.
+
+ The array and the line spec strings are allocated on the heap, it is
+ the caller's responsibility to free them. */
static void
parse_breakpoint_sals (char **address,
struct symtabs_and_lines *sals,
- char ***addr_string,
- int *not_found_ptr)
+ struct linespec_result *canonical)
{
char *addr_start = *address;
- *addr_string = NULL;
/* If no arg given, or if first arg is 'if ', use the default
breakpoint. */
if ((*address) == NULL
|| ((strchr ("+-", (*address)[0]) != NULL)
&& ((*address)[1] != '['))))
*sals = decode_line_1 (address, 1, default_breakpoint_symtab,
- default_breakpoint_line, addr_string,
- not_found_ptr);
+ default_breakpoint_line, canonical);
else
*sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
- addr_string, not_found_ptr);
+ canonical);
}
/* For any SAL that didn't have a canonical string, fill one in. */
- if (sals->nelts > 0 && *addr_string == NULL)
- *addr_string = xcalloc (sals->nelts, sizeof (char **));
+ if (sals->nelts > 0 && canonical->canonical == NULL)
+ canonical->canonical = xcalloc (sals->nelts, sizeof (char **));
if (addr_start != (*address))
{
int i;
for (i = 0; i < sals->nelts; i++)
{
/* Add the string if not present. */
- if ((*addr_string)[i] == NULL)
- (*addr_string)[i] = savestring (addr_start,
- (*address) - addr_start);
+ if (canonical->canonical[i] == NULL)
+ canonical->canonical[i] = savestring (addr_start,
+ (*address) - addr_start);
}
}
}
}
}
-static void
-do_captured_parse_breakpoint (struct ui_out *ui, void *data)
-{
- struct captured_parse_breakpoint_args *args = data;
-
- parse_breakpoint_sals (args->arg_p, args->sals_p, args->addr_string_p,
- args->not_found_ptr);
-}
-
/* Given TOK, a string specification of condition and thread, as
accepted by the 'break' command, extract the condition
string and thread number and set *COND_STRING and *THREAD.
char *cond_start = NULL;
char *cond_end = NULL;
- while (*tok == ' ' || *tok == '\t')
- tok++;
+ tok = skip_spaces (tok);
- end_tok = tok;
-
- while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
- end_tok++;
+ end_tok = skip_to_space (tok);
toklen = end_tok - tok;
char *marker_str;
int i;
- while (*p == ' ' || *p == '\t')
- p++;
+ p = skip_spaces (p);
- endp = p;
- while (*endp != ' ' && *endp != '\t' && *endp != '\0')
- endp++;
+ endp = skip_to_space (p);
marker_str = savestring (p, endp - p);
old_chain = make_cleanup (xfree, marker_str);
struct breakpoint_ops *ops,
int from_tty, int enabled, int internal)
{
- struct gdb_exception e;
+ volatile struct gdb_exception e;
struct symtabs_and_lines sals;
struct symtab_and_line pending_sal;
char *copy_arg;
char *addr_start = arg;
- char **addr_string;
+ struct linespec_result canonical;
struct cleanup *old_chain;
struct cleanup *bkpt_chain = NULL;
- struct captured_parse_breakpoint_args parse_args;
int i;
int pending = 0;
- int not_found = 0;
int task = 0;
int prev_bkpt_count = breakpoint_count;
sals.sals = NULL;
sals.nelts = 0;
- addr_string = NULL;
-
- parse_args.arg_p = &arg;
- parse_args.sals_p = &sals;
- parse_args.addr_string_p = &addr_string;
- parse_args.not_found_ptr = ¬_found;
+ init_linespec_result (&canonical);
if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
{
sals = decode_static_tracepoint_spec (&arg);
copy_arg = savestring (addr_start, arg - addr_start);
- addr_string = xcalloc (sals.nelts, sizeof (char **));
+ canonical.canonical = xcalloc (sals.nelts, sizeof (char **));
for (i = 0; i < sals.nelts; i++)
- addr_string[i] = xstrdup (copy_arg);
+ canonical.canonical[i] = xstrdup (copy_arg);
goto done;
}
- e = catch_exception (uiout, do_captured_parse_breakpoint,
- &parse_args, RETURN_MASK_ALL);
+ TRY_CATCH (e, RETURN_MASK_ALL)
+ {
+ parse_breakpoint_sals (&arg, &sals, &canonical);
+ }
/* If caller is interested in rc value from parse, set value. */
switch (e.reason)
breakpoint behavior is on and thus a pending breakpoint
is defaulted on behalf of the user. */
copy_arg = xstrdup (addr_start);
- addr_string = ©_arg;
+ canonical.canonical = ©_arg;
sals.nelts = 1;
sals.sals = &pending_sal;
pending_sal.pc = 0;
default:
throw_exception (e);
}
+ break;
default:
if (!sals.nelts)
return 0;
/* Make sure that all storage allocated to SALS gets freed. */
make_cleanup (xfree, sals.sals);
- /* Cleanup the addr_string array but not its contents. */
- make_cleanup (xfree, addr_string);
+ /* Cleanup the canonical array but not its contents. */
+ make_cleanup (xfree, canonical.canonical);
}
/* ----------------------------- SNIP -----------------------------
then the memory is not reclaimed. */
bkpt_chain = make_cleanup (null_cleanup, 0);
- /* Mark the contents of the addr_string for cleanup. These go on
+ /* Mark the contents of the canonical for cleanup. These go on
the bkpt_chain and only occur if the breakpoint create fails. */
for (i = 0; i < sals.nelts; i++)
{
- if (addr_string[i] != NULL)
- make_cleanup (xfree, addr_string[i]);
+ if (canonical.canonical[i] != NULL)
+ make_cleanup (xfree, canonical.canonical[i]);
}
/* Resolve all line numbers to PC's and verify that the addresses
expand multiple locations for each sal, given than SALS
already should contain all sals for MARKER_ID. */
if (type_wanted == bp_static_tracepoint
- && is_marker_spec (addr_string[0]))
+ && is_marker_spec (canonical.canonical[0]))
{
int i;
expanded.sals[0] = sals.sals[i];
old_chain = make_cleanup (xfree, expanded.sals);
- create_breakpoint_sal (gdbarch, expanded, addr_string[i],
+ create_breakpoint_sal (gdbarch, expanded, canonical.canonical[i],
cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
- from_tty, enabled, internal);
+ from_tty, enabled, internal,
+ canonical.special_display);
do_cleanups (old_chain);
}
}
else
- create_breakpoints_sal (gdbarch, sals, addr_string, cond_string,
+ create_breakpoints_sal (gdbarch, sals, &canonical, cond_string,
type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops, from_tty,
b = set_raw_breakpoint_without_location (gdbarch, type_wanted);
set_breakpoint_number (internal, b);
b->thread = -1;
- b->addr_string = addr_string[0];
+ b->addr_string = canonical.canonical[0];
b->cond_string = NULL;
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
}
static void
-stop_command (char *arg, int from_tty)
+stop_command (char *arg, int from_tty)
+{
+ printf_filtered (_("Specify the type of breakpoint to set.\n\
+Usage: stop in <function | address>\n\
+ stop at <line>\n"));
+}
+
+static void
+stopin_command (char *arg, int from_tty)
+{
+ int badInput = 0;
+
+ if (arg == (char *) NULL)
+ badInput = 1;
+ else if (*arg != '*')
+ {
+ char *argptr = arg;
+ int hasColon = 0;
+
+ /* Look for a ':'. If this is a line number specification, then
+ say it is bad, otherwise, it should be an address or
+ function/method name. */
+ while (*argptr && !hasColon)
+ {
+ hasColon = (*argptr == ':');
+ argptr++;
+ }
+
+ if (hasColon)
+ badInput = (*argptr != ':'); /* Not a class::method */
+ else
+ badInput = isdigit (*arg); /* a simple line number */
+ }
+
+ if (badInput)
+ printf_filtered (_("Usage: stop in <function | address>\n"));
+ else
+ break_command_1 (arg, 0, from_tty);
+}
+
+static void
+stopat_command (char *arg, int from_tty)
+{
+ int badInput = 0;
+
+ if (arg == (char *) NULL || *arg == '*') /* no line number */
+ badInput = 1;
+ else
+ {
+ char *argptr = arg;
+ int hasColon = 0;
+
+ /* Look for a ':'. If there is a '::' then get out, otherwise
+ it is probably a line number. */
+ while (*argptr && !hasColon)
+ {
+ hasColon = (*argptr == ':');
+ argptr++;
+ }
+
+ if (hasColon)
+ badInput = (*argptr == ':'); /* we have class::method */
+ else
+ badInput = !isdigit (*arg); /* not a line number */
+ }
+
+ if (badInput)
+ printf_filtered (_("Usage: stop at <line>\n"));
+ else
+ break_command_1 (arg, 0, from_tty);
+}
+
+/* Implement the "breakpoint_hit" breakpoint_ops method for
+ ranged breakpoints. */
+
+static int
+breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
+ struct address_space *aspace,
+ CORE_ADDR bp_addr)
+{
+ return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
+ bl->length, aspace, bp_addr);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+ ranged breakpoints. */
+
+static int
+resources_needed_ranged_breakpoint (const struct bp_location *bl)
+{
+ return target_ranged_break_num_registers ();
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+ ranged breakpoints. */
+
+static enum print_stop_action
+print_it_ranged_breakpoint (struct breakpoint *b)
+{
+ struct bp_location *bl = b->loc;
+
+ gdb_assert (b->type == bp_hardware_breakpoint);
+
+ /* Ranged breakpoints have only one location. */
+ gdb_assert (bl && bl->next == NULL);
+
+ annotate_breakpoint (b->number);
+ if (b->disposition == disp_del)
+ ui_out_text (uiout, "\nTemporary ranged breakpoint ");
+ else
+ ui_out_text (uiout, "\nRanged breakpoint ");
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ ui_out_field_string (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+ ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+ }
+ ui_out_field_int (uiout, "bkptno", b->number);
+ ui_out_text (uiout, ", ");
+
+ return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for
+ ranged breakpoints. */
+
+static void
+print_one_ranged_breakpoint (struct breakpoint *b,
+ struct bp_location **last_loc)
+{
+ struct bp_location *bl = b->loc;
+ struct value_print_options opts;
+
+ /* Ranged breakpoints have only one location. */
+ gdb_assert (bl && bl->next == NULL);
+
+ get_user_print_options (&opts);
+
+ if (opts.addressprint)
+ /* We don't print the address range here, it will be printed later
+ by print_one_detail_ranged_breakpoint. */
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ print_breakpoint_location (b, bl);
+ *last_loc = bl;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+ ranged breakpoints. */
+
+static void
+print_one_detail_ranged_breakpoint (const struct breakpoint *b,
+ struct ui_out *uiout)
+{
+ CORE_ADDR address_start, address_end;
+ struct bp_location *bl = b->loc;
+ struct ui_stream *stb = ui_out_stream_new (uiout);
+ struct cleanup *cleanup = make_cleanup_ui_out_stream_delete (stb);
+
+ gdb_assert (bl);
+
+ address_start = bl->address;
+ address_end = address_start + bl->length - 1;
+
+ ui_out_text (uiout, "\taddress range: ");
+ fprintf_unfiltered (stb->stream, "[%s, %s]",
+ print_core_address (bl->gdbarch, address_start),
+ print_core_address (bl->gdbarch, address_end));
+ ui_out_field_stream (uiout, "addr", stb);
+ ui_out_text (uiout, "\n");
+
+ do_cleanups (cleanup);
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+ ranged breakpoints. */
+
+static void
+print_mention_ranged_breakpoint (struct breakpoint *b)
+{
+ struct bp_location *bl = b->loc;
+
+ gdb_assert (bl);
+ gdb_assert (b->type == bp_hardware_breakpoint);
+
+ if (ui_out_is_mi_like_p (uiout))
+ return;
+
+ printf_filtered (_("Hardware assisted ranged breakpoint %d from %s to %s."),
+ b->number, paddress (bl->gdbarch, bl->address),
+ paddress (bl->gdbarch, bl->address + bl->length - 1));
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+ ranged breakpoints. */
+
+static void
+print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
{
- printf_filtered (_("Specify the type of breakpoint to set.\n\
-Usage: stop in <function | address>\n\
- stop at <line>\n"));
+ fprintf_unfiltered (fp, "break-range %s, %s", b->addr_string,
+ b->addr_string_range_end);
}
-static void
-stopin_command (char *arg, int from_tty)
+/* The breakpoint_ops structure to be used in ranged breakpoints. */
+
+static struct breakpoint_ops ranged_breakpoint_ops =
{
- int badInput = 0;
+ NULL, /* insert */
+ NULL, /* remove */
+ breakpoint_hit_ranged_breakpoint,
+ resources_needed_ranged_breakpoint,
+ print_it_ranged_breakpoint,
+ print_one_ranged_breakpoint,
+ print_one_detail_ranged_breakpoint,
+ print_mention_ranged_breakpoint,
+ print_recreate_ranged_breakpoint
+};
- if (arg == (char *) NULL)
- badInput = 1;
- else if (*arg != '*')
+/* Find the address where the end of the breakpoint range should be
+ placed, given the SAL of the end of the range. This is so that if
+ the user provides a line number, the end of the range is set to the
+ last instruction of the given line. */
+
+static CORE_ADDR
+find_breakpoint_range_end (struct symtab_and_line sal)
+{
+ CORE_ADDR end;
+
+ /* If the user provided a PC value, use it. Otherwise,
+ find the address of the end of the given location. */
+ if (sal.explicit_pc)
+ end = sal.pc;
+ else
{
- char *argptr = arg;
- int hasColon = 0;
+ int ret;
+ CORE_ADDR start;
- /* Look for a ':'. If this is a line number specification, then
- say it is bad, otherwise, it should be an address or
- function/method name. */
- while (*argptr && !hasColon)
- {
- hasColon = (*argptr == ':');
- argptr++;
- }
+ ret = find_line_pc_range (sal, &start, &end);
+ if (!ret)
+ error (_("Could not find location of the end of the range."));
- if (hasColon)
- badInput = (*argptr != ':'); /* Not a class::method */
- else
- badInput = isdigit (*arg); /* a simple line number */
+ /* find_line_pc_range returns the start of the next line. */
+ end--;
}
- if (badInput)
- printf_filtered (_("Usage: stop in <function | address>\n"));
- else
- break_command_1 (arg, 0, from_tty);
+ return end;
}
+/* Implement the "break-range" CLI command. */
+
static void
-stopat_command (char *arg, int from_tty)
+break_range_command (char *arg, int from_tty)
{
- int badInput = 0;
+ char *arg_start, *addr_string_start, *addr_string_end;
+ struct linespec_result canonical_start, canonical_end;
+ int bp_count, can_use_bp, length;
+ CORE_ADDR end;
+ struct breakpoint *b;
+ struct symtab_and_line sal_start, sal_end;
+ struct symtabs_and_lines sals_start, sals_end;
+ struct cleanup *cleanup_bkpt;
+
+ /* We don't support software ranged breakpoints. */
+ if (target_ranged_break_num_registers () < 0)
+ error (_("This target does not support hardware ranged breakpoints."));
+
+ bp_count = hw_breakpoint_used_count ();
+ bp_count += target_ranged_break_num_registers ();
+ can_use_bp = target_can_use_hardware_watchpoint (bp_hardware_breakpoint,
+ bp_count, 0);
+ if (can_use_bp < 0)
+ error (_("Hardware breakpoints used exceeds limit."));
+
+ if (arg == NULL || arg[0] == '\0')
+ error(_("No address range specified."));
+
+ sals_start.sals = NULL;
+ sals_start.nelts = 0;
+ init_linespec_result (&canonical_start);
+
+ while (*arg == ' ' || *arg == '\t')
+ arg++;
+
+ parse_breakpoint_sals (&arg, &sals_start, &canonical_start);
+
+ sal_start = sals_start.sals[0];
+ addr_string_start = canonical_start.canonical[0];
+ cleanup_bkpt = make_cleanup (xfree, addr_string_start);
+ xfree (sals_start.sals);
+ xfree (canonical_start.canonical);
+
+ if (arg[0] != ',')
+ error (_("Too few arguments."));
+ else if (sals_start.nelts == 0)
+ error (_("Could not find location of the beginning of the range."));
+ else if (sals_start.nelts != 1)
+ error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+ resolve_sal_pc (&sal_start);
+
+ arg++; /* Skip the comma. */
+ while (*arg == ' ' || *arg == '\t')
+ arg++;
+
+ /* Parse the end location. */
+
+ sals_end.sals = NULL;
+ sals_end.nelts = 0;
+ init_linespec_result (&canonical_end);
+ arg_start = arg;
+
+ /* We call decode_line_1 directly here instead of using
+ parse_breakpoint_sals because we need to specify the start location's
+ symtab and line as the default symtab and line for the end of the
+ range. This makes it possible to have ranges like "foo.c:27, +14",
+ where +14 means 14 lines from the start location. */
+ sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
+ &canonical_end);
+
+ /* canonical_end can be NULL if it was of the form "*0xdeadbeef". */
+ if (canonical_end.canonical == NULL)
+ canonical_end.canonical = xcalloc (1, sizeof (char **));
+ /* Add the string if not present. */
+ if (arg_start != arg && canonical_end.canonical[0] == NULL)
+ canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
+
+ sal_end = sals_end.sals[0];
+ addr_string_end = canonical_end.canonical[0];
+ make_cleanup (xfree, addr_string_end);
+ xfree (sals_end.sals);
+ xfree (canonical_end.canonical);
+
+ if (sals_end.nelts == 0)
+ error (_("Could not find location of the end of the range."));
+ else if (sals_end.nelts != 1)
+ error (_("Cannot create a ranged breakpoint with multiple locations."));
+
+ resolve_sal_pc (&sal_end);
+
+ end = find_breakpoint_range_end (sal_end);
+ if (sal_start.pc > end)
+ error (_("Invalid address range, end preceeds start."));
+
+ length = end - sal_start.pc + 1;
+ if (length < 0)
+ /* Length overflowed. */
+ error (_("Address range too large."));
+ else if (length == 1)
+ {
+ /* This range is simple enough to be handled by
+ the `hbreak' command. */
+ hbreak_command (addr_string_start, 1);
+
+ do_cleanups (cleanup_bkpt);
- if (arg == (char *) NULL || *arg == '*') /* no line number */
- badInput = 1;
- else
- {
- char *argptr = arg;
- int hasColon = 0;
+ return;
+ }
- /* Look for a ':'. If there is a '::' then get out, otherwise
- it is probably a line number. */
- while (*argptr && !hasColon)
- {
- hasColon = (*argptr == ':');
- argptr++;
- }
+ /* Now set up the breakpoint. */
+ b = set_raw_breakpoint (get_current_arch (), sal_start,
+ bp_hardware_breakpoint);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->disposition = disp_donttouch;
+ b->addr_string = addr_string_start;
+ b->addr_string_range_end = addr_string_end;
+ b->ops = &ranged_breakpoint_ops;
+ b->loc->length = length;
- if (hasColon)
- badInput = (*argptr == ':'); /* we have class::method */
- else
- badInput = !isdigit (*arg); /* not a line number */
- }
+ discard_cleanups (cleanup_bkpt);
- if (badInput)
- printf_filtered (_("Usage: stop at <line>\n"));
- else
- break_command_1 (arg, 0, from_tty);
+ mention (b);
+ update_global_location_list (1);
}
/* Return non-zero if EXP is verified as constant. Returned zero
return 1;
}
+/* Implement the "insert" breakpoint_ops method for hardware watchpoints. */
+
+static int
+insert_watchpoint (struct bp_location *bl)
+{
+ int length = bl->owner->exact? 1 : bl->length;
+
+ return target_insert_watchpoint (bl->address, length, bl->watchpoint_type,
+ bl->owner->cond_exp);
+}
+
+/* Implement the "remove" breakpoint_ops method for hardware watchpoints. */
+
+static int
+remove_watchpoint (struct bp_location *bl)
+{
+ int length = bl->owner->exact? 1 : bl->length;
+
+ return target_remove_watchpoint (bl->address, length, bl->watchpoint_type,
+ bl->owner->cond_exp);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+ hardware watchpoints. */
+
+static int
+resources_needed_watchpoint (const struct bp_location *bl)
+{
+ int length = bl->owner->exact? 1 : bl->length;
+
+ return target_region_ok_for_hw_watchpoint (bl->address, length);
+}
+
+/* The breakpoint_ops structure to be used in hardware watchpoints. */
+
+static struct breakpoint_ops watchpoint_breakpoint_ops =
+{
+ insert_watchpoint,
+ remove_watchpoint,
+ NULL, /* breakpoint_hit */
+ resources_needed_watchpoint,
+ NULL, /* print_it */
+ NULL, /* print_one */
+ NULL, /* print_one_detail */
+ NULL, /* print_mention */
+ NULL /* print_recreate */
+};
+
/* accessflag: hw_write: watch write,
hw_read: watch read,
hw_access: watch access (read or write) */
char *cond_end = NULL;
int i, other_type_used, target_resources_ok = 0;
enum bptype bp_type;
- int mem_cnt = 0;
+ int reg_cnt = 0;
int thread = -1;
int pc = 0;
else if (val != NULL)
release_value (val);
- tok = arg;
- while (*tok == ' ' || *tok == '\t')
- tok++;
- end_tok = tok;
-
- while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
- end_tok++;
+ tok = skip_spaces (arg);
+ end_tok = skip_to_space (tok);
toklen = end_tok - tok;
if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
else
bp_type = bp_hardware_watchpoint;
- mem_cnt = can_use_hardware_watchpoint (val);
- if (mem_cnt == 0 && bp_type != bp_hardware_watchpoint)
+ reg_cnt = can_use_hardware_watchpoint (val, target_exact_watchpoints);
+ if (reg_cnt == 0 && bp_type != bp_hardware_watchpoint)
error (_("Expression cannot be implemented with read/access watchpoint."));
- if (mem_cnt != 0)
+ if (reg_cnt != 0)
{
i = hw_watchpoint_used_count (bp_type, &other_type_used);
target_resources_ok =
- target_can_use_hardware_watchpoint (bp_type, i + mem_cnt,
+ target_can_use_hardware_watchpoint (bp_type, i + reg_cnt,
other_type_used);
if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint)
error (_("Target does not support this type of hardware watchpoint."));
/* Change the type of breakpoint to an ordinary watchpoint if a
hardware watchpoint could not be set. */
- if (!mem_cnt || target_resources_ok <= 0)
+ if (!reg_cnt || target_resources_ok <= 0)
bp_type = bp_watchpoint;
frame = block_innermost_frame (exp_valid_block);
core_addr_to_string (addr));
xfree (name);
- b->exp_string = xstrprintf ("-location: %.*s",
+ b->exp_string = xstrprintf ("-location %.*s",
(int) (exp_end - exp_start), exp_start);
/* The above expression is in C. */
b->exp_string = savestring (exp_start, exp_end - exp_start);
b->val = val;
b->val_valid = 1;
+ b->ops = &watchpoint_breakpoint_ops;
+
+ /* Use an exact watchpoint when there's only one memory region to be
+ watched, and only one debug register is needed to watch it. */
+ b->exact = target_exact_watchpoints && reg_cnt == 1;
+
if (cond_start)
b->cond_string = savestring (cond_start, cond_end - cond_start);
else
update_global_location_list (1);
}
-/* Return count of locations need to be watched and can be handled in
- hardware. If the watchpoint can not be handled in hardware return
- zero. */
+/* Return count of debug registers needed to watch the given expression.
+ If EXACT_WATCHPOINTS is 1, then consider that only the address of
+ the start of the watched region will be monitored (i.e., all accesses
+ will be aligned). This uses less debug registers on some targets.
+
+ If the watchpoint cannot be handled in hardware return zero. */
static int
-can_use_hardware_watchpoint (struct value *v)
+can_use_hardware_watchpoint (struct value *v, int exact_watchpoints)
{
int found_memory_cnt = 0;
struct value *head = v;
&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
{
CORE_ADDR vaddr = value_address (v);
- int len = TYPE_LENGTH (value_type (v));
+ int len;
+ int num_regs;
+
+ len = (exact_watchpoints
+ && is_scalar_type_recursive (vtype))?
+ 1 : TYPE_LENGTH (value_type (v));
- if (!target_region_ok_for_hw_watchpoint (vaddr, len))
+ num_regs = target_region_ok_for_hw_watchpoint (vaddr, len);
+ if (!num_regs)
return 0;
else
- found_memory_cnt++;
+ found_memory_cnt += num_regs;
}
}
}
&& (check_for_argument (&arg, "-location", sizeof ("-location") - 1)
|| check_for_argument (&arg, "-l", sizeof ("-l") - 1)))
{
- ep_skip_leading_whitespace (&arg);
+ arg = skip_spaces (arg);
just_location = 1;
}
if (default_breakpoint_valid)
sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
- default_breakpoint_line, (char ***) NULL, NULL);
+ default_breakpoint_line, NULL);
else
- sals = decode_line_1 (&arg, 1, (struct symtab *) NULL,
- 0, (char ***) NULL, NULL);
+ sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, NULL);
if (sals.nelts != 1)
error (_("Couldn't get information on specified line."));
do_cleanups (old_chain);
}
-static void
-ep_skip_leading_whitespace (char **s)
-{
- if ((s == NULL) || (*s == NULL))
- return;
- while (isspace (**s))
- *s += 1;
-}
-
/* This function attempts to parse an optional "if <cond>" clause
from the arg string. If one is not found, it returns NULL.
/* Skip any extra leading whitespace, and record the start of the
condition string. */
- ep_skip_leading_whitespace (arg);
+ *arg = skip_spaces (*arg);
cond_string = *arg;
/* Assume that the condition occupies the remainder of the arg
if (!arg)
arg = "";
- ep_skip_leading_whitespace (&arg);
+ arg = skip_spaces (arg);
/* The allowed syntax is:
catch [v]fork
if (!arg)
arg = "";
- ep_skip_leading_whitespace (&arg);
+ arg = skip_spaces (arg);
/* The allowed syntax is:
catch exec
}
static enum print_stop_action
-print_exception_catchpoint (struct breakpoint *b)
+print_it_exception_catchpoint (struct breakpoint *b)
{
int bp_temp, bp_throw;
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
- print_exception_catchpoint,
+ NULL, /* resources_needed */
+ print_it_exception_catchpoint,
print_one_exception_catchpoint,
+ NULL, /* print_one_detail */
print_mention_exception_catchpoint,
print_recreate_exception_catchpoint
};
if (!arg)
arg = "";
- ep_skip_leading_whitespace (&arg);
+ arg = skip_spaces (arg);
cond_string = ep_parse_optional_if_clause (&arg);
/* Checking if the feature if supported. */
if (gdbarch_get_syscall_number_p (gdbarch) == 0)
error (_("The feature 'catch syscall' is not supported on \
-this architeture yet."));
+this architecture yet."));
tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
- ep_skip_leading_whitespace (&arg);
+ arg = skip_spaces (arg);
/* We need to do this first "dummy" translation in order
to get the syscall XML file loaded or, most important,
&& b->source_file != NULL
&& sal.symtab != NULL
&& sal.pspace == loc->pspace
- && strcmp (b->source_file,
- sal.symtab->filename) == 0
+ && filename_cmp (b->source_file,
+ sal.symtab->filename) == 0
&& b->line_number == sal.line);
if (pc_match || line_match)
{
/* At least avoid this stale reference until the reference counting
of breakpoints gets resolved. */
- if (bpt->related_breakpoint != NULL)
+ if (bpt->related_breakpoint != bpt)
{
- gdb_assert (bpt->related_breakpoint->related_breakpoint == bpt);
- bpt->related_breakpoint->disposition = disp_del_at_next_stop;
- bpt->related_breakpoint->related_breakpoint = NULL;
- bpt->related_breakpoint = NULL;
+ struct breakpoint *related;
+
+ if (bpt->type == bp_watchpoint_scope)
+ watchpoint_del_at_next_stop (bpt->related_breakpoint);
+ else if (bpt->related_breakpoint->type == bp_watchpoint_scope)
+ watchpoint_del_at_next_stop (bpt);
+
+ /* Unlink bpt from the bpt->related_breakpoint ring. */
+ for (related = bpt; related->related_breakpoint != bpt;
+ related = related->related_breakpoint);
+ related->related_breakpoint = bpt->related_breakpoint;
+ bpt->related_breakpoint = bpt;
}
observer_notify_breakpoint_deleted (bpt->number);
xfree (bpt->cond_string);
xfree (bpt->cond_exp);
xfree (bpt->addr_string);
+ xfree (bpt->addr_string_range_end);
xfree (bpt->exp);
xfree (bpt->exp_string);
xfree (bpt->exp_string_reparse);
return sal;
}
-static void
+/* 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. */
+
+void
update_breakpoint_locations (struct breakpoint *b,
- struct symtabs_and_lines sals)
+ struct symtabs_and_lines sals,
+ struct symtabs_and_lines sals_end)
{
int i;
- char *s;
struct bp_location *existing_locations = b->loc;
+ /* Ranged breakpoints have only one start location and one end location. */
+ gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
+
/* 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.
old symtab. */
if (b->cond_string != NULL)
{
+ char *s;
struct gdb_exception e;
s = b->cond_string;
if (b->line_number == 0)
b->line_number = sals.sals[i].line;
+
+ if (sals_end.nelts)
+ {
+ CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
+
+ new_loc->length = end - sals.sals[0].pc + 1;
+ }
}
/* Update locations of permanent breakpoints. */
if (have_ambiguous_names)
{
for (; l; l = l->next)
- if (breakpoint_address_match (e->pspace->aspace, e->address,
- l->pspace->aspace, l->address))
+ if (breakpoint_locations_match (e, l))
{
l->enabled = 0;
break;
update_global_location_list (1);
}
+/* Find the SaL locations corresponding to the given ADDR_STRING.
+ On return, FOUND will be 1 if any SaL was found, zero otherwise. */
+
+static struct symtabs_and_lines
+addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
+{
+ char *s;
+ int marker_spec;
+ struct symtabs_and_lines sals = {0};
+ struct gdb_exception e;
+
+ s = addr_string;
+ marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s);
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ if (marker_spec)
+ {
+ sals = decode_static_tracepoint_spec (&s);
+ if (sals.nelts > b->static_trace_marker_id_idx)
+ {
+ sals.sals[0] = sals.sals[b->static_trace_marker_id_idx];
+ sals.nelts = 1;
+ }
+ else
+ error (_("marker %s not found"), b->static_trace_marker_id);
+ }
+ else
+ sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, NULL);
+ }
+ 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 (e.error == NOT_FOUND_ERROR
+ && (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)
+ {
+ /* 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);
+ }
+ }
+
+ if (e.reason == 0 || e.error != NOT_FOUND_ERROR)
+ {
+ 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;
+ int task = 0;
+
+ find_condition_and_thread (s, sals.sals[0].pc,
+ &cond_string, &thread, &task);
+ if (cond_string)
+ b->cond_string = cond_string;
+ b->thread = thread;
+ b->task = task;
+ b->condition_not_parsed = 0;
+ }
+
+ if (b->type == bp_static_tracepoint && !marker_spec)
+ sals.sals[0] = update_static_tracepoint (b, sals.sals[0]);
+
+ *found = 1;
+ }
+ else
+ *found = 0;
+
+ return sals;
+}
+
+/* Reevaluate a hardware or software breakpoint and recreate its locations.
+ This is necessary after symbols are read (e.g., an executable or DSO
+ was loaded, or the inferior just started). */
+
+static void
+re_set_breakpoint (struct breakpoint *b)
+{
+ int found;
+ struct symtabs_and_lines sals, sals_end;
+ struct symtabs_and_lines expanded = {0};
+ struct symtabs_and_lines expanded_end = {0};
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+
+ input_radix = b->input_radix;
+ save_current_space_and_thread ();
+ switch_to_program_space_and_thread (b->pspace);
+ set_language (b->language);
+
+ sals = addr_string_to_sals (b, b->addr_string, &found);
+ if (found)
+ {
+ make_cleanup (xfree, sals.sals);
+ expanded = expand_line_sal_maybe (sals.sals[0]);
+ }
+
+ if (b->addr_string_range_end)
+ {
+ sals_end = addr_string_to_sals (b, b->addr_string_range_end, &found);
+ if (found)
+ {
+ make_cleanup (xfree, sals_end.sals);
+ expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
+ }
+ }
+
+ update_breakpoint_locations (b, expanded, expanded_end);
+ do_cleanups (cleanups);
+}
+
/* 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. */
{
/* Get past catch_errs. */
struct breakpoint *b = (struct breakpoint *) bint;
- int not_found = 0;
- int *not_found_ptr = ¬_found;
- struct symtabs_and_lines sals = {0};
- struct symtabs_and_lines expanded = {0};
- char *s;
- struct gdb_exception e;
- struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
- int marker_spec = 0;
switch (b->type)
{
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_static_tracepoint:
+ case bp_gnu_ifunc_resolver:
/* Do not attempt to re-set breakpoints disabled during startup. */
if (b->enable_state == bp_startup_disabled)
return 0;
return 0;
}
- input_radix = b->input_radix;
- s = b->addr_string;
-
- save_current_space_and_thread ();
- switch_to_program_space_and_thread (b->pspace);
-
- marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s);
-
- set_language (b->language);
- TRY_CATCH (e, RETURN_MASK_ERROR)
- {
- if (marker_spec)
- {
- sals = decode_static_tracepoint_spec (&s);
- if (sals.nelts > b->static_trace_marker_id_idx)
- {
- sals.sals[0] = sals.sals[b->static_trace_marker_id_idx];
- sals.nelts = 1;
- }
- else
- error (_("marker %s not found"), b->static_trace_marker_id);
- }
- else
- 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)
- {
- /* 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);
- }
- }
-
- if (!not_found)
- {
- 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;
- int task = 0;
-
- find_condition_and_thread (s, sals.sals[0].pc,
- &cond_string, &thread, &task);
- if (cond_string)
- b->cond_string = cond_string;
- b->thread = thread;
- b->task = task;
- b->condition_not_parsed = 0;
- }
-
- if (b->type == bp_static_tracepoint && !marker_spec)
- sals.sals[0] = update_static_tracepoint (b, sals.sals[0]);
-
- expanded = expand_line_sal_maybe (sals.sals[0]);
- }
-
- make_cleanup (xfree, sals.sals);
- update_breakpoint_locations (b, expanded);
+ re_set_breakpoint (b);
break;
case bp_watchpoint:
case bp_exception:
case bp_exception_resume:
case bp_jit_event:
+ case bp_gnu_ifunc_resolver_return:
break;
}
- do_cleanups (cleanups);
return 0;
}
do_cleanups (old_chain);
- create_overlay_event_breakpoint ("_ovly_debug_event");
- create_longjmp_master_breakpoint ("longjmp");
- create_longjmp_master_breakpoint ("_longjmp");
- create_longjmp_master_breakpoint ("siglongjmp");
- create_longjmp_master_breakpoint ("_siglongjmp");
- create_std_terminate_master_breakpoint ("std::terminate()");
+ create_overlay_event_breakpoint ();
+ create_longjmp_master_breakpoint ();
+ create_std_terminate_master_breakpoint ();
create_exception_master_breakpoint ();
}
\f
error (_("No breakpoint number %d."), bptnum);
}
-void
-make_breakpoint_silent (struct breakpoint *b)
-{
- /* Silence the breakpoint. */
- b->silent = 1;
-}
-
/* Command to set ignore-count of breakpoint N to COUNT. */
static void
void *),
void *data)
{
- char *p = args;
- char *p1;
int num;
struct breakpoint *b, *tmp;
int match;
+ struct get_number_or_range_state state;
- if (p == 0)
+ if (args == 0)
error_no_arg (_("one or more breakpoint numbers"));
- while (*p)
+ init_number_or_range (&state, args);
+
+ while (!state.finished)
{
+ char *p = state.string;
+
match = 0;
- p1 = p;
- num = get_number_or_range (&p1);
+ num = get_number_or_range (&state);
if (num == 0)
{
warning (_("bad breakpoint number at or near '%s'"), p);
ALL_BREAKPOINTS_SAFE (b, tmp)
if (b->number == num)
{
- struct breakpoint *related_breakpoint = b->related_breakpoint;
+ struct breakpoint *related_breakpoint;
+
match = 1;
- function (b, data);
- if (related_breakpoint)
- function (related_breakpoint, data);
+ related_breakpoint = b;
+ do
+ {
+ struct breakpoint *next_related_b;
+
+ /* FUNCTION can be also delete_breakpoint. */
+ next_related_b = related_breakpoint->related_breakpoint;
+ function (related_breakpoint, data);
+
+ /* For delete_breakpoint of the last entry of the ring we
+ were traversing we would never get back to B. */
+ if (next_related_b == related_breakpoint)
+ break;
+ related_breakpoint = next_related_b;
+ }
+ while (related_breakpoint != b);
break;
}
if (match == 0)
printf_unfiltered (_("No breakpoint number %d.\n"), num);
}
- p = p1;
}
}
*dot = '\0';
p1 = number;
- bp_num = get_number_or_range (&p1);
+ bp_num = get_number (&p1);
if (bp_num == 0)
error (_("Bad breakpoint number '%s'"), number);
error (_("Bad breakpoint number '%s'"), number);
p1 = dot+1;
- loc_num = get_number_or_range (&p1);
+ loc_num = get_number (&p1);
if (loc_num == 0)
error (_("Bad breakpoint location number '%s'"), number);
case bp_none:
warning (_("attempted to disable apparently deleted breakpoint #%d?"),
bpt->number);
- continue;
+ break;
case bp_breakpoint:
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
disable_breakpoint (bpt);
+ break;
default:
- continue;
+ break;
}
else if (strchr (args, '.'))
{
case bp_none:
warning (_("attempted to enable apparently deleted breakpoint #%d?"),
bpt->number);
- continue;
+ break;
case bp_breakpoint:
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
enable_breakpoint (bpt);
+ break;
default:
- continue;
+ break;
}
else if (strchr (args, '.'))
{
sals = decode_line_1 (&string, funfirstline,
default_breakpoint_symtab,
default_breakpoint_line,
- (char ***) NULL, NULL);
+ NULL);
else
sals = decode_line_1 (&string, funfirstline,
- (struct symtab *) NULL, 0, (char ***) NULL, NULL);
+ (struct symtab *) NULL, 0, NULL);
if (*string)
error (_("Junk at end of line specification: %s"), string);
return sals;
char *text, char *word)
{
const char **list = get_syscall_names ();
+ char **retlist
+ = (list == NULL) ? NULL : complete_on_enum (list, text, word);
- return (list == NULL) ? NULL : complete_on_enum (list, text, word);
+ xfree (list);
+ return retlist;
}
/* Tracepoint-specific operations. */
omitted. */
static void
-tracepoints_info (char *tpnum_exp, int from_tty)
+tracepoints_info (char *args, int from_tty)
{
- int tpnum = -1, num_printed;
+ int num_printed;
- if (tpnum_exp)
- tpnum = parse_and_eval_long (tpnum_exp);
-
- num_printed = breakpoint_1 (tpnum, 0, is_tracepoint);
+ num_printed = breakpoint_1 (args, 0, is_tracepoint);
if (num_printed == 0)
{
- if (tpnum == -1)
+ if (args == NULL || *args == '\0')
ui_out_message (uiout, 0, "No tracepoints.\n");
else
- ui_out_message (uiout, 0, "No tracepoint number %d.\n", tpnum);
+ ui_out_message (uiout, 0, "No tracepoint matching '%s'.\n", args);
}
default_collect_info ();
map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
}
+/* Helper function for trace_pass_command. */
+
+static void
+trace_pass_set_count (struct breakpoint *bp, int count, int from_tty)
+{
+ bp->pass_count = count;
+ observer_notify_tracepoint_modified (bp->number);
+ if (from_tty)
+ printf_filtered (_("Setting tracepoint %d's passcount to %d\n"),
+ bp->number, count);
+}
+
/* Set passcount for tracepoint.
First command argument is passcount, second is tracepoint number.
static void
trace_pass_command (char *args, int from_tty)
{
- struct breakpoint *t1 = (struct breakpoint *) -1, *t2;
+ struct breakpoint *t1;
unsigned int count;
- int all = 0;
if (args == 0 || *args == 0)
error (_("passcount command requires an "
if (*args && strncasecmp (args, "all", 3) == 0)
{
args += 3; /* Skip special argument "all". */
- all = 1;
if (*args)
error (_("Junk at end of arguments."));
- }
- else
- t1 = get_tracepoint_by_number (&args, 1, 1);
- do
+ ALL_TRACEPOINTS (t1)
+ {
+ trace_pass_set_count (t1, count, from_tty);
+ }
+ }
+ else if (*args == '\0')
{
+ t1 = get_tracepoint_by_number (&args, NULL, 1);
if (t1)
+ trace_pass_set_count (t1, count, from_tty);
+ }
+ else
+ {
+ struct get_number_or_range_state state;
+
+ init_number_or_range (&state, args);
+ while (!state.finished)
{
- ALL_TRACEPOINTS (t2)
- if (t1 == (struct breakpoint *) -1 || t1 == t2)
- {
- t2->pass_count = count;
- observer_notify_tracepoint_modified (t2->number);
- if (from_tty)
- printf_filtered (_("Setting tracepoint %d's "
- "passcount to %d\n"),
- t2->number, count);
- }
- if (! all && *args)
- t1 = get_tracepoint_by_number (&args, 1, 0);
+ t1 = get_tracepoint_by_number (&args, &state, 1);
+ if (t1)
+ trace_pass_set_count (t1, count, from_tty);
}
}
- while (*args);
}
struct breakpoint *
}
/* Utility: parse a tracepoint number and look it up in the list.
- If MULTI_P is true, there might be a range of tracepoints in ARG.
- if OPTIONAL_P is true, then if the argument is missing, the most
+ If STATE is not NULL, use, get_number_or_range_state and ignore ARG.
+ If OPTIONAL_P is true, then if the argument is missing, the most
recent tracepoint (tracepoint_count) is returned. */
struct breakpoint *
-get_tracepoint_by_number (char **arg, int multi_p, int optional_p)
+get_tracepoint_by_number (char **arg,
+ struct get_number_or_range_state *state,
+ int optional_p)
{
extern int tracepoint_count;
struct breakpoint *t;
int tpnum;
char *instring = arg == NULL ? NULL : *arg;
- if (arg == NULL || *arg == NULL || ! **arg)
+ if (state)
+ {
+ gdb_assert (!state->finished);
+ tpnum = get_number_or_range (state);
+ }
+ else if (arg == NULL || *arg == NULL || ! **arg)
{
if (optional_p)
tpnum = tracepoint_count;
error_no_arg (_("tracepoint number"));
}
else
- tpnum = multi_p ? get_number_or_range (arg) : get_number (arg);
+ tpnum = get_number (arg);
if (tpnum <= 0)
{
return t;
}
- /* FIXME: if we are in the middle of a range we don't want to give
- a message. The current interface to get_number_or_range doesn't
- allow us to discover this. */
printf_unfiltered ("No tracepoint number %d.\n", tpnum);
return NULL;
}
ALL_BREAKPOINTS (tp)
{
/* Skip internal and momentary breakpoints. */
- if (!user_settable_breakpoint (tp) || tp->number < 0)
+ if (!user_breakpoint_p (tp))
continue;
/* If we have a filter, only save the breakpoints it accepts. */
ALL_BREAKPOINTS (tp)
{
/* Skip internal and momentary breakpoints. */
- if (!user_settable_breakpoint (tp) || tp->number < 0)
+ if (!user_breakpoint_p (tp))
continue;
/* If we have a filter, only save the breakpoints it accepts. */
if (filter && !filter (tp))
continue;
- if (tp->ops != NULL)
+ if (tp->ops != NULL && tp->ops->print_recreate != NULL)
(tp->ops->print_recreate) (tp, fp);
else
{
/* Create a vector of all tracepoints. */
VEC(breakpoint_p) *
-all_tracepoints ()
+all_tracepoints (void)
{
VEC(breakpoint_p) *tp_vec = 0;
struct breakpoint *tp;
observer_attach_inferior_exit (clear_syscall_counts);
observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
+ breakpoint_objfile_key = register_objfile_data ();
+
breakpoint_chain = 0;
/* Don't bother to call set_breakpoint_count. $bpnum isn't useful
before a breakpoint is set. */
set_cmd_completer (c, location_completer);
c = add_com ("hbreak", class_breakpoint, hbreak_command, _("\
-Set a hardware assisted breakpoint.\n\
+Set a hardware assisted breakpoint.\n\
Like \"break\" except the breakpoint requires hardware support,\n\
some target hardware may not have this support.\n\
\n"
}
add_info ("breakpoints", breakpoints_info, _("\
-Status of user-settable breakpoints, or breakpoint number NUMBER.\n\
+Status of specified breakpoints (all user-settable breakpoints if no argument).\n\
The \"Type\" column indicates one of:\n\
\tbreakpoint - normal breakpoint\n\
\twatchpoint - watchpoint\n\
set_cmd_completer (c, expression_completer);
add_info ("watchpoints", watchpoints_info, _("\
-Status of watchpoints, or watchpoint number NUMBER."));
-
-
+Status of specified watchpoints (all watchpoints if no argument)."));
/* XXX: cagney/2005-02-23: This should be a boolean, and should
respond to changes - contrary to the description. */
set_cmd_completer (c, location_completer);
add_info ("tracepoints", tracepoints_info, _("\
-Status of tracepoints, or tracepoint number NUMBER.\n\
+Status of specified tracepoints (all tracepoints if no argument).\n\
Convenience variable \"$tpnum\" contains the number of the\n\
last tracepoint set."));
&show_always_inserted_mode,
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
-
+
+ add_com ("break-range", class_breakpoint, break_range_command, _("\
+Set a breakpoint for an address range.\n\
+break-range START-LOCATION, END-LOCATION\n\
+where START-LOCATION and END-LOCATION can be one of the following:\n\
+ LINENUM, for that line in the current file,\n\
+ FILE:LINENUM, for that line in that file,\n\
+ +OFFSET, for that number of lines after the current line\n\
+ or the start of the range\n\
+ FUNCTION, for the first line in that function,\n\
+ FILE:FUNCTION, to distinguish among like-named static functions.\n\
+ *ADDRESS, for the instruction at that address.\n\
+\n\
+The breakpoint will stop execution of the inferior whenever it executes\n\
+an instruction at any address within the [START-LOCATION, END-LOCATION]\n\
+range (including START-LOCATION and END-LOCATION)."));
+
automatic_hardware_breakpoints = 1;
observer_attach_about_to_proceed (breakpoint_about_to_proceed);