Fix breakpoint cloning
diff --git a/breakpoint.h b/breakpoint.h
index 0509304..372c714 100644
--- a/breakpoint.h
+++ b/breakpoint.h
@@ -90,6 +90,13 @@
int breakpoint_init(struct breakpoint *bp, struct Process *proc,
target_address_t addr, struct library_symbol *libsym);
+/* Make a clone of breakpoint BP into the area of memory pointed to by
+ * RETP. The original breakpoint was assigned to process OLD_PROC,
+ * the cloned breakpoint will be attached to process NEW_PROC.
+ * Returns 0 on success or a negative value on failure. */
+int breakpoint_clone(struct breakpoint *retp, struct Process *new_proc,
+ struct breakpoint *bp, struct Process *old_proc);
+
/* Set callbacks. If CBS is non-NULL, then BP->cbs shall be NULL. */
void breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs);
diff --git a/breakpoints.c b/breakpoints.c
index dd1a010..42ca582 100644
--- a/breakpoints.c
+++ b/breakpoints.c
@@ -66,8 +66,25 @@
arch_breakpoint_destroy(struct breakpoint *sbp)
{
}
+
+int
+arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
+{
+ return 0;
+}
#endif
+static void
+breakpoint_init_base(struct breakpoint *bp, struct Process *proc,
+ target_address_t addr, struct library_symbol *libsym)
+{
+ bp->cbs = NULL;
+ bp->addr = addr;
+ memset(bp->orig_value, 0, sizeof(bp->orig_value));
+ bp->enabled = 0;
+ bp->libsym = libsym;
+}
+
/* On second thought, I don't think we need PROC. All the translation
* (arch_translate_address in particular) should be doable using
* static lookups of various sections in the ELF file. We shouldn't
@@ -76,11 +93,7 @@
breakpoint_init(struct breakpoint *bp, struct Process *proc,
target_address_t addr, struct library_symbol *libsym)
{
- bp->cbs = NULL;
- bp->addr = addr;
- memset(bp->orig_value, 0, sizeof(bp->orig_value));
- bp->enabled = 0;
- bp->libsym = libsym;
+ breakpoint_init_base(bp, proc, addr, libsym);
return arch_breakpoint_init(proc, bp);
}
@@ -97,11 +110,54 @@
{
if (bp == NULL)
return;
-
-
arch_breakpoint_destroy(bp);
}
+struct find_symbol_data {
+ struct library_symbol *old_libsym;
+ struct library_symbol *found_libsym;
+};
+
+static enum callback_status
+find_sym_in_lib(struct Process *proc, struct library *lib, void *u)
+{
+ struct find_symbol_data *fs = u;
+ fs->found_libsym
+ = library_each_symbol(lib, NULL, library_symbol_equal_cb,
+ fs->old_libsym);
+ return fs->found_libsym != NULL ? CBS_STOP : CBS_CONT;
+}
+
+int
+breakpoint_clone(struct breakpoint *retp, struct Process *new_proc,
+ struct breakpoint *bp, struct Process *old_proc)
+{
+ /* Find library and symbol that this breakpoint was linked to. */
+ struct library_symbol *libsym = bp->libsym;
+ struct library *lib = NULL;
+ if (libsym != NULL) {
+ struct find_symbol_data f_data = {
+ .old_libsym = libsym,
+ };
+ lib = proc_each_library(old_proc, NULL,
+ find_sym_in_lib, &f_data);
+ assert(lib != NULL);
+ libsym = f_data.found_libsym;
+ }
+
+ /* LIB and LIBSYM now hold the new library and symbol that
+ * correspond to the original breakpoint. Now we can do the
+ * clone itself. */
+ breakpoint_init_base(retp, new_proc, bp->addr, libsym);
+ memcpy(retp->orig_value, bp->orig_value, sizeof(bp->orig_value));
+ retp->enabled = bp->enabled;
+ retp->debug_enabled = bp->debug_enabled;
+ if (arch_breakpoint_clone(retp, bp) < 0)
+ return -1;
+ breakpoint_set_callbacks(retp, bp->cbs);
+ return 0;
+}
+
int
breakpoint_turn_on(struct breakpoint *bp, struct Process *proc)
{
diff --git a/common.h b/common.h
index eef3769..5c7ba09 100644
--- a/common.h
+++ b/common.h
@@ -235,6 +235,7 @@
int arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp);
void arch_breakpoint_destroy(struct breakpoint *sbp);
+int arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp);
typedef void *target_address_t;
/* This should extract entry point address and interpreter (dynamic
diff --git a/proc.c b/proc.c
index b9f269f..79af573 100644
--- a/proc.c
+++ b/proc.c
@@ -114,51 +114,25 @@
int error;
};
-struct find_symbol_data {
- struct library_symbol *old_libsym;
- struct library_symbol *found_libsym;
-};
-
-static enum callback_status
-find_sym_in_lib(struct Process *proc, struct library *lib, void *u)
-{
- struct find_symbol_data *fs = u;
- fs->found_libsym
- = library_each_symbol(lib, NULL, library_symbol_equal_cb,
- fs->old_libsym);
- return fs->found_libsym != NULL ? CBS_STOP : CBS_CONT;
-}
-
static void
clone_single_bp(void *key, void *value, void *u)
{
- target_address_t addr = (target_address_t)key;
struct breakpoint *bp = value;
struct clone_single_bp_data *data = u;
- /* Find library and symbol that this symbol was linked to. */
- struct library_symbol *libsym = bp->libsym;
- struct library *lib = NULL;
- if (libsym != NULL) {
- struct find_symbol_data f_data = {
- .old_libsym = libsym,
- };
- lib = proc_each_library(data->old_proc, NULL,
- find_sym_in_lib, &f_data);
- assert(lib != NULL);
- libsym = f_data.found_libsym;
- }
-
- /* LIB and LIBSYM now hold the new library and symbol that
- * correspond to the original breakpoint. Now we can do the
- * clone itself. */
+ data->error = 0;
struct breakpoint *clone = malloc(sizeof(*clone));
if (clone == NULL
- || breakpoint_init(clone, data->new_proc, addr, libsym) < 0) {
+ || breakpoint_clone(clone, data->new_proc,
+ bp, data->old_proc) < 0) {
+ fail:
+ free(clone);
data->error = -1;
- return;
}
- breakpoint_set_callbacks(clone, bp->cbs);
+ if (proc_add_breakpoint(data->new_proc->leader, clone) < 0) {
+ breakpoint_destroy(clone);
+ goto fail;
+ }
}
int
@@ -173,7 +147,7 @@
retp->tracesysgood = proc->tracesysgood;
/* For non-leader processes, that's all we need to do. */
- if (proc->leader != proc)
+ if (retp->leader != retp)
return 0;
/* Clone symbols first so that we can clone and relink
@@ -626,3 +600,53 @@
assert(!"Not yet implemented!");
abort();
}
+
+/* Dict doesn't support iteration restarts, so here's this contraption
+ * for now. XXX add restarts to dict. */
+struct each_breakpoint_data
+{
+ void *start;
+ void *end;
+ struct Process *proc;
+ enum callback_status (*cb)(struct Process *proc,
+ struct breakpoint *bp,
+ void *data);
+ void *cb_data;
+};
+
+static void
+each_breakpoint_cb(void *key, void *value, void *d)
+{
+ struct each_breakpoint_data *data = d;
+ if (data->end != NULL)
+ return;
+ if (data->start == key)
+ data->start = NULL;
+
+ if (data->start == NULL) {
+ switch (data->cb(data->proc, value, data->cb_data)) {
+ case CBS_FAIL:
+ /* XXX handle me */
+ case CBS_STOP:
+ data->end = key;
+ case CBS_CONT:
+ return;
+ }
+ }
+}
+
+void *
+proc_each_breakpoint(struct Process *proc, void *start,
+ enum callback_status (*cb)(struct Process *proc,
+ struct breakpoint *bp,
+ void *data), void *data)
+{
+ struct each_breakpoint_data dd = {
+ .start = start,
+ .proc = proc,
+ .cb = cb,
+ .cb_data = data,
+ };
+ dict_apply_to_all(proc->breakpoints, &each_breakpoint_cb, &dd);
+ return dd.end;
+}
diff --git a/proc.h b/proc.h
index 2759380..8b77c31 100644
--- a/proc.h
+++ b/proc.h
@@ -200,4 +200,12 @@
/* Remove BP from PROC. */
int proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp);
+/* Iterate through the libraries of PROC. See each_process for
+ * detailed description of the iteration interface. */
+void *proc_each_breakpoint(struct Process *proc, void *start,
+ enum callback_status (*cb)(struct Process *proc,
+ struct breakpoint *bp,
+ void *data),
+ void *data);
+
#endif /* _PROC_H_ */
diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c
index d2c57d9..324ff07 100644
--- a/sysdeps/linux-gnu/arm/breakpoint.c
+++ b/sysdeps/linux-gnu/arm/breakpoint.c
@@ -86,10 +86,13 @@
int
arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp)
{
- int thumb_mode = (int)addr & 1;
+ /* XXX That uintptr_t cast is there temporarily until
+ * target_address_t becomes integral type. */
+ int thumb_mode = ((uintptr_t)sbp->addr) & 1;
if (thumb_mode)
- addr = (void *)((int)addr & ~1);
+ sbp->addr = (void *)((uintptr_t)sbp->addr & ~1);
sbp->arch.thumb_mode = thumb_mode | proc->thumb_mode;
+ /* XXX This doesn't seem like it belongs here. */
proc->thumb_mode = 0;
return 0;
}
@@ -98,3 +101,10 @@
arch_breakpoint_destroy(struct breakpoint *sbp)
{
}
+
+int
+arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
+{
+ retp->arch.thumb_mode = sbp->arch.thumb_mode;
+ return 0;
+}
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
index 4aff818..3b03af8 100644
--- a/sysdeps/linux-gnu/ppc/plt.c
+++ b/sysdeps/linux-gnu/ppc/plt.c
@@ -548,3 +548,10 @@
arch_breakpoint_destroy(struct breakpoint *bp)
{
}
+
+int
+arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
+{
+ retp->arch = sbp->arch;
+ return 0;
+}