Change iterators each_task, each_process, library_each_symbol
... now the restarts are supported by start_after instead of start.
Otherwise the restart scenario was something like:
for (it *sym = NULL; (sym = next(sym)) != NULL; )
if ((sym = sym->next) == NULL)
break;
which just seems too convoluted.
diff --git a/library.c b/library.c
index d60a1a2..1ad5995 100644
--- a/library.c
+++ b/library.c
@@ -162,12 +162,12 @@
}
struct library_symbol *
-library_each_symbol(struct library *lib, struct library_symbol *it,
+library_each_symbol(struct library *lib, struct library_symbol *start_after,
enum callback_status (*cb)(struct library_symbol *, void *),
void *data)
{
- if (it == NULL)
- it = lib->symbols;
+ struct library_symbol *it = start_after == NULL ? lib->symbols
+ : start_after->next;
while (it != NULL) {
struct library_symbol *next = it->next;
diff --git a/library.h b/library.h
index 17f0c1b..13a4cab 100644
--- a/library.h
+++ b/library.h
@@ -120,10 +120,10 @@
void library_set_name(struct library *lib, const char *new_name, int own_name);
/* Iterate through list of symbols of library LIB. Restarts are
- * supported via START (see each_process for details of iteration
- * interface). */
+ * supported via START_AFTER (see each_process for details of
+ * iteration interface). */
struct library_symbol *library_each_symbol
- (struct library *lib, struct library_symbol *start,
+ (struct library *lib, struct library_symbol *start_after,
enum callback_status (*cb)(struct library_symbol *, void *),
void *data);
diff --git a/proc.c b/proc.c
index 82d7395..389c445 100644
--- a/proc.c
+++ b/proc.c
@@ -290,7 +290,7 @@
leader = pid2proc(pid)->leader;
enable_all_breakpoints(leader);
- each_task(pid2proc(pid)->leader, start_one_pid, NULL);
+ each_task(pid2proc(pid)->leader, NULL, start_one_pid, NULL);
}
static enum callback_status
@@ -330,15 +330,16 @@
}
struct Process *
-each_process(struct Process *it,
+each_process(struct Process *start_after,
enum callback_status(*cb)(struct Process *proc, void *data),
void *data)
{
- if (it == NULL)
- it = list_of_processes;
- for (; it != NULL; ) {
+ struct Process *it = start_after == NULL ? list_of_processes
+ : start_after->next;
+
+ while (it != NULL) {
/* Callback might call remove_process. */
- Process * next = it->next;
+ struct Process *next = it->next;
switch ((*cb)(it, data)) {
case CBS_STOP:
return it;
@@ -351,15 +352,19 @@
}
Process *
-each_task(struct Process *it,
+each_task(struct Process *proc, struct Process *start_after,
enum callback_status(*cb)(struct Process *proc, void *data),
void *data)
{
+ assert(proc != NULL);
+ struct Process *it = start_after == NULL ? proc->leader
+ : start_after->next;
+
if (it != NULL) {
- Process * leader = it->leader;
- for (; it != NULL && it->leader == leader; ) {
+ struct Process *leader = it->leader;
+ while (it != NULL && it->leader == leader) {
/* Callback might call remove_process. */
- Process * next = it->next;
+ struct Process *next = it->next;
switch ((*cb)(it, data)) {
case CBS_STOP:
return it;
@@ -446,7 +451,7 @@
debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
if (proc->leader == proc)
- each_task(proc, &clear_leader, NULL);
+ each_task(proc, NULL, &clear_leader, NULL);
unlist_process(proc);
delete_events_for(proc);
@@ -495,10 +500,8 @@
struct library_symbol *libsym = NULL;
while ((libsym = library_each_symbol(lib, libsym, breakpoint_for_symbol,
- proc)) != NULL) {
+ proc)) != NULL)
error(0, errno, "insert breakpoint for %s", libsym->name);
- libsym = libsym->next;
- }
}
int
diff --git a/proc.h b/proc.h
index 0f670e5..949bbe7 100644
--- a/proc.h
+++ b/proc.h
@@ -144,26 +144,25 @@
* called for each process. Tasks are considered to be processes for
* the purpose of this iterator.
*
- * Notes on this iteration interface: DATA is passed verbatim to CB.
- * If CB returns CBS_STOP, the iteration stops and the current
- * iterator is returned. That iterator can then be used to restart
- * the iteration. If you don't want CB to see the same process more
- * than once, restart with IT->next instead of just IT. NULL is
+ * Notes on this iteration interface: The iteration starts after the
+ * process designated by START_AFTER, or at the first process if
+ * START_AFTER is NULL. DATA is passed verbatim to CB. If CB returns
+ * CBS_STOP, the iteration stops and the current iterator is returned.
+ * That iterator can then be used to restart the iteration. NULL is
* returned when iteration ends.
*
* There's no provision for returning error states. Errors need to be
* signaled to the caller via DATA, together with any other data that
* the callback needs. */
-Process *each_process(Process *start,
+Process *each_process(Process *start_after,
enum callback_status (*cb)(struct Process *proc,
void *data),
void *data);
-/* Iterate through list of tasks of given process START. Normally you
- * start the iteration by calling this on PROC->leader, the iterator
- * doesn't do this for you (so as to support restarts). See above for
- * details on the iteration interface. */
-Process *each_task(Process *start,
+/* Iterate through list of tasks of given process PROC. Restarts are
+ * supported via START_AFTER (see each_process for details of
+ * iteration interface). */
+Process *each_task(struct Process *proc, struct Process *start_after,
enum callback_status (*cb)(struct Process *proc,
void *data),
void *data);
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index 20c42a8..30ff69a 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -340,9 +340,9 @@
}
static int
-is_vfork_parent(Process * task)
+is_vfork_parent(struct Process *task)
{
- return each_task(task->leader, &task_vforked, NULL) != NULL;
+ return each_task(task->leader, NULL, &task_vforked, NULL) != NULL;
}
static enum callback_status
@@ -481,11 +481,11 @@
if (proc == NULL)
continue;
if (proc->leader == leader) {
- each_task(leader, &untrace_task, NULL);
+ each_task(leader, NULL, &untrace_task, NULL);
break;
}
}
- each_task(leader, &remove_task, leader);
+ each_task(leader, NULL, &remove_task, leader);
destroy_event_handler(leader);
remove_task(leader, NULL);
}
@@ -728,7 +728,8 @@
switch (state) {
case psh_stopping:
/* If everyone is stopped, singlestep. */
- if (each_task(leader, &task_blocked, &self->pids) == NULL) {
+ if (each_task(leader, NULL, &task_blocked,
+ &self->pids) == NULL) {
debug(DEBUG_PROCESS, "all stopped, now SINGLESTEP %d",
teb->pid);
if (sbp->enabled)
@@ -835,7 +836,7 @@
handler->breakpoint_being_enabled = sbp;
install_event_handler(proc->leader, &handler->super);
- if (each_task(proc->leader, &send_sigstop,
+ if (each_task(proc->leader, NULL, &send_sigstop,
&handler->pids) != NULL)
goto fatal;
@@ -934,7 +935,7 @@
handler->super.destroy = ltrace_exiting_destroy;
install_event_handler(proc->leader, &handler->super);
- if (each_task(proc->leader, &send_sigstop,
+ if (each_task(proc->leader, NULL, &send_sigstop,
&handler->pids) != NULL)
goto fatal;