aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/dwarf.c135
-rw-r--r--arch/sh/kernel/module.c32
2 files changed, 137 insertions, 30 deletions
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}