mirror of
https://github.com/torvalds/linux.git
synced 2026-10-22 12:52:02 +02:00
Kbuild / Kconfig updates for 7.4
Kbuild:
- Suppress compiler flags in debug info for external module builds
- Use '-fmacro-prefix-map' in more places in the build
- Merge initial set of changes from Lorenzo's speed up series, along
with some fixes found through testing
- Avoid allocating .modinfo in vmlinux
- Speed up kallsyms by indexing symbols by token and outputting binary
data to disk directly then including in assembly via .incbin
- Don't sort $(NM) output when unnecessary
- Only emit relocations on the final vmlinx link
- Reimplement mksysmap in C
- Move many cc-option and ld-option calls into the Kconfig stage to
cache their results
- Use pigz for gzip compression when available
- Move gen_init_cpio and gen_initramfs.sh from usr/ to scripts/
- Add a TOML configuration to scripts/container and update documentation
accordingly
- Add a generic, opt-in mechanism for checking that headers can compile
standalone
- Update machine function splitting argument for LLVM 24 rename in
AutoFDO build
- Miscellaneous minor clean ups, fixes, and hardening, mostly
found/fixed via LLMs
Kconfig:
- Turn recursive ranges into an error
- Fix savedefconfig for defaults that were adjusted for being out of
range and revert a previously applied workaround
- Improvements and hardening around integer and hexadecimal values
- Emit a warning when selecting or implying a choice symbol, which has no
effect
- Emit a warning when KCONFIG_PROBABILITY is malformed
- Introduce def_string / def_int / def_hex to mirror the existing
def_bool / def_tristate to succinctly set a value and type at the same
time.
- Add cc-option-str and ld-option-str macros to act like Kbuild's
cc-option and ld-option, returning the string when the option is
supported, allowing many checks to be moved into Kconfig
- Minor usability improvements to Kconfig tests
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQR74yXHMTGczQHYypIdayaRccAalgUCatRBoQAKCRAdayaRccAa
lg+JAQCyjmh+xC2lLSHFGB9qTzqYpVoIT0Z9/6EGx09nYgMr5AEAmzg/+dor5u+6
vjklzsGs95G01yetVE5ifNNsLvVxTAo=
=HbPA
-----END PGP SIGNATURE-----
Merge tag 'kbuild-7.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux
Pull Kbuild / Kconfig updates from Nathan Chancellor:
"Kbuild:
- Suppress compiler flags in debug info for external module builds
- Use '-fmacro-prefix-map' in more places in the build
- Merge initial set of changes from Lorenzo's speed up series, along
with some fixes found through testing:
- Avoid allocating .modinfo in vmlinux
- Speed up kallsyms by indexing symbols by token and outputting
binary data to disk directly then including in assembly via
.incbin
- Don't sort $(NM) output when unnecessary
- Only emit relocations on the final vmlinx link
- Reimplement mksysmap in C
- Move many cc-option and ld-option calls into the Kconfig stage to
cache their results
- Use pigz for gzip compression when available
- Move gen_init_cpio and gen_initramfs.sh from usr/ to scripts/
- Add a TOML configuration to scripts/container and update
documentation accordingly
- Add a generic, opt-in mechanism for checking that headers can
compile standalone
- Update machine function splitting argument for LLVM 24 rename in
AutoFDO build
- Miscellaneous minor clean ups, fixes, and hardening, mostly
found/fixed via LLMs
Kconfig:
- Turn recursive ranges into an error
- Fix savedefconfig for defaults that were adjusted for being out of
range and revert a previously applied workaround
- Improvements and hardening around integer and hexadecimal values
- Emit a warning when selecting or implying a choice symbol, which
has no effect
- Emit a warning when KCONFIG_PROBABILITY is malformed
- Introduce def_string / def_int / def_hex to mirror the existing
def_bool / def_tristate to succinctly set a value and type at the
same time.
- Add cc-option-str and ld-option-str macros to act like Kbuild's
cc-option and ld-option, returning the string when the option is
supported, allowing many checks to be moved into Kconfig
- Minor usability improvements to Kconfig tests"
* tag 'kbuild-7.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux: (59 commits)
kbuild: AutoFDO: Update split machine function argument for upstream rename
kbuild: Mark the initcall ordering recipe as recursive
kbuild: Mark the gzip recipes as recursive
localmodconfig: Explicitly report boolean configs during integrity check
scripts/make_fit: Ignore schema checks when decomposing DTBs
clang-tools: Import os for broken pipe handling
kconfig: use the value argument in sym_get_near_range_bound()
kconfig: fix infinite loop in conf_choice() when no choice value is visible
kconfig: cleanup stale comment about 'keys' array
kconfig: Improve ergonomics around disabling warnings with cc-option
scripts/Kconfig.toolchain: Drop compiler symbols from dependencies
checkkconfigsymbols.py: Parse Git status output line by line
gen_init_cpio: stop parsing on lines with a missing argument list
.gitignore: drop Module.markers
.gitignore: ignore pacman package signatures
kbuild: add header check facility as a manually run static analyzer
Documentation: dev-tools: refer to user ID rather than id
Documentation: dev-tools: update container.rst with config file
scripts: add TOML config to container tool
kconfig: tests: {old,save}defconfig: Forward dynamic keyword arguments
...
This commit is contained in:
commit
bb29b957ea
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -28,6 +28,7 @@
|
|||
*.gcno
|
||||
*.gcda
|
||||
*.gz
|
||||
*.header-check
|
||||
*.i
|
||||
*.ko
|
||||
*.lex.c
|
||||
|
|
@ -75,7 +76,6 @@ modules.order
|
|||
/vmlinux-gdb.py
|
||||
/vmlinuz
|
||||
/System.map
|
||||
/Module.markers
|
||||
/modules.builtin
|
||||
/modules.builtin.modinfo
|
||||
/modules.builtin.ranges
|
||||
|
|
@ -104,6 +104,7 @@ modules.order
|
|||
#
|
||||
# pacman files (make pacman-pkg)
|
||||
#
|
||||
/*.pkg.*.sig
|
||||
/PKGBUILD
|
||||
/pacman/
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ various platforms, for example when a test bot has reported an issue which
|
|||
requires a specific version of a compiler or an external test suite. While
|
||||
this can already be done by users who are familiar with containers, having a
|
||||
dedicated tool in the kernel tree lowers the barrier to entry by solving common
|
||||
problems once and for all (e.g. user id management). It also makes it easier
|
||||
problems once and for all (e.g. user ID management). It also makes it easier
|
||||
to share an exact command line leading to a particular result. The main use
|
||||
case is likely to be kernel builds but virtually anything can be run: KUnit,
|
||||
checkpatch etc. provided a suitable image is available.
|
||||
|
|
@ -26,18 +26,28 @@ Command line syntax::
|
|||
|
||||
Available options:
|
||||
|
||||
``-c, --config-file CONFIG_FILE``
|
||||
|
||||
Path to the config file. If not specified, the default is to look for
|
||||
``.container.toml`` in the current working directory.
|
||||
|
||||
``-e, --env-file ENV_FILE``
|
||||
|
||||
Path to an environment file to load in the container.
|
||||
|
||||
``-g, --gid GID``
|
||||
|
||||
Group id to use inside the container.
|
||||
Group ID to use inside the container.
|
||||
|
||||
``-i, --image IMAGE``
|
||||
|
||||
Container image name (required).
|
||||
|
||||
``-p, --config-profile CONFIG_PROFILE``
|
||||
|
||||
Profile section to use in the config file. This will override any values
|
||||
defined in the ``DEFAULT`` section.
|
||||
|
||||
``-r, --runtime RUNTIME``
|
||||
|
||||
Container runtime name. Supported runtimes: ``podman``, ``docker``.
|
||||
|
|
@ -51,10 +61,10 @@ Available options:
|
|||
|
||||
``-u, --uid UID``
|
||||
|
||||
User id to use inside the container.
|
||||
User ID to use inside the container.
|
||||
|
||||
If the ``-g`` option is not specified, the user id will also be used for
|
||||
the group id.
|
||||
If the ``-g`` option is not specified and no group ID is defined in the
|
||||
configuration file, the user ID will also be set as the group ID.
|
||||
|
||||
``-v, --verbose``
|
||||
|
||||
|
|
@ -71,7 +81,7 @@ Usage
|
|||
It's entirely up to the user to choose which image to use and the ``CMD``
|
||||
arguments are passed directly as an arbitrary command line to run in the
|
||||
container. The tool will take care of mounting the source tree as the current
|
||||
working directory and adjust the user and group id as needed.
|
||||
working directory and adjust the user and group ID as needed.
|
||||
|
||||
The container image which would typically include a compiler toolchain is
|
||||
provided by the user and selected via the ``-i`` option. The container runtime
|
||||
|
|
@ -86,9 +96,13 @@ container with SIGINT (Ctrl-C). To run commands interactively with a TTY, the
|
|||
shell directly rather than the parent ``container`` process. To exit an
|
||||
interactive shell, use Ctrl-D or ``exit``.
|
||||
|
||||
A :ref:`configuration file<config_file>` may be used to facilitate running
|
||||
containers for various use cases. It also removes the burden of repeatedly
|
||||
providing the same options on the command line.
|
||||
|
||||
.. note::
|
||||
|
||||
The only host requirement aside from a container runtime is Python 3.10 or
|
||||
The only host requirement aside from a container runtime is Python 3.11 or
|
||||
later.
|
||||
|
||||
.. note::
|
||||
|
|
@ -131,26 +145,31 @@ User IDs
|
|||
|
||||
This is an area where the behaviour will vary slightly depending on the
|
||||
container runtime. The goal is to run commands as the user invoking the tool.
|
||||
With Podman, a namespace is created to map the current user id to a different
|
||||
With Podman, a namespace is created to map the current user ID to a different
|
||||
one in the container (1000 by default). With Docker, while this is also
|
||||
possible with recent versions it requires a special feature to be enabled in
|
||||
the daemon so it's not used here for simplicity. Instead, the container is run
|
||||
with the current user id directly. In both cases, this will provide the same
|
||||
with the current user ID directly. In both cases, this will provide the same
|
||||
file permissions for the kernel source tree mounted as a volume. The only
|
||||
difference is that when using Docker without a namespace, the user id may not
|
||||
difference is that when using Docker without a namespace, the user ID may not
|
||||
be the same as the default one set in the image.
|
||||
|
||||
Say, we're using an image which sets up a default user with id 1000 and the
|
||||
current user calling the ``container`` tool has id 1234. The kernel source
|
||||
Say, we're using an image which sets up a default user with ID 1000 and the
|
||||
current user calling the ``container`` tool has ID 1234. The kernel source
|
||||
tree was checked out by this same user so the files belong to user 1234. With
|
||||
Podman, the container will be running as user id 1000 with a mapping to id 1234
|
||||
so that the files from the mounted volume appear to belong to id 1000 inside
|
||||
Podman, the container will be running as user ID 1000 with a mapping to ID 1234
|
||||
so that the files from the mounted volume appear to belong to ID 1000 inside
|
||||
the container. With Docker and no namespace, the container will be running
|
||||
with user id 1234 which can access the files in the volume but not in the user
|
||||
with user ID 1234 which can access the files in the volume but not in the user
|
||||
1000 home directory. This shouldn't be an issue when running commands only in
|
||||
the kernel tree but it is worth highlighting here as it might matter for
|
||||
special corner cases.
|
||||
|
||||
Group IDs (GID) follow the same logic as user IDs (UID). When specifying a UID
|
||||
via the ``--uid`` option or in the configuration file, the GID takes the same
|
||||
value as the UID by default. A specific GID can be set via ``--gid`` or the
|
||||
configuration file.
|
||||
|
||||
.. note::
|
||||
|
||||
Podman's `Docker compatibility
|
||||
|
|
@ -225,3 +244,72 @@ To build the HTML documentation, which requires the ``kdocs`` image built with
|
|||
``make PREFIX=kernel.org/ extra`` as it's not a compiler toolchain::
|
||||
|
||||
scripts/container -i kernel.org/kdocs make htmldocs
|
||||
|
||||
.. _config_file:
|
||||
|
||||
Configuration File
|
||||
==================
|
||||
|
||||
By default, the tool will look for a configuration file named
|
||||
``.container.toml`` in the current working directory. If not found, it will be
|
||||
silently ignored as it's not required. Alternatively, any other path can be
|
||||
specified with the ``-c`` option in which case the file needs to be present or
|
||||
an error will be raised.
|
||||
|
||||
Its data follows the standard TOML format and is made up of different sections
|
||||
with ``DEFAULT`` as the default one. Other sections may be used to define
|
||||
alternative profiles under arbitrary names which can be selected by the ``-p``
|
||||
option. Command line options take precedence over configuration values, and
|
||||
profile sections take precedence over the default one.
|
||||
|
||||
Supported options in each section are:
|
||||
|
||||
``env_file``
|
||||
|
||||
Path to an environment file to load in the container, equivalent to the
|
||||
``-e`` command line option.
|
||||
|
||||
``image``
|
||||
|
||||
Name of the container image to use, equivalent to the ``-i`` command line
|
||||
option.
|
||||
|
||||
``runtime``
|
||||
|
||||
Name of the container runtime, equivalent to the ``-r`` command line option.
|
||||
|
||||
``uid`` / ``gid`` (integers)
|
||||
|
||||
User and group ID numbers to use inside the container, equivalents to the
|
||||
``-u`` and ``-g`` command line options respectively.
|
||||
|
||||
|
||||
Here's a sample configuration with an extra ``clang`` profile::
|
||||
|
||||
[DEFAULT]
|
||||
runtime = "podman"
|
||||
image = "tuxmake/korg-gcc"
|
||||
|
||||
[clang]
|
||||
image = "tuxmake/korg-clang"
|
||||
env_file = ".clang.env"
|
||||
|
||||
It mentions a ``.clang.env`` file which simply contains this flag::
|
||||
|
||||
LLVM=1
|
||||
|
||||
Let's take a look again at this example mentioned earlier::
|
||||
|
||||
scripts/container -i docker.io/tuxmake/korg-clang -- make LLVM=1 defconfig
|
||||
|
||||
Using the configuration file, it can now be simplified into this::
|
||||
|
||||
scripts/container -p clang -- make defconfig
|
||||
|
||||
Then to override the default user, the ``-u`` option can still be used::
|
||||
|
||||
scripts/container -p clang -u0 -- make defconfig
|
||||
|
||||
This also illustrates how values take precedence over each other: the runtime
|
||||
is loaded from the ``DEFAULT`` section, the image from the ``clang`` section
|
||||
and the user ID from the command line ``-u`` option.
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@ user root (0). INITRAMFS_ROOT_GID can be set to a group ID that needs
|
|||
to be mapped to group root (0).
|
||||
|
||||
A source file must be directives in the format required by the
|
||||
usr/gen_init_cpio utility (run 'usr/gen_init_cpio -h' to get the
|
||||
scripts/gen_init_cpio utility (run 'scripts/gen_init_cpio -h' to get the
|
||||
file format). The directives in the file will be passed directly to
|
||||
usr/gen_init_cpio.
|
||||
scripts/gen_init_cpio.
|
||||
|
||||
When a combination of directories and files are specified then the
|
||||
initramfs image will be an aggregate of all of them. In this way a user
|
||||
|
|
@ -69,17 +69,17 @@ early userspace image can be built by an unprivileged user.
|
|||
|
||||
As a technical note, when directories and files are specified, the
|
||||
entire CONFIG_INITRAMFS_SOURCE is passed to
|
||||
usr/gen_initramfs.sh. This means that CONFIG_INITRAMFS_SOURCE
|
||||
scripts/gen_initramfs.sh. This means that CONFIG_INITRAMFS_SOURCE
|
||||
can really be interpreted as any legal argument to
|
||||
gen_initramfs.sh. If a directory is specified as an argument then
|
||||
the contents are scanned, uid/gid translation is performed, and
|
||||
usr/gen_init_cpio file directives are output. If a file is
|
||||
specified as an argument to usr/gen_initramfs.sh then the
|
||||
scripts/gen_init_cpio file directives are output. If a file is
|
||||
specified as an argument to scripts/gen_initramfs.sh then the
|
||||
contents of the file are simply copied to the output. All of the output
|
||||
directives from directory scanning and file contents copying are
|
||||
processed by usr/gen_init_cpio.
|
||||
processed by scripts/gen_init_cpio.
|
||||
|
||||
See also 'usr/gen_initramfs.sh -h'.
|
||||
See also 'scripts/gen_initramfs.sh -h'.
|
||||
|
||||
Where's this all leading?
|
||||
=========================
|
||||
|
|
@ -142,7 +142,7 @@ b) some device and filesystem drivers built as modules and stored in an
|
|||
|
||||
c) using initramfs. The call to prepare_namespace() must be skipped.
|
||||
This means that a binary must do all the work. Said binary can be stored
|
||||
into initramfs either via modifying usr/gen_init_cpio.c or via the new
|
||||
into initramfs either via modifying scripts/gen_init_cpio.c or via the new
|
||||
initrd format, an cpio archive. It must be called "/init". This binary
|
||||
is responsible to do all the things prepare_namespace() would do.
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ specification such as the following example::
|
|||
dir /mnt 755 0 0
|
||||
file /init initramfs/init.sh 755 0 0
|
||||
|
||||
Run "usr/gen_init_cpio" (after the kernel build) to get a usage message
|
||||
Run "scripts/gen_init_cpio" (after the kernel build) to get a usage message
|
||||
documenting the above file format.
|
||||
|
||||
One advantage of the configuration file is that root access is not required to
|
||||
|
|
@ -167,9 +167,9 @@ Documentation/driver-api/early-userspace/early_userspace_support.rst for more de
|
|||
The kernel does not depend on external cpio tools. If you specify a
|
||||
directory instead of a configuration file, the kernel's build infrastructure
|
||||
creates a configuration file from that directory (usr/Makefile calls
|
||||
usr/gen_initramfs.sh), and proceeds to package up that directory
|
||||
using the config file (by feeding it to usr/gen_init_cpio, which is created
|
||||
from usr/gen_init_cpio.c). The kernel's build-time cpio creation code is
|
||||
scripts/gen_initramfs.sh), and proceeds to package up that directory
|
||||
using the config file (by feeding it to scripts/gen_init_cpio, which is created
|
||||
from scripts/gen_init_cpio.c). The kernel's build-time cpio creation code is
|
||||
entirely self-contained, and the kernel's boot-time extractor is also
|
||||
(obviously) self-contained.
|
||||
|
||||
|
|
@ -313,7 +313,7 @@ the above threads) is:
|
|||
2) The cpio archive format chosen by the kernel is simpler and cleaner (and
|
||||
thus easier to create and parse) than any of the (literally dozens of)
|
||||
various tar archive formats. The complete initramfs archive format is
|
||||
explained in buffer-format.rst, created in usr/gen_init_cpio.c, and
|
||||
explained in buffer-format.rst, created in scripts/gen_init_cpio.c, and
|
||||
extracted in init/initramfs.c. All three together come to less than 26k
|
||||
total of human-readable text.
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,23 @@ HOSTLDLIBS
|
|||
----------
|
||||
Additional libraries to link against when building host programs.
|
||||
|
||||
KGZIP
|
||||
-----
|
||||
The gzip program used for compressed modules, packaging and the embedded
|
||||
kernel configuration. Defaults to gzip.
|
||||
|
||||
KPGZIP
|
||||
------
|
||||
The gzip program used for the compressed kernel image. Defaults to pigz (a
|
||||
parallel implementation of gzip), run under scripts/jobserver-exec so that it
|
||||
uses the job slots make has free, if pigz is installed, otherwise to
|
||||
``KGZIP``. Set ``KPGZIP=`` on the make command line to use another program.
|
||||
|
||||
KBZIP2, KLZOP, LZMA, LZ4, XZ, ZSTD
|
||||
----------------------------------
|
||||
The compressor programs for the other formats. Each defaults to the program
|
||||
of the same name.
|
||||
|
||||
.. _userkbuildflags:
|
||||
|
||||
USERCFLAGS
|
||||
|
|
|
|||
|
|
@ -113,11 +113,22 @@ applicable everywhere (see syntax).
|
|||
|
||||
- type definition + default value::
|
||||
|
||||
"def_bool"/"def_tristate" <expr> ["if" <expr>]
|
||||
"def_bool" <expr> ["if" <expr>]
|
||||
"def_tristate" <expr> ["if" <expr>]
|
||||
"def_string" <expr> ["if" <expr>]
|
||||
"def_int" <expr> ["if" <expr>]
|
||||
"def_hex" <expr> ["if" <expr>]
|
||||
|
||||
This is a shorthand notation for a type definition plus a value.
|
||||
Optionally dependencies for this default value can be added with "if".
|
||||
|
||||
The shorthand supplies the type once, and is otherwise an ordinary
|
||||
default: it is the first entry of the list described above, so any
|
||||
further "default" entries still apply when its "if" is not met. Since
|
||||
that leaves the type definition inside one arm of a list, spelling the
|
||||
type out on its own line reads better for a symbol with several
|
||||
defaults.
|
||||
|
||||
- dependencies: "depends on" <expr> ["if" <expr>]
|
||||
|
||||
This defines a dependency for this menu entry. If multiple
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ not work::
|
|||
$(MY_TYPE) "foo"
|
||||
default y
|
||||
|
||||
Obviously from the design, $(shell command) is expanded in the textual
|
||||
Obviously from the design, $(shell,command) is expanded in the textual
|
||||
substitution phase. You cannot pass symbols to the 'shell' function.
|
||||
|
||||
The following does not work as expected::
|
||||
|
|
@ -236,12 +236,12 @@ The following does not work as expected::
|
|||
default "-mlittle-endian" if CPU_LITTLE_ENDIAN
|
||||
|
||||
config CC_HAS_ENDIAN_FLAG
|
||||
def_bool $(shell $(srctree)/scripts/gcc-check-flag ENDIAN_FLAG)
|
||||
def_bool $(shell,$(srctree)/scripts/gcc-check-flag ENDIAN_FLAG)
|
||||
|
||||
Instead, you can do like follows so that any function call is statically
|
||||
expanded::
|
||||
|
||||
config CC_HAS_ENDIAN_FLAG
|
||||
bool
|
||||
default $(shell $(srctree)/scripts/gcc-check-flag -mbig-endian) if CPU_BIG_ENDIAN
|
||||
default $(shell $(srctree)/scripts/gcc-check-flag -mlittle-endian) if CPU_LITTLE_ENDIAN
|
||||
default $(shell,$(srctree)/scripts/gcc-check-flag -mbig-endian) if CPU_BIG_ENDIAN
|
||||
default $(shell,$(srctree)/scripts/gcc-check-flag -mlittle-endian) if CPU_LITTLE_ENDIAN
|
||||
|
|
|
|||
|
|
@ -1452,13 +1452,16 @@ objcopy
|
|||
OBJCOPYFLAGS_$@ may be used to set additional options.
|
||||
|
||||
gzip
|
||||
Compress target. Use maximum compression to compress target.
|
||||
Compress target. Use maximum compression to compress target. Prefix the
|
||||
recipe line with '+' so that GNU Make passes it the jobserver, which
|
||||
scripts/jobserver-exec needs to run pigz (if available) on the free job
|
||||
slots.
|
||||
|
||||
Example::
|
||||
|
||||
#arch/x86/boot/compressed/Makefile
|
||||
$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
dtc
|
||||
Create flattened device tree blob object suitable for linking
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ nfs-utils 1.0.5 showmount --version
|
|||
openssl & libcrypto 1.0.0 openssl version
|
||||
pahole 1.26 pahole --version
|
||||
pcmciautils 004 pccardctl -V
|
||||
pigz (optional) 2.4 pigz --version
|
||||
PPP 2.4.0 pppd --version
|
||||
procps 3.2.0 ps --version
|
||||
Python 3.9.x python3 --version
|
||||
|
|
@ -206,6 +207,13 @@ GNU AWK
|
|||
GNU AWK is needed if you want kernel builds to generate address range data for
|
||||
builtin modules (CONFIG_BUILTIN_MODULE_RANGES).
|
||||
|
||||
pigz (optional)
|
||||
---------------
|
||||
|
||||
pigz is a parallel implementation of gzip. If it is installed the compressed
|
||||
kernel image is produced with it rather than with gzip, see ``KPGZIP`` in
|
||||
Documentation/kbuild/kbuild.rst.
|
||||
|
||||
System utilities
|
||||
****************
|
||||
|
||||
|
|
|
|||
|
|
@ -14092,6 +14092,7 @@ Q: https://patchwork.kernel.org/project/linux-kbuild/list/
|
|||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git
|
||||
F: Documentation/kbuild/kconfig*
|
||||
F: scripts/Kconfig.include
|
||||
F: scripts/Kconfig.toolchain
|
||||
F: scripts/kconfig/
|
||||
|
||||
KCORE
|
||||
|
|
@ -14173,6 +14174,7 @@ F: scripts/basic/
|
|||
F: scripts/clang-tools/
|
||||
F: scripts/container
|
||||
F: scripts/dummy-tools/
|
||||
F: scripts/gen_init*
|
||||
F: scripts/include/
|
||||
F: scripts/install.sh
|
||||
F: scripts/mk*
|
||||
|
|
|
|||
76
Makefile
76
Makefile
|
|
@ -298,10 +298,11 @@ no-dot-config-targets := $(clean-targets) \
|
|||
%asm-generic kernelversion %src-pkg dt_binding_check \
|
||||
dt_style_selftest \
|
||||
outputmakefile rustavailable rustfmt rustfmtcheck \
|
||||
scripts_gen_init_cpio \
|
||||
run-command
|
||||
no-sync-config-targets := $(no-dot-config-targets) %install modules_sign kernelrelease \
|
||||
image_name
|
||||
single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %/
|
||||
single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %.header-check %/
|
||||
|
||||
config-build :=
|
||||
mixed-build :=
|
||||
|
|
@ -570,6 +571,9 @@ LZMA = lzma
|
|||
LZ4 = lz4
|
||||
XZ = xz
|
||||
ZSTD = zstd
|
||||
# The kernel image is compressed with pigz, on the job slots make has free,
|
||||
# if it is installed. Everything else uses KGZIP.
|
||||
KPGZIP := $(if $(shell command -v pigz 2>/dev/null),$(PYTHON3) $(abs_srctree)/scripts/jobserver-exec pigz -p %PARALLELISM%,$(KGZIP))
|
||||
TAR = tar
|
||||
|
||||
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
|
||||
|
|
@ -650,7 +654,7 @@ export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN LLVM_
|
|||
export HOSTRUSTC KBUILD_HOSTRUSTFLAGS
|
||||
export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
|
||||
export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
|
||||
export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD TAR
|
||||
export KGZIP KPGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD TAR
|
||||
export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS KBUILD_PROCMACROLDFLAGS LDFLAGS_MODULE
|
||||
export KBUILD_USERCFLAGS KBUILD_USERLDFLAGS
|
||||
|
||||
|
|
@ -683,8 +687,8 @@ ifdef building_out_of_srctree
|
|||
# outputmakefile generates a Makefile in the output directory, if using a
|
||||
# separate output directory. This allows convenient use of make in the
|
||||
# output directory.
|
||||
# At the same time when output Makefile generated, generate .gitignore to
|
||||
# ignore whole output directory
|
||||
# At the same time as the output Makefile is generated, generate .gitignore to
|
||||
# ignore the whole output directory
|
||||
|
||||
ifdef KBUILD_EXTMOD
|
||||
print_env_for_makefile = \
|
||||
|
|
@ -948,8 +952,8 @@ KBUILD_RUSTFLAGS += -Coverflow-checks=$(if $(CONFIG_RUST_OVERFLOW_CHECKS),y,n)
|
|||
ifdef CONFIG_CC_IS_GCC
|
||||
# gcc-10 renamed --param=allow-store-data-races=0 to
|
||||
# -fno-allow-store-data-races.
|
||||
KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0)
|
||||
KBUILD_CFLAGS += $(call cc-option,-fno-allow-store-data-races)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_ALLOW_STORE_DATA_RACES_PARAM)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_NO_ALLOW_STORE_DATA_RACES)
|
||||
endif
|
||||
|
||||
ifdef CONFIG_READABLE_ASM
|
||||
|
|
@ -1013,18 +1017,20 @@ endif
|
|||
endif
|
||||
|
||||
# Explicitly clear padding bits during variable initialization
|
||||
KBUILD_CFLAGS += $(call cc-option,-fzero-init-padding-bits=all)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_ZERO_INIT_PADDING_BITS)
|
||||
|
||||
# While VLAs have been removed, GCC produces unreachable stack probes
|
||||
# for the randomize_kstack_offset feature. Disable it for all compilers.
|
||||
# Probed here rather than in Kconfig as clang only accepts it for some
|
||||
# sub-targets, so the architecture's flags matter.
|
||||
KBUILD_CFLAGS += $(call cc-option, -fno-stack-clash-protection)
|
||||
|
||||
# Get details on warnings generated due to GCC value tracking.
|
||||
KBUILD_CFLAGS += $(call cc-option, -fdiagnostics-show-context=2)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_DIAGNOSTICS_SHOW_CONTEXT)
|
||||
|
||||
# Show inlining notes for __attribute__((warning/error)) call chains.
|
||||
# GCC supports this unconditionally while Clang 23+ provides a flag.
|
||||
KBUILD_CFLAGS += $(call cc-option, -fdiagnostics-show-inlining-chain)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_DIAGNOSTICS_SHOW_INLINING_CHAIN)
|
||||
|
||||
# Clear used registers at func exit (to reduce data lifetime and ROP gadgets).
|
||||
ifdef CONFIG_ZERO_CALL_USED_REGS
|
||||
|
|
@ -1035,7 +1041,7 @@ ifdef CONFIG_FUNCTION_TRACER
|
|||
ifdef CONFIG_FTRACE_MCOUNT_USE_CC
|
||||
CC_FLAGS_FTRACE += -mrecord-mcount
|
||||
ifdef CONFIG_HAVE_NOP_MCOUNT
|
||||
ifeq ($(call cc-option-yn, -mnop-mcount),y)
|
||||
ifdef CONFIG_CC_HAS_MNOP_MCOUNT
|
||||
CC_FLAGS_FTRACE += -mnop-mcount
|
||||
CC_FLAGS_USING += -DCC_USING_NOP_MCOUNT
|
||||
endif
|
||||
|
|
@ -1053,8 +1059,7 @@ ifdef CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
|
|||
endif
|
||||
endif
|
||||
ifdef CONFIG_HAVE_FENTRY
|
||||
# s390-linux-gnu-gcc did not support -mfentry until gcc-9.
|
||||
ifeq ($(call cc-option-yn, -mfentry),y)
|
||||
ifdef CONFIG_CC_HAS_MFENTRY
|
||||
CC_FLAGS_FTRACE += -mfentry
|
||||
CC_FLAGS_USING += -DCC_USING_FENTRY
|
||||
endif
|
||||
|
|
@ -1146,7 +1151,7 @@ export CC_FLAGS_NO_FPU
|
|||
|
||||
ifneq ($(CONFIG_FUNCTION_ALIGNMENT),0)
|
||||
# Set the minimal function alignment. Use the newer GCC option
|
||||
# -fmin-function-alignment if it is available, or fall back to -falign-funtions.
|
||||
# -fmin-function-alignment if it is available, or fall back to -falign-functions.
|
||||
# See also CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT.
|
||||
ifdef CONFIG_CC_HAS_MIN_FUNCTION_ALIGNMENT
|
||||
KBUILD_CFLAGS += -fmin-function-alignment=$(CONFIG_FUNCTION_ALIGNMENT)
|
||||
|
|
@ -1162,7 +1167,7 @@ NOSTDINC_FLAGS += -nostdinc
|
|||
# the kernel uses only C99 flexible arrays for dynamically sized trailing
|
||||
# arrays. Enforce this for everything that may examine structure sizes and
|
||||
# perform bounds checking.
|
||||
KBUILD_CFLAGS += $(call cc-option, -fstrict-flex-arrays=3)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_STRICT_FLEX_ARRAYS)
|
||||
|
||||
# disable invalid "can't wrap" optimizations for signed / pointers
|
||||
KBUILD_CFLAGS += -fno-strict-overflow
|
||||
|
|
@ -1201,7 +1206,10 @@ export CFLAGS_GCOV
|
|||
|
||||
# change __FILE__ to the relative path to the source directory
|
||||
ifdef building_out_of_srctree
|
||||
KBUILD_CPPFLAGS += -fmacro-prefix-map=$(srcroot)/=
|
||||
CFLAGS_PREFIX_MAP := -fmacro-prefix-map=$(srcroot)/=
|
||||
KBUILD_CPPFLAGS += $(CFLAGS_PREFIX_MAP)
|
||||
KBUILD_USERCFLAGS += $(CFLAGS_PREFIX_MAP)
|
||||
KBUILD_HOSTCFLAGS += $(CFLAGS_PREFIX_MAP)
|
||||
ifeq ($(call rustc-option-yn, --remap-path-scope=macro),y)
|
||||
KBUILD_RUSTFLAGS += --remap-path-prefix=$(srcroot)/= --remap-path-scope=macro
|
||||
endif
|
||||
|
|
@ -1242,11 +1250,11 @@ LDFLAGS_vmlinux += --build-id=sha1
|
|||
# COMDAT-deduplicated sections. Use --force-group-allocation to resolve these
|
||||
# groups when linking modules. The option is available from ld.bfd 2.29 and
|
||||
# ld.lld 19.1.0.
|
||||
KBUILD_LDFLAGS_MODULE += $(call ld-option,--force-group-allocation)
|
||||
KBUILD_LDFLAGS_MODULE += $(CONFIG_LD_OPT_FORCE_GROUP_ALLOCATION)
|
||||
|
||||
KBUILD_LDFLAGS += -z noexecstack
|
||||
ifeq ($(CONFIG_LD_IS_BFD),y)
|
||||
KBUILD_LDFLAGS += $(call ld-option,--no-warn-rwx-segments)
|
||||
KBUILD_LDFLAGS += $(CONFIG_LD_OPT_NO_WARN_RWX_SEGMENTS)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
|
||||
|
|
@ -1264,8 +1272,9 @@ ifdef CONFIG_LD_ORPHAN_WARN
|
|||
LDFLAGS_vmlinux += --orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL)
|
||||
endif
|
||||
|
||||
# --emit-relocs is added by scripts/link-vmlinux.sh, for the final link only.
|
||||
ifneq ($(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS),)
|
||||
LDFLAGS_vmlinux += --emit-relocs --discard-none
|
||||
LDFLAGS_vmlinux += --discard-none
|
||||
endif
|
||||
|
||||
# Align the architecture of userspace programs with the kernel
|
||||
|
|
@ -1530,9 +1539,9 @@ ifdef CONFIG_HEADERS_INSTALL
|
|||
prepare: headers
|
||||
endif
|
||||
|
||||
PHONY += usr_gen_init_cpio
|
||||
usr_gen_init_cpio: scripts_basic
|
||||
$(Q)$(MAKE) $(build)=usr usr/gen_init_cpio
|
||||
PHONY += scripts_gen_init_cpio
|
||||
scripts_gen_init_cpio: scripts_basic
|
||||
$(Q)$(MAKE) $(build)=scripts scripts/gen_init_cpio
|
||||
|
||||
PHONY += scripts_unifdef
|
||||
scripts_unifdef: scripts_basic
|
||||
|
|
@ -1542,6 +1551,26 @@ PHONY += scripts_gen_packed_field_checks
|
|||
scripts_gen_packed_field_checks: scripts_basic
|
||||
$(Q)$(MAKE) $(build)=scripts scripts/gen_packed_field_checks
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Header check
|
||||
|
||||
# Check the headers in HEADER_CHECK=(headers|dirs)
|
||||
PHONY += headercheck
|
||||
|
||||
ifneq ($(HEADER_CHECK),)
|
||||
|
||||
header-check-dirs := $(filter-out %.h,$(HEADER_CHECK))
|
||||
header-check-files := $(filter %.h,$(HEADER_CHECK)) $(if $(header-check-dirs),$(shell cd $(srctree) && find $(header-check-dirs) -name '*.h' 2>/dev/null))
|
||||
header-check-targets := $(patsubst %.h,%.header-check,$(sort $(header-check-files)))
|
||||
|
||||
headercheck:
|
||||
$(if $(header-check-targets),,$(error $@ found no headers in HEADER_CHECK="$(HEADER_CHECK)"))
|
||||
$(Q)$(MAKE) $(header-check-targets)
|
||||
else
|
||||
headercheck:
|
||||
$(error $@ requires HEADER_CHECK=(headers|dirs))
|
||||
endif
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Install
|
||||
|
||||
|
|
@ -1833,7 +1862,7 @@ distclean: mrproper
|
|||
# Packaging of the kernel to various formats
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
modules-cpio-pkg: usr_gen_init_cpio
|
||||
modules-cpio-pkg: scripts_gen_init_cpio
|
||||
|
||||
%src-pkg: FORCE
|
||||
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.package $@
|
||||
|
|
@ -1888,6 +1917,8 @@ help:
|
|||
@echo ' versioncheck - Sanity check on version.h usage'
|
||||
@echo ' includecheck - Check for duplicate included header files'
|
||||
@echo ' headerdep - Detect inclusion cycles in headers'
|
||||
@echo ' headercheck - Check headers in HEADER_CHECK=(headers|dirs) are'
|
||||
@echo ' self-contained, have header guards, and pass kernel-doc.'
|
||||
@echo ' coccicheck - Check with Coccinelle'
|
||||
@echo ' kconfig-sym-check - Check for dangling Kconfig symbol references'
|
||||
@echo ' clang-analyzer - Check with clang static analyzer'
|
||||
|
|
@ -2253,6 +2284,7 @@ clean: $(clean-dirs)
|
|||
-o -name '*.ll' \
|
||||
-o -name '*.gcno' \
|
||||
-o -name '*.long-type-*.txt' \
|
||||
-o -name '*.header-check' \
|
||||
\) -type f -print \
|
||||
-o -name '.tmp_*' -print \
|
||||
| xargs rm -rf
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ $(obj)/vmlinux.nh: vmlinux $(OBJSTRIP) FORCE
|
|||
$(call if_changed,objstrip)
|
||||
|
||||
$(obj)/vmlinux.nh.gz: $(obj)/vmlinux.nh FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
$(obj)/tools/lxboot: $(obj)/bootloader $(OBJSTRIP) FORCE
|
||||
$(call if_changed,objstrip)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ suffix-$(CONFIG_KERNEL_ZSTD) := zst
|
|||
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,bzip2_with_size)
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
$(obj)/vmlinux.bin.lz4: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,lz4_with_size)
|
||||
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
|
|||
$(call if_changed,objcopy)
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,lzma)
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \
|
|||
@$(check_for_bad_syms)
|
||||
|
||||
$(obj)/piggy_data: $(obj)/../Image FORCE
|
||||
$(call if_changed,$(compress-y))
|
||||
+$(call if_changed,$(compress-y))
|
||||
|
||||
$(obj)/piggy.o: $(obj)/piggy_data
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ $(obj)/Image.bz2: $(obj)/Image FORCE
|
|||
$(call if_changed,bzip2)
|
||||
|
||||
$(obj)/Image.gz: $(obj)/Image FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
$(obj)/Image.lz4: $(obj)/Image FORCE
|
||||
$(call if_changed,lz4)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \
|
|||
-include $(srctree)/include/linux/hidden.h \
|
||||
-D__DISABLE_EXPORTS -ffreestanding -D__NO_FORTIFY \
|
||||
-fno-asynchronous-unwind-tables -fno-unwind-tables \
|
||||
$(call cc-option,-fno-addrsig)
|
||||
$(CONFIG_CC_OPT_NO_ADDRSIG)
|
||||
|
||||
# this code may run with the MMU off so disable unaligned accesses
|
||||
CFLAGS_map_range.o += -mstrict-align
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ compress-$(CONFIG_KERNEL_XZ) = xzkern
|
|||
compress-$(CONFIG_KERNEL_LZ4) = lz4
|
||||
|
||||
$(obj)/zImage: $(obj)/Image FORCE
|
||||
$(call if_changed,$(compress-y))
|
||||
+$(call if_changed,$(compress-y))
|
||||
@echo ' Kernel: $@ is ready'
|
||||
|
||||
UIMAGE_ARCH = sandbox
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ $(obj)/linux.bin.ub: $(obj)/linux.bin FORCE
|
|||
$(call if_changed,uimage)
|
||||
|
||||
$(obj)/linux.bin.gz: $(obj)/linux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
quiet_cmd_strip = STRIP $< $@$2
|
||||
cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
|
|||
$(call if_changed,bzip2)
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,lzma)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ tool_$(CONFIG_KERNEL_ZSTD) = zstd22_with_size
|
|||
targets += vmlinux.bin.z
|
||||
|
||||
$(obj)/vmlinux.bin.z: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,$(tool_y))
|
||||
+$(call if_changed,$(tool_y))
|
||||
|
||||
targets += piggy.o dummy.o
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
|
|||
$(call if_changed,objcopy)
|
||||
|
||||
$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
$(obj)/vmImage: $(obj)/vmlinux.gz FORCE
|
||||
$(call if_changed,uimage)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ suffix-$(CONFIG_KERNEL_LZO) := lzo
|
|||
suffix-$(CONFIG_KERNEL_XZ) := xz
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,bzip2_with_size)
|
||||
$(obj)/vmlinux.bin.lz4: $(obj)/vmlinux.bin FORCE
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ $(obj)/Image: vmlinux FORCE
|
|||
$(call if_changed,objcopy)
|
||||
|
||||
$(obj)/Image.gz: $(obj)/Image FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
$(obj)/loader.o: $(src)/loader.S $(obj)/Image
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \
|
|||
-include $(srctree)/include/linux/hidden.h \
|
||||
-D__DISABLE_EXPORTS -ffreestanding \
|
||||
-fno-asynchronous-unwind-tables -fno-unwind-tables \
|
||||
$(call cc-option,-fno-addrsig)
|
||||
$(CONFIG_CC_OPT_NO_ADDRSIG)
|
||||
|
||||
# Disable LTO
|
||||
KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS))
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ suffix-$(CONFIG_KERNEL_XZ) := .xz
|
|||
suffix-$(CONFIG_KERNEL_ZSTD) := .zst
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,bzip2_with_size)
|
||||
$(obj)/vmlinux.bin.lz4: $(obj)/vmlinux.bin FORCE
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
|
|||
$(call if_changed,objcopy)
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,bzip2)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
|
|||
$(call if_changed,objcopy)
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,bzip2_with_size)
|
||||
$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ ifeq ($(CONFIG_SPARC64),y)
|
|||
# Actual linking
|
||||
|
||||
$(obj)/zImage: $(obj)/image FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
@$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')'
|
||||
|
||||
$(obj)/vmlinux.aout: vmlinux FORCE
|
||||
|
|
@ -45,7 +45,7 @@ $(obj)/image.bin: $(obj)/image FORCE
|
|||
$(call if_changed,objcopy)
|
||||
|
||||
$(obj)/image.gz: $(obj)/image.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
UIMAGE_LOADADDR = $(CONFIG_UBOOT_LOAD_ADDR)
|
||||
UIMAGE_ENTRYADDR = $(CONFIG_UBOOT_ENTRY_ADDR)
|
||||
|
|
|
|||
|
|
@ -2363,6 +2363,23 @@ config CC_HAS_KCFI_ARITY
|
|||
def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
|
||||
depends on CC_IS_CLANG && !RUST
|
||||
|
||||
config CC_OPT_INDIRECT_BRANCH_CS_PREFIX
|
||||
def_string "$(cc-option-str,-mindirect-branch-cs-prefix)"
|
||||
|
||||
config CC_OPT_CF_PROTECTION_NONE
|
||||
def_string "$(cc-option-str,-fcf-protection=none)"
|
||||
|
||||
# with jump tables off: the compilers use NOTRACK for them, which kernel IBT
|
||||
# does not allow
|
||||
config CC_OPT_CF_PROTECTION_BRANCH
|
||||
def_string "$(cc-option-str,-fcf-protection=branch -fno-jump-tables)"
|
||||
|
||||
config CC_OPT_FALIGN_JUMPS
|
||||
def_string "$(cc-option-str,-falign-jumps=1)"
|
||||
|
||||
config CC_OPT_FALIGN_LOOPS
|
||||
def_string "$(cc-option-str,-falign-loops=1)"
|
||||
|
||||
config FUNCTION_PADDING_CFI
|
||||
int
|
||||
default 59 if FUNCTION_ALIGNMENT_64B
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ ifdef CONFIG_CC_IS_CLANG
|
|||
RETPOLINE_CFLAGS := -mretpoline-external-thunk
|
||||
RETPOLINE_VDSO_CFLAGS := -mretpoline
|
||||
endif
|
||||
RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch-cs-prefix)
|
||||
RETPOLINE_CFLAGS += $(CONFIG_CC_OPT_INDIRECT_BRANCH_CS_PREFIX)
|
||||
|
||||
ifdef CONFIG_MITIGATION_RETHUNK
|
||||
RETHUNK_CFLAGS := -mfunction-return=thunk-extern
|
||||
|
|
@ -52,7 +52,7 @@ REALMODE_CFLAGS := $(CC_FLAGS_DIALECT) -m16 -g -Os \
|
|||
-DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS \
|
||||
-Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
|
||||
-fno-strict-aliasing -fomit-frame-pointer -fno-pic \
|
||||
-mno-mmx -mno-sse $(call cc-option,-fcf-protection=none)
|
||||
-mno-mmx -mno-sse $(CONFIG_CC_OPT_CF_PROTECTION_NONE)
|
||||
|
||||
REALMODE_CFLAGS += -ffreestanding
|
||||
REALMODE_CFLAGS += -fno-stack-protector
|
||||
|
|
@ -99,10 +99,10 @@ ifeq ($(CONFIG_X86_KERNEL_IBT),y)
|
|||
#
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104816
|
||||
#
|
||||
KBUILD_CFLAGS += $(call cc-option,-fcf-protection=branch -fno-jump-tables)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_CF_PROTECTION_BRANCH)
|
||||
KBUILD_RUSTFLAGS += -Zcf-protection=branch $(if $(call rustc-min-version,109300),-Cjump-tables=n,-Zno-jump-tables)
|
||||
else
|
||||
KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_CF_PROTECTION_NONE)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_X86_32),y)
|
||||
|
|
@ -138,10 +138,10 @@ else
|
|||
KBUILD_CFLAGS += -m64
|
||||
|
||||
# Align jump targets to 1 byte, not the default 16 bytes:
|
||||
KBUILD_CFLAGS += $(call cc-option,-falign-jumps=1)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_FALIGN_JUMPS)
|
||||
|
||||
# Pack loops tightly as well:
|
||||
KBUILD_CFLAGS += $(call cc-option,-falign-loops=1)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_FALIGN_LOOPS)
|
||||
|
||||
# Don't autogenerate traditional x87 instructions
|
||||
KBUILD_CFLAGS += -mno-80387
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
|
|||
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|efi.._stub_entry\|efi\(32\)\?_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|_e\?data\|_e\?sbat\|z_.*\)$$/\#define ZO_\2 0x\1/p'
|
||||
|
||||
quiet_cmd_zoffset = ZOFFSET $@
|
||||
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
|
||||
cmd_zoffset = $(NM) -p $< | sed -n $(sed-zoffset) > $@
|
||||
|
||||
targets += zoffset.h
|
||||
$(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include
|
|||
sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABbCDGRSTtVW] \(_text\|__start_rodata\|_sinittext\|__inittext_end\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p'
|
||||
|
||||
quiet_cmd_voffset = VOFFSET $@
|
||||
cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@
|
||||
cmd_voffset = $(NM) -p $< | sed -n $(sed-voffset) > $@
|
||||
|
||||
targets += ../voffset.h
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin
|
|||
vmlinux.bin.all-$(CONFIG_X86_NEED_RELOCS) += $(obj)/vmlinux.relocs
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
|
||||
$(call if_changed,bzip2_with_size)
|
||||
$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
|
|||
$(call if_changed,objcopy)
|
||||
|
||||
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
+$(call if_changed,gzip)
|
||||
|
||||
boot-elf: $(obj)/vmlinux.bin
|
||||
boot-redboot: $(obj)/vmlinux.bin.gz
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(cflags-y)) \
|
|||
-D__NO_FORTIFY \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
$(call cc-option,-fno-addrsig) \
|
||||
$(CONFIG_CC_OPT_NO_ADDRSIG) \
|
||||
-D__DISABLE_EXPORTS
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ zboot-method-$(CONFIG_KERNEL_ZSTD) := zstd22_with_size
|
|||
zboot-size-len-$(CONFIG_KERNEL_ZSTD) := 4
|
||||
|
||||
$(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,$(zboot-method-y))
|
||||
+$(call if_changed,$(zboot-method-y))
|
||||
|
||||
# avoid eager evaluation to prevent references to non-existent build artifacts
|
||||
OBJCOPYFLAGS_vmlinuz.o = -I binary -O $(EFI_ZBOOT_BFD_TARGET) $(EFI_ZBOOT_OBJCOPY_FLAGS) \
|
||||
|
|
|
|||
|
|
@ -34,33 +34,17 @@ config QCOM_TZMEM
|
|||
tristate
|
||||
select GENERIC_ALLOCATOR
|
||||
|
||||
choice
|
||||
prompt "TrustZone interface memory allocator mode"
|
||||
depends on QCOM_TZMEM
|
||||
default QCOM_TZMEM_MODE_GENERIC
|
||||
help
|
||||
Selects the mode of the memory allocator providing memory buffers of
|
||||
suitable format for sharing with the TrustZone. If in doubt, select
|
||||
'Generic'.
|
||||
|
||||
config QCOM_TZMEM_MODE_GENERIC
|
||||
bool "Generic"
|
||||
help
|
||||
Use the generic allocator mode. The memory is page-aligned, non-cachable
|
||||
and physically contiguous.
|
||||
|
||||
config QCOM_TZMEM_MODE_SHMBRIDGE
|
||||
bool "SHM Bridge"
|
||||
bool "TrustZone interface memory allocator: SHM Bridge"
|
||||
depends on QCOM_TZMEM
|
||||
help
|
||||
Use Qualcomm Shared Memory Bridge. The memory has the same alignment as
|
||||
in the 'Generic' allocator but is also explicitly marked as an SHM Bridge
|
||||
buffer.
|
||||
Use Qualcomm Shared Memory Bridge as memory allocator. The memory has the
|
||||
same alignment as in the 'Generic' allocator, which is used when this option
|
||||
is disabled, but is also explicitly marked as an SHM Bridge buffer.
|
||||
|
||||
With this selected, all buffers passed to the TrustZone must be allocated
|
||||
using the TZMem allocator or else the TrustZone will refuse to use them.
|
||||
|
||||
endchoice
|
||||
|
||||
config QCOM_QSEECOM
|
||||
bool "Qualcomm QSEECOM interface driver"
|
||||
depends on QCOM_SCM=y
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ static struct device *qcom_tzmem_dev;
|
|||
static RADIX_TREE(qcom_tzmem_chunks, GFP_ATOMIC);
|
||||
static DEFINE_SPINLOCK(qcom_tzmem_chunks_lock);
|
||||
|
||||
#if IS_ENABLED(CONFIG_QCOM_TZMEM_MODE_GENERIC)
|
||||
#ifndef CONFIG_QCOM_TZMEM_MODE_SHMBRIDGE
|
||||
|
||||
static int qcom_tzmem_init(void)
|
||||
{
|
||||
|
|
@ -67,7 +67,7 @@ static void qcom_tzmem_cleanup_area(struct qcom_tzmem_area *area)
|
|||
|
||||
}
|
||||
|
||||
#elif IS_ENABLED(CONFIG_QCOM_TZMEM_MODE_SHMBRIDGE)
|
||||
#else
|
||||
|
||||
#include <linux/firmware/qcom/qcom_scm.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
|||
|
|
@ -132,13 +132,11 @@ config EROFS_FS_ZIP_LZMA
|
|||
Say N if you want to disable LZMA compression support.
|
||||
|
||||
config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS
|
||||
int "EROFS LZMA default maximum decompression streams" if SMP
|
||||
int "EROFS LZMA default maximum decompression streams"
|
||||
depends on EROFS_FS_ZIP_LZMA
|
||||
range 1 NR_CPUS if SMP
|
||||
range 1 1 if !SMP
|
||||
default 16 if SMP && NR_CPUS >= 16
|
||||
default NR_CPUS if SMP
|
||||
default 1
|
||||
default 16
|
||||
help
|
||||
By default EROFS allocates one LZMA decompression stream per CPU.
|
||||
Each stream can hold a dictionary of up to 8 MiB taken from the
|
||||
|
|
@ -146,7 +144,7 @@ config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS
|
|||
of memory. This caps the default; the lzma_streams module parameter
|
||||
still overrides it.
|
||||
|
||||
If unsure, keep the suggested default (16 or lower).
|
||||
If unsure, keep the default of 16.
|
||||
|
||||
config EROFS_FS_ZIP_DEFLATE
|
||||
bool "EROFS DEFLATE compressed data support"
|
||||
|
|
|
|||
|
|
@ -855,7 +855,7 @@
|
|||
KLP_SYMID
|
||||
|
||||
#define MODINFO \
|
||||
.modinfo : { *(.modinfo) . = ALIGN(8); }
|
||||
.modinfo (INFO) : { KEEP(*(.modinfo)) }
|
||||
|
||||
#ifdef CONFIG_GENERIC_BUG
|
||||
#define BUG_TABLE \
|
||||
|
|
|
|||
199
init/Kconfig
199
init/Kconfig
|
|
@ -1,203 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config CC_VERSION_TEXT
|
||||
string
|
||||
default "$(CC_VERSION_TEXT)"
|
||||
help
|
||||
This is used in unclear ways:
|
||||
|
||||
- Re-run Kconfig when the compiler is updated
|
||||
The 'default' property references the environment variable,
|
||||
CC_VERSION_TEXT so it is recorded in include/config/auto.conf.cmd.
|
||||
When the compiler is updated, Kconfig will be invoked.
|
||||
|
||||
- Ensure full rebuild when the compiler is updated
|
||||
include/linux/compiler-version.h contains this option in the comment
|
||||
line so fixdep adds include/config/CC_VERSION_TEXT into the
|
||||
auto-generated dependency. When the compiler is updated, syncconfig
|
||||
will touch it and then every file will be rebuilt.
|
||||
|
||||
config CC_IS_GCC
|
||||
def_bool $(success,test "$(cc-name)" = GCC)
|
||||
|
||||
config GCC_VERSION
|
||||
int
|
||||
default $(cc-version) if CC_IS_GCC
|
||||
default 0
|
||||
|
||||
config CC_IS_CLANG
|
||||
def_bool $(success,test "$(cc-name)" = Clang)
|
||||
|
||||
config CLANG_VERSION
|
||||
int
|
||||
default $(cc-version) if CC_IS_CLANG
|
||||
default 0
|
||||
|
||||
config AS_IS_GNU
|
||||
def_bool $(success,test "$(as-name)" = GNU)
|
||||
|
||||
config AS_IS_LLVM
|
||||
def_bool $(success,test "$(as-name)" = LLVM)
|
||||
|
||||
config AS_VERSION
|
||||
int
|
||||
# Use clang version if this is the integrated assembler
|
||||
default CLANG_VERSION if AS_IS_LLVM
|
||||
default $(as-version)
|
||||
|
||||
config LD_IS_BFD
|
||||
def_bool $(success,test "$(ld-name)" = BFD)
|
||||
|
||||
config LD_VERSION
|
||||
int
|
||||
default $(ld-version) if LD_IS_BFD
|
||||
default 0
|
||||
|
||||
config LD_IS_LLD
|
||||
def_bool $(success,test "$(ld-name)" = LLD)
|
||||
|
||||
config LLD_VERSION
|
||||
int
|
||||
default $(ld-version) if LD_IS_LLD
|
||||
default 0
|
||||
|
||||
config RUSTC_VERSION
|
||||
int
|
||||
default $(rustc-version)
|
||||
help
|
||||
It does not depend on `RUST` since that one may need to use the version
|
||||
in a `depends on`.
|
||||
|
||||
config RUST_IS_AVAILABLE
|
||||
def_bool $(success,$(srctree)/scripts/rust_is_available.sh)
|
||||
help
|
||||
This shows whether a suitable Rust toolchain is available (found).
|
||||
|
||||
Please see Documentation/rust/quick-start.rst for instructions on how
|
||||
to satisfy the build requirements of Rust support.
|
||||
|
||||
In particular, the Makefile target 'rustavailable' is useful to check
|
||||
why the Rust toolchain is not being detected.
|
||||
|
||||
config RUSTC_LLVM_VERSION
|
||||
int
|
||||
default $(rustc-llvm-version)
|
||||
|
||||
config RUSTC_LLVM_MAJOR_VERSION
|
||||
int
|
||||
default $(shell,expr $(rustc-llvm-version) / 10000)
|
||||
|
||||
config RUSTC_CLANG_LLVM_COMPATIBLE
|
||||
bool
|
||||
default y if CC_IS_CLANG && RUSTC_LLVM_MAJOR_VERSION = $(shell,expr $(cc-version) / 10000)
|
||||
help
|
||||
This indicates whether Rust and Clang use LLVM of the same major
|
||||
version.
|
||||
|
||||
Operations involving handling LLVM IR or bitcode (e.g. cross-language
|
||||
LTO) require the same LLVM major version to work properly. For best
|
||||
compatibility it is recommended that the exact same LLVM is used.
|
||||
|
||||
config ARCH_HAS_CC_CAN_LINK
|
||||
bool
|
||||
|
||||
config CC_CAN_LINK
|
||||
bool
|
||||
default ARCH_CC_CAN_LINK if ARCH_HAS_CC_CAN_LINK
|
||||
default $(cc_can_link_user,$(m64-flag)) if 64BIT
|
||||
default $(cc_can_link_user,$(m32-flag))
|
||||
|
||||
# Fixed in GCC 14, 13.3, 12.4 and 11.5
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921
|
||||
config GCC_ASM_GOTO_OUTPUT_BROKEN
|
||||
bool
|
||||
depends on CC_IS_GCC
|
||||
default y if GCC_VERSION < 110500
|
||||
default y if GCC_VERSION >= 120000 && GCC_VERSION < 120400
|
||||
default y if GCC_VERSION >= 130000 && GCC_VERSION < 130300
|
||||
|
||||
config CC_HAS_ASM_GOTO_OUTPUT
|
||||
def_bool y
|
||||
depends on !GCC_ASM_GOTO_OUTPUT_BROKEN
|
||||
depends on $(success,echo 'int foo(int x) { asm goto ("": "=r"(x) ::: bar); return x; bar: return 0; }' | $(CC) -x c - -c -o /dev/null)
|
||||
|
||||
config CC_HAS_ASM_GOTO_TIED_OUTPUT
|
||||
depends on CC_HAS_ASM_GOTO_OUTPUT
|
||||
# Detect buggy gcc and clang, fixed in gcc-11 clang-14.
|
||||
def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null)
|
||||
|
||||
config TOOLS_SUPPORT_RELR
|
||||
def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
|
||||
|
||||
config CC_HAS_ASM_INLINE
|
||||
def_bool $(success,echo 'void foo(void) { asm inline (""); }' | $(CC) -x c - -c -o /dev/null)
|
||||
|
||||
config CC_HAS_ASSUME
|
||||
bool
|
||||
# clang needs to be at least 19.1.0 since the meaning of the assume
|
||||
# attribute changed:
|
||||
# https://github.com/llvm/llvm-project/commit/c44fa3e8a9a44c2e9a575768a3c185354b9f6c17
|
||||
default y if CC_IS_CLANG && CLANG_VERSION >= 190100
|
||||
# supported since gcc 13.1.0
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106654
|
||||
default y if CC_IS_GCC && GCC_VERSION >= 130100
|
||||
|
||||
config CC_HAS_NO_PROFILE_FN_ATTR
|
||||
def_bool $(success,echo '__attribute__((no_profile_instrument_function)) int x();' | $(CC) -x c - -c -o /dev/null -Werror)
|
||||
|
||||
config CC_HAS_COUNTED_BY
|
||||
bool
|
||||
# clang needs to be at least 20.1.0 to avoid potential crashes
|
||||
# when building structures that contain __counted_by
|
||||
# https://github.com/ClangBuiltLinux/linux/issues/2114
|
||||
# https://github.com/llvm/llvm-project/commit/160fb1121cdf703c3ef5e61fb26c5659eb581489
|
||||
default y if CC_IS_CLANG && CLANG_VERSION >= 200100
|
||||
# supported since gcc 15.1.0
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
|
||||
default y if CC_IS_GCC && GCC_VERSION >= 150100
|
||||
|
||||
config CC_HAS_COUNTED_BY_PTR
|
||||
bool
|
||||
# supported since clang 22
|
||||
default y if CC_IS_CLANG && CLANG_VERSION >= 220100
|
||||
# supported since gcc 16.0.0
|
||||
default y if CC_IS_GCC && GCC_VERSION >= 160000
|
||||
|
||||
config CC_HAS_BROKEN_COUNTED_BY_REF
|
||||
bool
|
||||
# https://github.com/llvm/llvm-project/issues/182575
|
||||
default y if CC_IS_CLANG && CLANG_VERSION < 220100
|
||||
|
||||
config CC_HAS_ALLOC_TOKEN
|
||||
def_bool $(cc-option,-falloc-token-max=123)
|
||||
|
||||
config CC_HAS_MULTIDIMENSIONAL_NONSTRING
|
||||
def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror)
|
||||
|
||||
config CC_OPT_INLINE_MEMSET
|
||||
string
|
||||
default "-finline-stringops=memset" if $(cc-option,-finline-stringops=memset)
|
||||
default "-mllvm -max-store-memset=4294967294" if $(cc-option,-mllvm -max-store-memset=4294967294)
|
||||
|
||||
config LD_CAN_USE_KEEP_IN_OVERLAY
|
||||
# ld.lld prior to 21.0.0 did not support KEEP within an overlay description
|
||||
# https://github.com/llvm/llvm-project/pull/130661
|
||||
def_bool LD_IS_BFD || LLD_VERSION >= 210000
|
||||
|
||||
config RUSTC_HAS_UNNECESSARY_TRANSMUTES
|
||||
def_bool RUSTC_VERSION >= 108800
|
||||
|
||||
config RUSTC_HAS_FILE_WITH_NUL
|
||||
def_bool RUSTC_VERSION >= 108900
|
||||
|
||||
config RUSTC_HAS_FILE_AS_C_STR
|
||||
def_bool RUSTC_VERSION >= 109100
|
||||
|
||||
config RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS
|
||||
def_bool RUSTC_VERSION >= 109800
|
||||
|
||||
config PAHOLE_VERSION
|
||||
int
|
||||
default "$(PAHOLE_VERSION)"
|
||||
source "scripts/Kconfig.toolchain"
|
||||
|
||||
config CONSTRUCTORS
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -154,9 +154,13 @@ obj-$(CONFIG_SCF_TORTURE_TEST) += scftorture.o
|
|||
|
||||
$(obj)/configs.o: $(obj)/config_data.gz
|
||||
|
||||
# .config is small, so it is compressed with gzip rather than the image compressor.
|
||||
quiet_cmd_gzip_config = GZIP $@
|
||||
cmd_gzip_config = cat $(real-prereqs) | $(KGZIP) -n -f -9 > $@
|
||||
|
||||
targets += config_data config_data.gz
|
||||
$(obj)/config_data.gz: $(obj)/config_data FORCE
|
||||
$(call if_changed,gzip)
|
||||
$(call if_changed,gzip_config)
|
||||
|
||||
filechk_cat = cat $<
|
||||
|
||||
|
|
|
|||
1
scripts/.gitignore
vendored
1
scripts/.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
/asn1_compiler
|
||||
/gen_init_cpio
|
||||
/gen_packed_field_checks
|
||||
/generate_rust_target
|
||||
/insert-sys-cert
|
||||
|
|
|
|||
|
|
@ -23,13 +23,33 @@ success = $(if-success,$(1),y,n)
|
|||
# Return n if <command> exits with 0, y otherwise
|
||||
failure = $(if-success,$(1),n,y)
|
||||
|
||||
# $(cc-probe,<flag>)
|
||||
# The command $(cc-option) and $(cc-option-str) test <flag> with. Not meant
|
||||
# to be called directly; use one of those two instead.
|
||||
cc-probe = trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(CC) -Werror $(CLANG_FLAGS) $(shell,echo $(1) | sed "s;^-Wno-;-W;") -c -x c /dev/null -o .tmp_$$/tmp.o
|
||||
|
||||
# $(cc-option,<flag>)
|
||||
# Return y if the compiler supports <flag>, n otherwise
|
||||
cc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$/tmp.o)
|
||||
cc-option = $(success,$(cc-probe,$(1)))
|
||||
|
||||
# $(cc-option-str,<flag>[,<fallback>])
|
||||
# Return <flag> if the compiler supports it, <fallback> otherwise.
|
||||
# <fallback> defaults to an empty string and is returned untested.
|
||||
cc-option-str = $(if-success,$(cc-probe,$(1)),$(1),$(2))
|
||||
|
||||
# $(ld-probe,<flag>)
|
||||
# The command $(ld-option) and $(ld-option-str) test <flag> with. Not meant
|
||||
# to be called directly; use one of those two instead.
|
||||
ld-probe = $(LD) -v $(1)
|
||||
|
||||
# $(ld-option,<flag>)
|
||||
# Return y if the linker supports <flag>, n otherwise
|
||||
ld-option = $(success,$(LD) -v $(1))
|
||||
ld-option = $(success,$(ld-probe,$(1)))
|
||||
|
||||
# $(ld-option-str,<flag>[,<fallback>])
|
||||
# Return <flag> if the linker supports it, <fallback> otherwise.
|
||||
# <fallback> defaults to an empty string and is returned untested.
|
||||
ld-option-str = $(if-success,$(ld-probe,$(1)),$(1),$(2))
|
||||
|
||||
# $(as-instr,<instr>)
|
||||
# Return y if the assembler supports <instr>, n otherwise
|
||||
|
|
@ -61,9 +81,8 @@ ld-version := $(shell,set -- $(ld-info) && echo $2)
|
|||
# machine bit flags
|
||||
# $(m32-flag): -m32 if the compiler supports it, or an empty string otherwise.
|
||||
# $(m64-flag): -m64 if the compiler supports it, or an empty string otherwise.
|
||||
cc-option-bit = $(if-success,$(CC) -Werror $(1) -E -x c /dev/null -o /dev/null,$(1))
|
||||
m32-flag := $(cc-option-bit,-m32)
|
||||
m64-flag := $(cc-option-bit,-m64)
|
||||
m32-flag := $(cc-option-str,-m32)
|
||||
m64-flag := $(cc-option-str,-m64)
|
||||
|
||||
# Test whether the compiler can link userspace applications
|
||||
cc_can_link_user = $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(1))
|
||||
|
|
|
|||
274
scripts/Kconfig.toolchain
Normal file
274
scripts/Kconfig.toolchain
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config CC_VERSION_TEXT
|
||||
string
|
||||
default "$(CC_VERSION_TEXT)"
|
||||
help
|
||||
This is used in unclear ways:
|
||||
|
||||
- Re-run Kconfig when the compiler is updated
|
||||
The 'default' property references the environment variable,
|
||||
CC_VERSION_TEXT so it is recorded in include/config/auto.conf.cmd.
|
||||
When the compiler is updated, Kconfig will be invoked.
|
||||
|
||||
- Ensure full rebuild when the compiler is updated
|
||||
include/linux/compiler-version.h contains this option in the comment
|
||||
line so fixdep adds include/config/CC_VERSION_TEXT into the
|
||||
auto-generated dependency. When the compiler is updated, syncconfig
|
||||
will touch it and then every file will be rebuilt.
|
||||
|
||||
config CC_IS_GCC
|
||||
def_bool $(success,test "$(cc-name)" = GCC)
|
||||
|
||||
config GCC_VERSION
|
||||
int
|
||||
default $(cc-version) if CC_IS_GCC
|
||||
default 0
|
||||
|
||||
config CC_IS_CLANG
|
||||
def_bool $(success,test "$(cc-name)" = Clang)
|
||||
|
||||
config CLANG_VERSION
|
||||
int
|
||||
default $(cc-version) if CC_IS_CLANG
|
||||
default 0
|
||||
|
||||
config AS_IS_GNU
|
||||
def_bool $(success,test "$(as-name)" = GNU)
|
||||
|
||||
config AS_IS_LLVM
|
||||
def_bool $(success,test "$(as-name)" = LLVM)
|
||||
|
||||
config AS_VERSION
|
||||
int
|
||||
# Use clang version if this is the integrated assembler
|
||||
default CLANG_VERSION if AS_IS_LLVM
|
||||
default $(as-version)
|
||||
|
||||
config LD_IS_BFD
|
||||
def_bool $(success,test "$(ld-name)" = BFD)
|
||||
|
||||
config LD_VERSION
|
||||
int
|
||||
default $(ld-version) if LD_IS_BFD
|
||||
default 0
|
||||
|
||||
config LD_IS_LLD
|
||||
def_bool $(success,test "$(ld-name)" = LLD)
|
||||
|
||||
config LLD_VERSION
|
||||
int
|
||||
default $(ld-version) if LD_IS_LLD
|
||||
default 0
|
||||
|
||||
config RUSTC_VERSION
|
||||
int
|
||||
default $(rustc-version)
|
||||
help
|
||||
It does not depend on `RUST` since that one may need to use the version
|
||||
in a `depends on`.
|
||||
|
||||
config RUST_IS_AVAILABLE
|
||||
def_bool $(success,$(srctree)/scripts/rust_is_available.sh)
|
||||
help
|
||||
This shows whether a suitable Rust toolchain is available (found).
|
||||
|
||||
Please see Documentation/rust/quick-start.rst for instructions on how
|
||||
to satisfy the build requirements of Rust support.
|
||||
|
||||
In particular, the Makefile target 'rustavailable' is useful to check
|
||||
why the Rust toolchain is not being detected.
|
||||
|
||||
config RUSTC_LLVM_VERSION
|
||||
int
|
||||
default $(rustc-llvm-version)
|
||||
|
||||
config RUSTC_LLVM_MAJOR_VERSION
|
||||
int
|
||||
default $(shell,expr $(rustc-llvm-version) / 10000)
|
||||
|
||||
config RUSTC_CLANG_LLVM_COMPATIBLE
|
||||
bool
|
||||
default y if CC_IS_CLANG && RUSTC_LLVM_MAJOR_VERSION = $(shell,expr $(cc-version) / 10000)
|
||||
help
|
||||
This indicates whether Rust and Clang use LLVM of the same major
|
||||
version.
|
||||
|
||||
Operations involving handling LLVM IR or bitcode (e.g. cross-language
|
||||
LTO) require the same LLVM major version to work properly. For best
|
||||
compatibility it is recommended that the exact same LLVM is used.
|
||||
|
||||
config ARCH_HAS_CC_CAN_LINK
|
||||
bool
|
||||
|
||||
config CC_CAN_LINK
|
||||
bool
|
||||
default ARCH_CC_CAN_LINK if ARCH_HAS_CC_CAN_LINK
|
||||
default $(cc_can_link_user,$(m64-flag)) if 64BIT
|
||||
default $(cc_can_link_user,$(m32-flag))
|
||||
|
||||
# Fixed in GCC 14, 13.3, 12.4 and 11.5
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921
|
||||
config GCC_ASM_GOTO_OUTPUT_BROKEN
|
||||
bool
|
||||
depends on CC_IS_GCC
|
||||
default y if GCC_VERSION < 110500
|
||||
default y if GCC_VERSION >= 120000 && GCC_VERSION < 120400
|
||||
default y if GCC_VERSION >= 130000 && GCC_VERSION < 130300
|
||||
|
||||
config CC_HAS_ASM_GOTO_OUTPUT
|
||||
def_bool y
|
||||
depends on !GCC_ASM_GOTO_OUTPUT_BROKEN
|
||||
depends on $(success,echo 'int foo(int x) { asm goto ("": "=r"(x) ::: bar); return x; bar: return 0; }' | $(CC) -x c - -c -o /dev/null)
|
||||
|
||||
config CC_HAS_ASM_GOTO_TIED_OUTPUT
|
||||
depends on CC_HAS_ASM_GOTO_OUTPUT
|
||||
# Detect buggy gcc and clang, fixed in gcc-11 clang-14.
|
||||
def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null)
|
||||
|
||||
config TOOLS_SUPPORT_RELR
|
||||
def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
|
||||
|
||||
config CC_HAS_ASM_INLINE
|
||||
def_bool $(success,echo 'void foo(void) { asm inline (""); }' | $(CC) -x c - -c -o /dev/null)
|
||||
|
||||
config CC_HAS_ASSUME
|
||||
bool
|
||||
# clang needs to be at least 19.1.0 since the meaning of the assume
|
||||
# attribute changed:
|
||||
# https://github.com/llvm/llvm-project/commit/c44fa3e8a9a44c2e9a575768a3c185354b9f6c17
|
||||
default y if CC_IS_CLANG && CLANG_VERSION >= 190100
|
||||
# supported since gcc 13.1.0
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106654
|
||||
default y if CC_IS_GCC && GCC_VERSION >= 130100
|
||||
|
||||
config CC_HAS_NO_PROFILE_FN_ATTR
|
||||
def_bool $(success,echo '__attribute__((no_profile_instrument_function)) int x();' | $(CC) -x c - -c -o /dev/null -Werror)
|
||||
|
||||
config CC_OPT_ZERO_INIT_PADDING_BITS
|
||||
def_string "$(cc-option-str,-fzero-init-padding-bits=all)"
|
||||
|
||||
config CC_OPT_NO_ADDRSIG
|
||||
def_string "$(cc-option-str,-fno-addrsig)"
|
||||
|
||||
config CC_OPT_DIAGNOSTICS_SHOW_CONTEXT
|
||||
def_string "$(cc-option-str,-fdiagnostics-show-context=2)"
|
||||
|
||||
config CC_OPT_DIAGNOSTICS_SHOW_INLINING_CHAIN
|
||||
def_string "$(cc-option-str,-fdiagnostics-show-inlining-chain)"
|
||||
|
||||
config CC_OPT_STRICT_FLEX_ARRAYS
|
||||
def_string "$(cc-option-str,-fstrict-flex-arrays=3)"
|
||||
|
||||
# gcc-10 renamed --param=allow-store-data-races=0 to -fno-allow-store-data-races
|
||||
config CC_OPT_ALLOW_STORE_DATA_RACES_PARAM
|
||||
def_string "$(cc-option-str,--param=allow-store-data-races=0)"
|
||||
|
||||
config CC_OPT_NO_ALLOW_STORE_DATA_RACES
|
||||
def_string "$(cc-option-str,-fno-allow-store-data-races)"
|
||||
|
||||
config CC_HAS_MNOP_MCOUNT
|
||||
def_bool $(cc-option,-mnop-mcount)
|
||||
|
||||
# s390-linux-gnu-gcc did not support -mfentry until gcc-9.
|
||||
config CC_HAS_MFENTRY
|
||||
def_bool $(cc-option,-mfentry)
|
||||
|
||||
config LD_OPT_FORCE_GROUP_ALLOCATION
|
||||
def_string "$(ld-option-str,--force-group-allocation)"
|
||||
|
||||
config LD_OPT_NO_WARN_RWX_SEGMENTS
|
||||
def_string "$(ld-option-str,--no-warn-rwx-segments)"
|
||||
|
||||
config CC_OPT_WNO_ADDRESS_OF_PACKED_MEMBER
|
||||
def_string "$(cc-option-str,-Wno-address-of-packed-member)"
|
||||
|
||||
config CC_OPT_WNO_FORMAT_OVERFLOW_NON_KPRINTF
|
||||
def_string "$(cc-option-str,-Wno-format-overflow-non-kprintf)"
|
||||
|
||||
config CC_OPT_WNO_FORMAT_TRUNCATION_NON_KPRINTF
|
||||
def_string "$(cc-option-str,-Wno-format-truncation-non-kprintf)"
|
||||
|
||||
config CC_OPT_WNO_DEFAULT_CONST_INIT_UNSAFE
|
||||
def_string "$(cc-option-str,-Wno-default-const-init-unsafe)"
|
||||
|
||||
config CC_OPT_WNO_DANGLING_POINTER
|
||||
def_string "$(cc-option-str,-Wno-dangling-pointer)"
|
||||
|
||||
config CC_OPT_WVLA_LARGER_THAN
|
||||
def_string "$(cc-option-str,-Wvla-larger-than=1)"
|
||||
|
||||
config CC_HAS_WSTRINGOP_OVERFLOW
|
||||
def_bool $(cc-option,-Wstringop-overflow)
|
||||
|
||||
config CC_OPT_WNO_UNTERMINATED_STRING_INITIALIZATION
|
||||
def_string "$(cc-option-str,-Wno-unterminated-string-initialization)"
|
||||
|
||||
config CC_OPT_WERROR_DESIGNATED_INIT
|
||||
def_string "$(cc-option-str,-Werror=designated-init)"
|
||||
|
||||
config CC_OPT_WENUM_CONVERSION
|
||||
def_string "$(cc-option-str,-Wenum-conversion)"
|
||||
|
||||
config CC_OPT_WNO_PACKED_NOT_ALIGNED
|
||||
def_string "$(cc-option-str,-Wno-packed-not-aligned)"
|
||||
|
||||
config CC_OPT_WNO_FORMAT_OVERFLOW
|
||||
def_string "$(cc-option-str,-Wno-format-overflow)"
|
||||
|
||||
config CC_OPT_WNO_STRINGOP_TRUNCATION
|
||||
def_string "$(cc-option-str,-Wno-stringop-truncation)"
|
||||
|
||||
config CC_HAS_COUNTED_BY
|
||||
bool
|
||||
# clang needs to be at least 20.1.0 to avoid potential crashes
|
||||
# when building structures that contain __counted_by
|
||||
# https://github.com/ClangBuiltLinux/linux/issues/2114
|
||||
# https://github.com/llvm/llvm-project/commit/160fb1121cdf703c3ef5e61fb26c5659eb581489
|
||||
default y if CC_IS_CLANG && CLANG_VERSION >= 200100
|
||||
# supported since gcc 15.1.0
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
|
||||
default y if CC_IS_GCC && GCC_VERSION >= 150100
|
||||
|
||||
config CC_HAS_COUNTED_BY_PTR
|
||||
bool
|
||||
# supported since clang 22
|
||||
default y if CC_IS_CLANG && CLANG_VERSION >= 220100
|
||||
# supported since gcc 16.0.0
|
||||
default y if CC_IS_GCC && GCC_VERSION >= 160000
|
||||
|
||||
config CC_HAS_BROKEN_COUNTED_BY_REF
|
||||
bool
|
||||
# https://github.com/llvm/llvm-project/issues/182575
|
||||
default y if CC_IS_CLANG && CLANG_VERSION < 220100
|
||||
|
||||
config CC_HAS_ALLOC_TOKEN
|
||||
def_bool $(cc-option,-falloc-token-max=123)
|
||||
|
||||
config CC_HAS_MULTIDIMENSIONAL_NONSTRING
|
||||
def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror)
|
||||
|
||||
config CC_OPT_INLINE_MEMSET
|
||||
string
|
||||
default "-finline-stringops=memset" if $(cc-option,-finline-stringops=memset)
|
||||
default "-mllvm -max-store-memset=4294967294" if $(cc-option,-mllvm -max-store-memset=4294967294)
|
||||
|
||||
config LD_CAN_USE_KEEP_IN_OVERLAY
|
||||
# ld.lld prior to 21.0.0 did not support KEEP within an overlay description
|
||||
# https://github.com/llvm/llvm-project/pull/130661
|
||||
def_bool LD_IS_BFD || LLD_VERSION >= 210000
|
||||
|
||||
config RUSTC_HAS_UNNECESSARY_TRANSMUTES
|
||||
def_bool RUSTC_VERSION >= 108800
|
||||
|
||||
config RUSTC_HAS_FILE_WITH_NUL
|
||||
def_bool RUSTC_VERSION >= 108900
|
||||
|
||||
config RUSTC_HAS_FILE_AS_C_STR
|
||||
def_bool RUSTC_VERSION >= 109100
|
||||
|
||||
config RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS
|
||||
def_bool RUSTC_VERSION >= 109800
|
||||
|
||||
config PAHOLE_VERSION
|
||||
int
|
||||
default "$(PAHOLE_VERSION)"
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
# scripts contains sources for various helper programs used throughout
|
||||
# the kernel for the build process.
|
||||
|
||||
hostprogs-always-$(CONFIG_KALLSYMS) += kallsyms
|
||||
hostprogs-always-y += kallsyms
|
||||
hostprogs-always-$(BUILD_C_RECORDMCOUNT) += recordmcount
|
||||
hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable
|
||||
hostprogs-always-$(CONFIG_ASN1) += asn1_compiler
|
||||
|
|
@ -13,6 +13,7 @@ hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder
|
|||
hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen
|
||||
hostprogs-always-$(CONFIG_TRACEPOINTS) += tracepoint-update
|
||||
|
||||
kallsyms-objs := kallsyms.o kallsyms-sysmap.o elf-parse.o
|
||||
sorttable-objs := sorttable.o elf-parse.o
|
||||
tracepoint-update-objs := tracepoint-update.o elf-parse.o
|
||||
|
||||
|
|
@ -30,6 +31,8 @@ rustdoc_test_builder-rust := y
|
|||
rustdoc_test_gen-rust := y
|
||||
|
||||
HOSTCFLAGS_tracepoint-update.o = -I$(srctree)/tools/include
|
||||
HOSTCFLAGS_kallsyms.o = -I$(srctree)/tools/include
|
||||
HOSTCFLAGS_kallsyms-sysmap.o = -I$(srctree)/tools/include
|
||||
HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include
|
||||
HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
|
||||
HOSTLDLIBS_sorttable = -lpthread
|
||||
|
|
@ -53,6 +56,9 @@ ifdef CONFIG_BUILDTIME_MCOUNT_SORT
|
|||
HOSTCFLAGS_sorttable.o += -DMCOUNT_SORT_ENABLED
|
||||
endif
|
||||
|
||||
hostprogs += gen_init_cpio
|
||||
always-$(CONFIG_BLK_DEV_INITRD) += gen_init_cpio
|
||||
|
||||
# The following programs are only built on demand
|
||||
hostprogs += unifdef gen_packed_field_checks
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ ifdef CONFIG_LTO_CLANG_THIN
|
|||
KBUILD_LDFLAGS += --lto-sample-profile=$(CLANG_AUTOFDO_PROFILE)
|
||||
endif
|
||||
KBUILD_LDFLAGS += --mllvm=-enable-fs-discriminator=true --mllvm=-improved-fs-discriminator=true -plugin-opt=thinlto
|
||||
KBUILD_LDFLAGS += -plugin-opt=-split-machine-functions
|
||||
KBUILD_LDFLAGS += $(call ld-option,-plugin-opt=-function-splitting=all,-plugin-opt=-split-machine-functions)
|
||||
endif
|
||||
|
||||
export CFLAGS_AUTOFDO_CLANG RUSTFLAGS_AUTOFDO_CLANG
|
||||
|
|
|
|||
|
|
@ -306,6 +306,27 @@ quiet_cmd_cc_lst_c = MKLST $@
|
|||
$(obj)/%.lst: $(obj)/%.c FORCE
|
||||
$(call if_changed_dep,cc_lst_c)
|
||||
|
||||
# Compile C headers (.h) for header check
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Check a header is self-contained, has header guards, and passes kernel-doc.
|
||||
#
|
||||
# This is for 'make HEADER_CHECK=(headers|dirs) headercheck'. Not to be confused
|
||||
# with CONFIG_UAPI_HEADER_TEST.
|
||||
#
|
||||
# Please do *not* plug %.header-check into any configurable targets, unless you
|
||||
# also figure out a way to completely hide the %.header-check artefacts.
|
||||
|
||||
quiet_cmd_header_check = HDRCHK $(patsubst %.header-check,%.h,$@)
|
||||
cmd_header_check = \
|
||||
$(CC) $(c_flags) -fsyntax-only -x c /dev/null -include $< -include $<; \
|
||||
PYTHONDONTWRITEBYTECODE=1 $(PYTHON3) $(KERNELDOC) -none $(KDOCFLAGS) \
|
||||
$(if $(findstring e, $(KBUILD_EXTRA_WARN))$(CONFIG_WERROR),-Werror) $<; \
|
||||
touch $@
|
||||
|
||||
$(obj)/%.header-check: $(obj)/%.h FORCE
|
||||
$(call if_changed_dep,header_check)
|
||||
|
||||
# Compile Rust sources (.rs)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY
|
|||
endif
|
||||
export DISABLE_LATENT_ENTROPY_PLUGIN
|
||||
|
||||
# Disable recording GCC options in debug info when building external modules to
|
||||
# avoid leaking absolute host build paths
|
||||
gcc-plugin-cflags-$(if $(KBUILD_EXTMOD),y) += -gno-record-gcc-switches
|
||||
|
||||
# All the plugin CFLAGS are collected here in case a build target needs to
|
||||
# filter them out of the KBUILD_CFLAGS.
|
||||
GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) -DGCC_PLUGINS
|
||||
|
|
|
|||
|
|
@ -333,11 +333,11 @@ quiet_cmd_ar = AR $@
|
|||
quiet_cmd_objcopy = OBJCOPY $@
|
||||
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
|
||||
|
||||
# Gzip
|
||||
# Gzip, for the kernel image
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
quiet_cmd_gzip = GZIP $@
|
||||
cmd_gzip = cat $(real-prereqs) | $(KGZIP) -n -f -9 > $@
|
||||
cmd_gzip = cat $(real-prereqs) | $(KPGZIP) -n -f -9 > $@
|
||||
|
||||
# Bzip2
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ tar%-pkg: linux-$(KERNELRELEASE)-$(ARCH).tar.% FORCE
|
|||
$(Q)$(MAKE) -f $(srctree)/Makefile INSTALL_MOD_PATH=$@/$(INSTALL_MOD_PATH) modules_install
|
||||
|
||||
quiet_cmd_cpio = CPIO $@
|
||||
cmd_cpio = $(CONFIG_SHELL) $(srctree)/usr/gen_initramfs.sh -o $@ $<
|
||||
cmd_cpio = $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs.sh -o $@ $<
|
||||
|
||||
modules-$(KERNELRELEASE)-$(ARCH).cpio: .tmp_modules_cpio
|
||||
$(call cmd,cpio)
|
||||
|
|
|
|||
|
|
@ -89,11 +89,8 @@ remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel.*'
|
|||
|
||||
remove-symbols := -w --strip-unneeded-symbol='__mod_device_table__*'
|
||||
|
||||
# To avoid warnings: "empty loadable segment detected at ..." from GNU objcopy,
|
||||
# it is necessary to remove the PT_LOAD flag from the segment.
|
||||
quiet_cmd_strip_relocs = OBJCOPY $@
|
||||
cmd_strip_relocs = $(OBJCOPY) $(patsubst %,--set-section-flags %=noload,$(remove-section-y)) $< $@; \
|
||||
$(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $@
|
||||
cmd_strip_relocs = $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $< $@
|
||||
|
||||
targets += vmlinux
|
||||
vmlinux: vmlinux.unstripped FORCE
|
||||
|
|
@ -102,21 +99,8 @@ vmlinux: vmlinux.unstripped FORCE
|
|||
# modules.builtin.modinfo
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# .modinfo in vmlinux.unstripped is aligned to 8 bytes for compatibility with
|
||||
# tools that expect vmlinux to have sufficiently aligned sections but the
|
||||
# additional bytes used for padding .modinfo to satisfy this requirement break
|
||||
# certain versions of kmod with
|
||||
#
|
||||
# depmod: ERROR: kmod_builtin_iter_next: unexpected string without modname prefix
|
||||
#
|
||||
# Strip the trailing padding bytes after extracting .modinfo to comply with
|
||||
# what kmod expects to parse.
|
||||
quiet_cmd_modules_builtin_modinfo = GEN $@
|
||||
cmd_modules_builtin_modinfo = $(cmd_objcopy); \
|
||||
sed -i 's/\x00\+$$/\x00/g' $@; \
|
||||
chmod -x $@
|
||||
|
||||
OBJCOPYFLAGS_modules.builtin.modinfo := -j .modinfo -O binary
|
||||
cmd_modules_builtin_modinfo = $(OBJCOPY) -O binary -j .modinfo --dump-section .modinfo=$@ $< /dev/null
|
||||
|
||||
targets += modules.builtin.modinfo
|
||||
modules.builtin.modinfo: vmlinux.unstripped FORCE
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ quiet_cmd_gen_initcalls_lds = GEN $@
|
|||
|
||||
.tmp_initcalls.lds: $(srctree)/scripts/generate_initcall_order.pl \
|
||||
vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
|
||||
$(call if_changed,gen_initcalls_lds)
|
||||
+$(call if_changed,gen_initcalls_lds)
|
||||
|
||||
targets := .tmp_initcalls.lds
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ KBUILD_CFLAGS += -Werror=strict-prototypes
|
|||
KBUILD_CFLAGS += -Wno-format-security
|
||||
KBUILD_CFLAGS += -Wno-trigraphs
|
||||
KBUILD_CFLAGS += -Wno-frame-address
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-address-of-packed-member)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_ADDRESS_OF_PACKED_MEMBER)
|
||||
KBUILD_CFLAGS += -Wmissing-declarations
|
||||
KBUILD_CFLAGS += -Wmissing-prototypes
|
||||
|
||||
|
|
@ -30,8 +30,8 @@ KBUILD_CFLAGS-$(CONFIG_CC_NO_ARRAY_BOUNDS) += -Wno-array-bounds
|
|||
ifdef CONFIG_CC_IS_CLANG
|
||||
# Clang checks for overflow/truncation with '%p', while GCC does not:
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111219
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-format-overflow-non-kprintf)
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-format-truncation-non-kprintf)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_FORMAT_OVERFLOW_NON_KPRINTF)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_FORMAT_TRUNCATION_NON_KPRINTF)
|
||||
|
||||
# Clang may emit a warning when a const variable, such as the dummy variables
|
||||
# in typecheck(), or const member of an aggregate type are not initialized,
|
||||
|
|
@ -43,7 +43,7 @@ KBUILD_CFLAGS += $(call cc-option, -Wno-format-truncation-non-kprintf)
|
|||
# disabled with this same switch, there should not be too much coverage lost
|
||||
# because -Wuninitialized will still flag when an uninitialized const variable
|
||||
# is used.
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-default-const-init-unsafe)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_DEFAULT_CONST_INIT_UNSAFE)
|
||||
else
|
||||
|
||||
# gcc inanely warns about local variables called 'main'
|
||||
|
|
@ -54,7 +54,7 @@ endif
|
|||
KBUILD_CFLAGS += -Wno-type-limits
|
||||
|
||||
# These result in bogus false positives
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-dangling-pointer)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_DANGLING_POINTER)
|
||||
|
||||
# Stack Variable Length Arrays (VLAs) must not be used in the kernel.
|
||||
# Function array parameters should, however, be usable, but -Wvla will
|
||||
|
|
@ -62,7 +62,7 @@ KBUILD_CFLAGS += $(call cc-option, -Wno-dangling-pointer)
|
|||
# types, so depend on GCC for now to keep stack VLAs out of the tree.
|
||||
# https://github.com/llvm/llvm-project/issues/57098
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98217
|
||||
KBUILD_CFLAGS += $(call cc-option,-Wvla-larger-than=1)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WVLA_LARGER_THAN)
|
||||
|
||||
# disable pointer signed / unsigned warnings in gcc 4.0
|
||||
KBUILD_CFLAGS += -Wno-pointer-sign
|
||||
|
|
@ -73,11 +73,11 @@ KBUILD_CFLAGS += -Wno-pointer-sign
|
|||
KBUILD_CFLAGS += -Wcast-function-type
|
||||
|
||||
# Currently, disable -Wstringop-overflow for GCC 11, globally.
|
||||
KBUILD_CFLAGS-$(CONFIG_CC_NO_STRINGOP_OVERFLOW) += $(call cc-option, -Wno-stringop-overflow)
|
||||
KBUILD_CFLAGS-$(CONFIG_CC_STRINGOP_OVERFLOW) += $(call cc-option, -Wstringop-overflow)
|
||||
KBUILD_CFLAGS-$(CONFIG_CC_NO_STRINGOP_OVERFLOW) += $(if $(CONFIG_CC_HAS_WSTRINGOP_OVERFLOW),-Wno-stringop-overflow)
|
||||
KBUILD_CFLAGS-$(CONFIG_CC_STRINGOP_OVERFLOW) += $(if $(CONFIG_CC_HAS_WSTRINGOP_OVERFLOW),-Wstringop-overflow)
|
||||
|
||||
# Currently, disable -Wunterminated-string-initialization as broken
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-unterminated-string-initialization)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_UNTERMINATED_STRING_INITIALIZATION)
|
||||
|
||||
# The allocators already balk at large sizes, so silence the compiler
|
||||
# warnings for bounds checks involving those possible values. While
|
||||
|
|
@ -100,10 +100,10 @@ KBUILD_CFLAGS += -Werror=date-time
|
|||
KBUILD_CFLAGS += -Werror=incompatible-pointer-types
|
||||
|
||||
# Require designated initializers for all marked structures
|
||||
KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WERROR_DESIGNATED_INIT)
|
||||
|
||||
# Warn if there is an enum types mismatch
|
||||
KBUILD_CFLAGS += $(call cc-option,-Wenum-conversion)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WENUM_CONVERSION)
|
||||
|
||||
KBUILD_CFLAGS += -Wunused
|
||||
|
||||
|
|
@ -125,12 +125,12 @@ else
|
|||
# Suppress them by using -Wno... except for W=1.
|
||||
KBUILD_CFLAGS += -Wno-unused-but-set-variable
|
||||
KBUILD_CFLAGS += -Wno-unused-const-variable
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-packed-not-aligned)
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-format-overflow)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_PACKED_NOT_ALIGNED)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_FORMAT_OVERFLOW)
|
||||
ifdef CONFIG_CC_IS_GCC
|
||||
KBUILD_CFLAGS += -Wno-format-truncation
|
||||
endif
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-stringop-truncation)
|
||||
KBUILD_CFLAGS += $(CONFIG_CC_OPT_WNO_STRINGOP_TRUNCATION)
|
||||
|
||||
KBUILD_CFLAGS += -Wno-override-init # alias for -Wno-initializer-overrides in clang
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ if [ ! -f "$objfile" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
bad_symbols=$(${NM:-nm} "$objfile" | awk '$2 ~ /^[TtWw]$/ {print $3}' | grep -E '^(startup|exit|split|unlikely|hot|unknown)(\.|$)')
|
||||
bad_symbols=$(${NM:-nm} -p "$objfile" | awk '$2 ~ /^[TtWw]$/ {print $3}' |
|
||||
grep -E '^(startup|exit|split|unlikely|hot|unknown)(\.|$)')
|
||||
|
||||
if [ -n "$bad_symbols" ]; then
|
||||
echo "$bad_symbols" | while read -r sym; do
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ def tree_is_dirty():
|
|||
"""Return true if the current working tree is dirty (i.e., if any file has
|
||||
been added, deleted, modified, renamed or copied but not committed)."""
|
||||
stdout = execute(["git", "status", "--porcelain"])
|
||||
for line in stdout:
|
||||
for line in stdout.splitlines():
|
||||
if re.findall(r"[URMADC]{1}", line[:2]):
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ compile_commands.json.
|
|||
import argparse
|
||||
import json
|
||||
import multiprocessing
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (C) 2025 Guillaume Tucker
|
||||
# Copyright (C) 2025-2026 Guillaume Tucker
|
||||
|
||||
"""Containerized builds"""
|
||||
|
||||
import abc
|
||||
import argparse
|
||||
import dataclasses
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tomllib
|
||||
import uuid
|
||||
|
||||
|
||||
|
|
@ -20,10 +22,17 @@ class ContainerRuntime(abc.ABC):
|
|||
|
||||
name = None # Property defined in each implementation class
|
||||
|
||||
def __init__(self, args, logger):
|
||||
self._uid = args.uid or os.getuid()
|
||||
self._gid = args.gid or args.uid or os.getgid()
|
||||
self._env_file = args.env_file
|
||||
def __init__(self, args, config, logger):
|
||||
def _first_not_none(*args):
|
||||
return next((item for item in args if item is not None))
|
||||
|
||||
self._uid = _first_not_none(
|
||||
args.uid, config.uid, os.getuid()
|
||||
)
|
||||
self._gid = _first_not_none(
|
||||
args.gid, config.gid, args.uid, config.uid, os.getgid()
|
||||
)
|
||||
self._env_file = args.env_file or config.env_file
|
||||
self._shell = args.shell
|
||||
self._logger = logger
|
||||
|
||||
|
|
@ -131,6 +140,42 @@ class Runtimes:
|
|||
raise ValueError("no runtime found")
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Config:
|
||||
"""Container configuration"""
|
||||
image: str = None
|
||||
runtime: str = None
|
||||
env_file: str = None
|
||||
uid: int = None
|
||||
gid: int = None
|
||||
|
||||
@classmethod
|
||||
def from_toml(cls, config_file_path, profile_name):
|
||||
"""Create a config object from a TOML file"""
|
||||
if not config_file_path:
|
||||
config_file_path = '.container.toml'
|
||||
if not os.path.exists(config_file_path):
|
||||
return cls()
|
||||
elif not os.path.exists(config_file_path):
|
||||
raise ValueError(f"config file not found: {config_file_path}")
|
||||
with open(config_file_path, 'rb') as config_file:
|
||||
config = tomllib.load(config_file)
|
||||
default = config.get('DEFAULT', {})
|
||||
if not profile_name:
|
||||
profile = {}
|
||||
else:
|
||||
profile = config.get(profile_name)
|
||||
if profile is None:
|
||||
raise ValueError(f"unknown profile: {profile_name}")
|
||||
kwargs = {
|
||||
name: type(value) for (name, type, value) in (
|
||||
(op.name, op.type, profile.get(op.name, default.get(op.name)))
|
||||
for op in dataclasses.fields(cls)
|
||||
) if value is not None
|
||||
}
|
||||
return cls(**kwargs)
|
||||
|
||||
|
||||
def _get_logger(verbose):
|
||||
"""Set up a logger with the appropriate level"""
|
||||
logger = logging.getLogger('container')
|
||||
|
|
@ -147,13 +192,19 @@ def main(args):
|
|||
"""Main entry point for the container tool"""
|
||||
logger = _get_logger(args.verbose)
|
||||
try:
|
||||
cls = Runtimes.get(args.runtime) if args.runtime else Runtimes.find()
|
||||
config = Config.from_toml(args.config_file, args.config_profile)
|
||||
runtime = args.runtime or config.runtime
|
||||
cls = Runtimes.get(runtime) if runtime else Runtimes.find()
|
||||
except ValueError as ex:
|
||||
logger.error(ex)
|
||||
return 1
|
||||
logger.debug("runtime: %s", cls.name)
|
||||
logger.debug("image: %s", args.image)
|
||||
return cls(args, logger).run(args.image, args.cmd)
|
||||
image = args.image or config.image
|
||||
if not image:
|
||||
logger.error("no image specified")
|
||||
return 1
|
||||
logger.debug("image: %s", image)
|
||||
return cls(args, config, logger).run(image, args.cmd)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
@ -162,18 +213,28 @@ if __name__ == '__main__':
|
|||
description="See the documentation for more details: "
|
||||
"https://docs.kernel.org/dev-tools/container.html"
|
||||
)
|
||||
parser.add_argument(
|
||||
'-c', '--config-file',
|
||||
help="Path to the config file. If not specified, the default is to "
|
||||
"look for .container.toml in the current working directory."
|
||||
)
|
||||
parser.add_argument(
|
||||
'-e', '--env-file',
|
||||
help="Path to an environment file to load in the container."
|
||||
)
|
||||
parser.add_argument(
|
||||
'-g', '--gid',
|
||||
'-g', '--gid', type=int,
|
||||
help="Group ID to use inside the container."
|
||||
)
|
||||
parser.add_argument(
|
||||
'-i', '--image', required=True,
|
||||
'-i', '--image',
|
||||
help="Container image name."
|
||||
)
|
||||
parser.add_argument(
|
||||
'-p', '--config-profile',
|
||||
help="Profile section to use in the config file. This will override "
|
||||
"any values defined in the DEFAULT section."
|
||||
)
|
||||
parser.add_argument(
|
||||
'-r', '--runtime', choices=Runtimes.get_names(),
|
||||
help="Container runtime name. If not specified, the first one found "
|
||||
|
|
@ -184,9 +245,10 @@ if __name__ == '__main__':
|
|||
help="Run the container in an interactive shell."
|
||||
)
|
||||
parser.add_argument(
|
||||
'-u', '--uid',
|
||||
'-u', '--uid', type=int,
|
||||
help="User ID to use inside the container. If the -g option is not "
|
||||
"specified, the user ID will also be set as the group ID."
|
||||
"specified and no group ID is defined in the configuration file, the "
|
||||
"user ID will also be set as the group ID."
|
||||
)
|
||||
parser.add_argument(
|
||||
'-v', '--verbose', action='store_true',
|
||||
|
|
|
|||
|
|
@ -17,15 +17,21 @@ struct elf_funcs elf_parser;
|
|||
* Get the whole file as a programming convenience in order to avoid
|
||||
* malloc+lseek+read+free of many pieces. If successful, then mmap
|
||||
* avoids copying unused pieces; else just read the whole file.
|
||||
* Open for both read and write.
|
||||
* Open for both read and write if writable is true, otherwise open
|
||||
* read-only.
|
||||
*/
|
||||
static void *map_file(char const *fname, size_t *size)
|
||||
static void *map_file(char const *fname, size_t *size, bool writable)
|
||||
{
|
||||
int fd;
|
||||
int fd, prot = PROT_READ, flags = MAP_PRIVATE;
|
||||
struct stat sb;
|
||||
void *addr = NULL;
|
||||
|
||||
fd = open(fname, O_RDWR);
|
||||
if (writable) {
|
||||
prot |= PROT_WRITE;
|
||||
flags = MAP_SHARED;
|
||||
}
|
||||
|
||||
fd = open(fname, writable ? O_RDWR : O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror(fname);
|
||||
return NULL;
|
||||
|
|
@ -39,7 +45,7 @@ static void *map_file(char const *fname, size_t *size)
|
|||
goto out;
|
||||
}
|
||||
|
||||
addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
addr = mmap(0, sb.st_size, prot, flags, fd, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
fprintf(stderr, "Could not mmap file: %s\n", fname);
|
||||
goto out;
|
||||
|
|
@ -57,6 +63,12 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
|
|||
Elf_Ehdr *ehdr = addr;
|
||||
uint16_t type;
|
||||
|
||||
if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
|
||||
ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
fprintf(stderr, "unrecognized ELF file %s\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (ehdr->e32.e_ident[EI_DATA]) {
|
||||
case ELFDATA2LSB:
|
||||
elf_parser.r = rle;
|
||||
|
|
@ -78,12 +90,6 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
|
||||
ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
fprintf(stderr, "unrecognized ELF file %s\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
type = elf_parser.r2(&ehdr->e32.e_type);
|
||||
if (!((1 << type) & types)) {
|
||||
fprintf(stderr, "Invalid ELF type file %s\n", fname);
|
||||
|
|
@ -103,7 +109,9 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
|
|||
elf_parser.shdr_name = shdr32_name;
|
||||
elf_parser.shdr_type = shdr32_type;
|
||||
elf_parser.shdr_entsize = shdr32_entsize;
|
||||
elf_parser.shdr_flags = shdr32_flags;
|
||||
elf_parser.sym_type = sym32_type;
|
||||
elf_parser.sym_bind = sym32_bind;
|
||||
elf_parser.sym_name = sym32_name;
|
||||
elf_parser.sym_value = sym32_value;
|
||||
elf_parser.sym_shndx = sym32_shndx;
|
||||
|
|
@ -133,7 +141,9 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
|
|||
elf_parser.shdr_name = shdr64_name;
|
||||
elf_parser.shdr_type = shdr64_type;
|
||||
elf_parser.shdr_entsize = shdr64_entsize;
|
||||
elf_parser.shdr_flags = shdr64_flags;
|
||||
elf_parser.sym_type = sym64_type;
|
||||
elf_parser.sym_bind = sym64_bind;
|
||||
elf_parser.sym_name = sym64_name;
|
||||
elf_parser.sym_value = sym64_value;
|
||||
elf_parser.sym_shndx = sym64_shndx;
|
||||
|
|
@ -174,12 +184,13 @@ int elf_map_long_size(void *addr)
|
|||
return ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
|
||||
}
|
||||
|
||||
void *elf_map(char const *fname, size_t *size, uint32_t types)
|
||||
static void *__elf_map(char const *fname, size_t *size, uint32_t types,
|
||||
bool writable)
|
||||
{
|
||||
void *addr;
|
||||
int ret;
|
||||
|
||||
addr = map_file(fname, size);
|
||||
addr = map_file(fname, size, writable);
|
||||
if (!addr)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -192,7 +203,73 @@ void *elf_map(char const *fname, size_t *size, uint32_t types)
|
|||
return addr;
|
||||
}
|
||||
|
||||
void *elf_map(char const *fname, size_t *size, uint32_t types)
|
||||
{
|
||||
return __elf_map(fname, size, types, true);
|
||||
}
|
||||
|
||||
/* For tools that only read the file. */
|
||||
void *elf_map_ro(char const *fname, size_t *size, uint32_t types)
|
||||
{
|
||||
return __elf_map(fname, size, types, false);
|
||||
}
|
||||
|
||||
void elf_unmap(void *addr, size_t size)
|
||||
{
|
||||
munmap(addr, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open an ELF file and map it read-only, locating its section headers, section
|
||||
* names and symbol table which are populated in the elf out parameter.
|
||||
*
|
||||
* Returns 0 on success, otherwise -1.
|
||||
*/
|
||||
int elf_open_ro(char const *fname, uint32_t types, struct elf_file *elf)
|
||||
{
|
||||
Elf_Ehdr *ehdr;
|
||||
Elf_Shdr *first;
|
||||
unsigned int shstrndx, i;
|
||||
|
||||
memset(elf, 0, sizeof(*elf));
|
||||
elf->base = elf_map_ro(fname, &elf->size, types);
|
||||
if (!elf->base)
|
||||
return -1;
|
||||
|
||||
ehdr = elf->base;
|
||||
elf->shdrs = (const char *)elf->base + ehdr_shoff(ehdr);
|
||||
elf->shentsize = ehdr_shentsize(ehdr);
|
||||
first = elf_section(elf, 0);
|
||||
|
||||
/* A count or index too large for the header lives in section 0. */
|
||||
elf->shnum = ehdr_shnum(ehdr);
|
||||
if (elf->shnum == SHN_UNDEF)
|
||||
elf->shnum = shdr_size(first);
|
||||
shstrndx = ehdr_shstrndx(ehdr);
|
||||
if (shstrndx == SHN_XINDEX)
|
||||
shstrndx = shdr_link(first);
|
||||
elf->shstrtab = (const char *)elf->base +
|
||||
shdr_offset(elf_section(elf, shstrndx));
|
||||
|
||||
for (i = 0; i < elf->shnum && !elf->symtab; i++)
|
||||
if (shdr_type(elf_section(elf, i)) == SHT_SYMTAB)
|
||||
elf->symtab = elf_section(elf, i);
|
||||
|
||||
if (!elf->symtab) {
|
||||
fprintf(stderr, "%s: no symbol table\n", fname);
|
||||
elf_close(elf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
elf->strtab = (const char *)elf->base +
|
||||
shdr_offset(elf_section(elf, shdr_link(elf->symtab)));
|
||||
elf->nr_syms = shdr_size(elf->symtab) / shdr_entsize(elf->symtab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void elf_close(struct elf_file *elf)
|
||||
{
|
||||
elf_unmap(elf->base, elf->size);
|
||||
elf->base = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,10 +37,12 @@ struct elf_funcs {
|
|||
uint64_t (*shdr_offset)(Elf_Shdr *shdr);
|
||||
uint64_t (*shdr_size)(Elf_Shdr *shdr);
|
||||
uint64_t (*shdr_entsize)(Elf_Shdr *shdr);
|
||||
uint64_t (*shdr_flags)(Elf_Shdr *shdr);
|
||||
uint32_t (*shdr_link)(Elf_Shdr *shdr);
|
||||
uint32_t (*shdr_name)(Elf_Shdr *shdr);
|
||||
uint32_t (*shdr_type)(Elf_Shdr *shdr);
|
||||
uint8_t (*sym_type)(Elf_Sym *sym);
|
||||
uint8_t (*sym_bind)(Elf_Sym *sym);
|
||||
uint32_t (*sym_name)(Elf_Sym *sym);
|
||||
uint64_t (*sym_value)(Elf_Sym *sym);
|
||||
uint16_t (*sym_shndx)(Elf_Sym *sym);
|
||||
|
|
@ -143,6 +145,7 @@ SHDR_ADDR(addr)
|
|||
SHDR_ADDR(offset)
|
||||
SHDR_ADDR(size)
|
||||
SHDR_ADDR(entsize)
|
||||
SHDR_ADDR(flags)
|
||||
|
||||
SHDR_WORD(link)
|
||||
SHDR_WORD(name)
|
||||
|
|
@ -211,6 +214,21 @@ static inline uint8_t sym_type(Elf_Sym *sym)
|
|||
return elf_parser.sym_type(sym);
|
||||
}
|
||||
|
||||
static inline uint8_t sym64_bind(Elf_Sym *sym)
|
||||
{
|
||||
return ELF64_ST_BIND(sym->e64.st_info);
|
||||
}
|
||||
|
||||
static inline uint8_t sym32_bind(Elf_Sym *sym)
|
||||
{
|
||||
return ELF32_ST_BIND(sym->e32.st_info);
|
||||
}
|
||||
|
||||
static inline uint8_t sym_bind(Elf_Sym *sym)
|
||||
{
|
||||
return elf_parser.sym_bind(sym);
|
||||
}
|
||||
|
||||
SYM_ADDR(value)
|
||||
SYM_WORD(name)
|
||||
SYM_HALF(shndx)
|
||||
|
|
@ -298,8 +316,44 @@ static inline void w8le(uint64_t val, uint64_t *x)
|
|||
}
|
||||
|
||||
void *elf_map(char const *fname, size_t *size, uint32_t types);
|
||||
void *elf_map_ro(char const *fname, size_t *size, uint32_t types);
|
||||
void elf_unmap(void *addr, size_t size);
|
||||
int elf_map_machine(void *addr);
|
||||
int elf_map_long_size(void *addr);
|
||||
|
||||
/* A mapped file with its section headers, section names and symbol table. */
|
||||
struct elf_file {
|
||||
void *base;
|
||||
size_t size;
|
||||
const char *shdrs;
|
||||
unsigned int shnum, shentsize;
|
||||
const char *shstrtab;
|
||||
Elf_Shdr *symtab;
|
||||
const char *strtab;
|
||||
size_t nr_syms;
|
||||
};
|
||||
|
||||
int elf_open_ro(char const *fname, uint32_t types, struct elf_file *elf);
|
||||
void elf_close(struct elf_file *elf);
|
||||
|
||||
static inline Elf_Shdr *elf_section(const struct elf_file *elf,
|
||||
unsigned int index)
|
||||
{
|
||||
return (Elf_Shdr *)(elf->shdrs + (size_t)index * elf->shentsize);
|
||||
}
|
||||
|
||||
static inline const char *elf_section_name(const struct elf_file *elf,
|
||||
Elf_Shdr *shdr)
|
||||
{
|
||||
return elf->shstrtab + shdr_name(shdr);
|
||||
}
|
||||
|
||||
static inline Elf_Sym *elf_symbol(const struct elf_file *elf, size_t index)
|
||||
{
|
||||
const char *base = elf->base;
|
||||
|
||||
return (Elf_Sym *)(base + shdr_offset(elf->symtab) +
|
||||
index * shdr_entsize(elf->symtab));
|
||||
}
|
||||
|
||||
#endif /* _SCRIPTS_ELF_PARSE_H */
|
||||
|
|
|
|||
|
|
@ -756,6 +756,7 @@ int main (int argc, char *argv[])
|
|||
"ERROR: incorrect format, newline required line %d: '%s'\n",
|
||||
line_nr, line);
|
||||
ec = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
# Generate a cpio packed initramfs. It uses gen_init_cpio to generate
|
||||
# the cpio archive.
|
||||
# This script assumes that gen_init_cpio is located in usr/ directory
|
||||
# This script assumes that gen_init_cpio is located in scripts/ directory
|
||||
|
||||
# error out on errors
|
||||
set -e
|
||||
|
|
@ -247,4 +247,4 @@ done
|
|||
|
||||
# If output_file is set we will generate cpio archive
|
||||
# we are careful to delete tmp files
|
||||
usr/gen_init_cpio $output $timestamp $cpio_list
|
||||
scripts/gen_init_cpio $output $timestamp $cpio_list
|
||||
|
|
@ -4,7 +4,8 @@
|
|||
"""
|
||||
Determines how many parallel tasks "make" is expecting, as it is
|
||||
not exposed via any special variables, reserves them all, runs a subprocess
|
||||
with PARALLELISM environment variable set, and releases the jobs back again.
|
||||
with PARALLELISM environment variable set and any %PARALLELISM% in its
|
||||
arguments replaced by the count, and releases the jobs back again.
|
||||
|
||||
See:
|
||||
https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html#POSIX-Jobserver
|
||||
|
|
|
|||
248
scripts/kallsyms-sysmap.c
Normal file
248
scripts/kallsyms-sysmap.c
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Obtain symbols from vmlinux for usage by kallsyms. Replaces mksysmap.
|
||||
*
|
||||
* To retain compatibility, it provides the same output as nm, only faster.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#include "elf-parse.h"
|
||||
#include "kallsyms.h"
|
||||
|
||||
/*
|
||||
* What mksysmap dropped from System.map, by name: symbols that are not needed
|
||||
* there, or not suitable for kallsyms.
|
||||
*/
|
||||
static const char *const sysmap_omit_prefixes[] = {
|
||||
/* local symbols for ARM, MIPS, etc. */
|
||||
"$",
|
||||
/* local labels, .LBB, .Ltmpxxx, .L__unnamed_xx, .LASANPC, etc. */
|
||||
".L",
|
||||
/* arm64 EFI stub namespace */
|
||||
"__efistub_",
|
||||
/* arm64 local symbols in PIE namespace */
|
||||
"__pi_$",
|
||||
"__pi_.L",
|
||||
/* arm64 local symbols in non-VHE KVM namespace */
|
||||
"__kvm_nvhe_$",
|
||||
"__kvm_nvhe_.L",
|
||||
/* CFI type identifiers */
|
||||
"__kcfi_typeid_",
|
||||
"__kvm_nvhe___kcfi_typeid_",
|
||||
"__pi___kcfi_typeid_",
|
||||
/* CRC from modversions */
|
||||
"__crc_",
|
||||
/* EXPORT_SYMBOL (symbol name) */
|
||||
"__kstrtab_",
|
||||
/* EXPORT_SYMBOL (namespace) */
|
||||
"__kstrtabns_",
|
||||
/* MODULE_DEVICE_TABLE (symbol name) */
|
||||
"__mod_device_table__",
|
||||
};
|
||||
|
||||
static const char *const sysmap_omit_suffixes[] = {
|
||||
/* arm */
|
||||
"_from_arm",
|
||||
"_from_thumb",
|
||||
"_veneer",
|
||||
};
|
||||
|
||||
static const char *const sysmap_omit_names[] = {
|
||||
/* for LoongArch? */
|
||||
"L0",
|
||||
/* ppc */
|
||||
"_SDA_BASE_",
|
||||
"_SDA2_BASE_",
|
||||
};
|
||||
|
||||
/* Symbols that contain the pattern anywhere are dropped. */
|
||||
static const char *const sysmap_omit_patterns[] = {
|
||||
/* ppc stub */
|
||||
".long_branch.",
|
||||
".plt_branch.",
|
||||
};
|
||||
|
||||
/* __<alnum>*Thunk_: the linker's range extension thunks on arm. */
|
||||
static bool is_range_thunk(const char *name)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if (!string_starts_with(name, "__"))
|
||||
return false;
|
||||
for (p = name + 2; isalnum((unsigned char)*p); p++)
|
||||
;
|
||||
return p - name >= 7 && *p == '_' && strncmp(p - 5, "Thunk", 5) == 0;
|
||||
}
|
||||
|
||||
/* __UNIQUE_ID_modinfo_<n>: the MODULE_INFO() strings of built-in code. */
|
||||
static bool is_modinfo_id(const char *name)
|
||||
{
|
||||
static const char prefix[] = "__UNIQUE_ID_modinfo_";
|
||||
const char *p;
|
||||
|
||||
if (!string_starts_with(name, prefix))
|
||||
return false;
|
||||
for (p = name + strlen(prefix); isdigit((unsigned char)*p); p++)
|
||||
;
|
||||
return !*p;
|
||||
}
|
||||
|
||||
static bool sysmap_omits(const char *name, char type)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* Absolute, undefined and debugging symbols. */
|
||||
if (type == 'a' || type == 'N' || type == 'U' || type == 'w')
|
||||
return true;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sysmap_omit_prefixes); i++)
|
||||
if (string_starts_with(name, sysmap_omit_prefixes[i]))
|
||||
return true;
|
||||
for (i = 0; i < ARRAY_SIZE(sysmap_omit_suffixes); i++)
|
||||
if (string_ends_with(name, sysmap_omit_suffixes[i]))
|
||||
return true;
|
||||
for (i = 0; i < ARRAY_SIZE(sysmap_omit_names); i++)
|
||||
if (strcmp(name, sysmap_omit_names[i]) == 0)
|
||||
return true;
|
||||
for (i = 0; i < ARRAY_SIZE(sysmap_omit_patterns); i++)
|
||||
if (strstr(name, sysmap_omit_patterns[i]))
|
||||
return true;
|
||||
|
||||
return is_range_thunk(name) || is_modinfo_id(name);
|
||||
}
|
||||
|
||||
/* nm's letter for a symbol defined in a section, as BFD classifies it. */
|
||||
static char section_symbol_type(Elf_Shdr *shdr, const char *secname)
|
||||
{
|
||||
static const char *const debug_prefixes[] = {
|
||||
".debug", ".zdebug", ".gnu.debuglto_.debug_",
|
||||
".gnu.linkonce.wi.", ".line", ".stab",
|
||||
};
|
||||
const uint64_t flags = shdr_flags(shdr);
|
||||
size_t i;
|
||||
|
||||
if (flags & SHF_EXECINSTR)
|
||||
return 't';
|
||||
if (flags & SHF_ALLOC) {
|
||||
if (shdr_type(shdr) == SHT_NOBITS)
|
||||
return 'b';
|
||||
return flags & SHF_WRITE ? 'd' : 'r';
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(debug_prefixes); i++)
|
||||
if (string_starts_with(secname, debug_prefixes[i]))
|
||||
return 'N';
|
||||
if (shdr_type(shdr) != SHT_NOBITS && !(flags & SHF_WRITE))
|
||||
return 'n';
|
||||
return '?';
|
||||
}
|
||||
|
||||
/* The letter nm prints for a symbol, or 0 for one it leaves out. */
|
||||
static char elf_symbol_type(const struct elf_file *elf, Elf_Sym *sym)
|
||||
{
|
||||
unsigned int bind = sym_bind(sym), type = sym_type(sym);
|
||||
unsigned int shndx = sym_shndx(sym);
|
||||
Elf_Shdr *shdr;
|
||||
char c;
|
||||
|
||||
if (type == STT_SECTION || type == STT_FILE)
|
||||
return 0;
|
||||
if (shndx == SHN_COMMON)
|
||||
return 'C';
|
||||
if (shndx == SHN_UNDEF) {
|
||||
if (bind == STB_WEAK)
|
||||
return type == STT_OBJECT ? 'v' : 'w';
|
||||
return 'U';
|
||||
}
|
||||
if (type == STT_GNU_IFUNC)
|
||||
return 'i';
|
||||
if (bind == STB_WEAK)
|
||||
return type == STT_OBJECT ? 'V' : 'W';
|
||||
if (bind == STB_GNU_UNIQUE)
|
||||
return 'u';
|
||||
if (bind != STB_GLOBAL && bind != STB_LOCAL)
|
||||
return '?';
|
||||
|
||||
if (shndx == SHN_ABS) {
|
||||
c = 'a';
|
||||
} else if (shndx < elf->shnum) {
|
||||
shdr = elf_section(elf, shndx);
|
||||
c = section_symbol_type(shdr, elf_section_name(elf, shdr));
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
|
||||
return bind == STB_GLOBAL ? toupper(c) : c;
|
||||
}
|
||||
|
||||
/* nm -n order: by address, then by name. */
|
||||
static int compare_symbols(const void *a, const void *b)
|
||||
{
|
||||
const struct sysmap_symbol *sa = a, *sb = b;
|
||||
|
||||
if (sa->addr != sb->addr)
|
||||
return sa->addr < sb->addr ? -1 : 1;
|
||||
return strcmp(sa->name, sb->name);
|
||||
}
|
||||
|
||||
/* The symbols "nm -n | mksysmap" would list, in that order. */
|
||||
static struct sysmap_symbol *elf_read_symbols(const struct elf_file *elf,
|
||||
size_t *nr_kept)
|
||||
{
|
||||
struct sysmap_symbol *syms = xmalloc(elf->nr_syms * sizeof(*syms));
|
||||
size_t i, n = 0;
|
||||
|
||||
for (i = 1; i < elf->nr_syms; i++) {
|
||||
Elf_Sym *sym = elf_symbol(elf, i);
|
||||
const char *name = elf->strtab + sym_name(sym);
|
||||
char type = elf_symbol_type(elf, sym);
|
||||
|
||||
if (!type || sysmap_omits(name, type))
|
||||
continue;
|
||||
|
||||
syms[n].addr = sym_value(sym);
|
||||
syms[n].name = name;
|
||||
syms[n].type = type;
|
||||
n++;
|
||||
}
|
||||
|
||||
qsort(syms, n, sizeof(*syms), compare_symbols);
|
||||
*nr_kept = n;
|
||||
return syms;
|
||||
}
|
||||
|
||||
struct sysmap *sysmap_read(const char *path)
|
||||
{
|
||||
struct sysmap *map = xcalloc(1, sizeof(*map));
|
||||
|
||||
/* The names point into the mapping; keep it until the map is freed. */
|
||||
if (elf_open_ro(path, (1 << ET_EXEC) | (1 << ET_DYN), &map->elf))
|
||||
exit(EXIT_FAILURE);
|
||||
map->syms = elf_read_symbols(&map->elf, &map->nr_syms);
|
||||
map->addr_width = elf_map_long_size(map->elf.base) * 2;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
void sysmap_write(const struct sysmap *map, FILE *out)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < map->nr_syms; i++) {
|
||||
const struct sysmap_symbol *s = &map->syms[i];
|
||||
|
||||
fprintf(out, "%0*llx %c %s\n", map->addr_width, s->addr, s->type,
|
||||
s->name);
|
||||
}
|
||||
}
|
||||
|
||||
void sysmap_free(struct sysmap *map)
|
||||
{
|
||||
free(map->syms);
|
||||
elf_close(&map->elf);
|
||||
free(map);
|
||||
}
|
||||
|
|
@ -5,7 +5,15 @@
|
|||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
* Usage: kallsyms [--all-symbols] in.map > out.S
|
||||
* Usage: kallsyms [--all-symbols] [--pc-relative] [--sysmap=out.map] in out.bin > out.S
|
||||
* kallsyms --sysmap=out.map in
|
||||
*
|
||||
* in is vmlinux; an empty file stands for the first link, which has no
|
||||
* symbols yet, and gives an empty table. --sysmap also writes the symbols
|
||||
* in System.map format.
|
||||
*
|
||||
* The byte tables go to out.bin and are pulled into out.S with .incbin;
|
||||
* wider tables stay assembler source for endianness and relocations.
|
||||
*
|
||||
* Table compression uses all the unused char codes on the symbols and
|
||||
* maps these to the most used substrings (tokens). For instance, it might
|
||||
|
|
@ -18,7 +26,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -26,10 +33,10 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <xalloc.h>
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
#include "kallsyms.h"
|
||||
|
||||
#define KSYM_NAME_LEN 512
|
||||
|
||||
|
|
@ -58,20 +65,60 @@ static unsigned int table_size, table_cnt;
|
|||
static int all_symbols;
|
||||
static int pc_relative;
|
||||
|
||||
static int token_profit[0x10000];
|
||||
/* A dynamic array of symbols, encoded by symbol index. */
|
||||
struct sym_arr {
|
||||
unsigned int *sym_indexes;
|
||||
unsigned int cnt, cap;
|
||||
};
|
||||
|
||||
/* Every pair of bytes is a token. */
|
||||
#define NR_TOKENS 0x10000
|
||||
|
||||
static int token_profit[NR_TOKENS];
|
||||
static struct sym_arr token_syms[NR_TOKENS];
|
||||
|
||||
/* the table that holds the result of the compression */
|
||||
static unsigned char best_table[256][2];
|
||||
static unsigned char best_table_len[256];
|
||||
|
||||
static unsigned int sym_arr_last(const struct sym_arr *arr)
|
||||
{
|
||||
return arr->cnt ? arr->sym_indexes[arr->cnt - 1] : UINT_MAX;
|
||||
}
|
||||
|
||||
static void sym_arr_maybe_expand(struct sym_arr *arr)
|
||||
{
|
||||
if (arr->cap > arr->cnt)
|
||||
return;
|
||||
|
||||
arr->cap = arr->cap ? arr->cap * 2 : 16;
|
||||
arr->sym_indexes = xrealloc(arr->sym_indexes,
|
||||
arr->cap * sizeof(*arr->sym_indexes));
|
||||
}
|
||||
|
||||
static void sym_arr_add(struct sym_arr *arr, unsigned int sym_idx)
|
||||
{
|
||||
sym_arr_maybe_expand(arr);
|
||||
arr->sym_indexes[arr->cnt++] = sym_idx;
|
||||
}
|
||||
|
||||
static void sym_arr_free(struct sym_arr *arr)
|
||||
{
|
||||
free(arr->sym_indexes);
|
||||
arr->sym_indexes = NULL;
|
||||
arr->cnt = 0;
|
||||
arr->cap = 0;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: kallsyms [--all-symbols] in.map > out.S\n");
|
||||
fprintf(stderr, "Usage: kallsyms [--all-symbols] [--pc-relative] [--sysmap=out.map]\n"
|
||||
" in out.bin > out.S\n"
|
||||
" kallsyms --sysmap=out.map vmlinux\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static char *sym_name(const struct sym_entry *s)
|
||||
static char *sym_entry_name(const struct sym_entry *s)
|
||||
{
|
||||
return (char *)s->sym + 1;
|
||||
}
|
||||
|
|
@ -112,37 +159,12 @@ static void check_symbol_range(const char *sym, unsigned long long addr,
|
|||
}
|
||||
}
|
||||
|
||||
static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
|
||||
static struct sym_entry *add_symbol(unsigned long long addr, char type,
|
||||
const char *name)
|
||||
{
|
||||
char *name, type, *p;
|
||||
unsigned long long addr;
|
||||
size_t len;
|
||||
ssize_t readlen;
|
||||
size_t len = strlen(name);
|
||||
struct sym_entry *sym;
|
||||
|
||||
errno = 0;
|
||||
readlen = getline(buf, buf_len, in);
|
||||
if (readlen < 0) {
|
||||
if (errno) {
|
||||
perror("read_symbol");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((*buf)[readlen - 1] == '\n')
|
||||
(*buf)[readlen - 1] = 0;
|
||||
|
||||
addr = strtoull(*buf, &p, 16);
|
||||
|
||||
if (*buf == p || *p++ != ' ' || !isascii((type = *p++)) || *p++ != ' ') {
|
||||
fprintf(stderr, "line format error\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
name = p;
|
||||
len = strlen(name);
|
||||
|
||||
if (len >= KSYM_NAME_LEN) {
|
||||
fprintf(stderr, "Symbol %s too long for kallsyms (%zu >= %d).\n"
|
||||
"Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n",
|
||||
|
|
@ -167,7 +189,7 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
|
|||
sym->addr = addr;
|
||||
sym->len = len;
|
||||
sym->sym[0] = type;
|
||||
strcpy(sym_name(sym), name);
|
||||
strcpy(sym_entry_name(sym), name);
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
|
@ -188,14 +210,9 @@ static int symbol_in_range(const struct sym_entry *s,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool string_starts_with(const char *s, const char *prefix)
|
||||
{
|
||||
return strncmp(s, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
static int symbol_valid(const struct sym_entry *s)
|
||||
{
|
||||
const char *name = sym_name(s);
|
||||
const char *name = sym_entry_name(s);
|
||||
|
||||
/* if --all-symbols is not specified, then symbols outside the text
|
||||
* and inittext sections are discarded */
|
||||
|
|
@ -245,36 +262,55 @@ static void shrink_table(void)
|
|||
table_cnt = pos;
|
||||
}
|
||||
|
||||
static void read_map(const char *in)
|
||||
static void add_table_entry(struct sym_entry *sym)
|
||||
{
|
||||
FILE *fp;
|
||||
struct sym_entry *sym;
|
||||
char *buf = NULL;
|
||||
size_t buflen = 0;
|
||||
sym->seq = table_cnt;
|
||||
|
||||
fp = fopen(in, "r");
|
||||
if (!fp) {
|
||||
perror(in);
|
||||
exit(1);
|
||||
if (table_cnt >= table_size) {
|
||||
table_size = table_size ? table_size * 2 : 10000;
|
||||
table = xrealloc(table, sizeof(*table) * table_size);
|
||||
}
|
||||
|
||||
while (!feof(fp)) {
|
||||
sym = read_symbol(fp, &buf, &buflen);
|
||||
if (!sym)
|
||||
continue;
|
||||
table[table_cnt++] = sym;
|
||||
}
|
||||
|
||||
sym->seq = table_cnt;
|
||||
static bool file_is_empty(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (table_cnt >= table_size) {
|
||||
table_size += 10000;
|
||||
table = xrealloc(table, sizeof(*table) * table_size);
|
||||
}
|
||||
|
||||
table[table_cnt++] = sym;
|
||||
if (stat(path, &st)) {
|
||||
perror(path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
fclose(fp);
|
||||
return st.st_size == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the symbols from vmlinux, writing System.map if asked to. The first
|
||||
* link has no symbols yet: an empty file gives an empty table.
|
||||
*/
|
||||
static void read_elf(const char *path, FILE *sysmap_out)
|
||||
{
|
||||
struct sysmap *map;
|
||||
size_t i;
|
||||
|
||||
if (file_is_empty(path))
|
||||
return;
|
||||
|
||||
map = sysmap_read(path);
|
||||
if (sysmap_out)
|
||||
sysmap_write(map, sysmap_out);
|
||||
|
||||
for (i = 0; i < map->nr_syms; i++) {
|
||||
const struct sysmap_symbol *s = &map->syms[i];
|
||||
struct sym_entry *sym = add_symbol(s->addr, s->type, s->name);
|
||||
|
||||
if (sym)
|
||||
add_table_entry(sym);
|
||||
}
|
||||
|
||||
sysmap_free(map);
|
||||
}
|
||||
|
||||
static void output_label(const char *label)
|
||||
|
|
@ -284,6 +320,26 @@ static void output_label(const char *label)
|
|||
printf("%s:\n", label);
|
||||
}
|
||||
|
||||
static long bin_pos(FILE *file)
|
||||
{
|
||||
const long pos = ftell(file);
|
||||
|
||||
if (pos < 0) {
|
||||
perror("kallsyms: ftell");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void write_incbin(const char *filename, long start, long end)
|
||||
{
|
||||
if (start >= end)
|
||||
return;
|
||||
|
||||
printf("\t.incbin \"%s\", %ld, %ld\n", filename, start, end - start);
|
||||
}
|
||||
|
||||
/* uncompress a compressed symbol. When this function is called, the best table
|
||||
* might still be compressed itself, so the function needs to be recursive */
|
||||
static int expand_symbol(const unsigned char *data, int len, char *result)
|
||||
|
|
@ -317,7 +373,7 @@ static int compare_names(const void *a, const void *b)
|
|||
const struct sym_entry *sa = *(const struct sym_entry **)a;
|
||||
const struct sym_entry *sb = *(const struct sym_entry **)b;
|
||||
|
||||
ret = strcmp(sym_name(sa), sym_name(sb));
|
||||
ret = strcmp(sym_entry_name(sa), sym_entry_name(sb));
|
||||
if (!ret) {
|
||||
if (sa->addr > sb->addr)
|
||||
return 1;
|
||||
|
|
@ -336,11 +392,12 @@ static void sort_symbols_by_name(void)
|
|||
qsort(table, table_cnt, sizeof(table[0]), compare_names);
|
||||
}
|
||||
|
||||
static void write_src(void)
|
||||
static void write_src(FILE *out_bin_file, const char *out_bin_name)
|
||||
{
|
||||
unsigned int i, k, off;
|
||||
unsigned int i, off;
|
||||
unsigned int best_idx[256];
|
||||
unsigned int *markers, markers_cnt;
|
||||
long bin_start;
|
||||
char buf[KSYM_NAME_LEN];
|
||||
|
||||
printf("\t.section .rodata, \"a\"\n");
|
||||
|
|
@ -355,6 +412,7 @@ static void write_src(void)
|
|||
markers = xmalloc(sizeof(*markers) * markers_cnt);
|
||||
|
||||
output_label("kallsyms_names");
|
||||
bin_start = bin_pos(out_bin_file);
|
||||
off = 0;
|
||||
for (i = 0; i < table_cnt; i++) {
|
||||
if ((i & 0xFF) == 0)
|
||||
|
|
@ -378,26 +436,24 @@ static void write_src(void)
|
|||
/* Encode length with ULEB128. */
|
||||
if (table[i]->len <= 0x7F) {
|
||||
/* Most symbols use a single byte for the length. */
|
||||
printf("\t.byte 0x%02x", table[i]->len);
|
||||
fputc(table[i]->len, out_bin_file);
|
||||
off += table[i]->len + 1;
|
||||
} else {
|
||||
/* "Big" symbols use two bytes. */
|
||||
printf("\t.byte 0x%02x, 0x%02x",
|
||||
(table[i]->len & 0x7F) | 0x80,
|
||||
(table[i]->len >> 7) & 0x7F);
|
||||
fputc((table[i]->len & 0x7F) | 0x80, out_bin_file);
|
||||
fputc((table[i]->len >> 7) & 0x7F, out_bin_file);
|
||||
off += table[i]->len + 2;
|
||||
}
|
||||
for (k = 0; k < table[i]->len; k++)
|
||||
printf(", 0x%02x", table[i]->sym[k]);
|
||||
fwrite(table[i]->sym, 1, table[i]->len, out_bin_file);
|
||||
|
||||
/*
|
||||
* Now that we wrote out the compressed symbol name, restore the
|
||||
* original name and print it in the comment.
|
||||
* original name for the comments below.
|
||||
*/
|
||||
expand_symbol(table[i]->sym, table[i]->len, buf);
|
||||
strcpy((char *)table[i]->sym, buf);
|
||||
printf("\t/* %s */\n", table[i]->sym);
|
||||
}
|
||||
write_incbin(out_bin_name, bin_start, bin_pos(out_bin_file));
|
||||
printf(".size kallsyms_names, . - kallsyms_names\n");
|
||||
printf("\n");
|
||||
|
||||
|
|
@ -410,13 +466,15 @@ static void write_src(void)
|
|||
free(markers);
|
||||
|
||||
output_label("kallsyms_token_table");
|
||||
bin_start = bin_pos(out_bin_file);
|
||||
off = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
best_idx[i] = off;
|
||||
expand_symbol(best_table[i], best_table_len[i], buf);
|
||||
printf("\t.asciz\t\"%s\"\n", buf);
|
||||
fwrite(buf, 1, strlen(buf) + 1, out_bin_file);
|
||||
off += strlen(buf) + 1;
|
||||
}
|
||||
write_incbin(out_bin_name, bin_start, bin_pos(out_bin_file));
|
||||
printf(".size kallsyms_token_table, . - kallsyms_token_table\n");
|
||||
printf("\n");
|
||||
|
||||
|
|
@ -449,15 +507,25 @@ static void write_src(void)
|
|||
|
||||
sort_symbols_by_name();
|
||||
output_label("kallsyms_seqs_of_names");
|
||||
for (i = 0; i < table_cnt; i++)
|
||||
printf("\t.byte 0x%02x, 0x%02x, 0x%02x\t/* %s */\n",
|
||||
(unsigned char)(table[i]->seq >> 16),
|
||||
(unsigned char)(table[i]->seq >> 8),
|
||||
(unsigned char)(table[i]->seq >> 0),
|
||||
table[i]->sym);
|
||||
bin_start = bin_pos(out_bin_file);
|
||||
for (i = 0; i < table_cnt; i++) {
|
||||
fputc(table[i]->seq >> 16, out_bin_file);
|
||||
fputc(table[i]->seq >> 8, out_bin_file);
|
||||
fputc(table[i]->seq >> 0, out_bin_file);
|
||||
}
|
||||
write_incbin(out_bin_name, bin_start, bin_pos(out_bin_file));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static unsigned int token_index(unsigned char first, unsigned char second)
|
||||
{
|
||||
return first + (second << 8);
|
||||
}
|
||||
|
||||
static unsigned int sym_token_index(const unsigned char *symbol, int first_idx)
|
||||
{
|
||||
return token_index(symbol[first_idx], symbol[first_idx + 1]);
|
||||
}
|
||||
|
||||
/* table lookup compression functions */
|
||||
|
||||
|
|
@ -467,7 +535,7 @@ static void learn_symbol(const unsigned char *symbol, int len)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < len - 1; i++)
|
||||
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
|
||||
token_profit[sym_token_index(symbol, i)]++;
|
||||
}
|
||||
|
||||
/* decrease the count for all the possible tokens in a symbol */
|
||||
|
|
@ -476,16 +544,76 @@ static void forget_symbol(const unsigned char *symbol, int len)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < len - 1; i++)
|
||||
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
|
||||
token_profit[sym_token_index(symbol, i)]--;
|
||||
}
|
||||
|
||||
static void token_add_symbol(unsigned int token_idx, unsigned int sym_idx)
|
||||
{
|
||||
struct sym_arr *arr = &token_syms[token_idx];
|
||||
|
||||
/* Symbol indexes kept in sorted order, check for duplicate. */
|
||||
if (sym_arr_last(arr) == sym_idx)
|
||||
return;
|
||||
|
||||
sym_arr_add(arr, sym_idx);
|
||||
}
|
||||
|
||||
static void symbol_index_all_tokens(const unsigned char *symbol, int len,
|
||||
unsigned int sym_idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len - 1; i++) {
|
||||
const unsigned int token_idx = sym_token_index(symbol, i);
|
||||
|
||||
token_add_symbol(token_idx, sym_idx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The symbol just got compressed. The only parts of the symbol that changed
|
||||
* meaningfully are those containing the newly assigned compressed char, so
|
||||
* index those.
|
||||
*/
|
||||
static void symbol_index_new_tokens(const unsigned char *symbol, int len,
|
||||
unsigned int sym_idx, int compressed_chr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len - 1; i++) {
|
||||
const unsigned int token_idx = sym_token_index(symbol, i);
|
||||
|
||||
if (symbol[i] == compressed_chr ||
|
||||
symbol[i + 1] == compressed_chr)
|
||||
token_add_symbol(token_idx, sym_idx);
|
||||
}
|
||||
}
|
||||
|
||||
/* do the initial token count */
|
||||
static void build_initial_token_table(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < table_cnt; i++)
|
||||
learn_symbol(table[i]->sym, table[i]->len);
|
||||
|
||||
/*
|
||||
* The initial occurrence counts tell us exactly how much memory should
|
||||
* be reserved for each token's symbol array.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(token_syms); i++) {
|
||||
const int nr_syms = token_profit[i];
|
||||
|
||||
if (!nr_syms)
|
||||
continue;
|
||||
|
||||
token_syms[i].cap = nr_syms;
|
||||
token_syms[i].sym_indexes =
|
||||
xmalloc(nr_syms * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
/* For every symbol, index every token -> symbol it is present in. */
|
||||
for (i = 0; i < table_cnt; i++)
|
||||
symbol_index_all_tokens(table[i]->sym, table[i]->len, i);
|
||||
}
|
||||
|
||||
static unsigned char *find_token(unsigned char *str, int len,
|
||||
|
|
@ -502,27 +630,31 @@ static unsigned char *find_token(unsigned char *str, int len,
|
|||
|
||||
/* replace a given token in all the valid symbols. Use the sampled symbols
|
||||
* to update the counts */
|
||||
static void compress_symbols(const unsigned char *str, int idx)
|
||||
static void compress_symbols(const unsigned char *str, int compressed_chr)
|
||||
{
|
||||
unsigned int i, len, size;
|
||||
const unsigned int token_idx = sym_token_index(str, 0);
|
||||
struct sym_arr *arr = &token_syms[token_idx];
|
||||
unsigned int sym_idx, j, len, size;
|
||||
unsigned char *p1, *p2;
|
||||
|
||||
for (i = 0; i < table_cnt; i++) {
|
||||
/* Iterate through all symbols this token is found in and compress. */
|
||||
for (j = 0; j < arr->cnt; j++) {
|
||||
sym_idx = arr->sym_indexes[j];
|
||||
|
||||
len = table[i]->len;
|
||||
p1 = table[i]->sym;
|
||||
len = table[sym_idx]->len;
|
||||
p1 = table[sym_idx]->sym;
|
||||
|
||||
/* find the token on the symbol */
|
||||
p2 = find_token(p1, len, str);
|
||||
if (!p2) continue;
|
||||
|
||||
/* decrease the counts for this symbol's tokens */
|
||||
forget_symbol(table[i]->sym, len);
|
||||
forget_symbol(table[sym_idx]->sym, len);
|
||||
|
||||
size = len;
|
||||
|
||||
do {
|
||||
*p2 = idx;
|
||||
*p2 = compressed_chr;
|
||||
p2++;
|
||||
size -= (p2 - p1);
|
||||
memmove(p2, p2 + 1, size);
|
||||
|
|
@ -536,11 +668,15 @@ static void compress_symbols(const unsigned char *str, int idx)
|
|||
|
||||
} while (p2);
|
||||
|
||||
table[i]->len = len;
|
||||
table[sym_idx]->len = len;
|
||||
|
||||
/* increase the counts for this symbol's new tokens */
|
||||
learn_symbol(table[i]->sym, len);
|
||||
learn_symbol(table[sym_idx]->sym, len);
|
||||
symbol_index_new_tokens(table[sym_idx]->sym, len, sym_idx,
|
||||
compressed_chr);
|
||||
}
|
||||
|
||||
sym_arr_free(arr); /* No symbol contains this token any more. */
|
||||
}
|
||||
|
||||
/* search the token with the maximum profit */
|
||||
|
|
@ -551,7 +687,7 @@ static int find_best_token(void)
|
|||
bestprofit=-10000;
|
||||
best = 0;
|
||||
|
||||
for (i = 0; i < 0x10000; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(token_profit); i++) {
|
||||
if (token_profit[i] > bestprofit) {
|
||||
best = i;
|
||||
bestprofit = token_profit[i];
|
||||
|
|
@ -615,7 +751,7 @@ static void optimize_token_table(void)
|
|||
/* guess for "linker script provide" symbol */
|
||||
static int may_be_linker_script_provide_symbol(const struct sym_entry *se)
|
||||
{
|
||||
const char *symbol = sym_name(se);
|
||||
const char *symbol = sym_entry_name(se);
|
||||
int len = se->len - 1;
|
||||
|
||||
if (len < 8)
|
||||
|
|
@ -672,8 +808,8 @@ static int compare_symbols(const void *a, const void *b)
|
|||
return wa - wb;
|
||||
|
||||
/* sort by the number of prefix underscores */
|
||||
wa = strspn(sym_name(sa), "_");
|
||||
wb = strspn(sym_name(sb), "_");
|
||||
wa = strspn(sym_entry_name(sa), "_");
|
||||
wb = strspn(sym_entry_name(sb), "_");
|
||||
if (wa != wb)
|
||||
return wa - wb;
|
||||
|
||||
|
|
@ -688,10 +824,14 @@ static void sort_symbols(void)
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *in, *sysmap = NULL, *out_bin_name;
|
||||
FILE *sysmap_out = NULL, *out_bin_file;
|
||||
|
||||
while (1) {
|
||||
static const struct option long_options[] = {
|
||||
{"all-symbols", no_argument, &all_symbols, 1},
|
||||
{"pc-relative", no_argument, &pc_relative, 1},
|
||||
{"sysmap", required_argument, NULL, 's'},
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
@ -699,18 +839,55 @@ int main(int argc, char **argv)
|
|||
|
||||
if (c == -1)
|
||||
break;
|
||||
if (c != 0)
|
||||
if (c == 's')
|
||||
sysmap = optarg;
|
||||
else if (c != 0)
|
||||
usage();
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
if (optind + 2 != argc && !(sysmap && optind + 1 == argc))
|
||||
usage();
|
||||
|
||||
read_map(argv[optind]);
|
||||
in = argv[optind];
|
||||
if (sysmap) {
|
||||
sysmap_out = fopen(sysmap, "w");
|
||||
if (!sysmap_out) {
|
||||
perror(sysmap);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind + 1 == argc) {
|
||||
read_elf(in, sysmap_out);
|
||||
if (ferror(sysmap_out) || fclose(sysmap_out)) {
|
||||
perror(sysmap);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
out_bin_name = argv[optind + 1];
|
||||
out_bin_file = fopen(out_bin_name, "w");
|
||||
if (!out_bin_file) {
|
||||
perror(out_bin_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
read_elf(in, sysmap_out);
|
||||
if (sysmap_out && (ferror(sysmap_out) || fclose(sysmap_out))) {
|
||||
perror(sysmap);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
shrink_table();
|
||||
sort_symbols();
|
||||
optimize_token_table();
|
||||
write_src();
|
||||
write_src(out_bin_file, out_bin_name);
|
||||
|
||||
/* Write errors are latched in the stream, so one check at the end covers them all. */
|
||||
if (ferror(out_bin_file) || fclose(out_bin_file)) {
|
||||
perror(out_bin_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
44
scripts/kallsyms.h
Normal file
44
scripts/kallsyms.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef KALLSYMS_H
|
||||
#define KALLSYMS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <array_size.h>
|
||||
#include "elf-parse.h"
|
||||
|
||||
static inline bool string_starts_with(const char *s, const char *prefix)
|
||||
{
|
||||
return strncmp(s, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
static inline bool string_ends_with(const char *s, const char *suffix)
|
||||
{
|
||||
size_t len = strlen(s), suffix_len = strlen(suffix);
|
||||
|
||||
return len >= suffix_len && strcmp(s + len - suffix_len, suffix) == 0;
|
||||
}
|
||||
|
||||
/* A symbol as nm lists it. */
|
||||
struct sysmap_symbol {
|
||||
unsigned long long addr;
|
||||
const char *name;
|
||||
char type;
|
||||
};
|
||||
|
||||
/* The symbols of an ELF file that System.map lists, in its order. */
|
||||
struct sysmap {
|
||||
struct sysmap_symbol *syms;
|
||||
size_t nr_syms;
|
||||
int addr_width; /* hex digits of an address */
|
||||
struct elf_file elf; /* the mapping the names point into */
|
||||
};
|
||||
|
||||
struct sysmap *sysmap_read(const char *path);
|
||||
void sysmap_write(const struct sysmap *map, FILE *out);
|
||||
void sysmap_free(struct sysmap *map);
|
||||
|
||||
#endif /* KALLSYMS_H */
|
||||
|
|
@ -186,12 +186,23 @@ static void conf_set_all_new_symbols(enum conf_def_mode mode)
|
|||
|
||||
if (mode == def_random) {
|
||||
int n, p[3];
|
||||
bool warned = false;
|
||||
char *env = getenv("KCONFIG_PROBABILITY");
|
||||
|
||||
n = 0;
|
||||
while (env && *env) {
|
||||
char *endp;
|
||||
int tmp = strtol(env, &endp, 10);
|
||||
long tmp = strtol(env, &endp, 10);
|
||||
|
||||
if (!isdigit((unsigned char)*env) ||
|
||||
(*endp && *endp != ':') ||
|
||||
(*endp == ':' && (!endp[1] || n == 2))) {
|
||||
if (!warned) {
|
||||
fprintf(stderr,
|
||||
"warning: KCONFIG_PROBABILITY has malformed format\n");
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp >= 0 && tmp <= 100) {
|
||||
p[n++] = tmp;
|
||||
|
|
@ -227,6 +238,9 @@ static void conf_set_all_new_symbols(enum conf_def_mode mode)
|
|||
perror("KCONFIG_PROBABILITY");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (warned && getenv("KCONFIG_WERROR"))
|
||||
exit(1);
|
||||
}
|
||||
|
||||
menu_for_each_entry(menu) {
|
||||
|
|
@ -469,6 +483,9 @@ static void conf_choice(struct menu *menu)
|
|||
}
|
||||
printf("\n");
|
||||
}
|
||||
/* Nothing to ask if none of the choice values is visible. */
|
||||
if (!cnt)
|
||||
return;
|
||||
printf("%*schoice", indent - 1, "");
|
||||
if (cnt == 1) {
|
||||
printf("[1]: 1\n");
|
||||
|
|
|
|||
|
|
@ -354,6 +354,12 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
|
|||
case S_INT:
|
||||
case S_HEX:
|
||||
if (sym_string_valid(sym, p)) {
|
||||
if (def != S_DEF_AUTO &&
|
||||
!sym_string_check_bounds(sym, p))
|
||||
/* hex uses 64-bit unsigned integer */
|
||||
conf_warning("value '%s' for %s is outside the 64-bit %s integer bounds",
|
||||
p, sym->name,
|
||||
sym->type == S_INT ? "signed" : "unsigned");
|
||||
sym->def[def].val = xstrdup(p);
|
||||
sym->flags |= def_flags;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ foreach my $file (@files) {
|
|||
next;
|
||||
}
|
||||
|
||||
if (/^\s*(default|def_bool|def_tristate|select|depends\s+on|imply|visible\s+if|range|if|bool|tristate|int|hex|string|prompt)\s+(.+)\s*$/) {
|
||||
if (/^\s*(default|def_bool|def_tristate|def_string|def_int|def_hex|select|depends\s+on|imply|visible\s+if|range|if|bool|tristate|int|hex|string|prompt)\s+(.+)\s*$/) {
|
||||
my $s = $2;
|
||||
$s =~ s/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'//g;
|
||||
$s =~ s/#.*//;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,9 @@ n [A-Za-z0-9_-]
|
|||
"comment" return T_COMMENT;
|
||||
"config" return T_CONFIG;
|
||||
"def_bool" return T_DEF_BOOL;
|
||||
"def_hex" return T_DEF_HEX;
|
||||
"def_int" return T_DEF_INT;
|
||||
"def_string" return T_DEF_STRING;
|
||||
"def_tristate" return T_DEF_TRISTATE;
|
||||
"default" return T_DEFAULT;
|
||||
"depends" return T_DEPENDS;
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ struct property *menu_add_prompt(enum prop_type type, const char *prompt,
|
|||
struct expr *dep);
|
||||
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
|
||||
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
|
||||
void menu_finalize(void);
|
||||
int menu_finalize(void);
|
||||
void menu_set_type(int type);
|
||||
|
||||
extern struct menu rootmenu;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ bool sym_set_tristate_value(struct symbol *sym,tristate tri);
|
|||
void choice_set_value(struct menu *choice, struct symbol *sym);
|
||||
tristate sym_toggle_tristate_value(struct symbol *sym);
|
||||
bool sym_string_valid(struct symbol *sym, const char *newval);
|
||||
bool sym_string_check_bounds(struct symbol *sym, const char *str);
|
||||
bool sym_string_within_range(struct symbol *sym, const char *str);
|
||||
bool sym_set_string_value(struct symbol *sym, const char *newval);
|
||||
bool sym_is_changeable(const struct symbol *sym);
|
||||
|
|
|
|||
|
|
@ -145,8 +145,6 @@ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
|
|||
|
||||
/*
|
||||
* Display text from a file in a dialog box.
|
||||
*
|
||||
* keys is a null-terminated array
|
||||
*/
|
||||
int dialog_textbox(const char *title, const char *tbuf, int initial_height,
|
||||
int initial_width, int *_vscroll, int *_hscroll,
|
||||
|
|
|
|||
|
|
@ -234,17 +234,42 @@ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
|
|||
menu_add_prop(type, expr_alloc_symbol(sym), dep);
|
||||
}
|
||||
|
||||
static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
|
||||
/* Validate the sym2 value for numeric sym. */
|
||||
static int menu_validate_number(struct symbol *sym, struct symbol *sym2,
|
||||
const struct property *prop)
|
||||
{
|
||||
return sym2->type == S_INT || sym2->type == S_HEX ||
|
||||
(sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
|
||||
if (sym->type != S_INT && sym->type != S_HEX)
|
||||
return 0;
|
||||
|
||||
if (sym2->type == sym->type)
|
||||
return 0;
|
||||
|
||||
if (sym2->type != S_UNKNOWN ||
|
||||
!sym_string_valid(sym, sym2->name)) {
|
||||
fprintf(stderr, "%s:%d: error: '%s' is an invalid value for '%s'\n",
|
||||
prop->filename, prop->lineno, sym2->name,
|
||||
sym_type_name(sym->type));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!sym_string_check_bounds(sym, sym2->name)) {
|
||||
fprintf(stderr,
|
||||
"%s:%d: error: %s constant '%s' is outside the 64-bit %s bounds\n",
|
||||
prop->filename, prop->lineno, sym_type_name(sym->type),
|
||||
sym2->name, sym->type == S_INT ? "signed" : "unsigned");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sym_check_prop(struct symbol *sym)
|
||||
static int sym_check_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
struct symbol *sym2;
|
||||
char *use;
|
||||
int errors = 0;
|
||||
|
||||
for (prop = sym->prop; prop; prop = prop->next) {
|
||||
switch (prop->type) {
|
||||
|
|
@ -258,10 +283,7 @@ static void sym_check_prop(struct symbol *sym)
|
|||
break;
|
||||
sym2 = prop_get_symbol(prop);
|
||||
if (sym->type == S_HEX || sym->type == S_INT) {
|
||||
if (!menu_validate_number(sym, sym2))
|
||||
prop_warn(prop,
|
||||
"'%s': number is invalid",
|
||||
sym->name);
|
||||
errors += menu_validate_number(sym, sym2, prop);
|
||||
}
|
||||
if (sym_is_choice(sym)) {
|
||||
struct menu *choice = sym_get_choice_menu(sym2);
|
||||
|
|
@ -287,27 +309,33 @@ static void sym_check_prop(struct symbol *sym)
|
|||
"'%s' has wrong type. '%s' only "
|
||||
"accept arguments of bool and "
|
||||
"tristate type", sym2->name, use);
|
||||
if (sym_is_choice_value(sym2))
|
||||
prop_warn(prop,
|
||||
"config symbol '%s' uses %s for '%s', but '%s' is a choice value",
|
||||
sym->name, use, sym2->name, sym2->name);
|
||||
break;
|
||||
case P_RANGE:
|
||||
if (sym->type != S_INT && sym->type != S_HEX)
|
||||
prop_warn(prop, "range is only allowed "
|
||||
"for int or hex symbols");
|
||||
if (!menu_validate_number(sym, prop->expr->left.sym) ||
|
||||
!menu_validate_number(sym, prop->expr->right.sym))
|
||||
prop_warn(prop, "range is invalid");
|
||||
errors += menu_validate_number(sym, prop->expr->left.sym, prop);
|
||||
errors += menu_validate_number(sym, prop->expr->right.sym, prop);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
static void _menu_finalize(struct menu *parent, bool inside_choice)
|
||||
static int _menu_finalize(struct menu *parent, bool inside_choice)
|
||||
{
|
||||
struct menu *menu, *last_menu;
|
||||
struct symbol *sym;
|
||||
struct property *prop;
|
||||
struct expr *basedep, *dep, *dep2;
|
||||
int errors = 0;
|
||||
|
||||
sym = parent->sym;
|
||||
if (parent->list) {
|
||||
|
|
@ -393,7 +421,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
|
|||
* moving on
|
||||
*/
|
||||
for (menu = parent->list; menu; menu = menu->next)
|
||||
_menu_finalize(menu, sym && sym_is_choice(sym));
|
||||
errors += _menu_finalize(menu, sym && sym_is_choice(sym));
|
||||
} else if (!inside_choice && sym) {
|
||||
/*
|
||||
* Automatic submenu creation. If sym is a symbol and A, B, C,
|
||||
|
|
@ -461,7 +489,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
|
|||
}
|
||||
/* Superset, put in submenu */
|
||||
next:
|
||||
_menu_finalize(menu, false);
|
||||
errors += _menu_finalize(menu, false);
|
||||
menu->parent = parent;
|
||||
last_menu = menu;
|
||||
}
|
||||
|
|
@ -519,14 +547,16 @@ static void _menu_finalize(struct menu *parent, bool inside_choice)
|
|||
menu_warn(parent, "config symbol defined without type");
|
||||
|
||||
/* Check properties connected to this symbol */
|
||||
sym_check_prop(sym);
|
||||
errors += sym_check_prop(sym);
|
||||
sym->flags |= SYMBOL_WARNED;
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
void menu_finalize(void)
|
||||
int menu_finalize(void)
|
||||
{
|
||||
_menu_finalize(&rootmenu, false);
|
||||
return _menu_finalize(&rootmenu, false);
|
||||
}
|
||||
|
||||
bool menu_has_prompt(const struct menu *menu)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ struct menu *current_menu, *current_entry, *current_choice;
|
|||
%token T_CONFIG
|
||||
%token T_DEFAULT
|
||||
%token T_DEF_BOOL
|
||||
%token T_DEF_HEX
|
||||
%token T_DEF_INT
|
||||
%token T_DEF_STRING
|
||||
%token T_DEF_TRISTATE
|
||||
%token T_DEPENDS
|
||||
%token T_ENDCHOICE
|
||||
|
|
@ -309,6 +312,9 @@ type:
|
|||
default:
|
||||
T_DEFAULT { $$ = S_UNKNOWN; }
|
||||
| T_DEF_BOOL { $$ = S_BOOLEAN; }
|
||||
| T_DEF_HEX { $$ = S_HEX; }
|
||||
| T_DEF_INT { $$ = S_INT; }
|
||||
| T_DEF_STRING { $$ = S_STRING; }
|
||||
| T_DEF_TRISTATE { $$ = S_TRISTATE; }
|
||||
|
||||
/* if entry */
|
||||
|
|
@ -587,7 +593,7 @@ void conf_parse(const char *name)
|
|||
menu_add_prompt(P_MENU, "Main menu", NULL);
|
||||
}
|
||||
|
||||
menu_finalize();
|
||||
yynerrs += menu_finalize();
|
||||
|
||||
menu_for_each_entry(menu) {
|
||||
struct menu *child;
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ my %prompts;
|
|||
my %objects;
|
||||
my %config2kfile;
|
||||
my %defaults;
|
||||
my %types;
|
||||
my $var;
|
||||
my $iflevel = 0;
|
||||
my @ifdeps;
|
||||
|
|
@ -224,6 +225,7 @@ sub read_kconfig {
|
|||
} elsif ($state ne "NONE" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
|
||||
my $dep = $3;
|
||||
$defaults{$config} = 1;
|
||||
$types{$config} = $2 if (defined($2));
|
||||
if ($dep !~ /^\s*(y|m|n)\s*$/) {
|
||||
$dep =~ s/.*\sif\s+//;
|
||||
$depends{$config} .= " " . $dep;
|
||||
|
|
@ -240,7 +242,13 @@ sub read_kconfig {
|
|||
}
|
||||
|
||||
# configs without prompts must be selected
|
||||
} elsif ($state ne "NONE" && /^\s*(tristate\s+\S|prompt\b)/) {
|
||||
} elsif ($state ne "NONE" && /^\s*(bool|boolean)(\s+\S.*)?$/) {
|
||||
$types{$config} = "bool";
|
||||
$prompts{$config} = 1 if (defined($2));
|
||||
} elsif ($state ne "NONE" && /^\s*tristate(\s+\S.*)?$/) {
|
||||
$types{$config} = "tristate";
|
||||
$prompts{$config} = 1 if (defined($1));
|
||||
} elsif ($state ne "NONE" && /^\s*prompt\b/) {
|
||||
# note if the config has a prompt
|
||||
$prompts{$config} = 1;
|
||||
|
||||
|
|
@ -707,7 +715,15 @@ foreach my $module (keys(%modules)) {
|
|||
}
|
||||
print STDERR "module $module did not have configs";
|
||||
foreach my $conf (@arr) {
|
||||
print STDERR " " , $conf;
|
||||
my $c = $conf;
|
||||
$c =~ s/^CONFIG_//;
|
||||
if (!$localyesconfig && defined($types{$c}) && $types{$c} eq "bool") {
|
||||
print STDERR " $conf (boolean, not supported with =m)";
|
||||
} elsif (defined($types{$c})) {
|
||||
print STDERR " $conf ($types{$c})";
|
||||
} else {
|
||||
print STDERR " " , $conf;
|
||||
}
|
||||
}
|
||||
print STDERR "\n";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <regex.h>
|
||||
|
|
@ -141,8 +142,15 @@ struct property *sym_get_range_prop(struct symbol *sym)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static long long sym_get_range_val(struct symbol *sym, int base)
|
||||
union range_value {
|
||||
long long s;
|
||||
unsigned long long u;
|
||||
};
|
||||
|
||||
static union range_value sym_get_range_val(struct symbol *sym, int base)
|
||||
{
|
||||
union range_value val;
|
||||
|
||||
sym_calc_value(sym);
|
||||
switch (sym->type) {
|
||||
case S_INT:
|
||||
|
|
@ -154,15 +162,25 @@ static long long sym_get_range_val(struct symbol *sym, int base)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
return strtoll(sym->curr.val, NULL, base);
|
||||
if (base == 10)
|
||||
val.s = strtoll(sym->curr.val, NULL, base);
|
||||
else
|
||||
/* HEX */
|
||||
val.u = strtoull(sym->curr.val, NULL, base);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void sym_validate_range(struct symbol *sym)
|
||||
/*
|
||||
* Return the nearest range bound for an out-of-range default value.
|
||||
* Return NULL if the value is valid or the symbol has no active range.
|
||||
*/
|
||||
static struct symbol *sym_get_near_range_bound(struct symbol *sym,
|
||||
const char *value)
|
||||
{
|
||||
struct property *prop;
|
||||
struct symbol *range_sym;
|
||||
int base;
|
||||
long long val, val2;
|
||||
union range_value val, val2;
|
||||
|
||||
switch (sym->type) {
|
||||
case S_INT:
|
||||
|
|
@ -172,21 +190,40 @@ static void sym_validate_range(struct symbol *sym)
|
|||
base = 16;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
prop = sym_get_range_prop(sym);
|
||||
if (!prop)
|
||||
return;
|
||||
val = strtoll(sym->curr.val, NULL, base);
|
||||
return NULL;
|
||||
if (base == 10)
|
||||
val.s = strtoll(value, NULL, base);
|
||||
else
|
||||
val.u = strtoull(value, NULL, base);
|
||||
range_sym = prop->expr->left.sym;
|
||||
val2 = sym_get_range_val(range_sym, base);
|
||||
if (val >= val2) {
|
||||
|
||||
if (base == 10 && val.s >= val2.s) {
|
||||
range_sym = prop->expr->right.sym;
|
||||
val2 = sym_get_range_val(range_sym, base);
|
||||
if (val <= val2)
|
||||
return;
|
||||
if (val.s <= val2.s)
|
||||
return NULL;
|
||||
} else if (base == 16 && val.u >= val2.u) {
|
||||
range_sym = prop->expr->right.sym;
|
||||
val2 = sym_get_range_val(range_sym, base);
|
||||
if (val.u <= val2.u)
|
||||
return NULL;
|
||||
}
|
||||
sym->curr.val = range_sym->curr.val;
|
||||
|
||||
return range_sym;
|
||||
}
|
||||
|
||||
static void sym_validate_range(struct symbol *sym)
|
||||
{
|
||||
struct symbol *range_sym;
|
||||
|
||||
range_sym = sym_get_near_range_bound(sym, sym->curr.val);
|
||||
if (range_sym)
|
||||
sym->curr.val = range_sym->curr.val;
|
||||
}
|
||||
|
||||
static void sym_set_changed(struct symbol *sym)
|
||||
|
|
@ -711,10 +748,26 @@ bool sym_string_valid(struct symbol *sym, const char *str)
|
|||
}
|
||||
}
|
||||
|
||||
bool sym_string_check_bounds(struct symbol *sym, const char *str)
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
if (sym->type == S_INT)
|
||||
strtoll(str, NULL, 10);
|
||||
else if (sym->type == S_HEX)
|
||||
strtoull(str, NULL, 16);
|
||||
else
|
||||
/* string */
|
||||
return true;
|
||||
|
||||
return errno != ERANGE;
|
||||
}
|
||||
|
||||
bool sym_string_within_range(struct symbol *sym, const char *str)
|
||||
{
|
||||
struct property *prop;
|
||||
long long val;
|
||||
unsigned long long uval;
|
||||
|
||||
switch (sym->type) {
|
||||
case S_STRING:
|
||||
|
|
@ -722,21 +775,25 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
|
|||
case S_INT:
|
||||
if (!sym_string_valid(sym, str))
|
||||
return false;
|
||||
prop = sym_get_range_prop(sym);
|
||||
if (!prop)
|
||||
return true;
|
||||
val = strtoll(str, NULL, 10);
|
||||
return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
|
||||
val <= sym_get_range_val(prop->expr->right.sym, 10);
|
||||
case S_HEX:
|
||||
if (!sym_string_valid(sym, str))
|
||||
if (!sym_string_check_bounds(sym, str))
|
||||
return false;
|
||||
prop = sym_get_range_prop(sym);
|
||||
if (!prop)
|
||||
return true;
|
||||
val = strtoll(str, NULL, 16);
|
||||
return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
|
||||
val <= sym_get_range_val(prop->expr->right.sym, 16);
|
||||
val = strtoll(str, NULL, 10);
|
||||
return val >= sym_get_range_val(prop->expr->left.sym, 10).s &&
|
||||
val <= sym_get_range_val(prop->expr->right.sym, 10).s;
|
||||
case S_HEX:
|
||||
if (!sym_string_valid(sym, str))
|
||||
return false;
|
||||
if (!sym_string_check_bounds(sym, str))
|
||||
return false;
|
||||
prop = sym_get_range_prop(sym);
|
||||
if (!prop)
|
||||
return true;
|
||||
uval = strtoull(str, NULL, 16);
|
||||
return uval >= sym_get_range_val(prop->expr->left.sym, 16).u &&
|
||||
uval <= sym_get_range_val(prop->expr->right.sym, 16).u;
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
switch (str[0]) {
|
||||
|
|
@ -812,7 +869,7 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
|
|||
const char *sym_get_string_default(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
struct symbol *ds;
|
||||
struct symbol *ds, *range_sym;
|
||||
const char *str = "";
|
||||
tristate val;
|
||||
|
||||
|
|
@ -830,11 +887,6 @@ const char *sym_get_string_default(struct symbol *sym)
|
|||
val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* The following fails to handle the situation
|
||||
* where a default value is further limited by
|
||||
* the valid range.
|
||||
*/
|
||||
ds = prop_get_symbol(prop);
|
||||
if (ds != NULL) {
|
||||
sym_calc_value(ds);
|
||||
|
|
@ -878,6 +930,11 @@ const char *sym_get_string_default(struct symbol *sym)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
range_sym = sym_get_near_range_bound(sym, str);
|
||||
if (range_sym)
|
||||
str = range_sym->curr.val;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
|
@ -1196,6 +1253,7 @@ static struct symbol *sym_check_expr_deps(const struct expr *e)
|
|||
case E_GTH:
|
||||
case E_LEQ:
|
||||
case E_LTH:
|
||||
case E_RANGE:
|
||||
case E_UNEQUAL:
|
||||
sym = sym_check_deps(e->left.sym);
|
||||
if (sym)
|
||||
|
|
@ -1243,7 +1301,9 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym)
|
|||
sym2 = sym_check_expr_deps(prop->visible.expr);
|
||||
if (sym2)
|
||||
break;
|
||||
if (prop->type != P_DEFAULT || sym_is_choice(sym))
|
||||
if (sym_is_choice(sym))
|
||||
continue;
|
||||
if (prop->type != P_DEFAULT && prop->type != P_RANGE)
|
||||
continue;
|
||||
stack.expr = &prop->expr;
|
||||
sym2 = sym_check_expr_deps(prop->expr);
|
||||
|
|
|
|||
|
|
@ -57,9 +57,12 @@ class Conf:
|
|||
# Override 'srctree' environment to make the test as the top directory
|
||||
extra_env['srctree'] = self._test_dir
|
||||
|
||||
# Clear KCONFIG_DEFCONFIG_LIST to keep unit tests from being affected
|
||||
# by the user's environment.
|
||||
extra_env['KCONFIG_DEFCONFIG_LIST'] = ''
|
||||
# Clear all KCONFIG_* environment variables
|
||||
env = {
|
||||
varname: os.environ[varname]
|
||||
for varname in os.environ.keys()
|
||||
if not varname.startswith("KCONFIG_")
|
||||
}
|
||||
|
||||
# Run Kconfig in a temporary directory.
|
||||
# This directory is automatically removed when done.
|
||||
|
|
@ -75,7 +78,7 @@ class Conf:
|
|||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
cwd=temp_dir,
|
||||
env=dict(os.environ, **extra_env))
|
||||
env=dict(env, **extra_env))
|
||||
|
||||
# If input key sequence is given, feed it to stdin.
|
||||
if in_keys:
|
||||
|
|
@ -156,13 +159,13 @@ class Conf:
|
|||
return self._run_conf('--oldconfig', dot_config=dot_config,
|
||||
interactive=True, in_keys=in_keys)
|
||||
|
||||
def olddefconfig(self, dot_config=None):
|
||||
def olddefconfig(self, dot_config=None, **kw):
|
||||
"""Run olddefconfig.
|
||||
|
||||
dot_config: .config file to use for configuration base (optional)
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--olddefconfig', dot_config=dot_config)
|
||||
return self._run_conf('--olddefconfig', dot_config=dot_config, **kw)
|
||||
|
||||
def defconfig(self, defconfig):
|
||||
"""Run defconfig.
|
||||
|
|
@ -226,13 +229,15 @@ class Conf:
|
|||
|
||||
return self._allconfig('rand', all_config, extra_env=extra_env)
|
||||
|
||||
def savedefconfig(self, dot_config):
|
||||
def savedefconfig(self, dot_config, out_file='defconfig', **kw):
|
||||
"""Run savedefconfig.
|
||||
|
||||
dot_config: .config file for input
|
||||
out_file: defconfig file for output
|
||||
returncode: exit status of the Kconfig executable
|
||||
"""
|
||||
return self._run_conf('--savedefconfig', out_file='defconfig')
|
||||
return self._run_conf('--savedefconfig={}'.format(out_file),
|
||||
dot_config=dot_config, out_file=out_file, **kw)
|
||||
|
||||
def listnewconfig(self, dot_config=None):
|
||||
"""Run listnewconfig.
|
||||
|
|
@ -312,6 +317,12 @@ class Conf:
|
|||
return self._matches('stderr', expected)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clear_werror(monkeypatch):
|
||||
# extra_env can set strict mode, but cannot remove an inherited flag.
|
||||
monkeypatch.delenv('KCONFIG_WERROR', raising=False)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def conf(request):
|
||||
"""Create a Conf instance and provide it to test functions."""
|
||||
|
|
|
|||
28
scripts/kconfig/tests/def_type/Kconfig
Normal file
28
scripts/kconfig/tests/def_type/Kconfig
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# The def_<type> shorthands: a type definition plus a default value.
|
||||
|
||||
config MODULES
|
||||
bool "Enable loadable module support"
|
||||
modules
|
||||
default y
|
||||
|
||||
config GUARD
|
||||
bool "Guard symbol"
|
||||
|
||||
config DEF_BOOL
|
||||
def_bool GUARD
|
||||
|
||||
config DEF_TRISTATE
|
||||
def_tristate m if GUARD
|
||||
|
||||
config DEF_STRING
|
||||
def_string "guarded" if GUARD
|
||||
default "fallback"
|
||||
|
||||
config DEF_INT
|
||||
def_int 64 if GUARD
|
||||
default 32
|
||||
|
||||
config DEF_HEX
|
||||
def_hex 0xdead if GUARD
|
||||
default 0x0
|
||||
18
scripts/kconfig/tests/def_type/__init__.py
Normal file
18
scripts/kconfig/tests/def_type/__init__.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Set a symbol's type and its default value in one line.
|
||||
|
||||
"def_bool", "def_tristate", "def_string", "def_int" and "def_hex" are
|
||||
shorthand for a type definition plus a "default" property. Check that
|
||||
each one sets the type, and that an "if" on the shorthand does not
|
||||
disturb the usual default cascade: the shorthand is only the first arm
|
||||
of the list, so a later "default" still applies when its condition is
|
||||
not met.
|
||||
"""
|
||||
|
||||
def test(conf):
|
||||
assert conf.olddefconfig(dot_config='guard_y.config') == 0
|
||||
assert conf.config_matches('expected_guard_y')
|
||||
|
||||
assert conf.olddefconfig(dot_config='guard_n.config') == 0
|
||||
assert conf.config_matches('expected_guard_n')
|
||||
9
scripts/kconfig/tests/def_type/expected_guard_n
Normal file
9
scripts/kconfig/tests/def_type/expected_guard_n
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_GUARD is not set
|
||||
CONFIG_DEF_STRING="fallback"
|
||||
CONFIG_DEF_INT=32
|
||||
CONFIG_DEF_HEX=0x0
|
||||
11
scripts/kconfig/tests/def_type/expected_guard_y
Normal file
11
scripts/kconfig/tests/def_type/expected_guard_y
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Main menu
|
||||
#
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_GUARD=y
|
||||
CONFIG_DEF_BOOL=y
|
||||
CONFIG_DEF_TRISTATE=m
|
||||
CONFIG_DEF_STRING="guarded"
|
||||
CONFIG_DEF_INT=64
|
||||
CONFIG_DEF_HEX=0xdead
|
||||
1
scripts/kconfig/tests/def_type/guard_n.config
Normal file
1
scripts/kconfig/tests/def_type/guard_n.config
Normal file
|
|
@ -0,0 +1 @@
|
|||
# CONFIG_GUARD is not set
|
||||
1
scripts/kconfig/tests/def_type/guard_y.config
Normal file
1
scripts/kconfig/tests/def_type/guard_y.config
Normal file
|
|
@ -0,0 +1 @@
|
|||
CONFIG_GUARD=y
|
||||
79
scripts/kconfig/tests/err_num_bounds/Kconfig
Normal file
79
scripts/kconfig/tests/err_num_bounds/Kconfig
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Test bounds checks for 'int' and 'hex' constants
|
||||
|
||||
config INT_SOURCE
|
||||
int
|
||||
|
||||
config HEX_SOURCE
|
||||
hex
|
||||
|
||||
config BOOL_SOURCE
|
||||
bool
|
||||
|
||||
# Valid values at the limits of the type
|
||||
|
||||
config INT_MIN
|
||||
int
|
||||
default -9223372036854775808
|
||||
|
||||
config INT_MAX
|
||||
int
|
||||
default 9223372036854775807
|
||||
|
||||
config HEX_MIN
|
||||
hex
|
||||
default 0x0
|
||||
|
||||
config HEX_MAX
|
||||
hex
|
||||
default 0xffffffffffffffff
|
||||
|
||||
config INT_RANGE_LIMITS
|
||||
int
|
||||
range -9223372036854775808 9223372036854775807
|
||||
|
||||
config HEX_RANGE_LIMITS
|
||||
hex
|
||||
range 0 0xffffffffffffffff
|
||||
|
||||
config INT_FROM_INT
|
||||
int
|
||||
default INT_SOURCE
|
||||
|
||||
config HEX_FROM_HEX
|
||||
hex
|
||||
default HEX_SOURCE
|
||||
|
||||
# Constants outside the bounds
|
||||
|
||||
config INT_DEFAULT_TOO_HIGH
|
||||
int
|
||||
default 10000000000000000000
|
||||
|
||||
config INT_DEFAULT_TOO_LOW
|
||||
int
|
||||
default -9223372036854775809
|
||||
|
||||
config INT_RANGE_TOO_HIGH
|
||||
int
|
||||
range 0 10000000000000000000
|
||||
|
||||
config INT_RANGE_TOO_LOW
|
||||
int
|
||||
range -10000000000000000000 0
|
||||
|
||||
config INT_RANGE_BOTH_OUTSIDE
|
||||
int
|
||||
range -9223372036854775809 10000000000000000000
|
||||
|
||||
config HEX_DEFAULT_TOO_HIGH
|
||||
hex
|
||||
default 0x10000000000000000
|
||||
|
||||
config HEX_RANGE_TOO_HIGH
|
||||
hex
|
||||
range 0 0x10000000000000000
|
||||
|
||||
config HEX_RANGE_BOTH_TOO_HIGH
|
||||
hex
|
||||
range 0x10000000000000000 0x20000000000000000
|
||||
12
scripts/kconfig/tests/err_num_bounds/__init__.py
Normal file
12
scripts/kconfig/tests/err_num_bounds/__init__.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Detect constants outside the 'int' and 'hex' bounds.
|
||||
|
||||
An int constant must fit in a signed 64-bit integer, and a hex constant must
|
||||
fit in an unsigned 64-bit integer.
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.olddefconfig() == 1
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
10
scripts/kconfig/tests/err_num_bounds/expected_stderr
Normal file
10
scripts/kconfig/tests/err_num_bounds/expected_stderr
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
Kconfig:51: error: integer constant '10000000000000000000' is outside the 64-bit signed bounds
|
||||
Kconfig:55: error: integer constant '-9223372036854775809' is outside the 64-bit signed bounds
|
||||
Kconfig:59: error: integer constant '10000000000000000000' is outside the 64-bit signed bounds
|
||||
Kconfig:63: error: integer constant '-10000000000000000000' is outside the 64-bit signed bounds
|
||||
Kconfig:67: error: integer constant '-9223372036854775809' is outside the 64-bit signed bounds
|
||||
Kconfig:67: error: integer constant '10000000000000000000' is outside the 64-bit signed bounds
|
||||
Kconfig:71: error: hex constant '0x10000000000000000' is outside the 64-bit unsigned bounds
|
||||
Kconfig:75: error: hex constant '0x10000000000000000' is outside the 64-bit unsigned bounds
|
||||
Kconfig:79: error: hex constant '0x10000000000000000' is outside the 64-bit unsigned bounds
|
||||
Kconfig:79: error: hex constant '0x20000000000000000' is outside the 64-bit unsigned bounds
|
||||
38
scripts/kconfig/tests/err_num_mismatch/Kconfig
Normal file
38
scripts/kconfig/tests/err_num_mismatch/Kconfig
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Test 'int' and 'hex' symbols that reference each other
|
||||
|
||||
config INT_SOURCE
|
||||
int
|
||||
|
||||
config HEX_SOURCE
|
||||
hex
|
||||
|
||||
# 'hex' reference from 'int'
|
||||
|
||||
config INT_DEFAULT_HEX
|
||||
int
|
||||
default HEX_SOURCE
|
||||
|
||||
config INT_RANGE_HEX
|
||||
int
|
||||
range HEX_SOURCE 1
|
||||
|
||||
# A hex symbol must not reference an int symbol
|
||||
|
||||
config HEX_DEFAULT_INT
|
||||
hex
|
||||
default INT_SOURCE
|
||||
|
||||
config HEX_RANGE_INT
|
||||
hex
|
||||
range INT_SOURCE 0x1
|
||||
|
||||
# Referencing the same type is valid
|
||||
|
||||
config INT_FROM_INT
|
||||
int
|
||||
default INT_SOURCE
|
||||
|
||||
config HEX_FROM_HEX
|
||||
hex
|
||||
range 0 HEX_SOURCE
|
||||
9
scripts/kconfig/tests/err_num_mismatch/__init__.py
Normal file
9
scripts/kconfig/tests/err_num_mismatch/__init__.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Reject direct references ('default' or 'range') between int and hex options.
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.olddefconfig() == 1
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
4
scripts/kconfig/tests/err_num_mismatch/expected_stderr
Normal file
4
scripts/kconfig/tests/err_num_mismatch/expected_stderr
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Kconfig:14: error: 'HEX_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:18: error: 'HEX_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:24: error: 'INT_SOURCE' is an invalid value for 'hex'
|
||||
Kconfig:28: error: 'INT_SOURCE' is an invalid value for 'hex'
|
||||
75
scripts/kconfig/tests/err_num_non_numeric_ref/Kconfig
Normal file
75
scripts/kconfig/tests/err_num_non_numeric_ref/Kconfig
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Test non-numeric symbol references from numeric symbols
|
||||
|
||||
config BOOL_SOURCE
|
||||
bool
|
||||
|
||||
config TRISTATE_SOURCE
|
||||
tristate
|
||||
|
||||
config STRING_SOURCE
|
||||
string
|
||||
|
||||
# Invalid int defaults
|
||||
|
||||
config INT_DEFAULT_BOOL
|
||||
int
|
||||
default BOOL_SOURCE
|
||||
|
||||
config INT_DEFAULT_TRISTATE
|
||||
int
|
||||
default TRISTATE_SOURCE
|
||||
|
||||
config INT_DEFAULT_STRING
|
||||
int
|
||||
default STRING_SOURCE
|
||||
|
||||
# Invalid hex defaults
|
||||
|
||||
config HEX_DEFAULT_BOOL
|
||||
hex
|
||||
default BOOL_SOURCE
|
||||
|
||||
config HEX_DEFAULT_TRISTATE
|
||||
hex
|
||||
default TRISTATE_SOURCE
|
||||
|
||||
config HEX_DEFAULT_STRING
|
||||
hex
|
||||
default STRING_SOURCE
|
||||
|
||||
# Invalid int ranges
|
||||
|
||||
config INT_RANGE_BOOL
|
||||
int
|
||||
range BOOL_SOURCE 1
|
||||
|
||||
config INT_RANGE_TRISTATE
|
||||
int
|
||||
range TRISTATE_SOURCE 1
|
||||
|
||||
config INT_RANGE_STRING
|
||||
int
|
||||
range STRING_SOURCE 1
|
||||
|
||||
config INT_RANGE_MULTIPLE
|
||||
int
|
||||
range BOOL_SOURCE TRISTATE_SOURCE
|
||||
|
||||
# Invalid hex ranges
|
||||
|
||||
config HEX_RANGE_BOOL
|
||||
hex
|
||||
range BOOL_SOURCE 0x1
|
||||
|
||||
config HEX_RANGE_TRISTATE
|
||||
hex
|
||||
range TRISTATE_SOURCE 0x1
|
||||
|
||||
config HEX_RANGE_STRING
|
||||
hex
|
||||
range STRING_SOURCE 0x1
|
||||
|
||||
config HEX_RANGE_MULTIPLE
|
||||
hex
|
||||
range BOOL_SOURCE TRISTATE_SOURCE
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""
|
||||
Reject nonnumeric symbol references from int and hex properties.
|
||||
"""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf.olddefconfig() == 1
|
||||
assert conf.stderr_matches('expected_stderr')
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
Kconfig:17: error: 'BOOL_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:21: error: 'TRISTATE_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:25: error: 'STRING_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:31: error: 'BOOL_SOURCE' is an invalid value for 'hex'
|
||||
Kconfig:35: error: 'TRISTATE_SOURCE' is an invalid value for 'hex'
|
||||
Kconfig:39: error: 'STRING_SOURCE' is an invalid value for 'hex'
|
||||
Kconfig:45: error: 'BOOL_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:49: error: 'TRISTATE_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:53: error: 'STRING_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:57: error: 'BOOL_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:57: error: 'TRISTATE_SOURCE' is an invalid value for 'integer'
|
||||
Kconfig:63: error: 'BOOL_SOURCE' is an invalid value for 'hex'
|
||||
Kconfig:67: error: 'TRISTATE_SOURCE' is an invalid value for 'hex'
|
||||
Kconfig:71: error: 'STRING_SOURCE' is an invalid value for 'hex'
|
||||
Kconfig:75: error: 'BOOL_SOURCE' is an invalid value for 'hex'
|
||||
Kconfig:75: error: 'TRISTATE_SOURCE' is an invalid value for 'hex'
|
||||
|
|
@ -61,3 +61,27 @@ config G
|
|||
bool "G"
|
||||
|
||||
endmenu
|
||||
|
||||
# depends on and range
|
||||
|
||||
config H1
|
||||
int
|
||||
depends on H2 < H3
|
||||
|
||||
config H2
|
||||
int
|
||||
range H3 H1
|
||||
|
||||
config H3
|
||||
int
|
||||
range H1 H2
|
||||
|
||||
# range
|
||||
|
||||
config I1
|
||||
int
|
||||
range I2 I2
|
||||
|
||||
config I2
|
||||
int
|
||||
range I1 I1
|
||||
|
|
|
|||
|
|
@ -36,3 +36,16 @@ error: recursive dependency detected!
|
|||
symbol G depends on G
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
error: recursive dependency detected!
|
||||
symbol H1 depends on H2
|
||||
symbol H2 range value contains H3
|
||||
symbol H3 range value contains H1
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
||||
error: recursive dependency detected!
|
||||
symbol I1 range value contains I2
|
||||
symbol I2 range value contains I1
|
||||
For a resolution refer to Documentation/kbuild/kconfig-language.rst
|
||||
subsection "Kconfig recursive dependency limitations"
|
||||
|
|
|
|||
12
scripts/kconfig/tests/randconfig_probability/Kconfig
Normal file
12
scripts/kconfig/tests/randconfig_probability/Kconfig
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config MODULES
|
||||
bool
|
||||
default y
|
||||
modules
|
||||
|
||||
config BOOL
|
||||
bool "Bool"
|
||||
|
||||
config TRI
|
||||
tristate "Tristate"
|
||||
130
scripts/kconfig/tests/randconfig_probability/__init__.py
Normal file
130
scripts/kconfig/tests/randconfig_probability/__init__.py
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
"""Validate KCONFIG_PROBABILITY without changing the supported distributions."""
|
||||
|
||||
|
||||
def test_malformed_warns(conf):
|
||||
probabilities = [
|
||||
'invalid', ' ', '50%', '50 ', '0x32', '10 20', '10:20x',
|
||||
'10:20:invalid', '10:20:30x',
|
||||
':50', '50:', '10::20', '10:20:', '10:20:30:', '10:20:30:40',
|
||||
'-0', '+0', '+', '-', '+100:0', ' \t100:0', '0: \t100:0',
|
||||
]
|
||||
for probability in probabilities:
|
||||
assert conf._run_conf('--randconfig', extra_env={
|
||||
'KCONFIG_PROBABILITY': probability,
|
||||
'KCONFIG_SEED': '0',
|
||||
}) == 0, repr(probability)
|
||||
assert ('warning: KCONFIG_PROBABILITY has malformed format' in
|
||||
conf.stderr), repr(probability)
|
||||
assert conf.stderr.count('warning:') == 1, repr(probability)
|
||||
assert conf.config is not None, repr(probability)
|
||||
|
||||
|
||||
def test_malformed_preserves_config(conf):
|
||||
probabilities = [('50%', '50:0:0'), ('-0', '0')]
|
||||
for seed in range(20):
|
||||
for probability, equivalent in probabilities:
|
||||
context = 'probability={!r}, equivalent={!r}, seed={}'.format(
|
||||
probability, equivalent, seed)
|
||||
assert conf._run_conf('--randconfig', extra_env={
|
||||
'KCONFIG_PROBABILITY': probability,
|
||||
'KCONFIG_SEED': hex(seed),
|
||||
}) == 0, context
|
||||
assert ('warning: KCONFIG_PROBABILITY has malformed format' in
|
||||
conf.stderr), context
|
||||
assert conf.stderr.count('warning:') == 1, context
|
||||
malformed = conf.config
|
||||
|
||||
assert conf._run_conf('--randconfig', extra_env={
|
||||
'KCONFIG_PROBABILITY': equivalent,
|
||||
'KCONFIG_SEED': hex(seed),
|
||||
}) == 0, context
|
||||
assert 'warning:' not in conf.stderr, context
|
||||
assert conf.config == malformed, context
|
||||
|
||||
|
||||
def test_werror(conf):
|
||||
probabilities = [
|
||||
('', 0), ('50', 0), ('50%', 1), ('-0', 1), ('10:20:30:40', 1),
|
||||
]
|
||||
for probability, status in probabilities:
|
||||
for werror in ['', '0', '1']:
|
||||
context = 'probability={!r}, werror={!r}'.format(
|
||||
probability, werror)
|
||||
assert conf._run_conf('--randconfig', extra_env={
|
||||
'KCONFIG_PROBABILITY': probability,
|
||||
'KCONFIG_SEED': '0',
|
||||
'KCONFIG_WERROR': werror,
|
||||
}) == status, context
|
||||
if status:
|
||||
assert ('warning: KCONFIG_PROBABILITY has malformed format' in
|
||||
conf.stderr), context
|
||||
assert conf.stderr.count('warning:') == 1, context
|
||||
else:
|
||||
assert 'warning:' not in conf.stderr, context
|
||||
|
||||
|
||||
def test_out_of_range(conf):
|
||||
probabilities = [
|
||||
'-1', '101', '+101', '0:101', '0:0:101', '60:41', '0:60:41',
|
||||
'4294967296', '-4294967296',
|
||||
'999999999999999999999999', '-999999999999999999999999',
|
||||
]
|
||||
for probability in probabilities:
|
||||
assert conf._run_conf('--randconfig', extra_env={
|
||||
'KCONFIG_PROBABILITY': probability,
|
||||
'KCONFIG_SEED': '0',
|
||||
}) == 1, repr(probability)
|
||||
assert 'KCONFIG_PROBABILITY:' in conf.stderr, repr(probability)
|
||||
|
||||
|
||||
def test_valid(conf):
|
||||
probabilities = [
|
||||
('0', 'n', 'n'),
|
||||
('0:0', 'n', 'n'),
|
||||
('100:0', 'y', 'y'),
|
||||
('0:100', 'y', 'm'),
|
||||
('100:0:0', 'y', 'n'),
|
||||
('0:100:0', 'n', 'y'),
|
||||
('0:0:100', 'n', 'm'),
|
||||
('000:000:100', 'n', 'm'),
|
||||
]
|
||||
for probability, boolean, tristate in probabilities:
|
||||
assert conf._run_conf('--randconfig', extra_env={
|
||||
'KCONFIG_PROBABILITY': probability,
|
||||
'KCONFIG_SEED': '0',
|
||||
}) == 0, repr(probability)
|
||||
assert 'warning:' not in conf.stderr, repr(probability)
|
||||
for symbol, value in [('BOOL', boolean), ('TRI', tristate)]:
|
||||
if value == 'n':
|
||||
expected = '# CONFIG_{} is not set'.format(symbol)
|
||||
else:
|
||||
expected = 'CONFIG_{}={}'.format(symbol, value)
|
||||
assert expected in conf.config.splitlines(), repr(probability)
|
||||
|
||||
|
||||
def test_single_probability_matches_tristate_split(conf):
|
||||
for seed in range(20):
|
||||
context = 'seed={}'.format(seed)
|
||||
assert conf._run_conf('--randconfig', extra_env={
|
||||
'KCONFIG_PROBABILITY': '50',
|
||||
'KCONFIG_SEED': hex(seed),
|
||||
}) == 0, context
|
||||
assert 'warning:' not in conf.stderr, context
|
||||
single = conf.config
|
||||
|
||||
# 50% boolean y; 25% tristate y, 25% m, and 50% n.
|
||||
assert conf._run_conf('--randconfig', extra_env={
|
||||
'KCONFIG_PROBABILITY': '50:25:25',
|
||||
'KCONFIG_SEED': hex(seed),
|
||||
}) == 0, context
|
||||
assert 'warning:' not in conf.stderr, context
|
||||
assert conf.config == single, context
|
||||
|
||||
|
||||
def test_empty(conf):
|
||||
assert conf._run_conf('--randconfig', extra_env={
|
||||
'KCONFIG_PROBABILITY': '',
|
||||
'KCONFIG_SEED': '0',
|
||||
}) == 0
|
||||
assert 'warning:' not in conf.stderr
|
||||
67
scripts/kconfig/tests/savedefconfig_range/Kconfig
Normal file
67
scripts/kconfig/tests/savedefconfig_range/Kconfig
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# Static default and range values
|
||||
|
||||
config INT_DEFAULT_ABOVE_RANGE
|
||||
int
|
||||
range 1 1
|
||||
default 16
|
||||
|
||||
config INT_DEFAULT_BELOW_RANGE
|
||||
int
|
||||
range 4 8
|
||||
default 2
|
||||
|
||||
# Default and range values determined by other options
|
||||
|
||||
config RANGE_UPPER_BOUND
|
||||
int
|
||||
default 3
|
||||
|
||||
config INT_DYNAMIC_RANGE
|
||||
int
|
||||
range 0 RANGE_UPPER_BOUND
|
||||
default 4
|
||||
|
||||
# Hex
|
||||
|
||||
config HEX_DEFAULT_ABOVE_RANGE
|
||||
hex
|
||||
range 0x10 0x20
|
||||
default 0x40
|
||||
|
||||
# Implicit default value of 0
|
||||
|
||||
config INT_IMPLICIT_DEFAULT_ZERO
|
||||
int
|
||||
range 1 4
|
||||
|
||||
# Conditional range
|
||||
|
||||
config USE_FIRST_RANGE
|
||||
bool
|
||||
default y
|
||||
|
||||
config INT_CONDITIONAL_RANGE
|
||||
int
|
||||
range 1 2 if USE_FIRST_RANGE
|
||||
range 3 4 if !USE_FIRST_RANGE
|
||||
default 3
|
||||
|
||||
# Conditional default
|
||||
|
||||
config USE_DEFAULT
|
||||
bool
|
||||
default y
|
||||
|
||||
config INT_CONDITIONAL_DEFAULT
|
||||
int
|
||||
range 1 2
|
||||
default 3 if USE_DEFAULT
|
||||
|
||||
# Default outside of the range of a symbol with a prompt
|
||||
|
||||
config INT_PROMPT_DEFAULT_ABOVE_RANGE
|
||||
int "int with prompt"
|
||||
range 1 4
|
||||
default 8
|
||||
8
scripts/kconfig/tests/savedefconfig_range/__init__.py
Normal file
8
scripts/kconfig/tests/savedefconfig_range/__init__.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
"""Test savedefconfig with numerical defaults outside of ranges."""
|
||||
|
||||
|
||||
def test(conf):
|
||||
assert conf._run_conf('--savedefconfig=defconfig', dot_config='config',
|
||||
out_file='defconfig') == 0
|
||||
assert conf.config_matches('expected_defconfig')
|
||||
8
scripts/kconfig/tests/savedefconfig_range/config
Normal file
8
scripts/kconfig/tests/savedefconfig_range/config
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
CONFIG_INT_DEFAULT_ABOVE_RANGE=1
|
||||
CONFIG_INT_DEFAULT_BELOW_RANGE=4
|
||||
CONFIG_INT_DYNAMIC_RANGE=3
|
||||
CONFIG_HEX_DEFAULT_ABOVE_RANGE=0x20
|
||||
CONFIG_INT_IMPLICIT_DEFAULT_ZERO=1
|
||||
CONFIG_INT_CONDITIONAL_RANGE=2
|
||||
CONFIG_INT_CONDITIONAL_DEFAULT=2
|
||||
CONFIG_INT_PROMPT_DEFAULT_ABOVE_RANGE=4
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user