summaryrefslogtreecommitdiff
path: root/arch/sh/kernel/module.c
diff options
context:
space:
mode:
authorMatt Fleming <matt@console-pimps.org>2009-10-09 23:20:54 +0100
committerMatt Fleming <matt@console-pimps.org>2009-10-11 16:41:44 +0100
commita6a2f2ad67506090e332f440457553c0ec011d68 (patch)
treecfe974784b68cc3c09ed76e449a31d536b2b4589 /arch/sh/kernel/module.c
parentc153a58e715e16ffcd6c4b3da7fc6b4a556bf917 (diff)
sh: Teach the DWARF unwinder about modules
Pass a module's .eh_frame section to the DWARF unwinder at module load time so that the section's FDEs and CIEs can be registered with the DWARF unwinder. This allows us to unwind the stack through module code when generating backtraces. Signed-off-by: Matt Fleming <matt@console-pimps.org>
Diffstat (limited to 'arch/sh/kernel/module.c')
-rw-r--r--arch/sh/kernel/module.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
index c2efdcde266f..d297a148d16c 100644
--- a/arch/sh/kernel/module.c
+++ b/arch/sh/kernel/module.c
@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <asm/unaligned.h>
+#include <asm/dwarf.h>
void *module_alloc(unsigned long size)
{
@@ -145,10 +146,41 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
+#ifdef CONFIG_DWARF_UNWINDER
+ unsigned int i, err;
+ unsigned long start, end;
+ char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ start = end = 0;
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ /* Alloc bit cleared means "ignore it." */
+ if ((sechdrs[i].sh_flags & SHF_ALLOC)
+ && !strcmp(secstrings+sechdrs[i].sh_name, ".eh_frame")) {
+ start = sechdrs[i].sh_addr;
+ end = start + sechdrs[i].sh_size;
+ break;
+ }
+ }
+
+ /* Did we find the .eh_frame section? */
+ if (i != hdr->e_shnum) {
+ err = dwarf_parse_section((char *)start, (char *)end, me);
+ if (err)
+ printk(KERN_WARNING "%s: failed to parse DWARF info\n",
+ me->name);
+ }
+
+#endif /* CONFIG_DWARF_UNWINDER */
+
return module_bug_finalize(hdr, sechdrs, me);
}
void module_arch_cleanup(struct module *mod)
{
module_bug_cleanup(mod);
+
+#ifdef CONFIG_DWARF_UNWINDER
+ dwarf_module_unload(mod);
+#endif /* CONFIG_DWARF_UNWINDER */
}