+ if (bp == todel)
+ {
+ if (--bp->refcount == 0)
+ {
+ struct fast_tracepoint_jump *prev_bp_link = *bp_link;
+
+ /* Unlink it. */
+ *bp_link = bp->next;
+
+ /* Since there can be breakpoints inserted in the same
+ address range, we use `write_inferior_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
+ write_inferior_memory updates any shadow memory with
+ what we pass here, and we want that to be a nop. */
+ ret = write_inferior_memory (bp->pc,
+ fast_tracepoint_jump_shadow (bp),
+ bp->length);
+ if (ret != 0)
+ {
+ /* Something went wrong, relink the jump. */
+ *bp_link = prev_bp_link;
+
+ if (debug_threads)
+ fprintf (stderr,
+ "Failed to uninsert fast tracepoint jump "
+ "at 0x%s (%s) while deleting it.\n",
+ paddress (bp->pc), 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;
+}
+
+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;
+
+ /* 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 = xcalloc (1, sizeof (*jp) + (length * 2));
+ jp->pc = where;
+ jp->length = length;
+ memcpy (fast_tracepoint_jump_insn (jp), insn, length);
+ jp->refcount = 1;
+
+ /* 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,
+ fast_tracepoint_jump_shadow (jp), jp->length);
+ if (err != 0)
+ {
+ if (debug_threads)
+ fprintf (stderr,
+ "Failed to read shadow memory of"
+ " fast tracepoint at 0x%s (%s).\n",
+ paddress (where), strerror (err));
+ free (jp);
+ return NULL;
+ }
+
+ /* 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 `write_inferior_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 write_inferior_memory
+ updates any shadow memory with what we pass here, and we want
+ that to be a nop. */
+ err = write_inferior_memory (where, fast_tracepoint_jump_shadow (jp),
+ length);
+ if (err != 0)
+ {
+ if (debug_threads)
+ fprintf (stderr,
+ "Failed to insert fast tracepoint jump at 0x%s (%s).\n",
+ paddress (where), 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)
+ fprintf (stderr,
+ "Could not find fast tracepoint jump at 0x%s "
+ "in list (uninserting).\n",
+ paddress (pc));