mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-11-27 01:11:31 +00:00
Merge patch series "Add generated modalias to modules.builtin.modinfo"
Alexey Gladkov says: The modules.builtin.modinfo file is used by userspace (kmod to be specific) to get information about builtin modules. Among other information about the module, information about module aliases is stored. This is very important to determine that a particular modalias will be handled by a module that is inside the kernel. There are several mechanisms for creating modalias for modules: The first is to explicitly specify the MODULE_ALIAS of the macro. In this case, the aliases go into the '.modinfo' section of the module if it is compiled separately or into vmlinux.o if it is builtin into the kernel. The second is the use of MODULE_DEVICE_TABLE followed by the use of the modpost utility. In this case, vmlinux.o no longer has this information and does not get it into modules.builtin.modinfo. For example: $ modinfo pci:v00008086d0000A36Dsv00001043sd00008694bc0Csc03i30 modinfo: ERROR: Module pci:v00008086d0000A36Dsv00001043sd00008694bc0Csc03i30 not found. $ modinfo xhci_pci name: xhci_pci filename: (builtin) license: GPL file: drivers/usb/host/xhci-pci description: xHCI PCI Host Controller Driver The builtin module is missing alias "pci:v*d*sv*sd*bc0Csc03i30*" which will be generated by modpost if the module is built separately. To fix this it is necessary to add the generated by modpost modalias to modules.builtin.modinfo. Fortunately modpost already generates .vmlinux.export.c for exported symbols. It is possible to add `.modinfo` for builtin modules and modify the build system so that `.modinfo` section is extracted from the intermediate vmlinux after modpost is executed. Link: https://patch.msgid.link/cover.1758182101.git.legion@kernel.org Signed-off-by: Nathan Chancellor <nathan@kernel.org>
This commit is contained in:
commit
c7d3dd9163
12 changed files with 131 additions and 78 deletions
|
|
@ -209,6 +209,11 @@ SECTIONS
|
|||
. = ALIGN(PAGE_SIZE);
|
||||
_end = . ;
|
||||
|
||||
/* Debugging sections. */
|
||||
STABS_DEBUG
|
||||
DWARF_DEBUG
|
||||
ELF_DETAILS
|
||||
|
||||
/*
|
||||
* uncompressed image info used by the decompressor
|
||||
* it should match struct vmlinux_info
|
||||
|
|
@ -239,11 +244,6 @@ SECTIONS
|
|||
#endif
|
||||
} :NONE
|
||||
|
||||
/* Debugging sections. */
|
||||
STABS_DEBUG
|
||||
DWARF_DEBUG
|
||||
ELF_DETAILS
|
||||
|
||||
/*
|
||||
* Make sure that the .got.plt is either completely empty or it
|
||||
* contains only the three reserved double words.
|
||||
|
|
|
|||
|
|
@ -3715,7 +3715,6 @@ static void __exit blogic_exit(void)
|
|||
|
||||
__setup("BusLogic=", blogic_setup);
|
||||
|
||||
#ifdef MODULE
|
||||
/*static const struct pci_device_id blogic_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
|
|
@ -3725,13 +3724,12 @@ __setup("BusLogic=", blogic_setup);
|
|||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{ }
|
||||
};*/
|
||||
static const struct pci_device_id blogic_pci_tbl[] = {
|
||||
static const struct pci_device_id blogic_pci_tbl[] __maybe_unused = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT)},
|
||||
{0, },
|
||||
};
|
||||
#endif
|
||||
MODULE_DEVICE_TABLE(pci, blogic_pci_tbl);
|
||||
|
||||
module_init(blogic_init);
|
||||
|
|
|
|||
|
|
@ -831,6 +831,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
|
|||
|
||||
/* Required sections not related to debugging. */
|
||||
#define ELF_DETAILS \
|
||||
.modinfo : { *(.modinfo) } \
|
||||
.comment 0 : { *(.comment) } \
|
||||
.symtab 0 : { *(.symtab) } \
|
||||
.strtab 0 : { *(.strtab) } \
|
||||
|
|
@ -1044,7 +1045,6 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
|
|||
*(.discard.*) \
|
||||
*(.export_symbol) \
|
||||
*(.no_trim_symbol) \
|
||||
*(.modinfo) \
|
||||
/* ld.bfd warns about .gnu.version* even when not emitted */ \
|
||||
*(.gnu.version*) \
|
||||
|
||||
|
|
|
|||
|
|
@ -244,14 +244,22 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name);
|
|||
/* What your module does. */
|
||||
#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
|
||||
|
||||
#ifdef MODULE
|
||||
/*
|
||||
* Format: __mod_device_table__kmod_<modname>__<type>__<name>
|
||||
* Parts of the string `__kmod_` and `__` are used as delimiters when parsing
|
||||
* a symbol in file2alias.c
|
||||
*/
|
||||
#define __mod_device_table(type, name) \
|
||||
__PASTE(__mod_device_table__, \
|
||||
__PASTE(__KBUILD_MODNAME, \
|
||||
__PASTE(__, \
|
||||
__PASTE(type, \
|
||||
__PASTE(__, name)))))
|
||||
|
||||
/* Creates an alias so file2alias.c can find device table. */
|
||||
#define MODULE_DEVICE_TABLE(type, name) \
|
||||
static typeof(name) __mod_device_table__##type##__##name \
|
||||
static typeof(name) __mod_device_table(type, name) \
|
||||
__attribute__ ((used, alias(__stringify(name))))
|
||||
#else /* !MODULE */
|
||||
#define MODULE_DEVICE_TABLE(type, name)
|
||||
#endif
|
||||
|
||||
/* Version of form [<epoch>:]<version>[-<extra-version>].
|
||||
* Or for CVS/RCS ID version, everything but the number is stripped.
|
||||
|
|
|
|||
|
|
@ -195,10 +195,10 @@ macro_rules! module_device_table {
|
|||
($table_type: literal, $module_table_name:ident, $table_name:ident) => {
|
||||
#[rustfmt::skip]
|
||||
#[export_name =
|
||||
concat!("__mod_device_table__", $table_type,
|
||||
"__", module_path!(),
|
||||
"_", line!(),
|
||||
"_", stringify!($table_name))
|
||||
concat!("__mod_device_table__", line!(),
|
||||
"__kmod_", module_path!(),
|
||||
"__", $table_type,
|
||||
"__", stringify!($table_name))
|
||||
]
|
||||
static $module_table_name: [::core::mem::MaybeUninit<u8>; $table_name.raw_ids().size()] =
|
||||
unsafe { ::core::mem::transmute_copy($table_name.raw_ids()) };
|
||||
|
|
|
|||
|
|
@ -9,20 +9,6 @@ include $(srctree)/scripts/Makefile.lib
|
|||
|
||||
targets :=
|
||||
|
||||
ifdef CONFIG_ARCH_VMLINUX_NEEDS_RELOCS
|
||||
vmlinux-final := vmlinux.unstripped
|
||||
|
||||
quiet_cmd_strip_relocs = RSTRIP $@
|
||||
cmd_strip_relocs = $(OBJCOPY) --remove-section='.rel*' --remove-section=!'.rel*.dyn' $< $@
|
||||
|
||||
vmlinux: $(vmlinux-final) FORCE
|
||||
$(call if_changed,strip_relocs)
|
||||
|
||||
targets += vmlinux
|
||||
else
|
||||
vmlinux-final := vmlinux
|
||||
endif
|
||||
|
||||
%.o: %.c FORCE
|
||||
$(call if_changed_rule,cc_o_c)
|
||||
|
||||
|
|
@ -61,19 +47,14 @@ targets += .builtin-dtbs-list
|
|||
|
||||
ifdef CONFIG_GENERIC_BUILTIN_DTB
|
||||
targets += .builtin-dtbs.S .builtin-dtbs.o
|
||||
$(vmlinux-final): .builtin-dtbs.o
|
||||
vmlinux.unstripped: .builtin-dtbs.o
|
||||
endif
|
||||
|
||||
# vmlinux
|
||||
# vmlinux.unstripped
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ifdef CONFIG_MODULES
|
||||
targets += .vmlinux.export.o
|
||||
$(vmlinux-final): .vmlinux.export.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX
|
||||
$(vmlinux-final): arch/$(SRCARCH)/tools/vmlinux.arch.o
|
||||
vmlinux.unstripped: arch/$(SRCARCH)/tools/vmlinux.arch.o
|
||||
|
||||
arch/$(SRCARCH)/tools/vmlinux.arch.o: vmlinux.o FORCE
|
||||
$(Q)$(MAKE) $(build)=arch/$(SRCARCH)/tools $@
|
||||
|
|
@ -86,17 +67,61 @@ cmd_link_vmlinux = \
|
|||
$< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)" "$@"; \
|
||||
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
|
||||
|
||||
targets += $(vmlinux-final)
|
||||
$(vmlinux-final): scripts/link-vmlinux.sh vmlinux.o $(KBUILD_LDS) FORCE
|
||||
targets += vmlinux.unstripped .vmlinux.export.o
|
||||
vmlinux.unstripped: scripts/link-vmlinux.sh vmlinux.o .vmlinux.export.o $(KBUILD_LDS) FORCE
|
||||
+$(call if_changed_dep,link_vmlinux)
|
||||
ifdef CONFIG_DEBUG_INFO_BTF
|
||||
$(vmlinux-final): $(RESOLVE_BTFIDS)
|
||||
vmlinux.unstripped: $(RESOLVE_BTFIDS)
|
||||
endif
|
||||
|
||||
ifdef CONFIG_BUILDTIME_TABLE_SORT
|
||||
$(vmlinux-final): scripts/sorttable
|
||||
vmlinux.unstripped: scripts/sorttable
|
||||
endif
|
||||
|
||||
# vmlinux
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
remove-section-y := .modinfo
|
||||
remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*'
|
||||
|
||||
remove-symbols := -w --strip-symbol='__mod_device_table__*'
|
||||
|
||||
# To avoid warnings: "empty loadable segment detected at ..." from GNU objcopy,
|
||||
# it is necessary to remove the PT_LOAD flag from the segment.
|
||||
quiet_cmd_strip_relocs = OBJCOPY $@
|
||||
cmd_strip_relocs = $(OBJCOPY) $(patsubst %,--set-section-flags %=noload,$(remove-section-y)) $< $@; \
|
||||
$(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $@
|
||||
|
||||
targets += vmlinux
|
||||
vmlinux: vmlinux.unstripped FORCE
|
||||
$(call if_changed,strip_relocs)
|
||||
|
||||
# modules.builtin.modinfo
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
OBJCOPYFLAGS_modules.builtin.modinfo := -j .modinfo -O binary
|
||||
|
||||
targets += modules.builtin.modinfo
|
||||
modules.builtin.modinfo: vmlinux.unstripped FORCE
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
# modules.builtin
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
__default: modules.builtin
|
||||
|
||||
# The second line aids cases where multiple modules share the same object.
|
||||
|
||||
quiet_cmd_modules_builtin = GEN $@
|
||||
cmd_modules_builtin = \
|
||||
tr '\0' '\n' < $< | \
|
||||
sed -n 's/^[[:alnum:]:_]*\.file=//p' | \
|
||||
tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$$/.ko/' > $@
|
||||
|
||||
targets += modules.builtin
|
||||
modules.builtin: modules.builtin.modinfo FORCE
|
||||
$(call if_changed,modules_builtin)
|
||||
|
||||
# modules.builtin.ranges
|
||||
# ---------------------------------------------------------------------------
|
||||
ifdef CONFIG_BUILTIN_MODULE_RANGES
|
||||
|
|
@ -110,7 +135,7 @@ modules.builtin.ranges: $(srctree)/scripts/generate_builtin_ranges.awk \
|
|||
modules.builtin vmlinux.map vmlinux.o.map FORCE
|
||||
$(call if_changed,modules_builtin_ranges)
|
||||
|
||||
vmlinux.map: $(vmlinux-final)
|
||||
vmlinux.map: vmlinux.unstripped
|
||||
@:
|
||||
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
PHONY := __default
|
||||
__default: vmlinux.o modules.builtin.modinfo modules.builtin
|
||||
__default: vmlinux.o
|
||||
|
||||
include include/config/auto.conf
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
|
|
@ -73,30 +73,6 @@ vmlinux.o: $(initcalls-lds) vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
|
|||
|
||||
targets += vmlinux.o
|
||||
|
||||
# modules.builtin.modinfo
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
OBJCOPYFLAGS_modules.builtin.modinfo := -j .modinfo -O binary
|
||||
|
||||
targets += modules.builtin.modinfo
|
||||
modules.builtin.modinfo: vmlinux.o FORCE
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
# modules.builtin
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# The second line aids cases where multiple modules share the same object.
|
||||
|
||||
quiet_cmd_modules_builtin = GEN $@
|
||||
cmd_modules_builtin = \
|
||||
tr '\0' '\n' < $< | \
|
||||
sed -n 's/^[[:alnum:]:_]*\.file=//p' | \
|
||||
tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$$/.ko/' > $@
|
||||
|
||||
targets += modules.builtin
|
||||
modules.builtin: modules.builtin.modinfo FORCE
|
||||
$(call if_changed,modules_builtin)
|
||||
|
||||
# Add FORCE to the prerequisites of a target to force it to be always rebuilt.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -73,10 +73,7 @@ vmlinux_link()
|
|||
objs="${objs} .builtin-dtbs.o"
|
||||
fi
|
||||
|
||||
if is_enabled CONFIG_MODULES; then
|
||||
objs="${objs} .vmlinux.export.o"
|
||||
fi
|
||||
|
||||
objs="${objs} .vmlinux.export.o"
|
||||
objs="${objs} init/version-timestamp.o"
|
||||
|
||||
if [ "${SRCARCH}" = "um" ]; then
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@
|
|||
# EXPORT_SYMBOL (namespace)
|
||||
/ __kstrtabns_/d
|
||||
|
||||
# MODULE_DEVICE_TABLE (symbol name)
|
||||
/ __mod_device_table__/d
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Ignored suffixes
|
||||
# (do not forget '$' after each pattern)
|
||||
|
|
@ -79,6 +82,9 @@
|
|||
/ _SDA_BASE_$/d
|
||||
/ _SDA2_BASE_$/d
|
||||
|
||||
# MODULE_INFO()
|
||||
/ __UNIQUE_ID_modinfo[0-9]*$/d
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Ignored patterns
|
||||
# (symbols that contain the pattern are ignored)
|
||||
|
|
|
|||
|
|
@ -1476,8 +1476,8 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
|
|||
{
|
||||
void *symval;
|
||||
char *zeros = NULL;
|
||||
const char *type, *name;
|
||||
size_t typelen;
|
||||
const char *type, *name, *modname;
|
||||
size_t typelen, modnamelen;
|
||||
static const char *prefix = "__mod_device_table__";
|
||||
|
||||
/* We're looking for a section relative symbol */
|
||||
|
|
@ -1488,10 +1488,20 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
|
|||
if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
|
||||
return;
|
||||
|
||||
/* All our symbols are of form __mod_device_table__<type>__<name>. */
|
||||
/* All our symbols are of form __mod_device_table__kmod_<modname>__<type>__<name>. */
|
||||
if (!strstarts(symname, prefix))
|
||||
return;
|
||||
type = symname + strlen(prefix);
|
||||
|
||||
modname = strstr(symname, "__kmod_");
|
||||
if (!modname)
|
||||
return;
|
||||
modname += strlen("__kmod_");
|
||||
|
||||
type = strstr(modname, "__");
|
||||
if (!type)
|
||||
return;
|
||||
modnamelen = type - modname;
|
||||
type += strlen("__");
|
||||
|
||||
name = strstr(type, "__");
|
||||
if (!name)
|
||||
|
|
@ -1517,5 +1527,21 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
|
|||
}
|
||||
}
|
||||
|
||||
if (mod->is_vmlinux) {
|
||||
struct module_alias *alias;
|
||||
|
||||
/*
|
||||
* If this is vmlinux, record the name of the builtin module.
|
||||
* Traverse the linked list in the reverse order, and set the
|
||||
* builtin_modname unless it has already been set in the
|
||||
* previous call.
|
||||
*/
|
||||
list_for_each_entry_reverse(alias, &mod->aliases, node) {
|
||||
if (alias->builtin_modname)
|
||||
break;
|
||||
alias->builtin_modname = xstrndup(modname, modnamelen);
|
||||
}
|
||||
}
|
||||
|
||||
free(zeros);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2067,11 +2067,26 @@ static void write_if_changed(struct buffer *b, const char *fname)
|
|||
static void write_vmlinux_export_c_file(struct module *mod)
|
||||
{
|
||||
struct buffer buf = { };
|
||||
struct module_alias *alias, *next;
|
||||
|
||||
buf_printf(&buf,
|
||||
"#include <linux/export-internal.h>\n");
|
||||
|
||||
add_exported_symbols(&buf, mod);
|
||||
|
||||
buf_printf(&buf,
|
||||
"#include <linux/module.h>\n"
|
||||
"#undef __MODULE_INFO_PREFIX\n"
|
||||
"#define __MODULE_INFO_PREFIX\n");
|
||||
|
||||
list_for_each_entry_safe(alias, next, &mod->aliases, node) {
|
||||
buf_printf(&buf, "MODULE_INFO(%s.alias, \"%s\");\n",
|
||||
alias->builtin_modname, alias->str);
|
||||
list_del(&alias->node);
|
||||
free(alias->builtin_modname);
|
||||
free(alias);
|
||||
}
|
||||
|
||||
write_if_changed(&buf, ".vmlinux.export.c");
|
||||
free(buf.p);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,10 +99,12 @@ buf_write(struct buffer *buf, const char *s, int len);
|
|||
* struct module_alias - auto-generated MODULE_ALIAS()
|
||||
*
|
||||
* @node: linked to module::aliases
|
||||
* @modname: name of the builtin module (only for vmlinux)
|
||||
* @str: a string for MODULE_ALIAS()
|
||||
*/
|
||||
struct module_alias {
|
||||
struct list_head node;
|
||||
char *builtin_modname;
|
||||
char str[];
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue