summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2002-10-19 19:30:38 +0000
committermarcel <marcel@FreeBSD.org>2002-10-19 19:30:38 +0000
commit2a53e50eeb54dcf475578d37914a1647e40af38c (patch)
tree5c67cee6a275cbf8f35e1ce79012fed25ab1e423 /sys
parentd35d608c0774a40070b89879d9410bdf473177d7 (diff)
downloadFreeBSD-src-2a53e50eeb54dcf475578d37914a1647e40af38c.zip
FreeBSD-src-2a53e50eeb54dcf475578d37914a1647e40af38c.tar.gz
Update the unwind information when modules are loaded and unloaded
by using the linker hooks. Since these hooks are called for the kernel as well, we don't need to deal with that with a special SYSINIT. The initialization implicitly performed on the first update of the unwind information is made explicit with a SYSINIT. We now don't need the _ia64_unwind_{start|end} symbols.
Diffstat (limited to 'sys')
-rw-r--r--sys/ia64/ia64/elf_machdep.c33
-rw-r--r--sys/ia64/ia64/machdep.c14
-rw-r--r--sys/ia64/ia64/unwind.c83
-rw-r--r--sys/ia64/include/unwind.h7
4 files changed, 85 insertions, 52 deletions
diff --git a/sys/ia64/ia64/elf_machdep.c b/sys/ia64/ia64/elf_machdep.c
index ea8695f..c4a4938 100644
--- a/sys/ia64/ia64/elf_machdep.c
+++ b/sys/ia64/ia64/elf_machdep.c
@@ -218,15 +218,44 @@ elf_reloc(linker_file_t lf, const void *data, int type)
}
int
-elf_cpu_load_file(linker_file_t lf __unused)
+elf_cpu_load_file(linker_file_t lf)
{
+ Elf_Ehdr *hdr;
+ Elf_Phdr *ph, *phlim;
+ Elf_Addr reloc, vaddr;
+
+ hdr = (Elf_Ehdr *)(lf->address);
+ if (!IS_ELF(*hdr)) {
+ printf("Missing or corrupted ELF header at %p\n", hdr);
+ return (EFTYPE);
+ }
+
+ /*
+ * Iterate over the segments and register the unwind table if
+ * we come across it.
+ */
+ ph = (Elf_Phdr *)(lf->address + hdr->e_phoff);
+ phlim = ph + hdr->e_phnum;
+ reloc = ~0ULL;
+ while (ph < phlim) {
+ if (ph->p_type == PT_LOAD && reloc == ~0ULL)
+ reloc = (Elf_Addr)lf->address - ph->p_vaddr;
+
+ if (ph->p_type == PT_IA_64_UNWIND) {
+ vaddr = ph->p_vaddr + reloc;
+ ia64_add_unwind_table((vm_offset_t)lf->address, vaddr,
+ vaddr + ph->p_memsz);
+ }
+ ++ph;
+ }
return (0);
}
int
-elf_cpu_unload_file(linker_file_t lf __unused)
+elf_cpu_unload_file(linker_file_t lf)
{
+ ia64_delete_unwind_table((vm_offset_t)lf->address);
return (0);
}
diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c
index 88083a3..d3f5363 100644
--- a/sys/ia64/ia64/machdep.c
+++ b/sys/ia64/ia64/machdep.c
@@ -109,8 +109,6 @@ struct user *proc0uarea;
vm_offset_t proc0kstack;
extern u_int64_t kernel_text[], _end[];
-extern u_int64_t _ia64_unwind_start[];
-extern u_int64_t _ia64_unwind_end[];
FPSWA_INTERFACE *fpswa_interface;
@@ -303,18 +301,6 @@ identifycpu(void)
"\001LB");
}
-static void
-add_kernel_unwind_tables(void *arg)
-{
- /*
- * Register the kernel's unwind table.
- */
- ia64_add_unwind_table(kernel_text,
- _ia64_unwind_start,
- _ia64_unwind_end);
-}
-SYSINIT(unwind, SI_SUB_KMEM, SI_ORDER_ANY, add_kernel_unwind_tables, 0);
-
void
map_pal_code(void)
{
diff --git a/sys/ia64/ia64/unwind.c b/sys/ia64/ia64/unwind.c
index 4c0e4de..2da7041 100644
--- a/sys/ia64/ia64/unwind.c
+++ b/sys/ia64/ia64/unwind.c
@@ -122,42 +122,23 @@ static struct ia64_unwind_table_list ia64_unwind_tables;
static struct ia64_unwind_state ia64_unwind_state_static[MAX_UNWIND_STATES];
static LIST_HEAD(ia64_unwind_state_list, ia64_unwind_state) ia64_unwind_states;
-struct ia64_unwind_table *
-ia64_add_unwind_table(u_int64_t *base, u_int64_t *start, u_int64_t *end)
+static void
+ia64_initialise_unwind(void *arg __unused)
{
- struct ia64_unwind_table *ut;
-
- if (!ia64_unwind_initialised) {
- int i;
- LIST_INIT(&ia64_unwind_tables);
- LIST_INIT(&ia64_unwind_states);
- for (i = 0; i < MAX_UNWIND_STATES; i++) {
- LIST_INSERT_HEAD(&ia64_unwind_states,
- &ia64_unwind_state_static[i],
- us_link);
- }
- ia64_unwind_initialised = 1;
- }
-
- ut = malloc(sizeof(struct ia64_unwind_table), M_UNWIND, M_NOWAIT);
- if (!ut)
- return 0;
+ int i;
- ut->ut_base = (u_int64_t) base;
- ut->ut_start = (struct ia64_unwind_table_entry *) start;
- ut->ut_end = (struct ia64_unwind_table_entry *) end;
- ut->ut_limit = (u_int64_t) base + ut->ut_end[-1].ue_end;
- LIST_INSERT_HEAD(&ia64_unwind_tables, ut, ut_link);
+ KASSERT(!ia64_unwind_initialised, ("foo"));
- return ut;
-}
+ LIST_INIT(&ia64_unwind_tables);
+ LIST_INIT(&ia64_unwind_states);
+ for (i = 0; i < MAX_UNWIND_STATES; i++) {
+ LIST_INSERT_HEAD(&ia64_unwind_states,
+ &ia64_unwind_state_static[i], us_link);
+ }
-void
-ia64_free_unwind_table(struct ia64_unwind_table *ut)
-{
- LIST_REMOVE(ut, ut_link);
- free(ut, M_UNWIND);
+ ia64_unwind_initialised = 1;
}
+SYSINIT(unwind, SI_SUB_KMEM, SI_ORDER_ANY, ia64_initialise_unwind, 0);
static struct ia64_unwind_table *
find_table(u_int64_t ip)
@@ -198,6 +179,46 @@ find_entry(struct ia64_unwind_table *ut, u_int64_t ip)
return 0;
}
+int
+ia64_add_unwind_table(vm_offset_t base, vm_offset_t start, vm_offset_t end)
+{
+ struct ia64_unwind_table *ut;
+
+ KASSERT(ia64_unwind_initialised, ("foo"));
+
+ ut = malloc(sizeof(struct ia64_unwind_table), M_UNWIND, M_NOWAIT);
+ if (ut == NULL)
+ return (ENOMEM);
+
+ ut->ut_base = base;
+ ut->ut_start = (struct ia64_unwind_table_entry*)start;
+ ut->ut_end = (struct ia64_unwind_table_entry*)end;
+ ut->ut_limit = base + ut->ut_end[-1].ue_end;
+ LIST_INSERT_HEAD(&ia64_unwind_tables, ut, ut_link);
+
+ if (bootverbose)
+ printf("UNWIND: table added: base=%lx, start=%lx, end=%lx\n",
+ base, start, end);
+
+ return (0);
+}
+
+void
+ia64_delete_unwind_table(vm_offset_t base)
+{
+ struct ia64_unwind_table *ut;
+
+ KASSERT(ia64_unwind_initialised, ("foo"));
+
+ ut = find_table(base);
+ if (ut != NULL) {
+ LIST_REMOVE(ut, ut_link);
+ free(ut, M_UNWIND);
+ if (bootverbose)
+ printf("UNWIND: table removed: base=%lx\n", base);
+ }
+}
+
struct ia64_unwind_state *
ia64_create_unwind_state(struct trapframe *framep)
{
diff --git a/sys/ia64/include/unwind.h b/sys/ia64/include/unwind.h
index cc00b61..3509c05 100644
--- a/sys/ia64/include/unwind.h
+++ b/sys/ia64/include/unwind.h
@@ -26,12 +26,9 @@
* $FreeBSD$
*/
-struct ia64_unwind_table;
+int ia64_add_unwind_table(vm_offset_t, vm_offset_t, vm_offset_t);
+void ia64_delete_unwind_table(vm_offset_t);
-struct ia64_unwind_table *ia64_add_unwind_table(u_int64_t *base,
- u_int64_t *start,
- u_int64_t *end);
-void ia64_free_unwind_table(struct ia64_unwind_table *ut);
struct ia64_unwind_state *ia64_create_unwind_state(struct trapframe *framep);
void ia64_free_unwind_state(struct ia64_unwind_state *us);
u_int64_t ia64_unwind_state_get_ip(struct ia64_unwind_state *us);
OpenPOWER on IntegriCloud