Merge branch 'master' into devel
[sfrench/cifs-2.6.git] / arch / arm / kernel / module.c
index 9f509fd00fda40fab3888c6f6865e843052aedfe..d1731e39b496cc436a79fbb0631f181e166580e7 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <asm/pgtable.h>
 #include <asm/sections.h>
+#include <asm/unwind.h>
 
 #ifdef CONFIG_XIP_KERNEL
 /*
@@ -66,6 +67,24 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
                              char *secstrings,
                              struct module *mod)
 {
+#ifdef CONFIG_ARM_UNWIND
+       Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+
+       for (s = sechdrs; s < sechdrs_end; s++) {
+               if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0)
+                       mod->arch.unw_sec_init = s;
+               else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0)
+                       mod->arch.unw_sec_devinit = s;
+               else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0)
+                       mod->arch.unw_sec_core = s;
+               else if (strcmp(".init.text", secstrings + s->sh_name) == 0)
+                       mod->arch.sec_init_text = s;
+               else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0)
+                       mod->arch.sec_devinit_text = s;
+               else if (strcmp(".text", secstrings + s->sh_name) == 0)
+                       mod->arch.sec_core_text = s;
+       }
+#endif
        return 0;
 }
 
@@ -104,6 +123,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                loc = dstsec->sh_addr + rel->r_offset;
 
                switch (ELF32_R_TYPE(rel->r_info)) {
+               case R_ARM_NONE:
+                       /* ignore */
+                       break;
+
                case R_ARM_ABS32:
                        *(u32 *)loc += sym->st_value;
                        break;
@@ -141,6 +164,11 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                       *(u32 *)loc |= 0x01a0f000;
                       break;
 
+               case R_ARM_PREL31:
+                       offset = *(u32 *)loc + sym->st_value - loc;
+                       *(u32 *)loc = offset & 0x7fffffff;
+                       break;
+
                default:
                        printk(KERN_ERR "%s: unknown relocation: %u\n",
                               module->name, ELF32_R_TYPE(rel->r_info));
@@ -159,14 +187,50 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
        return -ENOEXEC;
 }
 
+#ifdef CONFIG_ARM_UNWIND
+static void register_unwind_tables(struct module *mod)
+{
+       if (mod->arch.unw_sec_init && mod->arch.sec_init_text)
+               mod->arch.unwind_init =
+                       unwind_table_add(mod->arch.unw_sec_init->sh_addr,
+                                        mod->arch.unw_sec_init->sh_size,
+                                        mod->arch.sec_init_text->sh_addr,
+                                        mod->arch.sec_init_text->sh_size);
+       if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text)
+               mod->arch.unwind_devinit =
+                       unwind_table_add(mod->arch.unw_sec_devinit->sh_addr,
+                                        mod->arch.unw_sec_devinit->sh_size,
+                                        mod->arch.sec_devinit_text->sh_addr,
+                                        mod->arch.sec_devinit_text->sh_size);
+       if (mod->arch.unw_sec_core && mod->arch.sec_core_text)
+               mod->arch.unwind_core =
+                       unwind_table_add(mod->arch.unw_sec_core->sh_addr,
+                                        mod->arch.unw_sec_core->sh_size,
+                                        mod->arch.sec_core_text->sh_addr,
+                                        mod->arch.sec_core_text->sh_size);
+}
+
+static void unregister_unwind_tables(struct module *mod)
+{
+       unwind_table_del(mod->arch.unwind_init);
+       unwind_table_del(mod->arch.unwind_devinit);
+       unwind_table_del(mod->arch.unwind_core);
+}
+#else
+static inline void register_unwind_tables(struct module *mod) { }
+static inline void unregister_unwind_tables(struct module *mod) { }
+#endif
+
 int
 module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
                struct module *module)
 {
+       register_unwind_tables(module);
        return 0;
 }
 
 void
 module_arch_cleanup(struct module *mod)
 {
+       unregister_unwind_tables(mod);
 }