diff options
author | marcel <marcel@FreeBSD.org> | 2002-10-19 19:30:38 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2002-10-19 19:30:38 +0000 |
commit | 2a53e50eeb54dcf475578d37914a1647e40af38c (patch) | |
tree | 5c67cee6a275cbf8f35e1ce79012fed25ab1e423 /sys | |
parent | d35d608c0774a40070b89879d9410bdf473177d7 (diff) | |
download | FreeBSD-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.c | 33 | ||||
-rw-r--r-- | sys/ia64/ia64/machdep.c | 14 | ||||
-rw-r--r-- | sys/ia64/ia64/unwind.c | 83 | ||||
-rw-r--r-- | 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 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); |