Commit 60b75a3c authored by David Mosberger's avatar David Mosberger

ia64: Fix/finish kernel module table support so it actually works.

parent 7502ff99
...@@ -322,6 +322,10 @@ module_alloc (unsigned long size) ...@@ -322,6 +322,10 @@ module_alloc (unsigned long size)
void void
module_free (struct module *mod, void *module_region) module_free (struct module *mod, void *module_region)
{ {
if (mod->arch.init_unw_table && module_region == mod->module_init) {
unw_remove_unwind_table(mod->arch.init_unw_table);
mod->arch.init_unw_table = NULL;
}
vfree(module_region); vfree(module_region);
} }
...@@ -843,23 +847,87 @@ apply_relocate (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, ...@@ -843,23 +847,87 @@ apply_relocate (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex,
return -ENOEXEC; return -ENOEXEC;
} }
/*
* Modules contain a single unwind table which covers both the core and the init text
* sections but since the two are not contiguous, we need to split this table up such that
* we can register (and unregister) each "segment" seperately. Fortunately, this sounds
* more complicated than it really is.
*/
static void
register_unwind_table (struct module *mod)
{
struct unw_table_entry *start = (void *) mod->arch.unwind->sh_addr;
struct unw_table_entry *end = start + mod->arch.unwind->sh_size / sizeof (*start);
struct unw_table_entry tmp, *e1, *e2, *core, *init;
unsigned long num_init = 0, num_core = 0;
/* First, count how many init and core unwind-table entries there are. */
for (e1 = start; e1 < end; ++e1)
if (in_init(mod, e1->start_offset))
++num_init;
else
++num_core;
/*
* Second, sort the table such that all unwind-table entries for the init and core
* text sections are nicely separated. We do this with a stupid bubble sort
* (unwind tables don't get ridiculously huge).
*/
for (e1 = start; e1 < end; ++e1) {
for (e2 = e1 + 1; e2 < end; ++e2) {
if (e2->start_offset < e1->start_offset) {
tmp = *e1;
*e1 = *e2;
*e2 = tmp;
}
}
}
/*
* Third, locate the init and core segments in the unwind table:
*/
if (in_init(mod, start->start_offset)) {
init = start;
core = start + num_init;
} else {
core = start;
init = start + num_core;
}
DEBUGP("%s: name=%s, gp=%lx, num_init=%lu, num_core=%lu\n", __FUNCTION__,
mod->name, mod->arch.gp, num_init, num_core);
/*
* Fourth, register both tables (if not empty).
*/
if (num_core > 0) {
mod->arch.core_unw_table = unw_add_unwind_table(mod->name, 0, mod->arch.gp,
core, core + num_core);
DEBUGP("%s: core: handle=%p [%p-%p)\n", __FUNCTION__,
mod->arch.core_unw_table, core, core + num_core);
}
if (num_init > 0) {
mod->arch.init_unw_table = unw_add_unwind_table(mod->name, 0, mod->arch.gp,
init, init + num_init);
DEBUGP("%s: init: handle=%p [%p-%p)\n", __FUNCTION__,
mod->arch.init_unw_table, init, init + num_init);
}
}
int int
module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod) module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod)
{ {
DEBUGP("%s: init: entry=%p\n", __FUNCTION__, mod->init); DEBUGP("%s: init: entry=%p\n", __FUNCTION__, mod->init);
if (mod->arch.unwind) if (mod->arch.unwind)
mod->arch.unw_table = unw_add_unwind_table(mod->name, 0, mod->arch.gp, register_unwind_table(mod);
(void *) mod->arch.unwind->sh_addr,
((void *) mod->arch.unwind->sh_addr
+ mod->arch.unwind->sh_size));
return 0; return 0;
} }
void void
module_arch_cleanup (struct module *mod) module_arch_cleanup (struct module *mod)
{ {
if (mod->arch.unwind) if (mod->arch.init_unw_table)
unw_remove_unwind_table(mod->arch.unw_table); unw_remove_unwind_table(mod->arch.init_unw_table);
if (mod->arch.core_unw_table)
unw_remove_unwind_table(mod->arch.core_unw_table);
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
......
/* /*
* Copyright (C) 2000, 2002 Hewlett-Packard Co * Copyright (C) 2000, 2002-2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* *
* Kernel unwind support. * Kernel unwind support.
...@@ -45,12 +45,6 @@ struct unw_info_block { ...@@ -45,12 +45,6 @@ struct unw_info_block {
/* personality routine and language-specific data follow behind descriptors */ /* personality routine and language-specific data follow behind descriptors */
}; };
struct unw_table_entry {
u64 start_offset;
u64 end_offset;
u64 info_offset;
};
struct unw_table { struct unw_table {
struct unw_table *next; /* must be first member! */ struct unw_table *next; /* must be first member! */
const char *name; const char *name;
......
...@@ -18,7 +18,8 @@ struct mod_arch_specific { ...@@ -18,7 +18,8 @@ struct mod_arch_specific {
struct elf64_shdr *unwind; /* unwind-table section */ struct elf64_shdr *unwind; /* unwind-table section */
unsigned long gp; /* global-pointer for module */ unsigned long gp; /* global-pointer for module */
void *unw_table; /* unwind-table cookie returned by unwinder */ void *core_unw_table; /* core unwind-table cookie returned by unwinder */
void *init_unw_table; /* init unwind-table cookie returned by unwinder */
unsigned int next_got_entry; /* index of next available got entry */ unsigned int next_got_entry; /* index of next available got entry */
}; };
......
...@@ -93,6 +93,12 @@ struct unw_frame_info { ...@@ -93,6 +93,12 @@ struct unw_frame_info {
* The official API follows below: * The official API follows below:
*/ */
struct unw_table_entry {
u64 start_offset;
u64 end_offset;
u64 info_offset;
};
/* /*
* Initialize unwind support. * Initialize unwind support.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment