| /* Everything about breakpoints, for GDB. |
| |
| Copyright (C) 1986-2024 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 "arch-utils.h" |
| #include <ctype.h> |
| #include "event-top.h" |
| #include "exceptions.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 "cli/cli-cmds.h" |
| #include "value.h" |
| #include "command.h" |
| #include "inferior.h" |
| #include "infrun.h" |
| #include "gdbthread.h" |
| #include "target.h" |
| #include "language.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 "ui-out.h" |
| #include "cli/cli-script.h" |
| #include "block.h" |
| #include "solib.h" |
| #include "solist.h" |
| #include "observable.h" |
| #include "memattr.h" |
| #include "ada-lang.h" |
| #include "top.h" |
| #include "ui.h" |
| #include "valprint.h" |
| #include "jit.h" |
| #include "parser-defs.h" |
| #include "probe.h" |
| #include "cli/cli-utils.h" |
| #include "stack.h" |
| #include "ax-gdb.h" |
| #include "dummy-frame.h" |
| #include "interps.h" |
| #include "gdbsupport/format.h" |
| #include "thread-fsm.h" |
| #include "tid-parse.h" |
| #include "cli/cli-style.h" |
| #include "cli/cli-decode.h" |
| #include <unordered_set> |
| |
| /* readline include files */ |
| #include "readline/tilde.h" |
| |
| /* readline defines this. */ |
| #undef savestring |
| |
| #include "mi/mi-common.h" |
| #include "extension.h" |
| #include <algorithm> |
| #include "progspace-and-thread.h" |
| #include "gdbsupport/array-view.h" |
| #include <optional> |
| #include "gdbsupport/common-utils.h" |
| |
| /* Prototypes for local functions. */ |
| |
| static void map_breakpoint_numbers (const char *, |
| gdb::function_view<void (breakpoint *)>); |
| |
| static void |
| create_sals_from_location_spec_default (location_spec *locspec, |
| linespec_result *canonical); |
| |
| static void create_breakpoints_sal (struct gdbarch *, |
| struct linespec_result *, |
| gdb::unique_xmalloc_ptr<char>, |
| gdb::unique_xmalloc_ptr<char>, |
| enum bptype, |
| enum bpdisp, int, int, int, |
| int, |
| int, int, int, unsigned); |
| |
| static int can_use_hardware_watchpoint |
| (const std::vector<value_ref_ptr> &vals); |
| |
| static void mention (const breakpoint *); |
| |
| static breakpoint *add_to_breakpoint_chain (std::unique_ptr<breakpoint> &&b); |
| |
| static breakpoint *add_to_breakpoint_chain (std::unique_ptr<breakpoint> &&b); |
| |
| static struct breakpoint * |
| momentary_breakpoint_from_master (struct breakpoint *orig, |
| enum bptype type, |
| int loc_enabled, int thread); |
| |
| static void breakpoint_adjustment_warning (CORE_ADDR, CORE_ADDR, int, bool); |
| |
| static CORE_ADDR adjust_breakpoint_address (struct gdbarch *gdbarch, |
| CORE_ADDR bpaddr, |
| enum bptype bptype, |
| struct program_space *pspace); |
| |
| static bool watchpoint_locations_match (const struct bp_location *loc1, |
| const struct bp_location *loc2); |
| |
| static bool breakpoint_locations_match (const struct bp_location *loc1, |
| const struct bp_location *loc2, |
| bool sw_hw_bps_match = false); |
| |
| static bool breakpoint_location_address_match (struct bp_location *bl, |
| const struct address_space *aspace, |
| CORE_ADDR addr); |
| |
| static bool breakpoint_location_address_range_overlap (struct bp_location *, |
| const address_space *, |
| CORE_ADDR, int); |
| |
| static int remove_breakpoint (struct bp_location *); |
| static int remove_breakpoint_1 (struct bp_location *, enum remove_bp_reason); |
| |
| static enum print_stop_action print_bp_stop_message (bpstat *bs); |
| |
| 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 enable_breakpoint_disp (struct breakpoint *, enum bpdisp, |
| int count); |
| |
| static void decref_bp_location (struct bp_location **loc); |
| |
| static std::vector<symtab_and_line> bkpt_probe_decode_location_spec |
| (struct breakpoint *b, |
| location_spec *locspec, |
| struct program_space *search_pspace); |
| |
| static bool bl_address_is_meaningful (bp_location *loc); |
| |
| static int find_loc_num_by_location (const bp_location *loc); |
| |
| /* update_global_location_list's modes of operation wrt to whether to |
| insert locations now. */ |
| enum ugll_insert_mode |
| { |
| /* Don't insert any breakpoint locations into the inferior, only |
| remove already-inserted locations that no longer should be |
| inserted. Functions that delete a breakpoint or breakpoints |
| should specify this mode, so that deleting a breakpoint doesn't |
| have the side effect of inserting the locations of other |
| breakpoints that are marked not-inserted, but should_be_inserted |
| returns true on them. |
| |
| This behavior is useful is situations close to tear-down -- e.g., |
| after an exec, while the target still has execution, but |
| breakpoint shadows of the previous executable image should *NOT* |
| be restored to the new image; or before detaching, where the |
| target still has execution and wants to delete breakpoints from |
| GDB's lists, and all breakpoints had already been removed from |
| the inferior. */ |
| UGLL_DONT_INSERT, |
| |
| /* May insert breakpoints iff breakpoints_should_be_inserted_now |
| claims breakpoints should be inserted now. */ |
| UGLL_MAY_INSERT, |
| |
| /* Insert locations now, irrespective of |
| breakpoints_should_be_inserted_now. E.g., say all threads are |
| stopped right now, and the user did "continue". We need to |
| insert breakpoints _before_ resuming the target, but |
| UGLL_MAY_INSERT wouldn't insert them, because |
| breakpoints_should_be_inserted_now returns false at that point, |
| as no thread is running yet. */ |
| UGLL_INSERT |
| }; |
| |
| /* Return a textual version of INSERT_MODE. */ |
| |
| static const char * |
| ugll_insert_mode_text (ugll_insert_mode insert_mode) |
| { |
| /* Make sure the compiler warns if a new ugll_insert_mode enumerator is added |
| but not handled here. */ |
| DIAGNOSTIC_PUSH |
| DIAGNOSTIC_ERROR_SWITCH |
| switch (insert_mode) |
| { |
| case UGLL_DONT_INSERT: |
| return "UGLL_DONT_INSERT"; |
| case UGLL_MAY_INSERT: |
| return "UGLL_MAY_INSERT"; |
| case UGLL_INSERT: |
| return "UGLL_INSERT"; |
| } |
| DIAGNOSTIC_POP |
| |
| gdb_assert_not_reached ("must handle all enum values"); |
| } |
| |
| /* Return a textual version of REASON. */ |
| |
| static const char * |
| remove_bp_reason_str (remove_bp_reason reason) |
| { |
| /* Make sure the compiler warns if a new remove_bp_reason enumerator is added |
| but not handled here. */ |
| DIAGNOSTIC_PUSH |
| DIAGNOSTIC_ERROR_SWITCH |
| switch (reason) |
| { |
| case REMOVE_BREAKPOINT: |
| return "regular remove"; |
| case DETACH_BREAKPOINT: |
| return "detach"; |
| } |
| DIAGNOSTIC_POP |
| |
| gdb_assert_not_reached ("must handle all enum values"); |
| } |
| |
| /* Return a textual version of breakpoint location BL describing number, |
| location and address. */ |
| |
| static std::string |
| breakpoint_location_address_str (const bp_location *bl) |
| { |
| std::string str = string_printf ("Breakpoint %d (%s) at address %s", |
| bl->owner->number, |
| host_address_to_string (bl), |
| paddress (bl->gdbarch, bl->address)); |
| |
| std::string loc_string = bl->to_string (); |
| if (!loc_string.empty ()) |
| str += string_printf (" %s", loc_string.c_str ()); |
| |
| return str; |
| } |
| |
| static void update_global_location_list (enum ugll_insert_mode); |
| |
| static void update_global_location_list_nothrow (enum ugll_insert_mode); |
| |
| static void insert_breakpoint_locations (void); |
| |
| static void trace_pass_command (const char *, int); |
| |
| static void set_tracepoint_count (int num); |
| |
| static bool is_masked_watchpoint (const struct breakpoint *b); |
| |
| /* Return true if B refers to a static tracepoint set by marker ("-m"), |
| zero otherwise. */ |
| |
| static bool strace_marker_p (struct breakpoint *b); |
| |
| static void bkpt_probe_create_sals_from_location_spec |
| (location_spec *locspec, |
| struct linespec_result *canonical); |
| |
| const struct breakpoint_ops code_breakpoint_ops = |
| { |
| create_sals_from_location_spec_default, |
| create_breakpoints_sal, |
| }; |
| |
| /* Breakpoints set on probes. */ |
| static const struct breakpoint_ops bkpt_probe_breakpoint_ops = |
| { |
| bkpt_probe_create_sals_from_location_spec, |
| create_breakpoints_sal, |
| }; |
| |
| /* Tracepoints set on probes. We use the same methods as for breakpoints |
| on probes. */ |
| static const struct breakpoint_ops tracepoint_probe_breakpoint_ops = |
| { |
| bkpt_probe_create_sals_from_location_spec, |
| create_breakpoints_sal, |
| }; |
| |
| /* Implementation of abstract dtors. These must exist to satisfy the |
| linker. */ |
| |
| breakpoint::~breakpoint () |
| { |
| } |
| |
| code_breakpoint::~code_breakpoint () |
| { |
| } |
| |
| catchpoint::~catchpoint () |
| { |
| } |
| |
| /* The structure to be used in regular breakpoints. */ |
| struct ordinary_breakpoint : public code_breakpoint |
| { |
| using code_breakpoint::code_breakpoint; |
| |
| int resources_needed (const struct bp_location *) override; |
| enum print_stop_action print_it (const bpstat *bs) const override; |
| void print_mention () const override; |
| void print_recreate (struct ui_file *fp) const override; |
| }; |
| |
| /* Internal breakpoints. These typically have a lifetime the same as |
| the program, and they end up installed on the breakpoint chain with |
| a negative breakpoint number. They're visible in "maint info |
| breakpoints", but not "info breakpoints". */ |
| struct internal_breakpoint : public code_breakpoint |
| { |
| internal_breakpoint (struct gdbarch *gdbarch, |
| enum bptype type, CORE_ADDR address) |
| : code_breakpoint (gdbarch, type) |
| { |
| symtab_and_line sal; |
| sal.pc = address; |
| sal.section = find_pc_overlay (sal.pc); |
| sal.pspace = current_program_space; |
| add_location (sal); |
| |
| pspace = current_program_space; |
| disposition = disp_donttouch; |
| } |
| |
| void re_set () override; |
| void check_status (struct bpstat *bs) override; |
| enum print_stop_action print_it (const bpstat *bs) const override; |
| void print_mention () const override; |
| }; |
| |
| /* Momentary breakpoints. These typically have a lifetime of some run |
| control command only, are always thread-specific, and have 0 for |
| breakpoint number. I.e., there can be many momentary breakpoints |
| on the breakpoint chain and they all same the same number (zero). |
| They're visible in "maint info breakpoints", but not "info |
| breakpoints". */ |
| struct momentary_breakpoint : public code_breakpoint |
| { |
| momentary_breakpoint (struct gdbarch *gdbarch_, enum bptype bptype, |
| program_space *pspace_, |
| const struct frame_id &frame_id_, |
| int thread_) |
| : code_breakpoint (gdbarch_, bptype) |
| { |
| /* If FRAME_ID is valid, it should be a real frame, not an inlined |
| or tail-called one. */ |
| gdb_assert (!frame_id_artificial_p (frame_id)); |
| |
| /* Momentary breakpoints are always thread-specific. */ |
| gdb_assert (thread_ > 0); |
| |
| pspace = pspace_; |
| enable_state = bp_enabled; |
| disposition = disp_donttouch; |
| frame_id = frame_id_; |
| thread = thread_; |
| |
| /* The inferior should have been set by the parent constructor. */ |
| gdb_assert (inferior == -1); |
| } |
| |
| void re_set () override; |
| void check_status (struct bpstat *bs) override; |
| enum print_stop_action print_it (const bpstat *bs) const override; |
| void print_mention () const override; |
| }; |
| |
| /* DPrintf breakpoints. */ |
| struct dprintf_breakpoint : public ordinary_breakpoint |
| { |
| using ordinary_breakpoint::ordinary_breakpoint; |
| |
| void re_set () override; |
| int breakpoint_hit (const struct bp_location *bl, |
| const address_space *aspace, |
| CORE_ADDR bp_addr, |
| const target_waitstatus &ws) override; |
| void print_recreate (struct ui_file *fp) const override; |
| void after_condition_true (struct bpstat *bs) override; |
| }; |
| |
| /* Ranged breakpoints. */ |
| struct ranged_breakpoint : public ordinary_breakpoint |
| { |
| explicit ranged_breakpoint (struct gdbarch *gdbarch, |
| const symtab_and_line &sal_start, |
| int length, |
| location_spec_up start_locspec, |
| location_spec_up end_locspec) |
| : ordinary_breakpoint (gdbarch, bp_hardware_breakpoint) |
| { |
| bp_location *bl = add_location (sal_start); |
| bl->length = length; |
| |
| disposition = disp_donttouch; |
| |
| locspec = std::move (start_locspec); |
| locspec_range_end = std::move (end_locspec); |
| } |
| |
| int breakpoint_hit (const struct bp_location *bl, |
| const address_space *aspace, |
| CORE_ADDR bp_addr, |
| const target_waitstatus &ws) override; |
| int resources_needed (const struct bp_location *) override; |
| enum print_stop_action print_it (const bpstat *bs) const override; |
| bool print_one (const bp_location **) const override; |
| void print_one_detail (struct ui_out *) const override; |
| void print_mention () const override; |
| void print_recreate (struct ui_file *fp) const override; |
| }; |
| |
| /* Static tracepoints with marker (`-m'). */ |
| struct static_marker_tracepoint : public tracepoint |
| { |
| using tracepoint::tracepoint; |
| |
| std::vector<symtab_and_line> decode_location_spec |
| (struct location_spec *locspec, |
| struct program_space *search_pspace) override; |
| }; |
| |
| /* 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 std::string dprintf_function = "printf"; |
| |
| /* 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 std::string dprintf_channel; |
| |
| /* True if dprintf commands should continue to operate even if GDB |
| has disconnected. */ |
| static bool disconnected_dprintf = true; |
| |
| struct command_line * |
| breakpoint_commands (struct breakpoint *b) |
| { |
| return b->commands ? b->commands.get () : NULL; |
| } |
| |
| /* Flag indicating that a command has proceeded the inferior past the |
| current breakpoint. */ |
| |
| static bool 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) |
| { |
| gdb_printf (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) |
| { |
| gdb_printf (file, |
| _("Debugger's behavior regarding " |
| "pending breakpoints is %s.\n"), |
| value); |
| } |
| |
| /* If true, gdb will automatically use hardware breakpoints for breakpoints |
| set with "break" but falling in read-only memory. |
| If false, gdb will warn about such breakpoints, but won't automatically |
| use hardware breakpoints. */ |
| static bool automatic_hardware_breakpoints; |
| static void |
| show_automatic_hardware_breakpoints (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, |
| const char *value) |
| { |
| gdb_printf (file, |
| _("Automatic usage of hardware breakpoints is %s.\n"), |
| value); |
| } |
| |
| /* If on, GDB keeps breakpoints inserted even if the inferior is |
| stopped, and immediately inserts any new breakpoints as soon as |
| they're created. If off (default), GDB keeps breakpoints off of |
| the target as long as possible. That is, it delays inserting |
| breakpoints until the next resume, and removes them again when the |
| target fully stops. This is a bit safer in case GDB crashes while |
| processing user input. */ |
| static bool always_inserted_mode = false; |
| |
| static void |
| show_always_inserted_mode (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, const char *value) |
| { |
| gdb_printf (file, _("Always inserted breakpoint mode is %s.\n"), |
| value); |
| } |
| |
| /* True if breakpoint debug output is enabled. */ |
| static bool debug_breakpoint = false; |
| |
| /* Print a "breakpoint" debug statement. */ |
| #define breakpoint_debug_printf(fmt, ...) \ |
| debug_prefixed_printf_cond (debug_breakpoint, "breakpoint", fmt, \ |
| ##__VA_ARGS__) |
| |
| /* "show debug breakpoint" implementation. */ |
| static void |
| show_debug_breakpoint (struct ui_file *file, int from_tty, |
| struct cmd_list_element *c, const char *value) |
| { |
| gdb_printf (file, _("Breakpoint location debugging is %s.\n"), value); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| int |
| breakpoints_should_be_inserted_now (void) |
| { |
| if (gdbarch_has_global_breakpoints (current_inferior ()->arch ())) |
| { |
| /* If breakpoints are global, they should be inserted even if no |
| thread under gdb's control is running, or even if there are |
| no threads under GDB's control yet. */ |
| return 1; |
| } |
| else |
| { |
| if (always_inserted_mode) |
| { |
| /* The user wants breakpoints inserted even if all threads |
| are stopped. */ |
| return 1; |
| } |
| |
| for (inferior *inf : all_inferiors ()) |
| if (inf->has_execution () |
| && threads_are_executing (inf->process_target ())) |
| return 1; |
| |
| /* Don't remove breakpoints yet if, even though all threads are |
| stopped, we still have events to process. */ |
| for (thread_info *tp : all_non_exited_threads ()) |
| if (tp->resumed () && tp->has_pending_waitstatus ()) |
| return 1; |
| } |
| return 0; |
| } |
| |
| 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 bool |
| gdb_evaluates_breakpoint_condition_p (void) |
| { |
| const char *mode = breakpoint_condition_evaluation_mode (); |
| |
| return (mode == condition_evaluation_host); |
| } |
| |
| /* 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. */ |
| bool target_exact_watchpoints = false; |
| |
| /* Chains of all breakpoints defined. */ |
| |
| static intrusive_list<breakpoint> breakpoint_chain; |
| |
| /* See breakpoint.h. */ |
| |
| breakpoint_range |
| all_breakpoints () |
| { |
| return breakpoint_range (breakpoint_chain.begin (), breakpoint_chain.end ()); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| breakpoint_safe_range |
| all_breakpoints_safe () |
| { |
| return breakpoint_safe_range (all_breakpoints ()); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| tracepoint_range |
| all_tracepoints () |
| { |
| return tracepoint_range (tracepoint_iterator (breakpoint_chain.begin ()), |
| tracepoint_iterator (breakpoint_chain.end ())); |
| } |
| |
| /* Array is sorted by bp_location_is_less_than - primarily by the ADDRESS. */ |
| |
| static std::vector<bp_location *> bp_locations; |
| |
| /* See breakpoint.h. */ |
| |
| const std::vector<bp_location *> & |
| all_bp_locations () |
| { |
| return bp_locations; |
| } |
| |
| /* Range to iterate over breakpoint locations at a given address. */ |
| |
| struct bp_locations_at_addr_range |
| { |
| using iterator = std::vector<bp_location *>::iterator; |
| |
| bp_locations_at_addr_range (CORE_ADDR addr) |
| { |
| struct compare |
| { |
| bool operator() (const bp_location *loc, CORE_ADDR addr_) const |
| { return loc->address < addr_; } |
| |
| bool operator() (CORE_ADDR addr_, const bp_location *loc) const |
| { return addr_ < loc->address; } |
| }; |
| |
| auto it_pair = std::equal_range (bp_locations.begin (), bp_locations.end (), |
| addr, compare ()); |
| |
| m_begin = it_pair.first; |
| m_end = it_pair.second; |
| } |
| |
| iterator begin () const |
| { return m_begin; } |
| |
| iterator end () const |
| { return m_end; } |
| |
| private: |
| iterator m_begin; |
| iterator m_end; |
| }; |
| |
| /* Return a range to iterate over all breakpoint locations exactly at address |
| ADDR. |
| |
| If it's needed to iterate multiple times on the same range, it's possible |
| to save the range in a local variable and use it multiple times: |
| |
| auto range = all_bp_locations_at_addr (addr); |
| |
| for (bp_location *loc : range) |
| // use loc |
| |
| for (bp_location *loc : range) |
| // use loc |
| |
| This saves a bit of time, as it avoids re-doing the binary searches to find |
| the range's boundaries. Just remember not to change the bp_locations vector |
| in the mean time, as it could make the range's iterators stale. */ |
| |
| static bp_locations_at_addr_range |
| all_bp_locations_at_addr (CORE_ADDR addr) |
| { |
| return bp_locations_at_addr_range (addr); |
| } |
| |
| /* Maximum alignment offset between bp_target_info.PLACED_ADDRESS and |
| ADDRESS for the current elements of BP_LOCATIONS which get a valid |
| result from bp_location_has_shadow. You can use it for roughly |
| limiting the subrange of BP_LOCATIONS to scan for shadow bytes for |
| an address you need to read. */ |
| |
| static CORE_ADDR bp_locations_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_LOCATIONS which get a valid result from bp_location_has_shadow. |
| You can use it for roughly limiting the subrange of BP_LOCATIONS to |
| scan for shadow bytes for an address you need to read. */ |
| |
| static CORE_ADDR bp_locations_shadow_len_after_address_max; |
| |
| /* The locations that no longer correspond to any breakpoint, unlinked |
| from the bp_locations array, but for which a hit may still be |
| reported by a target. */ |
| static std::vector<bp_location *> moribund_locations; |
| |
| /* 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 bool |
| 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. */ |
| |
| scoped_rbreak_breakpoints::scoped_rbreak_breakpoints () |
| { |
| rbreak_start_breakpoint_count = breakpoint_count; |
| } |
| |
| /* Called at the end of an "rbreak" command to record the last |
| breakpoint made. */ |
| |
| scoped_rbreak_breakpoints::~scoped_rbreak_breakpoints () |
| { |
| 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) |
| { |
| for (breakpoint &b : all_breakpoints ()) |
| b.hit_count = 0; |
| } |
| |
| |
| /* 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) |
| { |
| for (breakpoint &b : all_breakpoints ()) |
| if (b.number == num) |
| return &b; |
| |
| return nullptr; |
| } |
| |
| /* Return TRUE if NUM refer to an existing breakpoint that has |
| multiple code locations. */ |
| |
| static bool |
| has_multiple_locations (int num) |
| { |
| for (breakpoint &b : all_breakpoints ()) |
| if (b.number == num) |
| return b.has_multiple_locations (); |
| |
| return false; |
| } |
| |
| |
| |
| /* Mark locations as "conditions have changed" in case the target supports |
| evaluating conditions on its side. */ |
| |
| static void |
| mark_breakpoint_modified (struct breakpoint *b) |
| { |
| /* 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 (bp_location &loc : b->locations ()) |
| 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 (const 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) |
| { |
| /* 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. */ |
| for (bp_location *loc : all_bp_locations ()) |
| 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. */ |
| for (bp_location *loc : all_bp_locations ()) |
| if (is_breakpoint (loc->owner) && loc->inserted) |
| loc->needs_update = 1; |
| } |
| |
| /* Do the update. */ |
| update_global_location_list (UGLL_MAY_INSERT); |
| } |
| |
| 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) |
| gdb_printf (file, |
| _("Breakpoint condition evaluation " |
| "mode is %s (currently %s).\n"), |
| value, |
| breakpoint_condition_evaluation_mode ()); |
| else |
| gdb_printf (file, _("Breakpoint condition evaluation mode is %s.\n"), |
| value); |
| } |
| |
| /* Parse COND_STRING in the context of LOC and set as the condition |
| expression of LOC. BP_NUM is the number of LOC's owner, LOC_NUM is |
| the number of LOC within its owner. In case of parsing error, mark |
| LOC as DISABLED_BY_COND. In case of success, unset DISABLED_BY_COND. */ |
| |
| static void |
| set_breakpoint_location_condition (const char *cond_string, bp_location *loc, |
| int bp_num, int loc_num) |
| { |
| bool has_junk = false; |
| try |
| { |
| expression_up new_exp = parse_exp_1 (&cond_string, loc->address, |
| block_for_pc (loc->address), 0); |
| if (*cond_string != 0) |
| has_junk = true; |
| else |
| { |
| loc->cond = std::move (new_exp); |
| if (loc->disabled_by_cond && loc->enabled) |
| gdb_printf (_("Breakpoint %d's condition is now valid at " |
| "location %d, enabling.\n"), |
| bp_num, loc_num); |
| |
| loc->disabled_by_cond = false; |
| } |
| } |
| catch (const gdb_exception_error &e) |
| { |
| if (loc->enabled) |
| { |
| /* Warn if a user-enabled location is now becoming disabled-by-cond. |
| BP_NUM is 0 if the breakpoint is being defined for the first |
| time using the "break ... if ..." command, and non-zero if |
| already defined. */ |
| if (bp_num != 0) |
| warning (_("failed to validate condition at location %d.%d, " |
| "disabling:\n %s"), bp_num, loc_num, e.what ()); |
| else |
| warning (_("failed to validate condition at location %d, " |
| "disabling:\n %s"), loc_num, e.what ()); |
| } |
| |
| loc->disabled_by_cond = true; |
| } |
| |
| if (has_junk) |
| error (_("Garbage '%s' follows condition"), cond_string); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| void |
| notify_breakpoint_modified (breakpoint *b) |
| { |
| interps_notify_breakpoint_modified (b); |
| gdb::observers::breakpoint_modified.notify (b); |
| } |
| |
| void |
| set_breakpoint_condition (struct breakpoint *b, const char *exp, |
| int from_tty, bool force) |
| { |
| if (*exp == 0) |
| { |
| b->cond_string.reset (); |
| |
| if (is_watchpoint (b)) |
| gdb::checked_static_cast<watchpoint *> (b)->cond_exp.reset (); |
| else |
| { |
| int loc_num = 1; |
| for (bp_location &loc : b->locations ()) |
| { |
| loc.cond.reset (); |
| if (loc.disabled_by_cond && loc.enabled) |
| gdb_printf (_("Breakpoint %d's condition is now valid at " |
| "location %d, enabling.\n"), |
| b->number, loc_num); |
| loc.disabled_by_cond = false; |
| loc_num++; |
| |
| /* 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 (from_tty) |
| gdb_printf (_("Breakpoint %d now unconditional.\n"), b->number); |
| } |
| else |
| { |
| if (is_watchpoint (b)) |
| { |
| innermost_block_tracker tracker; |
| const char *arg = exp; |
| expression_up new_exp = parse_exp_1 (&arg, 0, 0, 0, &tracker); |
| if (*arg != 0) |
| error (_("Junk at end of expression")); |
| watchpoint *w = gdb::checked_static_cast<watchpoint *> (b); |
| w->cond_exp = std::move (new_exp); |
| w->cond_exp_valid_block = tracker.block (); |
| } |
| else |
| { |
| /* Parse and set condition expressions. We make two passes. |
| In the first, we parse the condition string to see if it |
| is valid in at least one location. If so, the condition |
| would be accepted. So we go ahead and set the locations' |
| conditions. In case no valid case is found, we throw |
| the error and the condition string will be rejected. |
| This two-pass approach is taken to avoid setting the |
| state of locations in case of a reject. */ |
| for (const bp_location &loc : b->locations ()) |
| { |
| try |
| { |
| const char *arg = exp; |
| parse_exp_1 (&arg, loc.address, |
| block_for_pc (loc.address), 0); |
| if (*arg != 0) |
| error (_("Junk at end of expression")); |
| break; |
| } |
| catch (const gdb_exception_error &e) |
| { |
| /* Condition string is invalid. If this happens to |
| be the last loc, abandon (if not forced) or continue |
| (if forced). */ |
| if (&loc == &b->last_loc () && !force) |
| throw; |
| } |
| } |
| |
| /* If we reach here, the condition is valid at some locations. */ |
| int loc_num = 1; |
| for (bp_location &loc : b->locations ()) |
| { |
| set_breakpoint_location_condition (exp, &loc, b->number, loc_num); |
| loc_num++; |
| } |
| } |
| |
| /* We know that the new condition parsed successfully. The |
| condition string of the breakpoint can be safely updated. */ |
| b->cond_string = make_unique_xstrdup (exp); |
| b->condition_not_parsed = 0; |
| } |
| mark_breakpoint_modified (b); |
| |
| notify_breakpoint_modified (b); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| void |
| set_breakpoint_condition (int bpnum, const char *exp, int from_tty, |
| bool force) |
| { |
| for (breakpoint &b : all_breakpoints ()) |
| if (b.number == bpnum) |
| { |
| /* Check if this breakpoint has a "stop" method implemented in an |
| extension language. This method and conditions entered into GDB |
| from the CLI are mutually exclusive. */ |
| const struct extension_language_defn *extlang |
| = get_breakpoint_cond_ext_lang (&b, EXT_LANG_NONE); |
| |
| if (extlang != NULL) |
| { |
| error (_("Only one stop condition allowed. There is currently" |
| " a %s stop condition defined for this breakpoint."), |
| ext_lang_capitalized_name (extlang)); |
| } |
| set_breakpoint_condition (&b, exp, from_tty, force); |
| |
| if (is_breakpoint (&b)) |
| update_global_location_list (UGLL_MAY_INSERT); |
| |
| return; |
| } |
| |
| error (_("No breakpoint number %d."), bpnum); |
| } |
| |
| /* The options for the "condition" command. */ |
| |
| struct condition_command_opts |
| { |
| /* For "-force". */ |
| bool force_condition = false; |
| }; |
| |
| static const gdb::option::option_def condition_command_option_defs[] = { |
| |
| gdb::option::flag_option_def<condition_command_opts> { |
| "force", |
| [] (condition_command_opts *opts) { return &opts->force_condition; }, |
| N_("Set the condition even if it is invalid for all current locations."), |
| }, |
| |
| }; |
| |
| /* Create an option_def_group for the "condition" options, with |
| CC_OPTS as context. */ |
| |
| static inline gdb::option::option_def_group |
| make_condition_command_options_def_group (condition_command_opts *cc_opts) |
| { |
| return {{condition_command_option_defs}, cc_opts}; |
| } |
| |
| /* Completion for the "condition" command. */ |
| |
| static void |
| condition_completer (struct cmd_list_element *cmd, |
| completion_tracker &tracker, |
| const char *text, const char * /*word*/) |
| { |
| bool has_no_arguments = (*text == '\0'); |
| condition_command_opts cc_opts; |
| const auto group = make_condition_command_options_def_group (&cc_opts); |
| if (gdb::option::complete_options |
| (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group)) |
| return; |
| |
| text = skip_spaces (text); |
| const char *space = skip_to_space (text); |
| if (*space == '\0') |
| { |
| int len; |
| |
| if (text[0] == '$') |
| { |
| tracker.advance_custom_word_point_by (1); |
| /* We don't support completion of history indices. */ |
| if (!isdigit (text[1])) |
| complete_internalvar (tracker, &text[1]); |
| return; |
| } |
| |
| /* Suggest the "-force" flag if no arguments are given. If |
| arguments were passed, they either already include the flag, |
| or we are beyond the point of suggesting it because it's |
| positionally the first argument. */ |
| if (has_no_arguments) |
| gdb::option::complete_on_all_options (tracker, group); |
| |
| /* We're completing the breakpoint number. */ |
| len = strlen (text); |
| |
| for (breakpoint &b : all_breakpoints ()) |
| { |
| char number[50]; |
| |
| xsnprintf (number, sizeof (number), "%d", b.number); |
| |
| if (strncmp (number, text, len) == 0) |
| tracker.add_completion (make_unique_xstrdup (number)); |
| } |
| |
| return; |
| } |
| |
| /* We're completing the expression part. Skip the breakpoint num. */ |
| const char *exp_start = skip_spaces (space); |
| tracker.advance_custom_word_point_by (exp_start - text); |
| text = exp_start; |
| const char *word = advance_to_expression_complete_word_point (tracker, text); |
| expression_completer (cmd, tracker, text, word); |
| } |
| |
| /* condition N EXP -- set break condition of breakpoint N to EXP. */ |
| |
| static void |
| condition_command (const char *arg, int from_tty) |
| { |
| const char *p; |
| int bnum; |
| |
| if (arg == 0) |
| error_no_arg (_("breakpoint number")); |
| |
| p = arg; |
| |
| /* Check if the "-force" flag was passed. */ |
| condition_command_opts cc_opts; |
| const auto group = make_condition_command_options_def_group (&cc_opts); |
| gdb::option::process_options |
| (&p, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group); |
| |
| bnum = get_number (&p); |
| if (bnum == 0) |
| error (_("Bad breakpoint argument: '%s'"), arg); |
| |
| set_breakpoint_condition (bnum, p, from_tty, cc_opts.force_condition); |
| } |
| |
| /* 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) |
| { |
| if (c->control_type == while_stepping_control) |
| error (_("The 'while-stepping' command can " |
| "only be used for tracepoints")); |
| |
| check_no_tracepoint_commands (c->body_list_0.get ()); |
| check_no_tracepoint_commands (c->body_list_1.get ()); |
| |
| /* 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")); |
| } |
| } |
| |
| struct longjmp_breakpoint : public momentary_breakpoint |
| { |
| using momentary_breakpoint::momentary_breakpoint; |
| |
| ~longjmp_breakpoint () override; |
| }; |
| |
| /* Encapsulate tests for different types of tracepoints. */ |
| |
| static bool |
| is_tracepoint_type (bptype type) |
| { |
| return (type == bp_tracepoint |
| || type == bp_fast_tracepoint |
| || type == bp_static_tracepoint |
| || type == bp_static_marker_tracepoint); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| bool |
| is_tracepoint (const struct breakpoint *b) |
| { |
| return is_tracepoint_type (b->type); |
| } |
| |
| /* Factory function to create an appropriate instance of breakpoint given |
| TYPE. */ |
| |
| template<typename... Arg> |
| static std::unique_ptr<code_breakpoint> |
| new_breakpoint_from_type (struct gdbarch *gdbarch, bptype type, |
| Arg&&... args) |
| { |
| code_breakpoint *b; |
| |
| switch (type) |
| { |
| case bp_breakpoint: |
| case bp_hardware_breakpoint: |
| b = new ordinary_breakpoint (gdbarch, type, |
| std::forward<Arg> (args)...); |
| break; |
| |
| case bp_fast_tracepoint: |
| case bp_static_tracepoint: |
| case bp_tracepoint: |
| b = new tracepoint (gdbarch, type, |
| std::forward<Arg> (args)...); |
| break; |
| |
| case bp_static_marker_tracepoint: |
| b = new static_marker_tracepoint (gdbarch, type, |
| std::forward<Arg> (args)...); |
| break; |
| |
| case bp_dprintf: |
| b = new dprintf_breakpoint (gdbarch, type, |
| std::forward<Arg> (args)...); |
| break; |
| |
| default: |
| gdb_assert_not_reached ("invalid type"); |
| } |
| |
| return std::unique_ptr<code_breakpoint> (b); |
| } |
| |
| /* 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)) |
| { |
| tracepoint *t = gdb::checked_static_cast<tracepoint *> (b); |
| struct command_line *c; |
| struct command_line *while_stepping = 0; |
| |
| /* Reset the while-stepping step count. The previous commands |
| might have included a while-stepping action, while the new |
| ones might not. */ |
| t->step_count = 0; |
| |
| /* 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 the while-stepping's body |
| has valid tracing commands excluding nested while-stepping. |
| We also need to validate the tracepoint action line in the |
| context of the tracepoint --- validate_actionline actually |
| has side effects, like setting the tracepoint's |
| while-stepping STEP_COUNT, in addition to checking if the |
| collect/teval actions parse and make sense in the |
| tracepoint's context. */ |
| 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 |
| || b->type == bp_static_marker_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; |
| } |
| |
| validate_actionline (c->line, t); |
| } |
| if (while_stepping) |
| { |
| struct command_line *c2; |
| |
| gdb_assert (while_stepping->body_list_1 == nullptr); |
| c2 = while_stepping->body_list_0.get (); |
| 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. */ |
| |
| std::vector<breakpoint *> |
| static_tracepoints_here (CORE_ADDR addr) |
| { |
| std::vector<breakpoint *> found; |
| |
| for (breakpoint &b : all_breakpoints ()) |
| if (b.type == bp_static_tracepoint |
| || b.type == bp_static_marker_tracepoint) |
| { |
| for (bp_location &loc : b.locations ()) |
| if (loc.address == addr) |
| found.push_back (&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, |
| counted_command_line &&commands) |
| { |
| validate_commands_for_breakpoint (b, commands.get ()); |
| |
| b->commands = std::move (commands); |
| 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) |
| notify_breakpoint_modified (b); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| void |
| breakpoint_set_thread (struct breakpoint *b, int thread) |
| { |
| /* THREAD should be -1, meaning no thread restriction, or it should be a |
| valid global thread-id, which are greater than zero. */ |
| gdb_assert (thread == -1 || thread > 0); |
| |
| /* It is not valid to set a thread restriction for a breakpoint that |
| already has task or inferior restriction. */ |
| gdb_assert (thread == -1 || (b->task == -1 && b->inferior == -1)); |
| |
| int old_thread = b->thread; |
| b->thread = thread; |
| if (old_thread != thread) |
| notify_breakpoint_modified (b); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| void |
| breakpoint_set_inferior (struct breakpoint *b, int inferior) |
| { |
| /* INFERIOR should be -1, meaning no inferior restriction, or it should |
| be a valid inferior number, which are greater than zero. */ |
| gdb_assert (inferior == -1 || inferior > 0); |
| |
| /* It is not valid to set an inferior restriction for a breakpoint that |
| already has a task or thread restriction. */ |
| gdb_assert (inferior == -1 || (b->task == -1 && b->thread == -1)); |
| |
| int old_inferior = b->inferior; |
| b->inferior = inferior; |
| if (old_inferior != inferior) |
| notify_breakpoint_modified (b); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| void |
| breakpoint_set_task (struct breakpoint *b, int task) |
| { |
| /* TASK should be -1, meaning no task restriction, or it should be a |
| valid task-id, which are greater than zero. */ |
| gdb_assert (task == -1 || task > 0); |
| |
| /* It is not valid to set a task restriction for a breakpoint that |
| already has a thread or inferior restriction. */ |
| gdb_assert (task == -1 || (b->thread == -1 && b->inferior == -1)); |
| |
| int old_task = b->task; |
| b->task = task; |
| if (old_task != task) |
| notify_breakpoint_modified (b); |
| } |
| |
| static void |
| commands_command_1 (const char *arg, int from_tty, |
| struct command_line *control) |
| { |
| counted_command_line cmd; |
| /* cmd_read will be true once we have read cmd. Note that cmd might still be |
| NULL after the call to read_command_lines if the user provides an empty |
| list of command by just typing "end". */ |
| bool cmd_read = false; |
| |
| std::string new_arg; |
| |
| if (arg == NULL || !*arg) |
| { |
| /* Argument not explicitly given. Synthesize it. */ |
| if (breakpoint_count - prev_breakpoint_count > 1) |
| new_arg = string_printf ("%d-%d", prev_breakpoint_count + 1, |
| breakpoint_count); |
| else if (breakpoint_count > 0) |
| new_arg = string_printf ("%d", breakpoint_count); |
| } |
| else |
| { |
| /* Create a copy of ARG. This is needed because the "commands" |
| command may be coming from a script. In that case, the read |
| line buffer is going to be overwritten in the lambda of |
| 'map_breakpoint_numbers' below when reading the next line |
| before we are are done parsing the breakpoint numbers. */ |
| new_arg = arg; |
| } |
| arg = new_arg.c_str (); |
| |
| map_breakpoint_numbers |
| (arg, [&] (breakpoint *b) |
| { |
| if (!cmd_read) |
| { |
| gdb_assert (cmd == NULL); |
| if (control != NULL) |
| cmd = control->body_list_0; |
| else |
| { |
| std::string str |
| = string_printf (_("Type commands for breakpoint(s) " |
| "%s, one per line."), |
| arg); |
| |
| auto do_validate = [=] (const char *line) |
| { |
| tracepoint *t |
| = gdb::checked_static_cast<tracepoint *> (b); |
| validate_actionline (line, t); |
| }; |
| gdb::function_view<void (const char *)> validator; |
| if (is_tracepoint (b)) |
| validator = do_validate; |
| |
| cmd = read_command_lines (str.c_str (), from_tty, 1, validator); |
| } |
| cmd_read = true; |
| } |
| |
| /* If a breakpoint was on the list more than once, we don't need to |
| do anything. */ |
| if (b->commands != cmd) |
| { |
| validate_commands_for_breakpoint (b, cmd.get ()); |
| b->commands = cmd; |
| notify_breakpoint_modified (b); |
| } |
| }); |
| } |
| |
| static void |
| commands_command (const 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 (const char *arg, struct command_line *cmd) |
| { |
| commands_command_1 (arg, 0, cmd); |
| return simple_control; |
| } |
| |
| /* Return true if BL->TARGET_INFO contains valid information. */ |
| |
| static bool |
| bp_location_has_shadow (struct bp_location *bl) |
| { |
| if (bl->loc_type != bp_loc_software_breakpoint) |
| return false; |
| if (!bl->inserted) |
| return false; |
| if (bl->target_info.shadow_len == 0) |
| /* BL isn't valid, or doesn't shadow memory. */ |
| return false; |
| return true; |
| } |
| |
| /* Update BUF, which is LEN bytes read from the target address |
| MEMADDR, by replacing a memory breakpoint with its shadowed |
| contents. |
| |
| If READBUF is not NULL, this buffer must not overlap with the of |
| the breakpoint location's shadow_contents buffer. Otherwise, a |
| failed assertion internal error will be raised. */ |
| |
| static void |
| one_breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf, |
| const gdb_byte *writebuf_org, |
| ULONGEST memaddr, LONGEST len, |
| struct bp_target_info *target_info, |
| struct gdbarch *gdbarch) |
| { |
| /* Now do full processing of the found relevant range of elements. */ |
| CORE_ADDR bp_addr = 0; |
| int bp_size = 0; |
| int bptoffset = 0; |
| |
| if (!breakpoint_address_match (target_info->placed_address_space, 0, |
| current_program_space->aspace.get (), 0)) |
| { |
| /* The breakpoint is inserted in a different address space. */ |
| return; |
| } |
| |
| /* Addresses and length of the part of the breakpoint that |
| we need to copy. */ |
| bp_addr = target_info->placed_address; |
| bp_size = target_info->shadow_len; |
| |
| if (bp_addr + bp_size <= memaddr) |
| { |
| /* The breakpoint is entirely before the chunk of memory we are |
| reading. */ |
| return; |
| } |
| |
| if (bp_addr >= memaddr + len) |
| { |
| /* The breakpoint is entirely after the chunk of memory we are |
| reading. */ |
| return; |
| } |
| |
| /* 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 (target_info->shadow_contents >= readbuf + len |
| || readbuf >= (target_info->shadow_contents |
| + target_info->shadow_len)); |
| |
| /* Update the read buffer with this inserted breakpoint's |
| shadow. */ |
| memcpy (readbuf + bp_addr - memaddr, |
| target_info->shadow_contents + bptoffset, bp_size); |
| } |
| else |
| { |
| const unsigned char *bp; |
| CORE_ADDR addr = target_info->reqstd_address; |
| int placed_size; |
| |
| /* Update the shadow with what we want to write to memory. */ |
| memcpy (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, &addr, &placed_size); |
| |
| /* Update the final write buffer with this inserted |
| breakpoint's INSN. */ |
| memcpy (writebuf + bp_addr - memaddr, bp + bptoffset, bp_size); |
| } |
| } |
| |
| /* 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_locations_placed_address_before_address_max |
| up to bl->address + bp_locations_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_locations_placed_address_before_address_max) |
| and: |
| bl->address + bp_locations_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_locations.size (); |
| while (bc_l + 1 < bc_r) |
| { |
| struct bp_location *bl; |
| |
| bc = (bc_l + bc_r) / 2; |
| bl = bp_locations[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_LOCATIONS_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_locations_shadow_len_after_address_max |
| >= bl->address) |
| && (bl->address + bp_locations_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_locations[bc_l]->address == bp_locations[bc_l - 1]->address) |
| bc_l--; |
| |
| /* Now do full processing of the found relevant range of elements. */ |
| |
| for (bc = bc_l; bc < bp_locations.size (); bc++) |
| { |
| struct bp_location *bl = bp_locations[bc]; |
| |
| /* 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_locations_placed_address_before_address_max |
| && (memaddr + len |
| <= (bl->address |
| - bp_locations_placed_address_before_address_max))) |
| break; |
| |
| if (!bp_location_has_shadow (bl)) |
| continue; |
| |
| one_breakpoint_xfer_memory (readbuf, writebuf, writebuf_org, |
| memaddr, len, &bl->target_info, bl->gdbarch); |
| } |
| } |
| |
| /* See breakpoint.h. */ |
| |
| bool |
| 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 bool |
| is_hardware_watchpoint (const struct breakpoint *bpt) |
| { |
| return (bpt->type == bp_hardware_watchpoint |
| || bpt->type == bp_read_watchpoint |
| || bpt->type == bp_access_watchpoint); |
| } |
| |
| /* See breakpoint.h. */ |
| |
| bool |
| 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 bool |
| watchpoint_in_thread_scope (struct watchpoint *b) |
| { |
| return (b->pspace == current_program_space |
| && (b->watchpoint_thread == null_ptid |
| || (inferior_ptid == b->watchpoint_thread |
| && !inferior_thread ()->executing ()))); |
| } |
| |
| /* 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) |
| { |
| if (w->related_breakpoint != w) |
| { |
| gdb_assert (w->related_breakpoint->type == bp_watchpoint_scope); |
| gdb_assert (w->related_breakpoint->related_breakpoint == w); |
| w->related_breakpoint->disposition = disp_del_at_next_stop; |
| w->related_breakpoint->related_breakpoint = w->related_breakpoint; |
| w->related_breakpoint = w; |
| } |
| w->disposition = disp_del_at_next_stop; |
| disable_breakpoint (w); |
| } |
| |
| /* Extract a bitfield value from value VAL using the bit parameters contained in |
| watchpoint W. */ |
| |
| static struct value * |
| extract_bitfield_from_watchpoint_value (struct watchpoint *w, struct value *val) |
| { |
| struct value *bit_val; |
| |
| if (val == NULL) |
| return NULL; |
| |
| bit_val = value::allocate (val->type ()); |
| |
| val->unpack_bitfield (bit_val, |
| w->val_bitpos, |
| w->val_bitsize, |
| val->contents_for_printing ().data (), |
| val->offset ()); |
| |
| return bit_val; |
| } |
| |
| /* Allocate a dummy location and add it to B. This is required |
| because bpstat_stop_status requires a location to be able to report |
| stops. */ |
| |
| static void |
| add_dummy_location (struct breakpoint *b, |
| struct program_space *pspace) |
| { |
| gdb_assert (!b->has_locations ()); |
| |
| bp_location *loc = new bp_location (b, bp_loc_other); |
| loc->pspace = pspace; |
| b->add_location (*loc); |
| } |
| |
| /* Assuming that B is a watchpoint: |
| - Reparse watchpoint expression, if REPARSE is true |
| - 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, bool reparse) |
| { |
| bool within_current_scope; |
| |
| /* 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->disposition == disp_del_at_next_stop) |
| return; |
| |
| std::optional<scoped_restore_selected_frame> restore_frame; |
| |
| /* Determine if the watchpoint is within scope. */ |
| if (b->exp_valid_block == NULL) |
| within_current_scope = true; |
| else |
| { |
| frame_info_ptr fi = get_current_frame (); |
| struct gdbarch *frame_arch = get_frame_arch (fi); |
| CORE_ADDR frame_pc = get_frame_pc (fi); |
| |
| /* If we're at a point where the stack has been destroyed |
| (e.g. in a function epilogue), unwinding may not work |
| properly. Do not attempt to recreate locations at this |
| point. See similar comments in watchpoint_check. */ |
| if (gdbarch_stack_frame_destroyed_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. */ |
| restore_frame.emplace (); |
| |
| 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->clear_locations (); |
| |
| if (within_current_scope && reparse) |
| { |
| const char *s; |
| |
| b->exp.reset (); |
| s = (b->exp_string_reparse |
| ? b->exp_string_reparse.get () |
| : b->exp_string.get ()); |
| 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. */ |
| b->val = NULL; |
| b->val_valid = false; |
| |
| /* 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->cond_string != NULL) |
| { |
| b->cond_exp.reset (); |
| |
| s = b->cond_string.get (); |
| 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. */ |
| if (!can_use_hw_watchpoints) |
| { |
| if (b->works_in_software_mode ()) |
| b->type = bp_watchpoint; |
| else |
| error (_("Can't set read/access watchpoint when " |
| "hardware watchpoints are disabled.")); |
| } |
| } |
| else if (within_current_scope && b->exp) |
| { |
| std::vector<value_ref_ptr> val_chain; |
| struct value *v, *result; |
| struct program_space *wp_pspace; |
| |
| fetch_subexp_value (b->exp.get (), b->exp->op.get (), &v, &result, |
| &val_chain, false); |
| |
| /* 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)) |
| { |
| if (b->val_bitsize != 0) |
| v = extract_bitfield_from_watchpoint_value (b, v); |
| b->val = release_value (v); |
| b->val_valid = true; |
| } |
| |
| if (b->exp_valid_block == nullptr) |
| wp_pspace = current_program_space; |
| else |
| wp_pspace = get_frame_program_space (get_selected_frame (NULL)); |
| |
| /* Look at each value on the value chain. */ |
| gdb_assert (!val_chain.empty ()); |
| for (const value_ref_ptr &iter : val_chain) |
| { |
| v = iter.get (); |
| |
| /* 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 (v->lval () == lval_memory |
| && (v == val_chain[0] || ! v->lazy ())) |
| { |
| struct type *vtype = check_typedef (v->type ()); |
| |
| /* 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 |
| || (vtype->code () != TYPE_CODE_STRUCT |
| && vtype->code () != TYPE_CODE_ARRAY)) |
| { |
| CORE_ADDR addr; |
| enum target_hw_bp_type type; |
| int bitpos = 0, bitsize = 0; |
| |
| if (v->bitsize () != 0) |
| { |
| /* Extract the bit parameters out from the bitfield |
| sub-expression. */ |
| bitpos = v->bitpos (); |
| bitsize = v->bitsize (); |
| } |
| else if (v == result && b->val_bitsize != 0) |
| { |
| /* If VAL_BITSIZE != 0 then RESULT is actually a bitfield |
| lvalue whose bit parameters are saved in the fields |
| VAL_BITPOS and VAL_BITSIZE. */ |
| bitpos = b->val_bitpos; |
| bitsize = b->val_bitsize; |
| } |
| |
| addr = v->address (); |
| if (bitsize != 0) |
| { |
| /* Skip the bytes that don't contain the bitfield. */ |
| addr += bitpos / 8; |
| } |
| |
| type = hw_write; |
| if (b->type == bp_read_watchpoint) |
| type = hw_read; |
| else if (b->type == bp_access_watchpoint) |
| type = hw_access; |
| |
| bp_location *loc = b->allocate_location (); |
| loc->gdbarch = v->type ()->arch (); |
| loc->pspace = wp_pspace; |
| loc->address |
| = gdbarch_remove_non_address_bits (loc->gdbarch, addr); |
| b->add_location (*loc); |
| |
| if (bitsize != 0) |
| { |
| /* Just cover the bytes that make up the bitfield. */ |
| loc->length = ((bitpos % 8) + bitsize + 7) / 8; |
| } |
| else |
| loc->length = v->type ()->length (); |
| |
| loc->watchpoint_type = type; |
| } |
| } |
| } |
| |
| /* Helper function to bundle possibly emitting a warning along with |
| changing the type of B to bp_watchpoint. */ |
| auto change_type_to_bp_watchpoint = [] (breakpoint *bp) |
| { |
| /* Only warn for breakpoints that have been assigned a +ve number, |
| anything else is either an internal watchpoint (which we don't |
| currently create) or has not yet been finalized, in which case |
| this change of type will be occurring before the user is told |
| the type of this watchpoint. */ |
| if (bp->type == bp_hardware_watchpoint && bp->number > 0) |
| warning (_("watchpoint %d downgraded to software watchpoint"), |
| bp->number); |
| bp->type = bp_watchpoint; |
| }; |
| |
| /* Change the type of breakpoint between hardware assisted or |
| an ordinary watchpoint depending on the hardware support and |
| free hardware slots. Recheck the number of free hardware slots |
| as the value chain may have changed. */ |
| { |
| int reg_cnt; |
| enum bp_loc_type loc_type; |
| |
| 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->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, type, &other_type_used); |
| |
| /* Add in the resources needed for B. */ |
| i += hw_watchpoint_use_count (b); |
| |
| target_resources_ok |
| = target_can_use_hardware_watchpoint (type, i, other_type_used); |
| if (target_resources_ok <= 0) |
| { |
| bool sw_mode = b->works_in_software_mode (); |
| |
| 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. */ |
| change_type_to_bp_watchpoint (b); |
| } |
| 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->type = type; |
| } |
| } |
| else if (!b->works_in_software_mode ()) |
| { |
| if (!can_use_hw_watchpoints) |
| error (_("Can't set read/access watchpoint when " |
| "hardware watchpoints are disabled.")); |
| else |
| error (_("Expression cannot be implemented with " |
| "read/access watchpoint.")); |
| } |
| else |
| change_type_to_bp_watchpoint (b); |
| |
| loc_type = (b->type == bp_watchpoint? bp_loc_software_watchpoint |
| : bp_loc_hardware_watchpoint); |
| |
| for (bp_location &bl : b->locations ()) |
| bl.loc_type = loc_type; |
| } |
| |
| /* 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->type == bp_watchpoint && !b->has_locations ()) |
| add_dummy_location (b, wp_pspace); |
| } |
| else if (!within_current_scope) |
| { |
| gdb_printf (_("\ |
| Watchpoint %d deleted because the program has left the block\n\ |
| in which its expression is valid.\n"), |
| b->number); |
| watchpoint_del_at_next_stop (b); |
| } |
| } |
| |
| /* Returns true 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 bool |
| should_be_inserted (struct bp_location *bl) |
| { |
| if (bl->owner == NULL || !breakpoint_enabled (bl->owner)) |
| return false; |
| |
| if (bl->owner->disposition == disp_del_at_next_stop) |
| return false; |
| |
| if (!bl->enabled || bl->disabled_by_cond |
| || bl->shlib_disabled || bl->duplicate) |
| return false; |
| |
| if (user_breakpoint_p (bl->owner) && bl->pspace->executing_startup) |
| return false; |
| |
| /* 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 false; |
| |
| /* Don't insert a breakpoint if we're trying to step past its |
| location, except if the breakpoint is a single-step breakpoint, |
| and the breakpoint's thread is the thread which is stepping past |
| a breakpoint. */ |
| if ((bl->loc_type == bp_loc_software_breakpoint |
| || bl->loc_type == bp_loc_hardware_breakpoint) |
| && stepping_past_instruction_at (bl->pspace->aspace.get (), |
| bl->address) |
| /* The single-step breakpoint may be inserted at the location |
| we're trying to step if the instruction branches to itself. |
| However, the instruction won't be executed at all and it may |
| break the semantics of the instruction, for example, the |
| instruction is a conditional branch or updates some flags. |
| We can't fix it unless GDB is able to emulate the instruction |
| or switch to displaced stepping. */ |
| && !(bl->owner->type == bp_single_step |
| && thread_is_stepping_over_breakpoint (bl->owner->thread))) |
| { |
| infrun_debug_printf ("skipping breakpoint: stepping past insn at: %s", |
| paddress (bl->gdbarch, bl->address)); |
| return false; |
| } |
| |
| /* Don't insert watchpoints if we're trying to step past the |
| instruction that triggered one. */ |
| if ((bl->loc_type == bp_loc_hardware_watchpoint) |
| && stepping_past_nonsteppable_watchpoint ()) |
| { |
| infrun_debug_printf ("stepping past non-steppable watchpoint. " |
| "skipping watchpoint at %s:%d", |
| paddress (bl->gdbarch, bl->address), bl->length); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* Same as should_be_inserted but does the check assuming |
| that the location is not duplicated. */ |
| |
| static bool |
| unduplicated_should_be_inserted (struct bp_location *bl) |
| { |
| scoped_restore restore_bl_duplicate |
| = make_scoped_restore (&bl->duplicate, 0); |
| |
| return should_be_inserted (bl); |
| } |
| |
| /* 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 agent_expr_up |
| parse_cond_to_aexpr (CORE_ADDR scope, struct expression *cond) |
| { |
| if (cond == NULL) |
| return NULL; |
| |
| agent_expr_up aexpr; |
| |
| /* We don't want to stop processing, so catch any errors |
| that may show up. */ |
| try |
| { |
| aexpr = gen_eval_for_expr (scope, cond); |
| } |
| |
| catch (const gdb_exception_error &ex) |
| { |
| /* 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. */ |
| } |
| |
| /* 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) |
| { |
| bool null_condition_or_parse_error = false; |
| int modified = bl->needs_update; |
| |
| /* Release conditions left over from a previous insert. */ |
| bl->target_info.conditions.clear (); |
| |
| /* 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; |
| |
| auto loc_range = all_bp_locations_at_addr (bl->address); |
| |
| /* 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. Note we consider |
| all locations at the same address irrespective of type, i.e., |
| even if the locations aren't considered duplicates (e.g., |
| software breakpoint and hardware breakpoint at the same |
| address). */ |
| for (bp_location *loc : loc_range) |
| { |
| if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num) |
| { |
| if (modified) |
| { |
| /* 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. */ |
| loc->cond_bytecode = parse_cond_to_aexpr (bl->address, |
| loc->cond.get ()); |
| } |
| |
| /* 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 = true; |
| 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) |
| { |
| for (bp_location *loc : loc_range) |
| { |
| 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; |
| |
| loc->cond_bytecode.reset (); |
| } |
| } |
| } |
| |
| /* No NULL conditions or failed bytecode generation. Build a |
| condition list for this location's address. If we have software |
| and hardware locations at the same address, they aren't |
| considered duplicates, but we still merge all the conditions |
| anyway, as it's simpler, and doesn't really make a practical |
| difference. */ |
| for (bp_location *loc : loc_range) |
| if (loc->cond |
| && is_breakpoint (loc->owner) |
| && loc->pspace->num == bl->pspace->num |
| && loc->owner->enable_state == bp_enabled |
| && loc->enabled |
| && !loc->disabled_by_cond) |
| { |
| /* Add the condition to the vector. This will be used later |
| to send the conditions to the target. */ |
| bl->target_info.conditions.push_back (loc->cond_bytecode.get ()); |
| } |
| |
| 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 agent_expr_up |
| parse_cmd_to_aexpr (CORE_ADDR scope, char *cmd) |
| { |
| const char *cmdrest; |
| const char *format_start, *format_end; |
| struct gdbarch *gdbarch = get_current_arch (); |
| |
| if (cmd == NULL) |
| return NULL; |
| |
| cmdrest = cmd; |
| |
| if (*cmdrest == ',') |
| ++cmdrest; |
| cmdrest = skip_spaces (cmdrest); |
| |
| if (*cmdrest++ != '"') |
| error (_("No format string following the location")); |
| |
| format_start = cmdrest; |
| |
| format_pieces fpieces (&cmdrest); |
| |
| 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. */ |
| |
| std::vector<struct expression *> argvec; |
| while (*cmdrest != '\0') |
| { |
| const char *cmd1; |
| |
| cmd1 = cmdrest; |
| expression_up expr = parse_exp_1 (&cmd1, scope, block_for_pc (scope), |
| PARSER_COMMA_TERMINATES); |
| argvec.push_back (expr.release ()); |
| cmdrest = cmd1; |
| if (*cmdrest == ',') |
| ++cmdrest; |
| } |
| |
| agent_expr_up aexpr; |
| |
| /* We don't want to stop processing, so catch any errors |
| that may show up. */ |
| try |
| { |
| aexpr = gen_printf (scope, gdbarch, 0, 0, |
| format_start, format_end - format_start, |
| argvec.size (), argvec.data ()); |
| } |
| catch (const gdb_exception_error &ex) |
| { |
| /* 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. */ |
| } |
| |
| /* 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) |
| { |
| bool null_command_or_parse_error = false; |
| int modified = bl->needs_update; |
| |
| /* Clear commands left over from a previous insert. */ |
| bl->target_info.tcommands.clear (); |
| |
| if (!target_can_run_breakpoint_commands ()) |
| return; |
| |
| /* For now, limit to agent-style dprintf breakpoints. */ |
| if (dprintf_style != dprintf_style_agent) |
| return; |
| |
| auto loc_range = all_bp_locations_at_addr (bl->address); |
| |
| /* For now, if we have any location at the same address that isn't a |
| dprintf, don't install the target-side commands, as that would |
| make the breakpoint not be reported to the core, and we'd lose |
| control. */ |
| for (bp_location *loc : loc_range) |
| if (is_breakpoint (loc->owner) |
| && loc->pspace->num == bl->pspace->num |
| && loc->owner->type != bp_dprintf) |
| 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. */ |
| for (bp_location *loc : loc_range) |
| { |
| if (is_breakpoint (loc->owner) && loc->pspace->num == bl->pspace->num) |
| { |
| if (modified) |
| { |
| /* 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. */ |
| loc->cmd_bytecode |
| = parse_cmd_to_aexpr (bl->address, |
| loc->owner->extra_string.get ()); |
| } |
| |
| /* 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 = true; |
| break; |
| } |
| } |
| } |
| |
| /* If anything failed, then we're not doing target-side commands, |
| and so clean up. */ |
| if (null_command_or_parse_error) |
| { |
| for (bp_location *loc : loc_range) |
| if (is_breakpoint (loc->owner) |
| && loc->pspace->num == bl->pspace->num) |
| { |
| /* Only go as far as the first NULL bytecode is |
| located. */ |
| if (loc->cmd_bytecode == NULL) |
| return; |
| |
| loc->cmd_bytecode.reset (); |
| } |
| } |
| |
| /* No NULL commands or failed bytecode generation. Build a command |
| list for all duplicate locations at this location's address. |
| Note that here we must care for whether the breakpoint location |
| types are considered duplicates, otherwise, say, if we have a |
| software and hardware location at the same address, the target |
| could end up running the commands twice. For the moment, we only |
| support targets-side commands with dprintf, but it doesn't hurt |
| to be pedantically correct in case that changes. */ |
| for (bp_location *loc : loc_range) |
| if (breakpoint_locations_match (bl, loc) |
| && loc->owner->extra_string |
| && is_breakpoint (loc->owner) |
| && loc->pspace->num == bl->pspace->num |
| && loc->owner->enable_state == bp_enabled |
| && loc->enabled |
| && !loc->disabled_by_cond) |
| { |
| /* Add the command to the vector. This will be used later |
| to send the commands to the target. */ |
| bl->target_info.tcommands.push_back (loc->cmd_bytecode.get ()); |
| } |
| |
| bl->target_info.persist = 0; |
| /* Maybe flag this location as persistent. */ |
| if (bl->owner->type == bp_dprintf && disconnected_dprintf) |
| bl->target_info.persist = 1; |
| } |
| |
| /* Return the kind of breakpoint on address *ADDR. Get the kind |
| of breakpoint according to ADDR except single-step breakpoint. |
| Get the kind of single-step breakpoint according to the current |
| registers state. */ |
| |
| static int |
| breakpoint_kind (const struct bp_location *bl, CORE_ADDR *addr) |
| { |
| if (bl->owner->type == bp_single_step) |
| { |
| struct thread_info *thr = find_thread_global_id (bl->owner->thread); |
| struct regcache *regcache; |
| |
| regcache = get_thread_regcache (thr); |
| |
| return gdbarch_breakpoint_kind_from_current_state (bl->gdbarch, |
| regcache, addr); |
| } |
| else |
| return gdbarch_breakpoint_kind_from_pc (bl->gdbarch, addr); |
| } |
| |
| /* Rethrow the currently handled exception, if it's a TARGET_CLOSE_ERROR. |
| E is either the currently handled exception, or a copy, or a sliced copy, |
| so we can't rethrow that one, but we can use it to inspect the properties |
| of the currently handled exception. */ |
| |
| static void |
| rethrow_on_target_close_error (const gdb_exception &e) |
| { |
| if (e.reason == 0) |
| return; |
| /* Can't set the breakpoint. */ |
| |
| if (e.error != TARGET_CLOSE_ERROR) |
| return; |
| |
| /* If the target has closed then it will have deleted any breakpoints |
| inserted within the target inferior, as a result any further attempts |
| to interact with the breakpoint objects is not possible. Just rethrow |
| the error. Don't use e to rethrow, to prevent object slicing of the |
| exception. */ |
| throw; |
| } |
| |
| /* 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 *hw_bp_error_explained_already) |
| { |
| gdb_exception bp_excpt; |
| |
| if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update)) |
| return 0; |
| |
| breakpoint_debug_printf ("%s", breakpoint_location_address_str (bl).c_str ()); |
| |
| /* 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.reqstd_address = bl->address; |
| bl->target_info.placed_address_space = bl->pspace->aspace.get (); |
| 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 "set breakpoint auto-hw" is "on" and a software breakpoint was |
| set at a read-only address, then a breakpoint location will have |
| been changed to hardware breakpoint before we get here. If it is |
| "off" however, error out before actually trying to insert the |
| breakpoint, with a nicer error message. */ |
| if (bl->loc_type == bp_loc_software_breakpoint |
| && !automatic_hardware_breakpoints) |
| { |
| mem_region *mr = lookup_mem_region (bl->address); |
| |
| if (mr != nullptr && mr->attrib.mode != MEM_RW) |
| { |
| gdb_printf (tmp_error_stream, |
| _("Cannot insert breakpoint %d.\n" |
| "Cannot set software breakpoint " |
| "at read-only address %s\n"), |
| bl->owner->number, |
| paddress (bl->gdbarch, bl->address)); |
| return 1; |
| } |
| } |
| |
| if (bl->loc_type == bp_loc_software_breakpoint |
| || bl->loc_type == bp_loc_hardware_breakpoint) |
| { |
| /* 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. */ |
| try |
| { |
| int val; |
| |
| val = bl->owner->insert_location (bl); |
| if (val) |
| bp_excpt = gdb_exception {RETURN_ERROR, GENERIC_ERROR}; |
| } |
| catch (gdb_exception &e) |
| { |
| rethrow_on_target_close_error (e); |
| bp_excpt = std::move (e); |
| } |
| } |
| 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.reqstd_address = addr; |
| |
| /* No overlay handling: just set the breakpoint. */ |
| try |
| { |
| int val; |
| |
| bl->overlay_target_info.kind |
| = breakpoint_kind (bl, &addr); |
| bl->overlay_target_info.placed_address = addr; |
| val = target_insert_breakpoint (bl->gdbarch, |
| &bl->overlay_target_info); |
| if (val) |
| bp_excpt |
| = gdb_exception {RETURN_ERROR, GENERIC_ERROR}; |
| } |
| catch (gdb_exception &e) |
| { |
| rethrow_on_target_close_error (e); |
| bp_excpt = std::move (e); |
| } |
| |
| if (bp_excpt.reason != 0) |
| gdb_printf (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. */ |
| try |
| { |
| int val; |
| |
| val = bl->owner->insert_location (bl); |
| if (val) |
| bp_excpt = gdb_exception {RETURN_ERROR, GENERIC_ERROR}; |
| } |
| catch (gdb_exception_error &e) |
| { |
| rethrow_on_target_close_error (e); |
| bp_excpt = std::move (e); |
| } |
| } |
| else |
| { |
| /* No. This breakpoint will not be inserted. |
| No error, but do not mark the bp as 'inserted'. */ |
| return 0; |
| } |
| } |
| |
| if (bp_excpt.reason != 0) |
| { |
| /* Can't set the breakpoint. */ |
| gdb_assert (bl->owner != nullptr); |
| |
| /* In some cases, we might not be able to insert a |
| breakpoint in a shared library that has already been |
| removed, but we have not yet processed the shlib unload |
| event. Unfortunately, some targets that implement |
| breakpoint insertion themselves can't tell why the |
| breakpoint insertion failed (e.g., the remote target |
| doesn't define error codes), so we must treat generic |
| errors as memory errors. */ |
| if (bp_excpt.reason == RETURN_ERROR |
| && (bp_excpt.error == GENERIC_ERROR |
| || bp_excpt.error == MEMORY_ERROR) |
| && bl->loc_type == bp_loc_software_breakpoint |
| && (solib_name_from_address (bl->pspace, bl->address) |
| || shared_objfile_contains_address_p (bl->pspace, |
| bl->address))) |
| { |
| /* See also: disable_breakpoints_in_shlibs. */ |
| bl->shlib_disabled = 1; |
| notify_breakpoint_modified (bl->owner); |
| if (!*disabled_breaks) |
| { |
| gdb_printf (tmp_error_stream, |
| "Cannot insert breakpoint %d.\n", |
| bl->owner->number); |
| gdb_printf (tmp_error_stream, |
| "Temporarily disabling shared " |
| "library breakpoints:\n"); |
| } |
| *disabled_breaks = 1; |
| gdb_printf (tmp_error_stream, |
| "breakpoint #%d\n", bl->owner->number); |
| return 0; |
| } |
| else |
| { |
| if (bl->loc_type == bp_loc_hardware_breakpoint) |
| { |
| *hw_breakpoint_error = 1; |
| *hw_bp_error_explained_already = bp_excpt.message != NULL; |
| gdb_printf (tmp_error_stream, |
| "Cannot insert hardware breakpoint %d%s", |
| bl->owner->number, |
| bp_excpt.message ? ":" : ".\n"); |
| if (bp_excpt.message != NULL) |
| gdb_printf (tmp_error_stream, "%s.\n", |
| bp_excpt.what ()); |
| } |
| else |
| { |
| if (bp_excpt.message == NULL) |
| { |
| std::string message |
| = memory_error_message (TARGET_XFER_E_IO, |
| bl->gdbarch, bl->address); |
| |
| gdb_printf (tmp_error_stream, |
| "Cannot insert breakpoint %d.\n" |
| "%s\n", |
| bl->owner->number, message.c_str ()); |
| } |
| else |
| { |
| gdb_printf (tmp_error_stream, |
| "Cannot insert breakpoint %d: %s\n", |
| bl->owner->number, |
| bp_excpt.what ()); |
| } |
| } |
| return 1; |
| |
| } |
| } |
| else |
| bl->inserted = 1; |
| |
| return 0; |
| } |
| |
| else if (bl->loc_type == bp_loc_hardware_watchpoint |
| && bl->owner->disposition != disp_del_at_next_stop) |
| { |
| int val; |
| |
| val = bl->owner->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) |
| { |
| /* But don't try to insert it, if there's already another |
| hw_access location that would be considered a duplicate |
| of this one. */ |
| for (bp_location *loc : all_bp_locations ()) |
| 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->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) |
| { |
| int val; |
| |
| val = bl->owner->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) |
| { |
| /* Remove any breakpoint that was set through this program space. */ |
| for (breakpoint &b : all_breakpoints_safe ()) |
| if (b.pspace == pspace) |
| delete_breakpoint (&b); |
| |
| /* Breakpoints set through other program spaces could have locations |
| bound to PSPACE as well. Remove those. */ |
| for (bp_location *loc : all_bp_locations ()) |
| if (loc->pspace == pspace) |
| { |
| /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */ |
| loc->owner->unadd_location (*loc); |
| } |
| |
| /* Now update the global location list to permanently delete the |
| removed locations above. */ |
| update_global_location_list (UGLL_DONT_INSERT); |
| } |
| |
| /* 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) |
| { |
| for (breakpoint &bpt : all_breakpoints ()) |
| if (is_hardware_watchpoint (&bpt)) |
| { |
| watchpoint &w = gdb::checked_static_cast<watchpoint &> (bpt); |
| |
| update_watchpoint (&w, false /* don't reparse. */); |
| } |
| |
| /* Updating watchpoints creates new locations, so update the global |
| location list. Explicitly tell ugll to insert locations and |
| ignore breakpoints_always_inserted_mode. Also, |
| update_global_location_list tries to "upgrade" software |
| breakpoints to hardware breakpoints to handle "set breakpoint |
| auto-hw", so we need to call it even if we don't have new |
| locations. */ |
| update_global_location_list (UGLL_INSERT); |
| } |
| |
| /* 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) |
| { |
| int error_flag = 0; |
| int val = 0; |
| int disabled_breaks = 0; |
| int hw_breakpoint_error = 0; |
| int hw_bp_details_reported = 0; |
| |
| string_file tmp_error_stream; |
| |
| /* Explicitly mark the warning -- this will only be printed if |
| there was an error. */ |
| tmp_error_stream.puts ("Warning:\n"); |
| |
| scoped_restore_current_pspace_and_thread restore_pspace_thread; |
| |
| for (bp_location *bl : all_bp_locations ()) |
| { |
| /* 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->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 (current_inferior ()->arch ()) |
| && (inferior_ptid == null_ptid || !target_has_execution ())) |
| continue; |
| |
| val = insert_bp_location (bl, &tmp_error_stream, &disabled_breaks, |
| &hw_breakpoint_error, &hw_bp_details_reported); |
| if (val) |
| error_flag = val; |
| } |
| |
| if (error_flag) |
| { |
| target_terminal::ours_for_output (); |
| error (("%s"), tmp_error_stream.c_str ()); |
| } |
| } |
| |
| /* Used when starting or continuing the program. */ |
| |
| static void |
| insert_breakpoint_locations (void) |
| { |
| int error_flag = 0; |
| int val = 0; |
| int disabled_breaks = 0; |
| int hw_breakpoint_error = 0; |
| int hw_bp_error_explained_already = 0; |
| |
| string_file tmp_error_stream; |
| |
| /* Explicitly mark the warning -- this will only be printed if |
| there was an error. */ |
| tmp_error_stream.puts ("Warning:\n"); |
| |
| scoped_restore_current_pspace_and_thread restore_pspace_thread; |
| |
| for (bp_location *bl : all_bp_locations ()) |
| { |
| 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_global_thread_id (bl->owner->thread)) |
| continue; |
| |
| /* Or inferior specific breakpoints if the inferior no longer |
| exists. */ |
| if (bl->owner->inferior != -1 |
| && !valid_global_inferior_id (bl->owner->inferior)) |
| 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 (current_inferior ()->arch ()) |
| && (inferior_ptid == null_ptid || !target_has_execution ())) |
| continue; |
| |
| val = insert_bp_location (bl, &tmp_error_stream, &disabled_breaks, |
| &hw_breakpoint_error, &hw_bp_error_explained_already); |
| 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. */ |
| for (breakpoint &bpt : all_breakpoints ()) |
| { |
| bool some_failed = false; |
| |
| if (!is_hardware_watchpoint (&bpt)) |
| continue; |
| |
| if (!breakpoint_enabled (&bpt)) |
| continue; |
| |
| if (bpt.disposition == disp_del_at_next_stop) |
| continue; |
| |
| for (bp_location &loc : bpt.locations ()) |
| if (!loc.inserted && should_be_inserted (&loc)) |
| { |
| some_failed = true; |
| break; |
| } |
| |
| if (some_failed) |
| { |
| for (bp_location &loc : bpt.locations ()) |
| if (loc.inserted) |
| remove_breakpoint (&loc); |
| |
| hw_breakpoint_error = 1; |
| tmp_error_stream.printf ("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 && !hw_bp_error_explained_already) |
| { |
| tmp_error_stream.printf ("Could not insert hardware breakpoints:\n\ |
| You may have requested too many hardware breakpoints/watchpoints.\n"); |
| } |
| target_terminal::ours_for_output (); |
| error (("%s"), tmp_error_stream.c_str ()); |
| } |
| } |
| |
| /* 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) |
| { |
| int val = 0; |
| |
| for (bp_location *bl : all_bp_locations ()) |
| if (bl->inserted && !is_tracepoint (bl->owner)) |
| val |= remove_breakpoint (bl); |
| |
| return val; |
| } |
| |
| /* When a thread exits, remove breakpoints that are related to |
| that thread. */ |
| |
| static void |
| <