/* Memory breakpoint operations for the remote server for GDB.
- Copyright (C) 2002-2014 Free Software Foundation, Inc.
+ Copyright (C) 2002-2018 Free Software Foundation, Inc.
Contributed by MontaVista Software.
#include "server.h"
#include "regcache.h"
#include "ax.h"
-#include <stdint.h>
-
-const unsigned char *breakpoint_data;
-int breakpoint_len;
#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
breakpoint for a given PC. */
CORE_ADDR pc;
- /* The breakpoint's size. */
- int size;
+ /* 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];
/* A GDB access watchpoint, requested with a Z4 packet. */
gdb_breakpoint_Z4,
- /* A basic-software-single-step breakpoint. */
- reinsert_breakpoint,
+ /* 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. */
/* 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
/* Point to the list of commands to run when this is hit. */
struct point_command_list *command_list;
+};
- /* Link to this breakpoint's raw breakpoint. This is always
- non-NULL. */
- struct raw_breakpoint *raw;
+/* 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,
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
case raw_bkpt_type_access_wp:
return hw_access;
default:
- fatal ("bad raw breakpoing type %d", (int) raw_type);
+ internal_error (__FILE__, __LINE__,
+ "bad raw breakpoint type %d", (int) raw_type);
}
}
{
gdb_assert ('0' <= z_type && z_type <= '4');
- return gdb_breakpoint_Z0 + (z_type - '0');
+ return (enum bkpt_type) (gdb_breakpoint_Z0 + (z_type - '0'));
}
/* See mem-break.h. */
}
}
+/* 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);
+}
+
int
-any_persistent_commands ()
+any_persistent_commands (void)
{
struct process_info *proc = current_process ();
struct breakpoint *bp;
for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
{
- for (cl = bp->command_list; cl != NULL; cl = cl->next)
- if (cl->persistence)
- return 1;
+ 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 1;
+ }
}
return 0;
NULL if not found. */
static struct raw_breakpoint *
-find_raw_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type, int size)
+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->size == size)
+ if (bp->pc == addr && bp->raw_type == type && bp->kind == kind)
return bp;
return NULL;
unsigned char buf[MAX_BREAKPOINT_LEN];
int err;
- if (breakpoint_data == NULL)
- return 1;
-
- /* If the architecture treats the size field of Z packets as a
- 'kind' field, then we'll need to be able to know which is the
- breakpoint instruction too. */
- if (bp->size != breakpoint_len)
- {
- if (debug_threads)
- debug_printf ("Don't know how to insert breakpoints of size %d.\n",
- bp->size);
- return -1;
- }
-
/* 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, breakpoint_len);
+ err = read_inferior_memory (bp->pc, buf, bp_size (bp));
if (err != 0)
{
if (debug_threads)
}
else
{
- memcpy (bp->old_data, buf, breakpoint_len);
+ memcpy (bp->old_data, buf, bp_size (bp));
- err = (*the_target->write_memory) (bp->pc, breakpoint_data,
- breakpoint_len);
+ err = (*the_target->write_memory) (bp->pc, bp_opcode (bp),
+ bp_size (bp));
if (err != 0)
{
if (debug_threads)
note that we need to pass the current shadow contents, because
write_inferior_memory updates any shadow memory with what we pass
here, and we want that to be a nop. */
- memcpy (buf, bp->old_data, breakpoint_len);
- err = write_inferior_memory (bp->pc, buf, breakpoint_len);
+ memcpy (buf, bp->old_data, bp_size (bp));
+ err = write_inferior_memory (bp->pc, buf, bp_size (bp));
if (err != 0)
{
if (debug_threads)
return err != 0 ? -1 : 0;
}
-/* Set a RAW breakpoint of type TYPE and size SIZE at WHERE. On
+/* 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 size,
+set_raw_breakpoint_at (enum raw_bkpt_type type, CORE_ADDR where, int kind,
int *err)
{
struct process_info *proc = current_process ();
if (type == raw_bkpt_type_sw || type == raw_bkpt_type_hw)
{
bp = find_enabled_raw_code_breakpoint_at (where, type);
- if (bp != NULL && bp->size != size)
+ if (bp != NULL && bp->kind != kind)
{
- /* A different size than previously seen. The previous
+ /* A different kind than previously seen. The previous
breakpoint must be gone then. */
if (debug_threads)
- debug_printf ("Inconsistent breakpoint size? Was %d, now %d.\n",
- bp->size, size);
+ 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, size);
+ bp = find_raw_breakpoint_at (where, type, kind);
- if (bp != NULL)
+ gdb::unique_xmalloc_ptr<struct raw_breakpoint> bp_holder;
+ if (bp == NULL)
{
- bp->refcount++;
- return bp;
+ bp_holder.reset (XCNEW (struct raw_breakpoint));
+ bp = bp_holder.get ();
+ bp->pc = where;
+ bp->kind = kind;
+ bp->raw_type = type;
}
- bp = xcalloc (1, sizeof (*bp));
- bp->pc = where;
- bp->size = size;
- bp->refcount = 1;
- bp->raw_type = type;
-
- *err = the_target->insert_point (bp->raw_type, bp->pc, bp->size, bp);
- if (*err != 0)
+ if (!bp->inserted)
{
- if (debug_threads)
- debug_printf ("Failed to insert breakpoint at 0x%s (%d).\n",
- paddress (where), *err);
- free (bp);
- return NULL;
+ *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;
}
- bp->inserted = 1;
- /* Link the breakpoint in. */
- bp->next = proc->raw_breakpoints;
- proc->raw_breakpoints = bp;
+ /* 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;
}
pass the current shadow contents, because
write_inferior_memory updates any shadow memory with
what we pass here, and we want that to be a nop. */
- buf = alloca (bp->length);
+ buf = (unsigned char *) alloca (bp->length);
memcpy (buf, fast_tracepoint_jump_shadow (bp), bp->length);
ret = write_inferior_memory (bp->pc, buf, bp->length);
if (ret != 0)
/* 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 = xcalloc (1, sizeof (*jp) + (length * 2));
+ 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 = alloca (length);
+ 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
pass the current shadow contents, because
write_inferior_memory updates any shadow memory with what we
pass here, and we want that to be a nop. */
- buf = alloca (jp->length);
+ buf = (unsigned char *) alloca (jp->length);
memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length);
err = write_inferior_memory (jp->pc, buf, jp->length);
if (err != 0)
to pass the current shadow contents, because
write_inferior_memory updates any shadow memory with what we pass
here, and we want that to be a nop. */
- buf = alloca (jp->length);
+ buf = (unsigned char *) alloca (jp->length);
memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length);
err = write_inferior_memory (where, buf, jp->length);
if (err != 0)
}
/* Set a high-level breakpoint of type TYPE, with low level type
- RAW_TYPE and size SIZE, at WHERE. On success, a pointer to the new
+ 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
static struct breakpoint *
set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type,
- CORE_ADDR where, int size,
+ 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, size, err);
+ raw = set_raw_breakpoint_at (raw_type, where, kind, err);
if (raw == NULL)
{
return NULL;
}
- bp = xcalloc (1, sizeof (struct breakpoint));
- bp->type = type;
+ 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->handler = handler;
bp->next = proc->breakpoints;
proc->breakpoints = bp;
return bp;
}
-/* See mem-break.h */
+/* Set breakpoint of TYPE on address WHERE with handler HANDLER. */
-struct breakpoint *
-set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
+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 (other_breakpoint, raw_bkpt_type_sw,
- where, breakpoint_len, handler,
+ 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)
*bp_link = bp->next;
- ret = the_target->remove_point (bp->raw_type, bp->pc, bp->size,
+ ret = the_target->remove_point (bp->raw_type, bp->pc, bp->kind,
bp);
if (ret != 0)
{
return delete_breakpoint_1 (proc, todel);
}
-/* Locate a GDB breakpoint of type Z_TYPE and size SIZE placed at
- address ADDR and return a pointer to its structure. If SIZE is -1,
- the breakpoints' sizes are ignored. */
+/* 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 breakpoint *
-find_gdb_breakpoint (char z_type, CORE_ADDR addr, int size)
+static struct gdb_breakpoint *
+find_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind)
{
struct process_info *proc = current_process ();
struct breakpoint *bp;
for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
if (bp->type == type && bp->raw->pc == addr
- && (size == -1 || bp->raw->size == size))
- return bp;
+ && (kind == -1 || bp->raw->kind == kind))
+ return (struct gdb_breakpoint *) bp;
return NULL;
}
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 size SIZE.
+/* 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 breakpoint *
-set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size, int *err)
+static struct gdb_breakpoint *
+set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind, int *err)
{
- struct breakpoint *bp;
+ struct gdb_breakpoint *bp;
enum bkpt_type type;
enum raw_bkpt_type raw_type;
if (bp != NULL)
{
- if (bp->raw->size != size)
+ if (bp->base.raw->kind != kind)
{
- /* A different size than previously seen. The previous
+ /* A different kind than previously seen. The previous
breakpoint must be gone then. */
- bp->raw->inserted = -1;
- delete_breakpoint (bp);
+ bp->base.raw->inserted = -1;
+ delete_breakpoint ((struct breakpoint *) bp);
bp = NULL;
}
else if (z_type == Z_PACKET_SW_BP)
}
else
{
- /* Data breakpoints for the same address but different size are
+ /* 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, size);
+ bp = find_gdb_breakpoint (z_type, addr, kind);
}
if (bp != NULL)
raw_type = Z_packet_to_raw_bkpt_type (z_type);
type = Z_packet_to_bkpt_type (z_type);
- return set_breakpoint (type, raw_type, addr, size, NULL, err);
+ return (struct gdb_breakpoint *) set_breakpoint (type, raw_type, addr,
+ kind, NULL, err);
}
static int
*err = 1;
return 0;
}
- else if (current_inferior == NULL)
- {
- *err = -1;
- return 0;
- }
- else
- return 1;
+
+ 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 breakpoint *
-set_gdb_breakpoint (char z_type, CORE_ADDR addr, int size, int *err)
+struct gdb_breakpoint *
+set_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind, int *err)
{
- struct breakpoint *bp;
+ struct gdb_breakpoint *bp;
if (!check_gdb_bp_preconditions (z_type, err))
return NULL;
access memory. */
if (z_type == Z_PACKET_SW_BP)
{
- *err = prepare_to_access_memory ();
- if (*err != 0)
- return NULL;
+ if (prepare_to_access_memory () != 0)
+ {
+ *err = -1;
+ return NULL;
+ }
}
- bp = set_gdb_breakpoint_1 (z_type, addr, size, err);
+ 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 size SIZE previously
+/* 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 size)
+delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind)
{
- struct breakpoint *bp;
+ struct gdb_breakpoint *bp;
int err;
- bp = find_gdb_breakpoint (z_type, addr, size);
+ bp = find_gdb_breakpoint (z_type, addr, kind);
if (bp == NULL)
return -1;
- /* Before deleting the breakpoint, make sure to free
- its condition list. */
- clear_breakpoint_conditions (bp);
- err = delete_breakpoint (bp);
+ /* 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;
knows to prepare to access memory for Z0 breakpoints. */
int
-delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int size)
+delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind)
{
int ret;
return -1;
}
- ret = delete_gdb_breakpoint_1 (z_type, addr, size);
+ ret = delete_gdb_breakpoint_1 (z_type, addr, kind);
if (z_type == Z_PACKET_SW_BP)
done_accessing_memory ();
/* Clear all conditions associated with a breakpoint. */
-void
-clear_breakpoint_conditions (struct breakpoint *bp)
+static void
+clear_breakpoint_conditions (struct gdb_breakpoint *bp)
{
struct point_cond_list *cond;
struct point_cond_list *cond_next;
cond_next = cond->next;
- free (cond->cond->bytes);
- free (cond->cond);
+ 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 breakpoint *bp,
+add_condition_to_breakpoint (struct gdb_breakpoint *bp,
struct agent_expr *condition)
{
struct point_cond_list *new_cond;
/* Create new condition. */
- new_cond = xcalloc (1, sizeof (*new_cond));
+ new_cond = XCNEW (struct point_cond_list);
new_cond->cond = condition;
/* Add condition to the list. */
/* Add a target-side condition CONDITION to a breakpoint. */
int
-add_breakpoint_condition (struct breakpoint *bp, char **condition)
+add_breakpoint_condition (struct gdb_breakpoint *bp, const char **condition)
{
- char *actparm = *condition;
+ const char *actparm = *condition;
struct agent_expr *cond;
if (condition == NULL)
if (cond == NULL)
{
- fprintf (stderr, "Condition evaluation failed. "
- "Assuming unconditional.\n");
+ warning ("Condition evaluation failed. Assuming unconditional.");
return 0;
}
gdb_condition_true_at_breakpoint_z_type (char z_type, CORE_ADDR addr)
{
/* Fetch registers for the current inferior. */
- struct breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
+ struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
ULONGEST value = 0;
struct point_cond_list *cl;
int err = 0;
if (bp->cond_list == NULL)
return 1;
- ctx.regcache = get_thread_regcache (current_inferior, 1);
+ ctx.regcache = get_thread_regcache (current_thread, 1);
ctx.tframe = NULL;
ctx.tpoint = NULL;
/* Add commands COMMANDS to GDBserver's breakpoint BP. */
-void
-add_commands_to_breakpoint (struct 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 = xcalloc (1, sizeof (*new_cmd));
+ new_cmd = XCNEW (struct point_command_list);
new_cmd->cmd = commands;
new_cmd->persistence = persist;
/* Add a target-side command COMMAND to the breakpoint at ADDR. */
int
-add_breakpoint_commands (struct breakpoint *bp, char **command,
+add_breakpoint_commands (struct gdb_breakpoint *bp, const char **command,
int persist)
{
- char *actparm = *command;
+ const char *actparm = *command;
struct agent_expr *cmd;
if (command == NULL)
if (cmd == NULL)
{
- fprintf (stderr, "Command evaluation failed. "
- "Disabling.\n");
+ warning ("Command evaluation failed. Disabling.");
return 0;
}
static int
gdb_no_commands_at_breakpoint_z_type (char z_type, CORE_ADDR addr)
{
- struct breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
+ struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
if (bp == NULL)
return 1;
run_breakpoint_commands_z_type (char z_type, CORE_ADDR addr)
{
/* Fetch registers for the current inferior. */
- struct breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
+ struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
ULONGEST value = 0;
struct point_command_list *cl;
int err = 0;
if (bp == NULL)
return 1;
- ctx.regcache = get_thread_regcache (current_inferior, 1);
+ ctx.regcache = get_thread_regcache (current_thread, 1);
ctx.tframe = NULL;
ctx.tpoint = NULL;
}
void
-set_reinsert_breakpoint (CORE_ADDR stop_at)
+set_single_step_breakpoint (CORE_ADDR stop_at, ptid_t ptid)
{
- struct breakpoint *bp;
+ struct single_step_breakpoint *bp;
+
+ gdb_assert (current_ptid.pid () == ptid.pid ());
- bp = set_breakpoint_at (stop_at, NULL);
- bp->type = reinsert_breakpoint;
+ bp = (struct single_step_breakpoint *) set_breakpoint_type_at (single_step_breakpoint,
+ stop_at, NULL);
+ bp->ptid = ptid;
}
void
-delete_reinsert_breakpoints (void)
+delete_single_step_breakpoints (struct thread_info *thread)
{
- struct process_info *proc = current_process ();
+ struct process_info *proc = get_thread_process (thread);
struct breakpoint *bp, **bp_link;
bp = proc->breakpoints;
while (bp)
{
- if (bp->type == reinsert_breakpoint)
+ 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->inserted = 0;
- err = the_target->remove_point (bp->raw_type, bp->pc, bp->size, bp);
+ err = the_target->remove_point (bp->raw_type, bp->pc, bp->kind, bp);
if (err != 0)
{
bp->inserted = 1;
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)
- error ("Breakpoint already inserted at reinsert time.");
+ return;
- err = the_target->insert_point (bp->raw_type, bp->pc, bp->size, bp);
+ err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp);
if (err == 0)
bp->inserted = 1;
else if (debug_threads)
}
}
+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)
{
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)
{
return;
}
- if (bp->handler != NULL && (*bp->handler) (stop_pc))
+ if (bp->type == other_breakpoint)
{
- *bp_link = bp->next;
+ struct other_breakpoint *other_bp
+ = (struct other_breakpoint *) bp;
- release_breakpoint (proc, bp);
+ if (other_bp->handler != NULL && (*other_bp->handler) (stop_pc))
+ {
+ *bp_link = bp->next;
+
+ release_breakpoint (proc, bp);
- bp = *bp_link;
- continue;
+ bp = *bp_link;
+ continue;
+ }
}
}
}
}
-void
-set_breakpoint_data (const unsigned char *bp_data, int bp_len)
-{
- breakpoint_data = bp_data;
- breakpoint_len = bp_len;
-}
-
int
breakpoint_here (CORE_ADDR addr)
{
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)
{
gdb_assert (bp->inserted);
gdb_assert (bp->raw_type == raw_bkpt_type_sw);
- buf = alloca (breakpoint_len);
- err = (*the_target->read_memory) (bp->pc, buf, breakpoint_len);
- if (err || memcmp (buf, breakpoint_data, breakpoint_len) != 0)
+ 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;
{
next = bp->next;
if (bp->raw->inserted < 0)
- delete_breakpoint_1 (proc, bp);
+ {
+ /* 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);
+ }
}
}
for (; bp != NULL; bp = bp->next)
{
- CORE_ADDR bp_end = bp->pc + breakpoint_len;
+ CORE_ADDR bp_end = bp->pc + bp_size (bp);
CORE_ADDR start, end;
int copy_offset, copy_len, buf_offset;
for (; bp != NULL; bp = bp->next)
{
- CORE_ADDR bp_end = bp->pc + breakpoint_len;
+ CORE_ADDR bp_end = bp->pc + bp_size (bp);
CORE_ADDR start, end;
int copy_offset, copy_len, buf_offset;
if (bp->inserted > 0)
{
if (validate_inserted_breakpoint (bp))
- memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
+ memcpy (buf + buf_offset, bp_opcode (bp) + copy_offset, copy_len);
else
disabled_one = 1;
}
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);
+ }
+}