#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 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
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)
{
&& !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;
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)
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;
- b = create_internal_breakpoint (get_objfile_arch (objfile),
- SYMBOL_VALUE_ADDRESS (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;
+ }
+
+ 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;
+
+ 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;
+ }
- b = create_internal_breakpoint (get_objfile_arch (objfile),
- SYMBOL_VALUE_ADDRESS (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);
- debug_hook = lookup_minimal_symbol ("_Unwind_DebugHook", NULL, objfile);
- if (debug_hook != NULL)
+ if (msym_not_found_p (bp_objfile_data->exception_msym))
+ continue;
+
+ 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 ();
}
&& 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 ();
}
+ for (bs = bs_head; bs != NULL; bs = bs->next)
+ {
+ struct breakpoint *b = bs->breakpoint_at;
+
+ 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;
}
\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;
-
- 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;
+ {
+ /* If we have a filter, only list the breakpoints it accepts. */
+ if (filter && !filter (b))
+ continue;
- nr_printable_breakpoints++;
- }
- }
+ /* 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;
+ }
+
+ if (allflag || user_breakpoint_p (b))
+ {
+ int addr_bit, type_len;
+
+ 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. */
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
NULL, /* resources_needed */
print_it_catch_fork,
print_one_catch_fork,
+ NULL, /* print_one_detail */
print_mention_catch_fork,
print_recreate_catch_fork
};
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
NULL, /* resources_needed */
print_it_catch_vfork,
print_one_catch_vfork,
+ NULL, /* print_one_detail */
print_mention_catch_vfork,
print_recreate_catch_vfork
};
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;
NULL, /* resources_needed */
print_it_catch_syscall,
print_one_catch_syscall,
+ NULL, /* print_one_detail */
print_mention_catch_syscall,
print_recreate_catch_syscall
};
}
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
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;
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++;
-
- end_tok = tok;
+ tok = skip_spaces (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;
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)
+{
+ fprintf_unfiltered (fp, "break-range %s, %s", b->addr_string,
+ b->addr_string_range_end);
+}
+
+/* The breakpoint_ops structure to be used in ranged breakpoints. */
+
+static struct breakpoint_ops ranged_breakpoint_ops =
+{
+ 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
+};
+
+/* 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
+ {
+ int ret;
+ CORE_ADDR start;
+
+ ret = find_line_pc_range (sal, &start, &end);
+ if (!ret)
+ error (_("Could not find location of the end of the range."));
+
+ /* find_line_pc_range returns the start of the next line. */
+ end--;
+ }
+
+ return end;
+}
+
+/* Implement the "break-range" CLI command. */
+
+static void
+break_range_command (char *arg, int from_tty)
+{
+ 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);
+
+ return;
+ }
+
+ /* 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;
+
+ discard_cleanups (cleanup_bkpt);
+
+ mention (b);
+ update_global_location_list (1);
+}
+
/* Return non-zero if EXP is verified as constant. Returned zero
means EXP is variable. Also the constant detection may fail for
some constant expressions and in such case still falsely return
resources_needed_watchpoint,
NULL, /* print_it */
NULL, /* print_one */
+ NULL, /* print_one_detail */
NULL, /* print_mention */
NULL /* print_recreate */
};
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)
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. */
&& (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, /* remove */
NULL, /* breakpoint_hit */
NULL, /* resources_needed */
- print_exception_catchpoint,
+ 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;
-
- if (tpnum_exp)
- tpnum = parse_and_eval_long (tpnum_exp);
+ int num_printed;
- 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);