aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/module.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2007-10-17 02:26:40 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 11:42:50 -0400
commit6d76013381ed28979cd122eb4b249a88b5e384fa (patch)
treef37571fad8690dead2344d1aa0ea86d5f778181f /kernel/module.c
parentae0b78d09dc1d521551e225a9831aba1eded518f (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>
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c106
1 files changed, 106 insertions, 0 deletions
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
1055struct module_notes_attrs {
1056 struct kobject *dir;
1057 unsigned int notes;
1058 struct bin_attribute attrs[0];
1059};
1060
1061static 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
1072static 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 &notes_attrs->attrs[i]);
1079 kobject_del(notes_attrs->dir);
1080 }
1081 kfree(notes_attrs);
1082}
1083
1084static 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 = &notes_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 &notes_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
1139static 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
1052static inline void add_sect_attrs(struct module *mod, unsigned int nsect, 1147static 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,
1057static inline void remove_sect_attrs(struct module *mod) 1152static inline void remove_sect_attrs(struct module *mod)
1058{ 1153{
1059} 1154}
1155
1156static inline void add_notes_attrs(struct module *mod, unsigned int nsect,
1157 char *sectstrings, Elf_Shdr *sechdrs)
1158{
1159}
1160
1161static 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,