| /* Everything about breakpoints, for GDB. |
| |
| Copyright (C) 1986-2012 Free Software Foundation, Inc. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include "defs.h" |
| #include "arch-utils.h" |
| #include <ctype.h> |
| #include "hashtab.h" |
| #include "symtab.h" |
| #include "frame.h" |
| #include "breakpoint.h" |
| #include "tracepoint.h" |
| #include "gdbtypes.h" |
| #include "expression.h" |
| #include "gdbcore.h" |
| #include "gdbcmd.h" |
| #include "value.h" |
| #include "command.h" |
| #include "inferior.h" |
| #include "gdbthread.h" |
| #include "target.h" |
| #include "language.h" |
| #include "gdb_string.h" |
| #include "gdb-demangle.h" |
| #include "filenames.h" |
| #include "annotate.h" |
| #include "symfile.h" |
| #include "objfiles.h" |
| #include "source.h" |
| #include "linespec.h" |
| #include "completer.h" |
| #include "gdb.h" |
| #include "ui-out.h" |
| #include "cli/cli-script.h" |
| #include "gdb_assert.h" |
| #include "block.h" |
| #include "solib.h" |
| #include "solist.h" |
| #include "observer.h" |
| #include "exceptions.h" |
| #include "memattr.h" |
| #include "ada-lang.h" |
| #include "top.h" |
| #include "valprint.h" |
| #include "jit.h" |
| #include "xml-syscall.h" |
| #include "parser-defs.h" |
| #include "gdb_regex.h" |
| #include "probe.h" |
| #include "cli/cli-utils.h" |
| #include "continuations.h" |
| #include "stack.h" |
| #include "skip.h" |
| #include "gdb_regex.h" |
| #include "ax-gdb.h" |
| #include "dummy-frame.h" |
| |
| #include "format.h" |
| |
| /* readline include files */ |
| #include "readline/readline.h" |
| #include "readline/history.h" |
| |
| /* readline defines this. */ |
| #undef savestring |
| |
| #include "mi/mi-common.h" |
| #include "python/python.h" |
| |
| /* Prototypes for local functions. */ |
| |
| static void enable_delete_command (char *, int); |
| |
| static void enable_once_command (char *, int); |
| |
| static void enable_count_command (char *, int); |
| |
| static void disable_command (char *, int); |
| |
| static void enable_command (char *, int); |
| |
| static void map_breakpoint_numbers (char *, void (*) (struct breakpoint *, |
| void *), |
| void *); |
| |
| static void ignore_command (char *, int); |
| |
| static int breakpoint_re_set_one (void *); |
| |
| static void breakpoint_re_set_default (struct breakpoint *); |
| |
| static void create_sals_from_address_default (char **, |
| struct linespec_result *, |
| enum bptype, char *, |
| char **); |
| |
| static void create_breakpoints_sal_default (struct gdbarch *, |
| struct linespec_result *, |
| struct linespec_sals *, |
| char *, char *, enum bptype, |
| enum bpdisp, int, int, |
| int, |
| const struct breakpoint_ops *, |
| int, int, int, unsigned); |
| |
| static void decode_linespec_default (struct breakpoint *, char **, |
| struct symtabs_and_lines *); |
| |
| static void clear_command (char *, int); |
| |
| static void catch_command (char *, int); |
| |
| static int can_use_hardware_watchpoint (struct value *); |
| |
| static void break_command_1 (char *, int, int); |
| |
| static void mention (struct breakpoint *); |
| |
| static struct breakpoint *set_raw_breakpoint_without_location (struct gdbarch *, |
| enum bptype, |
| const struct breakpoint_ops *); |
| static struct bp_location *add_location_to_breakpoint (struct breakpoint *, |
| const struct symtab_and_line *); |
| |
| /* This function is used in gdbtk sources and thus can not be made |
| static. */ |
| struct breakpoint *set_raw_breakpoint (struct gdbarch *gdbarch, |
| struct symtab_and_line, |
| enum bptype, |
| const struct breakpoint_ops *); |
| |
| static struct breakpoint * |
| momentary_breakpoint_from_master (struct breakpoint *orig, |
| enum bptype type, |
| const struct breakpoint_ops *ops); |
| |
| static void breakpoint_adjustment_warning (CORE_ADDR, CORE_ADDR, int, int); |
| |
| static CORE_ADDR adjust_breakpoint_address (struct gdbarch *gdbarch, |
| CORE_ADDR bpaddr, |
| enum bptype bptype); |
| |
| static void describe_other_breakpoints (struct gdbarch *, |
| struct program_space *, CORE_ADDR, |
| struct obj_section *, int); |
| |
| static int breakpoint_address_match (struct address_space *aspace1, |
| CORE_ADDR addr1, |
| struct address_space *aspace2, |
| CORE_ADDR addr2); |
| |
| 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 (char *, int, |
| int (*) (const struct breakpoint *)); |
| |
| static int breakpoint_cond_eval (void *); |
| |
| static void cleanup_executing_breakpoints (void *); |
| |
| static void commands_command (char *, int); |
| |
| static void condition_command (char *, int); |
| |
| typedef enum |
| { |
| mark_inserted, |
| mark_uninserted |
| } |
| insertion_state_t; |
| |
| static int remove_breakpoint (struct bp_location *, insertion_state_t); |
| static int remove_breakpoint_1 (struct bp_location *, insertion_state_t); |
| |
| static enum print_stop_action print_bp_stop_message (bpstat bs); |
| |
| static int watchpoint_check (void *); |
| |
| static void maintenance_info_breakpoints (char *, int); |
| |
| static int hw_breakpoint_used_count (void); |
| |
| static int hw_watchpoint_use_count (struct breakpoint *); |
| |
| static int hw_watchpoint_used_count_others (struct breakpoint *except, |
| enum bptype type, |
| int *other_type_used); |
| |
| static void hbreak_command (char *, int); |
| |
| static void thbreak_command (char *, int); |
| |
| static void enable_breakpoint_disp (struct breakpoint *, enum bpdisp, |
| int count); |
| |
| static void stop_command (char *arg, int from_tty); |
| |
| static void stopin_command (char *arg, int from_tty); |
| |
| static void stopat_command (char *arg, int from_tty); |
| |
| static char *ep_parse_optional_if_clause (char **arg); |
| |
| static void catch_exception_command_1 (enum exception_event_kind ex_event, |
| char *arg, int tempflag, int from_tty); |
| |
| static void tcatch_command (char *arg, int from_tty); |
| |
| static void detach_single_step_breakpoints (void); |
| |
| static int single_step_breakpoint_inserted_here_p (struct address_space *, |
| CORE_ADDR pc); |
| |
| static void free_bp_location (struct bp_location *loc); |
| static void incref_bp_location (struct bp_location *loc); |
| static void decref_bp_location (struct bp_location **loc); |
| |
| static struct bp_location *allocate_bp_location (struct breakpoint *bpt); |
| |
| static void update_global_location_list (int); |
| |
| static void update_global_location_list_nothrow (int); |
| |
| static int is_hardware_watchpoint (const struct breakpoint *bpt); |
| |
| static void insert_breakpoint_locations (void); |
| |
| static int syscall_catchpoint_p (struct breakpoint *b); |
| |
| static void tracepoints_info (char *, int); |
| |
| static void delete_trace_command (char *, int); |
| |
| static void enable_trace_command (char *, int); |
| |
| static void disable_trace_command (char *, int); |
| |
| static void trace_pass_command (char *, int); |
| |
| static int is_masked_watchpoint (const struct breakpoint *b); |
| |
| static struct bp_location **get_first_locp_gte_addr (CORE_ADDR address); |
| |
| /* Return 1 if B refers to a static tracepoint set by marker ("-m"), zero |
| otherwise. */ |
| |
| static int strace_marker_p (struct breakpoint *b); |
| |
| static void init_catchpoint (struct breakpoint *b, |
| struct gdbarch *gdbarch, int tempflag, |
| char *cond_string, |
| const struct breakpoint_ops *ops); |
| |
| /* The abstract base class all breakpoint_ops structures inherit |
| from. */ |
| static struct breakpoint_ops base_breakpoint_ops; |
| |
| /* The breakpoint_ops structure to be inherited by all breakpoint_ops |
| that are implemented on top of software or hardware breakpoints |
| (user breakpoints, internal and momentary breakpoints, etc.). */ |
| static struct breakpoint_ops bkpt_base_breakpoint_ops; |
| |
| /* Internal breakpoints class type. */ |
| static struct breakpoint_ops internal_breakpoint_ops; |
| |
| /* Momentary breakpoints class type. */ |
| static struct breakpoint_ops momentary_breakpoint_ops; |
| |
| /* Momentary breakpoints for bp_longjmp and bp_exception class type. */ |
| static struct breakpoint_ops longjmp_breakpoint_ops; |
| |
| /* The breakpoint_ops structure to be used in regular user created |
| breakpoints. */ |
| struct breakpoint_ops bkpt_breakpoint_ops; |
| |
| /* Breakpoints set on probes. */ |
| static struct breakpoint_ops bkpt_probe_breakpoint_ops; |
| |
| /* Dynamic printf class type. */ |
| static struct breakpoint_ops dprintf_breakpoint_ops; |
| |
| /* The style in which to perform a dynamic printf. This is a user |
| option because different output options have different tradeoffs; |
| if GDB does the printing, there is better error handling if there |
| is a problem with any of the arguments, but using an inferior |
| function lets you have special-purpose printers and sending of |
| output to the same place as compiled-in print functions. */ |
| |
| static const char dprintf_style_gdb[] = "gdb"; |
| static const char dprintf_style_call[] = "call"; |
| static const char dprintf_style_agent[] = "agent"; |
| static const char *const dprintf_style_enums[] = { |
| dprintf_style_gdb, |
| dprintf_style_call, |
| dprintf_style_agent, |
| NULL |
| }; |
| static const char *dprintf_style = dprintf_style_gdb; |
| |
| /* The function to use for dynamic printf if the preferred style is to |
| call into the inferior. The value is simply a string that is |
| copied into the command, so it can be anything that GDB can |
| evaluate to a callable address, not necessarily a function name. */ |
| |
| static char *dprintf_function = ""; |
| |
| /* The channel to use for dynamic printf if the preferred style is to |
| call into the inferior; if a nonempty string, it will be passed to |
| the call as the first argument, with the format string as the |
| second. As with the dprintf function, this can be anything that |
| GDB knows how to evaluate, so in addition to common choices like |
| "stderr", this could be an app-specific expression like |
| "mystreams[curlogger]". */ |
| |
| static char *dprintf_channel = ""; |
| |
| /* True if dprintf commands should continue to operate even if GDB |
| has disconnected. */ |
| static int disconnected_dprintf = 1; |
| |
| /* A reference-counted struct command_line. This lets multiple |
| breakpoints share a single command list. */ |
| struct counted_command_line |
| { |
| /* The reference count. */ |
| int refc; |
| |
| /* The command list. */ |
| struct command_line *commands; |
| }; |
| |
| struct command_line * |
| breakpoint_commands (struct breakpoint *b) |
| { |
| return b->commands ? b->commands->commands : NULL; |
| } |
| |
| /* Flag indicating that a command has proceeded the inferior past the |
| current breakpoint. */ |
| |
| static int breakpoint_proceeded; |
| |
| const char * |
| bpdisp_text (enum bpdisp disp) |
| { |
| /* NOTE: the following values are a part of MI protocol and |
| represent values of 'disp' field returned when inferior stops at |
| a breakpoint. */ |
| static const char * const bpdisps[] = {"del", "dstp", "dis", "keep"}; |
| |
| return bpdisps[(int) disp]; |
| } |
| |
| /* Prototypes for exported functions. */ |
| /* If FALSE, gdb will not use hardware support for watchpoints, even |
| if such is available. */ |
| static int can_use_hw_watchpoints; |
| |
| static void |
| show_can_use_hw_watchpoints (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, |
| const char *value) |
| { |
| fprintf_filtered (file, |
| _("Debugger's willingness to use " |
| "watchpoint hardware is %s.\n"), |
| value); |
| } |
| |
| /* If AUTO_BOOLEAN_FALSE, gdb will not attempt to create pending breakpoints. |
| If AUTO_BOOLEAN_TRUE, gdb will automatically create pending breakpoints |
| for unrecognized breakpoint locations. |
| If AUTO_BOOLEAN_AUTO, gdb will query when breakpoints are unrecognized. */ |
| static enum auto_boolean pending_break_support; |
| static void |
| show_pending_break_support (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, |
| const char *value) |
| { |
| fprintf_filtered (file, |
| _("Debugger's behavior regarding " |
| "pending breakpoints is %s.\n"), |
| value); |
| } |
| |
| /* If 1, gdb will automatically use hardware breakpoints for breakpoints |
| set with "break" but falling in read-only memory. |
| If 0, gdb will warn about such breakpoints, but won't automatically |
| use hardware breakpoints. */ |
| static int automatic_hardware_breakpoints; |
| static void |
| show_automatic_hardware_breakpoints (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, |
| const char *value) |
| { |
| fprintf_filtered (file, |
| _("Automatic usage of hardware breakpoints is %s.\n"), |
| value); |
| } |
| |
| /* If on, gdb will keep breakpoints inserted even as inferior is |
| stopped, and immediately insert any new breakpoints. If off, gdb |
| will insert breakpoints into inferior only when resuming it, and |
| will remove breakpoints upon stop. If auto, GDB will behave as ON |
| if in non-stop mode, and as OFF if all-stop mode.*/ |
| |
| static enum auto_boolean always_inserted_mode = AUTO_BOOLEAN_AUTO; |
| |
| static void |
| show_always_inserted_mode (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, const char *value) |
| { |
| if (always_inserted_mode == AUTO_BOOLEAN_AUTO) |
| fprintf_filtered (file, |
| _("Always inserted breakpoint " |
| "mode is %s (currently %s).\n"), |
| value, |
| breakpoints_always_inserted_mode () ? "on" : "off"); |
| else |
| fprintf_filtered (file, _("Always inserted breakpoint mode is %s.\n"), |
| value); |
| } |
| |
| int |
| breakpoints_always_inserted_mode (void) |
| { |
| return (always_inserted_mode == AUTO_BOOLEAN_TRUE |
| || (always_inserted_mode == AUTO_BOOLEAN_AUTO && non_stop)); |
| } |
| |
| static const char condition_evaluation_both[] = "host or target"; |
| |
| /* Modes for breakpoint condition evaluation. */ |
| static const char condition_evaluation_auto[] = "auto"; |
| static const char condition_evaluation_host[] = "host"; |
| static const char condition_evaluation_target[] = "target"; |
| static const char *const condition_evaluation_enums[] = { |
| condition_evaluation_auto, |
| condition_evaluation_host, |
| condition_evaluation_target, |
| NULL |
| }; |
| |
| /* Global that holds the current mode for breakpoint condition evaluation. */ |
| static const char *condition_evaluation_mode_1 = condition_evaluation_auto; |
| |
| /* Global that we use to display information to the user (gets its value from |
| condition_evaluation_mode_1. */ |
| static const char *condition_evaluation_mode = condition_evaluation_auto; |
| |
| /* Translate a condition evaluation mode MODE into either "host" |
| or "target". This is used mostly to translate from "auto" to the |
| real setting that is being used. It returns the translated |
| evaluation mode. */ |
| |
| static const char * |
| translate_condition_evaluation_mode (const char *mode) |
| { |
| if (mode == condition_evaluation_auto) |
| { |
| if (target_supports_evaluation_of_breakpoint_conditions ()) |
| return condition_evaluation_target; |
| else |
| return condition_evaluation_host; |
| } |
| else |
| return mode; |
| } |
| |
| /* Discovers what condition_evaluation_auto translates to. */ |
| |
| static const char * |
| breakpoint_condition_evaluation_mode (void) |
| { |
| return translate_condition_evaluation_mode (condition_evaluation_mode); |
| } |
| |
| /* Return true if GDB should evaluate breakpoint conditions or false |
| otherwise. */ |
| |
| static int |
| gdb_evaluates_breakpoint_condition_p (void) |
| { |
| const char *mode = breakpoint_condition_evaluation_mode (); |
| |
| return (mode == condition_evaluation_host); |
| } |
| |
| void _initialize_breakpoint (void); |
| |
| /* Are we executing breakpoint commands? */ |
| static int executing_breakpoint_commands; |
| |
| /* 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 statement deletes the |
| current breakpoint. */ |
| |
| #define ALL_BREAKPOINTS(B) for (B = breakpoint_chain; B; B = B->next) |
| |
| #define ALL_BREAKPOINTS_SAFE(B,TMP) \ |
| for (B = breakpoint_chain; \ |
| B ? (TMP=B->next, 1): 0; \ |
| B = TMP) |
| |
| /* Similar iterator for the low-level breakpoints. SAFE variant is |
| not provided so update_global_location_list must not be called |
| while executing the block of ALL_BP_LOCATIONS. */ |
| |
| #define ALL_BP_LOCATIONS(B,BP_TMP) \ |
| for (BP_TMP = bp_location; \ |
| BP_TMP < bp_location + bp_location_count && (B = *BP_TMP); \ |
| BP_TMP++) |
| |
| /* Iterates through locations with address ADDRESS for the currently selected |
| program space. BP_LOCP_TMP points to each object. BP_LOCP_START points |
| to where the loop should start from. |
| If BP_LOCP_START is a NULL pointer, the macro automatically seeks the |
| appropriate location to start with. */ |
| |
| #define ALL_BP_LOCATIONS_AT_ADDR(BP_LOCP_TMP, BP_LOCP_START, ADDRESS) \ |
| for (BP_LOCP_START = BP_LOCP_START == NULL ? get_first_locp_gte_addr (ADDRESS) : BP_LOCP_START, \ |
| BP_LOCP_TMP = BP_LOCP_START; \ |
| BP_LOCP_START \ |
| && (BP_LOCP_TMP < bp_location + bp_location_count \ |
| && (*BP_LOCP_TMP)->address == ADDRESS); \ |
| BP_LOCP_TMP++) |
| |
| /* Iterator for tracepoints only. */ |
| |
| #define ALL_TRACEPOINTS(B) \ |
| for (B = breakpoint_chain; B; B = B->next) \ |
| if (is_tracepoint (B)) |
| |
| /* Chains of all breakpoints defined. */ |
| |
| struct breakpoint *breakpoint_chain; |
| |
| /* Array is sorted by bp_location_compare - primarily by the ADDRESS. */ |
| |
| static struct bp_location **bp_location; |
| |
| /* Number of elements of BP_LOCATION. */ |
| |
| static unsigned bp_location_count; |
| |
| /* Maximum alignment offset between bp_target_info.PLACED_ADDRESS and |
| ADDRESS for the current elements of BP_LOCATION which get a valid |
| result from bp_location_has_shadow. You can use it for roughly |
| limiting the subrange of BP_LOCATION to scan for shadow bytes for |
| an address you need to read. */ |
| |
| static CORE_ADDR bp_location_placed_address_before_address_max; |
| |
| /* Maximum offset plus alignment between bp_target_info.PLACED_ADDRESS |
| + bp_target_info.SHADOW_LEN and ADDRESS for the current elements of |
| BP_LOCATION which get a valid result from bp_location_has_shadow. |
| You can use it for roughly limiting the subrange of BP_LOCATION to |
| scan for shadow bytes for an address you need to read. */ |
| |
| static CORE_ADDR bp_location_shadow_len_after_address_max; |
| |
| /* The locations that no longer correspond to any breakpoint, unlinked |
| from bp_location array, but for which a hit may still be reported |
| by a target. */ |
| VEC(bp_location_p) *moribund_locations = NULL; |
| |
| /* Number of last breakpoint made. */ |
| |
| static int breakpoint_count; |
| |
| /* The value of `breakpoint_count' before the last command that |
| created breakpoints. If the last (break-like) command created more |
| than one breakpoint, then the difference between BREAKPOINT_COUNT |
| and PREV_BREAKPOINT_COUNT is more than one. */ |
| static int prev_breakpoint_count; |
| |
| /* Number of last tracepoint made. */ |
| |
| static int tracepoint_count; |
| |
| static struct cmd_list_element *breakpoint_set_cmdlist; |
| static struct cmd_list_element *breakpoint_show_cmdlist; |
| struct cmd_list_element *save_cmdlist; |
| |
| /* Return whether a breakpoint is an active enabled breakpoint. */ |
| static int |
| breakpoint_enabled (struct breakpoint *b) |
| { |
| return (b->enable_state == bp_enabled); |
| } |
| |
| /* Set breakpoint count to NUM. */ |
| |
| static void |
| set_breakpoint_count (int num) |
| { |
| prev_breakpoint_count = breakpoint_count; |
| breakpoint_count = num; |
| set_internalvar_integer (lookup_internalvar ("bpnum"), num); |
| } |
| |
| /* Used by `start_rbreak_breakpoints' below, to record the current |
| breakpoint count before "rbreak" creates any breakpoint. */ |
| static int rbreak_start_breakpoint_count; |
| |
| /* Called at the start an "rbreak" command to record the first |
| breakpoint made. */ |
| |
| void |
| start_rbreak_breakpoints (void) |
| { |
| rbreak_start_breakpoint_count = breakpoint_count; |
| } |
| |
| /* Called at the end of an "rbreak" command to record the last |
| breakpoint made. */ |
| |
| void |
| end_rbreak_breakpoints (void) |
| { |
| prev_breakpoint_count = rbreak_start_breakpoint_count; |
| } |
| |
| /* Used in run_command to zero the hit count when a new run starts. */ |
| |
| void |
| clear_breakpoint_hit_counts (void) |
| { |
| struct breakpoint *b; |
| |
| ALL_BREAKPOINTS (b) |
| b->hit_count = 0; |
| } |
| |
| /* Allocate a new counted_command_line with reference count of 1. |
| The new structure owns COMMANDS. */ |
| |
| static struct counted_command_line * |
| alloc_counted_command_line (struct command_line *commands) |
| { |
| struct counted_command_line *result |
| = xmalloc (sizeof (struct counted_command_line)); |
| |
| result->refc = 1; |
| result->commands = commands; |
| return result; |
| } |
| |
| /* Increment reference count. This does nothing if CMD is NULL. */ |
| |
| static void |
| incref_counted_command_line (struct counted_command_line *cmd) |
| { |
| if (cmd) |
| ++cmd->refc; |
| } |
| |
| /* Decrement reference count. If the reference count reaches 0, |
| destroy the counted_command_line. Sets *CMDP to NULL. This does |
| nothing if *CMDP is NULL. */ |
| |
| static void |
| decref_counted_command_line (struct counted_command_line **cmdp) |
| { |
| if (*cmdp) |
| { |
| if (--(*cmdp)->refc == 0) |
| { |
| free_command_lines (&(*cmdp)->commands); |
| xfree (*cmdp); |
| } |
| *cmdp = NULL; |
| } |
| } |
| |
| /* A cleanup function that calls decref_counted_command_line. */ |
| |
| static void |
| do_cleanup_counted_command_line (void *arg) |
| { |
| decref_counted_command_line (arg); |
| } |
| |
| /* Create a cleanup that calls decref_counted_command_line on the |
| argument. */ |
| |
| static struct cleanup * |
| make_cleanup_decref_counted_command_line (struct counted_command_line **cmdp) |
| { |
| return make_cleanup (do_cleanup_counted_command_line, cmdp); |
| } |
| |
| |
| /* Return the breakpoint with the specified number, or NULL |
| if the number does not refer to an existing breakpoint. */ |
| |
| struct breakpoint * |
| get_breakpoint (int num) |
| { |
| struct breakpoint *b; |
| |
| ALL_BREAKPOINTS (b) |
| if (b->number == num) |
| return b; |
| |
| return NULL; |
| } |
| |
| |
| |
| /* Mark locations as "conditions have changed" in case the target supports |
| evaluating conditions on its side. */ |
| |
| static void |
| mark_breakpoint_modified (struct breakpoint *b) |
| { |
| struct bp_location *loc; |
| |
| /* This is only meaningful if the target is |
| evaluating conditions and if the user has |
| opted for condition evaluation on the target's |
| side. */ |
| if (gdb_evaluates_breakpoint_condition_p () |
| || !target_supports_evaluation_of_breakpoint_conditions ()) |
| return; |
| |
| if (!is_breakpoint (b)) |
| return; |
| |
| for (loc = b->loc; loc; loc = loc->next) |
| loc->condition_changed = condition_modified; |
| } |
| |
| /* Mark location as "conditions have changed" in case the target supports |
| evaluating conditions on its side. */ |
| |
| static void |
| mark_breakpoint_location_modified (struct bp_location *loc) |
| { |
| /* This is only meaningful if the target is |
| evaluating conditions and if the user has |
| opted for condition evaluation on the target's |
| side. */ |
| if (gdb_evaluates_breakpoint_condition_p () |
| || !target_supports_evaluation_of_breakpoint_conditions ()) |
| |
| return; |
| |
| if (!is_breakpoint (loc->owner)) |
| return; |
| |
| loc->condition_changed = condition_modified; |
| } |
| |
| /* Sets the condition-evaluation mode using the static global |
| condition_evaluation_mode. */ |
| |
| static void |
| set_condition_evaluation_mode (char *args, int from_tty, |
| struct cmd_list_element *c) |
| { |
| const char *old_mode, *new_mode; |
| |
| if ((condition_evaluation_mode_1 == condition_evaluation_target) |
| && !target_supports_evaluation_of_breakpoint_conditions ()) |
| { |
| condition_evaluation_mode_1 = condition_evaluation_mode; |
| warning (_("Target does not support breakpoint condition evaluation.\n" |
| "Using host evaluation mode instead.")); |
| return; |
| } |
| |
| new_mode = translate_condition_evaluation_mode (condition_evaluation_mode_1); |
| old_mode = translate_condition_evaluation_mode (condition_evaluation_mode); |
| |
| /* Flip the switch. Flip it even if OLD_MODE == NEW_MODE as one of the |
| settings was "auto". */ |
| condition_evaluation_mode = condition_evaluation_mode_1; |
| |
| /* Only update the mode if the user picked a different one. */ |
| if (new_mode != old_mode) |
| { |
| struct bp_location *loc, **loc_tmp; |
| /* If the user switched to a different evaluation mode, we |
| need to synch the changes with the target as follows: |
| |
| "host" -> "target": Send all (valid) conditions to the target. |
| "target" -> "host": Remove all the conditions from the target. |
| */ |
| |
| if (new_mode == condition_evaluation_target) |
| { |
| /* Mark everything modified and synch conditions with the |
| target. */ |
| ALL_BP_LOCATIONS (loc, loc_tmp) |
| mark_breakpoint_location_modified (loc); |
| } |
| else |
| { |
| /* Manually mark non-duplicate locations to synch conditions |
| with the target. We do this to remove all the conditions the |
| target knows about. */ |
| ALL_BP_LOCATIONS (loc, loc_tmp) |
| if (is_breakpoint (loc->owner) && loc->inserted) |
| loc->needs_update = 1; |
| } |
| |
| /* Do the update. */ |
| update_global_location_list (1); |
| } |
| |
| return; |
| } |
| |
| /* Shows the current mode of breakpoint condition evaluation. Explicitly shows |
| what "auto" is translating to. */ |
| |
| static void |
| show_condition_evaluation_mode (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, const char *value) |
| { |
| if (condition_evaluation_mode == condition_evaluation_auto) |
| fprintf_filtered (file, |
| _("Breakpoint condition evaluation " |
| "mode is %s (currently %s).\n"), |
| value, |
| breakpoint_condition_evaluation_mode ()); |
| else |
| fprintf_filtered (file, _("Breakpoint condition evaluation mode is %s.\n"), |
| value); |
| } |
| |
| /* A comparison function for bp_location AP and BP that is used by |
| bsearch. This comparison function only cares about addresses, unlike |
| the more general bp_location_compare function. */ |
| |
| static int |
| bp_location_compare_addrs (const void *ap, const void *bp) |
| { |
| struct bp_location *a = *(void **) ap; |
| struct bp_location *b = *(void **) bp; |
| |
| if (a->address == b->address) |
| return 0; |
| else |
| return ((a->address > b->address) - (a->address < b->address)); |
| } |
| |
| /* Helper function to skip all bp_locations with addresses |
| less than ADDRESS. It returns the first bp_location that |
| is greater than or equal to ADDRESS. If none is found, just |
| return NULL. */ |
| |
| static struct bp_location ** |
| get_first_locp_gte_addr (CORE_ADDR address) |
| { |
| struct bp_location dummy_loc; |
| struct bp_location *dummy_locp = &dummy_loc; |
| struct bp_location **locp_found = NULL; |
| |
| /* Initialize the dummy location's address field. */ |
| memset (&dummy_loc, 0, sizeof (struct bp_location)); |
| dummy_loc.address = address; |
| |
| /* Find a close match to the first location at ADDRESS. */ |
| locp_found = bsearch (&dummy_locp, bp_location, bp_location_count, |
| sizeof (struct bp_location **), |
| bp_location_compare_addrs); |
| |
| /* Nothing was found, nothing left to do. */ |
| if (locp_found == NULL) |
| return NULL; |
| |
| /* We may have found a location that is at ADDRESS but is not the first in the |
| location's list. Go backwards (if possible) and locate the first one. */ |
| while ((locp_found - 1) >= bp_location |
| && (*(locp_found - 1))->address == address) |
| locp_found--; |
| |
| return locp_found; |
| } |
| |
| void |
| set_breakpoint_condition (struct breakpoint *b, char *exp, |
| int from_tty) |
| { |
| xfree (b->cond_string); |
| b->cond_string = NULL; |
| |
| if (is_watchpoint (b)) |
| { |
| struct watchpoint *w = (struct watchpoint *) b; |
| |
| xfree (w->cond_exp); |
| w->cond_exp = NULL; |
| } |
| else |
| { |
| struct bp_location *loc; |
| |
| for (loc = b->loc; loc; loc = loc->next) |
| { |
| xfree (loc->cond); |
| loc->cond = NULL; |
| |
| /* No need to free the condition agent expression |
| bytecode (if we have one). We will handle this |
| when we go through update_global_location_list. */ |
| } |
| } |
| |
| if (*exp == 0) |
| { |
| if (from_tty) |
| printf_filtered (_("Breakpoint %d now unconditional.\n"), b->number); |
| } |
| else |
| { |
| char *arg = exp; |
| |
| /* I don't know if it matters whether this is the string the user |
| typed in or the decompiled expression. */ |
| b->cond_string = xstrdup (arg); |
| b->condition_not_parsed = 0; |
| |
| if (is_watchpoint (b)) |
| { |
| struct watchpoint *w = (struct watchpoint *) b; |
| |
| innermost_block = NULL; |
| arg = exp; |
| w->cond_exp = parse_exp_1 (&arg, 0, 0, 0); |
| if (*arg) |
| error (_("Junk at end of expression")); |
| w->cond_exp_valid_block = innermost_block; |
| } |
| else |
| { |
| struct bp_location *loc; |
| |
| for (loc = b->loc; loc; loc = loc->next) |
| { |
| arg = exp; |
| loc->cond = |
| parse_exp_1 (&arg, loc->address, |
| block_for_pc (loc->address), 0); |
| if (*arg) |
| error (_("Junk at end of expression")); |
| } |
| } |
| } |
| mark_breakpoint_modified (b); |
| |
| breakpoints_changed (); |
| observer_notify_breakpoint_modified (b); |
| } |
| |
| /* Completion for the "condition" command. */ |
| |
| static VEC (char_ptr) * |
| condition_completer (struct cmd_list_element *cmd, char *text, char *word) |
| { |
| char *space; |
| |
| text = skip_spaces (text); |
| space = skip_to_space (text); |
| if (*space == '\0') |
| { |
| int len; |
| struct breakpoint *b; |
| VEC (char_ptr) *result = NULL; |
| |
| if (text[0] == '$') |
| { |
| /* We don't support completion of history indices. */ |
| if (isdigit (text[1])) |
| return NULL; |
| return complete_internalvar (&text[1]); |
| } |
| |
| /* We're completing the breakpoint number. */ |
| len = strlen (text); |
| |
| ALL_BREAKPOINTS (b) |
| { |
| int single = b->loc->next == NULL; |
| struct bp_location *loc; |
| int count = 1; |
| |
| for (loc = b->loc; loc; loc = loc->next) |
| { |
| char location[50]; |
| |
| if (single) |
| sprintf (location, "%d", b->number); |
| else |
| sprintf (location, "%d.%d", b->number, count); |
| |
| if (strncmp (location, text, len) == 0) |
| VEC_safe_push (char_ptr, result, xstrdup (location)); |
| |
| ++count; |
| } |
| } |
| |
| return result; |
| } |
| |
| /* We're completing the expression part. */ |
| text = skip_spaces (space); |
| return expression_completer (cmd, text, word); |
| } |
| |
| /* condition N EXP -- set break condition of breakpoint N to EXP. */ |
| |
| static void |
| condition_command (char *arg, int from_tty) |
| { |
| struct breakpoint *b; |
| char *p; |
| int bnum; |
| |
| if (arg == 0) |
| error_no_arg (_("breakpoint number")); |
| |
| p = arg; |
| bnum = get_number (&p); |
| if (bnum == 0) |
| error (_("Bad breakpoint argument: '%s'"), arg); |
| |
| 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); |
| |
| if (is_breakpoint (b)) |
| update_global_location_list (1); |
| |
| return; |
| } |
| |
| error (_("No breakpoint number %d."), bnum); |
| } |
| |
| /* Check that COMMAND do not contain commands that are suitable |
| only for tracepoints and not suitable for ordinary breakpoints. |
| Throw if any such commands is found. */ |
| |
| static void |
| check_no_tracepoint_commands (struct command_line *commands) |
| { |
| struct command_line *c; |
| |
| for (c = commands; c; c = c->next) |
| { |
| int i; |
| |
| if (c->control_type == while_stepping_control) |
| error (_("The 'while-stepping' command can " |
| "only be used for tracepoints")); |
| |
| for (i = 0; i < c->body_count; ++i) |
| check_no_tracepoint_commands ((c->body_list)[i]); |
| |
| /* Not that command parsing removes leading whitespace and comment |
| lines and also empty lines. So, we only need to check for |
| command directly. */ |
| if (strstr (c->line, "collect ") == c->line) |
| error (_("The 'collect' command can only be used for tracepoints")); |
| |
| if (strstr (c->line, "teval ") == c->line) |
| error (_("The 'teval' command can only be used for tracepoints")); |
| } |
| } |
| |
| /* Encapsulate tests for different types of tracepoints. */ |
| |
| static int |
| is_tracepoint_type (enum bptype type) |
| { |
| return (type == bp_tracepoint |
| || type == bp_fast_tracepoint |
| || type == bp_static_tracepoint); |
| } |
| |
| int |
| is_tracepoint (const struct breakpoint *b) |
| { |
| return is_tracepoint_type (b->type); |
| } |
| |
| /* A helper function that validates that COMMANDS are valid for a |
| breakpoint. This function will throw an exception if a problem is |
| found. */ |
| |
| static void |
| validate_commands_for_breakpoint (struct breakpoint *b, |
| struct command_line *commands) |
| { |
| if (is_tracepoint (b)) |
| { |
| /* We need to verify that each top-level element of commands is |
| valid for tracepoints, that there's at most one |
| while-stepping element, and that while-stepping's body has |
| valid tracing commands excluding nested while-stepping. */ |
| struct command_line *c; |
| struct command_line *while_stepping = 0; |
| for (c = commands; c; c = c->next) |
| { |
| if (c->control_type == while_stepping_control) |
| { |
| if (b->type == bp_fast_tracepoint) |
| error (_("The 'while-stepping' command " |
| "cannot be used for fast tracepoint")); |
| else if (b->type == bp_static_tracepoint) |
| error (_("The 'while-stepping' command " |
| "cannot be used for static tracepoint")); |
| |
| if (while_stepping) |
| error (_("The 'while-stepping' command " |
| "can be used only once")); |
| else |
| while_stepping = c; |
| } |
| } |
| if (while_stepping) |
| { |
| struct command_line *c2; |
| |
| gdb_assert (while_stepping->body_count == 1); |
| c2 = while_stepping->body_list[0]; |
| for (; c2; c2 = c2->next) |
| { |
| if (c2->control_type == while_stepping_control) |
| error (_("The 'while-stepping' command cannot be nested")); |
| } |
| } |
| } |
| else |
| { |
| check_no_tracepoint_commands (commands); |
| } |
| } |
| |
| /* Return a vector of all the static tracepoints set at ADDR. The |
| caller is responsible for releasing the vector. */ |
| |
| VEC(breakpoint_p) * |
| static_tracepoints_here (CORE_ADDR addr) |
| { |
| struct breakpoint *b; |
| VEC(breakpoint_p) *found = 0; |
| struct bp_location *loc; |
| |
| ALL_BREAKPOINTS (b) |
| if (b->type == bp_static_tracepoint) |
| { |
| for (loc = b->loc; loc; loc = loc->next) |
| if (loc->address == addr) |
| VEC_safe_push(breakpoint_p, found, b); |
| } |
| |
| return found; |
| } |
| |
| /* Set the command list of B to COMMANDS. If breakpoint is tracepoint, |
| validate that only allowed commands are included. */ |
| |
| void |
| breakpoint_set_commands (struct breakpoint *b, |
| struct command_line *commands) |
| { |
| validate_commands_for_breakpoint (b, commands); |
| |
| decref_counted_command_line (&b->commands); |
| b->commands = alloc_counted_command_line (commands); |
| breakpoints_changed (); |
| observer_notify_breakpoint_modified (b); |
| } |
| |
| /* 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); |
| } |
| |
| /* 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); |
| } |
| |
| /* 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); |
| } |
| |
| void |
| check_tracepoint_command (char *line, void *closure) |
| { |
| struct breakpoint *b = closure; |
| |
| validate_actionline (&line, b); |
| } |
| |
| /* A structure used to pass information through |
| map_breakpoint_numbers. */ |
| |
| struct commands_info |
| { |
| /* True if the command was typed at a tty. */ |
| int from_tty; |
| |
| /* The breakpoint range spec. */ |
| char *arg; |
| |
| /* Non-NULL if the body of the commands are being read from this |
| already-parsed command. */ |
| struct command_line *control; |
| |
| /* The command lines read from the user, or NULL if they have not |
| yet been read. */ |
| struct counted_command_line *cmd; |
| }; |
| |
| /* A callback for map_breakpoint_numbers that sets the commands for |
| commands_command. */ |
| |
| static void |
| do_map_commands_command (struct breakpoint *b, void *data) |
| { |
| struct commands_info *info = data; |
| |
| if (info->cmd == NULL) |
| { |
| struct command_line *l; |
| |
| if (info->control != NULL) |
| l = copy_command_lines (info->control->body_list[0]); |
| else |
| { |
| struct cleanup *old_chain; |
| char *str; |
| |
| str = xstrprintf (_("Type commands for breakpoint(s) " |
| "%s, one per line."), |
| info->arg); |
| |
| old_chain = make_cleanup (xfree, str); |
| |
| l = read_command_lines (str, |
| info->from_tty, 1, |
| (is_tracepoint (b) |
| ? check_tracepoint_command : 0), |
| b); |
| |
| do_cleanups (old_chain); |
| } |
| |
| info->cmd = alloc_counted_command_line (l); |
| } |
| |
| /* If a breakpoint was on the list more than once, we don't need to |
| do anything. */ |
| if (b->commands != info->cmd) |
| { |
| validate_commands_for_breakpoint (b, info->cmd->commands); |
| incref_counted_command_line (info->cmd); |
| decref_counted_command_line (&b->commands); |
| b->commands = info->cmd; |
| breakpoints_changed (); |
| observer_notify_breakpoint_modified (b); |
| } |
| } |
| |
| static void |
| commands_command_1 (char *arg, int from_tty, |
| struct command_line *control) |
| { |
| struct cleanup *cleanups; |
| struct commands_info info; |
| |
| info.from_tty = from_tty; |
| info.control = control; |
| info.cmd = NULL; |
| /* If we read command lines from the user, then `info' will hold an |
| extra reference to the commands that we must clean up. */ |
| cleanups = make_cleanup_decref_counted_command_line (&info.cmd); |
| |
| if (arg == NULL || !*arg) |
| { |
| if (breakpoint_count - prev_breakpoint_count > 1) |
| arg = xstrprintf ("%d-%d", prev_breakpoint_count + 1, |
| breakpoint_count); |
| else if (breakpoint_count > 0) |
| arg = xstrprintf ("%d", breakpoint_count); |
| else |
| { |
| /* So that we don't try to free the incoming non-NULL |
| argument in the cleanup below. Mapping breakpoint |
| numbers will fail in this case. */ |
| arg = NULL; |
| } |
| } |
| else |
| /* The command loop has some static state, so we need to preserve |
| our argument. */ |
| arg = xstrdup (arg); |
| |
| if (arg != NULL) |
| make_cleanup (xfree, arg); |
| |
| info.arg = arg; |
| |
| map_breakpoint_numbers (arg, do_map_commands_command, &info); |
| |
| if (info.cmd == NULL) |
| error (_("No breakpoints specified.")); |
| |
| do_cleanups (cleanups); |
| } |
| |
| static void |
| commands_command (char *arg, int from_tty) |
| { |
| commands_command_1 (arg, from_tty, NULL); |
| } |
| |
| /* Like commands_command, but instead of reading the commands from |
| input stream, takes them from an already parsed command structure. |
| |
| This is used by cli-script.c to DTRT with breakpoint commands |
| that are part of if and while bodies. */ |
| enum command_control_type |
| commands_from_control_command (char *arg, struct command_line *cmd) |
| { |
| commands_command_1 (arg, 0, cmd); |
| return simple_control; |
| } |
| |
| /* Return non-zero if BL->TARGET_INFO contains valid information. */ |
| |
| static int |
| bp_location_has_shadow (struct bp_location *bl) |
| { |
| if (bl->loc_type != bp_loc_software_breakpoint) |
| return 0; |
| if (!bl->inserted) |
| return 0; |
| if (bl->target_info.shadow_len == 0) |
| /* BL isn't valid, or doesn't shadow memory. */ |
| return 0; |
| return 1; |
| } |
| |
| /* Update BUF, which is LEN bytes read from the target address MEMADDR, |
| by replacing any memory breakpoints with their shadowed contents. |
| |
| If READBUF is not NULL, this buffer must not overlap with any of |
| the breakpoint location's shadow_contents buffers. Otherwise, |
| a failed assertion internal error will be raised. |
| |
| The range of shadowed area by each bp_location is: |
| bl->address - bp_location_placed_address_before_address_max |
| up to bl->address + bp_location_shadow_len_after_address_max |
| The range we were requested to resolve shadows for is: |
| memaddr ... memaddr + len |
| Thus the safe cutoff boundaries for performance optimization are |
| memaddr + len <= (bl->address |
| - bp_location_placed_address_before_address_max) |
| and: |
| bl->address + bp_location_shadow_len_after_address_max <= memaddr */ |
| |
| void |
| breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf, |
| const gdb_byte *writebuf_org, |
| ULONGEST memaddr, LONGEST len) |
| { |
| /* Left boundary, right boundary and median element of our binary |
| search. */ |
| unsigned bc_l, bc_r, bc; |
| |
| /* Find BC_L which is a leftmost element which may affect BUF |
| content. It is safe to report lower value but a failure to |
| report higher one. */ |
| |
| bc_l = 0; |
| bc_r = bp_location_count; |
| while (bc_l + 1 < bc_r) |
| { |
| struct bp_location *bl; |
| |
| bc = (bc_l + bc_r) / 2; |
| bl = bp_location[bc]; |
| |
| /* Check first BL->ADDRESS will not overflow due to the added |
| constant. Then advance the left boundary only if we are sure |
| the BC element can in no way affect the BUF content (MEMADDR |
| to MEMADDR + LEN range). |
| |
| Use the BP_LOCATION_SHADOW_LEN_AFTER_ADDRESS_MAX safety |
| offset so that we cannot miss a breakpoint with its shadow |
| range tail still reaching MEMADDR. */ |
| |
| if ((bl->address + bp_location_shadow_len_after_address_max |
| >= bl->address) |
| && (bl->address + bp_location_shadow_len_after_address_max |
| <= memaddr)) |
| bc_l = bc; |
| else |
| bc_r = bc; |
| } |
| |
| /* Due to the binary search above, we need to make sure we pick the |
| first location that's at BC_L's address. E.g., if there are |
| multiple locations at the same address, BC_L may end up pointing |
| at a duplicate location, and miss the "master"/"inserted" |
| location. Say, given locations L1, L2 and L3 at addresses A and |
| B: |
| |
| L1@A, L2@A, L3@B, ... |
| |
| BC_L could end up pointing at location L2, while the "master" |
| location could be L1. Since the `loc->inserted' flag is only set |
| on "master" locations, we'd forget to restore the shadow of L1 |
| and L2. */ |
| while (bc_l > 0 |
| && bp_location[bc_l]->address == bp_location[bc_l - 1]->address) |
| bc_l--; |
| |
| /* Now do full processing of the found relevant range of elements. */ |
| |
| for (bc = bc_l; bc < bp_location_count; bc++) |
| { |
| struct bp_location *bl = bp_location[bc]; |
| CORE_ADDR bp_addr = 0; |
| int bp_size = 0; |
| int bptoffset = 0; |
| |
| /* bp_location array has BL->OWNER always non-NULL. */ |
| if (bl->owner->type == bp_none) |
| warning (_("reading through apparently deleted breakpoint #%d?"), |
| bl->owner->number); |
| |
| /* Performance optimization: any further element can no longer affect BUF |
| content. */ |
| |
| if (bl->address >= bp_location_placed_address_before_address_max |
| && memaddr + len <= (bl->address |
| - bp_location_placed_address_before_address_max)) |
| break; |
| |
| if (!bp_location_has_shadow (bl)) |
| continue; |
| if (!breakpoint_address_match (bl->target_info.placed_address_space, 0, |
| current_program_space->aspace, 0)) |
| continue; |
| |
| /* Addresses and length of the part of the breakpoint that |
| we need to copy. */ |
| bp_addr = bl->target_info.placed_address; |
| bp_size = bl->target_info.shadow_len; |
| |
| if (bp_addr + bp_size <= memaddr) |
| /* The breakpoint is entirely before the chunk of memory we |
| are reading. */ |
| continue; |
| |
| if (bp_addr >= memaddr + len) |
| /* The breakpoint is entirely after the chunk of memory we are |
| reading. */ |
| continue; |
| |
| /* Offset within shadow_contents. */ |
| if (bp_addr < memaddr) |
| { |
| /* Only copy the second part of the breakpoint. */ |
| bp_size -= memaddr - bp_addr; |
| bptoffset = memaddr - bp_addr; |
| bp_addr = memaddr; |
| } |
| |
| if (bp_addr + bp_size > memaddr + len) |
| { |
| /* Only copy the first part of the breakpoint. */ |
| bp_size -= (bp_addr + bp_size) - (memaddr + len); |
| } |
| |
| if (readbuf != NULL) |
| { |
| /* Verify that the readbuf buffer does not overlap with |
| the shadow_contents buffer. */ |
| gdb_assert (bl->target_info.shadow_contents >= readbuf + len |
| || readbuf >= (bl->target_info.shadow_contents |
| + bl->target_info.shadow_len)); |
| |
| /* Update the read buffer with this inserted breakpoint's |
| shadow. */ |
| memcpy (readbuf + bp_addr - memaddr, |
| bl->target_info.shadow_contents + bptoffset, bp_size); |
| } |
| else |
| { |
| struct gdbarch *gdbarch = bl->gdbarch; |
| const unsigned char *bp; |
| CORE_ADDR placed_address = bl->target_info.placed_address; |
| unsigned placed_size = bl->target_info.placed_size; |
| |
| /* Update the shadow with what we want to write to memory. */ |
| memcpy (bl->target_info.shadow_contents + bptoffset, |
| writebuf_org + bp_addr - memaddr, bp_size); |
| |
| /* Determine appropriate breakpoint contents and size for this |
| address. */ |
| bp = gdbarch_breakpoint_from_pc (gdbarch, &placed_address, &placed_size); |
| |
| /* Update the final write buffer with this inserted |
| breakpoint's INSN. */ |
| memcpy (writebuf + bp_addr - memaddr, bp + bptoffset, bp_size); |
| } |
| } |
| } |
| |
| |
| /* Return true if BPT is either a software breakpoint or a hardware |
| breakpoint. */ |
| |
| int |
| is_breakpoint (const struct breakpoint *bpt) |
| { |
| return (bpt->type == bp_breakpoint |
| || bpt->type == bp_hardware_breakpoint |
| || bpt->type == bp_dprintf); |
| } |
| |
| /* Return true if BPT is of any hardware watchpoint kind. */ |
| |
| static int |
| is_hardware_watchpoint (const struct breakpoint *bpt) |
| { |
| return (bpt->type == bp_hardware_watchpoint |
| || bpt->type == bp_read_watchpoint |
| || bpt->type == bp_access_watchpoint); |
| } |
| |
| /* Return true if BPT is of any watchpoint kind, hardware or |
| software. */ |
| |
| int |
| is_watchpoint (const struct breakpoint *bpt) |
| { |
| return (is_hardware_watchpoint (bpt) |
| || bpt->type == bp_watchpoint); |
| } |
| |
| /* Returns true if the current thread and its running state are safe |
| to evaluate or update watchpoint B. Watchpoints on local |
| expressions need to be evaluated in the context of the thread that |
| was current when the watchpoint was created, and, that thread needs |
| to be stopped to be able to select the correct frame context. |
| Watchpoints on global expressions can be evaluated on any thread, |
| and in any state. It is presently left to the target allowing |
| memory accesses when threads are running. */ |
| |
| static int |
| watchpoint_in_thread_scope (struct watchpoint *b) |
| { |
| return (b->base.pspace == current_program_space |
| && (ptid_equal (b->watchpoint_thread, null_ptid) |
| || (ptid_equal (inferior_ptid, b->watchpoint_thread) |
| && !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 watchpoint *w) |
| { |
| struct breakpoint *b = &w->base; |
| |
| 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 |
| - Evaluate the condition if there is one, and store the result |
| in b->loc->cond. |
| - Update the list of values that must be watched in B->loc. |
| |
| If the watchpoint disposition is disp_del_at_next_stop, then do |
| nothing. If this is local watchpoint that is out of scope, delete |
| it. |
| |
| Even with `set breakpoint always-inserted on' the watchpoints are |
| removed + inserted on each stop here. Normal breakpoints must |
| never be removed because they might be missed by a running thread |
| when debugging in non-stop mode. On the other hand, hardware |
| watchpoints (is_hardware_watchpoint; processed here) are specific |
| to each LWP since they are stored in each LWP's hardware debug |
| registers. Therefore, such LWP must be stopped first in order to |
| be able to modify its hardware watchpoints. |
| |
| Hardware watchpoints must be reset exactly once after being |
| presented to the user. It cannot be done sooner, because it would |
| reset the data used to present the watchpoint hit to the user. And |
| it must not be done later because it could display the same single |
| watchpoint hit during multiple GDB stops. Note that the latter is |
| relevant only to the hardware watchpoint types bp_read_watchpoint |
| and bp_access_watchpoint. False hit by bp_hardware_watchpoint is |
| not user-visible - its hit is suppressed if the memory content has |
| not changed. |
| |
| The following constraints influence the location where we can reset |
| hardware watchpoints: |
| |
| * target_stopped_by_watchpoint and target_stopped_data_address are |
| called several times when GDB stops. |
| |
| [linux] |
| * Multiple hardware watchpoints can be hit at the same time, |
| causing GDB to stop. GDB only presents one hardware watchpoint |
| hit at a time as the reason for stopping, and all the other hits |
| are presented later, one after the other, each time the user |
| requests the execution to be resumed. Execution is not resumed |
| for the threads still having pending hit event stored in |
| LWP_INFO->STATUS. While the watchpoint is already removed from |
| the inferior on the first stop the thread hit event is kept being |
| reported from its cached value by linux_nat_stopped_data_address |
| until the real thread resume happens after the watchpoint gets |
| presented and thus its LWP_INFO->STATUS gets reset. |
| |
| Therefore the hardware watchpoint hit can get safely reset on the |
| watchpoint removal from inferior. */ |
| |
| static void |
| update_watchpoint (struct watchpoint *b, int reparse) |
| { |
| int within_current_scope; |
| struct frame_id saved_frame_id; |
| int frame_saved; |
| |
| /* 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; |
| |
| if (b->base.disposition == disp_del_at_next_stop) |
| return; |
| |
| frame_saved = 0; |
| |
| /* Determine if the watchpoint is within scope. */ |
| if (b->exp_valid_block == NULL) |
| within_current_scope = 1; |
| else |
| { |
| 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. */ |
| /* FIXME drow/2003-09-09: It would be nice if evaluate_expression |
| took a frame parameter, so that we didn't have to change the |
| selected frame. */ |
| frame_saved = 1; |
| saved_frame_id = get_frame_id (get_selected_frame (NULL)); |
| |
| fi = frame_find_by_id (b->watchpoint_frame); |
| within_current_scope = (fi != NULL); |
| if (within_current_scope) |
| 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->base.loc = NULL; |
| |
| if (within_current_scope && reparse) |
| { |
| char *s; |
| |
| if (b->exp) |
| { |
| xfree (b->exp); |
| b->exp = NULL; |
| } |
| s = b->exp_string_reparse ? b->exp_string_reparse : b->exp_string; |
| b->exp = parse_exp_1 (&s, 0, b->exp_valid_block, 0); |
| /* If the meaning of expression itself changed, the old value is |
| no longer relevant. We don't want to report a watchpoint hit |
| to the user when the old value and the new value may actually |
| be completely different objects. */ |
| value_free (b->val); |
| b->val = NULL; |
| b->val_valid = 0; |
| |
| /* Note that unlike with breakpoints, the watchpoint's condition |
| expression is stored in the breakpoint object, not in the |
| locations (re)created below. */ |
| if (b->base.cond_string != NULL) |
| { |
| if (b->cond_exp != NULL) |
| { |
| xfree (b->cond_exp); |
| b->cond_exp = NULL; |
| } |
| |
| s = b->base.cond_string; |
| b->cond_exp = parse_exp_1 (&s, 0, b->cond_exp_valid_block, 0); |
| } |
| } |
| |
| /* If we failed to parse the expression, for example because |
| it refers to a global variable in a not-yet-loaded shared library, |
| don't try to insert watchpoint. We don't automatically delete |
| such watchpoint, though, since failure to parse expression |
| is different from out-of-scope watchpoint. */ |
| if ( !target_has_execution) |
| { |
| /* Without execution, memory can't change. No use to try and |
| set watchpoint locations. The watchpoint will be reset when |
| the target gains execution, through breakpoint_re_set. */ |
| } |
| else if (within_current_scope && b->exp) |
| { |
| int pc = 0; |
| struct value *val_chain, *v, *result, *next; |
| struct program_space *frame_pspace; |
| |
| fetch_subexp_value (b->exp, &pc, &v, &result, &val_chain); |
| |
| /* Avoid setting b->val if it's already set. The meaning of |
| b->val is 'the last value' user saw, and we should update |
| it only if we reported that last value to user. As it |
| happens, the code that reports it updates b->val directly. |
| We don't keep track of the memory value for masked |
| watchpoints. */ |
| if (!b->val_valid && !is_masked_watchpoint (&b->base)) |
| { |
| b->val = v; |
| b->val_valid = 1; |
| } |
| |
| frame_pspace = get_frame_program_space (get_selected_frame (NULL)); |
| |
| /* Look at each value on the value chain. */ |
| 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 |
| must watch it. If the first value returned is |
| still lazy, that means an error occurred reading it; |
| watch it anyway in case it becomes readable. */ |
| if (VALUE_LVAL (v) == lval_memory |
| && (v == val_chain || ! value_lazy (v))) |
| { |
| struct type *vtype = check_typedef (value_type (v)); |
| |
| /* We only watch structs and arrays if user asked |
| for it explicitly, never if they just happen to |
| appear in the middle of some value chain. */ |
| if (v == result |
| || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT |
| && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) |
| { |
| CORE_ADDR addr; |
| int len, type; |
| struct bp_location *loc, **tmp; |
| |
| addr = value_address (v); |
| len = TYPE_LENGTH (value_type (v)); |
| type = hw_write; |
| if (b->base.type == bp_read_watchpoint) |
| type = hw_read; |
| else if (b->base.type == bp_access_watchpoint) |
| type = hw_access; |
| |
| loc = allocate_bp_location (&b->base); |
| for (tmp = &(b->base.loc); *tmp != NULL; tmp = &((*tmp)->next)) |
| ; |
| *tmp = loc; |
| loc->gdbarch = get_type_arch (value_type (v)); |
| |
| loc->pspace = frame_pspace; |
| loc->address = addr; |
| loc->length = len; |
| 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 (reparse) |
| { |
| int reg_cnt; |
| enum bp_loc_type loc_type; |
| struct bp_location *bl; |
| |
| reg_cnt = can_use_hardware_watchpoint (val_chain); |
| |
| if (reg_cnt) |
| { |
| int i, target_resources_ok, other_type_used; |
| enum bptype type; |
| |
| /* 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; |
| |
| /* 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. */ |
| |
| /* If this is a software watchpoint, we try to turn it |
| to a hardware one -- count resources as if B was of |
| hardware watchpoint type. */ |
| type = b->base.type; |
| if (type == bp_watchpoint) |
| type = bp_hardware_watchpoint; |
| |
| /* This watchpoint may or may not have been placed on |
| the list yet at this point (it won't be in the list |
| if we're trying to create it for the first time, |
| through watch_command), so always account for it |
| manually. */ |
| |
| /* Count resources used by all watchpoints except B. */ |
| i = hw_watchpoint_used_count_others (&b->base, type, &other_type_used); |
| |
| /* Add in the resources needed for B. */ |
| i += hw_watchpoint_use_count (&b->base); |
| |
| target_resources_ok |
| = target_can_use_hardware_watchpoint (type, i, other_type_used); |
| if (target_resources_ok <= 0) |
| { |
| int sw_mode = b->base.ops->works_in_software_mode (&b->base); |
| |
| if (target_resources_ok == 0 && !sw_mode) |
| error (_("Target does not support this type of " |
| "hardware watchpoint.")); |
| else if (target_resources_ok < 0 && !sw_mode) |
| error (_("There are not enough available hardware " |
| "resources for this watchpoint.")); |
| |
| /* Downgrade to software watchpoint. */ |
| b->base.type = bp_watchpoint; |
| } |
| else |
| { |
| /* If this was a software watchpoint, we've just |
| found we have enough resources to turn it to a |
| hardware watchpoint. Otherwise, this is a |
| nop. */ |
| b->base.type = type; |
| } |
| } |
| else if (!b->base.ops->works_in_software_mode (&b->base)) |
| error (_("Expression cannot be implemented with " |
| "read/access watchpoint.")); |
| else |
| b->base.type = bp_watchpoint; |
| |
| loc_type = (b->base.type == bp_watchpoint? bp_loc_other |
| : bp_loc_hardware_watchpoint); |
| for (bl = b->base.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); |
| } |
| |
| /* If a software watchpoint is not watching any memory, then the |
| above left it without any location set up. But, |
| bpstat_stop_status requires a location to be able to report |
| stops, so make sure there's at least a dummy one. */ |
| if (b->base.type == bp_watchpoint && b->base.loc == NULL) |
| { |
| struct breakpoint *base = &b->base; |
| base->loc = allocate_bp_location (base); |
| base->loc->pspace = frame_pspace; |
| base->loc->address = -1; |
| base->loc->length = -1; |
| base->loc->watchpoint_type = -1; |
| } |
| } |
| 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"), |
| b->base.number); |
| watchpoint_del_at_next_stop (b); |
| } |
| |
| /* Restore the selected frame. */ |
| if (frame_saved) |
| select_frame (frame_find_by_id (saved_frame_id)); |
| } |
| |
| |
| /* Returns 1 iff breakpoint location should be |
| inserted in the inferior. We don't differentiate the type of BL's owner |
| (breakpoint vs. tracepoint), although insert_location in tracepoint's |
| breakpoint_ops is not defined, because in insert_bp_location, |
| tracepoint's insert_location will not be called. */ |
| static int |
| should_be_inserted (struct bp_location *bl) |
| { |
| if (bl->owner == NULL || !breakpoint_enabled (bl->owner)) |
| return 0; |
| |
| if (bl->owner->disposition == disp_del_at_next_stop) |
| return 0; |
| |
| if (!bl->enabled || bl->shlib_disabled || bl->duplicate) |
| return 0; |
| |
| if (user_breakpoint_p (bl->owner) && bl->pspace->executing_startup) |
| return 0; |
| |
| /* This is set for example, when we're attached to the parent of a |
| vfork, and have detached from the child. The child is running |
| free, and we expect it to do an exec or exit, at which point the |
| OS makes the parent schedulable again (and the target reports |
| that the vfork is done). Until the child is done with the shared |
| memory region, do not insert breakpoints in the parent, otherwise |
| the child could still trip on the parent's breakpoints. Since |
| the parent is blocked anyway, it won't miss any breakpoint. */ |
| if (bl->pspace->breakpoints_not_allowed) |
| return 0; |
| |
| return 1; |
| } |
| |
| /* Same as should_be_inserted but does the check assuming |
| that the location is not duplicated. */ |
| |
| static int |
| unduplicated_should_be_inserted (struct bp_location *bl) |
| { |
| int result; |
| const int save_duplicate = bl->duplicate; |
| |
| bl->duplicate = 0; |
| result = should_be_inserted (bl); |
| bl->duplicate = save_duplicate; |
| return result; |
| } |
| |
| /* Parses a conditional described by an expression COND into an |
| agent expression bytecode suitable for evaluation |
| by the bytecode interpreter. Return NULL if there was |
| any error during parsing. */ |
| |
| static struct agent_expr * |
| parse_cond_to_aexpr (CORE_ADDR scope, struct expression *cond) |
| { |
| struct agent_expr *aexpr = NULL; |
| struct cleanup *old_chain = NULL; |
| volatile struct gdb_exception ex; |
| |
| if (!cond) |
| return NULL; |
| |
| /* We don't want to stop processing, so catch any errors |
| that may show up. */ |
| TRY_CATCH (ex, RETURN_MASK_ERROR) |
| { |
| aexpr = gen_eval_for_expr (scope, cond); |
| } |
| |
| if (ex.reason < 0) |
| { |
| /* If we got here, it means the condition could not be parsed to a valid |
| bytecode expression and thus can't be evaluated on the target's side. |
| It's no use iterating through the conditions. */ |
| return NULL; |
| } |
| |
| /* We have a valid agent expression. */ |
| return aexpr; |
| } |
| |
| /* Based on location BL, create a list of breakpoint conditions to be |
| passed on to the target. If we have duplicated locations with different |
| conditions, we will add such conditions to the list. The idea is that the |
| target will evaluate the list of conditions and will only notify GDB when |
| one of them is true. */ |
| |
| static void |
| build_target_condition_list (struct bp_location *bl) |
| { |
| struct bp_location **locp = NULL, **loc2p; |
| int null_condition_or_parse_error = 0; |
| int modified = bl->needs_update; |
| struct bp_location *loc; |
| |
| /* This is only meaningful if the target is |
| evaluating conditions and if the user has |
| opted for condition evaluation on the target's |
| side. */ |
| if (gdb_evaluates_breakpoint_condition_p () |
| || !target_supports_evaluation_of_breakpoint_conditions ()) |
| return; |
| |
| /* Do a first pass to check for locations with no assigned |
| conditions or conditions that fail to parse to a valid agent expression |
| bytecode. If any of these happen, then it's no use to send conditions |
| to the target since this location will always trigger and generate a |
| response back to GDB. */ |
| ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) |
| { |
| loc = (*loc2p); |
| if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num) |
| { |
| if (modified) |
| { |
| struct agent_expr *aexpr; |
| |
| /* Re-parse the conditions since something changed. In that |
| case we already freed the condition bytecodes (see |
| force_breakpoint_reinsertion). We just |
| need to parse the condition to bytecodes again. */ |
| aexpr = parse_cond_to_aexpr (bl->address, loc->cond); |
| loc->cond_bytecode = aexpr; |
| |
| /* Check if we managed to parse the conditional expression |
| correctly. If not, we will not send this condition |
| to the target. */ |
| if (aexpr) |
| continue; |
| } |
| |
| /* If we have a NULL bytecode expression, it means something |
| went wrong or we have a null condition expression. */ |
| if (!loc->cond_bytecode) |
| { |
| null_condition_or_parse_error = 1; |
| break; |
| } |
| } |
| } |
| |
| /* If any of these happened, it means we will have to evaluate the conditions |
| for the location's address on gdb's side. It is no use keeping bytecodes |
| for all the other duplicate locations, thus we free all of them here. |
| |
| This is so we have a finer control over which locations' conditions are |
| being evaluated by GDB or the remote stub. */ |
| if (null_condition_or_parse_error) |
| { |
| ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) |
| { |
| loc = (*loc2p); |
| if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num) |
| { |
| /* Only go as far as the first NULL bytecode is |
| located. */ |
| if (!loc->cond_bytecode) |
| return; |
| |
| free_agent_expr (loc->cond_bytecode); |
| loc->cond_bytecode = NULL; |
| } |
| } |
| } |
| |
| /* No NULL conditions or failed bytecode generation. Build a condition list |
| for this location's address. */ |
| ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) |
| { |
| loc = (*loc2p); |
| if (loc->cond |
| && is_breakpoint (loc->owner) |
| && loc->pspace->num == bl->pspace->num |
| && loc->owner->enable_state == bp_enabled |
| && loc->enabled) |
| /* Add the condition to the vector. This will be used later to send the |
| conditions to the target. */ |
| VEC_safe_push (agent_expr_p, bl->target_info.conditions, |
| loc->cond_bytecode); |
| } |
| |
| return; |
| } |
| |
| /* Parses a command described by string CMD into an agent expression |
| bytecode suitable for evaluation by the bytecode interpreter. |
| Return NULL if there was any error during parsing. */ |
| |
| static struct agent_expr * |
| parse_cmd_to_aexpr (CORE_ADDR scope, char *cmd) |
| { |
| struct cleanup *old_cleanups = 0; |
| struct expression *expr, **argvec; |
| struct agent_expr *aexpr = NULL; |
| struct cleanup *old_chain = NULL; |
| volatile struct gdb_exception ex; |
| char *cmdrest; |
| char *format_start, *format_end; |
| struct format_piece *fpieces; |
| int nargs; |
| struct gdbarch *gdbarch = get_current_arch (); |
| |
| if (!cmd) |
| return NULL; |
| |
| cmdrest = cmd; |
| |
| if (*cmdrest == ',') |
| ++cmdrest; |
| cmdrest = skip_spaces (cmdrest); |
| |
| if (*cmdrest++ != '"') |
| error (_("No format string following the location")); |
| |
| format_start = cmdrest; |
| |
| fpieces = parse_format_string (&cmdrest); |
| |
| old_cleanups = make_cleanup (free_format_pieces_cleanup, &fpieces); |
| |
| format_end = cmdrest; |
| |
| if (*cmdrest++ != '"') |
| error (_("Bad format string, non-terminated '\"'.")); |
| |
| cmdrest = skip_spaces (cmdrest); |
| |
| if (!(*cmdrest == ',' || *cmdrest == '\0')) |
| error (_("Invalid argument syntax")); |
| |
| if (*cmdrest == ',') |
| cmdrest++; |
| cmdrest = skip_spaces (cmdrest); |
| |
| /* For each argument, make an expression. */ |
| |
| argvec = (struct expression **) alloca (strlen (cmd) |
| * sizeof (struct expression *)); |
| |
| nargs = 0; |
| while (*cmdrest != '\0') |
| { |
| char *cmd1; |
| |
| cmd1 = cmdrest; |
| expr = parse_exp_1 (&cmd1, scope, block_for_pc (scope), 1); |
| argvec[nargs++] = expr; |
| cmdrest = cmd1; |
| if (*cmdrest == ',') |
| ++cmdrest; |
| } |
| |
| /* We don't want to stop processing, so catch any errors |
| that may show up. */ |
| TRY_CATCH (ex, RETURN_MASK_ERROR) |
| { |
| aexpr = gen_printf (scope, gdbarch, 0, 0, |
| format_start, format_end - format_start, |
| fpieces, nargs, argvec); |
| } |
| |
| if (ex.reason < 0) |
| { |
| /* If we got here, it means the command could not be parsed to a valid |
| bytecode expression and thus can't be evaluated on the target's side. |
| It's no use iterating through the other commands. */ |
| return NULL; |
| } |
| |
| do_cleanups (old_cleanups); |
| |
| /* We have a valid agent expression, return it. */ |
| return aexpr; |
| } |
| |
| /* Based on location BL, create a list of breakpoint commands to be |
| passed on to the target. If we have duplicated locations with |
| different commands, we will add any such to the list. */ |
| |
| static void |
| build_target_command_list (struct bp_location *bl) |
| { |
| struct bp_location **locp = NULL, **loc2p; |
| int null_command_or_parse_error = 0; |
| int modified = bl->needs_update; |
| struct bp_location *loc; |
| |
| /* For now, limit to agent-style dprintf breakpoints. */ |
| if (bl->owner->type != bp_dprintf |
| || strcmp (dprintf_style, dprintf_style_agent) != 0) |
| return; |
| |
| if (!target_can_run_breakpoint_commands ()) |
| return; |
| |
| /* Do a first pass to check for locations with no assigned |
| conditions or conditions that fail to parse to a valid agent expression |
| bytecode. If any of these happen, then it's no use to send conditions |
| to the target since this location will always trigger and generate a |
| response back to GDB. */ |
| ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) |
| { |
| loc = (*loc2p); |
| if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num) |
| { |
| if (modified) |
| { |
| struct agent_expr *aexpr; |
| |
| /* Re-parse the commands since something changed. In that |
| case we already freed the command bytecodes (see |
| force_breakpoint_reinsertion). We just |
| need to parse the command to bytecodes again. */ |
| aexpr = parse_cmd_to_aexpr (bl->address, |
| loc->owner->extra_string); |
| loc->cmd_bytecode = aexpr; |
| |
| if (!aexpr) |
| continue; |
| } |
| |
| /* If we have a NULL bytecode expression, it means something |
| went wrong or we have a null command expression. */ |
| if (!loc->cmd_bytecode) |
| { |
| null_command_or_parse_error = 1; |
| break; |
| } |
| } |
| } |
| |
| /* If anything failed, then we're not doing target-side commands, |
| and so clean up. */ |
| if (null_command_or_parse_error) |
| { |
| ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) |
| { |
| loc = (*loc2p); |
| if (is_breakpoint (loc->owner) |
| && loc->pspace->num == bl->pspace->num) |
| { |
| /* Only go as far as the first NULL bytecode is |
| located. */ |
| if (!loc->cond_bytecode) |
| return; |
| |
| free_agent_expr (loc->cond_bytecode); |
| loc->cond_bytecode = NULL; |
| } |
| } |
| } |
| |
| /* No NULL commands or failed bytecode generation. Build a command list |
| for this location's address. */ |
| ALL_BP_LOCATIONS_AT_ADDR (loc2p, locp, bl->address) |
| { |
| loc = (*loc2p); |
| if (loc->owner->extra_string |
| && is_breakpoint (loc->owner) |
| && loc->pspace->num == bl->pspace->num |
| && loc->owner->enable_state == bp_enabled |
| && loc->enabled) |
| /* Add the command to the vector. This will be used later |
| to send the commands to the target. */ |
| VEC_safe_push (agent_expr_p, bl->target_info.tcommands, |
| loc->cmd_bytecode); |
| } |
| |
| bl->target_info.persist = 0; |
| /* Maybe flag this location as persistent. */ |
| if (bl->owner->type == bp_dprintf && disconnected_dprintf) |
| bl->target_info.persist = 1; |
| } |
| |
| /* Insert a low-level "breakpoint" of some type. BL is the breakpoint |
| location. Any error messages are printed to TMP_ERROR_STREAM; and |
| DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems. |
| Returns 0 for success, 1 if the bp_location type is not supported or |
| -1 for failure. |
| |
| NOTE drow/2003-09-09: This routine could be broken down to an |
| object-style method for each breakpoint or catchpoint type. */ |
| static int |
| insert_bp_location (struct bp_location *bl, |
| struct ui_file *tmp_error_stream, |
| int *disabled_breaks, |
| int *hw_breakpoint_error) |
| { |
| int val = 0; |
| |
| if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update)) |
| return 0; |
| |
| /* Note we don't initialize bl->target_info, as that wipes out |
| the breakpoint location's shadow_contents if the breakpoint |
| is still inserted at that location. This in turn breaks |
| target_read_memory which depends on these buffers when |
| a memory read is requested at the breakpoint location: |
| Once the target_info has been wiped, we fail to see that |
| we have a breakpoint inserted at that address and thus |
| read the breakpoint instead of returning the data saved in |
| the breakpoint location's shadow contents. */ |
| bl->target_info.placed_address = bl->address; |
| bl->target_info.placed_address_space = bl->pspace->aspace; |
| bl->target_info.length = bl->length; |
| |
| /* When working with target-side conditions, we must pass all the conditions |
| for the same breakpoint address down to the target since GDB will not |
| insert those locations. With a list of breakpoint conditions, the target |
| can decide when to stop and notify GDB. */ |
| |
| if (is_breakpoint (bl->owner)) |
| { |
| build_target_condition_list (bl); |
| build_target_command_list (bl); |
| /* Reset the modification marker. */ |
| bl->needs_update = 0; |
| } |
| |
| if (bl->loc_type == bp_loc_software_breakpoint |
| || bl->loc_type == bp_loc_hardware_breakpoint) |
| { |
| if (bl->owner->type != bp_hardware_breakpoint) |
| { |
| /* If the explicitly specified breakpoint type |
| is not hardware breakpoint, check the memory map to see |
| if the breakpoint address is in read only memory or not. |
| |
| Two important cases are: |
| - location type is not hardware breakpoint, memory |
| is readonly. We change the type of the location to |
| hardware breakpoint. |
| - location type is hardware breakpoint, memory is |
| read-write. This means we've previously made the |
| location hardware one, but then the memory map changed, |
| so we undo. |
| |
| When breakpoints are removed, remove_breakpoints will use |
| location types we've just set here, the only possible |
| problem is that memory map has changed during running |
| program, but it's not going to work anyway with current |
| gdb. */ |
| struct mem_region *mr |
| = lookup_mem_region (bl->target_info.placed_address); |
| |
| if (mr) |
| { |
| if (automatic_hardware_breakpoints) |
| { |
| enum bp_loc_type new_type; |
| |
| if (mr->attrib.mode != MEM_RW) |
| new_type = bp_loc_hardware_breakpoint; |
| else |
| new_type = bp_loc_software_breakpoint; |
| |
| if (new_type != bl->loc_type) |
| { |
| static int said = 0; |
| |
| bl->loc_type = new_type; |
| if (!said) |
| { |
| fprintf_filtered (gdb_stdout, |
| _("Note: automatically using " |
| "hardware breakpoints for " |
| "read-only addresses.\n")); |
| said = 1; |
| } |
| } |
| } |
| else if (bl->loc_type == bp_loc_software_breakpoint |
| && mr->attrib.mode != MEM_RW) |
| warning (_("cannot set software breakpoint " |
| "at readonly address %s"), |
| paddress (bl->gdbarch, bl->address)); |
| } |
| } |
| |
| /* First check to see if we have to handle an overlay. */ |
| if (overlay_debugging == ovly_off |
| || bl->section == NULL |
| || !(section_is_overlay (bl->section))) |
| { |
| /* No overlay handling: just set the breakpoint. */ |
| |
| val = bl->owner->ops->insert_location (bl); |
| } |
| else |
| { |
| /* This breakpoint is in an overlay section. |
| Shall we set a breakpoint at the LMA? */ |
| if (!overlay_events_enabled) |
| { |
| /* Yes -- overlay event support is not active, |
| so we must try to set a breakpoint at the LMA. |
| This will not work for a hardware breakpoint. */ |
| if (bl->loc_type == bp_loc_hardware_breakpoint) |
| warning (_("hardware breakpoint %d not supported in overlay!"), |
| bl->owner->number); |
| else |
| { |
| CORE_ADDR addr = overlay_unmapped_address (bl->address, |
| bl->section); |
| /* Set a software (trap) breakpoint at the LMA. */ |
| bl->overlay_target_info = bl->target_info; |
| bl->overlay_target_info.placed_address = addr; |
| val = target_insert_breakpoint (bl->gdbarch, |
| &bl->overlay_target_info); |
| if (val != 0) |
| fprintf_unfiltered (tmp_error_stream, |
| "Overlay breakpoint %d " |
| "failed: in ROM?\n", |
| bl->owner->number); |
| } |
| } |
| /* Shall we set a breakpoint at the VMA? */ |
| if (section_is_mapped (bl->section)) |
| { |
| /* Yes. This overlay section is mapped into memory. */ |
| val = bl->owner->ops->insert_location (bl); |
| } |
| else |
| { |
| /* No. This breakpoint will not be inserted. |
| No error, but do not mark the bp as 'inserted'. */ |
| return 0; |
| } |
| } |
| |
| if (val) |
| { |
| /* Can't set the breakpoint. */ |
| if (solib_name_from_address (bl->pspace, bl->address)) |
| { |
| /* See also: disable_breakpoints_in_shlibs. */ |
| val = 0; |
| bl->shlib_disabled = 1; |
| observer_notify_breakpoint_modified (bl->owner); |
| if (!*disabled_breaks) |
| { |
| fprintf_unfiltered (tmp_error_stream, |
| "Cannot insert breakpoint %d.\n", |
| bl->owner->number); |
| fprintf_unfiltered (tmp_error_stream, |
| "Temporarily disabling shared " |
| "library breakpoints:\n"); |
| } |
| *disabled_breaks = 1; |
| fprintf_unfiltered (tmp_error_stream, |
| "breakpoint #%d\n", bl->owner->number); |
| } |
| else |
| { |
| if (bl->loc_type == bp_loc_hardware_breakpoint) |
| { |
| *hw_breakpoint_error = 1; |
| fprintf_unfiltered (tmp_error_stream, |
| "Cannot insert hardware " |
| "breakpoint %d.\n", |
| bl->owner->number); |
| } |
| else |
| { |
| fprintf_unfiltered (tmp_error_stream, |
| "Cannot insert breakpoint %d.\n", |
| bl->owner->number); |
| fprintf_filtered (tmp_error_stream, |
| "Error accessing memory address "); |
| fputs_filtered (paddress (bl->gdbarch, bl->address), |
| tmp_error_stream); |
| fprintf_filtered (tmp_error_stream, ": %s.\n", |
| safe_strerror (val)); |
| } |
| |
| } |
| } |
| else |
| bl->inserted = 1; |
| |
| return val; |
| } |
| |
| else if (bl->loc_type == bp_loc_hardware_watchpoint |
| /* NOTE drow/2003-09-08: This state only exists for removing |
| watchpoints. It's not clear that it's necessary... */ |
| && bl->owner->disposition != disp_del_at_next_stop) |
| { |
| 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 && bl->watchpoint_type == hw_read) |
| { |
| struct bp_location *loc, **loc_temp; |
| |
| /* But don't try to insert it, if there's already another |
| hw_access location that would be considered a duplicate |
| of this one. */ |
| ALL_BP_LOCATIONS (loc, loc_temp) |
| if (loc != bl |
| && loc->watchpoint_type == hw_access |
| && watchpoint_locations_match (bl, loc)) |
| { |
| bl->duplicate = 1; |
| bl->inserted = 1; |
| bl->target_info = loc->target_info; |
| bl->watchpoint_type = hw_access; |
| val = 0; |
| break; |
| } |
| |
| if (val == 1) |
| { |
| bl->watchpoint_type = hw_access; |
| val = bl->owner->ops->insert_location (bl); |
| |
| if (val) |
| /* Back to the original value. */ |
| bl->watchpoint_type = hw_read; |
| } |
| } |
| |
| bl->inserted = (val == 0); |
| } |
| |
| else if (bl->owner->type == bp_catchpoint) |
| { |
| 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, |
| so just return success. */ |
| return 0; |
| } |
| |
| return 0; |
| } |
| |
| /* This function is called when program space PSPACE is about to be |
| deleted. It takes care of updating breakpoints to not reference |
| PSPACE anymore. */ |
| |
| void |
| breakpoint_program_space_exit (struct program_space *pspace) |
| { |
| struct breakpoint *b, *b_temp; |
| struct bp_location *loc, **loc_temp; |
| |
| /* Remove any breakpoint that was set through this program space. */ |
| ALL_BREAKPOINTS_SAFE (b, b_temp) |
| { |
| if (b->pspace == pspace) |
| delete_breakpoint (b); |
| } |
| |
| /* Breakpoints set through other program spaces could have locations |
| bound to PSPACE as well. Remove those. */ |
| ALL_BP_LOCATIONS (loc, loc_temp) |
| { |
| struct bp_location *tmp; |
| |
| if (loc->pspace == pspace) |
| { |
| /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */ |
| if (loc->owner->loc == loc) |
| loc->owner->loc = loc->next; |
| else |
| for (tmp = loc->owner->loc; tmp->next != NULL; tmp = tmp->next) |
| if (tmp->next == loc) |
| { |
| tmp->next = loc->next; |
| break; |
| } |
| } |
| } |
| |
| /* Now update the global location list to permanently delete the |
| removed locations above. */ |
| update_global_location_list (0); |
| } |
| |
| /* Make sure all breakpoints are inserted in inferior. |
| Throws exception on any error. |
| A breakpoint that is already inserted won't be inserted |
| again, so calling this function twice is safe. */ |
| void |
| insert_breakpoints (void) |
| { |
| struct breakpoint *bpt; |
| |
| ALL_BREAKPOINTS (bpt) |
| if (is_hardware_watchpoint (bpt)) |
| { |
| struct watchpoint *w = (struct watchpoint *) bpt; |
| |
| update_watchpoint (w, 0 /* don't reparse. */); |
| } |
| |
| update_global_location_list (1); |
| |
| /* update_global_location_list does not insert breakpoints when |
| always_inserted_mode is not enabled. Explicitly insert them |
| now. */ |
| if (!breakpoints_always_inserted_mode ()) |
| insert_breakpoint_locations (); |
| } |
| |
| /* Invoke CALLBACK for each of bp_location. */ |
| |
| void |
| iterate_over_bp_locations (walk_bp_location_callback callback) |
| { |
| struct bp_location *loc, **loc_tmp; |
| |
| ALL_BP_LOCATIONS (loc, loc_tmp) |
| { |
| callback (loc, NULL); |
| } |
| } |
| |
| /* This is used when we need to synch breakpoint conditions between GDB and the |
| target. It is the case with deleting and disabling of breakpoints when using |
| always-inserted mode. */ |
| |
| static void |
| update_inserted_breakpoint_locations (void) |
| { |
| struct bp_location *bl, **blp_tmp; |
| int error_flag = 0; |
| int val = 0; |
| int disabled_breaks = 0; |
| int hw_breakpoint_error = 0; |
| |
| struct ui_file *tmp_error_stream = mem_fileopen (); |
| struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream); |
| |
| /* Explicitly mark the warning -- this will only be printed if |
| there was an error. */ |
| fprintf_unfiltered (tmp_error_stream, "Warning:\n"); |
| |
| save_current_space_and_thread (); |
| |
| ALL_BP_LOCATIONS (bl, blp_tmp) |
| { |
| /* We only want to update software breakpoints and hardware |
| breakpoints. */ |
| if (!is_breakpoint (bl->owner)) |
| continue; |
| |
| /* We only want to update locations that are already inserted |
| and need updating. This is to avoid unwanted insertion during |
| deletion of breakpoints. */ |
| if (!bl->inserted || (bl->inserted && !bl->needs_update)) |
| continue; |
| |
| switch_to_program_space_and_thread (bl->pspace); |
| |
| /* For targets that support global breakpoints, there's no need |
| to select an inferior to insert breakpoint to. In fact, even |
| if we aren't attached to any process yet, we should still |
| insert breakpoints. */ |
| if (!gdbarch_has_global_breakpoints (target_gdbarch) |
| && ptid_equal (inferior_ptid, null_ptid)) |
| continue; |
| |
| val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks, |
| &hw_breakpoint_error); |
| if (val) |
| error_flag = val; |
| } |
| |
| if (error_flag) |
| { |
| target_terminal_ours_for_output (); |
| error_stream (tmp_error_stream); |
| } |
| |
| do_cleanups (cleanups); |
| } |
| |
| /* Used when starting or continuing the program. */ |
| |
| static void |
| insert_breakpoint_locations (void) |
| { |
| struct breakpoint *bpt; |
| struct bp_location *bl, **blp_tmp; |
| int error_flag = 0; |
| int val = 0; |
| int disabled_breaks = 0; |
| int hw_breakpoint_error = 0; |
| |
| struct ui_file *tmp_error_stream = mem_fileopen (); |
| struct cleanup *cleanups = make_cleanup_ui_file_delete (tmp_error_stream); |
| |
| /* Explicitly mark the warning -- this will only be printed if |
| there was an error. */ |
| fprintf_unfiltered (tmp_error_stream, "Warning:\n"); |
| |
| save_current_space_and_thread (); |
| |
| ALL_BP_LOCATIONS (bl, blp_tmp) |
| { |
| if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update)) |
| continue; |
| |
| /* There is no point inserting thread-specific breakpoints if |
| the thread no longer exists. ALL_BP_LOCATIONS bp_location |
| has BL->OWNER always non-NULL. */ |
| if (bl->owner->thread != -1 |
| && !valid_thread_id (bl->owner->thread)) |
| continue; |
| |
| switch_to_program_space_and_thread (bl->pspace); |
| |
| /* For targets that support global breakpoints, there's no need |
| to select an inferior to insert breakpoint to. In fact, even |
| if we aren't attached to any process yet, we should still |
| insert breakpoints. */ |
| if (!gdbarch_has_global_breakpoints (target_gdbarch) |
| && ptid_equal (inferior_ptid, null_ptid)) |
| continue; |
| |
| val = insert_bp_location (bl, tmp_error_stream, &disabled_breaks, |
| &hw_breakpoint_error); |
| if (val) |
| error_flag = val; |
| } |
| |
| /* If we failed to insert all locations of a watchpoint, remove |
| them, as half-inserted watchpoint is of limited use. */ |
| ALL_BREAKPOINTS (bpt) |
| { |
| int some_failed = 0; |
| struct bp_location *loc; |
| |
| if (!is_hardware_watchpoint (bpt)) |
| continue; |
| |
| if (!breakpoint_enabled (bpt)) |
| continue; |
| |
| if (bpt->disposition == disp_del_at_next_stop) |
| continue; |
| |
| for (loc = bpt->loc; loc; loc = loc->next) |
| if (!loc->inserted && should_be_inserted (loc)) |
| { |
| some_failed = 1; |
| break; |
| } |
| if (some_failed) |
| { |
| for (loc = bpt->loc; loc; loc = loc->next) |
| if (loc->inserted) |
| remove_breakpoint (loc, mark_uninserted); |
| |
| hw_breakpoint_error = 1; |
| fprintf_unfiltered (tmp_error_stream, |
| "Could not insert hardware watchpoint %d.\n", |
| bpt->number); |
| error_flag = -1; |
| } |
| } |
| |
| if (error_flag) |
| { |
| /* If a hardware breakpoint or watchpoint was inserted, add a |
| message about possibly exhausted resources. */ |
| if (hw_breakpoint_error) |
| { |
| fprintf_unfiltered (tmp_error_stream, |
| "Could not insert hardware breakpoints:\n\ |
| You may have requested too many hardware breakpoints/watchpoints.\n"); |
| } |
| target_terminal_ours_for_output (); |
| error_stream (tmp_error_stream); |
| } |
| |
| do_cleanups (cleanups); |
| } |
| |
| /* Used when the program stops. |
| Returns zero if successful, or non-zero if there was a problem |
| removing a breakpoint location. */ |
| |
| int |
| remove_breakpoints (void) |
| { |
| struct bp_location *bl, **blp_tmp; |
| int val = 0; |
| |
| ALL_BP_LOCATIONS (bl, blp_tmp) |
| { |
| if (bl->inserted && !is_tracepoint (bl->owner)) |
| val |= remove_breakpoint (bl, mark_uninserted); |
| } |
| return val; |
| } |
| |
| /* Remove breakpoints of process PID. */ |
| |
| int |
| remove_breakpoints_pid (int pid) |
| { |
| struct bp_location *bl, **blp_tmp; |
| int val; |
| struct inferior *inf = find_inferior_pid (pid); |
| |
| ALL_BP_LOCATIONS (bl, blp_tmp) |
| { |
| if (bl->pspace != inf->pspace) |
| continue; |
| |
| if (bl->owner->type == bp_dprintf) |
| continue; |
| |
| if (bl->inserted) |
| { |
| val = remove_breakpoint (bl, mark_uninserted); |
| if (val != 0) |
| return val; |
| } |
| } |
| return 0; |
| } |
| |
| int |
| reattach_breakpoints (int pid) |
| { |
| struct cleanup *old_chain; |
| struct bp_location *bl, **blp_tmp; |
| int val; |
| struct ui_file *tmp_error_stream; |
| int dummy1 = 0, dummy2 = 0; |
| struct inferior *inf; |
| struct thread_info *tp; |
| |
| tp = any_live_thread_of_process (pid); |
| if (tp == NULL) |
| return 1; |
| |
| inf = find_inferior_pid (pid); |
| old_chain = save_inferior_ptid (); |
| |
| inferior_ptid = tp->ptid; |
| |
| tmp_error_stream = mem_fileopen (); |
| make_cleanup_ui_file_delete (tmp_error_stream); |
| |
| ALL_BP_LOCATIONS (bl, blp_tmp) |
| { |
| if (bl->pspace != inf->pspace) |
| continue; |
| |
| if (bl->inserted) |
| { |
| bl->inserted = 0; |
| val = insert_bp_location (bl, tmp_error_stream, &dummy1, &dummy2); |
| if (val != 0) |
| { |
| do_cleanups (old_chain); |
| return val; |
| } |
| } |
| } |
| do_cleanups (old_chain); |
| return 0; |
| } |
| |
| static int internal_breakpoint_number = -1; |
| |
| /* Set the breakpoint number of B, depending on the value of INTERNAL. |
| If INTERNAL is non-zero, the breakpoint number will be populated |
| from internal_breakpoint_number and that variable decremented. |
| Otherwise the breakpoint number will be populated from |
| breakpoint_count and that value incremented. Internal breakpoints |
| do not set the internal var bpnum. */ |
| static void |
| set_breakpoint_number (int internal, struct breakpoint *b) |
| { |
| if (internal) |
| b->number = internal_breakpoint_number--; |
| else |
| { |
| set_breakpoint_count (breakpoint_count + 1); |
| b->number = breakpoint_count; |
| } |
| } |
| |
| static struct breakpoint * |
| create_internal_breakpoint (struct gdbarch *gdbarch, |
| CORE_ADDR address, enum bptype type, |
| const struct breakpoint_ops *ops) |
| { |
| struct symtab_and_line sal; |
| struct breakpoint *b; |
| |
| init_sal (&sal); /* Initialize to zeroes. */ |
| |
| sal.pc = address; |
| sal.section = find_pc_overlay (sal.pc); |
| sal.pspace = current_program_space; |
| |
| b = set_raw_breakpoint (gdbarch, sal, type, ops); |
| b->number = internal_breakpoint_number--; |
| b->disposition = disp_donttouch; |
| |
| 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]; |
| |
| /* True if we have looked for longjmp probes. */ |
| int longjmp_searched; |
| |
| /* SystemTap probe points for longjmp (if any). */ |
| VEC (probe_p) *longjmp_probes; |
| |
| /* Minimal symbol for "std::terminate()" (if any). */ |
| struct minimal_symbol *terminate_msym; |
| |
| /* Minimal symbol for "_Unwind_DebugHook" (if any). */ |
| struct minimal_symbol *exception_msym; |
| |
| /* True if we have looked for exception probes. */ |
| int exception_searched; |
| |
| /* SystemTap probe points for unwinding (if any). */ |
| VEC (probe_p) *exception_probes; |
| }; |
| |
| 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 |
| free_breakpoint_probes (struct objfile *obj, void *data) |
| { |
| struct breakpoint_objfile_data *bp_objfile_data = data; |
| |
| VEC_free (probe_p, bp_objfile_data->longjmp_probes); |
| VEC_free (probe_p, bp_objfile_data->exception_probes); |
| } |
| |
| static void |
| create_overlay_event_breakpoint (void) |
| { |
| struct objfile *objfile; |
| const char *const func_name = "_ovly_debug_event"; |
| |
| ALL_OBJFILES (objfile) |
| { |
| struct breakpoint *b; |
| 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->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; |
| } |
| |
| addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->overlay_msym); |
| b = create_internal_breakpoint (get_objfile_arch (objfile), addr, |
| bp_overlay_event, |
| &internal_breakpoint_ops); |
| b->addr_string = xstrdup (func_name); |
| |
| if (overlay_debugging == ovly_auto) |
| { |
| b->enable_state = bp_enabled; |
| overlay_events_enabled = 1; |
| } |
| else |
| { |
| b->enable_state = bp_disabled; |
| overlay_events_enabled = 0; |
| } |
| } |
| update_global_location_list (1); |
| } |
| |
| static void |
| create_longjmp_master_breakpoint (void) |
| { |
| struct program_space *pspace; |
| struct cleanup *old_chain; |
| |
| old_chain = save_current_program_space (); |
| |
| ALL_PSPACES (pspace) |
| { |
| struct objfile *objfile; |
| |
| set_current_program_space (pspace); |
| |
| ALL_OBJFILES (objfile) |
| { |
| int i; |
| struct gdbarch *gdbarch; |
| struct breakpoint_objfile_data *bp_objfile_data; |
| |
| gdbarch = get_objfile_arch (objfile); |
| if (!gdbarch_get_longjmp_target_p (gdbarch)) |
| continue; |
| |
| bp_objfile_data = get_breakpoint_objfile_data (objfile); |
| |
| if (!bp_objfile_data->longjmp_searched) |
| { |
| bp_objfile_data->longjmp_probes |
| = find_probes_in_objfile (objfile, "libc", "longjmp"); |
| bp_objfile_data->longjmp_searched = 1; |
| } |
| |
| if (bp_objfile_data->longjmp_probes != NULL) |
| { |
| int i; |
| struct probe *probe; |
| struct gdbarch *gdbarch = get_objfile_arch (objfile); |
| |
| for (i = 0; |
| VEC_iterate (probe_p, |
| bp_objfile_data->longjmp_probes, |
| i, probe); |
| ++i) |
| { |
| struct breakpoint *b; |
| |
| b = create_internal_breakpoint (gdbarch, probe->address, |
| bp_longjmp_master, |
| &internal_breakpoint_ops); |
| b->addr_string = xstrdup ("-probe-stap libc:longjmp"); |
| b->enable_state = bp_disabled; |
| } |
| |
| continue; |
| } |
| |
| for (i = 0; i < NUM_LONGJMP_NAMES; i++) |
| { |
| struct breakpoint *b; |
| const char *func_name; |
| CORE_ADDR addr; |
| |
| 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, |
| &internal_breakpoint_ops); |
| 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. */ |
| static void |
| create_std_terminate_master_breakpoint (void) |
| { |
| struct program_space *pspace; |
| 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 breakpoint_objfile_data *bp_objfile_data; |
| |
| bp_objfile_data = get_breakpoint_objfile_data (objfile); |
| |
| 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; |
| } |
| |
| addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->terminate_msym); |
| b = create_internal_breakpoint (get_objfile_arch (objfile), addr, |
| bp_std_terminate_master, |
| &internal_breakpoint_ops); |
| b->addr_string = xstrdup (func_name); |
| b->enable_state = bp_disabled; |
| } |
| } |
| |
| update_global_location_list (1); |
| |
| do_cleanups (old_chain); |
| } |
| |
| /* Install a master breakpoint on the unwinder's debug hook. */ |
| |
| static void |
| create_exception_master_breakpoint (void) |
| { |
| struct objfile *objfile; |
| const char *const func_name = "_Unwind_DebugHook"; |
| |
| ALL_OBJFILES (objfile) |
| { |
| struct breakpoint *b; |
| struct gdbarch *gdbarch; |
| struct breakpoint_objfile_data *bp_objfile_data; |
| CORE_ADDR addr; |
| |
| bp_objfile_data = get_breakpoint_objfile_data (objfile); |
| |
| /* We prefer the SystemTap probe point if it exists. */ |
| if (!bp_objfile_data->exception_searched) |
| { |
| bp_objfile_data->exception_probes |
| = find_probes_in_objfile (objfile, "libgcc", "unwind"); |
| bp_objfile_data->exception_searched = 1; |
| } |
| |
| if (bp_objfile_data->exception_probes != NULL) |
| { |
| struct gdbarch *gdbarch = get_objfile_arch (objfile); |
| int i; |
| struct probe *probe; |
| |
| for (i = 0; |
| VEC_iterate (probe_p, |
| bp_objfile_data->exception_probes, |
| i, probe); |
| ++i) |
| { |
| struct breakpoint *b; |
| |
| b = create_internal_breakpoint (gdbarch, probe->address, |
| bp_exception_master, |
| &internal_breakpoint_ops); |
| b->addr_string = xstrdup ("-probe-stap libgcc:unwind"); |
| b->enable_state = bp_disabled; |
| } |
| |
| continue; |
|