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.
This commit is contained in:
Marcel Moolenaar 2002-10-19 19:30:38 +00:00
parent 1aeb23cdfa
commit c8a4afbc11
4 changed files with 85 additions and 52 deletions

View file

@ -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);
}

View file

@ -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)
{

View file

@ -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)
{

View file

@ -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);