Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Mosberger <davidm@tiger.hpl.hp.com>2003-10-24 09:25:45 -0700
committerDavid Mosberger <davidm@tiger.hpl.hp.com>2003-10-24 09:25:45 -0700
commit60b75a3c144c337e6e246255b1ce25601d35fbd7 (patch)
tree8a0ec2032dc9041f9eaec699e386c8fd96f28a91
parent7502ff99ebd26e9898a54c54618f0144b9331c36 (diff)
ia64: Fix/finish kernel module table support so it actually works.
-rw-r--r--arch/ia64/kernel/module.c82
-rw-r--r--arch/ia64/kernel/unwind_i.h8
-rw-r--r--include/asm-ia64/module.h3
-rw-r--r--include/asm-ia64/unwind.h6
4 files changed, 84 insertions, 15 deletions
diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c
index 0a7ad2a30565..e8ea942fa2a1 100644
--- a/arch/ia64/kernel/module.c
+++ b/arch/ia64/kernel/module.c
@@ -322,6 +322,10 @@ module_alloc (unsigned long size)
void
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);
}
@@ -843,28 +847,92 @@ apply_relocate (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex,
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
module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod)
{
DEBUGP("%s: init: entry=%p\n", __FUNCTION__, mod->init);
if (mod->arch.unwind)
- mod->arch.unw_table = unw_add_unwind_table(mod->name, 0, mod->arch.gp,
- (void *) mod->arch.unwind->sh_addr,
- ((void *) mod->arch.unwind->sh_addr
- + mod->arch.unwind->sh_size));
+ register_unwind_table(mod);
return 0;
}
void
module_arch_cleanup (struct module *mod)
{
- if (mod->arch.unwind)
- unw_remove_unwind_table(mod->arch.unw_table);
+ if (mod->arch.init_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
void
-percpu_modcopy (void *pcpudst, const void *src, unsigned long size)
+percpu_modcopy (void *pcpudst, const void *src, unsigned long size)
{
unsigned int i;
for (i = 0; i < NR_CPUS; i++)
diff --git a/arch/ia64/kernel/unwind_i.h b/arch/ia64/kernel/unwind_i.h
index ac5b3afd5c6c..1853dc45073a 100644
--- a/arch/ia64/kernel/unwind_i.h
+++ b/arch/ia64/kernel/unwind_i.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000, 2002 Hewlett-Packard Co
+ * Copyright (C) 2000, 2002-2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*
* Kernel unwind support.
@@ -45,12 +45,6 @@ struct unw_info_block {
/* 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 *next; /* must be first member! */
const char *name;
diff --git a/include/asm-ia64/module.h b/include/asm-ia64/module.h
index d5b6ec9a1cec..85c82bd819f2 100644
--- a/include/asm-ia64/module.h
+++ b/include/asm-ia64/module.h
@@ -18,7 +18,8 @@ struct mod_arch_specific {
struct elf64_shdr *unwind; /* unwind-table section */
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 */
};
diff --git a/include/asm-ia64/unwind.h b/include/asm-ia64/unwind.h
index 3f7624a10e9b..61426ad3ecdb 100644
--- a/include/asm-ia64/unwind.h
+++ b/include/asm-ia64/unwind.h
@@ -93,6 +93,12 @@ struct unw_frame_info {
* The official API follows below:
*/
+struct unw_table_entry {
+ u64 start_offset;
+ u64 end_offset;
+ u64 info_offset;
+};
+
/*
* Initialize unwind support.
*/