Add auxv reader
We should be able to instrument dynamic linker as well, if that is
requested. Unfortunately we may still need artificial _start probe,
because we don't know _r_debug address until the dynamic linker fills
the DT_DEBUG entry. (Though we are likely to find _r_debug in symbol
table if we look.)
diff --git a/common.h b/common.h
index 0d824da..eef3769 100644
--- a/common.h
+++ b/common.h
@@ -236,5 +236,13 @@
int arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp);
void arch_breakpoint_destroy(struct breakpoint *sbp);
+typedef void *target_address_t;
+/* This should extract entry point address and interpreter (dynamic
+ * linker) bias if possible. Returns 0 if there were no errors, -1
+ * otherwise. Sets *ENTRYP and *INTERP_BIASP to non-zero values if
+ * the corresponding value is known. Unknown values are set to 0. */
+int process_get_entry(struct Process *proc,
+ target_address_t *entryp,
+ target_address_t *interp_biasp);
#endif
diff --git a/proc.c b/proc.c
index c50236b..afdc3a8 100644
--- a/proc.c
+++ b/proc.c
@@ -72,13 +72,26 @@
return -1;
}
- if (proc->leader == proc && breakpoints_init(proc, enable) < 0) {
- fprintf(stderr, "failed to init breakpoints %d\n",
+ /* For secondary threads, this is all that we need to do. */
+ if (proc->leader != proc)
+ return 0;
+
+ target_address_t entry;
+ target_address_t interp_bias;
+ if (process_get_entry(proc, &entry, &interp_bias) < 0) {
+ fprintf(stderr, "Couldn't get entry points of process %d\n",
proc->pid);
+ fail:
process_bare_destroy(proc);
return -1;
}
+ if (breakpoints_init(proc, enable) < 0) {
+ fprintf(stderr, "failed to init breakpoints %d\n",
+ proc->pid);
+ goto fail;
+ }
+
return 0;
}
diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
index 8a63ed9..3eacf2a 100644
--- a/sysdeps/linux-gnu/proc.c
+++ b/sysdeps/linux-gnu/proc.c
@@ -567,6 +567,76 @@
return 0;
}
+static int
+fetch_auxv64_entry(int fd, Elf64_auxv_t *ret)
+{
+ /* Reaching EOF is as much problem as not reading whole
+ * entry. */
+ return read(fd, ret, sizeof(*ret)) == sizeof(*ret) ? 0 : -1;
+}
+
+static int
+fetch_auxv32_entry(int fd, Elf64_auxv_t *ret)
+{
+ Elf32_auxv_t auxv;
+ if (read(fd, &auxv, sizeof(auxv)) != sizeof(auxv))
+ return -1;
+
+ ret->a_type = auxv.a_type;
+ ret->a_un.a_val = auxv.a_un.a_val;
+ return 0;
+}
+
+static int (*
+auxv_fetcher(struct Process *proc))(int, Elf64_auxv_t *)
+{
+ return select_32_64(proc, fetch_auxv32_entry, fetch_auxv64_entry);
+}
+
+int
+process_get_entry(struct Process *proc,
+ target_address_t *entryp,
+ target_address_t *interp_biasp)
+{
+ PROC_PID_FILE(fn, "/proc/%d/auxv", proc->pid);
+ int fd = open(fn, O_RDONLY);
+ if (fd == -1) {
+ fail:
+ error(0, errno, "couldn't read %s", fn);
+ done:
+ if (fd != -1)
+ close(fd);
+ return fd == -1 ? -1 : 0;
+ }
+
+ target_address_t at_entry = 0;
+ target_address_t at_bias = 0;
+ while (1) {
+ Elf64_auxv_t entry;
+ if (auxv_fetcher(proc)(fd, &entry) < 0)
+ goto fail;
+
+ switch (entry.a_type) {
+ case AT_BASE:
+ at_bias = (target_address_t)entry.a_un.a_val;
+ continue;
+
+ case AT_ENTRY:
+ at_entry = (target_address_t)entry.a_un.a_val;
+ default:
+ continue;
+
+ case AT_NULL:
+ break;
+ }
+ break;
+ }
+
+ *entryp = at_entry;
+ *interp_biasp = at_bias;
+ goto done;
+}
+
int
task_kill (pid_t pid, int sig)
{