aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMatt Fleming <matt@console-pimps.org>2009-10-09 18:20:54 -0400
committerMatt Fleming <matt@console-pimps.org>2009-10-11 11:41:44 -0400
commita6a2f2ad67506090e332f440457553c0ec011d68 (patch)
treecfe974784b68cc3c09ed76e449a31d536b2b4589 /arch
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')
-rw-r--r--arch/sh/include/asm/dwarf.h15
-rw-r--r--arch/sh/kernel/dwarf.c135
-rw-r--r--arch/sh/kernel/module.c32
3 files changed, 152 insertions, 30 deletions
diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h
index c367ed3373c5..aacdc746d07c 100644
--- a/arch/sh/include/asm/dwarf.h
+++ b/arch/sh/include/asm/dwarf.h
@@ -241,6 +241,12 @@ struct dwarf_cie {
241 241
242 unsigned long flags; 242 unsigned long flags;
243#define DWARF_CIE_Z_AUGMENTATION (1 << 0) 243#define DWARF_CIE_Z_AUGMENTATION (1 << 0)
244
245 /*
246 * 'mod' will be non-NULL if this CIE came from a module's
247 * .eh_frame section.
248 */
249 struct module *mod;
244}; 250};
245 251
246/** 252/**
@@ -255,6 +261,12 @@ struct dwarf_fde {
255 unsigned char *instructions; 261 unsigned char *instructions;
256 unsigned char *end; 262 unsigned char *end;
257 struct list_head link; 263 struct list_head link;
264
265 /*
266 * 'mod' will be non-NULL if this FDE came from a module's
267 * .eh_frame section.
268 */
269 struct module *mod;
258}; 270};
259 271
260/** 272/**
@@ -364,6 +376,9 @@ static inline unsigned int DW_CFA_operand(unsigned long insn)
364 376
365extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, 377extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
366 struct dwarf_frame *); 378 struct dwarf_frame *);
379extern int dwarf_parse_section(char *, char *, struct module *);
380extern void dwarf_module_unload(struct module *);
381
367#endif /* !__ASSEMBLY__ */ 382#endif /* !__ASSEMBLY__ */
368 383
369#define CFI_STARTPROC .cfi_startproc 384#define CFI_STARTPROC .cfi_startproc
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c
index 577302f31e6a..981315c6d656 100644
--- a/arch/sh/kernel/dwarf.c
+++ b/arch/sh/kernel/dwarf.c
@@ -655,7 +655,7 @@ bail:
655} 655}
656 656
657static int dwarf_parse_cie(void *entry, void *p, unsigned long len, 657static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
658 unsigned char *end) 658 unsigned char *end, struct module *mod)
659{ 659{
660 struct dwarf_cie *cie; 660 struct dwarf_cie *cie;
661 unsigned long flags; 661 unsigned long flags;
@@ -751,6 +751,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
751 cie->initial_instructions = p; 751 cie->initial_instructions = p;
752 cie->instructions_end = end; 752 cie->instructions_end = end;
753 753
754 cie->mod = mod;
755
754 /* Add to list */ 756 /* Add to list */
755 spin_lock_irqsave(&dwarf_cie_lock, flags); 757 spin_lock_irqsave(&dwarf_cie_lock, flags);
756 list_add_tail(&cie->link, &dwarf_cie_list); 758 list_add_tail(&cie->link, &dwarf_cie_list);
@@ -761,7 +763,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
761 763
762static int dwarf_parse_fde(void *entry, u32 entry_type, 764static int dwarf_parse_fde(void *entry, u32 entry_type,
763 void *start, unsigned long len, 765 void *start, unsigned long len,
764 unsigned char *end) 766 unsigned char *end, struct module *mod)
765{ 767{
766 struct dwarf_fde *fde; 768 struct dwarf_fde *fde;
767 struct dwarf_cie *cie; 769 struct dwarf_cie *cie;
@@ -810,6 +812,8 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
810 fde->instructions = p; 812 fde->instructions = p;
811 fde->end = end; 813 fde->end = end;
812 814
815 fde->mod = mod;
816
813 /* Add to list. */ 817 /* Add to list. */
814 spin_lock_irqsave(&dwarf_fde_lock, flags); 818 spin_lock_irqsave(&dwarf_fde_lock, flags);
815 list_add_tail(&fde->link, &dwarf_fde_list); 819 list_add_tail(&fde->link, &dwarf_fde_list);
@@ -875,15 +879,15 @@ static void dwarf_unwinder_cleanup(void)
875} 879}
876 880
877/** 881/**
878 * dwarf_unwinder_init - initialise the dwarf unwinder 882 * dwarf_parse_section - parse DWARF section
883 * @eh_frame_start: start address of the .eh_frame section
884 * @eh_frame_end: end address of the .eh_frame section
885 * @mod: the kernel module containing the .eh_frame section
879 * 886 *
880 * Build the data structures describing the .dwarf_frame section to 887 * Parse the information in a .eh_frame section.
881 * make it easier to lookup CIE and FDE entries. Because the
882 * .eh_frame section is packed as tightly as possible it is not
883 * easy to lookup the FDE for a given PC, so we build a list of FDE
884 * and CIE entries that make it easier.
885 */ 888 */
886static int __init dwarf_unwinder_init(void) 889int dwarf_parse_section(char *eh_frame_start, char *eh_frame_end,
890 struct module *mod)
887{ 891{
888 u32 entry_type; 892 u32 entry_type;
889 void *p, *entry; 893 void *p, *entry;
@@ -891,29 +895,12 @@ static int __init dwarf_unwinder_init(void)
891 unsigned long len; 895 unsigned long len;
892 unsigned int c_entries, f_entries; 896 unsigned int c_entries, f_entries;
893 unsigned char *end; 897 unsigned char *end;
894 INIT_LIST_HEAD(&dwarf_cie_list);
895 INIT_LIST_HEAD(&dwarf_fde_list);
896 898
897 c_entries = 0; 899 c_entries = 0;
898 f_entries = 0; 900 f_entries = 0;
899 entry = &__start_eh_frame; 901 entry = eh_frame_start;
900
901 dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
902 sizeof(struct dwarf_frame), 0, SLAB_PANIC, NULL);
903 dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
904 sizeof(struct dwarf_reg), 0, SLAB_PANIC, NULL);
905
906 dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ,
907 mempool_alloc_slab,
908 mempool_free_slab,
909 dwarf_frame_cachep);
910 902
911 dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ, 903 while ((char *)entry < eh_frame_end) {
912 mempool_alloc_slab,
913 mempool_free_slab,
914 dwarf_reg_cachep);
915
916 while ((char *)entry < __stop_eh_frame) {
917 p = entry; 904 p = entry;
918 905
919 count = dwarf_entry_len(p, &len); 906 count = dwarf_entry_len(p, &len);
@@ -925,6 +912,7 @@ static int __init dwarf_unwinder_init(void)
925 * entry and move to the next one because 'len' 912 * entry and move to the next one because 'len'
926 * tells us where our next entry is. 913 * tells us where our next entry is.
927 */ 914 */
915 err = -EINVAL;
928 goto out; 916 goto out;
929 } else 917 } else
930 p += count; 918 p += count;
@@ -936,13 +924,14 @@ static int __init dwarf_unwinder_init(void)
936 p += 4; 924 p += 4;
937 925
938 if (entry_type == DW_EH_FRAME_CIE) { 926 if (entry_type == DW_EH_FRAME_CIE) {
939 err = dwarf_parse_cie(entry, p, len, end); 927 err = dwarf_parse_cie(entry, p, len, end, mod);
940 if (err < 0) 928 if (err < 0)
941 goto out; 929 goto out;
942 else 930 else
943 c_entries++; 931 c_entries++;
944 } else { 932 } else {
945 err = dwarf_parse_fde(entry, entry_type, p, len, end); 933 err = dwarf_parse_fde(entry, entry_type, p, len,
934 end, mod);
946 if (err < 0) 935 if (err < 0)
947 goto out; 936 goto out;
948 else 937 else
@@ -955,6 +944,92 @@ static int __init dwarf_unwinder_init(void)
955 printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n", 944 printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n",
956 c_entries, f_entries); 945 c_entries, f_entries);
957 946
947 return 0;
948
949out:
950 return err;
951}
952
953/**
954 * dwarf_module_unload - remove FDE/CIEs associated with @mod
955 * @mod: the module that is being unloaded
956 *
957 * Remove any FDEs and CIEs from the global lists that came from
958 * @mod's .eh_frame section because @mod is being unloaded.
959 */
960void dwarf_module_unload(struct module *mod)
961{
962 struct dwarf_fde *fde;
963 struct dwarf_cie *cie;
964 unsigned long flags;
965
966 spin_lock_irqsave(&dwarf_cie_lock, flags);
967
968again_cie:
969 list_for_each_entry(cie, &dwarf_cie_list, link) {
970 if (cie->mod == mod)
971 break;
972 }
973
974 if (&cie->link != &dwarf_cie_list) {
975 list_del(&cie->link);
976 kfree(cie);
977 goto again_cie;
978 }
979
980 spin_unlock_irqrestore(&dwarf_cie_lock, flags);
981
982 spin_lock_irqsave(&dwarf_fde_lock, flags);
983
984again_fde:
985 list_for_each_entry(fde, &dwarf_fde_list, link) {
986 if (fde->mod == mod)
987 break;
988 }
989
990 if (&fde->link != &dwarf_fde_list) {
991 list_del(&fde->link);
992 kfree(fde);
993 goto again_fde;
994 }
995
996 spin_unlock_irqrestore(&dwarf_fde_lock, flags);
997}
998
999/**
1000 * dwarf_unwinder_init - initialise the dwarf unwinder
1001 *
1002 * Build the data structures describing the .dwarf_frame section to
1003 * make it easier to lookup CIE and FDE entries. Because the
1004 * .eh_frame section is packed as tightly as possible it is not
1005 * easy to lookup the FDE for a given PC, so we build a list of FDE
1006 * and CIE entries that make it easier.
1007 */
1008static int __init dwarf_unwinder_init(void)
1009{
1010 int err;
1011 INIT_LIST_HEAD(&dwarf_cie_list);
1012 INIT_LIST_HEAD(&dwarf_fde_list);
1013
1014 dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
1015 sizeof(struct dwarf_frame), 0, SLAB_PANIC, NULL);
1016 dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
1017 sizeof(struct dwarf_reg), 0, SLAB_PANIC, NULL);
1018
1019 dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ,
1020 mempool_alloc_slab,
1021 mempool_free_slab,
1022 dwarf_frame_cachep);
1023
1024 dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
1025 mempool_alloc_slab,
1026 mempool_free_slab,
1027 dwarf_reg_cachep);
1028
1029 err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
1030 if (err)
1031 goto out;
1032
958 err = unwinder_register(&dwarf_unwinder); 1033 err = unwinder_register(&dwarf_unwinder);
959 if (err) 1034 if (err)
960 goto out; 1035 goto out;
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 @@
32#include <linux/string.h> 32#include <linux/string.h>
33#include <linux/kernel.h> 33#include <linux/kernel.h>
34#include <asm/unaligned.h> 34#include <asm/unaligned.h>
35#include <asm/dwarf.h>
35 36
36void *module_alloc(unsigned long size) 37void *module_alloc(unsigned long size)
37{ 38{
@@ -145,10 +146,41 @@ int module_finalize(const Elf_Ehdr *hdr,
145 const Elf_Shdr *sechdrs, 146 const Elf_Shdr *sechdrs,
146 struct module *me) 147 struct module *me)
147{ 148{
149#ifdef CONFIG_DWARF_UNWINDER
150 unsigned int i, err;
151 unsigned long start, end;
152 char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
153
154 start = end = 0;
155
156 for (i = 1; i < hdr->e_shnum; i++) {
157 /* Alloc bit cleared means "ignore it." */
158 if ((sechdrs[i].sh_flags & SHF_ALLOC)
159 && !strcmp(secstrings+sechdrs[i].sh_name, ".eh_frame")) {
160 start = sechdrs[i].sh_addr;
161 end = start + sechdrs[i].sh_size;
162 break;
163 }
164 }
165
166 /* Did we find the .eh_frame section? */
167 if (i != hdr->e_shnum) {
168 err = dwarf_parse_section((char *)start, (char *)end, me);
169 if (err)
170 printk(KERN_WARNING "%s: failed to parse DWARF info\n",
171 me->name);
172 }
173
174#endif /* CONFIG_DWARF_UNWINDER */
175
148 return module_bug_finalize(hdr, sechdrs, me); 176 return module_bug_finalize(hdr, sechdrs, me);
149} 177}
150 178
151void module_arch_cleanup(struct module *mod) 179void module_arch_cleanup(struct module *mod)
152{ 180{
153 module_bug_cleanup(mod); 181 module_bug_cleanup(mod);
182
183#ifdef CONFIG_DWARF_UNWINDER
184 dwarf_module_unload(mod);
185#endif /* CONFIG_DWARF_UNWINDER */
154} 186}