Commit f4fdb17c authored by Masahiro Yamada's avatar Masahiro Yamada
Browse files

modpost: introduce module_alias_printf() helper



The generic ->do_entry() handler is currently limited to returning
a single alias string.

However, this is not flexible enough for several subsystems, which
currently require their own implementations:

 - do_usb_table()
 - do_of_table()
 - do_pnp_device_entry()
 - do_pnp_card_entries()

This commit introduces a helper function so that these special cases can
add multiple MODULE_ALIAS() and then migrate to the generic framework.

Signed-off-by: default avatarMasahiro Yamada <masahiroy@kernel.org>
parent b7bca42d
Loading
Loading
Loading
Loading
+66 −25
Original line number Diff line number Diff line
@@ -10,6 +10,12 @@
 * of the GNU General Public License, incorporated herein by reference.
 */

#include <stdarg.h>
#include <stdio.h>

#include "list.h"
#include "xalloc.h"

#include "modpost.h"
#include "devicetable-offsets.h"

@@ -31,6 +37,58 @@ typedef Elf64_Addr kernel_ulong_t;
#include <ctype.h>
#include <stdbool.h>

/**
 * module_alias_printf - add auto-generated MODULE_ALIAS()
 *
 * @mod: module
 * @append_wildcard: append '*' for future extension if not exist yet
 * @fmt: printf(3)-like format
 */
static void __attribute__((format (printf, 3, 4)))
module_alias_printf(struct module *mod, bool append_wildcard,
		    const char *fmt, ...)
{
	struct module_alias *new;
	size_t len;
	int n;
	va_list ap;

	/* Determine required size. */
	va_start(ap, fmt);
	n = vsnprintf(NULL, 0, fmt, ap);
	va_end(ap);

	if (n < 0) {
		error("vsnprintf failed\n");
		return;
	}

	len = n + 1;	/* extra byte for '\0' */

	if (append_wildcard)
		len++;	/* extra byte for '*' */

	new = xmalloc(sizeof(*new) + len);

	/* Now, really print it to the allocated buffer */
	va_start(ap, fmt);
	n = vsnprintf(new->str, len, fmt, ap);
	va_end(ap);

	if (n < 0) {
		error("vsnprintf failed\n");
		free(new);
		return;
	}

	if (append_wildcard && (n == 0 || new->str[n - 1] != '*')) {
		new->str[n] = '*';
		new->str[n + 1] = '\0';
	}

	list_add_tail(&new->node, &mod->aliases);
}

typedef uint32_t	__u32;
typedef uint16_t	__u16;
typedef unsigned char	__u8;
@@ -229,9 +287,7 @@ static void do_usb_entry(void *symval,
	ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER,
	    bInterfaceNumber);

	add_wildcard(alias);
	buf_printf(&mod->dev_table_buf,
		   "MODULE_ALIAS(\"%s\");\n", alias);
	module_alias_printf(mod, true, "%s", alias);
}

/* Handles increment/decrement of BCD formatted integers */
@@ -375,10 +431,8 @@ static void do_of_entry_multi(void *symval, struct module *mod)
		if (isspace(*tmp))
			*tmp = '_';

	buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias);
	strcat(alias, "C");
	add_wildcard(alias);
	buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias);
	module_alias_printf(mod, false, "%s", alias);
	module_alias_printf(mod, false, "%sC*", alias);
}

static void do_of_table(void *symval, unsigned long size,
@@ -608,14 +662,12 @@ static void do_pnp_device_entry(void *symval, unsigned long size,
		char acpi_id[sizeof(*id)];
		int j;

		buf_printf(&mod->dev_table_buf,
			   "MODULE_ALIAS(\"pnp:d%s*\");\n", *id);
		module_alias_printf(mod, false, "pnp:d%s*", *id);

		/* fix broken pnp bus lowercasing */
		for (j = 0; j < sizeof(acpi_id); j++)
			acpi_id[j] = toupper((*id)[j]);
		buf_printf(&mod->dev_table_buf,
			   "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id);
		module_alias_printf(mod, false, "acpi*:%s:*", acpi_id);
	}
}

@@ -666,14 +718,12 @@ static void do_pnp_card_entries(void *symval, unsigned long size,
				char acpi_id[PNP_ID_LEN];
				int k;

				buf_printf(&mod->dev_table_buf,
					   "MODULE_ALIAS(\"pnp:d%s*\");\n", id);
				module_alias_printf(mod, false, "pnp:d%s*", id);

				/* fix broken pnp bus lowercasing */
				for (k = 0; k < sizeof(acpi_id); k++)
					acpi_id[k] = toupper(id[k]);
				buf_printf(&mod->dev_table_buf,
					   "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id);
				module_alias_printf(mod, false, "acpi*:%s:*", acpi_id);
			}
		}
	}
