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>
This commit is contained in:
parent
ae0b78d09d
commit
6d76013381
2 changed files with 109 additions and 0 deletions
|
@ -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. */
|
||||||
|
|
106
kernel/module.c
106
kernel/module.c
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* /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,
|
||||||
|
¬es_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 = ¬es_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,
|
||||||
|
¬es_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,
|
||||||
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)
|
||||||
{
|
{
|
||||||
/* 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,
|
||||||
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,
|
||||||
|
|
Loading…
Reference in a new issue