]> git.hungrycats.org Git - linux/commitdiff
ia64: Fix/finish kernel module table support so it actually works.
authorDavid Mosberger <davidm@tiger.hpl.hp.com>
Fri, 24 Oct 2003 16:25:45 +0000 (09:25 -0700)
committerDavid Mosberger <davidm@tiger.hpl.hp.com>
Fri, 24 Oct 2003 16:25:45 +0000 (09:25 -0700)
arch/ia64/kernel/module.c
arch/ia64/kernel/unwind_i.h
include/asm-ia64/module.h
include/asm-ia64/unwind.h

index 0a7ad2a305652a3c89838bf5a5a4a760337a841b..e8ea942fa2a11211a8071d389d5ee08a8820b6be 100644 (file)
@@ -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++)
index ac5b3afd5c6cffccdc4e0dceef6f651b3adb7c07..1853dc45073a1fb275b18decb1ebfb50e4e45528 100644 (file)
@@ -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;
index d5b6ec9a1cec07096be289a73739ef4f38244ae4..85c82bd819f253009338af96ad04e939b011b720 100644 (file)
@@ -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 */
 };
 
index 3f7624a10e9bb1946ce02f9f5f9b5ad5447517ff..61426ad3ecdb8b988c033c592adbdc1fe963d88d 100644 (file)
@@ -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.
  */