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:
Linus Torvalds 2026-10-21 10:45:44 -10:00
commit bb29b957ea
127 changed files with 2382 additions and 686 deletions

3
.gitignore vendored
View File

@ -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/

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
****************

View File

@ -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*

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
#

View File

@ -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) \

View File

@ -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

View File

@ -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>

View File

@ -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"

View File

@ -855,7 +855,7 @@
KLP_SYMID
#define MODINFO \
.modinfo : { *(.modinfo) . = ALIGN(8); }
.modinfo (INFO) : { KEEP(*(.modinfo)) }
#ifdef CONFIG_GENERIC_BUG
#define BUG_TABLE \

View File

@ -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

View File

@ -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
View File

@ -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

View File

@ -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
View 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)"

View File

@ -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

View File

@ -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

View File

@ -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)
# ---------------------------------------------------------------------------

View File

@ -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

View File

@ -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
# ---------------------------------------------------------------------------

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -12,6 +12,7 @@ compile_commands.json.
import argparse
import json
import multiprocessing
import os
import subprocess
import sys

View File

@ -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',

View File

@ -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;
}

View File

@ -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 */

View File

@ -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++) {

View File

@ -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

View File

@ -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
View 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);
}

View File

@ -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
View 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 */

View File

@ -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");

View File

@ -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 {

View File

@ -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/#.*//;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -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";
}

View File

@ -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);

View File

@ -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."""

View 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

View 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')

View 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

View 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

View File

@ -0,0 +1 @@
# CONFIG_GUARD is not set

View File

@ -0,0 +1 @@
CONFIG_GUARD=y

View 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

View 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')

View 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

View 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

View 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')

View 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'

View 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

View File

@ -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')

View File

@ -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'

View File

@ -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

View File

@ -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"

View 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"

View 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

View 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

View 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')

View 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