kbuild: warn when a moduled uses a symbol marked UNUSED
We now have infrastructure in place to mark an EXPORTed symbol as unused. So the natural next step is to warn during buildtime when a module uses a symbol marked UNUSED. Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
This commit is contained in:
Родитель
534b89a9f6
Коммит
c96fca2137
|
@ -24,7 +24,10 @@ static int all_versions = 0;
|
||||||
/* If we are modposting external module set to 1 */
|
/* If we are modposting external module set to 1 */
|
||||||
static int external_module = 0;
|
static int external_module = 0;
|
||||||
/* How a symbol is exported */
|
/* How a symbol is exported */
|
||||||
enum export {export_plain, export_gpl, export_gpl_future, export_unknown};
|
enum export {
|
||||||
|
export_plain, export_unused, export_gpl,
|
||||||
|
export_unused_gpl, export_gpl_future, export_unknown
|
||||||
|
};
|
||||||
|
|
||||||
void fatal(const char *fmt, ...)
|
void fatal(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
@ -191,7 +194,9 @@ static struct {
|
||||||
enum export export;
|
enum export export;
|
||||||
} export_list[] = {
|
} export_list[] = {
|
||||||
{ .str = "EXPORT_SYMBOL", .export = export_plain },
|
{ .str = "EXPORT_SYMBOL", .export = export_plain },
|
||||||
|
{ .str = "EXPORT_UNUSED_SYMBOL", .export = export_unused },
|
||||||
{ .str = "EXPORT_SYMBOL_GPL", .export = export_gpl },
|
{ .str = "EXPORT_SYMBOL_GPL", .export = export_gpl },
|
||||||
|
{ .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl },
|
||||||
{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
|
{ .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future },
|
||||||
{ .str = "(unknown)", .export = export_unknown },
|
{ .str = "(unknown)", .export = export_unknown },
|
||||||
};
|
};
|
||||||
|
@ -218,8 +223,12 @@ static enum export export_from_sec(struct elf_info *elf, Elf_Section sec)
|
||||||
{
|
{
|
||||||
if (sec == elf->export_sec)
|
if (sec == elf->export_sec)
|
||||||
return export_plain;
|
return export_plain;
|
||||||
|
else if (sec == elf->export_unused_sec)
|
||||||
|
return export_unused;
|
||||||
else if (sec == elf->export_gpl_sec)
|
else if (sec == elf->export_gpl_sec)
|
||||||
return export_gpl;
|
return export_gpl;
|
||||||
|
else if (sec == elf->export_unused_gpl_sec)
|
||||||
|
return export_unused_gpl;
|
||||||
else if (sec == elf->export_gpl_future_sec)
|
else if (sec == elf->export_gpl_future_sec)
|
||||||
return export_gpl_future;
|
return export_gpl_future;
|
||||||
else
|
else
|
||||||
|
@ -368,8 +377,12 @@ static void parse_elf(struct elf_info *info, const char *filename)
|
||||||
info->modinfo_len = sechdrs[i].sh_size;
|
info->modinfo_len = sechdrs[i].sh_size;
|
||||||
} else if (strcmp(secname, "__ksymtab") == 0)
|
} else if (strcmp(secname, "__ksymtab") == 0)
|
||||||
info->export_sec = i;
|
info->export_sec = i;
|
||||||
|
else if (strcmp(secname, "__ksymtab_unused") == 0)
|
||||||
|
info->export_unused_sec = i;
|
||||||
else if (strcmp(secname, "__ksymtab_gpl") == 0)
|
else if (strcmp(secname, "__ksymtab_gpl") == 0)
|
||||||
info->export_gpl_sec = i;
|
info->export_gpl_sec = i;
|
||||||
|
else if (strcmp(secname, "__ksymtab_unused_gpl") == 0)
|
||||||
|
info->export_unused_gpl_sec = i;
|
||||||
else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
|
else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
|
||||||
info->export_gpl_future_sec = i;
|
info->export_gpl_future_sec = i;
|
||||||
|
|
||||||
|
@ -1087,38 +1100,64 @@ void buf_write(struct buffer *buf, const char *s, int len)
|
||||||
buf->pos += len;
|
buf->pos += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_license(struct module *mod)
|
static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
|
||||||
|
{
|
||||||
|
const char *e = is_vmlinux(m) ?"":".ko";
|
||||||
|
|
||||||
|
switch (exp) {
|
||||||
|
case export_gpl:
|
||||||
|
fatal("modpost: GPL-incompatible module %s%s "
|
||||||
|
"uses GPL-only symbol '%s'\n", m, e, s);
|
||||||
|
break;
|
||||||
|
case export_unused_gpl:
|
||||||
|
fatal("modpost: GPL-incompatible module %s%s "
|
||||||
|
"uses GPL-only symbol marked UNUSED '%s'\n", m, e, s);
|
||||||
|
break;
|
||||||
|
case export_gpl_future:
|
||||||
|
warn("modpost: GPL-incompatible module %s%s "
|
||||||
|
"uses future GPL-only symbol '%s'\n", m, e, s);
|
||||||
|
break;
|
||||||
|
case export_plain:
|
||||||
|
case export_unused:
|
||||||
|
case export_unknown:
|
||||||
|
/* ignore */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_for_unused(enum export exp, const char* m, const char* s)
|
||||||
|
{
|
||||||
|
const char *e = is_vmlinux(m) ?"":".ko";
|
||||||
|
|
||||||
|
switch (exp) {
|
||||||
|
case export_unused:
|
||||||
|
case export_unused_gpl:
|
||||||
|
warn("modpost: module %s%s "
|
||||||
|
"uses symbol '%s' marked UNUSED\n", m, e, s);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* ignore */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_exports(struct module *mod)
|
||||||
{
|
{
|
||||||
struct symbol *s, *exp;
|
struct symbol *s, *exp;
|
||||||
|
|
||||||
for (s = mod->unres; s; s = s->next) {
|
for (s = mod->unres; s; s = s->next) {
|
||||||
const char *basename;
|
const char *basename;
|
||||||
if (mod->gpl_compatible == 1) {
|
|
||||||
/* GPL-compatible modules may use all symbols */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
exp = find_symbol(s->name);
|
exp = find_symbol(s->name);
|
||||||
if (!exp || exp->module == mod)
|
if (!exp || exp->module == mod)
|
||||||
continue;
|
continue;
|
||||||
basename = strrchr(mod->name, '/');
|
basename = strrchr(mod->name, '/');
|
||||||
if (basename)
|
if (basename)
|
||||||
basename++;
|
basename++;
|
||||||
switch (exp->export) {
|
else
|
||||||
case export_gpl:
|
basename = mod->name;
|
||||||
fatal("modpost: GPL-incompatible module %s "
|
if (!mod->gpl_compatible)
|
||||||
"uses GPL-only symbol '%s'\n",
|
check_for_gpl_usage(exp->export, basename, exp->name);
|
||||||
basename ? basename : mod->name,
|
check_for_unused(exp->export, basename, exp->name);
|
||||||
exp->name);
|
|
||||||
break;
|
|
||||||
case export_gpl_future:
|
|
||||||
warn("modpost: GPL-incompatible module %s "
|
|
||||||
"uses future GPL-only symbol '%s'\n",
|
|
||||||
basename ? basename : mod->name,
|
|
||||||
exp->name);
|
|
||||||
break;
|
|
||||||
case export_plain: /* ignore */ break;
|
|
||||||
case export_unknown: /* ignore */ break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1399,7 +1438,7 @@ int main(int argc, char **argv)
|
||||||
for (mod = modules; mod; mod = mod->next) {
|
for (mod = modules; mod; mod = mod->next) {
|
||||||
if (mod->skip)
|
if (mod->skip)
|
||||||
continue;
|
continue;
|
||||||
check_license(mod);
|
check_exports(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (mod = modules; mod; mod = mod->next) {
|
for (mod = modules; mod; mod = mod->next) {
|
||||||
|
|
|
@ -117,7 +117,9 @@ struct elf_info {
|
||||||
Elf_Sym *symtab_start;
|
Elf_Sym *symtab_start;
|
||||||
Elf_Sym *symtab_stop;
|
Elf_Sym *symtab_stop;
|
||||||
Elf_Section export_sec;
|
Elf_Section export_sec;
|
||||||
|
Elf_Section export_unused_sec;
|
||||||
Elf_Section export_gpl_sec;
|
Elf_Section export_gpl_sec;
|
||||||
|
Elf_Section export_unused_gpl_sec;
|
||||||
Elf_Section export_gpl_future_sec;
|
Elf_Section export_gpl_future_sec;
|
||||||
const char *strtab;
|
const char *strtab;
|
||||||
char *modinfo;
|
char *modinfo;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче