mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 15:03:53 +02:00
Kbuild updates for v6.16
- Add support for the EXPORT_SYMBOL_GPL_FOR_MODULES() macro, which exports a symbol only to specified modules - Improve ABI handling in gendwarfksyms - Forcibly link lib-y objects to vmlinux even if CONFIG_MODULES=n - Add checkers for redundant or missing <linux/export.h> inclusion - Deprecate the extra-y syntax - Fix a genksyms bug when including enum constants from *.symref files -----BEGIN PGP SIGNATURE----- iQJJBAABCgAzFiEEbmPs18K1szRHjPqEPYsBB53g2wYFAmhEZc4VHG1hc2FoaXJv eUBrZXJuZWwub3JnAAoJED2LAQed4NsGVAgQAKLRdBGga1kBJJFIkUOHWC5+g/je U/dO5rGnuOLviWDexC6QT8AQV2N+dQXhB11x+KacSu1bwowsEvwuegtA6VqwbETs tyWmB0PftEzVyPfc+Rjfy0LDfKkiKkm4RhXiMwcem/rlw45gvJXrVU7jJin9fI3A So8glpOAX+mEizUHkjZkS51nkYCZFDsn7hVo0X43vqjeFrrFGLEQ5xas4Ci+dkY3 9g8Q5bFL8CC5PHjSO8wFftCcAWwTukAht6CSSb522MKGnCVZ9RxTmRwEPXrBmXtS 5eWa8yg6y0tFVmot8iwZGBYleAWDNsj0a2j2oVjUN+EF91sk3WQApJVNBok/nQFb 4MgO3N3UXZdy4tYkBX8tMgOcGkfjZAFoNxSUm5oVouh9NyT0dpqYHhJHBNVbVJoF igQWeVOYcioDjeU1iXnP2cw64q44ROfxmOpDxOSRz9PTM6CCya1R0m/zzBLV6Lwk rzlXk1LLf+jIfgmS5RLlkCgrXS1U0vNGXxQH9Ui9dZSEtzdU7qt5WQ/Rz44bEBhS OeIlJfMMx6QYJztJc/BaUjkKsutTkII52QctRbRCj/nKswHd8SnHV+xk1c2WPxrg yKq10rPpdg1BcvmODY6cmcndt7ogDRfkogm2gvGQIBZEglRimpmpg51sZQRD0ueE 0rt12TmktsLbglB4 =Dy49 -----END PGP SIGNATURE----- Merge tag 'kbuild-v6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild Pull Kbuild updates from Masahiro Yamada: - Add support for the EXPORT_SYMBOL_GPL_FOR_MODULES() macro, which exports a symbol only to specified modules - Improve ABI handling in gendwarfksyms - Forcibly link lib-y objects to vmlinux even if CONFIG_MODULES=n - Add checkers for redundant or missing <linux/export.h> inclusion - Deprecate the extra-y syntax - Fix a genksyms bug when including enum constants from *.symref files * tag 'kbuild-v6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild: (28 commits) genksyms: Fix enum consts from a reference affecting new values arch: use always-$(KBUILD_BUILTIN) for vmlinux.lds kbuild: set y instead of 1 to KBUILD_{BUILTIN,MODULES} efi/libstub: use 'targets' instead of extra-y in Makefile module: make __mod_device_table__* symbols static scripts/misc-check: check unnecessary #include <linux/export.h> when W=1 scripts/misc-check: check missing #include <linux/export.h> when W=1 scripts/misc-check: add double-quotes to satisfy shellcheck kbuild: move W=1 check for scripts/misc-check to top-level Makefile scripts/tags.sh: allow to use alternative ctags implementation kconfig: introduce menu type enum docs: symbol-namespaces: fix reST warning with literal block kbuild: link lib-y objects to vmlinux forcibly even when CONFIG_MODULES=n tinyconfig: enable CONFIG_LD_DEAD_CODE_DATA_ELIMINATION docs/core-api/symbol-namespaces: drop table of contents and section numbering modpost: check forbidden MODULE_IMPORT_NS("module:") at compile time kbuild: move kbuild syntax processing to scripts/Makefile.build Makefile: remove dependency on archscripts for header installation Documentation/kbuild: Add new gendwarfksyms kABI rules Documentation/kbuild: Drop section numbers ...
This commit is contained in:
commit
8630c59e99
|
@ -6,18 +6,8 @@ The following document describes how to use Symbol Namespaces to structure the
|
|||
export surface of in-kernel symbols exported through the family of
|
||||
EXPORT_SYMBOL() macros.
|
||||
|
||||
.. Table of Contents
|
||||
|
||||
=== 1 Introduction
|
||||
=== 2 How to define Symbol Namespaces
|
||||
--- 2.1 Using the EXPORT_SYMBOL macros
|
||||
--- 2.2 Using the DEFAULT_SYMBOL_NAMESPACE define
|
||||
=== 3 How to use Symbols exported in Namespaces
|
||||
=== 4 Loading Modules that use namespaced Symbols
|
||||
=== 5 Automatically creating MODULE_IMPORT_NS statements
|
||||
|
||||
1. Introduction
|
||||
===============
|
||||
Introduction
|
||||
============
|
||||
|
||||
Symbol Namespaces have been introduced as a means to structure the export
|
||||
surface of the in-kernel API. It allows subsystem maintainers to partition
|
||||
|
@ -28,15 +18,18 @@ kernel. As of today, modules that make use of symbols exported into namespaces,
|
|||
are required to import the namespace. Otherwise the kernel will, depending on
|
||||
its configuration, reject loading the module or warn about a missing import.
|
||||
|
||||
2. How to define Symbol Namespaces
|
||||
==================================
|
||||
Additionally, it is possible to put symbols into a module namespace, strictly
|
||||
limiting which modules are allowed to use these symbols.
|
||||
|
||||
How to define Symbol Namespaces
|
||||
===============================
|
||||
|
||||
Symbols can be exported into namespace using different methods. All of them are
|
||||
changing the way EXPORT_SYMBOL and friends are instrumented to create ksymtab
|
||||
entries.
|
||||
|
||||
2.1 Using the EXPORT_SYMBOL macros
|
||||
==================================
|
||||
Using the EXPORT_SYMBOL macros
|
||||
------------------------------
|
||||
|
||||
In addition to the macros EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(), that allow
|
||||
exporting of kernel symbols to the kernel symbol table, variants of these are
|
||||
|
@ -54,8 +47,8 @@ refer to ``NULL``. There is no default namespace if none is defined. ``modpost``
|
|||
and kernel/module/main.c make use the namespace at build time or module load
|
||||
time, respectively.
|
||||
|
||||
2.2 Using the DEFAULT_SYMBOL_NAMESPACE define
|
||||
=============================================
|
||||
Using the DEFAULT_SYMBOL_NAMESPACE define
|
||||
-----------------------------------------
|
||||
|
||||
Defining namespaces for all symbols of a subsystem can be very verbose and may
|
||||
become hard to maintain. Therefore a default define (DEFAULT_SYMBOL_NAMESPACE)
|
||||
|
@ -83,8 +76,24 @@ unit as preprocessor statement. The above example would then read::
|
|||
within the corresponding compilation unit before the #include for
|
||||
<linux/export.h>. Typically it's placed before the first #include statement.
|
||||
|
||||
3. How to use Symbols exported in Namespaces
|
||||
============================================
|
||||
Using the EXPORT_SYMBOL_GPL_FOR_MODULES() macro
|
||||
-----------------------------------------------
|
||||
|
||||
Symbols exported using this macro are put into a module namespace. This
|
||||
namespace cannot be imported.
|
||||
|
||||
The macro takes a comma separated list of module names, allowing only those
|
||||
modules to access this symbol. Simple tail-globs are supported.
|
||||
|
||||
For example::
|
||||
|
||||
EXPORT_SYMBOL_GPL_FOR_MODULES(preempt_notifier_inc, "kvm,kvm-*")
|
||||
|
||||
will limit usage of this symbol to modules whoes name matches the given
|
||||
patterns.
|
||||
|
||||
How to use Symbols exported in Namespaces
|
||||
=========================================
|
||||
|
||||
In order to use symbols that are exported into namespaces, kernel modules need
|
||||
to explicitly import these namespaces. Otherwise the kernel might reject to
|
||||
|
@ -106,11 +115,10 @@ inspected with modinfo::
|
|||
|
||||
|
||||
It is advisable to add the MODULE_IMPORT_NS() statement close to other module
|
||||
metadata definitions like MODULE_AUTHOR() or MODULE_LICENSE(). Refer to section
|
||||
5. for a way to create missing import statements automatically.
|
||||
metadata definitions like MODULE_AUTHOR() or MODULE_LICENSE().
|
||||
|
||||
4. Loading Modules that use namespaced Symbols
|
||||
==============================================
|
||||
Loading Modules that use namespaced Symbols
|
||||
===========================================
|
||||
|
||||
At module loading time (e.g. ``insmod``), the kernel will check each symbol
|
||||
referenced from the module for its availability and whether the namespace it
|
||||
|
@ -121,8 +129,8 @@ allow loading of modules that don't satisfy this precondition, a configuration
|
|||
option is available: Setting MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y will
|
||||
enable loading regardless, but will emit a warning.
|
||||
|
||||
5. Automatically creating MODULE_IMPORT_NS statements
|
||||
=====================================================
|
||||
Automatically creating MODULE_IMPORT_NS statements
|
||||
==================================================
|
||||
|
||||
Missing namespaces imports can easily be detected at build time. In fact,
|
||||
modpost will emit a warning if a module uses a symbol from a namespace
|
||||
|
@ -154,3 +162,6 @@ in-tree modules::
|
|||
You can also run nsdeps for external module builds. A typical usage is::
|
||||
|
||||
$ make -C <path_to_kernel_src> M=$PWD nsdeps
|
||||
|
||||
Note: it will happily generate an import statement for the module namespace;
|
||||
which will not work and generates build and runtime failures.
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
DWARF module versioning
|
||||
=======================
|
||||
|
||||
1. Introduction
|
||||
===============
|
||||
Introduction
|
||||
============
|
||||
|
||||
When CONFIG_MODVERSIONS is enabled, symbol versions for modules
|
||||
are typically calculated from preprocessed source code using the
|
||||
|
@ -14,8 +14,8 @@ selected, **gendwarfksyms** is used instead to calculate symbol versions
|
|||
from the DWARF debugging information, which contains the necessary
|
||||
details about the final module ABI.
|
||||
|
||||
1.1. Usage
|
||||
==========
|
||||
Usage
|
||||
-----
|
||||
|
||||
gendwarfksyms accepts a list of object files on the command line, and a
|
||||
list of symbol names (one per line) in standard input::
|
||||
|
@ -33,8 +33,8 @@ list of symbol names (one per line) in standard input::
|
|||
-h, --help Print this message
|
||||
|
||||
|
||||
2. Type information availability
|
||||
================================
|
||||
Type information availability
|
||||
=============================
|
||||
|
||||
While symbols are typically exported in the same translation unit (TU)
|
||||
where they're defined, it's also perfectly fine for a TU to export
|
||||
|
@ -56,8 +56,8 @@ type for calculating symbol versions even if the symbol is defined
|
|||
elsewhere. The name of the symbol pointer is expected to start with
|
||||
`__gendwarfksyms_ptr_`, followed by the name of the exported symbol.
|
||||
|
||||
3. Symtypes output format
|
||||
=========================
|
||||
Symtypes output format
|
||||
======================
|
||||
|
||||
Similarly to genksyms, gendwarfksyms supports writing a symtypes
|
||||
file for each processed object that contain types for exported
|
||||
|
@ -85,8 +85,8 @@ produces C-style type strings, gendwarfksyms uses the same simple parsed
|
|||
DWARF format produced by **--dump-dies**, but with type references
|
||||
instead of fully expanded strings.
|
||||
|
||||
4. Maintaining a stable kABI
|
||||
============================
|
||||
Maintaining a stable kABI
|
||||
=========================
|
||||
|
||||
Distribution maintainers often need the ability to make ABI compatible
|
||||
changes to kernel data structures due to LTS updates or backports. Using
|
||||
|
@ -104,8 +104,8 @@ for source code annotation. Note that as these features are only used to
|
|||
transform the inputs for symbol versioning, the user is responsible for
|
||||
ensuring that their changes actually won't break the ABI.
|
||||
|
||||
4.1. kABI rules
|
||||
===============
|
||||
kABI rules
|
||||
----------
|
||||
|
||||
kABI rules allow distributions to fine-tune certain parts
|
||||
of gendwarfksyms output and thus control how symbol
|
||||
|
@ -125,22 +125,25 @@ the rules. The fields are as follows:
|
|||
qualified name of the DWARF Debugging Information Entry (DIE).
|
||||
- `value`: Provides rule-specific data.
|
||||
|
||||
The following helper macro, for example, can be used to specify rules
|
||||
The following helper macros, for example, can be used to specify rules
|
||||
in the source code::
|
||||
|
||||
#define __KABI_RULE(hint, target, value) \
|
||||
static const char __PASTE(__gendwarfksyms_rule_, \
|
||||
#define ___KABI_RULE(hint, target, value) \
|
||||
static const char __PASTE(__gendwarfksyms_rule_, \
|
||||
__COUNTER__)[] __used __aligned(1) \
|
||||
__section(".discard.gendwarfksyms.kabi_rules") = \
|
||||
"1\0" #hint "\0" #target "\0" #value
|
||||
"1\0" #hint "\0" target "\0" value
|
||||
|
||||
#define __KABI_RULE(hint, target, value) \
|
||||
___KABI_RULE(hint, #target, #value)
|
||||
|
||||
|
||||
Currently, only the rules discussed in this section are supported, but
|
||||
the format is extensible enough to allow further rules to be added as
|
||||
need arises.
|
||||
|
||||
4.1.1. Managing definition visibility
|
||||
=====================================
|
||||
Managing definition visibility
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A declaration can change into a full definition when additional includes
|
||||
are pulled into the translation unit. This changes the versions of any
|
||||
|
@ -168,8 +171,8 @@ Example usage::
|
|||
|
||||
KABI_DECLONLY(s);
|
||||
|
||||
4.1.2. Adding enumerators
|
||||
=========================
|
||||
Adding enumerators
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For enums, all enumerators and their values are included in calculating
|
||||
symbol versions, which becomes a problem if we later need to add more
|
||||
|
@ -223,8 +226,89 @@ Example usage::
|
|||
KABI_ENUMERATOR_IGNORE(e, C);
|
||||
KABI_ENUMERATOR_VALUE(e, LAST, 2);
|
||||
|
||||
4.3. Adding structure members
|
||||
=============================
|
||||
Managing structure size changes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A data structure can be partially opaque to modules if its allocation is
|
||||
handled by the core kernel, and modules only need to access some of its
|
||||
members. In this situation, it's possible to append new members to the
|
||||
structure without breaking the ABI, as long as the layout for the original
|
||||
members remains unchanged.
|
||||
|
||||
To append new members, we can hide them from symbol versioning as
|
||||
described in section :ref:`Hiding members <hiding_members>`, but we can't
|
||||
hide the increase in structure size. The `byte_size` rule allows us to
|
||||
override the structure size used for symbol versioning.
|
||||
|
||||
The rule fields are expected to be as follows:
|
||||
|
||||
- `type`: "byte_size"
|
||||
- `target`: The fully qualified name of the target data structure
|
||||
(as shown in **--dump-dies** output).
|
||||
- `value`: A positive decimal number indicating the structure size
|
||||
in bytes.
|
||||
|
||||
Using the `__KABI_RULE` macro, this rule can be defined as::
|
||||
|
||||
#define KABI_BYTE_SIZE(fqn, value) \
|
||||
__KABI_RULE(byte_size, fqn, value)
|
||||
|
||||
Example usage::
|
||||
|
||||
struct s {
|
||||
/* Unchanged original members */
|
||||
unsigned long a;
|
||||
void *p;
|
||||
|
||||
/* Appended new members */
|
||||
KABI_IGNORE(0, unsigned long n);
|
||||
};
|
||||
|
||||
KABI_BYTE_SIZE(s, 16);
|
||||
|
||||
Overriding type strings
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In rare situations where distributions must make significant changes to
|
||||
otherwise opaque data structures that have inadvertently been included
|
||||
in the published ABI, keeping symbol versions stable using the more
|
||||
targeted kABI rules can become tedious. The `type_string` rule allows us
|
||||
to override the full type string for a type or a symbol, and even add
|
||||
types for versioning that no longer exist in the kernel.
|
||||
|
||||
The rule fields are expected to be as follows:
|
||||
|
||||
- `type`: "type_string"
|
||||
- `target`: The fully qualified name of the target data structure
|
||||
(as shown in **--dump-dies** output) or symbol.
|
||||
- `value`: A valid type string (as shown in **--symtypes**) output)
|
||||
to use instead of the real type.
|
||||
|
||||
Using the `__KABI_RULE` macro, this rule can be defined as::
|
||||
|
||||
#define KABI_TYPE_STRING(type, str) \
|
||||
___KABI_RULE("type_string", type, str)
|
||||
|
||||
Example usage::
|
||||
|
||||
/* Override type for a structure */
|
||||
KABI_TYPE_STRING("s#s",
|
||||
"structure_type s { "
|
||||
"member base_type int byte_size(4) "
|
||||
"encoding(5) n "
|
||||
"data_member_location(0) "
|
||||
"} byte_size(8)");
|
||||
|
||||
/* Override type for a symbol */
|
||||
KABI_TYPE_STRING("my_symbol", "variable s#s");
|
||||
|
||||
The `type_string` rule should be used only as a last resort if maintaining
|
||||
a stable symbol versions cannot be reasonably achieved using other
|
||||
means. Overriding a type string increases the risk of actual ABI breakages
|
||||
going unnoticed as it hides all changes to the type.
|
||||
|
||||
Adding structure members
|
||||
------------------------
|
||||
|
||||
Perhaps the most common ABI compatible change is adding a member to a
|
||||
kernel data structure. When changes to a structure are anticipated,
|
||||
|
@ -237,8 +321,8 @@ natural method. This section describes gendwarfksyms support for using
|
|||
reserved space in data structures and hiding members that don't change
|
||||
the ABI when calculating symbol versions.
|
||||
|
||||
4.3.1. Reserving space and replacing members
|
||||
============================================
|
||||
Reserving space and replacing members
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Space is typically reserved for later use by appending integer types, or
|
||||
arrays, to the end of the data structure, but any type can be used. Each
|
||||
|
@ -276,8 +360,10 @@ The examples include `KABI_(RESERVE|USE|REPLACE)*` macros that help
|
|||
simplify the process and also ensure the replacement member is correctly
|
||||
aligned and its size won't exceed the reserved space.
|
||||
|
||||
4.3.2. Hiding members
|
||||
=====================
|
||||
.. _hiding_members:
|
||||
|
||||
Hiding members
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Predicting which structures will require changes during the support
|
||||
timeframe isn't always possible, in which case one might have to resort
|
||||
|
@ -305,4 +391,5 @@ member to a union where one of the fields has a name starting with
|
|||
unsigned long b;
|
||||
};
|
||||
|
||||
With **--stable**, both versions produce the same symbol version.
|
||||
With **--stable**, both versions produce the same symbol version. The
|
||||
examples include a `KABI_IGNORE` macro to simplify the code.
|
||||
|
|
|
@ -291,6 +291,10 @@ Example::
|
|||
# arch/x86/kernel/Makefile
|
||||
extra-y += vmlinux.lds
|
||||
|
||||
extra-y is now deprecated because this is equivalent to:
|
||||
|
||||
always-$(KBUILD_BUILTIN) += vmlinux.lds
|
||||
|
||||
$(extra-y) should only contain targets needed for vmlinux.
|
||||
|
||||
Kbuild skips extra-y when vmlinux is apparently not a final goal.
|
||||
|
|
|
@ -10,8 +10,8 @@ Questo documento descrive come usare lo spazio dei nomi dei simboli
|
|||
per strutturare quello che viene esportato internamente al kernel
|
||||
grazie alle macro della famiglia EXPORT_SYMBOL().
|
||||
|
||||
1. Introduzione
|
||||
===============
|
||||
Introduzione
|
||||
============
|
||||
|
||||
Lo spazio dei nomi dei simboli è stato introdotto come mezzo per strutturare
|
||||
l'API esposta internamente al kernel. Permette ai manutentori di un
|
||||
|
@ -24,15 +24,15 @@ devono prima importare detto spazio. Altrimenti il kernel, a seconda
|
|||
della configurazione, potrebbe rifiutare di caricare il modulo o
|
||||
avvisare l'utente di un'importazione mancante.
|
||||
|
||||
2. Come definire uno spazio dei nomi dei simboli
|
||||
================================================
|
||||
Come definire uno spazio dei nomi dei simboli
|
||||
=============================================
|
||||
|
||||
I simboli possono essere esportati in spazi dei nomi usando diversi
|
||||
meccanismi. Tutti questi meccanismi cambiano il modo in cui
|
||||
EXPORT_SYMBOL e simili vengono guidati verso la creazione di voci in ksymtab.
|
||||
|
||||
2.1 Usare le macro EXPORT_SYMBOL
|
||||
================================
|
||||
Usare le macro EXPORT_SYMBOL
|
||||
----------------------------
|
||||
|
||||
In aggiunta alle macro EXPORT_SYMBOL() e EXPORT_SYMBOL_GPL(), che permettono
|
||||
di esportare simboli del kernel nella rispettiva tabella, ci sono
|
||||
|
@ -53,8 +53,8 @@ di base. Il programma ``modpost`` e il codice in kernel/module/main.c usano lo
|
|||
spazio dei nomi, rispettivamente, durante la compilazione e durante il
|
||||
caricamento di un modulo.
|
||||
|
||||
2.2 Usare il simbolo di preprocessore DEFAULT_SYMBOL_NAMESPACE
|
||||
==============================================================
|
||||
Usare il simbolo di preprocessore DEFAULT_SYMBOL_NAMESPACE
|
||||
----------------------------------------------------------
|
||||
|
||||
Definire lo spazio dei nomi per tutti i simboli di un sottosistema può essere
|
||||
logorante e di difficile manutenzione. Perciò è stato fornito un simbolo
|
||||
|
@ -83,8 +83,8 @@ direttamente nei file da compilare. L'esempio precedente diventerebbe::
|
|||
|
||||
Questo va messo prima di un qualsiasi uso di EXPORT_SYMBOL.
|
||||
|
||||
3. Come usare i simboli esportati attraverso uno spazio dei nomi
|
||||
================================================================
|
||||
Come usare i simboli esportati attraverso uno spazio dei nomi
|
||||
=============================================================
|
||||
|
||||
Per usare i simboli esportati da uno spazio dei nomi, i moduli del
|
||||
kernel devono esplicitamente importare il relativo spazio dei nomi; altrimenti
|
||||
|
@ -108,12 +108,10 @@ modinfo::
|
|||
|
||||
|
||||
Si consiglia di posizionare la dichiarazione MODULE_IMPORT_NS() vicino
|
||||
ai metadati del modulo come MODULE_AUTHOR() o MODULE_LICENSE(). Fate
|
||||
riferimento alla sezione 5. per creare automaticamente le importazioni
|
||||
mancanti.
|
||||
ai metadati del modulo come MODULE_AUTHOR() o MODULE_LICENSE().
|
||||
|
||||
4. Caricare moduli che usano simboli provenienti da spazi dei nomi
|
||||
==================================================================
|
||||
Caricare moduli che usano simboli provenienti da spazi dei nomi
|
||||
===============================================================
|
||||
|
||||
Quando un modulo viene caricato (per esempio usando ``insmod``), il kernel
|
||||
verificherà la disponibilità di ogni simbolo usato e se lo spazio dei nomi
|
||||
|
@ -125,8 +123,8 @@ un'opzione di configurazione: impostare
|
|||
MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y caricherà i moduli comunque ma
|
||||
emetterà un avviso.
|
||||
|
||||
5. Creare automaticamente la dichiarazione MODULE_IMPORT_NS
|
||||
===========================================================
|
||||
Creare automaticamente la dichiarazione MODULE_IMPORT_NS
|
||||
========================================================
|
||||
|
||||
La mancanza di un'importazione può essere individuata facilmente al momento
|
||||
della compilazione. Infatti, modpost emetterà un avviso se il modulo usa
|
||||
|
|
|
@ -14,18 +14,8 @@
|
|||
|
||||
本文档描述了如何使用符号命名空间来构造通过EXPORT_SYMBOL()系列宏导出的内核内符号的导出面。
|
||||
|
||||
.. 目录
|
||||
|
||||
=== 1 简介
|
||||
=== 2 如何定义符号命名空间
|
||||
--- 2.1 使用EXPORT_SYMBOL宏
|
||||
--- 2.2 使用DEFAULT_SYMBOL_NAMESPACE定义
|
||||
=== 3 如何使用命名空间中导出的符号
|
||||
=== 4 加载使用命名空间符号的模块
|
||||
=== 5 自动创建MODULE_IMPORT_NS声明
|
||||
|
||||
1. 简介
|
||||
=======
|
||||
简介
|
||||
====
|
||||
|
||||
符号命名空间已经被引入,作为构造内核内API的导出面的一种手段。它允许子系统维护者将
|
||||
他们导出的符号划分进独立的命名空间。这对于文档的编写非常有用(想想SUBSYSTEM_DEBUG
|
||||
|
@ -33,14 +23,14 @@
|
|||
的模块必须导入命名空间。否则,内核将根据其配置,拒绝加载该模块或警告说缺少
|
||||
导入。
|
||||
|
||||
2. 如何定义符号命名空间
|
||||
=======================
|
||||
如何定义符号命名空间
|
||||
====================
|
||||
|
||||
符号可以用不同的方法导出到命名空间。所有这些都在改变 EXPORT_SYMBOL 和与之类似的那些宏
|
||||
被检测到的方式,以创建 ksymtab 条目。
|
||||
|
||||
2.1 使用EXPORT_SYMBOL宏
|
||||
=======================
|
||||
使用EXPORT_SYMBOL宏
|
||||
-------------------
|
||||
|
||||
除了允许将内核符号导出到内核符号表的宏EXPORT_SYMBOL()和EXPORT_SYMBOL_GPL()之外,
|
||||
这些宏的变体还可以将符号导出到某个命名空间:EXPORT_SYMBOL_NS() 和 EXPORT_SYMBOL_NS_GPL()。
|
||||
|
@ -54,8 +44,8 @@
|
|||
导出时未指明命名空间的符号将指向 ``NULL`` 。如果没有定义命名空间,则默认没有。
|
||||
``modpost`` 和kernel/module/main.c分别在构建时或模块加载时使用名称空间。
|
||||
|
||||
2.2 使用DEFAULT_SYMBOL_NAMESPACE定义
|
||||
====================================
|
||||
使用DEFAULT_SYMBOL_NAMESPACE定义
|
||||
--------------------------------
|
||||
|
||||
为一个子系统的所有符号定义命名空间可能会非常冗长,并可能变得难以维护。因此,我
|
||||
们提供了一个默认定义(DEFAULT_SYMBOL_NAMESPACE),如果设置了这个定义, 它将成
|
||||
|
@ -80,8 +70,8 @@
|
|||
|
||||
应置于相关编译单元中任何 EXPORT_SYMBOL 宏之前
|
||||
|
||||
3. 如何使用命名空间中导出的符号
|
||||
===============================
|
||||
如何使用命名空间中导出的符号
|
||||
============================
|
||||
|
||||
为了使用被导出到命名空间的符号,内核模块需要明确地导入这些命名空间。
|
||||
否则内核可能会拒绝加载该模块。模块代码需要使用宏MODULE_IMPORT_NS来
|
||||
|
@ -100,11 +90,10 @@
|
|||
|
||||
|
||||
建议将 MODULE_IMPORT_NS() 语句添加到靠近其他模块元数据定义的地方,
|
||||
如 MODULE_AUTHOR() 或 MODULE_LICENSE() 。关于自动创建缺失的导入
|
||||
语句的方法,请参考第5节。
|
||||
如 MODULE_AUTHOR() 或 MODULE_LICENSE() 。
|
||||
|
||||
4. 加载使用命名空间符号的模块
|
||||
=============================
|
||||
加载使用命名空间符号的模块
|
||||
==========================
|
||||
|
||||
在模块加载时(比如 ``insmod`` ),内核将检查每个从模块中引用的符号是否可
|
||||
用,以及它可能被导出到的名字空间是否被模块导入。内核的默认行为是拒绝
|
||||
|
@ -113,8 +102,8 @@ EINVAL方式失败。要允许加载不满足这个前提条件的模块,可
|
|||
设置 MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y 将使加载不受影响,但会
|
||||
发出警告。
|
||||
|
||||
5. 自动创建MODULE_IMPORT_NS声明
|
||||
===============================
|
||||
自动创建MODULE_IMPORT_NS声明
|
||||
============================
|
||||
|
||||
缺少命名空间的导入可以在构建时很容易被检测到。事实上,如果一个模块
|
||||
使用了一个命名空间的符号而没有导入它,modpost会发出警告。
|
||||
|
|
28
Makefile
28
Makefile
|
@ -754,7 +754,7 @@ targets :=
|
|||
# Normally, just do built-in.
|
||||
|
||||
KBUILD_MODULES :=
|
||||
KBUILD_BUILTIN := 1
|
||||
KBUILD_BUILTIN := y
|
||||
|
||||
# If we have only "make modules", don't compile built-in objects.
|
||||
ifeq ($(MAKECMDGOALS),modules)
|
||||
|
@ -766,11 +766,11 @@ endif
|
|||
# Just "make" or "make all" shall build modules as well
|
||||
|
||||
ifneq ($(filter all modules nsdeps compile_commands.json clang-%,$(MAKECMDGOALS)),)
|
||||
KBUILD_MODULES := 1
|
||||
KBUILD_MODULES := y
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),)
|
||||
KBUILD_MODULES := 1
|
||||
KBUILD_MODULES := y
|
||||
endif
|
||||
|
||||
export KBUILD_MODULES KBUILD_BUILTIN
|
||||
|
@ -1189,13 +1189,8 @@ export ARCH_LIB := $(filter %/, $(libs-y))
|
|||
export ARCH_DRIVERS := $(drivers-y) $(drivers-m)
|
||||
# Externally visible symbols (used by link-vmlinux.sh)
|
||||
|
||||
KBUILD_VMLINUX_OBJS := ./built-in.a
|
||||
ifdef CONFIG_MODULES
|
||||
KBUILD_VMLINUX_OBJS += $(patsubst %/, %/lib.a, $(filter %/, $(libs-y)))
|
||||
KBUILD_VMLINUX_OBJS := built-in.a $(patsubst %/, %/lib.a, $(filter %/, $(libs-y)))
|
||||
KBUILD_VMLINUX_LIBS := $(filter-out %/, $(libs-y))
|
||||
else
|
||||
KBUILD_VMLINUX_LIBS := $(patsubst %/,%/lib.a, $(libs-y))
|
||||
endif
|
||||
|
||||
export KBUILD_VMLINUX_LIBS
|
||||
export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds
|
||||
|
@ -1203,7 +1198,7 @@ export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds
|
|||
ifdef CONFIG_TRIM_UNUSED_KSYMS
|
||||
# For the kernel to actually contain only the needed exported symbols,
|
||||
# we have to build modules as well to determine what those symbols are.
|
||||
KBUILD_MODULES := 1
|
||||
KBUILD_MODULES := y
|
||||
endif
|
||||
|
||||
# '$(AR) mPi' needs 'T' to workaround the bug of llvm-ar <= 14
|
||||
|
@ -1370,7 +1365,7 @@ PHONY += archheaders archscripts
|
|||
hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj
|
||||
|
||||
PHONY += headers
|
||||
headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders archscripts
|
||||
headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders
|
||||
ifdef HEADER_ARCH
|
||||
$(Q)$(MAKE) -f $(srctree)/Makefile HEADER_ARCH= SRCARCH=$(HEADER_ARCH) headers
|
||||
else
|
||||
|
@ -1543,7 +1538,7 @@ all: modules
|
|||
# the built-in objects during the descend as well, in order to
|
||||
# make sure the checksums are up to date before we record them.
|
||||
ifdef CONFIG_MODVERSIONS
|
||||
KBUILD_BUILTIN := 1
|
||||
KBUILD_BUILTIN := y
|
||||
endif
|
||||
|
||||
# Build modules
|
||||
|
@ -1552,7 +1547,7 @@ endif
|
|||
# *.ko are usually independent of vmlinux, but CONFIG_DEBUG_INFO_BTF_MODULES
|
||||
# is an exception.
|
||||
ifdef CONFIG_DEBUG_INFO_BTF_MODULES
|
||||
KBUILD_BUILTIN := 1
|
||||
KBUILD_BUILTIN := y
|
||||
modules: vmlinux
|
||||
endif
|
||||
|
||||
|
@ -1837,9 +1832,12 @@ rustfmtcheck: rustfmt
|
|||
# Misc
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Run misc checks when ${KBUILD_EXTRA_WARN} contains 1
|
||||
PHONY += misc-check
|
||||
ifneq ($(findstring 1,$(KBUILD_EXTRA_WARN)),)
|
||||
misc-check:
|
||||
$(Q)$(srctree)/scripts/misc-check
|
||||
endif
|
||||
|
||||
all: misc-check
|
||||
|
||||
|
@ -1865,7 +1863,7 @@ filechk_kernel.release = echo $(KERNELRELEASE)
|
|||
|
||||
# We are always building only modules.
|
||||
KBUILD_BUILTIN :=
|
||||
KBUILD_MODULES := 1
|
||||
KBUILD_MODULES := y
|
||||
|
||||
build-dir := .
|
||||
|
||||
|
@ -1993,7 +1991,7 @@ endif
|
|||
|
||||
single-goals := $(addprefix $(build-dir)/, $(single-no-ko))
|
||||
|
||||
KBUILD_MODULES := 1
|
||||
KBUILD_MODULES := y
|
||||
|
||||
endif
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
asflags-y := $(KBUILD_CFLAGS)
|
||||
ccflags-y := -Wno-sign-compare
|
||||
|
||||
|
|
|
@ -26,4 +26,4 @@ ifdef CONFIG_ISA_ARCOMPACT
|
|||
CFLAGS_fpu.o += -mdpfp
|
||||
endif
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
|
|
@ -104,4 +104,4 @@ obj-$(CONFIG_HAVE_ARM_SMCCC) += smccc-call.o
|
|||
|
||||
obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += spectre.o
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
|
|
@ -78,7 +78,7 @@ $(obj)/vdso32-wrap.o: $(obj)/vdso32/vdso.so
|
|||
|
||||
obj-y += probes/
|
||||
obj-y += head.o
|
||||
extra-y += vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) += vmlinux.lds
|
||||
|
||||
ifeq ($(CONFIG_DEBUG_EFI),y)
|
||||
AFLAGS_head.o += -DVMLINUX_PATH="\"$(realpath $(objtree)/vmlinux)\""
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
obj-y += head.o entry.o atomic.o signal.o traps.o irq.o time.o vdso.o vdso/
|
||||
obj-y += power.o syscall.o syscall_table.o setup.o
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
obj-y += head.o
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
OBJECT_FILES_NON_STANDARD_head.o := y
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
|
||||
traps.o irq.o idle.o process.o dma.o mem.o reset.o switch.o \
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
extra-y += vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) += vmlinux.lds
|
||||
|
||||
obj-$(CONFIG_MMU_MOTOROLA) := head.o
|
||||
obj-$(CONFIG_SUN3) := sun3-head.o
|
||||
|
|
|
@ -11,7 +11,7 @@ CFLAGS_REMOVE_ftrace.o = -pg
|
|||
CFLAGS_REMOVE_process.o = -pg
|
||||
endif
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
obj-y += head.o dma.o exceptions.o \
|
||||
hw_exception_handler.o irq.o \
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for the Linux/MIPS kernel.
|
||||
#
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
obj-y += head.o branch.o cmpxchg.o elf.o entry.o genex.o idle.o irq.o \
|
||||
process.o prom.o ptrace.o reset.o setup.o signal.o \
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for the nios2 linux kernel.
|
||||
#
|
||||
|
||||
extra-y += vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) += vmlinux.lds
|
||||
|
||||
obj-y += head.o
|
||||
obj-y += cpuinfo.o
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
obj-y := head.o setup.o or32_ksyms.o process.o dma.o \
|
||||
traps.o time.o irq.o entry.o ptrace.o signal.o \
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for arch/parisc/kernel
|
||||
#
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
obj-y := head.o cache.o pacache.o setup.o pdt.o traps.o time.o irq.o \
|
||||
syscall.o entry.o sys_parisc.o firmware.o \
|
||||
|
|
|
@ -126,7 +126,7 @@ obj-$(CONFIG_PPC_BOOK3S_32) += head_book3s_32.o
|
|||
obj-$(CONFIG_44x) += head_44x.o
|
||||
obj-$(CONFIG_PPC_8xx) += head_8xx.o
|
||||
obj-$(CONFIG_PPC_85xx) += head_85xx.o
|
||||
extra-y += vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) += vmlinux.lds
|
||||
|
||||
obj-$(CONFIG_RELOCATABLE) += reloc_$(BITS).o
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ CFLAGS_sbi_ecall.o += -D__NO_FORTIFY
|
|||
endif
|
||||
endif
|
||||
|
||||
extra-y += vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) += vmlinux.lds
|
||||
|
||||
obj-y += head.o
|
||||
obj-y += soc.o
|
||||
|
|
|
@ -46,7 +46,7 @@ obj-y += nospec-branch.o ipl_vmparm.o machine_kexec_reloc.o unwind_bc.o
|
|||
obj-y += smp.o text_amode31.o stacktrace.o abs_lowcore.o facility.o uv.o wti.o
|
||||
obj-y += diag/
|
||||
|
||||
extra-y += vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) += vmlinux.lds
|
||||
|
||||
obj-$(CONFIG_SYSFS) += nospec-sysfs.o
|
||||
CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for the Linux/SuperH kernel.
|
||||
#
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
# Do not profile debug and lowlevel utilities
|
||||
|
|
|
@ -9,7 +9,7 @@ asflags-y := -ansi
|
|||
# Undefine sparc when processing vmlinux.lds - it is used
|
||||
# And teach CPP we are doing $(BITS) builds (for this case)
|
||||
CPPFLAGS_vmlinux.lds := -Usparc -m$(BITS)
|
||||
extra-y += vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) += vmlinux.lds
|
||||
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
# Do not profile debug and lowlevel utilities
|
||||
|
|
|
@ -12,7 +12,7 @@ CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START) \
|
|||
-DELF_ARCH=$(LDS_ELF_ARCH) \
|
||||
-DELF_FORMAT=$(LDS_ELF_FORMAT) \
|
||||
$(LDS_EXTRA)
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \
|
||||
physmem.o process.o ptrace.o reboot.o sigio.o \
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
extra-y += vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) += vmlinux.lds
|
||||
|
||||
CPPFLAGS_vmlinux.lds += -U$(UTS_MACHINE)
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for the Linux/Xtensa kernel.
|
||||
#
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
always-$(KBUILD_BUILTIN) := vmlinux.lds
|
||||
|
||||
obj-y := head.o align.o coprocessor.o entry.o irq.o platform.o process.o \
|
||||
ptrace.o setup.o signal.o stacktrace.o syscall.o time.o traps.o \
|
||||
|
|
|
@ -101,7 +101,7 @@ lib-$(CONFIG_EFI_ZBOOT) += zboot.o $(zboot-obj-y)
|
|||
|
||||
lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o
|
||||
|
||||
extra-y := $(lib-y)
|
||||
targets := $(lib-y)
|
||||
lib-y := $(patsubst %.o,%.stub.o,$(lib-y))
|
||||
|
||||
# Even when -mbranch-protection=none is set, Clang will generate a
|
||||
|
|
|
@ -24,11 +24,17 @@
|
|||
.long sym
|
||||
#endif
|
||||
|
||||
#define ___EXPORT_SYMBOL(sym, license, ns) \
|
||||
/*
|
||||
* LLVM integrated assembler cam merge adjacent string literals (like
|
||||
* C and GNU-as) passed to '.ascii', but not to '.asciz' and chokes on:
|
||||
*
|
||||
* .asciz "MODULE_" "kvm" ;
|
||||
*/
|
||||
#define ___EXPORT_SYMBOL(sym, license, ns...) \
|
||||
.section ".export_symbol","a" ASM_NL \
|
||||
__export_symbol_##sym: ASM_NL \
|
||||
.asciz license ASM_NL \
|
||||
.asciz ns ASM_NL \
|
||||
.ascii ns "\0" ASM_NL \
|
||||
__EXPORT_SYMBOL_REF(sym) ASM_NL \
|
||||
.previous
|
||||
|
||||
|
@ -85,4 +91,6 @@
|
|||
#define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", ns)
|
||||
#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "GPL", ns)
|
||||
|
||||
#define EXPORT_SYMBOL_GPL_FOR_MODULES(sym, mods) __EXPORT_SYMBOL(sym, "GPL", "module:" mods)
|
||||
|
||||
#endif /* _LINUX_EXPORT_H */
|
||||
|
|
|
@ -249,8 +249,8 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name);
|
|||
#ifdef MODULE
|
||||
/* Creates an alias so file2alias.c can find device table. */
|
||||
#define MODULE_DEVICE_TABLE(type, name) \
|
||||
extern typeof(name) __mod_device_table__##type##__##name \
|
||||
__attribute__ ((unused, alias(__stringify(name))))
|
||||
static typeof(name) __mod_device_table__##type##__##name \
|
||||
__attribute__ ((used, alias(__stringify(name))))
|
||||
#else /* !MODULE */
|
||||
#define MODULE_DEVICE_TABLE(type, name)
|
||||
#endif
|
||||
|
|
|
@ -2,3 +2,4 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
|||
CONFIG_KERNEL_XZ=y
|
||||
CONFIG_SLUB=y
|
||||
CONFIG_SLUB_TINY=y
|
||||
CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y
|
||||
|
|
|
@ -169,6 +169,30 @@ static inline void add_taint_module(struct module *mod, unsigned flag,
|
|||
set_bit(flag, &mod->taints);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like strncmp(), except s/-/_/g as per scripts/Makefile.lib:name-fix-token rule.
|
||||
*/
|
||||
static int mod_strncmp(const char *str_a, const char *str_b, size_t n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
char a = str_a[i];
|
||||
char b = str_b[i];
|
||||
int d;
|
||||
|
||||
if (a == '-') a = '_';
|
||||
if (b == '-') b = '_';
|
||||
|
||||
d = a - b;
|
||||
if (d)
|
||||
return d;
|
||||
|
||||
if (!a)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A thread that wants to hold a reference to a module only while it
|
||||
* is running can call this to safely exit.
|
||||
|
@ -1083,6 +1107,46 @@ static char *get_modinfo(const struct load_info *info, const char *tag)
|
|||
return get_next_modinfo(info, tag, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* verify_module_namespace() - does @modname have access to this symbol's @namespace
|
||||
* @namespace: export symbol namespace
|
||||
* @modname: module name
|
||||
*
|
||||
* If @namespace is prefixed with "module:" to indicate it is a module namespace
|
||||
* then test if @modname matches any of the comma separated patterns.
|
||||
*
|
||||
* The patterns only support tail-glob.
|
||||
*/
|
||||
static bool verify_module_namespace(const char *namespace, const char *modname)
|
||||
{
|
||||
size_t len, modlen = strlen(modname);
|
||||
const char *prefix = "module:";
|
||||
const char *sep;
|
||||
bool glob;
|
||||
|
||||
if (!strstarts(namespace, prefix))
|
||||
return false;
|
||||
|
||||
for (namespace += strlen(prefix); *namespace; namespace = sep) {
|
||||
sep = strchrnul(namespace, ',');
|
||||
len = sep - namespace;
|
||||
|
||||
glob = false;
|
||||
if (sep[-1] == '*') {
|
||||
len--;
|
||||
glob = true;
|
||||
}
|
||||
|
||||
if (*sep)
|
||||
sep++;
|
||||
|
||||
if (mod_strncmp(namespace, modname, len) == 0 && (glob || len == modlen))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int verify_namespace_is_imported(const struct load_info *info,
|
||||
const struct kernel_symbol *sym,
|
||||
struct module *mod)
|
||||
|
@ -1092,6 +1156,10 @@ static int verify_namespace_is_imported(const struct load_info *info,
|
|||
|
||||
namespace = kernel_symbol_namespace(sym);
|
||||
if (namespace && namespace[0]) {
|
||||
|
||||
if (verify_module_namespace(namespace, mod->name))
|
||||
return 0;
|
||||
|
||||
for_each_modinfo_entry(imported_namespace, info, "import_ns") {
|
||||
if (strcmp(namespace, imported_namespace) == 0)
|
||||
return 0;
|
||||
|
@ -1658,15 +1726,30 @@ static void module_license_taint_check(struct module *mod, const char *license)
|
|||
}
|
||||
}
|
||||
|
||||
static void setup_modinfo(struct module *mod, struct load_info *info)
|
||||
static int setup_modinfo(struct module *mod, struct load_info *info)
|
||||
{
|
||||
const struct module_attribute *attr;
|
||||
char *imported_namespace;
|
||||
int i;
|
||||
|
||||
for (i = 0; (attr = modinfo_attrs[i]); i++) {
|
||||
if (attr->setup)
|
||||
attr->setup(mod, get_modinfo(info, attr->attr.name));
|
||||
}
|
||||
|
||||
for_each_modinfo_entry(imported_namespace, info, "import_ns") {
|
||||
/*
|
||||
* 'module:' prefixed namespaces are implicit, disallow
|
||||
* explicit imports.
|
||||
*/
|
||||
if (strstarts(imported_namespace, "module:")) {
|
||||
pr_err("%s: module tries to import module namespace: %s\n",
|
||||
mod->name, imported_namespace);
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_modinfo(struct module *mod)
|
||||
|
@ -3323,7 +3406,9 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
|||
goto free_unload;
|
||||
|
||||
/* Set up MODINFO_ATTR fields */
|
||||
setup_modinfo(mod, info);
|
||||
err = setup_modinfo(mod, info);
|
||||
if (err)
|
||||
goto free_modinfo;
|
||||
|
||||
/* Fix up syms, so that st_value is a pointer to location. */
|
||||
err = simplify_symbols(mod, info);
|
||||
|
|
|
@ -37,6 +37,90 @@ include $(srctree)/scripts/Makefile.compiler
|
|||
include $(kbuild-file)
|
||||
include $(srctree)/scripts/Makefile.lib
|
||||
|
||||
# flags that take effect in current and sub directories
|
||||
KBUILD_AFLAGS += $(subdir-asflags-y)
|
||||
KBUILD_CFLAGS += $(subdir-ccflags-y)
|
||||
KBUILD_RUSTFLAGS += $(subdir-rustflags-y)
|
||||
|
||||
# Figure out what we need to build from the various variables
|
||||
# ===========================================================================
|
||||
|
||||
# When an object is listed to be built compiled-in and modular,
|
||||
# only build the compiled-in version
|
||||
obj-m := $(filter-out $(obj-y),$(obj-m))
|
||||
|
||||
# Libraries are always collected in one lib file.
|
||||
# Filter out objects already built-in
|
||||
lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
|
||||
|
||||
# Subdirectories we need to descend into
|
||||
subdir-ym := $(sort $(subdir-y) $(subdir-m) \
|
||||
$(patsubst %/,%, $(filter %/, $(obj-y) $(obj-m))))
|
||||
|
||||
# Handle objects in subdirs:
|
||||
# - If we encounter foo/ in $(obj-y), replace it by foo/built-in.a and
|
||||
# foo/modules.order
|
||||
# - If we encounter foo/ in $(obj-m), replace it by foo/modules.order
|
||||
#
|
||||
# Generate modules.order to determine modorder. Unfortunately, we don't have
|
||||
# information about ordering between -y and -m subdirs. Just put -y's first.
|
||||
|
||||
ifdef need-modorder
|
||||
obj-m := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m))
|
||||
else
|
||||
obj-m := $(filter-out %/, $(obj-m))
|
||||
endif
|
||||
|
||||
ifdef need-builtin
|
||||
obj-y := $(patsubst %/, %/built-in.a, $(obj-y))
|
||||
else
|
||||
obj-y := $(filter-out %/, $(obj-y))
|
||||
endif
|
||||
|
||||
# Expand $(foo-objs) $(foo-y) etc. by replacing their individuals
|
||||
suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s))))
|
||||
# List composite targets that are constructed by combining other targets
|
||||
multi-search = $(sort $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $m)))
|
||||
# List primitive targets that are compiled from source files
|
||||
real-search = $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $(call suffix-search, $m, $2, $3), $m))
|
||||
|
||||
# If $(foo-objs), $(foo-y), $(foo-m), or $(foo-) exists, foo.o is a composite object
|
||||
multi-obj-y := $(call multi-search, $(obj-y), .o, -objs -y)
|
||||
multi-obj-m := $(call multi-search, $(obj-m), .o, -objs -y -m)
|
||||
multi-obj-ym := $(multi-obj-y) $(multi-obj-m)
|
||||
|
||||
# Replace multi-part objects by their individual parts,
|
||||
# including built-in.a from subdirectories
|
||||
real-obj-y := $(call real-search, $(obj-y), .o, -objs -y)
|
||||
real-obj-m := $(call real-search, $(obj-m), .o, -objs -y -m)
|
||||
|
||||
always-y += $(always-m)
|
||||
|
||||
# hostprogs-always-y += foo
|
||||
# ... is a shorthand for
|
||||
# hostprogs += foo
|
||||
# always-y += foo
|
||||
hostprogs += $(hostprogs-always-y) $(hostprogs-always-m)
|
||||
always-y += $(hostprogs-always-y) $(hostprogs-always-m)
|
||||
|
||||
# userprogs-always-y is likewise.
|
||||
userprogs += $(userprogs-always-y) $(userprogs-always-m)
|
||||
always-y += $(userprogs-always-y) $(userprogs-always-m)
|
||||
|
||||
# Add subdir path
|
||||
|
||||
ifneq ($(obj),.)
|
||||
extra-y := $(addprefix $(obj)/, $(extra-y))
|
||||
always-y := $(addprefix $(obj)/, $(always-y))
|
||||
targets := $(addprefix $(obj)/, $(targets))
|
||||
obj-m := $(addprefix $(obj)/, $(obj-m))
|
||||
lib-y := $(addprefix $(obj)/, $(lib-y))
|
||||
real-obj-y := $(addprefix $(obj)/, $(real-obj-y))
|
||||
real-obj-m := $(addprefix $(obj)/, $(real-obj-m))
|
||||
multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m))
|
||||
subdir-ym := $(addprefix $(obj)/, $(subdir-ym))
|
||||
endif
|
||||
|
||||
ifndef obj
|
||||
$(warning kbuild: Makefile.build is included improperly)
|
||||
endif
|
||||
|
|
|
@ -1,89 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# flags that take effect in current and sub directories
|
||||
KBUILD_AFLAGS += $(subdir-asflags-y)
|
||||
KBUILD_CFLAGS += $(subdir-ccflags-y)
|
||||
KBUILD_RUSTFLAGS += $(subdir-rustflags-y)
|
||||
|
||||
# Figure out what we need to build from the various variables
|
||||
# ===========================================================================
|
||||
|
||||
# When an object is listed to be built compiled-in and modular,
|
||||
# only build the compiled-in version
|
||||
obj-m := $(filter-out $(obj-y),$(obj-m))
|
||||
|
||||
# Libraries are always collected in one lib file.
|
||||
# Filter out objects already built-in
|
||||
lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
|
||||
|
||||
# Subdirectories we need to descend into
|
||||
subdir-ym := $(sort $(subdir-y) $(subdir-m) \
|
||||
$(patsubst %/,%, $(filter %/, $(obj-y) $(obj-m))))
|
||||
|
||||
# Handle objects in subdirs:
|
||||
# - If we encounter foo/ in $(obj-y), replace it by foo/built-in.a and
|
||||
# foo/modules.order
|
||||
# - If we encounter foo/ in $(obj-m), replace it by foo/modules.order
|
||||
#
|
||||
# Generate modules.order to determine modorder. Unfortunately, we don't have
|
||||
# information about ordering between -y and -m subdirs. Just put -y's first.
|
||||
|
||||
ifdef need-modorder
|
||||
obj-m := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m))
|
||||
else
|
||||
obj-m := $(filter-out %/, $(obj-m))
|
||||
endif
|
||||
|
||||
ifdef need-builtin
|
||||
obj-y := $(patsubst %/, %/built-in.a, $(obj-y))
|
||||
else
|
||||
obj-y := $(filter-out %/, $(obj-y))
|
||||
endif
|
||||
|
||||
# Expand $(foo-objs) $(foo-y) etc. by replacing their individuals
|
||||
suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s))))
|
||||
# List composite targets that are constructed by combining other targets
|
||||
multi-search = $(sort $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $m)))
|
||||
# List primitive targets that are compiled from source files
|
||||
real-search = $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $(call suffix-search, $m, $2, $3), $m))
|
||||
|
||||
# If $(foo-objs), $(foo-y), $(foo-m), or $(foo-) exists, foo.o is a composite object
|
||||
multi-obj-y := $(call multi-search, $(obj-y), .o, -objs -y)
|
||||
multi-obj-m := $(call multi-search, $(obj-m), .o, -objs -y -m)
|
||||
multi-obj-ym := $(multi-obj-y) $(multi-obj-m)
|
||||
|
||||
# Replace multi-part objects by their individual parts,
|
||||
# including built-in.a from subdirectories
|
||||
real-obj-y := $(call real-search, $(obj-y), .o, -objs -y)
|
||||
real-obj-m := $(call real-search, $(obj-m), .o, -objs -y -m)
|
||||
|
||||
always-y += $(always-m)
|
||||
|
||||
# hostprogs-always-y += foo
|
||||
# ... is a shorthand for
|
||||
# hostprogs += foo
|
||||
# always-y += foo
|
||||
hostprogs += $(hostprogs-always-y) $(hostprogs-always-m)
|
||||
always-y += $(hostprogs-always-y) $(hostprogs-always-m)
|
||||
|
||||
# userprogs-always-y is likewise.
|
||||
userprogs += $(userprogs-always-y) $(userprogs-always-m)
|
||||
always-y += $(userprogs-always-y) $(userprogs-always-m)
|
||||
|
||||
# Add subdir path
|
||||
|
||||
ifneq ($(obj),.)
|
||||
extra-y := $(addprefix $(obj)/,$(extra-y))
|
||||
always-y := $(addprefix $(obj)/,$(always-y))
|
||||
targets := $(addprefix $(obj)/,$(targets))
|
||||
obj-m := $(addprefix $(obj)/,$(obj-m))
|
||||
lib-y := $(addprefix $(obj)/,$(lib-y))
|
||||
real-obj-y := $(addprefix $(obj)/,$(real-obj-y))
|
||||
real-obj-m := $(addprefix $(obj)/,$(real-obj-m))
|
||||
multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m))
|
||||
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
|
||||
endif
|
||||
|
||||
# Finds the multi-part object the current object will be linked into.
|
||||
# If the object belongs to two or more multi-part objects, list them all.
|
||||
modname-multi = $(sort $(foreach m,$(multi-obj-ym),\
|
||||
|
|
|
@ -228,12 +228,24 @@ static void process_fqn(struct die *cache, Dwarf_Die *die)
|
|||
DEFINE_PROCESS_UDATA_ATTRIBUTE(accessibility)
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment)
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(bit_size)
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size)
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding)
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(data_bit_offset)
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(data_member_location)
|
||||
DEFINE_PROCESS_UDATA_ATTRIBUTE(discr_value)
|
||||
|
||||
static void process_byte_size_attr(struct die *cache, Dwarf_Die *die)
|
||||
{
|
||||
Dwarf_Word value;
|
||||
unsigned long override;
|
||||
|
||||
if (get_udata_attr(die, DW_AT_byte_size, &value)) {
|
||||
if (stable && kabi_get_byte_size(cache->fqn, &override))
|
||||
value = override;
|
||||
|
||||
process_fmt(cache, " byte_size(%" PRIu64 ")", value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Match functions -- die_match_callback_t */
|
||||
#define DEFINE_MATCH(type) \
|
||||
static bool match_##type##_type(Dwarf_Die *die) \
|
||||
|
|
|
@ -37,11 +37,14 @@
|
|||
#define __stringify(x...) __stringify_1(x)
|
||||
#endif
|
||||
|
||||
#define __KABI_RULE(hint, target, value) \
|
||||
#define ___KABI_RULE(hint, target, value) \
|
||||
static const char __PASTE(__gendwarfksyms_rule_, \
|
||||
__COUNTER__)[] __used __aligned(1) \
|
||||
__section(".discard.gendwarfksyms.kabi_rules") = \
|
||||
"1\0" #hint "\0" #target "\0" #value
|
||||
"1\0" #hint "\0" target "\0" value
|
||||
|
||||
#define __KABI_RULE(hint, target, value) \
|
||||
___KABI_RULE(hint, #target, #value)
|
||||
|
||||
#define __KABI_NORMAL_SIZE_ALIGN(_orig, _new) \
|
||||
union { \
|
||||
|
@ -89,6 +92,20 @@
|
|||
#define KABI_ENUMERATOR_VALUE(fqn, field, value) \
|
||||
__KABI_RULE(enumerator_value, fqn field, value)
|
||||
|
||||
/*
|
||||
* KABI_BYTE_SIZE(fqn, value)
|
||||
* Set the byte_size attribute for the struct/union/enum fqn to
|
||||
* value bytes.
|
||||
*/
|
||||
#define KABI_BYTE_SIZE(fqn, value) __KABI_RULE(byte_size, fqn, value)
|
||||
|
||||
/*
|
||||
* KABI_TYPE_STRING(type, str)
|
||||
* For the given type, override the type string used in symtypes
|
||||
* output and version calculation with str.
|
||||
*/
|
||||
#define KABI_TYPE_STRING(type, str) ___KABI_RULE(type_string, type, str)
|
||||
|
||||
/*
|
||||
* KABI_RESERVE
|
||||
* Reserve some "padding" in a structure for use by LTS backports.
|
||||
|
|
|
@ -28,3 +28,10 @@ struct ex2c ex2c;
|
|||
struct ex3a ex3a;
|
||||
struct ex3b ex3b;
|
||||
struct ex3c ex3c;
|
||||
|
||||
struct ex4a ex4a;
|
||||
|
||||
struct ex5a ex5a;
|
||||
struct ex5b ex5b;
|
||||
|
||||
int ex6a;
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
* ./gendwarfksyms --stable --dump-dies \
|
||||
* examples/kabi_ex.o 2>&1 >/dev/null | \
|
||||
* FileCheck examples/kabi_ex.h --check-prefix=STABLE
|
||||
|
||||
* $ nm examples/kabi_ex.o | awk '{ print $NF }' | \
|
||||
* ./gendwarfksyms --stable --dump-versions \
|
||||
* examples/kabi_ex.o 2>&1 >/dev/null | \
|
||||
* sort | \
|
||||
* FileCheck examples/kabi_ex.h --check-prefix=VERSIONS
|
||||
*/
|
||||
|
||||
#ifndef __KABI_EX_H__
|
||||
|
@ -170,7 +176,7 @@ struct ex2a {
|
|||
/*
|
||||
* STABLE: variable structure_type ex2a {
|
||||
* STABLE-NEXT: member base_type int byte_size(4) encoding(5) a data_member_location(0) ,
|
||||
* STABLE-NEXT: member base_type [[ULONG:long unsigned int|unsigned long]] byte_size(8) encoding(7) b data_member_location(8)
|
||||
* STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) b data_member_location(8)
|
||||
* STABLE-NEXT: member base_type int byte_size(4) encoding(5) c data_member_location(16) ,
|
||||
* STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) d data_member_location(24)
|
||||
* STABLE-NEXT: } byte_size(32)
|
||||
|
@ -227,7 +233,7 @@ struct ex3a {
|
|||
|
||||
/*
|
||||
* STABLE: variable structure_type ex3a {
|
||||
* STABLE-NEXT: member base_type [[ULONG:long unsigned int|unsigned long]] byte_size(8) encoding(7) a data_member_location(0)
|
||||
* STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) a data_member_location(0)
|
||||
* STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) unused data_member_location(8)
|
||||
* STABLE-NEXT: } byte_size(16)
|
||||
*/
|
||||
|
@ -260,4 +266,95 @@ _Static_assert(sizeof(struct ex3a) == sizeof(struct ex3c), "ex3a size doesn't ma
|
|||
* STABLE-NEXT: } byte_size(16)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Example: An ignored field added to an end of a partially opaque struct,
|
||||
* while keeping the byte_size attribute unchanged.
|
||||
*/
|
||||
|
||||
struct ex4a {
|
||||
unsigned long a;
|
||||
KABI_IGNORE(0, unsigned long b);
|
||||
};
|
||||
|
||||
/*
|
||||
* This may be safe if the structure allocation is managed by the core kernel
|
||||
* and the layout remains unchanged except for appended new members.
|
||||
*/
|
||||
KABI_BYTE_SIZE(ex4a, 8);
|
||||
|
||||
/*
|
||||
* STABLE: variable structure_type ex4a {
|
||||
* STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) a data_member_location(0)
|
||||
* STABLE-NEXT: } byte_size(8)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Example: A type string override.
|
||||
*/
|
||||
|
||||
struct ex5a {
|
||||
unsigned long a;
|
||||
};
|
||||
|
||||
/*
|
||||
* This may be safe if the structure is fully opaque to modules, even though
|
||||
* its definition has inadvertently become part of the ABI.
|
||||
*/
|
||||
KABI_TYPE_STRING(
|
||||
"s#ex5a",
|
||||
"structure_type ex5a { member pointer_type { s#ex4a } byte_size(8) p data_member_location(0) } byte_size(8)");
|
||||
|
||||
/*
|
||||
* Make sure the fully expanded type string includes ex4a.
|
||||
*
|
||||
* VERSIONS: ex5a variable structure_type ex5a {
|
||||
* VERSIONS-SAME: member pointer_type {
|
||||
* VERSIONS-SAME: structure_type ex4a {
|
||||
* VERSIONS-SAME: member base_type [[ULONG:long unsigned int|unsigned long]] byte_size(8) encoding(7) a data_member_location(0)
|
||||
* VERSIONS-SAME: } byte_size(8)
|
||||
* VERSIONS-SAME: } byte_size(8) p data_member_location(0)
|
||||
* VERSIONS-SAME: } byte_size(8)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Example: A type string definition for a non-existent type.
|
||||
*/
|
||||
|
||||
struct ex5b {
|
||||
unsigned long a;
|
||||
};
|
||||
|
||||
/* Replace the type string for struct ex5b */
|
||||
KABI_TYPE_STRING(
|
||||
"s#ex5b",
|
||||
"structure_type ex5b { member pointer_type { s#ex5c } byte_size(8) p data_member_location(0) } byte_size(8)");
|
||||
|
||||
/* Define a type string for a non-existent struct ex5c */
|
||||
KABI_TYPE_STRING(
|
||||
"s#ex5c",
|
||||
"structure_type ex5c { member base_type int byte_size(4) encoding(5) n data_member_location(0) } byte_size(8)");
|
||||
|
||||
/*
|
||||
* Make sure the fully expanded type string includes the definition for ex5c.
|
||||
*
|
||||
* VERSIONS: ex5b variable structure_type ex5b {
|
||||
* VERSIONS-SAME: member pointer_type {
|
||||
* VERSIONS-SAME: structure_type ex5c {
|
||||
* VERSIONS-SAME: member base_type int byte_size(4) encoding(5) n data_member_location(0)
|
||||
* VERSIONS-SAME: } byte_size(8)
|
||||
* VERSIONS-SAME: } byte_size(8) p data_member_location(0)
|
||||
* VERSIONS-SAME: } byte_size(8)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Example: A type string override for a symbol.
|
||||
*/
|
||||
|
||||
KABI_TYPE_STRING("ex6a", "variable s#ex5c");
|
||||
|
||||
/*
|
||||
* VERSIONS: ex6a variable structure_type ex5c {
|
||||
* VERSIONS-SAME: member base_type int byte_size(4) encoding(5) n data_member_location(0)
|
||||
* VERSIONS-SAME: } byte_size(8)
|
||||
*/
|
||||
#endif /* __KABI_EX_H__ */
|
||||
|
|
|
@ -287,10 +287,12 @@ void generate_symtypes_and_versions(FILE *file);
|
|||
* kabi.c
|
||||
*/
|
||||
|
||||
bool kabi_get_byte_size(const char *fqn, unsigned long *value);
|
||||
bool kabi_is_enumerator_ignored(const char *fqn, const char *field);
|
||||
bool kabi_get_enumerator_value(const char *fqn, const char *field,
|
||||
unsigned long *value);
|
||||
bool kabi_is_declonly(const char *fqn);
|
||||
bool kabi_get_type_string(const char *type, const char **str);
|
||||
|
||||
void kabi_read_rules(int fd);
|
||||
void kabi_free(void);
|
||||
|
|
|
@ -54,11 +54,27 @@
|
|||
*/
|
||||
#define KABI_RULE_TAG_ENUMERATOR_VALUE "enumerator_value"
|
||||
|
||||
/*
|
||||
* Rule: byte_size
|
||||
* - For the fqn_field in the target field, set the byte_size
|
||||
* attribute to the value in the value field.
|
||||
*/
|
||||
#define KABI_RULE_TAG_BYTE_SIZE "byte_size"
|
||||
|
||||
/*
|
||||
* Rule: type_string
|
||||
* - For the type reference in the fqn field, use the type string
|
||||
* in the value field.
|
||||
*/
|
||||
#define KABI_RULE_TAG_TYPE_STRING "type_string"
|
||||
|
||||
enum kabi_rule_type {
|
||||
KABI_RULE_TYPE_UNKNOWN,
|
||||
KABI_RULE_TYPE_DECLONLY,
|
||||
KABI_RULE_TYPE_ENUMERATOR_IGNORE,
|
||||
KABI_RULE_TYPE_ENUMERATOR_VALUE,
|
||||
KABI_RULE_TYPE_BYTE_SIZE,
|
||||
KABI_RULE_TYPE_TYPE_STRING,
|
||||
};
|
||||
|
||||
#define RULE_HASH_BITS 7
|
||||
|
@ -127,6 +143,14 @@ void kabi_read_rules(int fd)
|
|||
.type = KABI_RULE_TYPE_ENUMERATOR_VALUE,
|
||||
.tag = KABI_RULE_TAG_ENUMERATOR_VALUE,
|
||||
},
|
||||
{
|
||||
.type = KABI_RULE_TYPE_BYTE_SIZE,
|
||||
.tag = KABI_RULE_TAG_BYTE_SIZE,
|
||||
},
|
||||
{
|
||||
.type = KABI_RULE_TYPE_TYPE_STRING,
|
||||
.tag = KABI_RULE_TAG_TYPE_STRING,
|
||||
},
|
||||
};
|
||||
|
||||
if (!stable)
|
||||
|
@ -222,25 +246,6 @@ void kabi_read_rules(int fd)
|
|||
check(elf_end(elf));
|
||||
}
|
||||
|
||||
bool kabi_is_declonly(const char *fqn)
|
||||
{
|
||||
struct rule *rule;
|
||||
|
||||
if (!stable)
|
||||
return false;
|
||||
if (!fqn || !*fqn)
|
||||
return false;
|
||||
|
||||
hash_for_each_possible(rules, rule, hash,
|
||||
rule_values_hash(KABI_RULE_TYPE_DECLONLY, fqn)) {
|
||||
if (rule->type == KABI_RULE_TYPE_DECLONLY &&
|
||||
!strcmp(fqn, rule->target))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static char *get_enumerator_target(const char *fqn, const char *field)
|
||||
{
|
||||
char *target = NULL;
|
||||
|
@ -251,6 +256,47 @@ static char *get_enumerator_target(const char *fqn, const char *field)
|
|||
return target;
|
||||
}
|
||||
|
||||
static struct rule *find_rule(enum kabi_rule_type type, const char *target)
|
||||
{
|
||||
struct rule *rule;
|
||||
|
||||
if (!stable)
|
||||
return NULL;
|
||||
if (!target || !*target)
|
||||
return NULL;
|
||||
|
||||
hash_for_each_possible(rules, rule, hash,
|
||||
rule_values_hash(type, target)) {
|
||||
if (rule->type == type && !strcmp(target, rule->target))
|
||||
return rule;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct rule *find_enumerator_rule(enum kabi_rule_type type,
|
||||
const char *fqn, const char *field)
|
||||
{
|
||||
struct rule *rule;
|
||||
char *target;
|
||||
|
||||
if (!stable)
|
||||
return NULL;
|
||||
if (!fqn || !*fqn || !field || !*field)
|
||||
return NULL;
|
||||
|
||||
target = get_enumerator_target(fqn, field);
|
||||
rule = find_rule(type, target);
|
||||
|
||||
free(target);
|
||||
return rule;
|
||||
}
|
||||
|
||||
bool kabi_is_declonly(const char *fqn)
|
||||
{
|
||||
return !!find_rule(KABI_RULE_TYPE_DECLONLY, fqn);
|
||||
}
|
||||
|
||||
static unsigned long get_ulong_value(const char *value)
|
||||
{
|
||||
unsigned long result = 0;
|
||||
|
@ -267,58 +313,49 @@ static unsigned long get_ulong_value(const char *value)
|
|||
|
||||
bool kabi_is_enumerator_ignored(const char *fqn, const char *field)
|
||||
{
|
||||
bool match = false;
|
||||
struct rule *rule;
|
||||
char *target;
|
||||
|
||||
if (!stable)
|
||||
return false;
|
||||
if (!fqn || !*fqn || !field || !*field)
|
||||
return false;
|
||||
|
||||
target = get_enumerator_target(fqn, field);
|
||||
|
||||
hash_for_each_possible(
|
||||
rules, rule, hash,
|
||||
rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_IGNORE, target)) {
|
||||
if (rule->type == KABI_RULE_TYPE_ENUMERATOR_IGNORE &&
|
||||
!strcmp(target, rule->target)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(target);
|
||||
return match;
|
||||
return !!find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_IGNORE, fqn,
|
||||
field);
|
||||
}
|
||||
|
||||
bool kabi_get_enumerator_value(const char *fqn, const char *field,
|
||||
unsigned long *value)
|
||||
{
|
||||
bool match = false;
|
||||
struct rule *rule;
|
||||
char *target;
|
||||
|
||||
if (!stable)
|
||||
return false;
|
||||
if (!fqn || !*fqn || !field || !*field)
|
||||
return false;
|
||||
|
||||
target = get_enumerator_target(fqn, field);
|
||||
|
||||
hash_for_each_possible(rules, rule, hash,
|
||||
rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_VALUE,
|
||||
target)) {
|
||||
if (rule->type == KABI_RULE_TYPE_ENUMERATOR_VALUE &&
|
||||
!strcmp(target, rule->target)) {
|
||||
*value = get_ulong_value(rule->value);
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
rule = find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_VALUE, fqn,
|
||||
field);
|
||||
if (rule) {
|
||||
*value = get_ulong_value(rule->value);
|
||||
return true;
|
||||
}
|
||||
|
||||
free(target);
|
||||
return match;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kabi_get_byte_size(const char *fqn, unsigned long *value)
|
||||
{
|
||||
struct rule *rule;
|
||||
|
||||
rule = find_rule(KABI_RULE_TYPE_BYTE_SIZE, fqn);
|
||||
if (rule) {
|
||||
*value = get_ulong_value(rule->value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kabi_get_type_string(const char *type, const char **str)
|
||||
{
|
||||
struct rule *rule;
|
||||
|
||||
rule = find_rule(KABI_RULE_TYPE_TYPE_STRING, type);
|
||||
if (rule) {
|
||||
*str = rule->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void kabi_free(void)
|
||||
|
|
|
@ -100,7 +100,7 @@ static void type_expansion_append(struct type_expansion *type, const char *s,
|
|||
#define TYPE_HASH_BITS 12
|
||||
static HASHTABLE_DEFINE(type_map, 1 << TYPE_HASH_BITS);
|
||||
|
||||
static int type_map_get(const char *name, struct type_expansion **res)
|
||||
static int __type_map_get(const char *name, struct type_expansion **res)
|
||||
{
|
||||
struct type_expansion *e;
|
||||
|
||||
|
@ -114,11 +114,12 @@ static int type_map_get(const char *name, struct type_expansion **res)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void type_map_add(const char *name, struct type_expansion *type)
|
||||
static struct type_expansion *type_map_add(const char *name,
|
||||
struct type_expansion *type)
|
||||
{
|
||||
struct type_expansion *e;
|
||||
|
||||
if (type_map_get(name, &e)) {
|
||||
if (__type_map_get(name, &e)) {
|
||||
e = xmalloc(sizeof(struct type_expansion));
|
||||
type_expansion_init(e);
|
||||
e->name = xstrdup(name);
|
||||
|
@ -130,7 +131,7 @@ static void type_map_add(const char *name, struct type_expansion *type)
|
|||
} else {
|
||||
/* Use the longest available expansion */
|
||||
if (type->len <= e->len)
|
||||
return;
|
||||
return e;
|
||||
|
||||
type_list_free(&e->expanded);
|
||||
|
||||
|
@ -148,6 +149,34 @@ static void type_map_add(const char *name, struct type_expansion *type)
|
|||
type_list_write(&e->expanded, stderr);
|
||||
checkp(fputs("\n", stderr));
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static void type_parse(const char *name, const char *str,
|
||||
struct type_expansion *type);
|
||||
|
||||
static int type_map_get(const char *name, struct type_expansion **res)
|
||||
{
|
||||
struct type_expansion type;
|
||||
const char *override;
|
||||
|
||||
if (!__type_map_get(name, res))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If die_map didn't contain a type, we might still have
|
||||
* a type_string kABI rule that defines it.
|
||||
*/
|
||||
if (stable && kabi_get_type_string(name, &override)) {
|
||||
type_expansion_init(&type);
|
||||
type_parse(name, override, &type);
|
||||
*res = type_map_add(name, &type);
|
||||
type_expansion_free(&type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void type_map_write(FILE *file)
|
||||
|
@ -267,15 +296,18 @@ static char *get_type_name(struct die *cache)
|
|||
return name;
|
||||
}
|
||||
|
||||
static void __calculate_version(struct version *version, struct list_head *list)
|
||||
static void __calculate_version(struct version *version,
|
||||
struct type_expansion *type)
|
||||
{
|
||||
struct type_list_entry *entry;
|
||||
struct type_expansion *e;
|
||||
|
||||
/* Calculate a CRC over an expanded type string */
|
||||
list_for_each_entry(entry, list, list) {
|
||||
list_for_each_entry(entry, &type->expanded, list) {
|
||||
if (is_type_prefix(entry->str)) {
|
||||
check(type_map_get(entry->str, &e));
|
||||
if (type_map_get(entry->str, &e))
|
||||
error("unknown type reference to '%s' when expanding '%s'",
|
||||
entry->str, type->name);
|
||||
|
||||
/*
|
||||
* It's sufficient to expand each type reference just
|
||||
|
@ -285,7 +317,7 @@ static void __calculate_version(struct version *version, struct list_head *list)
|
|||
version_add(version, entry->str);
|
||||
} else {
|
||||
cache_mark_expanded(&expansion_cache, e);
|
||||
__calculate_version(version, &e->expanded);
|
||||
__calculate_version(version, e);
|
||||
}
|
||||
} else {
|
||||
version_add(version, entry->str);
|
||||
|
@ -293,10 +325,11 @@ static void __calculate_version(struct version *version, struct list_head *list)
|
|||
}
|
||||
}
|
||||
|
||||
static void calculate_version(struct version *version, struct list_head *list)
|
||||
static void calculate_version(struct version *version,
|
||||
struct type_expansion *type)
|
||||
{
|
||||
version_init(version);
|
||||
__calculate_version(version, list);
|
||||
__calculate_version(version, type);
|
||||
cache_free(&expansion_cache);
|
||||
}
|
||||
|
||||
|
@ -372,9 +405,80 @@ static void type_expand(struct die *cache, struct type_expansion *type,
|
|||
cache_free(&expansion_cache);
|
||||
}
|
||||
|
||||
static void type_parse(const char *name, const char *str,
|
||||
struct type_expansion *type)
|
||||
{
|
||||
char *fragment;
|
||||
size_t start = 0;
|
||||
size_t end;
|
||||
size_t pos;
|
||||
|
||||
if (!*str)
|
||||
error("empty type string override for '%s'", name);
|
||||
|
||||
type_expansion_init(type);
|
||||
|
||||
for (pos = 0; str[pos]; ++pos) {
|
||||
bool empty;
|
||||
char marker = ' ';
|
||||
|
||||
if (!is_type_prefix(&str[pos]))
|
||||
continue;
|
||||
|
||||
end = pos + 2;
|
||||
|
||||
/*
|
||||
* Find the end of the type reference. If the type name contains
|
||||
* spaces, it must be in single quotes.
|
||||
*/
|
||||
if (str[end] == '\'') {
|
||||
marker = '\'';
|
||||
++end;
|
||||
}
|
||||
while (str[end] && str[end] != marker)
|
||||
++end;
|
||||
|
||||
/* Check that we have a non-empty type name */
|
||||
if (marker == '\'') {
|
||||
if (str[end] != marker)
|
||||
error("incomplete %c# type reference for '%s' (string : '%s')",
|
||||
str[pos], name, str);
|
||||
empty = end == pos + 3;
|
||||
++end;
|
||||
} else {
|
||||
empty = end == pos + 2;
|
||||
}
|
||||
if (empty)
|
||||
error("empty %c# type name for '%s' (string: '%s')",
|
||||
str[pos], name, str);
|
||||
|
||||
/* Append the part of the string before the type reference */
|
||||
if (pos > start) {
|
||||
fragment = xstrndup(&str[start], pos - start);
|
||||
type_expansion_append(type, fragment, fragment);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append the type reference -- note that if the reference
|
||||
* is invalid, i.e. points to a non-existent type, we will
|
||||
* print out an error when calculating versions.
|
||||
*/
|
||||
fragment = xstrndup(&str[pos], end - pos);
|
||||
type_expansion_append(type, fragment, fragment);
|
||||
|
||||
start = end;
|
||||
pos = end - 1;
|
||||
}
|
||||
|
||||
/* Append the rest of the type string, if there's any left */
|
||||
if (str[start])
|
||||
type_expansion_append(type, &str[start], NULL);
|
||||
}
|
||||
|
||||
static void expand_type(struct die *cache, void *arg)
|
||||
{
|
||||
struct type_expansion type;
|
||||
const char *override;
|
||||
char *name;
|
||||
|
||||
if (cache->mapped)
|
||||
|
@ -399,9 +503,13 @@ static void expand_type(struct die *cache, void *arg)
|
|||
return;
|
||||
|
||||
debug("%s", name);
|
||||
type_expand(cache, &type, true);
|
||||
type_map_add(name, &type);
|
||||
|
||||
if (stable && kabi_get_type_string(name, &override))
|
||||
type_parse(name, override, &type);
|
||||
else
|
||||
type_expand(cache, &type, true);
|
||||
|
||||
type_map_add(name, &type);
|
||||
type_expansion_free(&type);
|
||||
free(name);
|
||||
}
|
||||
|
@ -410,6 +518,7 @@ static void expand_symbol(struct symbol *sym, void *arg)
|
|||
{
|
||||
struct type_expansion type;
|
||||
struct version version;
|
||||
const char *override;
|
||||
struct die *cache;
|
||||
|
||||
/*
|
||||
|
@ -423,11 +532,14 @@ static void expand_symbol(struct symbol *sym, void *arg)
|
|||
if (__die_map_get(sym->die_addr, DIE_SYMBOL, &cache))
|
||||
return; /* We'll warn about missing CRCs later. */
|
||||
|
||||
type_expand(cache, &type, false);
|
||||
if (stable && kabi_get_type_string(sym->name, &override))
|
||||
type_parse(sym->name, override, &type);
|
||||
else
|
||||
type_expand(cache, &type, false);
|
||||
|
||||
/* If the symbol already has a version, don't calculate it again. */
|
||||
if (sym->state != SYMBOL_PROCESSED) {
|
||||
calculate_version(&version, &type.expanded);
|
||||
calculate_version(&version, &type);
|
||||
symbol_set_crc(sym, version.crc);
|
||||
debug("%s = %lx", sym->name, version.crc);
|
||||
|
||||
|
|
|
@ -181,13 +181,9 @@ static int is_unknown_symbol(struct symbol *sym)
|
|||
strcmp(defn->string, "{") == 0);
|
||||
}
|
||||
|
||||
static struct symbol *__add_symbol(const char *name, enum symbol_type type,
|
||||
struct string_list *defn, int is_extern,
|
||||
int is_reference)
|
||||
static struct string_list *process_enum(const char *name, enum symbol_type type,
|
||||
struct string_list *defn)
|
||||
{
|
||||
unsigned long h;
|
||||
struct symbol *sym;
|
||||
enum symbol_status status = STATUS_UNCHANGED;
|
||||
/* The parser adds symbols in the order their declaration completes,
|
||||
* so it is safe to store the value of the previous enum constant in
|
||||
* a static variable.
|
||||
|
@ -216,7 +212,7 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type,
|
|||
defn = mk_node(buf);
|
||||
}
|
||||
}
|
||||
} else if (type == SYM_ENUM) {
|
||||
} else {
|
||||
free_list(last_enum_expr, NULL);
|
||||
last_enum_expr = NULL;
|
||||
enum_counter = 0;
|
||||
|
@ -225,6 +221,23 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return defn;
|
||||
}
|
||||
|
||||
static struct symbol *__add_symbol(const char *name, enum symbol_type type,
|
||||
struct string_list *defn, int is_extern,
|
||||
int is_reference)
|
||||
{
|
||||
unsigned long h;
|
||||
struct symbol *sym;
|
||||
enum symbol_status status = STATUS_UNCHANGED;
|
||||
|
||||
if ((type == SYM_ENUM_CONST || type == SYM_ENUM) && !is_reference) {
|
||||
defn = process_enum(name, type, defn);
|
||||
if (defn == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
h = crc32(name);
|
||||
hash_for_each_possible(symbol_hashtable, sym, hnode, h) {
|
||||
if (map_to_ns(sym->type) != map_to_ns(type) ||
|
||||
|
|
|
@ -205,15 +205,26 @@ struct property {
|
|||
for (st = sym->prop; st; st = st->next) \
|
||||
if (st->text)
|
||||
|
||||
enum menu_type {
|
||||
M_CHOICE, // "choice"
|
||||
M_COMMENT, // "comment"
|
||||
M_IF, // "if"
|
||||
M_MENU, // "mainmenu", "menu", "menuconfig"
|
||||
M_NORMAL, // others, i.e., "config"
|
||||
};
|
||||
|
||||
/*
|
||||
* Represents a node in the menu tree, as seen in e.g. menuconfig (though used
|
||||
* for all front ends). Each symbol, menu, etc. defined in the Kconfig files
|
||||
* gets a node. A symbol defined in multiple locations gets one node at each
|
||||
* location.
|
||||
*
|
||||
* @type: type of the menu entry
|
||||
* @choice_members: list of choice members with priority.
|
||||
*/
|
||||
struct menu {
|
||||
enum menu_type type;
|
||||
|
||||
/* The next menu node at the same level */
|
||||
struct menu *next;
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ void _menu_init(void);
|
|||
void menu_warn(const struct menu *menu, const char *fmt, ...);
|
||||
struct menu *menu_add_menu(void);
|
||||
void menu_end_menu(void);
|
||||
void menu_add_entry(struct symbol *sym);
|
||||
void menu_add_entry(struct symbol *sym, enum menu_type type);
|
||||
void menu_add_dep(struct expr *dep);
|
||||
void menu_add_visibility(struct expr *dep);
|
||||
struct property *menu_add_prompt(enum prop_type type, const char *prompt,
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
static const char nohelp_text[] = "There is no help available for this option.";
|
||||
|
||||
struct menu rootmenu;
|
||||
struct menu rootmenu = { .type = M_MENU };
|
||||
static struct menu **last_entry_ptr;
|
||||
|
||||
/**
|
||||
|
@ -65,12 +65,13 @@ void _menu_init(void)
|
|||
last_entry_ptr = &rootmenu.list;
|
||||
}
|
||||
|
||||
void menu_add_entry(struct symbol *sym)
|
||||
void menu_add_entry(struct symbol *sym, enum menu_type type)
|
||||
{
|
||||
struct menu *menu;
|
||||
|
||||
menu = xmalloc(sizeof(*menu));
|
||||
memset(menu, 0, sizeof(*menu));
|
||||
menu->type = type;
|
||||
menu->sym = sym;
|
||||
menu->parent = current_menu;
|
||||
menu->filename = cur_filename;
|
||||
|
|
|
@ -139,7 +139,7 @@ stmt_list_in_choice:
|
|||
|
||||
config_entry_start: T_CONFIG nonconst_symbol T_EOL
|
||||
{
|
||||
menu_add_entry($2);
|
||||
menu_add_entry($2, M_NORMAL);
|
||||
printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name);
|
||||
};
|
||||
|
||||
|
@ -173,7 +173,7 @@ config_stmt: config_entry_start config_option_list
|
|||
|
||||
menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
|
||||
{
|
||||
menu_add_entry($2);
|
||||
menu_add_entry($2, M_MENU);
|
||||
printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name);
|
||||
};
|
||||
|
||||
|
@ -246,7 +246,7 @@ choice: T_CHOICE T_EOL
|
|||
{
|
||||
struct symbol *sym = sym_lookup(NULL, 0);
|
||||
|
||||
menu_add_entry(sym);
|
||||
menu_add_entry(sym, M_CHOICE);
|
||||
menu_set_type(S_BOOLEAN);
|
||||
INIT_LIST_HEAD(¤t_entry->choice_members);
|
||||
|
||||
|
@ -315,7 +315,7 @@ default:
|
|||
if_entry: T_IF expr T_EOL
|
||||
{
|
||||
printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno);
|
||||
menu_add_entry(NULL);
|
||||
menu_add_entry(NULL, M_IF);
|
||||
menu_add_dep($2);
|
||||
$$ = menu_add_menu();
|
||||
};
|
||||
|
@ -338,7 +338,7 @@ if_stmt_in_choice: if_entry stmt_list_in_choice if_end
|
|||
|
||||
menu: T_MENU T_WORD_QUOTE T_EOL
|
||||
{
|
||||
menu_add_entry(NULL);
|
||||
menu_add_entry(NULL, M_MENU);
|
||||
menu_add_prompt(P_MENU, $2, NULL);
|
||||
printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno);
|
||||
};
|
||||
|
@ -376,7 +376,7 @@ source_stmt: T_SOURCE T_WORD_QUOTE T_EOL
|
|||
|
||||
comment: T_COMMENT T_WORD_QUOTE T_EOL
|
||||
{
|
||||
menu_add_entry(NULL);
|
||||
menu_add_entry(NULL, M_COMMENT);
|
||||
menu_add_prompt(P_COMMENT, $2, NULL);
|
||||
printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno);
|
||||
};
|
||||
|
|
|
@ -3,17 +3,65 @@
|
|||
|
||||
set -e
|
||||
|
||||
# Detect files that are tracked but ignored by git. This is checked only when
|
||||
# ${KBUILD_EXTRA_WARN} contains 1, git is installed, and the source tree is
|
||||
# tracked by git.
|
||||
# Detect files that are tracked but ignored by git.
|
||||
check_tracked_ignored_files () {
|
||||
case "${KBUILD_EXTRA_WARN}" in
|
||||
*1*) ;;
|
||||
*) return;;
|
||||
esac
|
||||
|
||||
git -C ${srctree:-.} ls-files -i -c --exclude-per-directory=.gitignore 2>/dev/null |
|
||||
git -C "${srctree:-.}" ls-files -i -c --exclude-per-directory=.gitignore 2>/dev/null |
|
||||
sed 's/$/: warning: ignored by one of the .gitignore files/' >&2
|
||||
}
|
||||
|
||||
# Check for missing #include <linux/export.h>
|
||||
#
|
||||
# The rule for including <linux/export.h> is very simple:
|
||||
# Include <linux/export.h> only when you use EXPORT_SYMBOL(). That's it.
|
||||
#
|
||||
# However, some headers include <linux/export.h> even though they are completely
|
||||
# unrelated to EXPORT_SYMBOL().
|
||||
#
|
||||
# One example is include/linux/module.h. Please note <linux/module.h> and
|
||||
# <linux/export.h> are orthogonal. <linux/module.h> should be included by files
|
||||
# that can be compiled as modules. In other words, <linux/module.h> should be
|
||||
# included by EXPORT_SYMBOL consumers. In contrast, <linux/export.h> should be
|
||||
# included from EXPORT_SYMBOL providers, which may or may not be modular.
|
||||
# Hence, include/linux/module.h should *not* include <linux/export.h>.
|
||||
#
|
||||
# Another example is include/linux/linkage.h, which is completely unrelated to
|
||||
# EXPORT_SYMBOL(). Worse, it is included by most C files, which means, most C
|
||||
# files end up including <linux/export.h>, even though only some of them
|
||||
# actually export symbols. Hence, include/linux/linkage.h should *not* include
|
||||
# <linux/export.h>.
|
||||
#
|
||||
# Before fixing such headers, we must ensure that C files using EXPORT_SYMBOL()
|
||||
# include <linux/export.h> directly, since many C files currently rely on
|
||||
# <linux/export.h> being included indirectly (likely, via <linux/linkage> etc.).
|
||||
#
|
||||
# Therefore, this check.
|
||||
#
|
||||
# The problem is simple - the warned files use EXPORT_SYMBOL(), but do not
|
||||
# include <linux/export.h>. Please add #include <linux/export.h> to them.
|
||||
#
|
||||
# If the included headers are sorted alphabetically, please insert
|
||||
# <linux/export.h> in the appropriate position to maintain the sort order.
|
||||
# For this reason, this script only checks missing <linux/export.h>, but
|
||||
# does not automatically fix it.
|
||||
check_missing_include_linux_export_h () {
|
||||
|
||||
git -C "${srctree:-.}" grep --files-with-matches -E 'EXPORT_SYMBOL((_NS)?(_GPL)?|_GPL_FOR_MODULES)\(.*\)' \
|
||||
-- '*.[ch]' :^tools/ :^include/linux/export.h |
|
||||
xargs -r git -C "${srctree:-.}" grep --files-without-match '#include[[:space:]]*<linux/export\.h>' |
|
||||
xargs -r printf "%s: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing\n" >&2
|
||||
}
|
||||
|
||||
# If you do not use EXPORT_SYMBOL(), please do not include <linux/export.h>.
|
||||
# Currently, this is checked for *.c files, but not for *.h files, because some
|
||||
# *.c files rely on <linux/export.h> being included indirectly.
|
||||
check_unnecessary_include_linux_export_h () {
|
||||
|
||||
git -C "${srctree:-.}" grep --files-with-matches '#include[[:space:]]*<linux/export\.h>' \
|
||||
-- '*.[c]' :^tools/ |
|
||||
xargs -r git -C "${srctree:-.}" grep --files-without-match -E 'EXPORT_SYMBOL((_NS)?(_GPL)?|_GPL_FOR_MODULES)\(.*\)' |
|
||||
xargs -r printf "%s: warning: EXPORT_SYMBOL() is not used, but #include <linux/export.h> is present\n" >&2
|
||||
}
|
||||
|
||||
check_tracked_ignored_files
|
||||
check_missing_include_linux_export_h
|
||||
check_unnecessary_include_linux_export_h
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include "modpost.h"
|
||||
#include "../../include/linux/license.h"
|
||||
|
||||
#define MODULE_NS_PREFIX "module:"
|
||||
|
||||
static bool module_enabled;
|
||||
/* Are we using CONFIG_MODVERSIONS? */
|
||||
static bool modversions;
|
||||
|
@ -1595,11 +1597,14 @@ static void read_symbols(const char *modname)
|
|||
license = get_next_modinfo(&info, "license", license);
|
||||
}
|
||||
|
||||
namespace = get_modinfo(&info, "import_ns");
|
||||
while (namespace) {
|
||||
for (namespace = get_modinfo(&info, "import_ns");
|
||||
namespace;
|
||||
namespace = get_next_modinfo(&info, "import_ns", namespace)) {
|
||||
if (strstarts(namespace, MODULE_NS_PREFIX))
|
||||
error("%s: explicitly importing namespace \"%s\" is not allowed.\n",
|
||||
mod->name, namespace);
|
||||
|
||||
add_namespace(&mod->imported_namespaces, namespace);
|
||||
namespace = get_next_modinfo(&info, "import_ns",
|
||||
namespace);
|
||||
}
|
||||
|
||||
if (!get_modinfo(&info, "description"))
|
||||
|
@ -1684,6 +1689,46 @@ void buf_write(struct buffer *buf, const char *s, int len)
|
|||
buf->pos += len;
|
||||
}
|
||||
|
||||
/**
|
||||
* verify_module_namespace() - does @modname have access to this symbol's @namespace
|
||||
* @namespace: export symbol namespace
|
||||
* @modname: module name
|
||||
*
|
||||
* If @namespace is prefixed with "module:" to indicate it is a module namespace
|
||||
* then test if @modname matches any of the comma separated patterns.
|
||||
*
|
||||
* The patterns only support tail-glob.
|
||||
*/
|
||||
static bool verify_module_namespace(const char *namespace, const char *modname)
|
||||
{
|
||||
size_t len, modlen = strlen(modname);
|
||||
const char *prefix = "module:";
|
||||
const char *sep;
|
||||
bool glob;
|
||||
|
||||
if (!strstarts(namespace, prefix))
|
||||
return false;
|
||||
|
||||
for (namespace += strlen(prefix); *namespace; namespace = sep) {
|
||||
sep = strchrnul(namespace, ',');
|
||||
len = sep - namespace;
|
||||
|
||||
glob = false;
|
||||
if (sep[-1] == '*') {
|
||||
len--;
|
||||
glob = true;
|
||||
}
|
||||
|
||||
if (*sep)
|
||||
sep++;
|
||||
|
||||
if (strncmp(namespace, modname, len) == 0 && (glob || len == modlen))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void check_exports(struct module *mod)
|
||||
{
|
||||
struct symbol *s, *exp;
|
||||
|
@ -1711,7 +1756,8 @@ static void check_exports(struct module *mod)
|
|||
|
||||
basename = get_basename(mod->name);
|
||||
|
||||
if (!contains_namespace(&mod->imported_namespaces, exp->namespace)) {
|
||||
if (!verify_module_namespace(exp->namespace, basename) &&
|
||||
!contains_namespace(&mod->imported_namespaces, exp->namespace)) {
|
||||
modpost_log(!allow_missing_ns_imports,
|
||||
"module %s uses symbol %s from namespace %s, but does not import it.\n",
|
||||
basename, exp->name, exp->namespace);
|
||||
|
|
|
@ -344,7 +344,7 @@ case "$1" in
|
|||
|
||||
"tags")
|
||||
rm -f tags
|
||||
xtags ctags
|
||||
xtags ${CTAGS:-ctags}
|
||||
remove_structs=y
|
||||
;;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user