Commit 6d760133 authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

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: default avatarRoland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ae0b78d0
...@@ -343,6 +343,9 @@ struct module ...@@ -343,6 +343,9 @@ struct module
/* Section attributes */ /* Section attributes */
struct module_sect_attrs *sect_attrs; struct module_sect_attrs *sect_attrs;
/* Notes attributes */
struct module_notes_attrs *notes_attrs;
#endif #endif
/* Per-cpu data. */ /* Per-cpu data. */
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/moduleloader.h> #include <linux/moduleloader.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/sysfs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
...@@ -1047,6 +1048,100 @@ static void remove_sect_attrs(struct module *mod) ...@@ -1047,6 +1048,100 @@ static void remove_sect_attrs(struct module *mod)
} }
} }
/*
* /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
*/
struct module_notes_attrs {
struct kobject *dir;
unsigned int notes;
struct bin_attribute attrs[0];
};
static ssize_t module_notes_read(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t count)
{
/*
* The caller checked the pos and count against our size.
*/
memcpy(buf, bin_attr->private + pos, count);
return count;
}
static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
unsigned int i)
{
if (notes_attrs->dir) {
while (i-- > 0)
sysfs_remove_bin_file(notes_attrs->dir,
&notes_attrs->attrs[i]);
kobject_del(notes_attrs->dir);
}
kfree(notes_attrs);
}
static void add_notes_attrs(struct module *mod, unsigned int nsect,
char *secstrings, Elf_Shdr *sechdrs)
{
unsigned int notes, loaded, i;
struct module_notes_attrs *notes_attrs;
struct bin_attribute *nattr;
/* Count notes sections and allocate structures. */
notes = 0;
for (i = 0; i < nsect; i++)
if ((sechdrs[i].sh_flags & SHF_ALLOC) &&
(sechdrs[i].sh_type == SHT_NOTE))
++notes;
if (notes == 0)
return;
notes_attrs = kzalloc(sizeof(*notes_attrs)
+ notes * sizeof(notes_attrs->attrs[0]),
GFP_KERNEL);
if (notes_attrs == NULL)
return;
notes_attrs->notes = notes;
nattr = &notes_attrs->attrs[0];
for (loaded = i = 0; i < nsect; ++i) {
if (!(sechdrs[i].sh_flags & SHF_ALLOC))
continue;
if (sechdrs[i].sh_type == SHT_NOTE) {
nattr->attr.name = mod->sect_attrs->attrs[loaded].name;
nattr->attr.mode = S_IRUGO;
nattr->size = sechdrs[i].sh_size;
nattr->private = (void *) sechdrs[i].sh_addr;
nattr->read = module_notes_read;
++nattr;
}
++loaded;
}
notes_attrs->dir = kobject_add_dir(&mod->mkobj.kobj, "notes");
if (!notes_attrs->dir)
goto out;
for (i = 0; i < notes; ++i)
if (sysfs_create_bin_file(notes_attrs->dir,
&notes_attrs->attrs[i]))
goto out;
mod->notes_attrs = notes_attrs;
return;
out:
free_notes_attrs(notes_attrs, i);
}
static void remove_notes_attrs(struct module *mod)
{
if (mod->notes_attrs)
free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
}
#else #else
static inline void add_sect_attrs(struct module *mod, unsigned int nsect, 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,6 +1152,15 @@ static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
static inline void remove_sect_attrs(struct module *mod) static inline void remove_sect_attrs(struct module *mod)
{ {
} }
static inline void add_notes_attrs(struct module *mod, unsigned int nsect,
char *sectstrings, Elf_Shdr *sechdrs)
{
}
static inline void remove_notes_attrs(struct module *mod)
{
}
#endif /* CONFIG_KALLSYMS */ #endif /* CONFIG_KALLSYMS */
#ifdef CONFIG_SYSFS #ifdef CONFIG_SYSFS
...@@ -1191,6 +1295,7 @@ static void free_module(struct module *mod) ...@@ -1191,6 +1295,7 @@ static void free_module(struct module *mod)
{ {
/* Delete from various lists */ /* Delete from various lists */
stop_machine_run(__unlink_module, mod, NR_CPUS); stop_machine_run(__unlink_module, mod, NR_CPUS);
remove_notes_attrs(mod);
remove_sect_attrs(mod); remove_sect_attrs(mod);
mod_kobject_remove(mod); mod_kobject_remove(mod);
...@@ -1918,6 +2023,7 @@ static struct module *load_module(void __user *umod, ...@@ -1918,6 +2023,7 @@ static struct module *load_module(void __user *umod,
if (err < 0) if (err < 0)
goto arch_cleanup; goto arch_cleanup;
add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
/* Size of section 0 is 0, so this works well if no unwind info. */ /* Size of section 0 is 0, so this works well if no unwind info. */
mod->unwind_info = unwind_add_table(mod, mod->unwind_info = unwind_add_table(mod,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment