diff options
author | Tom Tromey <tom@tromey.com> | 2019-12-15 07:37:06 -0700 |
---|---|---|
committer | Tom Tromey <tromey@adacore.com> | 2020-02-07 08:42:25 -0700 |
commit | 919adfe8409211c726c1d05b47ca59890ee648f1 (patch) | |
tree | d2ef4abf9e5590b43a59f3f8747b0d5bab94ab6f /gdb/gdbserver/mem-break.c | |
parent | e8319fde715960466aca2461c74cec8907abd391 (diff) | |
download | gdb-919adfe8409211c726c1d05b47ca59890ee648f1.zip gdb-919adfe8409211c726c1d05b47ca59890ee648f1.tar.gz gdb-919adfe8409211c726c1d05b47ca59890ee648f1.tar.bz2 |
Move gdbserver to top level
This patch moves gdbserver to the top level.
This patch is as close to a pure move as possible -- gdbserver still
builds its own variant of gnulib and gdbsupport. Changing this will
be done in a separate patch.
[v2] Note that, per Simon's review comment, this patch changes the
tree so that gdbserver is not built for or1k or score. This makes
sense, because there is apparently not actually a gdbserver port here.
[v3] This version of the patch also splits out some configury into a
new file, gdbserver/configure.host, so that the top-level configure
script can simply rely on it in order to decide whether gdbserver
should be built.
[v4] This version adds documentation and removes some unnecessary
top-level dependencies.
[v5] Update docs to mention "make all-gdbserver" and change how
top-level configure decides whether to build gdbserver, switching to a
single, shared script.
Tested by the buildbot.
ChangeLog
2020-02-07 Tom Tromey <tom@tromey.com>
Pedro Alves <palves@redhat.com>
* src-release.sh (GDB_SUPPORT_DIRS): Add gdbserver.
* gdbserver: New directory, moved from gdb/gdbserver.
* configure.ac (host_tools): Add gdbserver.
Only build gdbserver on certain systems.
* Makefile.in, configure: Rebuild.
* Makefile.def (host_modules, dependencies): Add gdbserver.
* MAINTAINERS: Add gdbserver.
gdb/ChangeLog
2020-02-07 Tom Tromey <tom@tromey.com>
* README: Update gdbserver documentation.
* gdbserver: Move to top level.
* configure.tgt (build_gdbserver): Remove.
* configure.ac: Remove --enable-gdbserver.
* configure: Rebuild.
* Makefile.in (distclean): Don't mention gdbserver.
Change-Id: I826b7565b54604711dc7a11edea0499cd51ff39e
Diffstat (limited to 'gdb/gdbserver/mem-break.c')
-rw-r--r-- | gdb/gdbserver/mem-break.c | 2237 |
1 files changed, 0 insertions, 2237 deletions
diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c deleted file mode 100644 index 1b6f236..0000000 --- a/gdb/gdbserver/mem-break.c +++ /dev/null @@ -1,2237 +0,0 @@ -/* Memory breakpoint operations for the remote server for GDB. - Copyright (C) 2002-2020 Free Software Foundation, Inc. - - Contributed by MontaVista Software. - - 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 "server.h" -#include "regcache.h" -#include "ax.h" - -#define MAX_BREAKPOINT_LEN 8 - -/* Helper macro used in loops that append multiple items to a singly-linked - list instead of inserting items at the head of the list, as, say, in the - breakpoint lists. LISTPP is a pointer to the pointer that is the head of - the new list. ITEMP is a pointer to the item to be added to the list. - TAILP must be defined to be the same type as ITEMP, and initialized to - NULL. */ - -#define APPEND_TO_LIST(listpp, itemp, tailp) \ - do \ - { \ - if ((tailp) == NULL) \ - *(listpp) = (itemp); \ - else \ - (tailp)->next = (itemp); \ - (tailp) = (itemp); \ - } \ - while (0) - -/* GDB will never try to install multiple breakpoints at the same - address. However, we can see GDB requesting to insert a breakpoint - at an address is had already inserted one previously in a few - situations. - - - The RSP documentation on Z packets says that to avoid potential - problems with duplicate packets, the operations should be - implemented in an idempotent way. - - - A breakpoint is set at ADDR, an address in a shared library. - Then the shared library is unloaded. And then another, unrelated, - breakpoint at ADDR is set. There is not breakpoint removal request - between the first and the second breakpoint. - - - When GDB wants to update the target-side breakpoint conditions or - commands, it re-inserts the breakpoint, with updated - conditions/commands associated. - - Also, we need to keep track of internal breakpoints too, so we do - need to be able to install multiple breakpoints at the same address - transparently. - - We keep track of two different, and closely related structures. A - raw breakpoint, which manages the low level, close to the metal - aspect of a breakpoint. It holds the breakpoint address, and for - software breakpoints, a buffer holding a copy of the instructions - that would be in memory had not been a breakpoint there (we call - that the shadow memory of the breakpoint). We occasionally need to - temporarilly uninsert a breakpoint without the client knowing about - it (e.g., to step over an internal breakpoint), so we keep an - `inserted' state associated with this low level breakpoint - structure. There can only be one such object for a given address. - Then, we have (a bit higher level) breakpoints. This structure - holds a callback to be called whenever a breakpoint is hit, a - high-level type, and a link to a low level raw breakpoint. There - can be many high-level breakpoints at the same address, and all of - them will point to the same raw breakpoint, which is reference - counted. */ - -/* The low level, physical, raw breakpoint. */ -struct raw_breakpoint -{ - struct raw_breakpoint *next; - - /* The low level type of the breakpoint (software breakpoint, - watchpoint, etc.) */ - enum raw_bkpt_type raw_type; - - /* A reference count. Each high level breakpoint referencing this - raw breakpoint accounts for one reference. */ - int refcount; - - /* The breakpoint's insertion address. There can only be one raw - breakpoint for a given PC. */ - CORE_ADDR pc; - - /* The breakpoint's kind. This is target specific. Most - architectures only use one specific instruction for breakpoints, while - others may use more than one. E.g., on ARM, we need to use different - breakpoint instructions on Thumb, Thumb-2, and ARM code. Likewise for - hardware breakpoints -- some architectures (including ARM) need to - setup debug registers differently depending on mode. */ - int kind; - - /* The breakpoint's shadow memory. */ - unsigned char old_data[MAX_BREAKPOINT_LEN]; - - /* Positive if this breakpoint is currently inserted in the - inferior. Negative if it was, but we've detected that it's now - gone. Zero if not inserted. */ - int inserted; -}; - -/* The type of a breakpoint. */ -enum bkpt_type - { - /* A GDB breakpoint, requested with a Z0 packet. */ - gdb_breakpoint_Z0, - - /* A GDB hardware breakpoint, requested with a Z1 packet. */ - gdb_breakpoint_Z1, - - /* A GDB write watchpoint, requested with a Z2 packet. */ - gdb_breakpoint_Z2, - - /* A GDB read watchpoint, requested with a Z3 packet. */ - gdb_breakpoint_Z3, - - /* A GDB access watchpoint, requested with a Z4 packet. */ - gdb_breakpoint_Z4, - - /* A software single-step breakpoint. */ - single_step_breakpoint, - - /* Any other breakpoint type that doesn't require specific - treatment goes here. E.g., an event breakpoint. */ - other_breakpoint, - }; - -struct point_cond_list -{ - /* Pointer to the agent expression that is the breakpoint's - conditional. */ - struct agent_expr *cond; - - /* Pointer to the next condition. */ - struct point_cond_list *next; -}; - -struct point_command_list -{ - /* Pointer to the agent expression that is the breakpoint's - commands. */ - struct agent_expr *cmd; - - /* Flag that is true if this command should run even while GDB is - disconnected. */ - int persistence; - - /* Pointer to the next command. */ - struct point_command_list *next; -}; - -/* A high level (in gdbserver's perspective) breakpoint. */ -struct breakpoint -{ - struct breakpoint *next; - - /* The breakpoint's type. */ - enum bkpt_type type; - - /* Link to this breakpoint's raw breakpoint. This is always - non-NULL. */ - struct raw_breakpoint *raw; -}; - -/* Breakpoint requested by GDB. */ - -struct gdb_breakpoint -{ - struct breakpoint base; - - /* Pointer to the condition list that should be evaluated on - the target or NULL if the breakpoint is unconditional or - if GDB doesn't want us to evaluate the conditionals on the - target's side. */ - struct point_cond_list *cond_list; - - /* Point to the list of commands to run when this is hit. */ - struct point_command_list *command_list; -}; - -/* Breakpoint used by GDBserver. */ - -struct other_breakpoint -{ - struct breakpoint base; - - /* Function to call when we hit this breakpoint. If it returns 1, - the breakpoint shall be deleted; 0 or if this callback is NULL, - it will be left inserted. */ - int (*handler) (CORE_ADDR); -}; - -/* Breakpoint for single step. */ - -struct single_step_breakpoint -{ - struct breakpoint base; - - /* Thread the reinsert breakpoint belongs to. */ - ptid_t ptid; -}; - -/* Return the breakpoint size from its kind. */ - -static int -bp_size (struct raw_breakpoint *bp) -{ - int size = 0; - - the_target->sw_breakpoint_from_kind (bp->kind, &size); - return size; -} - -/* Return the breakpoint opcode from its kind. */ - -static const gdb_byte * -bp_opcode (struct raw_breakpoint *bp) -{ - int size = 0; - - return the_target->sw_breakpoint_from_kind (bp->kind, &size); -} - -/* See mem-break.h. */ - -enum target_hw_bp_type -raw_bkpt_type_to_target_hw_bp_type (enum raw_bkpt_type raw_type) -{ - switch (raw_type) - { - case raw_bkpt_type_hw: - return hw_execute; - case raw_bkpt_type_write_wp: - return hw_write; - case raw_bkpt_type_read_wp: - return hw_read; - case raw_bkpt_type_access_wp: - return hw_access; - default: - internal_error (__FILE__, __LINE__, - "bad raw breakpoint type %d", (int) raw_type); - } -} - -/* See mem-break.h. */ - -static enum bkpt_type -Z_packet_to_bkpt_type (char z_type) -{ - gdb_assert ('0' <= z_type && z_type <= '4'); - - return (enum bkpt_type) (gdb_breakpoint_Z0 + (z_type - '0')); -} - -/* See mem-break.h. */ - -enum raw_bkpt_type -Z_packet_to_raw_bkpt_type (char z_type) -{ - switch (z_type) - { - case Z_PACKET_SW_BP: - return raw_bkpt_type_sw; - case Z_PACKET_HW_BP: - return raw_bkpt_type_hw; - case Z_PACKET_WRITE_WP: - return raw_bkpt_type_write_wp; - case Z_PACKET_READ_WP: - return raw_bkpt_type_read_wp; - case Z_PACKET_ACCESS_WP: - return raw_bkpt_type_access_wp; - default: - gdb_assert_not_reached ("unhandled Z packet type."); - } -} - -/* Return true if breakpoint TYPE is a GDB breakpoint. */ - -static int -is_gdb_breakpoint (enum bkpt_type type) -{ - return (type == gdb_breakpoint_Z0 - || type == gdb_breakpoint_Z1 - || type == gdb_breakpoint_Z2 - || type == gdb_breakpoint_Z3 - || type == gdb_breakpoint_Z4); -} - -bool -any_persistent_commands (process_info *proc) -{ - struct breakpoint *bp; - struct point_command_list *cl; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - { - if (is_gdb_breakpoint (bp->type)) - { - struct gdb_breakpoint *gdb_bp = (struct gdb_breakpoint *) bp; - - for (cl = gdb_bp->command_list; cl != NULL; cl = cl->next) - if (cl->persistence) - return true; - } - } - - return false; -} - -/* Find low-level breakpoint of type TYPE at address ADDR that is not - insert-disabled. Returns NULL if not found. */ - -static struct raw_breakpoint * -find_enabled_raw_code_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if (bp->pc == addr - && bp->raw_type == type - && bp->inserted >= 0) - return bp; - - return NULL; -} - -/* Find low-level breakpoint of type TYPE at address ADDR. Returns - NULL if not found. */ - -static struct raw_breakpoint * -find_raw_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type, int kind) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if (bp->pc == addr && bp->raw_type == type && bp->kind == kind) - return bp; - - return NULL; -} - -/* See mem-break.h. */ - -int -insert_memory_breakpoint (struct raw_breakpoint *bp) -{ - unsigned char buf[MAX_BREAKPOINT_LEN]; - int err; - - /* Note that there can be fast tracepoint jumps installed in the - same memory range, so to get at the original memory, we need to - use read_inferior_memory, which masks those out. */ - err = read_inferior_memory (bp->pc, buf, bp_size (bp)); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to read shadow memory of" - " breakpoint at 0x%s (%s).\n", - paddress (bp->pc), safe_strerror (err)); - } - else - { - memcpy (bp->old_data, buf, bp_size (bp)); - - err = (*the_target->write_memory) (bp->pc, bp_opcode (bp), - bp_size (bp)); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to insert breakpoint at 0x%s (%s).\n", - paddress (bp->pc), safe_strerror (err)); - } - } - return err != 0 ? -1 : 0; -} - -/* See mem-break.h */ - -int -remove_memory_breakpoint (struct raw_breakpoint *bp) -{ - unsigned char buf[MAX_BREAKPOINT_LEN]; - int err; - - /* Since there can be trap breakpoints inserted in the same address - range, we use `target_write_memory', which takes care of - layering breakpoints on top of fast tracepoints, and on top of - the buffer we pass it. This works because the caller has already - either unlinked the breakpoint or marked it uninserted. Also - note that we need to pass the current shadow contents, because - target_write_memory updates any shadow memory with what we pass - here, and we want that to be a nop. */ - memcpy (buf, bp->old_data, bp_size (bp)); - err = target_write_memory (bp->pc, buf, bp_size (bp)); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to uninsert raw breakpoint " - "at 0x%s (%s) while deleting it.\n", - paddress (bp->pc), safe_strerror (err)); - } - return err != 0 ? -1 : 0; -} - -/* Set a RAW breakpoint of type TYPE and kind KIND at WHERE. On - success, a pointer to the new breakpoint is returned. On failure, - returns NULL and writes the error code to *ERR. */ - -static struct raw_breakpoint * -set_raw_breakpoint_at (enum raw_bkpt_type type, CORE_ADDR where, int kind, - int *err) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - if (type == raw_bkpt_type_sw || type == raw_bkpt_type_hw) - { - bp = find_enabled_raw_code_breakpoint_at (where, type); - if (bp != NULL && bp->kind != kind) - { - /* A different kind than previously seen. The previous - breakpoint must be gone then. */ - if (debug_threads) - debug_printf ("Inconsistent breakpoint kind? Was %d, now %d.\n", - bp->kind, kind); - bp->inserted = -1; - bp = NULL; - } - } - else - bp = find_raw_breakpoint_at (where, type, kind); - - gdb::unique_xmalloc_ptr<struct raw_breakpoint> bp_holder; - if (bp == NULL) - { - bp_holder.reset (XCNEW (struct raw_breakpoint)); - bp = bp_holder.get (); - bp->pc = where; - bp->kind = kind; - bp->raw_type = type; - } - - if (!bp->inserted) - { - *err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp); - if (*err != 0) - { - if (debug_threads) - debug_printf ("Failed to insert breakpoint at 0x%s (%d).\n", - paddress (where), *err); - - return NULL; - } - - bp->inserted = 1; - } - - /* If the breakpoint was allocated above, we know we want to keep it - now. */ - bp_holder.release (); - - /* Link the breakpoint in, if this is the first reference. */ - if (++bp->refcount == 1) - { - bp->next = proc->raw_breakpoints; - proc->raw_breakpoints = bp; - } - return bp; -} - -/* Notice that breakpoint traps are always installed on top of fast - tracepoint jumps. This is even if the fast tracepoint is installed - at a later time compared to when the breakpoint was installed. - This means that a stopping breakpoint or tracepoint has higher - "priority". In turn, this allows having fast and slow tracepoints - (and breakpoints) at the same address behave correctly. */ - - -/* A fast tracepoint jump. */ - -struct fast_tracepoint_jump -{ - struct fast_tracepoint_jump *next; - - /* A reference count. GDB can install more than one fast tracepoint - at the same address (each with its own action list, for - example). */ - int refcount; - - /* The fast tracepoint's insertion address. There can only be one - of these for a given PC. */ - CORE_ADDR pc; - - /* Non-zero if this fast tracepoint jump is currently inserted in - the inferior. */ - int inserted; - - /* The length of the jump instruction. */ - int length; - - /* A poor-man's flexible array member, holding both the jump - instruction to insert, and a copy of the instruction that would - be in memory had not been a jump there (the shadow memory of the - tracepoint jump). */ - unsigned char insn_and_shadow[0]; -}; - -/* Fast tracepoint FP's jump instruction to insert. */ -#define fast_tracepoint_jump_insn(fp) \ - ((fp)->insn_and_shadow + 0) - -/* The shadow memory of fast tracepoint jump FP. */ -#define fast_tracepoint_jump_shadow(fp) \ - ((fp)->insn_and_shadow + (fp)->length) - - -/* Return the fast tracepoint jump set at WHERE. */ - -static struct fast_tracepoint_jump * -find_fast_tracepoint_jump_at (CORE_ADDR where) -{ - struct process_info *proc = current_process (); - struct fast_tracepoint_jump *jp; - - for (jp = proc->fast_tracepoint_jumps; jp != NULL; jp = jp->next) - if (jp->pc == where) - return jp; - - return NULL; -} - -int -fast_tracepoint_jump_here (CORE_ADDR where) -{ - struct fast_tracepoint_jump *jp = find_fast_tracepoint_jump_at (where); - - return (jp != NULL); -} - -int -delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel) -{ - struct fast_tracepoint_jump *bp, **bp_link; - int ret; - struct process_info *proc = current_process (); - - bp = proc->fast_tracepoint_jumps; - bp_link = &proc->fast_tracepoint_jumps; - - while (bp) - { - if (bp == todel) - { - if (--bp->refcount == 0) - { - struct fast_tracepoint_jump *prev_bp_link = *bp_link; - unsigned char *buf; - - /* Unlink it. */ - *bp_link = bp->next; - - /* Since there can be breakpoints inserted in the same - address range, we use `target_write_memory', which - takes care of layering breakpoints on top of fast - tracepoints, and on top of the buffer we pass it. - This works because we've already unlinked the fast - tracepoint jump above. Also note that we need to - pass the current shadow contents, because - target_write_memory updates any shadow memory with - what we pass here, and we want that to be a nop. */ - buf = (unsigned char *) alloca (bp->length); - memcpy (buf, fast_tracepoint_jump_shadow (bp), bp->length); - ret = target_write_memory (bp->pc, buf, bp->length); - if (ret != 0) - { - /* Something went wrong, relink the jump. */ - *bp_link = prev_bp_link; - - if (debug_threads) - debug_printf ("Failed to uninsert fast tracepoint jump " - "at 0x%s (%s) while deleting it.\n", - paddress (bp->pc), safe_strerror (ret)); - return ret; - } - - free (bp); - } - - return 0; - } - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } - - warning ("Could not find fast tracepoint jump in list."); - return ENOENT; -} - -void -inc_ref_fast_tracepoint_jump (struct fast_tracepoint_jump *jp) -{ - jp->refcount++; -} - -struct fast_tracepoint_jump * -set_fast_tracepoint_jump (CORE_ADDR where, - unsigned char *insn, ULONGEST length) -{ - struct process_info *proc = current_process (); - struct fast_tracepoint_jump *jp; - int err; - unsigned char *buf; - - /* We refcount fast tracepoint jumps. Check if we already know - about a jump at this address. */ - jp = find_fast_tracepoint_jump_at (where); - if (jp != NULL) - { - jp->refcount++; - return jp; - } - - /* We don't, so create a new object. Double the length, because the - flexible array member holds both the jump insn, and the - shadow. */ - jp = (struct fast_tracepoint_jump *) xcalloc (1, sizeof (*jp) + (length * 2)); - jp->pc = where; - jp->length = length; - memcpy (fast_tracepoint_jump_insn (jp), insn, length); - jp->refcount = 1; - buf = (unsigned char *) alloca (length); - - /* Note that there can be trap breakpoints inserted in the same - address range. To access the original memory contents, we use - `read_inferior_memory', which masks out breakpoints. */ - err = read_inferior_memory (where, buf, length); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to read shadow memory of" - " fast tracepoint at 0x%s (%s).\n", - paddress (where), safe_strerror (err)); - free (jp); - return NULL; - } - memcpy (fast_tracepoint_jump_shadow (jp), buf, length); - - /* Link the jump in. */ - jp->inserted = 1; - jp->next = proc->fast_tracepoint_jumps; - proc->fast_tracepoint_jumps = jp; - - /* Since there can be trap breakpoints inserted in the same address - range, we use use `target_write_memory', which takes care of - layering breakpoints on top of fast tracepoints, on top of the - buffer we pass it. This works because we've already linked in - the fast tracepoint jump above. Also note that we need to pass - the current shadow contents, because target_write_memory - updates any shadow memory with what we pass here, and we want - that to be a nop. */ - err = target_write_memory (where, buf, length); - if (err != 0) - { - if (debug_threads) - debug_printf ("Failed to insert fast tracepoint jump at 0x%s (%s).\n", - paddress (where), safe_strerror (err)); - - /* Unlink it. */ - proc->fast_tracepoint_jumps = jp->next; - free (jp); - - return NULL; - } - - return jp; -} - -void -uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc) -{ - struct fast_tracepoint_jump *jp; - int err; - - jp = find_fast_tracepoint_jump_at (pc); - if (jp == NULL) - { - /* This can happen when we remove all breakpoints while handling - a step-over. */ - if (debug_threads) - debug_printf ("Could not find fast tracepoint jump at 0x%s " - "in list (uninserting).\n", - paddress (pc)); - return; - } - - if (jp->inserted) - { - unsigned char *buf; - - jp->inserted = 0; - - /* Since there can be trap breakpoints inserted in the same - address range, we use use `target_write_memory', which - takes care of layering breakpoints on top of fast - tracepoints, and on top of the buffer we pass it. This works - because we've already marked the fast tracepoint fast - tracepoint jump uninserted above. Also note that we need to - pass the current shadow contents, because - target_write_memory updates any shadow memory with what we - pass here, and we want that to be a nop. */ - buf = (unsigned char *) alloca (jp->length); - memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length); - err = target_write_memory (jp->pc, buf, jp->length); - if (err != 0) - { - jp->inserted = 1; - - if (debug_threads) - debug_printf ("Failed to uninsert fast tracepoint jump at" - " 0x%s (%s).\n", - paddress (pc), safe_strerror (err)); - } - } -} - -void -reinsert_fast_tracepoint_jumps_at (CORE_ADDR where) -{ - struct fast_tracepoint_jump *jp; - int err; - unsigned char *buf; - - jp = find_fast_tracepoint_jump_at (where); - if (jp == NULL) - { - /* This can happen when we remove breakpoints when a tracepoint - hit causes a tracing stop, while handling a step-over. */ - if (debug_threads) - debug_printf ("Could not find fast tracepoint jump at 0x%s " - "in list (reinserting).\n", - paddress (where)); - return; - } - - if (jp->inserted) - error ("Jump already inserted at reinsert time."); - - jp->inserted = 1; - - /* Since there can be trap breakpoints inserted in the same address - range, we use `target_write_memory', which takes care of - layering breakpoints on top of fast tracepoints, and on top of - the buffer we pass it. This works because we've already marked - the fast tracepoint jump inserted above. Also note that we need - to pass the current shadow contents, because - target_write_memory updates any shadow memory with what we pass - here, and we want that to be a nop. */ - buf = (unsigned char *) alloca (jp->length); - memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length); - err = target_write_memory (where, buf, jp->length); - if (err != 0) - { - jp->inserted = 0; - - if (debug_threads) - debug_printf ("Failed to reinsert fast tracepoint jump at" - " 0x%s (%s).\n", - paddress (where), safe_strerror (err)); - } -} - -/* Set a high-level breakpoint of type TYPE, with low level type - RAW_TYPE and kind KIND, at WHERE. On success, a pointer to the new - breakpoint is returned. On failure, returns NULL and writes the - error code to *ERR. HANDLER is called when the breakpoint is hit. - HANDLER should return 1 if the breakpoint should be deleted, 0 - otherwise. */ - -static struct breakpoint * -set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type, - CORE_ADDR where, int kind, - int (*handler) (CORE_ADDR), int *err) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp; - struct raw_breakpoint *raw; - - raw = set_raw_breakpoint_at (raw_type, where, kind, err); - - if (raw == NULL) - { - /* warn? */ - return NULL; - } - - if (is_gdb_breakpoint (type)) - { - struct gdb_breakpoint *gdb_bp = XCNEW (struct gdb_breakpoint); - - bp = (struct breakpoint *) gdb_bp; - gdb_assert (handler == NULL); - } - else if (type == other_breakpoint) - { - struct other_breakpoint *other_bp = XCNEW (struct other_breakpoint); - - other_bp->handler = handler; - bp = (struct breakpoint *) other_bp; - } - else if (type == single_step_breakpoint) - { - struct single_step_breakpoint *ss_bp - = XCNEW (struct single_step_breakpoint); - - bp = (struct breakpoint *) ss_bp; - } - else - gdb_assert_not_reached ("unhandled breakpoint type"); - - bp->type = type; - bp->raw = raw; - - bp->next = proc->breakpoints; - proc->breakpoints = bp; - - return bp; -} - -/* Set breakpoint of TYPE on address WHERE with handler HANDLER. */ - -static struct breakpoint * -set_breakpoint_type_at (enum bkpt_type type, CORE_ADDR where, - int (*handler) (CORE_ADDR)) -{ - int err_ignored; - CORE_ADDR placed_address = where; - int breakpoint_kind = target_breakpoint_kind_from_pc (&placed_address); - - return set_breakpoint (type, raw_bkpt_type_sw, - placed_address, breakpoint_kind, handler, - &err_ignored); -} - -/* See mem-break.h */ - -struct breakpoint * -set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR)) -{ - return set_breakpoint_type_at (other_breakpoint, where, handler); -} - - -static int -delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel) -{ - struct raw_breakpoint *bp, **bp_link; - int ret; - - bp = proc->raw_breakpoints; - bp_link = &proc->raw_breakpoints; - - while (bp) - { - if (bp == todel) - { - if (bp->inserted > 0) - { - struct raw_breakpoint *prev_bp_link = *bp_link; - - *bp_link = bp->next; - - ret = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, - bp); - if (ret != 0) - { - /* Something went wrong, relink the breakpoint. */ - *bp_link = prev_bp_link; - - if (debug_threads) - debug_printf ("Failed to uninsert raw breakpoint " - "at 0x%s while deleting it.\n", - paddress (bp->pc)); - return ret; - } - } - else - *bp_link = bp->next; - - free (bp); - return 0; - } - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } - - warning ("Could not find raw breakpoint in list."); - return ENOENT; -} - -static int -release_breakpoint (struct process_info *proc, struct breakpoint *bp) -{ - int newrefcount; - int ret; - - newrefcount = bp->raw->refcount - 1; - if (newrefcount == 0) - { - ret = delete_raw_breakpoint (proc, bp->raw); - if (ret != 0) - return ret; - } - else - bp->raw->refcount = newrefcount; - - free (bp); - - return 0; -} - -static int -delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel) -{ - struct breakpoint *bp, **bp_link; - int err; - - bp = proc->breakpoints; - bp_link = &proc->breakpoints; - - while (bp) - { - if (bp == todel) - { - *bp_link = bp->next; - - err = release_breakpoint (proc, bp); - if (err != 0) - return err; - - bp = *bp_link; - return 0; - } - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } - - warning ("Could not find breakpoint in list."); - return ENOENT; -} - -int -delete_breakpoint (struct breakpoint *todel) -{ - struct process_info *proc = current_process (); - return delete_breakpoint_1 (proc, todel); -} - -/* Locate a GDB breakpoint of type Z_TYPE and kind KIND placed at - address ADDR and return a pointer to its structure. If KIND is -1, - the breakpoint's kind is ignored. */ - -static struct gdb_breakpoint * -find_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp; - enum bkpt_type type = Z_packet_to_bkpt_type (z_type); - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - if (bp->type == type && bp->raw->pc == addr - && (kind == -1 || bp->raw->kind == kind)) - return (struct gdb_breakpoint *) bp; - - return NULL; -} - -static int -z_type_supported (char z_type) -{ - return (z_type >= '0' && z_type <= '4' - && the_target->supports_z_point_type != NULL - && the_target->supports_z_point_type (z_type)); -} - -/* Create a new GDB breakpoint of type Z_TYPE at ADDR with kind KIND. - Returns a pointer to the newly created breakpoint on success. On - failure returns NULL and sets *ERR to either -1 for error, or 1 if - Z_TYPE breakpoints are not supported on this target. */ - -static struct gdb_breakpoint * -set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind, int *err) -{ - struct gdb_breakpoint *bp; - enum bkpt_type type; - enum raw_bkpt_type raw_type; - - /* If we see GDB inserting a second code breakpoint at the same - address, then either: GDB is updating the breakpoint's conditions - or commands; or, the first breakpoint must have disappeared due - to a shared library unload. On targets where the shared - libraries are handled by userspace, like SVR4, for example, - GDBserver can't tell if a library was loaded or unloaded. Since - we refcount raw breakpoints, we must be careful to make sure GDB - breakpoints never contribute more than one reference. if we - didn't do this, in case the previous breakpoint is gone due to a - shared library unload, we'd just increase the refcount of the - previous breakpoint at this address, but the trap was not planted - in the inferior anymore, thus the breakpoint would never be hit. - Note this must be careful to not create a window where - breakpoints are removed from the target, for non-stop, in case - the target can poke at memory while the program is running. */ - if (z_type == Z_PACKET_SW_BP - || z_type == Z_PACKET_HW_BP) - { - bp = find_gdb_breakpoint (z_type, addr, -1); - - if (bp != NULL) - { - if (bp->base.raw->kind != kind) - { - /* A different kind than previously seen. The previous - breakpoint must be gone then. */ - bp->base.raw->inserted = -1; - delete_breakpoint ((struct breakpoint *) bp); - bp = NULL; - } - else if (z_type == Z_PACKET_SW_BP) - { - /* Check if the breakpoint is actually gone from the - target, due to an solib unload, for example. Might - as well validate _all_ breakpoints. */ - validate_breakpoints (); - - /* Breakpoints that don't pass validation are - deleted. */ - bp = find_gdb_breakpoint (z_type, addr, -1); - } - } - } - else - { - /* Data breakpoints for the same address but different kind are - expected. GDB doesn't merge these. The backend gets to do - that if it wants/can. */ - bp = find_gdb_breakpoint (z_type, addr, kind); - } - - if (bp != NULL) - { - /* We already know about this breakpoint, there's nothing else - to do - GDB's reference is already accounted for. Note that - whether the breakpoint inserted is left as is - we may be - stepping over it, for example, in which case we don't want to - force-reinsert it. */ - return bp; - } - - raw_type = Z_packet_to_raw_bkpt_type (z_type); - type = Z_packet_to_bkpt_type (z_type); - return (struct gdb_breakpoint *) set_breakpoint (type, raw_type, addr, - kind, NULL, err); -} - -static int -check_gdb_bp_preconditions (char z_type, int *err) -{ - /* As software/memory breakpoints work by poking at memory, we need - to prepare to access memory. If that operation fails, we need to - return error. Seeing an error, if this is the first breakpoint - of that type that GDB tries to insert, GDB would then assume the - breakpoint type is supported, but it may actually not be. So we - need to check whether the type is supported at all before - preparing to access memory. */ - if (!z_type_supported (z_type)) - { - *err = 1; - return 0; - } - - return 1; -} - -/* See mem-break.h. This is a wrapper for set_gdb_breakpoint_1 that - knows to prepare to access memory for Z0 breakpoints. */ - -struct gdb_breakpoint * -set_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind, int *err) -{ - struct gdb_breakpoint *bp; - - if (!check_gdb_bp_preconditions (z_type, err)) - return NULL; - - /* If inserting a software/memory breakpoint, need to prepare to - access memory. */ - if (z_type == Z_PACKET_SW_BP) - { - if (prepare_to_access_memory () != 0) - { - *err = -1; - return NULL; - } - } - - bp = set_gdb_breakpoint_1 (z_type, addr, kind, err); - - if (z_type == Z_PACKET_SW_BP) - done_accessing_memory (); - - return bp; -} - -/* Delete a GDB breakpoint of type Z_TYPE and kind KIND previously - inserted at ADDR with set_gdb_breakpoint_at. Returns 0 on success, - -1 on error, and 1 if Z_TYPE breakpoints are not supported on this - target. */ - -static int -delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind) -{ - struct gdb_breakpoint *bp; - int err; - - bp = find_gdb_breakpoint (z_type, addr, kind); - if (bp == NULL) - return -1; - - /* Before deleting the breakpoint, make sure to free its condition - and command lists. */ - clear_breakpoint_conditions_and_commands (bp); - err = delete_breakpoint ((struct breakpoint *) bp); - if (err != 0) - return -1; - - return 0; -} - -/* See mem-break.h. This is a wrapper for delete_gdb_breakpoint that - knows to prepare to access memory for Z0 breakpoints. */ - -int -delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind) -{ - int ret; - - if (!check_gdb_bp_preconditions (z_type, &ret)) - return ret; - - /* If inserting a software/memory breakpoint, need to prepare to - access memory. */ - if (z_type == Z_PACKET_SW_BP) - { - int err; - - err = prepare_to_access_memory (); - if (err != 0) - return -1; - } - - ret = delete_gdb_breakpoint_1 (z_type, addr, kind); - - if (z_type == Z_PACKET_SW_BP) - done_accessing_memory (); - - return ret; -} - -/* Clear all conditions associated with a breakpoint. */ - -static void -clear_breakpoint_conditions (struct gdb_breakpoint *bp) -{ - struct point_cond_list *cond; - - if (bp->cond_list == NULL) - return; - - cond = bp->cond_list; - - while (cond != NULL) - { - struct point_cond_list *cond_next; - - cond_next = cond->next; - gdb_free_agent_expr (cond->cond); - free (cond); - cond = cond_next; - } - - bp->cond_list = NULL; -} - -/* Clear all commands associated with a breakpoint. */ - -static void -clear_breakpoint_commands (struct gdb_breakpoint *bp) -{ - struct point_command_list *cmd; - - if (bp->command_list == NULL) - return; - - cmd = bp->command_list; - - while (cmd != NULL) - { - struct point_command_list *cmd_next; - - cmd_next = cmd->next; - gdb_free_agent_expr (cmd->cmd); - free (cmd); - cmd = cmd_next; - } - - bp->command_list = NULL; -} - -void -clear_breakpoint_conditions_and_commands (struct gdb_breakpoint *bp) -{ - clear_breakpoint_conditions (bp); - clear_breakpoint_commands (bp); -} - -/* Add condition CONDITION to GDBserver's breakpoint BP. */ - -static void -add_condition_to_breakpoint (struct gdb_breakpoint *bp, - struct agent_expr *condition) -{ - struct point_cond_list *new_cond; - - /* Create new condition. */ - new_cond = XCNEW (struct point_cond_list); - new_cond->cond = condition; - - /* Add condition to the list. */ - new_cond->next = bp->cond_list; - bp->cond_list = new_cond; -} - -/* Add a target-side condition CONDITION to a breakpoint. */ - -int -add_breakpoint_condition (struct gdb_breakpoint *bp, const char **condition) -{ - const char *actparm = *condition; - struct agent_expr *cond; - - if (condition == NULL) - return 1; - - if (bp == NULL) - return 0; - - cond = gdb_parse_agent_expr (&actparm); - - if (cond == NULL) - { - warning ("Condition evaluation failed. Assuming unconditional."); - return 0; - } - - add_condition_to_breakpoint (bp, cond); - - *condition = actparm; - - return 1; -} - -/* Evaluate condition (if any) at breakpoint BP. Return 1 if - true and 0 otherwise. */ - -static int -gdb_condition_true_at_breakpoint_z_type (char z_type, CORE_ADDR addr) -{ - /* Fetch registers for the current inferior. */ - struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1); - ULONGEST value = 0; - struct point_cond_list *cl; - int err = 0; - struct eval_agent_expr_context ctx; - - if (bp == NULL) - return 0; - - /* Check if the breakpoint is unconditional. If it is, - the condition always evaluates to TRUE. */ - if (bp->cond_list == NULL) - return 1; - - ctx.regcache = get_thread_regcache (current_thread, 1); - ctx.tframe = NULL; - ctx.tpoint = NULL; - - /* Evaluate each condition in the breakpoint's list of conditions. - Return true if any of the conditions evaluates to TRUE. - - If we failed to evaluate the expression, TRUE is returned. This - forces GDB to reevaluate the conditions. */ - for (cl = bp->cond_list; - cl && !value && !err; cl = cl->next) - { - /* Evaluate the condition. */ - err = gdb_eval_agent_expr (&ctx, cl->cond, &value); - } - - if (err) - return 1; - - return (value != 0); -} - -int -gdb_condition_true_at_breakpoint (CORE_ADDR where) -{ - /* Only check code (software or hardware) breakpoints. */ - return (gdb_condition_true_at_breakpoint_z_type (Z_PACKET_SW_BP, where) - || gdb_condition_true_at_breakpoint_z_type (Z_PACKET_HW_BP, where)); -} - -/* Add commands COMMANDS to GDBserver's breakpoint BP. */ - -static void -add_commands_to_breakpoint (struct gdb_breakpoint *bp, - struct agent_expr *commands, int persist) -{ - struct point_command_list *new_cmd; - - /* Create new command. */ - new_cmd = XCNEW (struct point_command_list); - new_cmd->cmd = commands; - new_cmd->persistence = persist; - - /* Add commands to the list. */ - new_cmd->next = bp->command_list; - bp->command_list = new_cmd; -} - -/* Add a target-side command COMMAND to the breakpoint at ADDR. */ - -int -add_breakpoint_commands (struct gdb_breakpoint *bp, const char **command, - int persist) -{ - const char *actparm = *command; - struct agent_expr *cmd; - - if (command == NULL) - return 1; - - if (bp == NULL) - return 0; - - cmd = gdb_parse_agent_expr (&actparm); - - if (cmd == NULL) - { - warning ("Command evaluation failed. Disabling."); - return 0; - } - - add_commands_to_breakpoint (bp, cmd, persist); - - *command = actparm; - - return 1; -} - -/* Return true if there are no commands to run at this location, - which likely means we want to report back to GDB. */ - -static int -gdb_no_commands_at_breakpoint_z_type (char z_type, CORE_ADDR addr) -{ - struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1); - - if (bp == NULL) - return 1; - - if (debug_threads) - debug_printf ("at 0x%s, type Z%c, bp command_list is 0x%s\n", - paddress (addr), z_type, - phex_nz ((uintptr_t) bp->command_list, 0)); - return (bp->command_list == NULL); -} - -/* Return true if there are no commands to run at this location, - which likely means we want to report back to GDB. */ - -int -gdb_no_commands_at_breakpoint (CORE_ADDR where) -{ - /* Only check code (software or hardware) breakpoints. */ - return (gdb_no_commands_at_breakpoint_z_type (Z_PACKET_SW_BP, where) - && gdb_no_commands_at_breakpoint_z_type (Z_PACKET_HW_BP, where)); -} - -/* Run a breakpoint's commands. Returns 0 if there was a problem - running any command, 1 otherwise. */ - -static int -run_breakpoint_commands_z_type (char z_type, CORE_ADDR addr) -{ - /* Fetch registers for the current inferior. */ - struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1); - ULONGEST value = 0; - struct point_command_list *cl; - int err = 0; - struct eval_agent_expr_context ctx; - - if (bp == NULL) - return 1; - - ctx.regcache = get_thread_regcache (current_thread, 1); - ctx.tframe = NULL; - ctx.tpoint = NULL; - - for (cl = bp->command_list; - cl && !value && !err; cl = cl->next) - { - /* Run the command. */ - err = gdb_eval_agent_expr (&ctx, cl->cmd, &value); - - /* If one command has a problem, stop digging the hole deeper. */ - if (err) - return 0; - } - - return 1; -} - -void -run_breakpoint_commands (CORE_ADDR where) -{ - /* Only check code (software or hardware) breakpoints. If one - command has a problem, stop digging the hole deeper. */ - if (run_breakpoint_commands_z_type (Z_PACKET_SW_BP, where)) - run_breakpoint_commands_z_type (Z_PACKET_HW_BP, where); -} - -/* See mem-break.h. */ - -int -gdb_breakpoint_here (CORE_ADDR where) -{ - /* Only check code (software or hardware) breakpoints. */ - return (find_gdb_breakpoint (Z_PACKET_SW_BP, where, -1) != NULL - || find_gdb_breakpoint (Z_PACKET_HW_BP, where, -1) != NULL); -} - -void -set_single_step_breakpoint (CORE_ADDR stop_at, ptid_t ptid) -{ - struct single_step_breakpoint *bp; - - gdb_assert (current_ptid.pid () == ptid.pid ()); - - bp = (struct single_step_breakpoint *) set_breakpoint_type_at (single_step_breakpoint, - stop_at, NULL); - bp->ptid = ptid; -} - -void -delete_single_step_breakpoints (struct thread_info *thread) -{ - struct process_info *proc = get_thread_process (thread); - struct breakpoint *bp, **bp_link; - - bp = proc->breakpoints; - bp_link = &proc->breakpoints; - - while (bp) - { - if (bp->type == single_step_breakpoint - && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) - { - struct thread_info *saved_thread = current_thread; - - current_thread = thread; - *bp_link = bp->next; - release_breakpoint (proc, bp); - bp = *bp_link; - current_thread = saved_thread; - } - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } -} - -static void -uninsert_raw_breakpoint (struct raw_breakpoint *bp) -{ - if (bp->inserted < 0) - { - if (debug_threads) - debug_printf ("Breakpoint at %s is marked insert-disabled.\n", - paddress (bp->pc)); - } - else if (bp->inserted > 0) - { - int err; - - bp->inserted = 0; - - err = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, bp); - if (err != 0) - { - bp->inserted = 1; - - if (debug_threads) - debug_printf ("Failed to uninsert raw breakpoint at 0x%s.\n", - paddress (bp->pc)); - } - } -} - -void -uninsert_breakpoints_at (CORE_ADDR pc) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - int found = 0; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->pc == pc) - { - found = 1; - - if (bp->inserted) - uninsert_raw_breakpoint (bp); - } - - if (!found) - { - /* This can happen when we remove all breakpoints while handling - a step-over. */ - if (debug_threads) - debug_printf ("Could not find breakpoint at 0x%s " - "in list (uninserting).\n", - paddress (pc)); - } -} - -void -uninsert_all_breakpoints (void) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->inserted) - uninsert_raw_breakpoint (bp); -} - -void -uninsert_single_step_breakpoints (struct thread_info *thread) -{ - struct process_info *proc = get_thread_process (thread); - struct breakpoint *bp; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - { - if (bp->type == single_step_breakpoint - && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) - { - gdb_assert (bp->raw->inserted > 0); - - /* Only uninsert the raw breakpoint if it only belongs to a - reinsert breakpoint. */ - if (bp->raw->refcount == 1) - { - struct thread_info *saved_thread = current_thread; - - current_thread = thread; - uninsert_raw_breakpoint (bp->raw); - current_thread = saved_thread; - } - } - } -} - -static void -reinsert_raw_breakpoint (struct raw_breakpoint *bp) -{ - int err; - - if (bp->inserted) - return; - - err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp); - if (err == 0) - bp->inserted = 1; - else if (debug_threads) - debug_printf ("Failed to reinsert breakpoint at 0x%s (%d).\n", - paddress (bp->pc), err); -} - -void -reinsert_breakpoints_at (CORE_ADDR pc) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - int found = 0; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->pc == pc) - { - found = 1; - - reinsert_raw_breakpoint (bp); - } - - if (!found) - { - /* This can happen when we remove all breakpoints while handling - a step-over. */ - if (debug_threads) - debug_printf ("Could not find raw breakpoint at 0x%s " - "in list (reinserting).\n", - paddress (pc)); - } -} - -int -has_single_step_breakpoints (struct thread_info *thread) -{ - struct process_info *proc = get_thread_process (thread); - struct breakpoint *bp, **bp_link; - - bp = proc->breakpoints; - bp_link = &proc->breakpoints; - - while (bp) - { - if (bp->type == single_step_breakpoint - && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) - return 1; - else - { - bp_link = &bp->next; - bp = *bp_link; - } - } - - return 0; -} - -void -reinsert_all_breakpoints (void) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && !bp->inserted) - reinsert_raw_breakpoint (bp); -} - -void -reinsert_single_step_breakpoints (struct thread_info *thread) -{ - struct process_info *proc = get_thread_process (thread); - struct breakpoint *bp; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - { - if (bp->type == single_step_breakpoint - && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread)) - { - gdb_assert (bp->raw->inserted > 0); - - if (bp->raw->refcount == 1) - { - struct thread_info *saved_thread = current_thread; - - current_thread = thread; - reinsert_raw_breakpoint (bp->raw); - current_thread = saved_thread; - } - } - } -} - -void -check_breakpoints (CORE_ADDR stop_pc) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp, **bp_link; - - bp = proc->breakpoints; - bp_link = &proc->breakpoints; - - while (bp) - { - struct raw_breakpoint *raw = bp->raw; - - if ((raw->raw_type == raw_bkpt_type_sw - || raw->raw_type == raw_bkpt_type_hw) - && raw->pc == stop_pc) - { - if (!raw->inserted) - { - warning ("Hit a removed breakpoint?"); - return; - } - - if (bp->type == other_breakpoint) - { - struct other_breakpoint *other_bp - = (struct other_breakpoint *) bp; - - if (other_bp->handler != NULL && (*other_bp->handler) (stop_pc)) - { - *bp_link = bp->next; - - release_breakpoint (proc, bp); - - bp = *bp_link; - continue; - } - } - } - - bp_link = &bp->next; - bp = *bp_link; - } -} - -int -breakpoint_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->pc == addr) - return 1; - - return 0; -} - -int -breakpoint_inserted_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if ((bp->raw_type == raw_bkpt_type_sw - || bp->raw_type == raw_bkpt_type_hw) - && bp->pc == addr - && bp->inserted) - return 1; - - return 0; -} - -/* See mem-break.h. */ - -int -software_breakpoint_inserted_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if (bp->raw_type == raw_bkpt_type_sw - && bp->pc == addr - && bp->inserted) - return 1; - - return 0; -} - -/* See mem-break.h. */ - -int -hardware_breakpoint_inserted_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp; - - for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) - if (bp->raw_type == raw_bkpt_type_hw - && bp->pc == addr - && bp->inserted) - return 1; - - return 0; -} - -/* See mem-break.h. */ - -int -single_step_breakpoint_inserted_here (CORE_ADDR addr) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - if (bp->type == single_step_breakpoint - && bp->raw->pc == addr - && bp->raw->inserted) - return 1; - - return 0; -} - -static int -validate_inserted_breakpoint (struct raw_breakpoint *bp) -{ - unsigned char *buf; - int err; - - gdb_assert (bp->inserted); - gdb_assert (bp->raw_type == raw_bkpt_type_sw); - - buf = (unsigned char *) alloca (bp_size (bp)); - err = (*the_target->read_memory) (bp->pc, buf, bp_size (bp)); - if (err || memcmp (buf, bp_opcode (bp), bp_size (bp)) != 0) - { - /* Tag it as gone. */ - bp->inserted = -1; - return 0; - } - - return 1; -} - -static void -delete_disabled_breakpoints (void) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp, *next; - - for (bp = proc->breakpoints; bp != NULL; bp = next) - { - next = bp->next; - if (bp->raw->inserted < 0) - { - /* If single_step_breakpoints become disabled, that means the - manipulations (insertion and removal) of them are wrong. */ - gdb_assert (bp->type != single_step_breakpoint); - delete_breakpoint_1 (proc, bp); - } - } -} - -/* Check if breakpoints we inserted still appear to be inserted. They - may disappear due to a shared library unload, and worse, a new - shared library may be reloaded at the same address as the - previously unloaded one. If that happens, we should make sure that - the shadow memory of the old breakpoints isn't used when reading or - writing memory. */ - -void -validate_breakpoints (void) -{ - struct process_info *proc = current_process (); - struct breakpoint *bp; - - for (bp = proc->breakpoints; bp != NULL; bp = bp->next) - { - struct raw_breakpoint *raw = bp->raw; - - if (raw->raw_type == raw_bkpt_type_sw && raw->inserted > 0) - validate_inserted_breakpoint (raw); - } - - delete_disabled_breakpoints (); -} - -void -check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp = proc->raw_breakpoints; - struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps; - CORE_ADDR mem_end = mem_addr + mem_len; - int disabled_one = 0; - - for (; jp != NULL; jp = jp->next) - { - CORE_ADDR bp_end = jp->pc + jp->length; - CORE_ADDR start, end; - int copy_offset, copy_len, buf_offset; - - gdb_assert (fast_tracepoint_jump_shadow (jp) >= buf + mem_len - || buf >= fast_tracepoint_jump_shadow (jp) + (jp)->length); - - if (mem_addr >= bp_end) - continue; - if (jp->pc >= mem_end) - continue; - - start = jp->pc; - if (mem_addr > start) - start = mem_addr; - - end = bp_end; - if (end > mem_end) - end = mem_end; - - copy_len = end - start; - copy_offset = start - jp->pc; - buf_offset = start - mem_addr; - - if (jp->inserted) - memcpy (buf + buf_offset, - fast_tracepoint_jump_shadow (jp) + copy_offset, - copy_len); - } - - for (; bp != NULL; bp = bp->next) - { - CORE_ADDR bp_end = bp->pc + bp_size (bp); - CORE_ADDR start, end; - int copy_offset, copy_len, buf_offset; - - if (bp->raw_type != raw_bkpt_type_sw) - continue; - - gdb_assert (bp->old_data >= buf + mem_len - || buf >= &bp->old_data[sizeof (bp->old_data)]); - - if (mem_addr >= bp_end) - continue; - if (bp->pc >= mem_end) - continue; - - start = bp->pc; - if (mem_addr > start) - start = mem_addr; - - end = bp_end; - if (end > mem_end) - end = mem_end; - - copy_len = end - start; - copy_offset = start - bp->pc; - buf_offset = start - mem_addr; - - if (bp->inserted > 0) - { - if (validate_inserted_breakpoint (bp)) - memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len); - else - disabled_one = 1; - } - } - - if (disabled_one) - delete_disabled_breakpoints (); -} - -void -check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, - const unsigned char *myaddr, int mem_len) -{ - struct process_info *proc = current_process (); - struct raw_breakpoint *bp = proc->raw_breakpoints; - struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps; - CORE_ADDR mem_end = mem_addr + mem_len; - int disabled_one = 0; - - /* First fast tracepoint jumps, then breakpoint traps on top. */ - - for (; jp != NULL; jp = jp->next) - { - CORE_ADDR jp_end = jp->pc + jp->length; - CORE_ADDR start, end; - int copy_offset, copy_len, buf_offset; - - gdb_assert (fast_tracepoint_jump_shadow (jp) >= myaddr + mem_len - || myaddr >= fast_tracepoint_jump_shadow (jp) + (jp)->length); - gdb_assert (fast_tracepoint_jump_insn (jp) >= buf + mem_len - || buf >= fast_tracepoint_jump_insn (jp) + (jp)->length); - - if (mem_addr >= jp_end) - continue; - if (jp->pc >= mem_end) - continue; - - start = jp->pc; - if (mem_addr > start) - start = mem_addr; - - end = jp_end; - if (end > mem_end) - end = mem_end; - - copy_len = end - start; - copy_offset = start - jp->pc; - buf_offset = start - mem_addr; - - memcpy (fast_tracepoint_jump_shadow (jp) + copy_offset, - myaddr + buf_offset, copy_len); - if (jp->inserted) - memcpy (buf + buf_offset, - fast_tracepoint_jump_insn (jp) + copy_offset, copy_len); - } - - for (; bp != NULL; bp = bp->next) - { - CORE_ADDR bp_end = bp->pc + bp_size (bp); - CORE_ADDR start, end; - int copy_offset, copy_len, buf_offset; - - if (bp->raw_type != raw_bkpt_type_sw) - continue; - - gdb_assert (bp->old_data >= myaddr + mem_len - || myaddr >= &bp->old_data[sizeof (bp->old_data)]); - - if (mem_addr >= bp_end) - continue; - if (bp->pc >= mem_end) - continue; - - start = bp->pc; - if (mem_addr > start) - start = mem_addr; - - end = bp_end; - if (end > mem_end) - end = mem_end; - - copy_len = end - start; - copy_offset = start - bp->pc; - buf_offset = start - mem_addr; - - memcpy (bp->old_data + copy_offset, myaddr + buf_offset, copy_len); - if (bp->inserted > 0) - { - if (validate_inserted_breakpoint (bp)) - memcpy (buf + buf_offset, bp_opcode (bp) + copy_offset, copy_len); - else - disabled_one = 1; - } - } - - if (disabled_one) - delete_disabled_breakpoints (); -} - -/* Delete all breakpoints, and un-insert them from the inferior. */ - -void -delete_all_breakpoints (void) -{ - struct process_info *proc = current_process (); - - while (proc->breakpoints) - delete_breakpoint_1 (proc, proc->breakpoints); -} - -/* Clear the "inserted" flag in all breakpoints. */ - -void -mark_breakpoints_out (struct process_info *proc) -{ - struct raw_breakpoint *raw_bp; - - for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next) - raw_bp->inserted = 0; -} - -/* Release all breakpoints, but do not try to un-insert them from the - inferior. */ - -void -free_all_breakpoints (struct process_info *proc) -{ - mark_breakpoints_out (proc); - - /* Note: use PROC explicitly instead of deferring to - delete_all_breakpoints --- CURRENT_INFERIOR may already have been - released when we get here. There should be no call to - current_process from here on. */ - while (proc->breakpoints) - delete_breakpoint_1 (proc, proc->breakpoints); -} - -/* Clone an agent expression. */ - -static struct agent_expr * -clone_agent_expr (const struct agent_expr *src_ax) -{ - struct agent_expr *ax; - - ax = XCNEW (struct agent_expr); - ax->length = src_ax->length; - ax->bytes = (unsigned char *) xcalloc (ax->length, 1); - memcpy (ax->bytes, src_ax->bytes, ax->length); - return ax; -} - -/* Deep-copy the contents of one breakpoint to another. */ - -static struct breakpoint * -clone_one_breakpoint (const struct breakpoint *src, ptid_t ptid) -{ - struct breakpoint *dest; - struct raw_breakpoint *dest_raw; - - /* Clone the raw breakpoint. */ - dest_raw = XCNEW (struct raw_breakpoint); - dest_raw->raw_type = src->raw->raw_type; - dest_raw->refcount = src->raw->refcount; - dest_raw->pc = src->raw->pc; - dest_raw->kind = src->raw->kind; - memcpy (dest_raw->old_data, src->raw->old_data, MAX_BREAKPOINT_LEN); - dest_raw->inserted = src->raw->inserted; - - /* Clone the high-level breakpoint. */ - if (is_gdb_breakpoint (src->type)) - { - struct gdb_breakpoint *gdb_dest = XCNEW (struct gdb_breakpoint); - struct point_cond_list *current_cond; - struct point_cond_list *new_cond; - struct point_cond_list *cond_tail = NULL; - struct point_command_list *current_cmd; - struct point_command_list *new_cmd; - struct point_command_list *cmd_tail = NULL; - - /* Clone the condition list. */ - for (current_cond = ((struct gdb_breakpoint *) src)->cond_list; - current_cond != NULL; - current_cond = current_cond->next) - { - new_cond = XCNEW (struct point_cond_list); - new_cond->cond = clone_agent_expr (current_cond->cond); - APPEND_TO_LIST (&gdb_dest->cond_list, new_cond, cond_tail); - } - - /* Clone the command list. */ - for (current_cmd = ((struct gdb_breakpoint *) src)->command_list; - current_cmd != NULL; - current_cmd = current_cmd->next) - { - new_cmd = XCNEW (struct point_command_list); - new_cmd->cmd = clone_agent_expr (current_cmd->cmd); - new_cmd->persistence = current_cmd->persistence; - APPEND_TO_LIST (&gdb_dest->command_list, new_cmd, cmd_tail); - } - - dest = (struct breakpoint *) gdb_dest; - } - else if (src->type == other_breakpoint) - { - struct other_breakpoint *other_dest = XCNEW (struct other_breakpoint); - - other_dest->handler = ((struct other_breakpoint *) src)->handler; - dest = (struct breakpoint *) other_dest; - } - else if (src->type == single_step_breakpoint) - { - struct single_step_breakpoint *ss_dest - = XCNEW (struct single_step_breakpoint); - - dest = (struct breakpoint *) ss_dest; - /* Since single-step breakpoint is thread specific, don't copy - thread id from SRC, use ID instead. */ - ss_dest->ptid = ptid; - } - else - gdb_assert_not_reached ("unhandled breakpoint type"); - - dest->type = src->type; - dest->raw = dest_raw; - - return dest; -} - -/* See mem-break.h. */ - -void -clone_all_breakpoints (struct thread_info *child_thread, - const struct thread_info *parent_thread) -{ - const struct breakpoint *bp; - struct breakpoint *new_bkpt; - struct breakpoint *bkpt_tail = NULL; - struct raw_breakpoint *raw_bkpt_tail = NULL; - struct process_info *child_proc = get_thread_process (child_thread); - struct process_info *parent_proc = get_thread_process (parent_thread); - struct breakpoint **new_list = &child_proc->breakpoints; - struct raw_breakpoint **new_raw_list = &child_proc->raw_breakpoints; - - for (bp = parent_proc->breakpoints; bp != NULL; bp = bp->next) - { - new_bkpt = clone_one_breakpoint (bp, ptid_of (child_thread)); - APPEND_TO_LIST (new_list, new_bkpt, bkpt_tail); - APPEND_TO_LIST (new_raw_list, new_bkpt->raw, raw_bkpt_tail); - } -} |