diff options
author | Roland McGrath <roland@redhat.com> | 2007-10-17 02:26:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:42:50 -0400 |
commit | 6d76013381ed28979cd122eb4b249a88b5e384fa (patch) | |
tree | f37571fad8690dead2344d1aa0ea86d5f778181f | |
parent | ae0b78d09dc1d521551e225a9831aba1eded518f (diff) |
Add /sys/module/name/notes
This patch adds the /sys/module/<name>/notes/ magic directory, which has a
file for each allocated SHT_NOTE section that appears in <name>.ko. This
is the counterpart for each module of /sys/kernel/notes for vmlinux.
Reading this delivers the contents of the module's SHT_NOTE sections. This
lets userland easily glean any detailed information about that module's
build that was stored there at compile time (e.g. by ld --build-id).
Signed-off-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/module.h | 3 | ||||
-rw-r--r-- | kernel/module.c | 106 |
2 files changed, 109 insertions, 0 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 5523e10fb2f0..642f325e4917 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -343,6 +343,9 @@ struct module | |||
343 | 343 | ||
344 | /* Section attributes */ | 344 | /* Section attributes */ |
345 | struct module_sect_attrs *sect_attrs; | 345 | struct module_sect_attrs *sect_attrs; |
346 | |||
347 | /* Notes attributes */ | ||
348 | struct module_notes_attrs *notes_attrs; | ||
346 | #endif | 349 | #endif |
347 | 350 | ||
348 | /* Per-cpu data. */ | 351 | /* Per-cpu data. */ |
diff --git a/kernel/module.c b/kernel/module.c index 35246a61a7e9..c24c3c35405a 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/moduleloader.h> | 20 | #include <linux/moduleloader.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/kallsyms.h> | 22 | #include <linux/kallsyms.h> |
23 | #include <linux/sysfs.h> | ||
23 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
25 | #include <linux/vmalloc.h> | 26 | #include <linux/vmalloc.h> |
@@ -1047,6 +1048,100 @@ static void remove_sect_attrs(struct module *mod) | |||
1047 | } | 1048 | } |
1048 | } | 1049 | } |
1049 | 1050 | ||
1051 | /* | ||
1052 | * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections. | ||
1053 | */ | ||
1054 | |||
1055 | struct module_notes_attrs { | ||
1056 | struct kobject *dir; | ||
1057 | unsigned int notes; | ||
1058 | struct bin_attribute attrs[0]; | ||
1059 | }; | ||
1060 | |||
1061 | static ssize_t module_notes_read(struct kobject *kobj, | ||
1062 | struct bin_attribute *bin_attr, | ||
1063 | char *buf, loff_t pos, size_t count) | ||
1064 | { | ||
1065 | /* | ||
1066 | * The caller checked the pos and count against our size. | ||
1067 | */ | ||
1068 | memcpy(buf, bin_attr->private + pos, count); | ||
1069 | return count; | ||
1070 | } | ||
1071 | |||
1072 | static void free_notes_attrs(struct module_notes_attrs *notes_attrs, | ||
1073 | unsigned int i) | ||
1074 | { | ||
1075 | if (notes_attrs->dir) { | ||
1076 | while (i-- > 0) | ||
1077 | sysfs_remove_bin_file(notes_attrs->dir, | ||
1078 | ¬es_attrs->attrs[i]); | ||
1079 | kobject_del(notes_attrs->dir); | ||
1080 | } | ||
1081 | kfree(notes_attrs); | ||
1082 | } | ||
1083 | |||
1084 | static void add_notes_attrs(struct module *mod, unsigned int nsect, | ||
1085 | char *secstrings, Elf_Shdr *sechdrs) | ||
1086 | { | ||
1087 | unsigned int notes, loaded, i; | ||
1088 | struct module_notes_attrs *notes_attrs; | ||
1089 | struct bin_attribute *nattr; | ||
1090 | |||
1091 | /* Count notes sections and allocate structures. */ | ||
1092 | notes = 0; | ||
1093 | for (i = 0; i < nsect; i++) | ||
1094 | if ((sechdrs[i].sh_flags & SHF_ALLOC) && | ||
1095 | (sechdrs[i].sh_type == SHT_NOTE)) | ||
1096 | ++notes; | ||
1097 | |||
1098 | if (notes == 0) | ||
1099 | return; | ||
1100 | |||
1101 | notes_attrs = kzalloc(sizeof(*notes_attrs) | ||
1102 | + notes * sizeof(notes_attrs->attrs[0]), | ||
1103 | GFP_KERNEL); | ||
1104 | if (notes_attrs == NULL) | ||
1105 | return; | ||
1106 | |||
1107 | notes_attrs->notes = notes; | ||
1108 | nattr = ¬es_attrs->attrs[0]; | ||
1109 | for (loaded = i = 0; i < nsect; ++i) { | ||
1110 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | ||
1111 | continue; | ||
1112 | if (sechdrs[i].sh_type == SHT_NOTE) { | ||
1113 | nattr->attr.name = mod->sect_attrs->attrs[loaded].name; | ||
1114 | nattr->attr.mode = S_IRUGO; | ||
1115 | nattr->size = sechdrs[i].sh_size; | ||
1116 | nattr->private = (void *) sechdrs[i].sh_addr; | ||
1117 | nattr->read = module_notes_read; | ||
1118 | ++nattr; | ||
1119 | } | ||
1120 | ++loaded; | ||
1121 | } | ||
1122 | |||
1123 | notes_attrs->dir = kobject_add_dir(&mod->mkobj.kobj, "notes"); | ||
1124 | if (!notes_attrs->dir) | ||
1125 | goto out; | ||
1126 | |||
1127 | for (i = 0; i < notes; ++i) | ||
1128 | if (sysfs_create_bin_file(notes_attrs->dir, | ||
1129 | ¬es_attrs->attrs[i])) | ||
1130 | goto out; | ||
1131 | |||
1132 | mod->notes_attrs = notes_attrs; | ||
1133 | return; | ||
1134 | |||
1135 | out: | ||
1136 | free_notes_attrs(notes_attrs, i); | ||
1137 | } | ||
1138 | |||
1139 | static void remove_notes_attrs(struct module *mod) | ||
1140 | { | ||
1141 | if (mod->notes_attrs) | ||
1142 | free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes); | ||
1143 | } | ||
1144 | |||
1050 | #else | 1145 | #else |
1051 | 1146 | ||
1052 | static inline void add_sect_attrs(struct module *mod, unsigned int nsect, | 1147 | static inline void add_sect_attrs(struct module *mod, unsigned int nsect, |
@@ -1057,6 +1152,15 @@ static inline void add_sect_attrs(struct module *mod, unsigned int nsect, | |||
1057 | static inline void remove_sect_attrs(struct module *mod) | 1152 | static inline void remove_sect_attrs(struct module *mod) |
1058 | { | 1153 | { |
1059 | } | 1154 | } |
1155 | |||
1156 | static inline void add_notes_attrs(struct module *mod, unsigned int nsect, | ||
1157 | char *sectstrings, Elf_Shdr *sechdrs) | ||
1158 | { | ||
1159 | } | ||
1160 | |||
1161 | static inline void remove_notes_attrs(struct module *mod) | ||
1162 | { | ||
1163 | } | ||
1060 | #endif /* CONFIG_KALLSYMS */ | 1164 | #endif /* CONFIG_KALLSYMS */ |
1061 | 1165 | ||
1062 | #ifdef CONFIG_SYSFS | 1166 | #ifdef CONFIG_SYSFS |
@@ -1191,6 +1295,7 @@ static void free_module(struct module *mod) | |||
1191 | { | 1295 | { |
1192 | /* Delete from various lists */ | 1296 | /* Delete from various lists */ |
1193 | stop_machine_run(__unlink_module, mod, NR_CPUS); | 1297 | stop_machine_run(__unlink_module, mod, NR_CPUS); |
1298 | remove_notes_attrs(mod); | ||
1194 | remove_sect_attrs(mod); | 1299 | remove_sect_attrs(mod); |
1195 | mod_kobject_remove(mod); | 1300 | mod_kobject_remove(mod); |
1196 | 1301 | ||
@@ -1918,6 +2023,7 @@ static struct module *load_module(void __user *umod, | |||
1918 | if (err < 0) | 2023 | if (err < 0) |
1919 | goto arch_cleanup; | 2024 | goto arch_cleanup; |
1920 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); | 2025 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); |
2026 | add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs); | ||
1921 | 2027 | ||
1922 | /* Size of section 0 is 0, so this works well if no unwind info. */ | 2028 | /* Size of section 0 is 0, so this works well if no unwind info. */ |
1923 | mod->unwind_info = unwind_add_table(mod, | 2029 | mod->unwind_info = unwind_add_table(mod, |