+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. */
+