From c8a4afbc116d3e5d0caa2b0fa0cdec112edf63f7 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Sat, 19 Oct 2002 19:30:38 +0000 Subject: [PATCH] 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. --- sys/ia64/ia64/elf_machdep.c | 33 ++++++++++++++- sys/ia64/ia64/machdep.c | 14 ------- sys/ia64/ia64/unwind.c | 83 +++++++++++++++++++++++-------------- sys/ia64/include/unwind.h | 7 +--- 4 files changed, 85 insertions(+), 52 deletions(-) diff --git a/sys/ia64/ia64/elf_machdep.c b/sys/ia64/ia64/elf_machdep.c index ea8695fda0a..c4a4938f5e2 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 88083a3b099..d3f5363235e 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 4c0e4def992..2da70419534 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; + int i; - 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; + KASSERT(!ia64_unwind_initialised, ("foo")); + + 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); } - ut = malloc(sizeof(struct ia64_unwind_table), M_UNWIND, M_NOWAIT); - if (!ut) - return 0; - - 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); - - return ut; -} - -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 cc00b617e4b..3509c054ea6 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);