@@ -1534,8 +1584,7 @@ static void do_table(void *symval, unsigned long size,

	for (i = 0; i < size; i += id_size) {
		if (do_entry(mod->name, symval+i, alias)) {
			buf_printf(&mod->dev_table_buf,
				   "MODULE_ALIAS(\"%s\");\n", alias);
			module_alias_printf(mod, false, "%s", alias);
		}
	}
}
@@ -1660,11 +1709,3 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
	}
	free(zeros);
}

/* Now add out buffered information to the generated C source */
void add_moddevtable(struct buffer *buf, struct module *mod)
{
	buf_printf(buf, "\n");
	buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos);
	free(mod->dev_table_buf.p);
}
+10 −1
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@ static struct module *new_module(const char *name, size_t namelen)
	INIT_LIST_HEAD(&mod->unresolved_symbols);
	INIT_LIST_HEAD(&mod->missing_namespaces);
	INIT_LIST_HEAD(&mod->imported_namespaces);
	INIT_LIST_HEAD(&mod->aliases);

	memcpy(mod->name, name, namelen);
	mod->name[namelen] = '\0';
@@ -1966,6 +1967,7 @@ static void write_vmlinux_export_c_file(struct module *mod)
static void write_mod_c_file(struct module *mod)
{
	struct buffer buf = { };
	struct module_alias *alias, *next;
	char fname[PATH_MAX];
	int ret;

@@ -1973,7 +1975,14 @@ static void write_mod_c_file(struct module *mod)
	add_exported_symbols(&buf, mod);
	add_versions(&buf, mod);
	add_depends(&buf, mod);
	add_moddevtable(&buf, mod);

	buf_printf(&buf, "\n");
	list_for_each_entry_safe(alias, next, &mod->aliases, node) {
		buf_printf(&buf, "MODULE_ALIAS(\"%s\");\n", alias->str);
		list_del(&alias->node);
		free(alias);
	}

	add_srcversion(&buf, mod);

	ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
+17 −2
Original line number Diff line number Diff line
@@ -79,6 +79,22 @@ buf_printf(struct buffer *buf, const char *fmt, ...);
void
buf_write(struct buffer *buf, const char *s, int len);

/**
 * struct module_alias - auto-generated MODULE_ALIAS()
 *
 * @node: linked to module::aliases
 * @str: a string for MODULE_ALIAS()
 */
struct module_alias {
	struct list_head node;
	char str[];
};

/**
 * struct module - represent a module (vmlinux or *.ko)
 *
 * @aliases: list head for module_aliases
 */
struct module {
	struct list_head list;
	struct list_head exported_symbols;
@@ -89,12 +105,12 @@ struct module {
	bool seen;
	bool has_init;
	bool has_cleanup;
	struct buffer dev_table_buf;
	char	     srcversion[25];
	// Missing namespace dependencies
	struct list_head missing_namespaces;
	// Actual imported namespaces
	struct list_head imported_namespaces;
	struct list_head aliases;
	char name[];
};

@@ -170,7 +186,6 @@ Elf_Sym *symsearch_find_nearest(struct elf_info *elf, Elf_Addr addr,
/* file2alias.c */
void handle_moddevtable(struct module *mod, struct elf_info *info,
			Elf_Sym *sym, const char *symname);
void add_moddevtable(struct buffer *buf, struct module *mod);

/* sumversion.c */
void get_src_version(const char *modname, char sum[], unsigned sumlen);