aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/.gitignore18
-rw-r--r--scripts/Kbuild.include260
-rw-r--r--scripts/Kconfig.include16
-rw-r--r--scripts/Makefile26
-rw-r--r--scripts/Makefile.asm-generic8
-rw-r--r--scripts/Makefile.build347
-rw-r--r--scripts/Makefile.clang39
-rw-r--r--scripts/Makefile.clean19
-rw-r--r--scripts/Makefile.compiler74
-rw-r--r--scripts/Makefile.debug44
-rw-r--r--scripts/Makefile.defconf29
-rw-r--r--scripts/Makefile.dtbinst6
-rw-r--r--scripts/Makefile.extrawarn30
-rw-r--r--scripts/Makefile.gcc-plugins32
-rw-r--r--scripts/Makefile.headersinst2
-rw-r--r--scripts/Makefile.host48
-rw-r--r--scripts/Makefile.kasan41
-rw-r--r--scripts/Makefile.kcsan15
-rw-r--r--scripts/Makefile.kmsan8
-rw-r--r--scripts/Makefile.lib260
-rw-r--r--scripts/Makefile.modfinal43
-rw-r--r--scripts/Makefile.modinst117
-rw-r--r--scripts/Makefile.modpost148
-rw-r--r--scripts/Makefile.modsign29
-rw-r--r--scripts/Makefile.package278
-rw-r--r--scripts/Makefile.randstruct17
-rw-r--r--scripts/Makefile.ubsan3
-rw-r--r--scripts/Makefile.vmlinux53
-rw-r--r--scripts/Makefile.vmlinux_o104
-rwxr-xr-xscripts/adjust_autoksyms.sh73
-rwxr-xr-xscripts/as-version.sh82
-rw-r--r--scripts/asn1_compiler.c12
-rwxr-xr-xscripts/atomic/atomic-tbl.sh112
-rw-r--r--[-rwxr-xr-x]scripts/atomic/atomics.tbl4
-rwxr-xr-xscripts/atomic/check-atomics.sh34
-rwxr-xr-xscripts/atomic/fallbacks/acquire6
-rwxr-xr-xscripts/atomic/fallbacks/add_negative15
-rwxr-xr-xscripts/atomic/fallbacks/add_unless15
-rwxr-xr-xscripts/atomic/fallbacks/andnot6
-rw-r--r--scripts/atomic/fallbacks/cmpxchg3
-rwxr-xr-xscripts/atomic/fallbacks/dec6
-rwxr-xr-xscripts/atomic/fallbacks/dec_and_test14
-rwxr-xr-xscripts/atomic/fallbacks/dec_if_positive8
-rwxr-xr-xscripts/atomic/fallbacks/dec_unless_positive8
-rwxr-xr-xscripts/atomic/fallbacks/fence6
-rwxr-xr-xscripts/atomic/fallbacks/fetch_add_unless17
-rwxr-xr-xscripts/atomic/fallbacks/inc6
-rwxr-xr-xscripts/atomic/fallbacks/inc_and_test14
-rwxr-xr-xscripts/atomic/fallbacks/inc_not_zero13
-rwxr-xr-xscripts/atomic/fallbacks/inc_unless_negative8
-rwxr-xr-xscripts/atomic/fallbacks/read_acquire15
-rwxr-xr-xscripts/atomic/fallbacks/release6
-rwxr-xr-xscripts/atomic/fallbacks/set_release11
-rwxr-xr-xscripts/atomic/fallbacks/sub_and_test15
-rwxr-xr-xscripts/atomic/fallbacks/try_cmpxchg6
-rw-r--r--scripts/atomic/fallbacks/xchg3
-rwxr-xr-xscripts/atomic/gen-atomic-fallback.sh295
-rwxr-xr-xscripts/atomic/gen-atomic-instrumented.sh127
-rwxr-xr-xscripts/atomic/gen-atomic-long.sh44
-rwxr-xr-xscripts/atomic/gen-atomics.sh7
-rw-r--r--scripts/atomic/kerneldoc/add13
-rw-r--r--scripts/atomic/kerneldoc/add_negative13
-rw-r--r--scripts/atomic/kerneldoc/add_unless18
-rw-r--r--scripts/atomic/kerneldoc/and13
-rw-r--r--scripts/atomic/kerneldoc/andnot13
-rw-r--r--scripts/atomic/kerneldoc/cmpxchg14
-rw-r--r--scripts/atomic/kerneldoc/dec12
-rw-r--r--scripts/atomic/kerneldoc/dec_and_test12
-rw-r--r--scripts/atomic/kerneldoc/dec_if_positive12
-rw-r--r--scripts/atomic/kerneldoc/dec_unless_positive12
-rw-r--r--scripts/atomic/kerneldoc/inc12
-rw-r--r--scripts/atomic/kerneldoc/inc_and_test12
-rw-r--r--scripts/atomic/kerneldoc/inc_not_zero12
-rw-r--r--scripts/atomic/kerneldoc/inc_unless_negative12
-rw-r--r--scripts/atomic/kerneldoc/or13
-rw-r--r--scripts/atomic/kerneldoc/read12
-rw-r--r--scripts/atomic/kerneldoc/set13
-rw-r--r--scripts/atomic/kerneldoc/sub13
-rw-r--r--scripts/atomic/kerneldoc/sub_and_test13
-rw-r--r--scripts/atomic/kerneldoc/try_cmpxchg15
-rw-r--r--scripts/atomic/kerneldoc/xchg13
-rw-r--r--scripts/atomic/kerneldoc/xor13
-rw-r--r--scripts/basic/.gitignore3
-rw-r--r--scripts/basic/Makefile11
-rw-r--r--scripts/basic/fixdep.c315
-rw-r--r--scripts/bin2c.c36
-rwxr-xr-xscripts/bloat-o-meter51
-rwxr-xr-xscripts/bpf_doc.py (renamed from scripts/bpf_helpers_doc.py)420
-rwxr-xr-xscripts/cc-version.sh36
-rwxr-xr-xscripts/check-git14
-rwxr-xr-xscripts/check-sysctl-docs26
-rwxr-xr-xscripts/check_extable.sh2
-rwxr-xr-xscripts/checkdeclares.pl53
-rwxr-xr-xscripts/checkkconfigsymbols.py26
-rwxr-xr-xscripts/checkpatch.pl598
-rwxr-xr-xscripts/checkstack.pl11
-rwxr-xr-xscripts/checksyscalls.sh16
-rwxr-xr-xscripts/checkversion.pl18
-rwxr-xr-xscripts/clang-tools/gen_compile_commands.py36
-rwxr-xr-xscripts/clang-tools/run-clang-tools.py32
-rwxr-xr-xscripts/coccicheck8
-rw-r--r--scripts/coccinelle/api/alloc/zalloc-simple.cocci2
-rw-r--r--scripts/coccinelle/api/atomic_as_refcounter.cocci10
-rw-r--r--scripts/coccinelle/api/check_bq27xxx_data.cocci2
-rw-r--r--scripts/coccinelle/api/d_find_alias.cocci2
-rw-r--r--scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci68
-rw-r--r--scripts/coccinelle/api/err_cast.cocci2
-rw-r--r--scripts/coccinelle/api/kobj_to_dev.cocci45
-rw-r--r--scripts/coccinelle/api/kstrdup.cocci2
-rw-r--r--scripts/coccinelle/api/kvmalloc.cocci2
-rw-r--r--scripts/coccinelle/api/memdup.cocci2
-rw-r--r--scripts/coccinelle/api/memdup_user.cocci2
-rw-r--r--scripts/coccinelle/api/pm_runtime.cocci2
-rw-r--r--scripts/coccinelle/api/resource_size.cocci2
-rw-r--r--scripts/coccinelle/free/clk_put.cocci2
-rw-r--r--scripts/coccinelle/free/devm_free.cocci2
-rw-r--r--scripts/coccinelle/free/ifnulldev_put.cocci55
-rw-r--r--scripts/coccinelle/free/iounmap.cocci2
-rw-r--r--scripts/coccinelle/free/kfree.cocci14
-rw-r--r--scripts/coccinelle/free/kfreeaddr.cocci2
-rw-r--r--scripts/coccinelle/free/pci_free_consistent.cocci2
-rw-r--r--scripts/coccinelle/iterators/device_node_continue.cocci2
-rw-r--r--scripts/coccinelle/iterators/fen.cocci124
-rw-r--r--scripts/coccinelle/iterators/for_each_child.cocci2
-rw-r--r--scripts/coccinelle/iterators/itnull.cocci2
-rw-r--r--scripts/coccinelle/iterators/list_entry_update.cocci2
-rw-r--r--scripts/coccinelle/iterators/use_after_iter.cocci4
-rw-r--r--scripts/coccinelle/locks/call_kern.cocci2
-rw-r--r--scripts/coccinelle/locks/double_lock.cocci2
-rw-r--r--scripts/coccinelle/locks/flags.cocci2
-rw-r--r--scripts/coccinelle/locks/mini_lock.cocci2
-rw-r--r--scripts/coccinelle/misc/boolreturn.cocci59
-rw-r--r--scripts/coccinelle/misc/bugon.cocci63
-rw-r--r--scripts/coccinelle/misc/cstptr.cocci2
-rw-r--r--scripts/coccinelle/misc/do_div.cocci155
-rw-r--r--scripts/coccinelle/misc/doubleinit.cocci2
-rw-r--r--scripts/coccinelle/misc/flexible_array.cocci23
-rw-r--r--scripts/coccinelle/misc/ifcol.cocci2
-rw-r--r--scripts/coccinelle/misc/irqf_oneshot.cocci4
-rw-r--r--scripts/coccinelle/misc/minmax.cocci222
-rw-r--r--scripts/coccinelle/misc/newline_in_nl_msg.cocci2
-rw-r--r--scripts/coccinelle/misc/noderef.cocci2
-rw-r--r--scripts/coccinelle/misc/orplus.cocci2
-rw-r--r--scripts/coccinelle/misc/returnvar.cocci2
-rw-r--r--scripts/coccinelle/misc/semicolon.cocci2
-rw-r--r--scripts/coccinelle/misc/swap.cocci122
-rw-r--r--scripts/coccinelle/misc/test_addr.cocci (renamed from scripts/coccinelle/misc/ifaddr.cocci)6
-rw-r--r--scripts/coccinelle/misc/uninitialized_var.cocci15
-rw-r--r--scripts/coccinelle/misc/warn.cocci2
-rw-r--r--scripts/coccinelle/null/badzero.cocci2
-rw-r--r--scripts/coccinelle/null/deref_null.cocci2
-rw-r--r--scripts/coccinelle/null/eno.cocci2
-rw-r--r--scripts/coccinelle/null/kmerr.cocci2
-rw-r--r--scripts/coccinelle/tests/doublebitand.cocci2
-rw-r--r--scripts/coccinelle/tests/doubletest.cocci2
-rw-r--r--scripts/coccinelle/tests/odd_ptr_err.cocci2
-rw-r--r--scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci2
-rw-r--r--scripts/const_structs.checkpatch28
-rwxr-xr-xscripts/decode_stacktrace.sh128
-rwxr-xr-xscripts/decodecode132
-rwxr-xr-xscripts/depmod.sh6
-rwxr-xr-xscripts/diffconfig16
-rwxr-xr-xscripts/documentation-file-ref-check6
-rw-r--r--scripts/dtc/.gitignore4
-rw-r--r--scripts/dtc/Makefile13
-rw-r--r--scripts/dtc/checks.c237
-rwxr-xr-xscripts/dtc/dt-extract-compatibles69
-rw-r--r--scripts/dtc/dtc-lexer.l4
-rw-r--r--scripts/dtc/dtc-parser.y24
-rw-r--r--scripts/dtc/dtc.c6
-rw-r--r--scripts/dtc/dtc.h40
-rwxr-xr-xscripts/dtc/dtx_diff8
-rw-r--r--scripts/dtc/flattree.c11
l---------scripts/dtc/include-prefixes/c6x1
l---------scripts/dtc/include-prefixes/h83001
l---------scripts/dtc/include-prefixes/riscv1
-rw-r--r--scripts/dtc/libfdt/fdt.c24
-rw-r--r--scripts/dtc/libfdt/fdt.h4
-rw-r--r--scripts/dtc/libfdt/fdt_addresses.c2
-rw-r--r--scripts/dtc/libfdt/fdt_overlay.c29
-rw-r--r--scripts/dtc/libfdt/fdt_ro.c2
-rw-r--r--scripts/dtc/libfdt/fdt_rw.c18
-rw-r--r--scripts/dtc/libfdt/fdt_strerror.c1
-rw-r--r--scripts/dtc/libfdt/libfdt.h32
-rw-r--r--scripts/dtc/livetree.c45
-rwxr-xr-xscripts/dtc/of_unittest_expect541
-rw-r--r--scripts/dtc/treesource.c48
-rwxr-xr-xscripts/dtc/update-dtc-source.sh2
-rw-r--r--scripts/dtc/util.c15
-rw-r--r--scripts/dtc/util.h10
-rw-r--r--scripts/dtc/version_gen.h2
-rw-r--r--scripts/dtc/yamltree.c16
-rw-r--r--scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h0
-rwxr-xr-xscripts/dummy-tools/gcc37
-rwxr-xr-xscripts/dummy-tools/pahole4
-rw-r--r--scripts/extract-cert.c162
-rwxr-xr-xscripts/extract-ikconfig1
-rwxr-xr-xscripts/faddr2line185
-rwxr-xr-xscripts/gcc-goto.sh22
-rwxr-xr-xscripts/gcc-ld30
-rw-r--r--scripts/gcc-plugins/.gitignore2
-rw-r--r--scripts/gcc-plugins/Kconfig58
-rw-r--r--scripts/gcc-plugins/Makefile25
-rw-r--r--scripts/gcc-plugins/arm_ssp_per_task_plugin.c27
-rw-r--r--scripts/gcc-plugins/cyc_complexity_plugin.c69
-rw-r--r--scripts/gcc-plugins/gcc-common.h136
-rw-r--r--scripts/gcc-plugins/gcc-generate-gimple-pass.h19
-rw-r--r--scripts/gcc-plugins/gcc-generate-ipa-pass.h19
-rw-r--r--scripts/gcc-plugins/gcc-generate-rtl-pass.h19
-rw-r--r--scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h19
-rw-r--r--scripts/gcc-plugins/gen-random-seed.sh9
-rw-r--r--scripts/gcc-plugins/latent_entropy_plugin.c50
-rw-r--r--scripts/gcc-plugins/randomize_layout_plugin.c89
-rw-r--r--scripts/gcc-plugins/sancov_plugin.c2
-rw-r--r--scripts/gcc-plugins/stackleak_plugin.c33
-rw-r--r--scripts/gcc-plugins/structleak_plugin.c9
-rwxr-xr-xscripts/gcc-x86_32-has-stack-protector.sh6
-rw-r--r--scripts/gdb/linux/clk.py2
-rw-r--r--scripts/gdb/linux/config.py6
-rw-r--r--scripts/gdb/linux/constants.py.in42
-rw-r--r--scripts/gdb/linux/cpus.py29
-rw-r--r--scripts/gdb/linux/dmesg.py42
-rw-r--r--scripts/gdb/linux/genpd.py4
-rw-r--r--scripts/gdb/linux/interrupts.py232
-rw-r--r--scripts/gdb/linux/mm.py222
-rw-r--r--scripts/gdb/linux/modules.py14
-rw-r--r--scripts/gdb/linux/proc.py16
-rw-r--r--scripts/gdb/linux/radixtree.py90
-rw-r--r--scripts/gdb/linux/symbols.py12
-rw-r--r--scripts/gdb/linux/timerlist.py12
-rw-r--r--scripts/gdb/linux/utils.py27
-rw-r--r--scripts/gdb/linux/vfs.py59
-rw-r--r--scripts/gdb/vmlinux-gdb.py11
-rwxr-xr-xscripts/gen-randstruct-seed.sh7
-rwxr-xr-xscripts/gen_autoksyms.sh72
-rwxr-xr-xscripts/gen_ksymdeps.sh25
-rwxr-xr-xscripts/generate_rust_analyzer.py144
-rw-r--r--scripts/generate_rust_target.rs182
-rw-r--r--scripts/genksyms/.gitignore2
-rw-r--r--scripts/genksyms/Makefile2
-rw-r--r--scripts/genksyms/genksyms.c18
-rwxr-xr-xscripts/get_abi.pl574
-rwxr-xr-xscripts/get_feat.pl13
-rwxr-xr-xscripts/get_maintainer.pl3
-rwxr-xr-xscripts/gfp-translate6
-rw-r--r--scripts/head-object-list.txt45
-rwxr-xr-xscripts/headers_check.pl171
-rwxr-xr-xscripts/headers_install.sh6
-rwxr-xr-xscripts/install.sh40
-rwxr-xr-xscripts/is_rust_module.sh16
-rwxr-xr-xscripts/jobserver-exec25
-rw-r--r--scripts/kallsyms.c376
-rw-r--r--scripts/kconfig/.gitignore15
-rw-r--r--scripts/kconfig/Makefile69
-rw-r--r--scripts/kconfig/conf.c389
-rw-r--r--scripts/kconfig/confdata.c836
-rw-r--r--scripts/kconfig/expr.h6
-rwxr-xr-xscripts/kconfig/gconf-cfg.sh15
-rw-r--r--scripts/kconfig/gconf.c26
-rw-r--r--scripts/kconfig/internal.h9
-rw-r--r--scripts/kconfig/lexer.l12
-rw-r--r--scripts/kconfig/lkc.h29
-rw-r--r--scripts/kconfig/lkc_proto.h3
-rw-r--r--scripts/kconfig/lxdialog/dialog.h27
-rw-r--r--scripts/kconfig/lxdialog/menubox.c8
-rw-r--r--scripts/kconfig/lxdialog/textbox.c267
-rw-r--r--scripts/kconfig/lxdialog/util.c4
-rwxr-xr-xscripts/kconfig/mconf-cfg.sh31
-rw-r--r--scripts/kconfig/mconf.c340
-rw-r--r--scripts/kconfig/menu.c70
-rwxr-xr-xscripts/kconfig/merge_config.sh40
-rwxr-xr-xscripts/kconfig/nconf-cfg.sh31
-rw-r--r--scripts/kconfig/nconf.c66
-rw-r--r--scripts/kconfig/nconf.gui.c284
-rw-r--r--scripts/kconfig/nconf.h51
-rw-r--r--scripts/kconfig/parser.y27
-rw-r--r--scripts/kconfig/preprocess.c5
-rwxr-xr-xscripts/kconfig/qconf-cfg.sh19
-rw-r--r--scripts/kconfig/qconf.cc1
-rwxr-xr-xscripts/kconfig/streamline_config.pl88
-rw-r--r--scripts/kconfig/symbol.c46
-rw-r--r--scripts/kconfig/tests/choice/Kconfig2
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/Kconfig2
-rw-r--r--scripts/kconfig/tests/conftest.py4
-rw-r--r--scripts/kconfig/tests/inter_choice/Kconfig2
-rw-r--r--scripts/kconfig/util.c2
-rwxr-xr-xscripts/kernel-doc679
-rwxr-xr-xscripts/ld-version.sh31
-rwxr-xr-xscripts/leaking_addresses.pl4
-rwxr-xr-xscripts/link-vmlinux.sh301
-rwxr-xr-xscripts/min-tool-version.sh43
-rwxr-xr-xscripts/misc-check19
-rwxr-xr-xscripts/mkcompile_h83
-rwxr-xr-xscripts/mkmakefile17
-rwxr-xr-xscripts/mksysmap129
-rw-r--r--scripts/mod/.gitignore8
-rw-r--r--scripts/mod/devicetable-offsets.c9
-rw-r--r--scripts/mod/file2alias.c114
-rw-r--r--scripts/mod/list.h213
-rw-r--r--scripts/mod/modpost.c1936
-rw-r--r--scripts/mod/modpost.h82
-rw-r--r--scripts/mod/sumversion.c30
-rw-r--r--scripts/module.lds.S17
-rwxr-xr-xscripts/modules-check.sh4
-rw-r--r--scripts/nsdeps7
-rwxr-xr-xscripts/objdiff6
-rwxr-xr-xscripts/objdump-func45
-rw-r--r--scripts/orc_hash.sh16
-rwxr-xr-xscripts/package/builddeb278
-rwxr-xr-xscripts/package/buildtar58
-rwxr-xr-xscripts/package/deb-build-option14
-rwxr-xr-xscripts/package/gen-diff-patch36
-rwxr-xr-xscripts/package/mkdebian112
-rwxr-xr-xscripts/package/mkspec39
-rwxr-xr-xscripts/pahole-flags.sh30
-rwxr-xr-xscripts/pahole-version.sh13
-rwxr-xr-xscripts/prune-kernel6
-rw-r--r--scripts/recordmcount.c47
-rw-r--r--scripts/recordmcount.h15
-rwxr-xr-xscripts/recordmcount.pl77
-rwxr-xr-xscripts/relocs_check.sh20
-rwxr-xr-xscripts/remove-stale-files39
-rwxr-xr-xscripts/rust_is_available.sh162
-rw-r--r--scripts/rust_is_available_bindgen_libclang.h2
-rw-r--r--scripts/selinux/genheaders/genheaders.c75
-rwxr-xr-xscripts/selinux/install_policy.sh5
-rw-r--r--scripts/selinux/mdp/mdp.c4
-rwxr-xr-xscripts/setlocalversion216
-rw-r--r--scripts/sign-file.c9
-rw-r--r--scripts/sorttable.c65
-rw-r--r--scripts/sorttable.h127
-rw-r--r--scripts/spdxcheck-test.sh16
-rwxr-xr-xscripts/spdxcheck.py182
-rw-r--r--scripts/spdxexclude18
-rw-r--r--scripts/spelling.txt151
-rwxr-xr-xscripts/sphinx-pre-install346
-rw-r--r--scripts/subarch.include4
-rwxr-xr-xscripts/syscallhdr.sh2
-rwxr-xr-xscripts/syscallnr.sh74
-rwxr-xr-xscripts/syscalltbl.sh7
-rwxr-xr-xscripts/tags.sh176
-rwxr-xr-xscripts/test_dwarf5_support.sh8
-rw-r--r--scripts/test_fortify.sh66
-rwxr-xr-xscripts/tools-support-relr.sh7
-rwxr-xr-xscripts/tracing/draw_functrace.py14
-rwxr-xr-xscripts/tracing/ftrace-bisect.sh34
-rwxr-xr-xscripts/ver_linux1
-rwxr-xr-x[-rw-r--r--]scripts/xen-hypercalls.sh0
348 files changed, 12648 insertions, 7802 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore
index a6c11316c969..6e9ce6720a05 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -1,11 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
-bin2c
-kallsyms
-unifdef
-recordmcount
-sorttable
-asn1_compiler
-extract-cert
-sign-file
-insert-sys-cert
+/asn1_compiler
+/generate_rust_target
+/insert-sys-cert
+/kallsyms
/module.lds
+/recordmcount
+/sign-file
+/sorttable
+/target.json
+/unifdef
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 509e0856d653..7778cc97a4e0 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -10,12 +10,36 @@ empty :=
space := $(empty) $(empty)
space_escape := _-_SPACE_-_
pound := \#
+define newline
+
+
+endef
+
+###
+# Comparison macros.
+# Usage: $(call test-lt, $(CONFIG_LLD_VERSION), 150000)
+#
+# Use $(intcmp ...) if supported. (Make >= 4.4)
+# Otherwise, fall back to the 'test' shell command.
+ifeq ($(intcmp 1,0,,,y),y)
+test-ge = $(intcmp $(strip $1)0, $(strip $2)0,,y,y)
+test-gt = $(intcmp $(strip $1)0, $(strip $2)0,,,y)
+else
+test-ge = $(shell test $(strip $1)0 -ge $(strip $2)0 && echo y)
+test-gt = $(shell test $(strip $1)0 -gt $(strip $2)0 && echo y)
+endif
+test-le = $(call test-ge, $2, $1)
+test-lt = $(call test-gt, $2, $1)
###
# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
dot-target = $(dir $@).$(notdir $@)
###
+# Name of target with a '.tmp_' as filename prefix. foo/bar.o => foo/.tmp_bar.o
+tmp-target = $(dir $@).tmp_$(notdir $@)
+
+###
# The temporary file to save gcc -MMD generated dependencies must not
# contain a comma
depfile = $(subst $(comma),_,$(dot-target).d)
@@ -37,6 +61,21 @@ escsq = $(subst $(squote),'\$(squote)',$1)
stringify = $(squote)$(quote)$1$(quote)$(squote)
###
+# The path to Kbuild or Makefile. Kbuild has precedence over Makefile.
+kbuild-dir = $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+kbuild-file = $(or $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Makefile)
+
+###
+# Read a file, replacing newlines with spaces
+#
+# Make 4.2 or later can read a file by using its builtin function.
+ifneq ($(filter-out 3.% 4.0 4.1, $(MAKE_VERSION)),)
+read-file = $(subst $(newline),$(space),$(file < $1))
+else
+read-file = $(shell cat $1 2>/dev/null)
+endif
+
+###
# Easy method for doing a status message
kecho := :
quiet_kecho := echo
@@ -57,96 +96,17 @@ kecho := $($(quiet)kecho)
# - If the content differ the new file is used
# - If they are equal no change, and no timestamp update
define filechk
+ $(check-FORCE)
$(Q)set -e; \
mkdir -p $(dir $@); \
- trap "rm -f $(dot-target).tmp" EXIT; \
- { $(filechk_$(1)); } > $(dot-target).tmp; \
- if [ ! -r $@ ] || ! cmp -s $@ $(dot-target).tmp; then \
+ trap "rm -f $(tmp-target)" EXIT; \
+ { $(filechk_$(1)); } > $(tmp-target); \
+ if [ ! -r $@ ] || ! cmp -s $@ $(tmp-target); then \
$(kecho) ' UPD $@'; \
- mv -f $(dot-target).tmp $@; \
+ mv -f $(tmp-target) $@; \
fi
endef
-######
-# gcc support functions
-# See documentation in Documentation/kbuild/makefiles.rst
-
-# cc-cross-prefix
-# Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-)
-# Return first <prefix> where a <prefix>gcc is found in PATH.
-# If no gcc found in PATH with listed prefixes return nothing
-#
-# Note: '2>/dev/null' is here to force Make to invoke a shell. Otherwise, it
-# would try to directly execute the shell builtin 'command'. This workaround
-# should be kept for a long time since this issue was fixed only after the
-# GNU Make 4.2.1 release.
-cc-cross-prefix = $(firstword $(foreach c, $(1), \
- $(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c))))
-
-# output directory for tests below
-TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$
-
-# try-run
-# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
-# Exit code chooses option. "$$TMP" serves as a temporary file and is
-# automatically cleaned up.
-try-run = $(shell set -e; \
- TMP=$(TMPOUT)/tmp; \
- TMPO=$(TMPOUT)/tmp.o; \
- mkdir -p $(TMPOUT); \
- trap "rm -rf $(TMPOUT)" EXIT; \
- if ($(1)) >/dev/null 2>&1; \
- then echo "$(2)"; \
- else echo "$(3)"; \
- fi)
-
-# as-option
-# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
-
-as-option = $(call try-run,\
- $(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2))
-
-# as-instr
-# Usage: cflags-y += $(call as-instr,instr,option1,option2)
-
-as-instr = $(call try-run,\
- printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3))
-
-# __cc-option
-# Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586)
-__cc-option = $(call try-run,\
- $(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4))
-
-# cc-option
-# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
-
-cc-option = $(call __cc-option, $(CC),\
- $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS),$(1),$(2))
-
-# cc-option-yn
-# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
-cc-option-yn = $(call try-run,\
- $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
-
-# cc-disable-warning
-# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
-cc-disable-warning = $(call try-run,\
- $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
-
-# cc-ifversion
-# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
-cc-ifversion = $(shell [ $(CONFIG_GCC_VERSION)0 $(1) $(2)000 ] && echo $(3) || echo $(4))
-
-# ld-option
-# Usage: KBUILD_LDFLAGS += $(call ld-option, -X, -Y)
-ld-option = $(call try-run, $(LD) $(KBUILD_LDFLAGS) $(1) -v,$(1),$(2),$(3))
-
-# ld-ifversion
-# Usage: $(call ld-ifversion, -ge, 22252, y)
-ld-ifversion = $(shell [ $(CONFIG_LD_VERSION)0 $(1) $(2)0 ] && echo $(3) || echo $(4))
-
-######
-
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
@@ -165,13 +125,39 @@ dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj
# $(Q)$(MAKE) $(clean)=dir
clean := -f $(srctree)/scripts/Makefile.clean obj
-# echo command.
-# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
-echo-cmd = $(if $($(quiet)cmd_$(1)),\
- echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
+# pring log
+#
+# If quiet is "silent_", print nothing and sink stdout
+# If quiet is "quiet_", print short log
+# If quiet is empty, print short log and whole command
+silent_log_print = exec >/dev/null;
+ quiet_log_print = $(if $(quiet_cmd_$1), echo ' $(call escsq,$(quiet_cmd_$1)$(why))';)
+ log_print = echo '$(pound) $(call escsq,$(or $(quiet_cmd_$1),cmd_$1 $@)$(why))'; \
+ echo ' $(call escsq,$(cmd_$1))';
+
+# Delete the target on interruption
+#
+# GNU Make automatically deletes the target if it has already been changed by
+# the interrupted recipe. So, you can safely stop the build by Ctrl-C (Make
+# will delete incomplete targets), and resume it later.
+#
+# However, this does not work when the stderr is piped to another program, like
+# $ make >&2 | tee log
+# Make dies with SIGPIPE before cleaning the targets.
+#
+# To address it, we clean the target in signal traps.
+#
+# Make deletes the target when it catches SIGHUP, SIGINT, SIGQUIT, SIGTERM.
+# So, we cover them, and also SIGPIPE just in case.
+#
+# Of course, this is unneeded for phony targets.
+delete-on-interrupt = \
+ $(if $(filter-out $(PHONY), $@), \
+ $(foreach sig, HUP INT QUIT TERM PIPE, \
+ trap 'rm -f $@; trap - $(sig); kill -s $(sig) $$$$' $(sig);))
-# printing commands
-cmd = @set -e; $(echo-cmd) $(cmd_$(1))
+# print and execute commands
+cmd = @$(if $(cmd_$(1)),set -e; $($(quiet)log_print) $(delete-on-interrupt) $(cmd_$(1)),:)
###
# if_changed - execute command if any prerequisite is newer than
@@ -184,10 +170,14 @@ cmd = @set -e; $(echo-cmd) $(cmd_$(1))
ifneq ($(KBUILD_NOCMDDEP),1)
# Check if both commands are the same including their order. Result is empty
# string if equal. User may override this check using make KBUILD_NOCMDDEP=1
-cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \
+# If the target does not exist, the *.cmd file should not be included so
+# $(savedcmd_$@) gets empty. Then, target will be built even if $(newer-prereqs)
+# happens to become empty.
+cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(savedcmd_$@))), \
$(subst $(space),$(space_escape),$(strip $(cmd_$1))))
else
-cmd-check = $(if $(strip $(cmd_$@)),,1)
+# We still need to detect missing targets.
+cmd-check = $(if $(strip $(savedcmd_$@)),,1)
endif
# Replace >$< with >$$< to preserve $ when reloading the .cmd file
@@ -199,19 +189,26 @@ endif
make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1)))))
# Find any prerequisites that are newer than target or that do not exist.
-# (This is not true for now; $? should contain any non-existent prerequisites,
-# but it does not work as expected when .SECONDARY is present. This seems a bug
-# of GNU Make.)
# PHONY targets skipped in both cases.
+# If there is no prerequisite other than phony targets, $(newer-prereqs) becomes
+# empty even if the target does not exist. cmd-check saves this corner case.
newer-prereqs = $(filter-out $(PHONY),$?)
+# It is a typical mistake to forget the FORCE prerequisite. Check it here so
+# no more breakage will slip in.
+check-FORCE = $(if $(filter FORCE, $^),,$(warning FORCE prerequisite is missing))
+
+if-changed-cond = $(newer-prereqs)$(cmd-check)$(check-FORCE)
+
# Execute command if command has changed or prerequisite(s) are updated.
-if_changed = $(if $(newer-prereqs)$(cmd-check), \
+if_changed = $(if $(if-changed-cond),$(cmd_and_savecmd),@:)
+
+cmd_and_savecmd = \
$(cmd); \
- printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
+ printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd
# Execute the command and also postprocess generated .d dependencies file.
-if_changed_dep = $(if $(newer-prereqs)$(cmd-check),$(cmd_and_fixdep),@:)
+if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:)
cmd_and_fixdep = \
$(cmd); \
@@ -221,7 +218,7 @@ cmd_and_fixdep = \
# Usage: $(call if_changed_rule,foo)
# Will check if $(cmd_foo) or any of the prerequisites changed,
# and if so will execute $(rule_foo).
-if_changed_rule = $(if $(newer-prereqs)$(cmd-check),$(rule_$(1)),@:)
+if_changed_rule = $(if $(if-changed-cond),$(rule_$(1)),@:)
###
# why - tell why a target got built
@@ -242,13 +239,13 @@ if_changed_rule = $(if $(newer-prereqs)$(cmd-check),$(rule_$(1)),@:)
# (5) No dir/.target.cmd file (used to store command line)
# (6) No dir/.target.cmd file and target not listed in $(targets)
# This is a good hint that there is a bug in the kbuild file
-ifeq ($(KBUILD_VERBOSE),2)
-why = \
+ifneq ($(findstring 2, $(KBUILD_VERBOSE)),)
+_why = \
$(if $(filter $@, $(PHONY)),- due to target is PHONY, \
$(if $(wildcard $@), \
$(if $(newer-prereqs),- due to: $(newer-prereqs), \
$(if $(cmd-check), \
- $(if $(cmd_$@),- due to command line change, \
+ $(if $(savedcmd_$@),- due to command line change, \
$(if $(filter $@, $(targets)), \
- due to missing .cmd file, \
- due to $(notdir $@) not in $$(targets) \
@@ -260,60 +257,23 @@ why = \
) \
)
-echo-why = $(call escsq, $(strip $(why)))
+why = $(space)$(strip $(_why))
endif
###############################################################################
-#
-# When a Kconfig string contains a filename, it is suitable for
-# passing to shell commands. It is surrounded by double-quotes, and
-# any double-quotes or backslashes within it are escaped by
-# backslashes.
-#
-# This is no use for dependencies or $(wildcard). We need to strip the
-# surrounding quotes and the escaping from quotes and backslashes, and
-# we *do* need to escape any spaces in the string. So, for example:
-#
-# Usage: $(eval $(call config_filename,FOO))
-#
-# Defines FOO_FILENAME based on the contents of the CONFIG_FOO option,
-# transformed as described above to be suitable for use within the
-# makefile.
-#
-# Also, if the filename is a relative filename and exists in the source
-# tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to
-# be prefixed to *both* command invocation and dependencies.
-#
-# Note: We also print the filenames in the quiet_cmd_foo text, and
-# perhaps ought to have a version specially escaped for that purpose.
-# But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good
-# enough. It'll strip the quotes in the common case where there's no
-# space and it's a simple filename, and it'll retain the quotes when
-# there's a space. There are some esoteric cases in which it'll print
-# the wrong thing, but we don't really care. The actual dependencies
-# and commands *do* get it right, with various combinations of single
-# and double quotes, backslashes and spaces in the filenames.
-#
-###############################################################################
-#
-define config_filename
-ifneq ($$(CONFIG_$(1)),"")
-$(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1)))))))
-ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME)))
-else
-ifeq ($$(wildcard $$($(1)_FILENAME)),)
-ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),)
-$(1)_SRCPREFIX := $(srctree)/
-endif
-endif
-endif
-endif
-endef
-#
-###############################################################################
# delete partially updated (i.e. corrupted) files on error
.DELETE_ON_ERROR:
# do not delete intermediate files automatically
+#
+# .NOTINTERMEDIATE is more correct, but only available on newer Make versions.
+# Make 4.4 introduced .NOTINTERMEDIATE, and it appears in .FEATURES, but the
+# global .NOTINTERMEDIATE does not work. We can use it on Make > 4.4.
+# Use .SECONDARY for older Make versions, but "newer-prereq" cannot detect
+# deleted files.
+ifneq ($(and $(filter notintermediate, $(.FEATURES)),$(filter-out 4.4,$(MAKE_VERSION))),)
+.NOTINTERMEDIATE:
+else
.SECONDARY:
+endif
diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include
index 58fdb5308725..5a84b6443875 100644
--- a/scripts/Kconfig.include
+++ b/scripts/Kconfig.include
@@ -25,7 +25,7 @@ failure = $(if-success,$(1),n,y)
# $(cc-option,<flag>)
# Return y if the compiler supports <flag>, n otherwise
-cc-option = $(success,mkdir .tmp_$$$$; trap "rm -rf .tmp_$$$$" EXIT; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$$$/tmp.o)
+cc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$/tmp.o)
# $(ld-option,<flag>)
# Return y if the linker supports <flag>, n otherwise
@@ -33,18 +33,24 @@ ld-option = $(success,$(LD) -v $(1))
# $(as-instr,<instr>)
# Return y if the assembler supports <instr>, n otherwise
-as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler -o /dev/null -)
+as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler-with-cpp -o /dev/null -)
# check if $(CC) and $(LD) exist
-$(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found)
+$(error-if,$(failure,command -v $(CC)),C compiler '$(CC)' not found)
$(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found)
-# Get the compiler name, version, and error out if it is not supported.
+# Get the C compiler name, version, and error out if it is not supported.
cc-info := $(shell,$(srctree)/scripts/cc-version.sh $(CC))
-$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this compiler is not supported.)
+$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this C compiler is not supported.)
cc-name := $(shell,set -- $(cc-info) && echo $1)
cc-version := $(shell,set -- $(cc-info) && echo $2)
+# Get the assembler name, version, and error out if it is not supported.
+as-info := $(shell,$(srctree)/scripts/as-version.sh $(CC) $(CLANG_FLAGS))
+$(error-if,$(success,test -z "$(as-info)"),Sorry$(comma) this assembler is not supported.)
+as-name := $(shell,set -- $(as-info) && echo $1)
+as-version := $(shell,set -- $(as-info) && echo $2)
+
# Get the linker name, version, and error out if it is not supported.
ld-info := $(shell,$(srctree)/scripts/ld-version.sh $(LD))
$(error-if,$(success,test -z "$(ld-info)"),Sorry$(comma) this linker is not supported.)
diff --git a/scripts/Makefile b/scripts/Makefile
index c36106bce80e..32b6ba722728 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -3,24 +3,27 @@
# scripts contains sources for various helper programs used throughout
# the kernel for the build process.
-CRYPTO_LIBS = $(shell pkg-config --libs libcrypto 2> /dev/null || echo -lcrypto)
-CRYPTO_CFLAGS = $(shell pkg-config --cflags libcrypto 2> /dev/null)
-
-hostprogs-always-$(CONFIG_BUILD_BIN2C) += bin2c
hostprogs-always-$(CONFIG_KALLSYMS) += kallsyms
hostprogs-always-$(BUILD_C_RECORDMCOUNT) += recordmcount
hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable
hostprogs-always-$(CONFIG_ASN1) += asn1_compiler
hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file
-hostprogs-always-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert
hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert
+always-$(CONFIG_RUST) += target.json
+
+filechk_rust_target = $< < include/config/auto.conf
+
+$(obj)/target.json: scripts/generate_rust_target include/config/auto.conf FORCE
+ $(call filechk,rust_target)
+
+hostprogs += generate_rust_target
+generate_rust_target-rust := y
HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
+HOSTLDLIBS_sorttable = -lpthread
HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
-HOSTCFLAGS_sign-file.o = $(CRYPTO_CFLAGS)
-HOSTLDLIBS_sign-file = $(CRYPTO_LIBS)
-HOSTCFLAGS_extract-cert.o = $(CRYPTO_CFLAGS)
-HOSTLDLIBS_extract-cert = $(CRYPTO_LIBS)
+HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null)
+HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto)
ifdef CONFIG_UNWINDER_ORC
ifeq ($(ARCH),x86_64)
@@ -28,7 +31,10 @@ ARCH := x86
endif
HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include
HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED
-HOSTLDLIBS_sorttable = -lpthread
+endif
+
+ifdef CONFIG_BUILDTIME_MCOUNT_SORT
+HOSTCFLAGS_sorttable.o += -DMCOUNT_SORT_ENABLED
endif
# The following programs are only built on demand
diff --git a/scripts/Makefile.asm-generic b/scripts/Makefile.asm-generic
index 82ad63dcd62b..8d01b37b7677 100644
--- a/scripts/Makefile.asm-generic
+++ b/scripts/Makefile.asm-generic
@@ -10,15 +10,15 @@ PHONY := all
all:
src := $(subst /generated,,$(obj))
--include $(src)/Kbuild
+
+include $(srctree)/scripts/Kbuild.include
+-include $(kbuild-file)
# $(generic)/Kbuild lists mandatory-y. Exclude um since it is a special case.
ifneq ($(SRCARCH),um)
-include $(generic)/Kbuild
+include $(srctree)/$(generic)/Kbuild
endif
-include scripts/Kbuild.include
-
redundant := $(filter $(mandatory-y) $(generated-y), $(generic-y))
redundant += $(foreach f, $(generic-y), $(if $(wildcard $(srctree)/$(src)/$(f)),$(f)))
redundant := $(sort $(redundant))
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 1b6094a13034..82e3fb19fdaf 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -5,8 +5,8 @@
src := $(obj)
-PHONY := __build
-__build:
+PHONY := $(obj)/
+$(obj)/:
# Init all relevant variables used in kbuild files so
# 1) they have correct type
@@ -26,6 +26,7 @@ EXTRA_CPPFLAGS :=
EXTRA_LDFLAGS :=
asflags-y :=
ccflags-y :=
+rustflags-y :=
cppflags-y :=
ldflags-y :=
@@ -35,27 +36,23 @@ subdir-ccflags-y :=
# Read auto.conf if it exists, otherwise ignore
-include include/config/auto.conf
-include scripts/Kbuild.include
-
-# The filename Kbuild has precedence over Makefile
-kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
-kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
+include $(srctree)/scripts/Kbuild.include
+include $(srctree)/scripts/Makefile.compiler
include $(kbuild-file)
-
-include scripts/Makefile.lib
+include $(srctree)/scripts/Makefile.lib
# Do not include hostprogs rules unless needed.
# $(sort ...) is used here to remove duplicated words and excessive spaces.
hostprogs := $(sort $(hostprogs))
ifneq ($(hostprogs),)
-include scripts/Makefile.host
+include $(srctree)/scripts/Makefile.host
endif
# Do not include userprogs rules unless needed.
# $(sort ...) is used here to remove duplicated words and excessive spaces.
userprogs := $(sort $(userprogs))
ifneq ($(userprogs),)
-include scripts/Makefile.userprogs
+include $(srctree)/scripts/Makefile.userprogs
endif
ifndef obj
@@ -85,7 +82,8 @@ ifdef need-builtin
targets-for-builtin += $(obj)/built-in.a
endif
-targets-for-modules := $(patsubst %.o, %.mod, $(filter %.o, $(obj-m)))
+targets-for-modules := $(foreach x, o mod, \
+ $(patsubst %.o, %.$x, $(filter %.o, $(obj-m))))
ifdef need-modorder
targets-for-modules += $(obj)/modules.order
@@ -103,7 +101,9 @@ else ifeq ($(KBUILD_CHECKSRC),2)
endif
ifneq ($(KBUILD_EXTRA_WARN),)
- cmd_checkdoc = $(srctree)/scripts/kernel-doc -none $<
+ cmd_checkdoc = $(srctree)/scripts/kernel-doc -none $(KDOCFLAGS) \
+ $(if $(findstring 2, $(KBUILD_EXTRA_WARN)), -Wall) \
+ $<
endif
# Compile C sources (.c)
@@ -121,18 +121,16 @@ cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $<
$(obj)/%.i: $(src)/%.c FORCE
$(call if_changed_dep,cpp_i_c)
+genksyms = scripts/genksyms/genksyms \
+ $(if $(1), -T $(2)) \
+ $(if $(KBUILD_PRESERVE), -p) \
+ -r $(or $(wildcard $(2:.symtypes=.symref)), /dev/null)
+
# These mirror gensymtypes_S and co below, keep them in synch.
-cmd_gensymtypes_c = \
- $(CPP) -D__GENKSYMS__ $(c_flags) $< | \
- scripts/genksyms/genksyms $(if $(1), -T $(2)) \
- $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \
- $(if $(KBUILD_PRESERVE),-p) \
- -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
+cmd_gensymtypes_c = $(CPP) -D__GENKSYMS__ $(c_flags) $< | $(genksyms)
quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
-cmd_cc_symtypes_c = \
- $(call cmd_gensymtypes_c,true,$@) >/dev/null; \
- test -s $@ || rm -f $@
+ cmd_cc_symtypes_c = $(call cmd_gensymtypes_c,true,$@) >/dev/null
$(obj)/%.symtypes : $(src)/%.c FORCE
$(call cmd,cc_symtypes_c)
@@ -140,7 +138,7 @@ $(obj)/%.symtypes : $(src)/%.c FORCE
# LLVM assembly
# Generate .ll files from .c
quiet_cmd_cc_ll_c = CC $(quiet_modtag) $@
- cmd_cc_ll_c = $(CC) $(c_flags) -emit-llvm -S -o $@ $<
+ cmd_cc_ll_c = $(CC) $(c_flags) -emit-llvm -S -fno-discard-value-names -o $@ $<
$(obj)/%.ll: $(src)/%.c FORCE
$(call if_changed_dep,cc_ll_c)
@@ -149,42 +147,37 @@ $(obj)/%.ll: $(src)/%.c FORCE
# The C file is compiled and updated dependency information is generated.
# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
+is-single-obj-m = $(and $(part-of-module),$(filter $@, $(obj-m)),y)
+
+# When a module consists of a single object, there is no reason to keep LLVM IR.
+# Make $(LD) covert LLVM IR to ELF here.
+ifdef CONFIG_LTO_CLANG
+cmd_ld_single_m = $(if $(is-single-obj-m), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@)
+endif
+
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
- cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+ cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \
+ $(cmd_ld_single_m) \
+ $(cmd_objtool)
ifdef CONFIG_MODVERSIONS
# When module versioning is enabled the following steps are executed:
# o compile a <file>.o from <file>.c
-# o if <file>.o doesn't contain a __ksymtab version, i.e. does
+# o if <file>.o doesn't contain a __export_symbol_*, i.e. does
# not export symbols, it's done.
# o otherwise, we calculate symbol versions using the good old
-# genksyms on the preprocessed source and postprocess them in a way
-# that they are usable as a linker script
-# o generate .tmp_<file>.o from <file>.o using the linker to
-# replace the unresolved symbols __crc_exported_symbol with
-# the actual value of the checksum generated by genksyms
-# o remove .tmp_<file>.o to <file>.o
-
-ifdef CONFIG_LTO_CLANG
-# Generate .o.symversions files for each .o with exported symbols, and link these
-# to the kernel and/or modules at the end.
-cmd_modversions_c = \
- if $(NM) $@ 2>/dev/null | grep -q __ksymtab; then \
- $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
- > $@.symversions; \
- fi;
-else
-cmd_modversions_c = \
- if $(OBJDUMP) -h $@ | grep -q __ksymtab; then \
- $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
- > $(@D)/.tmp_$(@F:.o=.ver); \
- \
- $(LD) $(KBUILD_LDFLAGS) -r -o $(@D)/.tmp_$(@F) $@ \
- -T $(@D)/.tmp_$(@F:.o=.ver); \
- mv -f $(@D)/.tmp_$(@F) $@; \
- rm -f $(@D)/.tmp_$(@F:.o=.ver); \
+# genksyms on the preprocessed source and dump them into the .cmd file.
+# o modpost will extract versions from that file and create *.c files that will
+# be compiled and linked to the kernel and/or modules.
+
+gen_symversions = \
+ if $(NM) $@ 2>/dev/null | grep -q ' __export_symbol_'; then \
+ $(call cmd_gensymtypes_$(1),$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
+ >> $(dot-target).cmd; \
fi
-endif
+
+cmd_gen_symversions_c = $(call gen_symversions,c)
+
endif
ifdef CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
@@ -216,67 +209,46 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)),
$(sub_cmd_record_mcount))
endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
-ifdef CONFIG_STACK_VALIDATION
-ifndef CONFIG_LTO_CLANG
-ifneq ($(SKIP_STACK_VALIDATION),1)
-
-__objtool_obj := $(objtree)/tools/objtool/objtool
-
# 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory
# 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file
# 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file
-cmd_objtool = $(if $(patsubst y%,, \
- $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \
- $(__objtool_obj) $(objtool_args) $@)
-objtool_obj = $(if $(patsubst y%,, \
- $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \
- $(__objtool_obj))
-
-endif # SKIP_STACK_VALIDATION
-endif # CONFIG_LTO_CLANG
-endif # CONFIG_STACK_VALIDATION
-
-# Rebuild all objects when objtool changes, or is enabled/disabled.
-objtool_dep = $(objtool_obj) \
- $(wildcard include/config/orc/unwinder.h \
- include/config/stack/validation.h)
-
-ifdef CONFIG_TRIM_UNUSED_KSYMS
-cmd_gen_ksymdeps = \
- $(CONFIG_SHELL) $(srctree)/scripts/gen_ksymdeps.sh $@ >> $(dot-target).cmd
-
-# List module undefined symbols
-undefined_syms = $(NM) $< | $(AWK) '$$1 == "U" { printf("%s%s", x++ ? " " : "", $$2) }';
+
+is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y)
+
+$(obj)/%.o: objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y))
+
+ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),)
+cmd_warn_shared_object = $(if $(word 2, $(modname-multi)),$(warning $(kbuild-file): $*.o is added to multiple modules: $(modname-multi)))
endif
define rule_cc_o_c
$(call cmd_and_fixdep,cc_o_c)
- $(call cmd,gen_ksymdeps)
$(call cmd,checksrc)
$(call cmd,checkdoc)
- $(call cmd,objtool)
- $(call cmd,modversions_c)
+ $(call cmd,gen_objtooldep)
+ $(call cmd,gen_symversions_c)
$(call cmd,record_mcount)
+ $(call cmd,warn_shared_object)
endef
define rule_as_o_S
$(call cmd_and_fixdep,as_o_S)
- $(call cmd,gen_ksymdeps)
- $(call cmd,objtool)
- $(call cmd,modversions_S)
+ $(call cmd,gen_objtooldep)
+ $(call cmd,gen_symversions_S)
+ $(call cmd,warn_shared_object)
endef
# Built-in and composite module parts
-$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
+$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call if_changed_rule,cc_o_c)
$(call cmd,force_checksrc)
-cmd_mod = { \
- echo $(if $($*-objs)$($*-y)$($*-m), $(addprefix $(obj)/, $($*-objs) $($*-y) $($*-m)), $(@:.mod=.o)); \
- $(undefined_syms) echo; \
- } > $@
+# To make this rule robust against "Argument list too long" error,
+# ensure to add $(obj)/ prefix by a shell command.
+cmd_mod = printf '%s\n' $(call real-search, $*.o, .o, -objs -y -m) | \
+ $(AWK) '!x[$$0]++ { print("$(obj)/"$$0) }' > $@
-$(obj)/%.mod: $(obj)/%.o FORCE
+$(obj)/%.mod: FORCE
$(call if_changed,mod)
quiet_cmd_cc_lst_c = MKLST $@
@@ -287,6 +259,58 @@ quiet_cmd_cc_lst_c = MKLST $@
$(obj)/%.lst: $(src)/%.c FORCE
$(call if_changed_dep,cc_lst_c)
+# Compile Rust sources (.rs)
+# ---------------------------------------------------------------------------
+
+rust_allowed_features := new_uninit
+
+# `--out-dir` is required to avoid temporaries being created by `rustc` in the
+# current working directory, which may be not accessible in the out-of-tree
+# modules case.
+rust_common_cmd = \
+ RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
+ -Zallow-features=$(rust_allowed_features) \
+ -Zcrate-attr=no_std \
+ -Zcrate-attr='feature($(rust_allowed_features))' \
+ --extern alloc --extern kernel \
+ --crate-type rlib -L $(objtree)/rust/ \
+ --crate-name $(basename $(notdir $@)) \
+ --out-dir $(dir $@) --emit=dep-info=$(depfile)
+
+# `--emit=obj`, `--emit=asm` and `--emit=llvm-ir` imply a single codegen unit
+# will be used. We explicitly request `-Ccodegen-units=1` in any case, and
+# the compiler shows a warning if it is not 1. However, if we ever stop
+# requesting it explicitly and we start using some other `--emit` that does not
+# imply it (and for which codegen is performed), then we would be out of sync,
+# i.e. the outputs we would get for the different single targets (e.g. `.ll`)
+# would not match each other.
+
+quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
+ cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $<
+
+$(obj)/%.o: $(src)/%.rs FORCE
+ $(call if_changed_dep,rustc_o_rs)
+
+quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
+ cmd_rustc_rsi_rs = \
+ $(rust_common_cmd) -Zunpretty=expanded $< >$@; \
+ command -v $(RUSTFMT) >/dev/null && $(RUSTFMT) $@
+
+$(obj)/%.rsi: $(src)/%.rs FORCE
+ $(call if_changed_dep,rustc_rsi_rs)
+
+quiet_cmd_rustc_s_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
+ cmd_rustc_s_rs = $(rust_common_cmd) --emit=asm=$@ $<
+
+$(obj)/%.s: $(src)/%.rs FORCE
+ $(call if_changed_dep,rustc_s_rs)
+
+quiet_cmd_rustc_ll_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
+ cmd_rustc_ll_rs = $(rust_common_cmd) --emit=llvm-ir=$@ $<
+
+$(obj)/%.ll: $(src)/%.rs FORCE
+ $(call if_changed_dep,rustc_ll_rs)
+
# Compile assembler sources (.S)
# ---------------------------------------------------------------------------
@@ -304,19 +328,11 @@ $(obj)/%.lst: $(src)/%.c FORCE
cmd_gensymtypes_S = \
{ echo "\#include <linux/kernel.h>" ; \
echo "\#include <asm/asm-prototypes.h>" ; \
- $(CPP) $(a_flags) $< | \
- grep "\<___EXPORT_SYMBOL\>" | \
- sed 's/.*___EXPORT_SYMBOL[[:space:]]*\([a-zA-Z0-9_]*\)[[:space:]]*,.*/EXPORT_SYMBOL(\1);/' ; } | \
- $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | \
- scripts/genksyms/genksyms $(if $(1), -T $(2)) \
- $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \
- $(if $(KBUILD_PRESERVE),-p) \
- -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
+ $(NM) $@ | sed -n 's/.* __export_symbol_\(.*\)/EXPORT_SYMBOL(\1);/p' ; } | \
+ $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms)
quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@
-cmd_cc_symtypes_S = \
- $(call cmd_gensymtypes_S,true,$@) >/dev/null; \
- test -s $@ || rm -f $@
+ cmd_cc_symtypes_S = $(call cmd_gensymtypes_S,true,$@) >/dev/null
$(obj)/%.symtypes : $(src)/%.S FORCE
$(call cmd,cc_symtypes_S)
@@ -329,31 +345,23 @@ $(obj)/%.s: $(src)/%.S FORCE
$(call if_changed_dep,cpp_s_S)
quiet_cmd_as_o_S = AS $(quiet_modtag) $@
- cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
+ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< $(cmd_objtool)
ifdef CONFIG_ASM_MODVERSIONS
# versioning matches the C process described above, with difference that
# we parse asm-prototypes.h C header to get function definitions.
-cmd_modversions_S = \
- if $(OBJDUMP) -h $@ | grep -q __ksymtab; then \
- $(call cmd_gensymtypes_S,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
- > $(@D)/.tmp_$(@F:.o=.ver); \
- \
- $(LD) $(KBUILD_LDFLAGS) -r -o $(@D)/.tmp_$(@F) $@ \
- -T $(@D)/.tmp_$(@F:.o=.ver); \
- mv -f $(@D)/.tmp_$(@F) $@; \
- rm -f $(@D)/.tmp_$(@F:.o=.ver); \
- fi
+cmd_gen_symversions_S = $(call gen_symversions,S)
+
endif
-$(obj)/%.o: $(src)/%.S $(objtool_dep) FORCE
+$(obj)/%.o: $(src)/%.S FORCE
$(call if_changed_rule,as_o_S)
targets += $(filter-out $(subdir-builtin), $(real-obj-y))
targets += $(filter-out $(subdir-modorder), $(real-obj-m))
-targets += $(lib-y) $(always-y) $(MAKECMDGOALS)
+targets += $(real-dtb-y) $(lib-y) $(always-y)
# Linker scripts preprocessor (.lds.S -> .lds)
# ---------------------------------------------------------------------------
@@ -380,30 +388,19 @@ $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
$(subdir-builtin): $(obj)/%/built-in.a: $(obj)/% ;
$(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ;
-# combine symversions for later processing
-quiet_cmd_update_lto_symversions = SYMVER $@
-ifeq ($(CONFIG_LTO_CLANG) $(CONFIG_MODVERSIONS),y y)
- cmd_update_lto_symversions = \
- rm -f $@.symversions \
- $(foreach n, $(filter-out FORCE,$^), \
- $(if $(wildcard $(n).symversions), \
- ; cat $(n).symversions >> $@.symversions))
-else
- cmd_update_lto_symversions = echo >/dev/null
-endif
-
#
# Rule to compile a set of .o files into one .a file (without symbol table)
#
+# To make this rule robust against "Argument list too long" error,
+# remove $(obj)/ prefix, and restore it by a shell command.
quiet_cmd_ar_builtin = AR $@
- cmd_ar_builtin = rm -f $@; $(AR) cDPrST $@ $(real-prereqs)
-
-quiet_cmd_ar_and_symver = AR $@
- cmd_ar_and_symver = $(cmd_update_lto_symversions); $(cmd_ar_builtin)
+ cmd_ar_builtin = rm -f $@; \
+ $(if $(real-prereqs), printf "$(obj)/%s " $(patsubst $(obj)/%,%,$(real-prereqs)) | xargs) \
+ $(AR) cDPrST $@
$(obj)/built-in.a: $(real-obj-y) FORCE
- $(call if_changed,ar_and_symver)
+ $(call if_changed,ar_builtin)
#
# Rule to create modules.order file
@@ -414,8 +411,8 @@ $(obj)/built-in.a: $(real-obj-y) FORCE
# modules.order unless contained modules are updated.
cmd_modules_order = { $(foreach m, $(real-prereqs), \
- $(if $(filter %/modules.order, $m), cat $m, echo $(patsubst %.o,%.ko,$m));) :; } \
- | $(AWK) '!x[$$0]++' - > $@
+ $(if $(filter %/modules.order, $m), cat $m, echo $m);) :; } \
+ > $@
$(obj)/modules.order: $(obj-m) FORCE
$(call if_changed,modules_order)
@@ -423,33 +420,23 @@ $(obj)/modules.order: $(obj-m) FORCE
#
# Rule to compile a set of .o files into one .a file (with symbol table)
#
-quiet_cmd_ar_lib = AR $@
- cmd_ar_lib = $(cmd_update_lto_symversions); $(cmd_ar)
$(obj)/lib.a: $(lib-y) FORCE
- $(call if_changed,ar_lib)
+ $(call if_changed,ar)
-# NOTE:
-# Do not replace $(filter %.o,^) with $(real-prereqs). When a single object
-# module is turned into a multi object module, $^ will contain header file
-# dependencies recorded in the .*.cmd file.
-ifdef CONFIG_LTO_CLANG
-quiet_cmd_link_multi-m = AR [M] $@
-cmd_link_multi-m = \
- $(cmd_update_lto_symversions); \
- rm -f $@; \
- $(AR) cDPrsT $@ $(filter %.o,$^)
-else
-quiet_cmd_link_multi-m = LD [M] $@
- cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(filter %.o,$^)
-endif
+quiet_cmd_ld_multi_m = LD [M] $@
+ cmd_ld_multi_m = $(LD) $(ld_flags) -r -o $@ @$(patsubst %.o,%.mod,$@) $(cmd_objtool)
-$(multi-used-m): FORCE
- $(call if_changed,link_multi-m)
-$(call multi_depend, $(multi-used-m), .o, -objs -y -m)
+define rule_ld_multi_m
+ $(call cmd_and_savecmd,ld_multi_m)
+ $(call cmd,gen_objtooldep)
+endef
-targets += $(multi-used-m)
-targets := $(filter-out $(PHONY), $(targets))
+$(multi-obj-m): objtool-enabled := $(delay-objtool)
+$(multi-obj-m): part-of-module := y
+$(multi-obj-m): %.o: %.mod FORCE
+ $(call if_changed_rule,ld_multi_m)
+$(call multi_depend, $(multi-obj-m), .o, -objs -y -m)
# Add intermediate targets:
# When building objects with specific suffix patterns, add intermediate
@@ -459,62 +446,41 @@ intermediate_targets = $(foreach sfx, $(2), \
$(filter %$(strip $(1)), $(targets))))
# %.asn1.o <- %.asn1.[ch] <- %.asn1
# %.dtb.o <- %.dtb.S <- %.dtb <- %.dts
+# %.dtbo.o <- %.dtbo.S <- %.dtbo <- %.dtso
# %.lex.o <- %.lex.c <- %.l
# %.tab.o <- %.tab.[ch] <- %.y
targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \
$(call intermediate_targets, .dtb.o, .dtb.S .dtb) \
+ $(call intermediate_targets, .dtbo.o, .dtbo.S .dtbo) \
$(call intermediate_targets, .lex.o, .lex.c) \
$(call intermediate_targets, .tab.o, .tab.c .tab.h)
# Build
# ---------------------------------------------------------------------------
-ifdef single-build
-
-KBUILD_SINGLE_TARGETS := $(filter $(obj)/%, $(KBUILD_SINGLE_TARGETS))
-
-curdir-single := $(sort $(foreach x, $(KBUILD_SINGLE_TARGETS), \
- $(if $(filter $(x) $(basename $(x)).o, $(targets)), $(x))))
-
-# Handle single targets without any rule: show "Nothing to be done for ..." or
-# "No rule to make target ..." depending on whether the target exists.
-unknown-single := $(filter-out $(addsuffix /%, $(subdir-ym)), \
- $(filter-out $(curdir-single), $(KBUILD_SINGLE_TARGETS)))
-
-single-subdirs := $(foreach d, $(subdir-ym), \
- $(if $(filter $(d)/%, $(KBUILD_SINGLE_TARGETS)), $(d)))
-
-__build: $(curdir-single) $(single-subdirs)
-ifneq ($(unknown-single),)
- $(Q)$(MAKE) -f /dev/null $(unknown-single)
-endif
+$(obj)/: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \
+ $(if $(KBUILD_MODULES), $(targets-for-modules)) \
+ $(subdir-ym) $(always-y)
@:
-ifeq ($(curdir-single),)
-# Nothing to do in this directory. Do not include any .*.cmd file for speed-up
-targets :=
-else
-targets += $(curdir-single)
-endif
+# Single targets
+# ---------------------------------------------------------------------------
-else
+single-subdirs := $(foreach d, $(subdir-ym), $(if $(filter $d/%, $(MAKECMDGOALS)), $d))
+single-subdir-goals := $(filter $(addsuffix /%, $(single-subdirs)), $(MAKECMDGOALS))
-__build: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \
- $(if $(KBUILD_MODULES), $(targets-for-modules)) \
- $(subdir-ym) $(always-y)
+$(single-subdir-goals): $(single-subdirs)
@:
-endif
-
# Descending
# ---------------------------------------------------------------------------
PHONY += $(subdir-ym)
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@ \
- $(if $(filter $@/, $(KBUILD_SINGLE_TARGETS)),single-build=) \
need-builtin=$(if $(filter $@/built-in.a, $(subdir-builtin)),1) \
- need-modorder=$(if $(filter $@/modules.order, $(subdir-modorder)),1)
+ need-modorder=$(if $(filter $@/modules.order, $(subdir-modorder)),1) \
+ $(filter $@/%, $(single-subdir-goals))
# Add FORCE to the prequisites of a target to force it to be always rebuilt.
# ---------------------------------------------------------------------------
@@ -523,6 +489,9 @@ PHONY += FORCE
FORCE:
+targets += $(filter-out $(single-subdir-goals), $(MAKECMDGOALS))
+targets := $(filter-out $(PHONY), $(targets))
+
# Read all saved command lines and dependencies for the $(targets) we
# may be building above, using $(if_changed{,_dep}). As an
# optimization, we don't need to read them if the target does not
diff --git a/scripts/Makefile.clang b/scripts/Makefile.clang
new file mode 100644
index 000000000000..6c23c6af797f
--- /dev/null
+++ b/scripts/Makefile.clang
@@ -0,0 +1,39 @@
+# Individual arch/{arch}/Makefiles should use -EL/-EB to set intended
+# endianness and -m32/-m64 to set word size based on Kconfigs instead of
+# relying on the target triple.
+CLANG_TARGET_FLAGS_arm := arm-linux-gnueabi
+CLANG_TARGET_FLAGS_arm64 := aarch64-linux-gnu
+CLANG_TARGET_FLAGS_hexagon := hexagon-linux-musl
+CLANG_TARGET_FLAGS_loongarch := loongarch64-linux-gnusf
+CLANG_TARGET_FLAGS_m68k := m68k-linux-gnu
+CLANG_TARGET_FLAGS_mips := mipsel-linux-gnu
+CLANG_TARGET_FLAGS_powerpc := powerpc64le-linux-gnu
+CLANG_TARGET_FLAGS_riscv := riscv64-linux-gnu
+CLANG_TARGET_FLAGS_s390 := s390x-linux-gnu
+CLANG_TARGET_FLAGS_x86 := x86_64-linux-gnu
+CLANG_TARGET_FLAGS_um := $(CLANG_TARGET_FLAGS_$(SUBARCH))
+CLANG_TARGET_FLAGS := $(CLANG_TARGET_FLAGS_$(SRCARCH))
+
+ifeq ($(CLANG_TARGET_FLAGS),)
+$(error add '--target=' option to scripts/Makefile.clang)
+else
+CLANG_FLAGS += --target=$(CLANG_TARGET_FLAGS)
+endif
+
+ifeq ($(LLVM_IAS),0)
+CLANG_FLAGS += -fno-integrated-as
+GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)elfedit))
+CLANG_FLAGS += --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE))
+else
+CLANG_FLAGS += -fintegrated-as
+endif
+# By default, clang only warns when it encounters an unknown warning flag or
+# certain optimization flags it knows it has not implemented.
+# Make it behave more like gcc by erroring when these flags are encountered
+# so they can be implemented or wrapped in cc-option.
+CLANG_FLAGS += -Werror=unknown-warning-option
+CLANG_FLAGS += -Werror=ignored-optimization-argument
+CLANG_FLAGS += -Werror=option-ignored
+CLANG_FLAGS += -Werror=unused-command-line-argument
+KBUILD_CPPFLAGS += $(CLANG_FLAGS)
+export CLANG_FLAGS
diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
index 22a8172bce1f..f2cb4d7ffd96 100644
--- a/scripts/Makefile.clean
+++ b/scripts/Makefile.clean
@@ -8,11 +8,8 @@ src := $(obj)
PHONY := __clean
__clean:
-include scripts/Kbuild.include
-
-# The filename Kbuild has precedence over Makefile
-kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
-include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
+include $(srctree)/scripts/Kbuild.include
+include $(kbuild-file)
# Figure out what we need to build from the various variables
# ==========================================================================
@@ -36,18 +33,14 @@ __clean-files := \
__clean-files := $(filter-out $(no-clean-files), $(__clean-files))
-# clean-files is given relative to the current directory, unless it
-# starts with $(objtree)/ (which means "./", so do not add "./" unless
-# you want to delete a file from the toplevel object directory).
-
-__clean-files := $(wildcard \
- $(addprefix $(obj)/, $(filter-out $(objtree)/%, $(__clean-files))) \
- $(filter $(objtree)/%, $(__clean-files)))
+__clean-files := $(wildcard $(addprefix $(obj)/, $(__clean-files)))
# ==========================================================================
+# To make this rule robust against "Argument list too long" error,
+# remove $(obj)/ prefix, and restore it by a shell command.
quiet_cmd_clean = CLEAN $(obj)
- cmd_clean = rm -rf $(__clean-files)
+ cmd_clean = printf '$(obj)/%s ' $(patsubst $(obj)/%,%,$(__clean-files)) | xargs rm -rf
__clean: $(subdir-ymn)
ifneq ($(strip $(__clean-files)),)
diff --git a/scripts/Makefile.compiler b/scripts/Makefile.compiler
new file mode 100644
index 000000000000..8fcb427405a6
--- /dev/null
+++ b/scripts/Makefile.compiler
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# cc-cross-prefix
+# Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-)
+# Return first <prefix> where a <prefix>gcc is found in PATH.
+# If no gcc found in PATH with listed prefixes return nothing
+#
+# Note: '2>/dev/null' is here to force Make to invoke a shell. Otherwise, it
+# would try to directly execute the shell builtin 'command'. This workaround
+# should be kept for a long time since this issue was fixed only after the
+# GNU Make 4.2.1 release.
+cc-cross-prefix = $(firstword $(foreach c, $(1), \
+ $(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c))))
+
+# output directory for tests below
+TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$
+
+# try-run
+# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
+# Exit code chooses option. "$$TMP" serves as a temporary file and is
+# automatically cleaned up.
+try-run = $(shell set -e; \
+ TMP=$(TMPOUT)/tmp; \
+ trap "rm -rf $(TMPOUT)" EXIT; \
+ mkdir -p $(TMPOUT); \
+ if ($(1)) >/dev/null 2>&1; \
+ then echo "$(2)"; \
+ else echo "$(3)"; \
+ fi)
+
+# as-option
+# Usage: aflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
+
+as-option = $(call try-run,\
+ $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(1) -c -x assembler-with-cpp /dev/null -o "$$TMP",$(1),$(2))
+
+# as-instr
+# Usage: aflags-y += $(call as-instr,instr,option1,option2)
+
+as-instr = $(call try-run,\
+ printf "%b\n" "$(1)" | $(CC) -Werror $(CLANG_FLAGS) $(KBUILD_AFLAGS) -c -x assembler-with-cpp -o "$$TMP" -,$(2),$(3))
+
+# __cc-option
+# Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586)
+__cc-option = $(call try-run,\
+ $(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4))
+
+# cc-option
+# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
+
+cc-option = $(call __cc-option, $(CC),\
+ $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS),$(1),$(2))
+
+# cc-option-yn
+# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
+cc-option-yn = $(call try-run,\
+ $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
+
+# cc-disable-warning
+# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
+cc-disable-warning = $(call try-run,\
+ $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+
+# gcc-min-version
+# Usage: cflags-$(call gcc-min-version, 70100) += -foo
+gcc-min-version = $(call test-ge, $(CONFIG_GCC_VERSION), $1)
+
+# clang-min-version
+# Usage: cflags-$(call clang-min-version, 110000) += -foo
+clang-min-version = $(call test-ge, $(CONFIG_CLANG_VERSION), $1)
+
+# ld-option
+# Usage: KBUILD_LDFLAGS += $(call ld-option, -X, -Y)
+ld-option = $(call try-run, $(LD) $(KBUILD_LDFLAGS) $(1) -v,$(1),$(2),$(3))
diff --git a/scripts/Makefile.debug b/scripts/Makefile.debug
new file mode 100644
index 000000000000..059ff38fe0cb
--- /dev/null
+++ b/scripts/Makefile.debug
@@ -0,0 +1,44 @@
+DEBUG_CFLAGS :=
+DEBUG_RUSTFLAGS :=
+
+debug-flags-y := -g
+
+ifdef CONFIG_DEBUG_INFO_SPLIT
+DEBUG_CFLAGS += -gsplit-dwarf
+endif
+
+debug-flags-$(CONFIG_DEBUG_INFO_DWARF4) += -gdwarf-4
+debug-flags-$(CONFIG_DEBUG_INFO_DWARF5) += -gdwarf-5
+ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_AS_IS_GNU),yy)
+# Clang does not pass -g or -gdwarf-* option down to GAS.
+# Add -Wa, prefix to explicitly specify the flags.
+KBUILD_AFLAGS += $(addprefix -Wa$(comma), $(debug-flags-y))
+endif
+DEBUG_CFLAGS += $(debug-flags-y)
+KBUILD_AFLAGS += $(debug-flags-y)
+
+ifdef CONFIG_DEBUG_INFO_REDUCED
+DEBUG_CFLAGS += -fno-var-tracking
+DEBUG_RUSTFLAGS += -Cdebuginfo=1
+ifdef CONFIG_CC_IS_GCC
+DEBUG_CFLAGS += -femit-struct-debug-baseonly
+endif
+else
+DEBUG_RUSTFLAGS += -Cdebuginfo=2
+endif
+
+ifdef CONFIG_DEBUG_INFO_COMPRESSED_ZLIB
+DEBUG_CFLAGS += -gz=zlib
+KBUILD_AFLAGS += -gz=zlib
+KBUILD_LDFLAGS += --compress-debug-sections=zlib
+else ifdef CONFIG_DEBUG_INFO_COMPRESSED_ZSTD
+DEBUG_CFLAGS += -gz=zstd
+KBUILD_AFLAGS += -gz=zstd
+KBUILD_LDFLAGS += --compress-debug-sections=zstd
+endif
+
+KBUILD_CFLAGS += $(DEBUG_CFLAGS)
+export DEBUG_CFLAGS
+
+KBUILD_RUSTFLAGS += $(DEBUG_RUSTFLAGS)
+export DEBUG_RUSTFLAGS
diff --git a/scripts/Makefile.defconf b/scripts/Makefile.defconf
new file mode 100644
index 000000000000..ab271b2051a2
--- /dev/null
+++ b/scripts/Makefile.defconf
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0
+# Configuration heplers
+
+# Creates 'merged defconfigs'
+# ---------------------------------------------------------------------------
+# Usage:
+# $(call merge_into_defconfig,base_config,config_fragment1 config_fragment2 ...)
+#
+# Input config fragments without '.config' suffix
+define merge_into_defconfig
+ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \
+ -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/$(1) \
+ $(foreach config,$(2),$(srctree)/arch/$(ARCH)/configs/$(config).config)
+ +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig
+endef
+
+
+# Creates 'merged defconfigs without warning about overrides'
+# ---------------------------------------------------------------------------
+# Usage:
+# $(call merge_into_defconfig_override,base_config,config_fragment1 config_fragment2 ...)
+#
+# Input config fragments without '.config' suffix
+define merge_into_defconfig_override
+ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \
+ -Q -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/$(1) \
+ $(foreach config,$(2),$(srctree)/arch/$(ARCH)/configs/$(config).config)
+ +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig
+endef
diff --git a/scripts/Makefile.dtbinst b/scripts/Makefile.dtbinst
index ba01f5ba2517..4405d5b67578 100644
--- a/scripts/Makefile.dtbinst
+++ b/scripts/Makefile.dtbinst
@@ -14,8 +14,8 @@ PHONY := __dtbs_install
__dtbs_install:
include include/config/auto.conf
-include scripts/Kbuild.include
-include $(src)/Makefile
+include $(srctree)/scripts/Kbuild.include
+include $(kbuild-file)
dtbs := $(addprefix $(dst)/, $(dtb-y) $(if $(CONFIG_OF_ALL_DTBS),$(dtb-)))
subdirs := $(addprefix $(obj)/, $(subdir-y) $(subdir-m))
@@ -34,6 +34,6 @@ $(dst)/%.dtbo: $(obj)/%.dtbo
PHONY += $(subdirs)
$(subdirs):
- $(Q)$(MAKE) $(dtbinst)=$@ dst=$(patsubst $(obj)/%,$(dst)/%,$@)
+ $(Q)$(MAKE) $(dtbinst)=$@ dst=$(if $(CONFIG_ARCH_WANT_FLAT_DTB_INSTALL),$(dst),$(patsubst $(obj)/%,$(dst)/%,$@))
.PHONY: $(PHONY)
diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn
index d53825503874..40cd13eca82e 100644
--- a/scripts/Makefile.extrawarn
+++ b/scripts/Makefile.extrawarn
@@ -2,8 +2,8 @@
# ==========================================================================
# make W=... settings
#
-# There are three warning groups enabled by W=1, W=2, W=3.
-# They are independent, and can be combined like W=12 or W=123.
+# There are four warning groups enabled by W=1, W=2, W=3, and W=e
+# They are independent, and can be combined like W=12 or W=123e.
# ==========================================================================
KBUILD_CFLAGS += $(call cc-disable-warning, packed-not-aligned)
@@ -36,7 +36,9 @@ KBUILD_CFLAGS += $(call cc-option, -Wstringop-truncation)
KBUILD_CFLAGS += -Wno-missing-field-initializers
KBUILD_CFLAGS += -Wno-sign-compare
KBUILD_CFLAGS += -Wno-type-limits
+KBUILD_CFLAGS += -Wno-shift-negative-value
+KBUILD_CPPFLAGS += -Wundef
KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN1
else
@@ -46,11 +48,24 @@ else
ifdef CONFIG_CC_IS_CLANG
KBUILD_CFLAGS += -Wno-initializer-overrides
+# Clang before clang-16 would warn on default argument promotions.
+ifneq ($(call clang-min-version, 160000),y)
+# Disable -Wformat
KBUILD_CFLAGS += -Wno-format
+# Then re-enable flags that were part of the -Wformat group that aren't
+# problematic.
+KBUILD_CFLAGS += -Wformat-extra-args -Wformat-invalid-specifier
+KBUILD_CFLAGS += -Wformat-zero-length -Wnonnull
+# Requires clang-12+.
+ifeq ($(call clang-min-version, 120000),y)
+KBUILD_CFLAGS += -Wformat-insufficient-args
+endif
+endif
KBUILD_CFLAGS += -Wno-sign-compare
-KBUILD_CFLAGS += -Wno-format-zero-length
KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast)
KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare
+KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access)
+KBUILD_CFLAGS += $(call cc-disable-warning, cast-function-type-strict)
endif
endif
@@ -92,3 +107,12 @@ KBUILD_CFLAGS += $(call cc-option, -Wpacked-bitfield-compat)
KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN3
endif
+
+#
+# W=e - error out on warnings
+#
+ifneq ($(findstring e, $(KBUILD_EXTRA_WARN)),)
+
+KBUILD_CFLAGS += -Werror
+
+endif
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 952e46876329..e4deaf5fa571 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -1,17 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
-gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so
-
gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) \
+= -DLATENT_ENTROPY_PLUGIN
ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY
- DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable
+ DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable -ULATENT_ENTROPY_PLUGIN
endif
export DISABLE_LATENT_ENTROPY_PLUGIN
-gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so
-
gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) \
+= -fplugin-arg-structleak_plugin-verbose
@@ -19,15 +15,13 @@ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF) \
+= -fplugin-arg-structleak_plugin-byref
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) \
+= -fplugin-arg-structleak_plugin-byref-all
+ifdef CONFIG_GCC_PLUGIN_STRUCTLEAK
+ DISABLE_STRUCTLEAK_PLUGIN += -fplugin-arg-structleak_plugin-disable
+endif
+export DISABLE_STRUCTLEAK_PLUGIN
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \
+= -DSTRUCTLEAK_PLUGIN
-gcc-plugin-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) += randomize_layout_plugin.so
-gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) \
- += -DRANDSTRUCT_PLUGIN
-gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) \
- += -fplugin-arg-randomize_layout_plugin-performance-mode
-
gcc-plugin-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak_plugin.so
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
+= -DSTACKLEAK_PLUGIN
@@ -35,6 +29,8 @@ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
+= -fplugin-arg-stackleak_plugin-track-min-size=$(CONFIG_STACKLEAK_TRACK_MIN_SIZE)
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
+= -fplugin-arg-stackleak_plugin-arch=$(SRCARCH)
+gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK_VERBOSE) \
+ += -fplugin-arg-stackleak_plugin-verbose
ifdef CONFIG_GCC_PLUGIN_STACKLEAK
DISABLE_STACKLEAK_PLUGIN += -fplugin-arg-stackleak_plugin-disable
endif
@@ -49,13 +45,19 @@ export DISABLE_ARM_SSP_PER_TASK_PLUGIN
# 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))
-# The sancov_plugin.so is included via CFLAGS_KCOV, so it is removed here.
-GCC_PLUGINS_CFLAGS := $(filter-out %/sancov_plugin.so, $(GCC_PLUGINS_CFLAGS))
export GCC_PLUGINS_CFLAGS
# Add the flags to the build!
KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
-# All enabled GCC plugins are collected here for building below.
-GCC_PLUGIN := $(gcc-plugin-y)
+# Some plugins are enabled outside of this Makefile, but they still need to
+# be included in GCC_PLUGIN so they can get built.
+gcc-plugin-external-$(CONFIG_GCC_PLUGIN_SANCOV) \
+ += sancov_plugin.so
+gcc-plugin-external-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) \
+ += randomize_layout_plugin.so
+
+# All enabled GCC plugins are collected here for building in
+# scripts/gcc-scripts/Makefile.
+GCC_PLUGIN := $(gcc-plugin-y) $(gcc-plugin-external-y)
export GCC_PLUGIN
diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst
index 708fbd08a2c5..029d85bb0b23 100644
--- a/scripts/Makefile.headersinst
+++ b/scripts/Makefile.headersinst
@@ -12,7 +12,7 @@
PHONY := __headers
__headers:
-include scripts/Kbuild.include
+include $(srctree)/scripts/Kbuild.include
src := $(srctree)/$(obj)
gen := $(objtree)/$(subst include/,include/generated/,$(obj))
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 278b4d6ac945..8f7f842b54f9 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -22,6 +22,8 @@ $(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE
# to preprocess a data file.
#
# Both C and C++ are supported, but preferred language is C for such utilities.
+# Rust is also supported, but it may only be used in scenarios where a Rust
+# toolchain is required to be available (e.g. when `CONFIG_RUST` is enabled).
#
# Sample syntax (see Documentation/kbuild/makefiles.rst for reference)
# hostprogs := bin2hex
@@ -37,15 +39,20 @@ $(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE
# qconf-objs := menu.o
# Will compile qconf as a C++ program, and menu as a C program.
# They are linked as C++ code to the executable qconf
+#
+# hostprogs := target
+# target-rust := y
+# Will compile `target` as a Rust program, using `target.rs` as the crate root.
+# The crate may consist of several source files.
# C code
# Executables compiled from a single .c file
host-csingle := $(foreach m,$(hostprogs), \
- $(if $($(m)-objs)$($(m)-cxxobjs),,$(m)))
+ $(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-rust),,$(m)))
# C executables linked based on several .o files
host-cmulti := $(foreach m,$(hostprogs),\
- $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
+ $(if $($(m)-cxxobjs)$($(m)-rust),,$(if $($(m)-objs),$(m))))
# Object (.o) files compiled from .c files
host-cobjs := $(sort $(foreach m,$(hostprogs),$($(m)-objs)))
@@ -58,31 +65,43 @@ host-cxxmulti := $(foreach m,$(hostprogs),$(if $($(m)-cxxobjs),$(m)))
# C++ Object (.o) files compiled from .cc files
host-cxxobjs := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
+# Rust code
+# Executables compiled from a single Rust crate (which may consist of
+# one or more .rs files)
+host-rust := $(foreach m,$(hostprogs),$(if $($(m)-rust),$(m)))
+
host-csingle := $(addprefix $(obj)/,$(host-csingle))
host-cmulti := $(addprefix $(obj)/,$(host-cmulti))
host-cobjs := $(addprefix $(obj)/,$(host-cobjs))
host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti))
host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs))
+host-rust := $(addprefix $(obj)/,$(host-rust))
#####
# Handle options to gcc. Support building with separate output directory
-_hostc_flags = $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) \
+hostc_flags = -Wp,-MMD,$(depfile) \
+ $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) \
$(HOSTCFLAGS_$(target-stem).o)
-_hostcxx_flags = $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
+hostcxx_flags = -Wp,-MMD,$(depfile) \
+ $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
$(HOSTCXXFLAGS_$(target-stem).o)
+# `--out-dir` is required to avoid temporaries being created by `rustc` in the
+# current working directory, which may be not accessible in the out-of-tree
+# modules case.
+hostrust_flags = --out-dir $(dir $@) --emit=dep-info=$(depfile) \
+ $(KBUILD_HOSTRUSTFLAGS) $(HOST_EXTRARUSTFLAGS) \
+ $(HOSTRUSTFLAGS_$(target-stem))
+
# $(objtree)/$(obj) for including generated headers from checkin source files
ifeq ($(KBUILD_EXTMOD),)
ifdef building_out_of_srctree
-_hostc_flags += -I $(objtree)/$(obj)
-_hostcxx_flags += -I $(objtree)/$(obj)
+hostc_flags += -I $(objtree)/$(obj)
+hostcxx_flags += -I $(objtree)/$(obj)
endif
endif
-hostc_flags = -Wp,-MMD,$(depfile) $(_hostc_flags)
-hostcxx_flags = -Wp,-MMD,$(depfile) $(_hostcxx_flags)
-
#####
# Compile programs on the host
@@ -128,5 +147,14 @@ quiet_cmd_host-cxxobjs = HOSTCXX $@
$(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
$(call if_changed_dep,host-cxxobjs)
+# Create executable from a single Rust crate (which may consist of
+# one or more `.rs` files)
+# host-rust -> Executable
+quiet_cmd_host-rust = HOSTRUSTC $@
+ cmd_host-rust = \
+ $(HOSTRUSTC) $(hostrust_flags) --emit=link=$@ $<
+$(host-rust): $(obj)/%: $(src)/%.rs FORCE
+ $(call if_changed_dep,host-rust)
+
targets += $(host-csingle) $(host-cmulti) $(host-cobjs) \
- $(host-cxxmulti) $(host-cxxobjs)
+ $(host-cxxmulti) $(host-cxxobjs) $(host-rust)
diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan
index 1e000cc2e7b4..390658a2d5b7 100644
--- a/scripts/Makefile.kasan
+++ b/scripts/Makefile.kasan
@@ -1,7 +1,24 @@
# SPDX-License-Identifier: GPL-2.0
+
+ifdef CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX
+# Safe for compiler to generate meminstrinsic calls in uninstrumented files.
+CFLAGS_KASAN_NOSANITIZE :=
+else
+# Don't let compiler generate memintrinsic calls in uninstrumented files
+# because they are instrumented.
CFLAGS_KASAN_NOSANITIZE := -fno-builtin
+endif
+
KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET)
+cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1)))
+
+ifdef CONFIG_KASAN_STACK
+ stack_enable := 1
+else
+ stack_enable := 0
+endif
+
ifdef CONFIG_KASAN_GENERIC
ifdef CONFIG_KASAN_INLINE
@@ -12,8 +29,6 @@ endif
CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address
-cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1)))
-
# -fasan-shadow-offset fails without -fsanitize
CFLAGS_KASAN_SHADOW := $(call cc-option, -fsanitize=kernel-address \
-fasan-shadow-offset=$(KASAN_SHADOW_OFFSET), \
@@ -27,25 +42,37 @@ else
CFLAGS_KASAN := $(CFLAGS_KASAN_SHADOW) \
$(call cc-param,asan-globals=1) \
$(call cc-param,asan-instrumentation-with-call-threshold=$(call_threshold)) \
- $(call cc-param,asan-stack=$(CONFIG_KASAN_STACK)) \
$(call cc-param,asan-instrument-allocas=1)
endif
+CFLAGS_KASAN += $(call cc-param,asan-stack=$(stack_enable))
+
+# Instrument memcpy/memset/memmove calls by using instrumented __asan_mem*()
+# instead. With compilers that don't support this option, compiler-inserted
+# memintrinsics won't be checked by KASAN on GENERIC_ENTRY architectures.
+CFLAGS_KASAN += $(call cc-param,asan-kernel-mem-intrinsic-prefix=1)
+
endif # CONFIG_KASAN_GENERIC
ifdef CONFIG_KASAN_SW_TAGS
ifdef CONFIG_KASAN_INLINE
- instrumentation_flags := -mllvm -hwasan-mapping-offset=$(KASAN_SHADOW_OFFSET)
+ instrumentation_flags := $(call cc-param,hwasan-mapping-offset=$(KASAN_SHADOW_OFFSET))
else
- instrumentation_flags := -mllvm -hwasan-instrument-with-calls=1
+ instrumentation_flags := $(call cc-param,hwasan-instrument-with-calls=1)
endif
CFLAGS_KASAN := -fsanitize=kernel-hwaddress \
- -mllvm -hwasan-instrument-stack=$(CONFIG_KASAN_STACK) \
- -mllvm -hwasan-use-short-granules=0 \
+ $(call cc-param,hwasan-instrument-stack=$(stack_enable)) \
+ $(call cc-param,hwasan-use-short-granules=0) \
+ $(call cc-param,hwasan-inline-all-checks=0) \
$(instrumentation_flags)
+# Instrument memcpy/memset/memmove calls by using instrumented __hwasan_mem*().
+ifeq ($(call clang-min-version, 150000)$(call gcc-min-version, 130000),y)
+CFLAGS_KASAN += $(call cc-param,hwasan-kernel-mem-intrinsic-prefix=1)
+endif
+
endif # CONFIG_KASAN_SW_TAGS
export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE
diff --git a/scripts/Makefile.kcsan b/scripts/Makefile.kcsan
index 37cb504c77e1..19f693b68a96 100644
--- a/scripts/Makefile.kcsan
+++ b/scripts/Makefile.kcsan
@@ -9,7 +9,18 @@ endif
# Keep most options here optional, to allow enabling more compilers if absence
# of some options does not break KCSAN nor causes false positive reports.
-export CFLAGS_KCSAN := -fsanitize=thread \
- $(call cc-option,$(call cc-param,tsan-instrument-func-entry-exit=0) -fno-optimize-sibling-calls) \
+kcsan-cflags := -fsanitize=thread -fno-optimize-sibling-calls \
$(call cc-option,$(call cc-param,tsan-compound-read-before-write=1),$(call cc-option,$(call cc-param,tsan-instrument-read-before-write=1))) \
$(call cc-param,tsan-distinguish-volatile=1)
+
+ifdef CONFIG_CC_IS_GCC
+# GCC started warning about operations unsupported by the TSan runtime. But
+# KCSAN != TSan, so just ignore these warnings.
+kcsan-cflags += -Wno-tsan
+endif
+
+ifndef CONFIG_KCSAN_WEAK_MEMORY
+kcsan-cflags += $(call cc-option,$(call cc-param,tsan-instrument-func-entry-exit=0))
+endif
+
+export CFLAGS_KCSAN := $(kcsan-cflags)
diff --git a/scripts/Makefile.kmsan b/scripts/Makefile.kmsan
new file mode 100644
index 000000000000..b5b0aa61322e
--- /dev/null
+++ b/scripts/Makefile.kmsan
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+kmsan-cflags := -fsanitize=kernel-memory
+
+ifdef CONFIG_KMSAN_CHECK_PARAM_RETVAL
+kmsan-cflags += -fsanitize-memory-param-retval
+endif
+
+export CFLAGS_KMSAN := $(kmsan-cflags)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index eee59184de64..68d0134bdbf9 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -8,6 +8,7 @@ ldflags-y += $(EXTRA_LDFLAGS)
# flags that take effect in current and sub directories
KBUILD_AFLAGS += $(subdir-asflags-y)
KBUILD_CFLAGS += $(subdir-ccflags-y)
+KBUILD_RUSTFLAGS += $(subdir-rustflags-y)
# Figure out what we need to build from the various variables
# ===========================================================================
@@ -44,19 +45,22 @@ else
obj-y := $(filter-out %/, $(obj-y))
endif
-# Expand $(foo-objs) $(foo-y) by calling $(call suffix-search,foo.o,-objs -y)
-suffix-search = $(foreach s,$(2),$($(1:.o=$s)))
+# Expand $(foo-objs) $(foo-y) etc. by replacing their individuals
+suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s))))
+# List composite targets that are constructed by combining other targets
+multi-search = $(sort $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $m)))
+# List primitive targets that are compiled from source files
+real-search = $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $(call suffix-search, $m, $2, $3), $m))
+
# If $(foo-objs), $(foo-y), $(foo-m), or $(foo-) exists, foo.o is a composite object
-multi-search = $(sort $(foreach m,$(1), $(if $(strip $(call suffix-search,$(m),$(2) -)), $(m))))
-multi-used-y := $(call multi-search,$(obj-y),-objs -y)
-multi-used-m := $(call multi-search,$(obj-m),-objs -y -m)
-multi-used := $(multi-used-y) $(multi-used-m)
+multi-obj-y := $(call multi-search, $(obj-y), .o, -objs -y)
+multi-obj-m := $(call multi-search, $(obj-m), .o, -objs -y -m)
+multi-obj-ym := $(multi-obj-y) $(multi-obj-m)
# Replace multi-part objects by their individual parts,
# including built-in.a from subdirectories
-real-search = $(foreach m,$(1), $(if $(strip $(call suffix-search,$(m),$(2) -)),$(call suffix-search,$(m),$(2)),$(m)))
-real-obj-y := $(call real-search, $(obj-y),-objs -y)
-real-obj-m := $(call real-search, $(obj-m),-objs -y -m)
+real-obj-y := $(call real-search, $(obj-y), .o, -objs -y)
+real-obj-m := $(call real-search, $(obj-m), .o, -objs -y -m)
always-y += $(always-m)
@@ -73,18 +77,20 @@ always-y += $(userprogs-always-y) $(userprogs-always-m)
# DTB
# If CONFIG_OF_ALL_DTBS is enabled, all DT blobs are built
-always-y += $(dtb-y)
-always-$(CONFIG_OF_ALL_DTBS) += $(dtb-)
+dtb-$(CONFIG_OF_ALL_DTBS) += $(dtb-)
-ifneq ($(CHECK_DTBS),)
-always-y += $(patsubst %.dtb,%.dt.yaml, $(dtb-y))
-always-y += $(patsubst %.dtbo,%.dt.yaml, $(dtb-y))
-always-$(CONFIG_OF_ALL_DTBS) += $(patsubst %.dtb,%.dt.yaml, $(dtb-))
-always-$(CONFIG_OF_ALL_DTBS) += $(patsubst %.dtbo,%.dt.yaml, $(dtb-))
-endif
+# Composite DTB (i.e. DTB constructed by overlay)
+multi-dtb-y := $(call multi-search, $(dtb-y), .dtb, -dtbs)
+# Primitive DTB compiled from *.dts
+real-dtb-y := $(call real-search, $(dtb-y), .dtb, -dtbs)
+# Base DTB that overlay is applied onto (each first word of $(*-dtbs) expansion)
+base-dtb-y := $(foreach m, $(multi-dtb-y), $(firstword $(call suffix-search, $m, .dtb, -dtbs)))
+
+always-y += $(dtb-y)
# Add subdir path
+ifneq ($(obj),.)
extra-y := $(addprefix $(obj)/,$(extra-y))
always-y := $(addprefix $(obj)/,$(always-y))
targets := $(addprefix $(obj)/,$(targets))
@@ -92,15 +98,18 @@ obj-m := $(addprefix $(obj)/,$(obj-m))
lib-y := $(addprefix $(obj)/,$(lib-y))
real-obj-y := $(addprefix $(obj)/,$(real-obj-y))
real-obj-m := $(addprefix $(obj)/,$(real-obj-m))
-multi-used-m := $(addprefix $(obj)/,$(multi-used-m))
+multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m))
+multi-dtb-y := $(addprefix $(obj)/, $(multi-dtb-y))
+real-dtb-y := $(addprefix $(obj)/, $(real-dtb-y))
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
+endif
# Finds the multi-part object the current object will be linked into.
# If the object belongs to two or more multi-part objects, list them all.
-modname-multi = $(sort $(foreach m,$(multi-used),\
- $(if $(filter $*.o, $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))),$(m:.o=))))
+modname-multi = $(sort $(foreach m,$(multi-obj-ym),\
+ $(if $(filter $*.o, $(call suffix-search, $m, .o, -objs -y -m)),$(m:.o=))))
-__modname = $(if $(modname-multi),$(modname-multi),$(basetarget))
+__modname = $(or $(modname-multi),$(basetarget))
modname = $(subst $(space),:,$(__modname))
modfile = $(addprefix $(obj)/,$(__modname))
@@ -122,6 +131,10 @@ _c_flags = $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), \
$(filter-out $(ccflags-remove-y), \
$(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(ccflags-y)) \
$(CFLAGS_$(target-stem).o))
+_rust_flags = $(filter-out $(RUSTFLAGS_REMOVE_$(target-stem).o), \
+ $(filter-out $(rustflags-remove-y), \
+ $(KBUILD_RUSTFLAGS) $(rustflags-y)) \
+ $(RUSTFLAGS_$(target-stem).o))
_a_flags = $(filter-out $(AFLAGS_REMOVE_$(target-stem).o), \
$(filter-out $(asflags-remove-y), \
$(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(asflags-y)) \
@@ -151,6 +164,15 @@ _c_flags += $(if $(patsubst n%,, \
endif
endif
+ifeq ($(CONFIG_KMSAN),y)
+_c_flags += $(if $(patsubst n%,, \
+ $(KMSAN_SANITIZE_$(basetarget).o)$(KMSAN_SANITIZE)y), \
+ $(CFLAGS_KMSAN))
+_c_flags += $(if $(patsubst n%,, \
+ $(KMSAN_ENABLE_CHECKS_$(basetarget).o)$(KMSAN_ENABLE_CHECKS)y), \
+ , -mllvm -msan-disable-checks=1)
+endif
+
ifeq ($(CONFIG_UBSAN),y)
_c_flags += $(if $(patsubst n%,, \
$(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)$(CONFIG_UBSAN_SANITIZE_ALL)), \
@@ -171,6 +193,11 @@ ifeq ($(CONFIG_KCSAN),y)
_c_flags += $(if $(patsubst n%,, \
$(KCSAN_SANITIZE_$(basetarget).o)$(KCSAN_SANITIZE)y), \
$(CFLAGS_KCSAN))
+# Some uninstrumented files provide implied barriers required to avoid false
+# positives: set KCSAN_INSTRUMENT_BARRIERS for barrier instrumentation only.
+_c_flags += $(if $(patsubst n%,, \
+ $(KCSAN_INSTRUMENT_BARRIERS_$(basetarget).o)$(KCSAN_INSTRUMENT_BARRIERS)n), \
+ -D__KCSAN_INSTRUMENT_BARRIERS__)
endif
# $(srctree)/$(src) for including checkin headers from generated source files
@@ -191,6 +218,11 @@ modkern_cflags = \
$(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \
$(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL) $(modfile_flags))
+modkern_rustflags = \
+ $(if $(part-of-module), \
+ $(KBUILD_RUSTFLAGS_MODULE) $(RUSTFLAGS_MODULE), \
+ $(KBUILD_RUSTFLAGS_KERNEL) $(RUSTFLAGS_KERNEL))
+
modkern_aflags = $(if $(part-of-module), \
$(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE), \
$(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL))
@@ -200,6 +232,8 @@ c_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
$(_c_flags) $(modkern_cflags) \
$(basename_flags) $(modname_flags)
+rust_flags = $(_rust_flags) $(modkern_rustflags) @$(objtree)/include/generated/rustc_cfg
+
a_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
$(_a_flags) $(modkern_aflags)
@@ -214,38 +248,59 @@ dtc_cpp_flags = -Wp,-MMD,$(depfile).pre.tmp -nostdinc \
$(addprefix -I,$(DTC_INCLUDE)) \
-undef -D__DTS__
-# Objtool arguments are also needed for modfinal with LTO, so we define
-# then here to avoid duplication.
-objtool_args = \
- $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \
- $(if $(part-of-module), --module,) \
- $(if $(CONFIG_FRAME_POINTER),, --no-fp) \
- $(if $(or $(CONFIG_GCOV_KERNEL),$(CONFIG_LTO_CLANG)), \
- --no-unreachable,) \
- $(if $(CONFIG_RETPOLINE), --retpoline,) \
- $(if $(CONFIG_X86_SMAP), --uaccess,) \
- $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount,)
+ifdef CONFIG_OBJTOOL
+
+objtool := $(objtree)/tools/objtool/objtool
+
+objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK) += --hacks=jump_label
+objtool-args-$(CONFIG_HAVE_NOINSTR_HACK) += --hacks=noinstr
+objtool-args-$(CONFIG_CALL_DEPTH_TRACKING) += --hacks=skylake
+objtool-args-$(CONFIG_X86_KERNEL_IBT) += --ibt
+objtool-args-$(CONFIG_FINEIBT) += --cfi
+objtool-args-$(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL) += --mcount
+ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL
+objtool-args-$(CONFIG_HAVE_OBJTOOL_NOP_MCOUNT) += --mnop
+endif
+objtool-args-$(CONFIG_UNWINDER_ORC) += --orc
+objtool-args-$(CONFIG_RETPOLINE) += --retpoline
+objtool-args-$(CONFIG_RETHUNK) += --rethunk
+objtool-args-$(CONFIG_SLS) += --sls
+objtool-args-$(CONFIG_STACK_VALIDATION) += --stackval
+objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call
+objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess
+objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable
+objtool-args-$(CONFIG_PREFIX_SYMBOLS) += --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
+
+objtool-args = $(objtool-args-y) \
+ $(if $(delay-objtool), --link) \
+ $(if $(part-of-module), --module)
+
+delay-objtool := $(or $(CONFIG_LTO_CLANG),$(CONFIG_X86_KERNEL_IBT))
+
+cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool-args) $@)
+cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd)
+
+endif # CONFIG_OBJTOOL
# Useful for describing the dependency of composite objects
# Usage:
# $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add)
define multi_depend
-$(foreach m, $(notdir $1), \
- $(eval $(obj)/$m: \
- $(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s)))))))
+$(foreach m, $1, \
+ $(eval $m: \
+ $(addprefix $(obj)/, $(call suffix-search, $(patsubst $(obj)/%,%,$m), $2, $3))))
endef
-quiet_cmd_copy = COPY $@
- cmd_copy = cp $< $@
-
-# Shipped files
+# Copy a file
# ===========================================================================
-
-quiet_cmd_shipped = SHIPPED $@
-cmd_shipped = cat $< > $@
+# 'cp' preserves permissions. If you use it to copy a file in read-only srctree,
+# the copy would be read-only as well, leading to an error when executing the
+# rule next time. Use 'cat' instead in order to generate a writable file.
+quiet_cmd_copy = COPY $@
+ cmd_copy = cat $< > $@
$(obj)/%: $(src)/%_shipped
- $(call cmd,shipped)
+ $(call cmd,copy)
# Commands useful for building a boot image
# ===========================================================================
@@ -285,74 +340,86 @@ quiet_cmd_gzip = GZIP $@
# DTC
# ---------------------------------------------------------------------------
DTC ?= $(objtree)/scripts/dtc/dtc
-DTC_FLAGS += -Wno-interrupt_provider
+DTC_FLAGS += -Wno-interrupt_provider \
+ -Wno-unique_unit_address
# Disable noisy checks by default
ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),)
DTC_FLAGS += -Wno-unit_address_vs_reg \
- -Wno-unit_address_format \
-Wno-avoid_unnecessary_addr_size \
-Wno-alias_paths \
-Wno-graph_child_address \
- -Wno-simple_bus_reg \
- -Wno-unique_unit_address \
- -Wno-pci_device_reg
+ -Wno-simple_bus_reg
+else
+DTC_FLAGS += \
+ -Wunique_unit_address_if_enabled
endif
ifneq ($(findstring 2,$(KBUILD_EXTRA_WARN)),)
DTC_FLAGS += -Wnode_name_chars_strict \
-Wproperty_name_chars_strict \
- -Winterrupt_provider
+ -Winterrupt_provider \
+ -Wunique_unit_address
endif
DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
+# Set -@ if the target is a base DTB that overlay is applied onto
+DTC_FLAGS += $(if $(filter $(patsubst $(obj)/%,%,$@), $(base-dtb-y)), -@)
+
# Generate an assembly file to wrap the output of the device tree compiler
-quiet_cmd_dt_S_dtb= DTB $@
-cmd_dt_S_dtb= \
-{ \
- echo '\#include <asm-generic/vmlinux.lds.h>'; \
- echo '.section .dtb.init.rodata,"a"'; \
- echo '.balign STRUCT_ALIGNMENT'; \
- echo '.global __dtb_$(subst -,_,$(*F))_begin'; \
- echo '__dtb_$(subst -,_,$(*F))_begin:'; \
- echo '.incbin "$<" '; \
- echo '__dtb_$(subst -,_,$(*F))_end:'; \
- echo '.global __dtb_$(subst -,_,$(*F))_end'; \
- echo '.balign STRUCT_ALIGNMENT'; \
-} > $@
+quiet_cmd_wrap_S_dtb = WRAP $@
+ cmd_wrap_S_dtb = { \
+ symbase=__$(patsubst .%,%,$(suffix $<))_$(subst -,_,$(notdir $*)); \
+ echo '\#include <asm-generic/vmlinux.lds.h>'; \
+ echo '.section .dtb.init.rodata,"a"'; \
+ echo '.balign STRUCT_ALIGNMENT'; \
+ echo ".global $${symbase}_begin"; \
+ echo "$${symbase}_begin:"; \
+ echo '.incbin "$<" '; \
+ echo ".global $${symbase}_end"; \
+ echo "$${symbase}_end:"; \
+ echo '.balign STRUCT_ALIGNMENT'; \
+ } > $@
$(obj)/%.dtb.S: $(obj)/%.dtb FORCE
- $(call if_changed,dt_S_dtb)
+ $(call if_changed,wrap_S_dtb)
+
+$(obj)/%.dtbo.S: $(obj)/%.dtbo FORCE
+ $(call if_changed,wrap_S_dtb)
quiet_cmd_dtc = DTC $@
cmd_dtc = $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
- $(DTC) -O $(patsubst .%,%,$(suffix $@)) -o $@ -b 0 \
+ $(DTC) -o $@ -b 0 \
$(addprefix -i,$(dir $<) $(DTC_INCLUDE)) $(DTC_FLAGS) \
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
-$(obj)/%.dtb: $(src)/%.dts $(DTC) FORCE
- $(call if_changed_dep,dtc)
+quiet_cmd_fdtoverlay = DTOVL $@
+ cmd_fdtoverlay = $(objtree)/scripts/dtc/fdtoverlay -o $@ -i $(real-prereqs)
-$(obj)/%.dtbo: $(src)/%.dts $(DTC) FORCE
- $(call if_changed_dep,dtc)
+$(multi-dtb-y): FORCE
+ $(call if_changed,fdtoverlay)
+$(call multi_depend, $(multi-dtb-y), .dtb, -dtbs)
+ifneq ($(CHECK_DTBS)$(CHECK_DT_BINDING),)
DT_CHECKER ?= dt-validate
+DT_CHECKER_FLAGS ?= $(if $(DT_SCHEMA_FILES),-l $(DT_SCHEMA_FILES),-m)
DT_BINDING_DIR := Documentation/devicetree/bindings
-# DT_TMP_SCHEMA may be overridden from Documentation/devicetree/bindings/Makefile
-DT_TMP_SCHEMA ?= $(objtree)/$(DT_BINDING_DIR)/processed-schema.json
+DT_TMP_SCHEMA := $(objtree)/$(DT_BINDING_DIR)/processed-schema.json
-quiet_cmd_dtb_check = CHECK $@
- cmd_dtb_check = $(DT_CHECKER) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@
+quiet_cmd_dtb = DTC_CHK $@
+ cmd_dtb = $(cmd_dtc) ; $(DT_CHECKER) $(DT_CHECKER_FLAGS) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@ || true
+else
+quiet_cmd_dtb = $(quiet_cmd_dtc)
+ cmd_dtb = $(cmd_dtc)
+endif
-define rule_dtc
- $(call cmd_and_fixdep,dtc)
- $(call cmd,dtb_check)
-endef
+$(obj)/%.dtb: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE
+ $(call if_changed_dep,dtb)
-$(obj)/%.dt.yaml: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE
- $(call if_changed_rule,dtc,yaml)
+$(obj)/%.dtbo: $(src)/%.dtso $(DTC) FORCE
+ $(call if_changed_dep,dtc)
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
@@ -376,20 +443,35 @@ printf "%08x\n" $$dec_size | \
} \
)
+quiet_cmd_file_size = GEN $@
+ cmd_file_size = $(size_append) > $@
+
quiet_cmd_bzip2 = BZIP2 $@
- cmd_bzip2 = { cat $(real-prereqs) | $(KBZIP2) -9; $(size_append); } > $@
+ cmd_bzip2 = cat $(real-prereqs) | $(KBZIP2) -9 > $@
+
+quiet_cmd_bzip2_with_size = BZIP2 $@
+ cmd_bzip2_with_size = { cat $(real-prereqs) | $(KBZIP2) -9; $(size_append); } > $@
# Lzma
# ---------------------------------------------------------------------------
quiet_cmd_lzma = LZMA $@
- cmd_lzma = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@
+ cmd_lzma = cat $(real-prereqs) | $(LZMA) -9 > $@
+
+quiet_cmd_lzma_with_size = LZMA $@
+ cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@
quiet_cmd_lzo = LZO $@
- cmd_lzo = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@
+ cmd_lzo = cat $(real-prereqs) | $(KLZOP) -9 > $@
+
+quiet_cmd_lzo_with_size = LZO $@
+ cmd_lzo_with_size = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@
quiet_cmd_lz4 = LZ4 $@
- cmd_lz4 = { cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout; \
+ cmd_lz4 = cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout > $@
+
+quiet_cmd_lz4_with_size = LZ4 $@
+ cmd_lz4_with_size = { cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout; \
$(size_append); } > $@
# U-Boot mkimage
@@ -400,7 +482,7 @@ MKIMAGE := $(srctree)/scripts/mkuboot.sh
# SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces
# the number of overrides in arch makefiles
UIMAGE_ARCH ?= $(SRCARCH)
-UIMAGE_COMPRESSION ?= $(if $(2),$(2),none)
+UIMAGE_COMPRESSION ?= $(or $(2),none)
UIMAGE_OPTS-y ?=
UIMAGE_TYPE ?= kernel
UIMAGE_LOADADDR ?= arch_must_set_this
@@ -432,7 +514,10 @@ quiet_cmd_uimage = UIMAGE $@
# big dictionary would increase the memory usage too much in the multi-call
# decompression mode. A BCJ filter isn't used either.
quiet_cmd_xzkern = XZKERN $@
- cmd_xzkern = { cat $(real-prereqs) | sh $(srctree)/scripts/xz_wrap.sh; \
+ cmd_xzkern = cat $(real-prereqs) | sh $(srctree)/scripts/xz_wrap.sh > $@
+
+quiet_cmd_xzkern_with_size = XZKERN $@
+ cmd_xzkern_with_size = { cat $(real-prereqs) | sh $(srctree)/scripts/xz_wrap.sh; \
$(size_append); } > $@
quiet_cmd_xzmisc = XZMISC $@
@@ -455,10 +540,13 @@ quiet_cmd_xzmisc = XZMISC $@
# be used because it would require zstd to allocate a 128 MB buffer.
quiet_cmd_zstd = ZSTD $@
- cmd_zstd = { cat $(real-prereqs) | $(ZSTD) -19; $(size_append); } > $@
+ cmd_zstd = cat $(real-prereqs) | $(ZSTD) -19 > $@
quiet_cmd_zstd22 = ZSTD22 $@
- cmd_zstd22 = { cat $(real-prereqs) | $(ZSTD) -22 --ultra; $(size_append); } > $@
+ cmd_zstd22 = cat $(real-prereqs) | $(ZSTD) -22 --ultra > $@
+
+quiet_cmd_zstd22_with_size = ZSTD22 $@
+ cmd_zstd22_with_size = { cat $(real-prereqs) | $(ZSTD) -22 --ultra; $(size_append); } > $@
# ASM offsets
# ---------------------------------------------------------------------------
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index 735e11e9041b..fc19f67039bd 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -9,13 +9,13 @@ __modfinal:
include include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
-# for c_flags and objtool_args
+# for c_flags
include $(srctree)/scripts/Makefile.lib
# find all modules listed in modules.order
-modules := $(sort $(shell cat $(MODORDER)))
+modules := $(call read-file, $(MODORDER))
-__modfinal: $(modules)
+__modfinal: $(modules:%.o=%.ko)
@:
# modname and part-of-module are set to make c_flags define proper module flags
@@ -23,32 +23,13 @@ modname = $(notdir $(@:.mod.o=))
part-of-module = y
quiet_cmd_cc_o_c = CC [M] $@
- cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+ cmd_cc_o_c = $(CC) $(filter-out $(CC_FLAGS_CFI) $(CFLAGS_GCOV), $(c_flags)) -c -o $@ $<
%.mod.o: %.mod.c FORCE
$(call if_changed_dep,cc_o_c)
ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
-ifdef CONFIG_LTO_CLANG
-# With CONFIG_LTO_CLANG, reuse the object file we compiled for modpost to
-# avoid a second slow LTO link
-prelink-ext := .lto
-
-# ELF processing was skipped earlier because we didn't have native code,
-# so let's now process the prelinked binary before we link the module.
-
-ifdef CONFIG_STACK_VALIDATION
-ifneq ($(SKIP_STACK_VALIDATION),1)
-cmd_ld_ko_o += \
- $(objtree)/tools/objtool/objtool $(objtool_args) \
- $(@:.ko=$(prelink-ext).o);
-
-endif # SKIP_STACK_VALIDATION
-endif # CONFIG_STACK_VALIDATION
-
-endif # CONFIG_LTO_CLANG
-
quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o += \
$(LD) -r $(KBUILD_LDFLAGS) \
@@ -58,10 +39,13 @@ quiet_cmd_ld_ko_o = LD [M] $@
quiet_cmd_btf_ko = BTF [M] $@
cmd_btf_ko = \
- if [ -f vmlinux ]; then \
- LLVM_OBJCOPY=$(OBJCOPY) $(PAHOLE) -J --btf_base vmlinux $@; \
- else \
+ if [ ! -f vmlinux ]; then \
printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \
+ elif [ -n "$(CONFIG_RUST)" ] && $(srctree)/scripts/is_rust_module.sh $@; then \
+ printf "Skipping BTF generation for %s because it's a Rust module\n" $@ 1>&2; \
+ else \
+ LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) --btf_base vmlinux $@; \
+ $(RESOLVE_BTFIDS) -b vmlinux $@; \
fi;
# Same as newer-prereqs, but allows to exclude specified extra dependencies
@@ -70,17 +54,16 @@ newer_prereqs_except = $(filter-out $(PHONY) $(1),$?)
# Same as if_changed, but allows to exclude specified extra dependencies
if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \
$(cmd); \
- printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
-
+ printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
# Re-generate module BTFs if either module's .ko or vmlinux changed
-$(modules): %.ko: %$(prelink-ext).o %.mod.o scripts/module.lds $(if $(KBUILD_BUILTIN),vmlinux) FORCE
+%.ko: %.o %.mod.o scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),vmlinux) FORCE
+$(call if_changed_except,ld_ko_o,vmlinux)
ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+$(if $(newer-prereqs),$(call cmd,btf_ko))
endif
-targets += $(modules) $(modules:.ko=.mod.o)
+targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o)
# Add FORCE to the prequisites of a target to force it to be always rebuilt.
# ---------------------------------------------------------------------------
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
index 5a4579e76485..ab0c5bd1a60f 100644
--- a/scripts/Makefile.modinst
+++ b/scripts/Makefile.modinst
@@ -6,30 +6,113 @@
PHONY := __modinst
__modinst:
-include scripts/Kbuild.include
+include include/config/auto.conf
+include $(srctree)/scripts/Kbuild.include
-modules := $(sort $(shell cat $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/)modules.order))
+modules := $(call read-file, $(MODORDER))
+
+ifeq ($(KBUILD_EXTMOD),)
+dst := $(MODLIB)/kernel
+else
+INSTALL_MOD_DIR ?= updates
+dst := $(MODLIB)/$(INSTALL_MOD_DIR)
+endif
+
+$(foreach x, % :, $(if $(findstring $x, $(dst)), \
+ $(error module installation path cannot contain '$x')))
+
+suffix-y :=
+suffix-$(CONFIG_MODULE_COMPRESS_GZIP) := .gz
+suffix-$(CONFIG_MODULE_COMPRESS_XZ) := .xz
+suffix-$(CONFIG_MODULE_COMPRESS_ZSTD) := .zst
+
+modules := $(patsubst $(extmod_prefix)%.o, $(dst)/%.ko$(suffix-y), $(modules))
-PHONY += $(modules)
__modinst: $(modules)
@:
-# Don't stop modules_install if we can't sign external modules.
-quiet_cmd_modules_install = INSTALL $@
- cmd_modules_install = \
- mkdir -p $(2) ; \
- cp $@ $(2) ; \
- $(mod_strip_cmd) $(2)/$(notdir $@) ; \
- $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) ; \
- $(mod_compress_cmd) $(2)/$(notdir $@)
+#
+# Installation
+#
+quiet_cmd_install = INSTALL $@
+ cmd_install = mkdir -p $(dir $@); cp $< $@
+
+# Strip
+#
+# INSTALL_MOD_STRIP, if defined, will cause modules to be stripped after they
+# are installed. If INSTALL_MOD_STRIP is '1', then the default option
+# --strip-debug will be used. Otherwise, INSTALL_MOD_STRIP value will be used
+# as the options to the strip command.
+ifdef INSTALL_MOD_STRIP
+
+ifeq ($(INSTALL_MOD_STRIP),1)
+strip-option := --strip-debug
+else
+strip-option := $(INSTALL_MOD_STRIP)
+endif
+
+quiet_cmd_strip = STRIP $@
+ cmd_strip = $(STRIP) $(strip-option) $@
+
+else
+
+quiet_cmd_strip =
+ cmd_strip = :
+
+endif
+
+#
+# Signing
+# Don't stop modules_install even if we can't sign external modules.
+#
+ifeq ($(CONFIG_MODULE_SIG_ALL),y)
+ifeq ($(filter pkcs11:%, $(CONFIG_MODULE_SIG_KEY)),)
+sig-key := $(if $(wildcard $(CONFIG_MODULE_SIG_KEY)),,$(srctree)/)$(CONFIG_MODULE_SIG_KEY)
+else
+sig-key := $(CONFIG_MODULE_SIG_KEY)
+endif
+quiet_cmd_sign = SIGN $@
+ cmd_sign = scripts/sign-file $(CONFIG_MODULE_SIG_HASH) "$(sig-key)" certs/signing_key.x509 $@ \
+ $(if $(KBUILD_EXTMOD),|| true)
+else
+quiet_cmd_sign :=
+ cmd_sign := :
+endif
+
+ifeq ($(modules_sign_only),)
+
+$(dst)/%.ko: $(extmod_prefix)%.ko FORCE
+ $(call cmd,install)
+ $(call cmd,strip)
+ $(call cmd,sign)
+
+else
+
+$(dst)/%.ko: FORCE
+ $(call cmd,sign)
+
+endif
+
+#
+# Compression
+#
+quiet_cmd_gzip = GZIP $@
+ cmd_gzip = $(KGZIP) -n -f $<
+quiet_cmd_xz = XZ $@
+ cmd_xz = $(XZ) --lzma2=dict=2MiB -f $<
+quiet_cmd_zstd = ZSTD $@
+ cmd_zstd = $(ZSTD) -T0 --rm -f -q $<
+
+$(dst)/%.ko.gz: $(dst)/%.ko FORCE
+ $(call cmd,gzip)
-# Modules built outside the kernel source tree go into extra by default
-INSTALL_MOD_DIR ?= extra
-ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(patsubst %/,%,$(KBUILD_EXTMOD)),,$(@D))
+$(dst)/%.ko.xz: $(dst)/%.ko FORCE
+ $(call cmd,xz)
-modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
+$(dst)/%.ko.zst: $(dst)/%.ko FORCE
+ $(call cmd,zstd)
-$(modules):
- $(call cmd,modules_install,$(MODLIB)/$(modinst_dir))
+PHONY += FORCE
+FORCE:
.PHONY: $(PHONY)
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 066beffca09a..39472e834b63 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -13,7 +13,7 @@
# Stage 2 is handled by this file and does the following
# 1) Find all modules listed in modules.order
# 2) modpost is then used to
-# 3) create one <module>.mod.c file pr. module
+# 3) create one <module>.mod.c file per module
# 4) create one Module.symvers file with CRC for all exported symbols
# Step 3 is used to place certain information in the module's ELF
@@ -32,43 +32,80 @@
# Step 4 is solely used to allow module versioning in external modules,
# where the CRC of each module is retrieved from the Module.symvers file.
-# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
-# symbols in the final module linking stage
-# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
-# This is solely useful to speed up test compiles
-
PHONY := __modpost
__modpost:
include include/config/auto.conf
-include scripts/Kbuild.include
+include $(srctree)/scripts/Kbuild.include
-# for ld_flags
-include scripts/Makefile.lib
+MODPOST = scripts/mod/modpost
-MODPOST = scripts/mod/modpost \
+modpost-args = \
$(if $(CONFIG_MODVERSIONS),-m) \
$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \
$(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \
- $(if $(KBUILD_MODPOST_WARN),-w) \
+ $(if $(KBUILD_MODPOST_WARN),-w) \
+ $(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS)) \
+ $(if $(CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS)$(KBUILD_NSDEPS),-N) \
+ $(if $(findstring 1, $(KBUILD_EXTRA_WARN)),-W) \
-o $@
-ifdef MODPOST_VMLINUX
+modpost-deps := $(MODPOST)
-quiet_cmd_modpost = MODPOST $@
- cmd_modpost = $(MODPOST) $<
+# 'make -i -k' ignores compile errors, and builds as many modules as possible.
+ifneq ($(findstring i,$(filter-out --%,$(MAKEFLAGS))),)
+modpost-args += -n
+endif
-vmlinux.symvers: vmlinux.o
- $(call cmd,modpost)
+# Read out modules.order to pass in modpost.
+# Otherwise, allmodconfig would fail with "Argument list too long".
+ifdef KBUILD_MODULES
+modpost-args += -T $(MODORDER)
+modpost-deps += $(MODORDER)
+endif
-__modpost: vmlinux.symvers
+ifeq ($(KBUILD_EXTMOD),)
-else
+# Generate the list of in-tree objects in vmlinux
+# ---------------------------------------------------------------------------
-ifeq ($(KBUILD_EXTMOD),)
+# This is used to retrieve symbol versions generated by genksyms.
+ifdef CONFIG_MODVERSIONS
+vmlinux.symvers Module.symvers: .vmlinux.objs
+endif
+
+# Ignore libgcc.a
+# Some architectures do '$(CC) --print-libgcc-file-name' to borrow libgcc.a
+# from the toolchain, but there is no EXPORT_SYMBOL in it.
+
+quiet_cmd_vmlinux_objs = GEN $@
+ cmd_vmlinux_objs = \
+ for f in $(real-prereqs); do \
+ case $${f} in \
+ *libgcc.a) ;; \
+ *) $(AR) t $${f} ;; \
+ esac \
+ done > $@
+
+targets += .vmlinux.objs
+.vmlinux.objs: vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
+ $(call if_changed,vmlinux_objs)
+
+ifdef CONFIG_TRIM_UNUSED_KSYMS
+ksym-wl := $(CONFIG_UNUSED_KSYMS_WHITELIST)
+ksym-wl := $(if $(filter-out /%, $(ksym-wl)),$(srctree)/)$(ksym-wl)
+modpost-args += -t $(addprefix -u , $(ksym-wl))
+modpost-deps += $(ksym-wl)
+endif
-input-symdump := vmlinux.symvers
-output-symdump := Module.symvers
+ifeq ($(wildcard vmlinux.o),)
+missing-input := vmlinux.o
+output-symdump := modules-only.symvers
+else
+modpost-args += vmlinux.o
+modpost-deps += vmlinux.o
+output-symdump := $(if $(KBUILD_MODULES), Module.symvers, vmlinux.symvers)
+endif
else
@@ -77,67 +114,36 @@ obj := $(KBUILD_EXTMOD)
src := $(obj)
# Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS
-include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \
- $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile)
-
-# modpost option for external modules
-MODPOST += -e
+include $(kbuild-file)
-input-symdump := Module.symvers $(KBUILD_EXTRA_SYMBOLS)
output-symdump := $(KBUILD_EXTMOD)/Module.symvers
+ifeq ($(wildcard Module.symvers),)
+missing-input := Module.symvers
+else
+modpost-args += -i Module.symvers
+modpost-deps += Module.symvers
endif
-# modpost options for modules (both in-kernel and external)
-MODPOST += \
- $(addprefix -i ,$(wildcard $(input-symdump))) \
- $(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS)) \
- $(if $(CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS)$(KBUILD_NSDEPS),-N)
-
-# 'make -i -k' ignores compile errors, and builds as many modules as possible.
-ifneq ($(findstring i,$(filter-out --%,$(MAKEFLAGS))),)
-MODPOST += -n
-endif
-
-# Clear VPATH to not search for *.symvers in $(srctree). Check only $(objtree).
-VPATH :=
-$(input-symdump):
- @echo >&2 'WARNING: Symbol version dump "$@" is missing.'
- @echo >&2 ' Modules may not have dependencies or modversions.'
-
-ifdef CONFIG_LTO_CLANG
-# With CONFIG_LTO_CLANG, .o files might be LLVM bitcode, so we need to run
-# LTO to compile them into native code before running modpost
-prelink-ext := .lto
-
-quiet_cmd_cc_lto_link_modules = LTO [M] $@
-cmd_cc_lto_link_modules = \
- $(LD) $(ld_flags) -r -o $@ \
- $(shell [ -s $(@:.lto.o=.o.symversions) ] && \
- echo -T $(@:.lto.o=.o.symversions)) \
- --whole-archive $^
-
-%.lto.o: %.o
- $(call if_changed,cc_lto_link_modules)
-endif
+modpost-args += -e $(addprefix -i , $(KBUILD_EXTRA_SYMBOLS))
-modules := $(sort $(shell cat $(MODORDER)))
+endif # ($(KBUILD_EXTMOD),)
-# Read out modules.order to pass in modpost.
-# Otherwise, allmodconfig would fail with "Argument list too long".
quiet_cmd_modpost = MODPOST $@
- cmd_modpost = sed 's/\.ko$$/$(prelink-ext)\.o/' $< | $(MODPOST) -T -
-
-$(output-symdump): $(MODORDER) $(input-symdump) $(modules:.ko=$(prelink-ext).o) FORCE
- $(call if_changed,modpost)
+ cmd_modpost = \
+ $(if $(missing-input), \
+ echo >&2 "WARNING: $(missing-input) is missing."; \
+ echo >&2 " Modules may not have dependencies or modversions."; \
+ echo >&2 " You may get many unresolved symbol errors."; \
+ echo >&2 " You can set KBUILD_MODPOST_WARN=1 to turn errors into warning"; \
+ echo >&2 " if you want to proceed at your own risk.";) \
+ $(MODPOST) $(modpost-args)
targets += $(output-symdump)
+$(output-symdump): $(modpost-deps) FORCE
+ $(call if_changed,modpost)
__modpost: $(output-symdump)
-ifneq ($(KBUILD_MODPOST_NOFINAL),1)
- $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal
-endif
-
PHONY += FORCE
FORCE:
@@ -145,6 +151,4 @@ existing-targets := $(wildcard $(sort $(targets)))
-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
-endif
-
.PHONY: $(PHONY)
diff --git a/scripts/Makefile.modsign b/scripts/Makefile.modsign
deleted file mode 100644
index d7325cefe709..000000000000
--- a/scripts/Makefile.modsign
+++ /dev/null
@@ -1,29 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# ==========================================================================
-# Signing modules
-# ==========================================================================
-
-PHONY := __modsign
-__modsign:
-
-include scripts/Kbuild.include
-
-modules := $(sort $(shell cat modules.order))
-
-PHONY += $(modules)
-__modsign: $(modules)
- @:
-
-quiet_cmd_sign_ko = SIGN [M] $(2)/$(notdir $@)
- cmd_sign_ko = $(mod_sign_cmd) $(2)/$(notdir $@)
-
-# Modules built outside the kernel source tree go into extra by default
-INSTALL_MOD_DIR ?= extra
-ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(patsubst %/,%,$(KBUILD_EXTMOD)),,$(@D))
-
-modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
-
-$(modules):
- $(call cmd,sign_ko,$(MODLIB)/$(modinst_dir))
-
-.PHONY: $(PHONY)
diff --git a/scripts/Makefile.package b/scripts/Makefile.package
index f952fb64789d..92dbc889bd7c 100644
--- a/scripts/Makefile.package
+++ b/scripts/Makefile.package
@@ -2,34 +2,14 @@
# Makefile for the different targets used to generate full packages of a kernel
include $(srctree)/scripts/Kbuild.include
+include $(srctree)/scripts/Makefile.lib
-# RPM target
-# ---------------------------------------------------------------------------
-# The rpm target generates two rpm files:
-# /usr/src/packages/SRPMS/kernel-2.6.7rc2-1.src.rpm
-# /usr/src/packages/RPMS/i386/kernel-2.6.7rc2-1.<arch>.rpm
-# The src.rpm files includes all source for the kernel being built
-# The <arch>.rpm includes kernel configuration, modules etc.
-#
-# Process to create the rpm files
-# a) clean the kernel
-# b) Generate .spec file
-# c) Build a tar ball, using symlink to make kernel version
-# first entry in the path
-# d) and pack the result to a tar.gz file
-# e) generate the rpm files, based on kernel.spec
-# - Use /. to avoid tar packing just the symlink
-
-# Note that the rpm-pkg target cannot be used with KBUILD_OUTPUT,
-# but the binrpm-pkg target can; for some reason O= gets ignored.
-
-# Remove hyphens since they have special meaning in RPM filenames
KERNELPATH := kernel-$(subst -,_,$(KERNELRELEASE))
-KDEB_SOURCENAME ?= linux-$(KERNELRELEASE)
-KBUILD_PKG_ROOTCMD ?="fakeroot -u"
-export KDEB_SOURCENAME
# Include only those top-level files that are needed by make, plus the GPL copy
-TAR_CONTENT := $(KBUILD_ALLDIRS) .config .scmversion Makefile \
+TAR_CONTENT := Documentation LICENSES arch block certs crypto drivers fs \
+ include init io_uring ipc kernel lib mm net rust \
+ samples scripts security sound tools usr virt \
+ .config Makefile \
Kbuild Kconfig COPYING $(wildcard localversion*)
MKSPEC := $(srctree)/scripts/package/mkspec
@@ -39,26 +19,69 @@ if test "$(objtree)" != "$(srctree)"; then \
echo >&2; \
echo >&2 " ERROR:"; \
echo >&2 " Building source tarball is not possible outside the"; \
- echo >&2 " kernel source tree. Don't set KBUILD_OUTPUT, or use the"; \
- echo >&2 " binrpm-pkg or bindeb-pkg target instead."; \
+ echo >&2 " kernel source tree. Don't set KBUILD_OUTPUT"; \
echo >&2; \
false; \
fi ; \
-$(srctree)/scripts/setlocalversion --save-scmversion; \
tar -I $(KGZIP) -c $(RCS_TAR_IGNORE) -f $(2).tar.gz \
- --transform 's:^:$(2)/:S' $(TAR_CONTENT) $(3); \
-rm -f $(objtree)/.scmversion
+ --transform 's:^:$(2)/:S' $(TAR_CONTENT) $(3)
+
+# Git
+# ---------------------------------------------------------------------------
+
+filechk_HEAD = git -C $(srctree) rev-parse --verify HEAD 2>/dev/null
+
+.tmp_HEAD: check-git FORCE
+ $(call filechk,HEAD)
+
+PHONY += check-git
+check-git:
+ @if ! $(srctree)/scripts/check-git; then \
+ echo >&2 "error: creating source package requires git repository"; \
+ false; \
+ fi
+
+git-config-tar.gz = -c tar.tar.gz.command="$(KGZIP)"
+git-config-tar.bz2 = -c tar.tar.bz2.command="$(KBZIP2)"
+git-config-tar.lzma = -c tar.tar.lzma.command="$(LZMA)"
+git-config-tar.xz = -c tar.tar.xz.command="$(XZ)"
+git-config-tar.zst = -c tar.tar.zst.command="$(ZSTD)"
+
+quiet_cmd_archive = ARCHIVE $@
+ cmd_archive = git -C $(srctree) $(git-config-tar$(suffix $@)) archive \
+ --output=$$(realpath $@) $(archive-args)
+
+suffix-gzip := .gz
+suffix-bzip2 := .bz2
+suffix-lzma := .lzma
+suffix-xz := .xz
+
+# Linux source tarball
+# ---------------------------------------------------------------------------
+
+linux-tarballs := $(addprefix linux, .tar.gz .tar.bz2 .tar.lzma .tar.xz)
+
+targets += $(linux-tarballs)
+$(linux-tarballs): archive-args = --prefix=linux/ $$(cat $<)
+$(linux-tarballs): .tmp_HEAD FORCE
+ $(call if_changed,archive)
# rpm-pkg
# ---------------------------------------------------------------------------
PHONY += rpm-pkg
-rpm-pkg:
- $(MAKE) clean
- $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec
- $(call cmd,src_tar,$(KERNELPATH),kernel.spec)
- +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz \
+rpm-pkg: srpm = $(shell rpmspec --srpm --query --queryformat='%{name}-%{VERSION}-%{RELEASE}.src.rpm' kernel.spec)
+rpm-pkg: srcrpm-pkg
+ +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -rb $(srpm) \
--define='_smp_mflags %{nil}'
+# srcrpm-pkg
+# ---------------------------------------------------------------------------
+PHONY += srcrpm-pkg
+srcrpm-pkg: linux.tar.gz
+ $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec
+ +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -bs kernel.spec \
+ --define='_smp_mflags %{nil}' --define='_sourcedir rpmbuild/SOURCES' --define='_srcrpmdir .'
+
# binrpm-pkg
# ---------------------------------------------------------------------------
PHONY += binrpm-pkg
@@ -66,21 +89,61 @@ binrpm-pkg:
$(MAKE) -f $(srctree)/Makefile
$(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec
+rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \
- $(UTS_MACHINE) -bb $(objtree)/binkernel.spec
+ $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec
-PHONY += deb-pkg
-deb-pkg:
- $(MAKE) clean
- $(CONFIG_SHELL) $(srctree)/scripts/package/mkdebian
- $(call cmd,src_tar,$(KDEB_SOURCENAME))
- origversion=$$(dpkg-parsechangelog -SVersion |sed 's/-[^-]*$$//');\
- mv $(KDEB_SOURCENAME).tar.gz ../$(KDEB_SOURCENAME)_$${origversion}.orig.tar.gz
- +dpkg-buildpackage -r$(KBUILD_PKG_ROOTCMD) -a$$(cat debian/arch) $(DPKG_FLAGS) -i.git -us -uc
+# deb-pkg srcdeb-pkg bindeb-pkg
+# ---------------------------------------------------------------------------
+
+KDEB_SOURCE_COMPRESS ?= gzip
+
+supported-deb-source-compress := gzip bzip2 lzma xz
+
+PHONY += linux.tar.unsupported-deb-src-compress
+linux.tar.unsupported-deb-src-compress:
+ @echo "error: KDEB_SOURCE_COMPRESS=$(KDEB_SOURCE_COMPRESS) is not supported. The supported values are: $(supported-deb-source-compress)" >&2
+ @false
+
+debian-orig-suffix := \
+ $(strip $(if $(filter $(supported-deb-source-compress), $(KDEB_SOURCE_COMPRESS)), \
+ $(suffix-$(KDEB_SOURCE_COMPRESS)),.unsupported-deb-src-compress))
+
+quiet_cmd_debianize = GEN $@
+ cmd_debianize = $(srctree)/scripts/package/mkdebian $(mkdebian-opts)
+
+debian: FORCE
+ $(call cmd,debianize)
-PHONY += bindeb-pkg
-bindeb-pkg:
- $(CONFIG_SHELL) $(srctree)/scripts/package/mkdebian
- +dpkg-buildpackage -r$(KBUILD_PKG_ROOTCMD) -a$$(cat debian/arch) $(DPKG_FLAGS) -b -nc -uc
+PHONY += debian-orig
+debian-orig: private source = $(shell dpkg-parsechangelog -S Source)
+debian-orig: private version = $(shell dpkg-parsechangelog -S Version | sed 's/-[^-]*$$//')
+debian-orig: private orig-name = $(source)_$(version).orig.tar$(debian-orig-suffix)
+debian-orig: mkdebian-opts = --need-source
+debian-orig: linux.tar$(debian-orig-suffix) debian
+ $(Q)if [ "$(df --output=target .. 2>/dev/null)" = "$(df --output=target $< 2>/dev/null)" ]; then \
+ ln -f $< ../$(orig-name); \
+ else \
+ cp $< ../$(orig-name); \
+ fi
+
+KBUILD_PKG_ROOTCMD ?= 'fakeroot -u'
+
+PHONY += deb-pkg srcdeb-pkg bindeb-pkg
+
+deb-pkg: private build-type := source,binary
+srcdeb-pkg: private build-type := source
+bindeb-pkg: private build-type := binary
+
+deb-pkg srcdeb-pkg: debian-orig
+bindeb-pkg: debian
+deb-pkg srcdeb-pkg bindeb-pkg:
+ +$(strip dpkg-buildpackage \
+ --build=$(build-type) --no-pre-clean --unsigned-changes \
+ $(if $(findstring source, $(build-type)), \
+ --unsigned-source --compression=$(KDEB_SOURCE_COMPRESS)) \
+ $(if $(findstring binary, $(build-type)), \
+ -r$(KBUILD_PKG_ROOTCMD) -a$$(cat debian/arch), \
+ --no-check-builddeps) \
+ $(DPKG_FLAGS))
PHONY += intdeb-pkg
intdeb-pkg:
@@ -101,50 +164,83 @@ snap-pkg:
cd $(objtree)/snap && \
snapcraft --target-arch=$(UTS_MACHINE)
-# tarball targets
+# dir-pkg tar*-pkg - tarball targets
# ---------------------------------------------------------------------------
-tar-pkgs := dir-pkg tar-pkg targz-pkg tarbz2-pkg tarxz-pkg
-PHONY += $(tar-pkgs)
-$(tar-pkgs):
- $(MAKE) -f $(srctree)/Makefile
- +$(CONFIG_SHELL) $(srctree)/scripts/package/buildtar $@
-# perf-pkg - generate a source tarball with perf source
+tar-install: FORCE
+ $(Q)$(MAKE) -f $(srctree)/Makefile
+ +$(Q)$(srctree)/scripts/package/buildtar $@
+
+compress-tar.gz = -I "$(KGZIP)"
+compress-tar.bz2 = -I "$(KBZIP2)"
+compress-tar.xz = -I "$(XZ)"
+compress-tar.zst = -I "$(ZSTD)"
+
+quiet_cmd_tar = TAR $@
+ cmd_tar = cd $<; tar cf ../$@ $(compress-tar$(suffix $@)) --owner=root --group=root --sort=name *
+
+dir-tarballs := $(addprefix linux-$(KERNELRELEASE)-$(ARCH), .tar .tar.gz .tar.bz2 .tar.xz .tar.zst)
+
+$(dir-tarballs): tar-install
+ $(call cmd,tar)
+
+PHONY += dir-pkg
+dir-pkg: tar-install
+ @echo "Kernel tree successfully created in $<"
+
+PHONY += tar-pkg
+tar-pkg: linux-$(KERNELRELEASE)-$(ARCH).tar
+ @:
+
+tar%-pkg: linux-$(KERNELRELEASE)-$(ARCH).tar.% FORCE
+ @:
+
+# perf-tar*-src-pkg - generate a source tarball with perf source
# ---------------------------------------------------------------------------
-perf-tar=perf-$(KERNELVERSION)
-
-quiet_cmd_perf_tar = TAR
- cmd_perf_tar = \
-git --git-dir=$(srctree)/.git archive --prefix=$(perf-tar)/ \
- HEAD^{tree} $$(cd $(srctree); \
- echo $$(cat tools/perf/MANIFEST)) \
- -o $(perf-tar).tar; \
-mkdir -p $(perf-tar); \
-git --git-dir=$(srctree)/.git rev-parse HEAD > $(perf-tar)/HEAD; \
-(cd $(srctree)/tools/perf; \
-util/PERF-VERSION-GEN $(CURDIR)/$(perf-tar)/); \
-tar rf $(perf-tar).tar $(perf-tar)/HEAD $(perf-tar)/PERF-VERSION-FILE; \
-rm -r $(perf-tar); \
-$(if $(findstring tar-src,$@),, \
-$(if $(findstring bz2,$@),$(KBZIP2), \
-$(if $(findstring gz,$@),$(KGZIP), \
-$(if $(findstring xz,$@),$(XZ), \
-$(error unknown target $@)))) \
- -f -9 $(perf-tar).tar)
-
-perf-tar-pkgs := perf-tar-src-pkg perf-targz-src-pkg perf-tarbz2-src-pkg perf-tarxz-src-pkg
-PHONY += $(perf-tar-pkgs)
-$(perf-tar-pkgs):
- $(call cmd,perf_tar)
+.tmp_perf:
+ $(Q)mkdir .tmp_perf
+
+.tmp_perf/HEAD: .tmp_HEAD | .tmp_perf
+ $(call cmd,copy)
+
+quiet_cmd_perf_version_file = GEN $@
+ cmd_perf_version_file = cd $(srctree)/tools/perf; util/PERF-VERSION-GEN $(dir $(abspath $@))
+
+# PERF-VERSION-FILE and .tmp_HEAD are independent, but this avoids updating the
+# timestamp of PERF-VERSION-FILE.
+# The best is to fix tools/perf/util/PERF-VERSION-GEN.
+.tmp_perf/PERF-VERSION-FILE: .tmp_HEAD $(srctree)/tools/perf/util/PERF-VERSION-GEN | .tmp_perf
+ $(call cmd,perf_version_file)
+
+perf-archive-args = --add-file=$$(realpath $(word 2, $^)) \
+ --add-file=$$(realpath $(word 3, $^)) \
+ $$(cat $(word 2, $^))^{tree} $$(cat $<)
+
+
+perf-tarballs := $(addprefix perf-$(KERNELVERSION), .tar .tar.gz .tar.bz2 .tar.xz .tar.zst)
+
+targets += $(perf-tarballs)
+$(perf-tarballs): archive-args = --prefix=perf-$(KERNELVERSION)/ $(perf-archive-args)
+$(perf-tarballs): tools/perf/MANIFEST .tmp_perf/HEAD .tmp_perf/PERF-VERSION-FILE FORCE
+ $(call if_changed,archive)
+
+PHONY += perf-tar-src-pkg
+perf-tar-src-pkg: perf-$(KERNELVERSION).tar
+ @:
+
+perf-tar%-src-pkg: perf-$(KERNELVERSION).tar.% FORCE
+ @:
# Help text displayed when executing 'make help'
# ---------------------------------------------------------------------------
PHONY += help
help:
@echo ' rpm-pkg - Build both source and binary RPM kernel packages'
+ @echo ' srcrpm-pkg - Build only the source kernel RPM package'
@echo ' binrpm-pkg - Build only the binary kernel RPM package'
@echo ' deb-pkg - Build both source and binary deb kernel packages'
+ @echo ' srcdeb-pkg - Build only the source kernel deb package'
@echo ' bindeb-pkg - Build only the binary kernel deb package'
@echo ' snap-pkg - Build only the binary kernel snap package'
@echo ' (will connect to external hosts)'
@@ -153,9 +249,23 @@ help:
@echo ' targz-pkg - Build the kernel as a gzip compressed tarball'
@echo ' tarbz2-pkg - Build the kernel as a bzip2 compressed tarball'
@echo ' tarxz-pkg - Build the kernel as a xz compressed tarball'
- @echo ' perf-tar-src-pkg - Build $(perf-tar).tar source tarball'
- @echo ' perf-targz-src-pkg - Build $(perf-tar).tar.gz source tarball'
- @echo ' perf-tarbz2-src-pkg - Build $(perf-tar).tar.bz2 source tarball'
- @echo ' perf-tarxz-src-pkg - Build $(perf-tar).tar.xz source tarball'
+ @echo ' tarzst-pkg - Build the kernel as a zstd compressed tarball'
+ @echo ' perf-tar-src-pkg - Build the perf source tarball with no compression'
+ @echo ' perf-targz-src-pkg - Build the perf source tarball with gzip compression'
+ @echo ' perf-tarbz2-src-pkg - Build the perf source tarball with bz2 compression'
+ @echo ' perf-tarxz-src-pkg - Build the perf source tarball with xz compression'
+ @echo ' perf-tarzst-src-pkg - Build the perf source tarball with zst compression'
+
+PHONY += FORCE
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+existing-targets := $(wildcard $(sort $(targets)))
+
+-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
.PHONY: $(PHONY)
diff --git a/scripts/Makefile.randstruct b/scripts/Makefile.randstruct
new file mode 100644
index 000000000000..24e283e89893
--- /dev/null
+++ b/scripts/Makefile.randstruct
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+
+randstruct-cflags-y += -DRANDSTRUCT
+
+ifdef CONFIG_GCC_PLUGIN_RANDSTRUCT
+randstruct-cflags-y \
+ += -fplugin=$(objtree)/scripts/gcc-plugins/randomize_layout_plugin.so
+randstruct-cflags-$(CONFIG_RANDSTRUCT_PERFORMANCE) \
+ += -fplugin-arg-randomize_layout_plugin-performance-mode
+else
+randstruct-cflags-y \
+ += -frandomize-layout-seed-file=$(objtree)/scripts/basic/randstruct.seed
+endif
+
+export RANDSTRUCT_CFLAGS := $(randstruct-cflags-y)
+
+KBUILD_CFLAGS += $(RANDSTRUCT_CFLAGS)
diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan
index 9e2092fd5206..4749865c1b2c 100644
--- a/scripts/Makefile.ubsan
+++ b/scripts/Makefile.ubsan
@@ -2,13 +2,12 @@
# Enable available and selected UBSAN features.
ubsan-cflags-$(CONFIG_UBSAN_ALIGNMENT) += -fsanitize=alignment
-ubsan-cflags-$(CONFIG_UBSAN_ONLY_BOUNDS) += -fsanitize=bounds
+ubsan-cflags-$(CONFIG_UBSAN_BOUNDS_STRICT) += -fsanitize=bounds-strict
ubsan-cflags-$(CONFIG_UBSAN_ARRAY_BOUNDS) += -fsanitize=array-bounds
ubsan-cflags-$(CONFIG_UBSAN_LOCAL_BOUNDS) += -fsanitize=local-bounds
ubsan-cflags-$(CONFIG_UBSAN_SHIFT) += -fsanitize=shift
ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero
ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable
-ubsan-cflags-$(CONFIG_UBSAN_OBJECT_SIZE) += -fsanitize=object-size
ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool
ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum
ubsan-cflags-$(CONFIG_UBSAN_TRAP) += -fsanitize-undefined-trap-on-error
diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
new file mode 100644
index 000000000000..3cd6ca15f390
--- /dev/null
+++ b/scripts/Makefile.vmlinux
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+PHONY := __default
+__default: vmlinux
+
+include include/config/auto.conf
+include $(srctree)/scripts/Kbuild.include
+
+# for c_flags
+include $(srctree)/scripts/Makefile.lib
+
+targets :=
+
+quiet_cmd_cc_o_c = CC $@
+ cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+
+%.o: %.c FORCE
+ $(call if_changed_dep,cc_o_c)
+
+ifdef CONFIG_MODULES
+KASAN_SANITIZE_.vmlinux.export.o := n
+GCOV_PROFILE_.vmlinux.export.o := n
+targets += .vmlinux.export.o
+vmlinux: .vmlinux.export.o
+endif
+
+ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
+
+# Final link of vmlinux with optional arch pass after final link
+cmd_link_vmlinux = \
+ $< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)"; \
+ $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
+
+targets += vmlinux
+vmlinux: scripts/link-vmlinux.sh vmlinux.o $(KBUILD_LDS) FORCE
+ +$(call if_changed_dep,link_vmlinux)
+
+# Add FORCE to the prequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+PHONY += FORCE
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+existing-targets := $(wildcard $(sort $(targets)))
+
+-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
+
+.PHONY: $(PHONY)
diff --git a/scripts/Makefile.vmlinux_o b/scripts/Makefile.vmlinux_o
new file mode 100644
index 000000000000..0edfdb40364b
--- /dev/null
+++ b/scripts/Makefile.vmlinux_o
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+PHONY := __default
+__default: vmlinux.o modules.builtin.modinfo modules.builtin
+
+include include/config/auto.conf
+include $(srctree)/scripts/Kbuild.include
+
+# for objtool
+include $(srctree)/scripts/Makefile.lib
+
+# Generate a linker script to ensure correct ordering of initcalls for Clang LTO
+# ---------------------------------------------------------------------------
+
+quiet_cmd_gen_initcalls_lds = GEN $@
+ cmd_gen_initcalls_lds = \
+ $(PYTHON3) $(srctree)/scripts/jobserver-exec \
+ $(PERL) $(real-prereqs) > $@
+
+.tmp_initcalls.lds: $(srctree)/scripts/generate_initcall_order.pl \
+ vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
+ $(call if_changed,gen_initcalls_lds)
+
+targets := .tmp_initcalls.lds
+
+ifdef CONFIG_LTO_CLANG
+initcalls-lds := .tmp_initcalls.lds
+endif
+
+# objtool for vmlinux.o
+# ---------------------------------------------------------------------------
+#
+# For LTO and IBT, objtool doesn't run on individual translation units.
+# Run everything on vmlinux instead.
+
+objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION))
+
+vmlinux-objtool-args-$(delay-objtool) += $(objtool-args-y)
+vmlinux-objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable
+vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION) += --noinstr $(if $(CONFIG_CPU_UNRET_ENTRY), --unret)
+
+objtool-args = $(vmlinux-objtool-args-y) --link
+
+# Link of vmlinux.o used for section mismatch analysis
+# ---------------------------------------------------------------------------
+
+quiet_cmd_ld_vmlinux.o = LD $@
+ cmd_ld_vmlinux.o = \
+ $(LD) ${KBUILD_LDFLAGS} -r -o $@ \
+ $(addprefix -T , $(initcalls-lds)) \
+ --whole-archive vmlinux.a --no-whole-archive \
+ --start-group $(KBUILD_VMLINUX_LIBS) --end-group \
+ $(cmd_objtool)
+
+define rule_ld_vmlinux.o
+ $(call cmd_and_savecmd,ld_vmlinux.o)
+ $(call cmd,gen_objtooldep)
+endef
+
+vmlinux.o: $(initcalls-lds) vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
+ $(call if_changed_rule,ld_vmlinux.o)
+
+targets += vmlinux.o
+
+# module.builtin.modinfo
+# ---------------------------------------------------------------------------
+
+OBJCOPYFLAGS_modules.builtin.modinfo := -j .modinfo -O binary
+
+targets += modules.builtin.modinfo
+modules.builtin.modinfo: vmlinux.o FORCE
+ $(call if_changed,objcopy)
+
+# module.builtin
+# ---------------------------------------------------------------------------
+
+# The second line aids cases where multiple modules share the same object.
+
+quiet_cmd_modules_builtin = GEN $@
+ cmd_modules_builtin = \
+ tr '\0' '\n' < $< | \
+ sed -n 's/^[[:alnum:]:_]*\.file=//p' | \
+ tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$$/.ko/' > $@
+
+targets += modules.builtin
+modules.builtin: modules.builtin.modinfo FORCE
+ $(call if_changed,modules_builtin)
+
+# Add FORCE to the prequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+PHONY += FORCE
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+existing-targets := $(wildcard $(sort $(targets)))
+
+-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
+
+.PHONY: $(PHONY)
diff --git a/scripts/adjust_autoksyms.sh b/scripts/adjust_autoksyms.sh
deleted file mode 100755
index d8f6f9c63043..000000000000
--- a/scripts/adjust_autoksyms.sh
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0-only
-
-# Script to update include/generated/autoksyms.h and dependency files
-#
-# Copyright: (C) 2016 Linaro Limited
-# Created by: Nicolas Pitre, January 2016
-#
-
-# Update the include/generated/autoksyms.h file.
-#
-# For each symbol being added or removed, the corresponding dependency
-# file's timestamp is updated to force a rebuild of the affected source
-# file. All arguments passed to this script are assumed to be a command
-# to be exec'd to trigger a rebuild of those files.
-
-set -e
-
-cur_ksyms_file="include/generated/autoksyms.h"
-new_ksyms_file="include/generated/autoksyms.h.tmpnew"
-
-info() {
- if [ "$quiet" != "silent_" ]; then
- printf " %-7s %s\n" "$1" "$2"
- fi
-}
-
-info "CHK" "$cur_ksyms_file"
-
-# Use "make V=1" to debug this script.
-case "$KBUILD_VERBOSE" in
-*1*)
- set -x
- ;;
-esac
-
-# Generate a new symbol list file
-$CONFIG_SHELL $srctree/scripts/gen_autoksyms.sh "$new_ksyms_file"
-
-# Extract changes between old and new list and touch corresponding
-# dependency files.
-changed=$(
-count=0
-sort "$cur_ksyms_file" "$new_ksyms_file" | uniq -u |
-sed -n 's/^#define __KSYM_\(.*\) 1/\1/p' | tr "A-Z_" "a-z/" |
-while read sympath; do
- if [ -z "$sympath" ]; then continue; fi
- depfile="include/ksym/${sympath}.h"
- mkdir -p "$(dirname "$depfile")"
- touch "$depfile"
- # Filesystems with coarse time precision may create timestamps
- # equal to the one from a file that was very recently built and that
- # needs to be rebuild. Let's guard against that by making sure our
- # dep files are always newer than the first file we created here.
- while [ ! "$depfile" -nt "$new_ksyms_file" ]; do
- touch "$depfile"
- done
- echo $((count += 1))
-done | tail -1 )
-changed=${changed:-0}
-
-if [ $changed -gt 0 ]; then
- # Replace the old list with tne new one
- old=$(grep -c "^#define __KSYM_" "$cur_ksyms_file" || true)
- new=$(grep -c "^#define __KSYM_" "$new_ksyms_file" || true)
- info "KSYMS" "symbols: before=$old, after=$new, changed=$changed"
- info "UPD" "$cur_ksyms_file"
- mv -f "$new_ksyms_file" "$cur_ksyms_file"
- # Then trigger a rebuild of affected source files
- exec $@
-else
- rm -f "$new_ksyms_file"
-fi
diff --git a/scripts/as-version.sh b/scripts/as-version.sh
new file mode 100755
index 000000000000..af717476152d
--- /dev/null
+++ b/scripts/as-version.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Print the assembler name and its version in a 5 or 6-digit form.
+# Also, perform the minimum version check.
+# (If it is the integrated assembler, return 0 as the version, and
+# skip the version check.)
+
+set -e
+
+# Convert the version string x.y.z to a canonical 5 or 6-digit form.
+get_canonical_version()
+{
+ IFS=.
+ set -- $1
+
+ # If the 2nd or 3rd field is missing, fill it with a zero.
+ #
+ # The 4th field, if present, is ignored.
+ # This occurs in development snapshots as in 2.35.1.20201116
+ echo $((10000 * $1 + 100 * ${2:-0} + ${3:-0}))
+}
+
+# Clang fails to handle -Wa,--version unless -fno-integrated-as is given.
+# We check -fintegrated-as, expecting it is explicitly passed in for the
+# integrated assembler case.
+check_integrated_as()
+{
+ while [ $# -gt 0 ]; do
+ if [ "$1" = -fintegrated-as ]; then
+ # For the integrated assembler, we do not check the
+ # version here. It is the same as the clang version, and
+ # it has been already checked by scripts/cc-version.sh.
+ echo LLVM 0
+ exit 0
+ fi
+ shift
+ done
+}
+
+check_integrated_as "$@"
+
+orig_args="$@"
+
+# Get the first line of the --version output.
+IFS='
+'
+set -- $(LC_ALL=C "$@" -Wa,--version -c -x assembler-with-cpp /dev/null -o /dev/null 2>/dev/null)
+
+# Split the line on spaces.
+IFS=' '
+set -- $1
+
+min_tool_version=$(dirname $0)/min-tool-version.sh
+
+if [ "$1" = GNU -a "$2" = assembler ]; then
+ shift $(($# - 1))
+ version=$1
+ min_version=$($min_tool_version binutils)
+ name=GNU
+else
+ echo "$orig_args: unknown assembler invoked" >&2
+ exit 1
+fi
+
+# Some distributions append a package release number, as in 2.34-4.fc32
+# Trim the hyphen and any characters that follow.
+version=${version%-*}
+
+cversion=$(get_canonical_version $version)
+min_cversion=$(get_canonical_version $min_version)
+
+if [ "$cversion" -lt "$min_cversion" ]; then
+ echo >&2 "***"
+ echo >&2 "*** Assembler is too old."
+ echo >&2 "*** Your $name assembler version: $version"
+ echo >&2 "*** Minimum $name assembler version: $min_version"
+ echo >&2 "***"
+ exit 1
+fi
+
+echo $name $cversion
diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c
index adabd4145264..4c3f645065a4 100644
--- a/scripts/asn1_compiler.c
+++ b/scripts/asn1_compiler.c
@@ -567,8 +567,8 @@ int main(int argc, char **argv)
int fd;
kbuild_verbose = getenv("KBUILD_VERBOSE");
- if (kbuild_verbose)
- verbose_opt = atoi(kbuild_verbose);
+ if (kbuild_verbose && strchr(kbuild_verbose, '1'))
+ verbose_opt = true;
while (argc > 4) {
if (strcmp(argv[1], "-v") == 0)
@@ -625,7 +625,7 @@ int main(int argc, char **argv)
p = strrchr(argv[1], '/');
p = p ? p + 1 : argv[1];
grammar_name = strdup(p);
- if (!p) {
+ if (!grammar_name) {
perror(NULL);
exit(1);
}
@@ -832,7 +832,7 @@ static void parse(void)
static struct element *element_list;
-static struct element *alloc_elem(struct token *type)
+static struct element *alloc_elem(void)
{
struct element *e = calloc(1, sizeof(*e));
if (!e) {
@@ -860,7 +860,7 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
char *p;
int labelled = 0, implicit = 0;
- top = element = alloc_elem(cursor);
+ top = element = alloc_elem();
element->class = ASN1_UNIV;
element->method = ASN1_PRIM;
element->tag = token_to_tag[cursor->token_type];
@@ -939,7 +939,7 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
if (!implicit)
element->method |= ASN1_CONS;
element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
- element->children = alloc_elem(cursor);
+ element->children = alloc_elem();
element = element->children;
element->class = ASN1_UNIV;
element->method = ASN1_PRIM;
diff --git a/scripts/atomic/atomic-tbl.sh b/scripts/atomic/atomic-tbl.sh
index 81d5c32039dd..608ff39ebd8c 100755
--- a/scripts/atomic/atomic-tbl.sh
+++ b/scripts/atomic/atomic-tbl.sh
@@ -36,9 +36,16 @@ meta_has_relaxed()
meta_in "$1" "BFIR"
}
-#find_fallback_template(pfx, name, sfx, order)
-find_fallback_template()
+#meta_is_implicitly_relaxed(meta)
+meta_is_implicitly_relaxed()
{
+ meta_in "$1" "vls"
+}
+
+#find_template(tmpltype, pfx, name, sfx, order)
+find_template()
+{
+ local tmpltype="$1"; shift
local pfx="$1"; shift
local name="$1"; shift
local sfx="$1"; shift
@@ -52,8 +59,8 @@ find_fallback_template()
#
# Start at the most specific, and fall back to the most general. Once
# we find a specific fallback, don't bother looking for more.
- for base in "${pfx}${name}${sfx}${order}" "${name}"; do
- file="${ATOMICDIR}/fallbacks/${base}"
+ for base in "${pfx}${name}${sfx}${order}" "${pfx}${name}${sfx}" "${name}"; do
+ file="${ATOMICDIR}/${tmpltype}/${base}"
if [ -f "${file}" ]; then
printf "${file}"
@@ -62,6 +69,18 @@ find_fallback_template()
done
}
+#find_fallback_template(pfx, name, sfx, order)
+find_fallback_template()
+{
+ find_template "fallbacks" "$@"
+}
+
+#find_kerneldoc_template(pfx, name, sfx, order)
+find_kerneldoc_template()
+{
+ find_template "kerneldoc" "$@"
+}
+
#gen_ret_type(meta, int)
gen_ret_type() {
local meta="$1"; shift
@@ -142,6 +161,91 @@ gen_args()
done
}
+#gen_desc_return(meta)
+gen_desc_return()
+{
+ local meta="$1"; shift
+
+ case "${meta}" in
+ [v])
+ printf "Return: Nothing."
+ ;;
+ [Ff])
+ printf "Return: The original value of @v."
+ ;;
+ [R])
+ printf "Return: The updated value of @v."
+ ;;
+ [l])
+ printf "Return: The value of @v."
+ ;;
+ esac
+}
+
+#gen_template_kerneldoc(template, class, meta, pfx, name, sfx, order, atomic, int, args...)
+gen_template_kerneldoc()
+{
+ local template="$1"; shift
+ local class="$1"; shift
+ local meta="$1"; shift
+ local pfx="$1"; shift
+ local name="$1"; shift
+ local sfx="$1"; shift
+ local order="$1"; shift
+ local atomic="$1"; shift
+ local int="$1"; shift
+
+ local atomicname="${atomic}_${pfx}${name}${sfx}${order}"
+
+ local ret="$(gen_ret_type "${meta}" "${int}")"
+ local retstmt="$(gen_ret_stmt "${meta}")"
+ local params="$(gen_params "${int}" "${atomic}" "$@")"
+ local args="$(gen_args "$@")"
+ local desc_order=""
+ local desc_instrumentation=""
+ local desc_return=""
+
+ if [ ! -z "${order}" ]; then
+ desc_order="${order##_}"
+ elif meta_is_implicitly_relaxed "${meta}"; then
+ desc_order="relaxed"
+ else
+ desc_order="full"
+ fi
+
+ if [ -z "${class}" ]; then
+ desc_noinstr="Unsafe to use in noinstr code; use raw_${atomicname}() there."
+ else
+ desc_noinstr="Safe to use in noinstr code; prefer ${atomicname}() elsewhere."
+ fi
+
+ desc_return="$(gen_desc_return "${meta}")"
+
+ . ${template}
+}
+
+#gen_kerneldoc(class, meta, pfx, name, sfx, order, atomic, int, args...)
+gen_kerneldoc()
+{
+ local class="$1"; shift
+ local meta="$1"; shift
+ local pfx="$1"; shift
+ local name="$1"; shift
+ local sfx="$1"; shift
+ local order="$1"; shift
+
+ local atomicname="${atomic}_${pfx}${name}${sfx}${order}"
+
+ local tmpl="$(find_kerneldoc_template "${pfx}" "${name}" "${sfx}" "${order}")"
+ if [ -z "${tmpl}" ]; then
+ printf "/*\n"
+ printf " * No kerneldoc available for ${class}${atomicname}\n"
+ printf " */\n"
+ else
+ gen_template_kerneldoc "${tmpl}" "${class}" "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "$@"
+ fi
+}
+
#gen_proto_order_variants(meta, pfx, name, sfx, ...)
gen_proto_order_variants()
{
diff --git a/scripts/atomic/atomics.tbl b/scripts/atomic/atomics.tbl
index fbee2f6190d9..903946cbf1b3 100755..100644
--- a/scripts/atomic/atomics.tbl
+++ b/scripts/atomic/atomics.tbl
@@ -27,13 +27,13 @@ and vF i v
andnot vF i v
or vF i v
xor vF i v
-xchg I v i
+xchg I v i:new
cmpxchg I v i:old i:new
try_cmpxchg B v p:old i:new
sub_and_test b i v
dec_and_test b v
inc_and_test b v
-add_negative b i v
+add_negative B i v
add_unless fb v i:a i:u
inc_not_zero b v
inc_unless_negative b v
diff --git a/scripts/atomic/check-atomics.sh b/scripts/atomic/check-atomics.sh
deleted file mode 100755
index 82748d42ecc5..000000000000
--- a/scripts/atomic/check-atomics.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-#
-# Check if atomic headers are up-to-date
-
-ATOMICDIR=$(dirname $0)
-ATOMICTBL=${ATOMICDIR}/atomics.tbl
-LINUXDIR=${ATOMICDIR}/../..
-
-echo '' | sha1sum - > /dev/null 2>&1
-if [ $? -ne 0 ]; then
- printf "sha1sum not available, skipping atomic header checks.\n"
- exit 0
-fi
-
-cat <<EOF |
-asm-generic/atomic-instrumented.h
-asm-generic/atomic-long.h
-linux/atomic-arch-fallback.h
-linux/atomic-fallback.h
-EOF
-while read header; do
- OLDSUM="$(tail -n 1 ${LINUXDIR}/include/${header})"
- OLDSUM="${OLDSUM#// }"
-
- NEWSUM="$(sed '$d' ${LINUXDIR}/include/${header} | sha1sum)"
- NEWSUM="${NEWSUM%% *}"
-
- if [ "${OLDSUM}" != "${NEWSUM}" ]; then
- printf "warning: generated include/${header} has been modified.\n"
- fi
-done
-
-exit 0
diff --git a/scripts/atomic/fallbacks/acquire b/scripts/atomic/fallbacks/acquire
index 59c00529dc7c..4da0cab3604e 100755
--- a/scripts/atomic/fallbacks/acquire
+++ b/scripts/atomic/fallbacks/acquire
@@ -1,9 +1,5 @@
cat <<EOF
-static __always_inline ${ret}
-${arch}${atomic}_${pfx}${name}${sfx}_acquire(${params})
-{
- ${ret} ret = ${arch}${atomic}_${pfx}${name}${sfx}_relaxed(${args});
+ ${ret} ret = arch_${atomic}_${pfx}${name}${sfx}_relaxed(${args});
__atomic_acquire_fence();
return ret;
-}
EOF
diff --git a/scripts/atomic/fallbacks/add_negative b/scripts/atomic/fallbacks/add_negative
index a66635bceefb..1d3d4ab3a9d2 100755
--- a/scripts/atomic/fallbacks/add_negative
+++ b/scripts/atomic/fallbacks/add_negative
@@ -1,16 +1,3 @@
cat <<EOF
-/**
- * ${arch}${atomic}_add_negative - add and test if negative
- * @i: integer value to add
- * @v: pointer of type ${atomic}_t
- *
- * Atomically adds @i to @v and returns true
- * if the result is negative, or false when
- * result is greater than or equal to zero.
- */
-static __always_inline bool
-${arch}${atomic}_add_negative(${int} i, ${atomic}_t *v)
-{
- return ${arch}${atomic}_add_return(i, v) < 0;
-}
+ return raw_${atomic}_add_return${order}(i, v) < 0;
EOF
diff --git a/scripts/atomic/fallbacks/add_unless b/scripts/atomic/fallbacks/add_unless
index 2ff598a3f9ec..95ecb2b7405b 100755
--- a/scripts/atomic/fallbacks/add_unless
+++ b/scripts/atomic/fallbacks/add_unless
@@ -1,16 +1,3 @@
cat << EOF
-/**
- * ${arch}${atomic}_add_unless - add unless the number is already a given value
- * @v: pointer of type ${atomic}_t
- * @a: the amount to add to v...
- * @u: ...unless v is equal to u.
- *
- * Atomically adds @a to @v, if @v was not already @u.
- * Returns true if the addition was done.
- */
-static __always_inline bool
-${arch}${atomic}_add_unless(${atomic}_t *v, ${int} a, ${int} u)
-{
- return ${arch}${atomic}_fetch_add_unless(v, a, u) != u;
-}
+ return raw_${atomic}_fetch_add_unless(v, a, u) != u;
EOF
diff --git a/scripts/atomic/fallbacks/andnot b/scripts/atomic/fallbacks/andnot
index 3f18663dcefb..66760457e67a 100755
--- a/scripts/atomic/fallbacks/andnot
+++ b/scripts/atomic/fallbacks/andnot
@@ -1,7 +1,3 @@
cat <<EOF
-static __always_inline ${ret}
-${arch}${atomic}_${pfx}andnot${sfx}${order}(${int} i, ${atomic}_t *v)
-{
- ${retstmt}${arch}${atomic}_${pfx}and${sfx}${order}(~i, v);
-}
+ ${retstmt}raw_${atomic}_${pfx}and${sfx}${order}(~i, v);
EOF
diff --git a/scripts/atomic/fallbacks/cmpxchg b/scripts/atomic/fallbacks/cmpxchg
new file mode 100644
index 000000000000..1c8507f62e04
--- /dev/null
+++ b/scripts/atomic/fallbacks/cmpxchg
@@ -0,0 +1,3 @@
+cat <<EOF
+ return raw_cmpxchg${order}(&v->counter, old, new);
+EOF
diff --git a/scripts/atomic/fallbacks/dec b/scripts/atomic/fallbacks/dec
index e2e01f0574bb..60d286d40300 100755
--- a/scripts/atomic/fallbacks/dec
+++ b/scripts/atomic/fallbacks/dec
@@ -1,7 +1,3 @@
cat <<EOF
-static __always_inline ${ret}
-${arch}${atomic}_${pfx}dec${sfx}${order}(${atomic}_t *v)
-{
- ${retstmt}${arch}${atomic}_${pfx}sub${sfx}${order}(1, v);
-}
+ ${retstmt}raw_${atomic}_${pfx}sub${sfx}${order}(1, v);
EOF
diff --git a/scripts/atomic/fallbacks/dec_and_test b/scripts/atomic/fallbacks/dec_and_test
index e8a5e492eb5f..3a0278e0ddd7 100755
--- a/scripts/atomic/fallbacks/dec_and_test
+++ b/scripts/atomic/fallbacks/dec_and_test
@@ -1,15 +1,3 @@
cat <<EOF
-/**
- * ${arch}${atomic}_dec_and_test - decrement and test
- * @v: pointer of type ${atomic}_t
- *
- * Atomically decrements @v by 1 and
- * returns true if the result is 0, or false for all other
- * cases.
- */
-static __always_inline bool
-${arch}${atomic}_dec_and_test(${atomic}_t *v)
-{
- return ${arch}${atomic}_dec_return(v) == 0;
-}
+ return raw_${atomic}_dec_return(v) == 0;
EOF
diff --git a/scripts/atomic/fallbacks/dec_if_positive b/scripts/atomic/fallbacks/dec_if_positive
index 527adec89c37..f65c11b4b85b 100755
--- a/scripts/atomic/fallbacks/dec_if_positive
+++ b/scripts/atomic/fallbacks/dec_if_positive
@@ -1,15 +1,11 @@
cat <<EOF
-static __always_inline ${ret}
-${arch}${atomic}_dec_if_positive(${atomic}_t *v)
-{
- ${int} dec, c = ${arch}${atomic}_read(v);
+ ${int} dec, c = raw_${atomic}_read(v);
do {
dec = c - 1;
if (unlikely(dec < 0))
break;
- } while (!${arch}${atomic}_try_cmpxchg(v, &c, dec));
+ } while (!raw_${atomic}_try_cmpxchg(v, &c, dec));
return dec;
-}
EOF
diff --git a/scripts/atomic/fallbacks/dec_unless_positive b/scripts/atomic/fallbacks/dec_unless_positive
index dcab6848ca1e..d025361d7b85 100755
--- a/scripts/atomic/fallbacks/dec_unless_positive
+++ b/scripts/atomic/fallbacks/dec_unless_positive
@@ -1,14 +1,10 @@
cat <<EOF
-static __always_inline bool
-${arch}${atomic}_dec_unless_positive(${atomic}_t *v)
-{
- ${int} c = ${arch}${atomic}_read(v);
+ ${int} c = raw_${atomic}_read(v);
do {
if (unlikely(c > 0))
return false;
- } while (!${arch}${atomic}_try_cmpxchg(v, &c, c - 1));
+ } while (!raw_${atomic}_try_cmpxchg(v, &c, c - 1));
return true;
-}
EOF
diff --git a/scripts/atomic/fallbacks/fence b/scripts/atomic/fallbacks/fence
index 3764fc8ce945..40d5b397658f 100755
--- a/scripts/atomic/fallbacks/fence
+++ b/scripts/atomic/fallbacks/fence
@@ -1,11 +1,7 @@
cat <<EOF
-static __always_inline ${ret}
-${arch}${atomic}_${pfx}${name}${sfx}(${params})
-{
${ret} ret;
__atomic_pre_full_fence();
- ret = ${arch}${atomic}_${pfx}${name}${sfx}_relaxed(${args});
+ ret = arch_${atomic}_${pfx}${name}${sfx}_relaxed(${args});
__atomic_post_full_fence();
return ret;
-}
EOF
diff --git a/scripts/atomic/fallbacks/fetch_add_unless b/scripts/atomic/fallbacks/fetch_add_unless
index 0e0b9aef1515..8db7e9e17fac 100755
--- a/scripts/atomic/fallbacks/fetch_add_unless
+++ b/scripts/atomic/fallbacks/fetch_add_unless
@@ -1,23 +1,10 @@
cat << EOF
-/**
- * ${arch}${atomic}_fetch_add_unless - add unless the number is already a given value
- * @v: pointer of type ${atomic}_t
- * @a: the amount to add to v...
- * @u: ...unless v is equal to u.
- *
- * Atomically adds @a to @v, so long as @v was not already @u.
- * Returns original value of @v
- */
-static __always_inline ${int}
-${arch}${atomic}_fetch_add_unless(${atomic}_t *v, ${int} a, ${int} u)
-{
- ${int} c = ${arch}${atomic}_read(v);
+ ${int} c = raw_${atomic}_read(v);
do {
if (unlikely(c == u))
break;
- } while (!${arch}${atomic}_try_cmpxchg(v, &c, c + a));
+ } while (!raw_${atomic}_try_cmpxchg(v, &c, c + a));
return c;
-}
EOF
diff --git a/scripts/atomic/fallbacks/inc b/scripts/atomic/fallbacks/inc
index 15ec62946e8c..56c770f5919c 100755
--- a/scripts/atomic/fallbacks/inc
+++ b/scripts/atomic/fallbacks/inc
@@ -1,7 +1,3 @@
cat <<EOF
-static __always_inline ${ret}
-${arch}${atomic}_${pfx}inc${sfx}${order}(${atomic}_t *v)
-{
- ${retstmt}${arch}${atomic}_${pfx}add${sfx}${order}(1, v);
-}
+ ${retstmt}raw_${atomic}_${pfx}add${sfx}${order}(1, v);
EOF
diff --git a/scripts/atomic/fallbacks/inc_and_test b/scripts/atomic/fallbacks/inc_and_test
index cecc8322a21f..7d16a10f2257 100755
--- a/scripts/atomic/fallbacks/inc_and_test
+++ b/scripts/atomic/fallbacks/inc_and_test
@@ -1,15 +1,3 @@
cat <<EOF
-/**
- * ${arch}${atomic}_inc_and_test - increment and test
- * @v: pointer of type ${atomic}_t
- *
- * Atomically increments @v by 1
- * and returns true if the result is zero, or false for all
- * other cases.
- */
-static __always_inline bool
-${arch}${atomic}_inc_and_test(${atomic}_t *v)
-{
- return ${arch}${atomic}_inc_return(v) == 0;
-}
+ return raw_${atomic}_inc_return(v) == 0;
EOF
diff --git a/scripts/atomic/fallbacks/inc_not_zero b/scripts/atomic/fallbacks/inc_not_zero
index 50f2d4d48279..1fcef1e55bc9 100755
--- a/scripts/atomic/fallbacks/inc_not_zero
+++ b/scripts/atomic/fallbacks/inc_not_zero
@@ -1,14 +1,3 @@
cat <<EOF
-/**
- * ${arch}${atomic}_inc_not_zero - increment unless the number is zero
- * @v: pointer of type ${atomic}_t
- *
- * Atomically increments @v by 1, if @v is non-zero.
- * Returns true if the increment was done.
- */
-static __always_inline bool
-${arch}${atomic}_inc_not_zero(${atomic}_t *v)
-{
- return ${arch}${atomic}_add_unless(v, 1, 0);
-}
+ return raw_${atomic}_add_unless(v, 1, 0);
EOF
diff --git a/scripts/atomic/fallbacks/inc_unless_negative b/scripts/atomic/fallbacks/inc_unless_negative
index 87629e0d4a80..7b4b09868842 100755
--- a/scripts/atomic/fallbacks/inc_unless_negative
+++ b/scripts/atomic/fallbacks/inc_unless_negative
@@ -1,14 +1,10 @@
cat <<EOF
-static __always_inline bool
-${arch}${atomic}_inc_unless_negative(${atomic}_t *v)
-{
- ${int} c = ${arch}${atomic}_read(v);
+ ${int} c = raw_${atomic}_read(v);
do {
if (unlikely(c < 0))
return false;
- } while (!${arch}${atomic}_try_cmpxchg(v, &c, c + 1));
+ } while (!raw_${atomic}_try_cmpxchg(v, &c, c + 1));
return true;
-}
EOF
diff --git a/scripts/atomic/fallbacks/read_acquire b/scripts/atomic/fallbacks/read_acquire
index 341a88dccaa7..e319862d2f1a 100755
--- a/scripts/atomic/fallbacks/read_acquire
+++ b/scripts/atomic/fallbacks/read_acquire
@@ -1,7 +1,12 @@
cat <<EOF
-static __always_inline ${ret}
-${arch}${atomic}_read_acquire(const ${atomic}_t *v)
-{
- return smp_load_acquire(&(v)->counter);
-}
+ ${int} ret;
+
+ if (__native_word(${atomic}_t)) {
+ ret = smp_load_acquire(&(v)->counter);
+ } else {
+ ret = raw_${atomic}_read(v);
+ __atomic_acquire_fence();
+ }
+
+ return ret;
EOF
diff --git a/scripts/atomic/fallbacks/release b/scripts/atomic/fallbacks/release
index f8906d537c0f..1e6daf57b4ba 100755
--- a/scripts/atomic/fallbacks/release
+++ b/scripts/atomic/fallbacks/release
@@ -1,8 +1,4 @@
cat <<EOF
-static __always_inline ${ret}
-${arch}${atomic}_${pfx}${name}${sfx}_release(${params})
-{
__atomic_release_fence();
- ${retstmt}${arch}${atomic}_${pfx}${name}${sfx}_relaxed(${args});
-}
+ ${retstmt}arch_${atomic}_${pfx}${name}${sfx}_relaxed(${args});
EOF
diff --git a/scripts/atomic/fallbacks/set_release b/scripts/atomic/fallbacks/set_release
index 76068272d5f5..16a374ae6bb1 100755
--- a/scripts/atomic/fallbacks/set_release
+++ b/scripts/atomic/fallbacks/set_release
@@ -1,7 +1,8 @@
cat <<EOF
-static __always_inline void
-${arch}${atomic}_set_release(${atomic}_t *v, ${int} i)
-{
- smp_store_release(&(v)->counter, i);
-}
+ if (__native_word(${atomic}_t)) {
+ smp_store_release(&(v)->counter, i);
+ } else {
+ __atomic_release_fence();
+ raw_${atomic}_set(v, i);
+ }
EOF
diff --git a/scripts/atomic/fallbacks/sub_and_test b/scripts/atomic/fallbacks/sub_and_test
index c580f4c2136e..d1f746fe0ca4 100755
--- a/scripts/atomic/fallbacks/sub_and_test
+++ b/scripts/atomic/fallbacks/sub_and_test
@@ -1,16 +1,3 @@
cat <<EOF
-/**
- * ${arch}${atomic}_sub_and_test - subtract value from variable and test result
- * @i: integer value to subtract
- * @v: pointer of type ${atomic}_t
- *
- * Atomically subtracts @i from @v and returns
- * true if the result is zero, or false for all
- * other cases.
- */
-static __always_inline bool
-${arch}${atomic}_sub_and_test(${int} i, ${atomic}_t *v)
-{
- return ${arch}${atomic}_sub_return(i, v) == 0;
-}
+ return raw_${atomic}_sub_return(i, v) == 0;
EOF
diff --git a/scripts/atomic/fallbacks/try_cmpxchg b/scripts/atomic/fallbacks/try_cmpxchg
index 06db0f738e45..d4da82092baf 100755
--- a/scripts/atomic/fallbacks/try_cmpxchg
+++ b/scripts/atomic/fallbacks/try_cmpxchg
@@ -1,11 +1,7 @@
cat <<EOF
-static __always_inline bool
-${arch}${atomic}_try_cmpxchg${order}(${atomic}_t *v, ${int} *old, ${int} new)
-{
${int} r, o = *old;
- r = ${arch}${atomic}_cmpxchg${order}(v, o, new);
+ r = raw_${atomic}_cmpxchg${order}(v, o, new);
if (unlikely(r != o))
*old = r;
return likely(r == o);
-}
EOF
diff --git a/scripts/atomic/fallbacks/xchg b/scripts/atomic/fallbacks/xchg
new file mode 100644
index 000000000000..e4def1e0d092
--- /dev/null
+++ b/scripts/atomic/fallbacks/xchg
@@ -0,0 +1,3 @@
+cat <<EOF
+ return raw_xchg${order}(&v->counter, new);
+EOF
diff --git a/scripts/atomic/gen-atomic-fallback.sh b/scripts/atomic/gen-atomic-fallback.sh
index 317a6cec76e1..c0c8a85d7c81 100755
--- a/scripts/atomic/gen-atomic-fallback.sh
+++ b/scripts/atomic/gen-atomic-fallback.sh
@@ -2,11 +2,10 @@
# SPDX-License-Identifier: GPL-2.0
ATOMICDIR=$(dirname $0)
-ARCH=$2
. ${ATOMICDIR}/atomic-tbl.sh
-#gen_template_fallback(template, meta, pfx, name, sfx, order, arch, atomic, int, args...)
+#gen_template_fallback(template, meta, pfx, name, sfx, order, atomic, int, args...)
gen_template_fallback()
{
local template="$1"; shift
@@ -15,27 +14,19 @@ gen_template_fallback()
local name="$1"; shift
local sfx="$1"; shift
local order="$1"; shift
- local arch="$1"; shift
local atomic="$1"; shift
local int="$1"; shift
- local atomicname="${arch}${atomic}_${pfx}${name}${sfx}${order}"
-
local ret="$(gen_ret_type "${meta}" "${int}")"
local retstmt="$(gen_ret_stmt "${meta}")"
local params="$(gen_params "${int}" "${atomic}" "$@")"
local args="$(gen_args "$@")"
- if [ ! -z "${template}" ]; then
- printf "#ifndef ${atomicname}\n"
- . ${template}
- printf "#define ${atomicname} ${atomicname}\n"
- printf "#endif\n\n"
- fi
+ . ${template}
}
-#gen_proto_fallback(meta, pfx, name, sfx, order, arch, atomic, int, args...)
-gen_proto_fallback()
+#gen_order_fallback(meta, pfx, name, sfx, order, atomic, int, args...)
+gen_order_fallback()
{
local meta="$1"; shift
local pfx="$1"; shift
@@ -43,105 +34,124 @@ gen_proto_fallback()
local sfx="$1"; shift
local order="$1"; shift
- local tmpl="$(find_fallback_template "${pfx}" "${name}" "${sfx}" "${order}")"
+ local tmpl_order=${order#_}
+ local tmpl="${ATOMICDIR}/fallbacks/${tmpl_order:-fence}"
gen_template_fallback "${tmpl}" "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "$@"
}
-#gen_basic_fallbacks(basename)
-gen_basic_fallbacks()
-{
- local basename="$1"; shift
-cat << EOF
-#define ${basename}_acquire ${basename}
-#define ${basename}_release ${basename}
-#define ${basename}_relaxed ${basename}
-EOF
-}
-
-gen_proto_order_variant()
+#gen_proto_fallback(meta, pfx, name, sfx, order, atomic, int, args...)
+gen_proto_fallback()
{
local meta="$1"; shift
local pfx="$1"; shift
local name="$1"; shift
local sfx="$1"; shift
local order="$1"; shift
- local arch="$1"
- local atomic="$2"
-
- local basename="${arch}${atomic}_${pfx}${name}${sfx}"
- printf "#define arch_${basename}${order} ${basename}${order}\n"
+ local tmpl="$(find_fallback_template "${pfx}" "${name}" "${sfx}" "${order}")"
+ gen_template_fallback "${tmpl}" "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "$@"
}
-#gen_proto_order_variants(meta, pfx, name, sfx, arch, atomic, int, args...)
-gen_proto_order_variants()
+#gen_proto_order_variant(meta, pfx, name, sfx, order, atomic, int, args...)
+gen_proto_order_variant()
{
local meta="$1"; shift
local pfx="$1"; shift
local name="$1"; shift
local sfx="$1"; shift
- local arch="$1"
- local atomic="$2"
+ local order="$1"; shift
+ local atomic="$1"; shift
+ local int="$1"; shift
- local basename="${arch}${atomic}_${pfx}${name}${sfx}"
+ local atomicname="${atomic}_${pfx}${name}${sfx}${order}"
+ local basename="${atomic}_${pfx}${name}${sfx}"
local template="$(find_fallback_template "${pfx}" "${name}" "${sfx}" "${order}")"
- if [ -z "$arch" ]; then
- gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "" "$@"
-
- if meta_has_acquire "${meta}"; then
- gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "_acquire" "$@"
- fi
- if meta_has_release "${meta}"; then
- gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "_release" "$@"
- fi
- if meta_has_relaxed "${meta}"; then
- gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "_relaxed" "$@"
- fi
+ local ret="$(gen_ret_type "${meta}" "${int}")"
+ local retstmt="$(gen_ret_stmt "${meta}")"
+ local params="$(gen_params "${int}" "${atomic}" "$@")"
+ local args="$(gen_args "$@")"
- echo ""
+ gen_kerneldoc "raw_" "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "${atomic}" "${int}" "$@"
+
+ printf "static __always_inline ${ret}\n"
+ printf "raw_${atomicname}(${params})\n"
+ printf "{\n"
+
+ # Where there is no possible fallback, this order variant is mandatory
+ # and must be provided by arch code. Add a comment to the header to
+ # make this obvious.
+ #
+ # Ideally we'd error on a missing definition, but arch code might
+ # define this order variant as a C function without a preprocessor
+ # symbol.
+ if [ -z ${template} ] && [ -z "${order}" ] && ! meta_has_relaxed "${meta}"; then
+ printf "\t${retstmt}arch_${atomicname}(${args});\n"
+ printf "}\n\n"
+ return
fi
- # If we don't have relaxed atomics, then we don't bother with ordering fallbacks
- # read_acquire and set_release need to be templated, though
- if ! meta_has_relaxed "${meta}"; then
- gen_proto_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "" "$@"
-
- if meta_has_acquire "${meta}"; then
- gen_proto_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "_acquire" "$@"
- fi
-
- if meta_has_release "${meta}"; then
- gen_proto_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "_release" "$@"
- fi
+ printf "#if defined(arch_${atomicname})\n"
+ printf "\t${retstmt}arch_${atomicname}(${args});\n"
- return
+ # Allow FULL/ACQUIRE/RELEASE ops to be defined in terms of RELAXED ops
+ if [ "${order}" != "_relaxed" ] && meta_has_relaxed "${meta}"; then
+ printf "#elif defined(arch_${basename}_relaxed)\n"
+ gen_order_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "${atomic}" "${int}" "$@"
fi
- printf "#ifndef ${basename}_relaxed\n"
+ # Allow ACQUIRE/RELEASE/RELAXED ops to be defined in terms of FULL ops
+ if [ ! -z "${order}" ]; then
+ printf "#elif defined(arch_${basename})\n"
+ printf "\t${retstmt}arch_${basename}(${args});\n"
+ fi
+ printf "#else\n"
if [ ! -z "${template}" ]; then
- printf "#ifdef ${basename}\n"
+ gen_proto_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "${atomic}" "${int}" "$@"
+ else
+ printf "#error \"Unable to define raw_${atomicname}\"\n"
fi
- gen_basic_fallbacks "${basename}"
+ printf "#endif\n"
+ printf "}\n\n"
+}
- if [ ! -z "${template}" ]; then
- printf "#endif /* ${arch}${atomic}_${pfx}${name}${sfx} */\n\n"
- gen_proto_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "" "$@"
- gen_proto_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "_acquire" "$@"
- gen_proto_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "_release" "$@"
- gen_proto_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "_relaxed" "$@"
+
+#gen_proto_order_variants(meta, pfx, name, sfx, atomic, int, args...)
+gen_proto_order_variants()
+{
+ local meta="$1"; shift
+ local pfx="$1"; shift
+ local name="$1"; shift
+ local sfx="$1"; shift
+ local atomic="$1"
+
+ gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "" "$@"
+
+ if meta_has_acquire "${meta}"; then
+ gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "_acquire" "$@"
fi
- printf "#else /* ${basename}_relaxed */\n\n"
+ if meta_has_release "${meta}"; then
+ gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "_release" "$@"
+ fi
- gen_template_fallback "${ATOMICDIR}/fallbacks/acquire" "${meta}" "${pfx}" "${name}" "${sfx}" "_acquire" "$@"
- gen_template_fallback "${ATOMICDIR}/fallbacks/release" "${meta}" "${pfx}" "${name}" "${sfx}" "_release" "$@"
- gen_template_fallback "${ATOMICDIR}/fallbacks/fence" "${meta}" "${pfx}" "${name}" "${sfx}" "" "$@"
+ if meta_has_relaxed "${meta}"; then
+ gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "_relaxed" "$@"
+ fi
+}
- printf "#endif /* ${basename}_relaxed */\n\n"
+#gen_basic_fallbacks(basename)
+gen_basic_fallbacks()
+{
+ local basename="$1"; shift
+cat << EOF
+#define raw_${basename}_acquire arch_${basename}
+#define raw_${basename}_release arch_${basename}
+#define raw_${basename}_relaxed arch_${basename}
+EOF
}
gen_order_fallbacks()
@@ -150,75 +160,128 @@ gen_order_fallbacks()
cat <<EOF
-#ifndef ${xchg}_acquire
-#define ${xchg}_acquire(...) \\
- __atomic_op_acquire(${xchg}, __VA_ARGS__)
+#define raw_${xchg}_relaxed arch_${xchg}_relaxed
+
+#ifdef arch_${xchg}_acquire
+#define raw_${xchg}_acquire arch_${xchg}_acquire
+#else
+#define raw_${xchg}_acquire(...) \\
+ __atomic_op_acquire(arch_${xchg}, __VA_ARGS__)
#endif
-#ifndef ${xchg}_release
-#define ${xchg}_release(...) \\
- __atomic_op_release(${xchg}, __VA_ARGS__)
+#ifdef arch_${xchg}_release
+#define raw_${xchg}_release arch_${xchg}_release
+#else
+#define raw_${xchg}_release(...) \\
+ __atomic_op_release(arch_${xchg}, __VA_ARGS__)
#endif
-#ifndef ${xchg}
-#define ${xchg}(...) \\
- __atomic_op_fence(${xchg}, __VA_ARGS__)
+#ifdef arch_${xchg}
+#define raw_${xchg} arch_${xchg}
+#else
+#define raw_${xchg}(...) \\
+ __atomic_op_fence(arch_${xchg}, __VA_ARGS__)
#endif
EOF
}
-gen_xchg_fallbacks()
+gen_xchg_order_fallback()
{
local xchg="$1"; shift
- printf "#ifndef ${xchg}_relaxed\n"
+ local order="$1"; shift
+ local forder="${order:-_fence}"
- gen_basic_fallbacks ${xchg}
+ printf "#if defined(arch_${xchg}${order})\n"
+ printf "#define raw_${xchg}${order} arch_${xchg}${order}\n"
- printf "#else /* ${xchg}_relaxed */\n"
+ if [ "${order}" != "_relaxed" ]; then
+ printf "#elif defined(arch_${xchg}_relaxed)\n"
+ printf "#define raw_${xchg}${order}(...) \\\\\n"
+ printf " __atomic_op${forder}(arch_${xchg}, __VA_ARGS__)\n"
+ fi
- gen_order_fallbacks ${xchg}
+ if [ ! -z "${order}" ]; then
+ printf "#elif defined(arch_${xchg})\n"
+ printf "#define raw_${xchg}${order} arch_${xchg}\n"
+ fi
- printf "#endif /* ${xchg}_relaxed */\n\n"
+ printf "#else\n"
+ printf "extern void raw_${xchg}${order}_not_implemented(void);\n"
+ printf "#define raw_${xchg}${order}(...) raw_${xchg}${order}_not_implemented()\n"
+ printf "#endif\n\n"
+}
+
+gen_xchg_fallbacks()
+{
+ local xchg="$1"; shift
+
+ for order in "" "_acquire" "_release" "_relaxed"; do
+ gen_xchg_order_fallback "${xchg}" "${order}"
+ done
}
gen_try_cmpxchg_fallback()
{
+ local cmpxchg="$1"; shift;
local order="$1"; shift;
cat <<EOF
-#ifndef ${ARCH}try_cmpxchg${order}
-#define ${ARCH}try_cmpxchg${order}(_ptr, _oldp, _new) \\
+#define raw_try_${cmpxchg}${order}(_ptr, _oldp, _new) \\
({ \\
typeof(*(_ptr)) *___op = (_oldp), ___o = *___op, ___r; \\
- ___r = ${ARCH}cmpxchg${order}((_ptr), ___o, (_new)); \\
+ ___r = raw_${cmpxchg}${order}((_ptr), ___o, (_new)); \\
if (unlikely(___r != ___o)) \\
*___op = ___r; \\
likely(___r == ___o); \\
})
-#endif /* ${ARCH}try_cmpxchg${order} */
-
EOF
}
-gen_try_cmpxchg_fallbacks()
+gen_try_cmpxchg_order_fallback()
{
- printf "#ifndef ${ARCH}try_cmpxchg_relaxed\n"
- printf "#ifdef ${ARCH}try_cmpxchg\n"
+ local cmpxchg="$1"; shift
+ local order="$1"; shift
+ local forder="${order:-_fence}"
- gen_basic_fallbacks "${ARCH}try_cmpxchg"
+ printf "#if defined(arch_try_${cmpxchg}${order})\n"
+ printf "#define raw_try_${cmpxchg}${order} arch_try_${cmpxchg}${order}\n"
- printf "#endif /* ${ARCH}try_cmpxchg */\n\n"
+ if [ "${order}" != "_relaxed" ]; then
+ printf "#elif defined(arch_try_${cmpxchg}_relaxed)\n"
+ printf "#define raw_try_${cmpxchg}${order}(...) \\\\\n"
+ printf " __atomic_op${forder}(arch_try_${cmpxchg}, __VA_ARGS__)\n"
+ fi
- for order in "" "_acquire" "_release" "_relaxed"; do
- gen_try_cmpxchg_fallback "${order}"
- done
+ if [ ! -z "${order}" ]; then
+ printf "#elif defined(arch_try_${cmpxchg})\n"
+ printf "#define raw_try_${cmpxchg}${order} arch_try_${cmpxchg}\n"
+ fi
- printf "#else /* ${ARCH}try_cmpxchg_relaxed */\n"
+ printf "#else\n"
+ gen_try_cmpxchg_fallback "${cmpxchg}" "${order}"
+ printf "#endif\n\n"
+}
- gen_order_fallbacks "${ARCH}try_cmpxchg"
+gen_try_cmpxchg_fallbacks()
+{
+ local cmpxchg="$1"; shift;
- printf "#endif /* ${ARCH}try_cmpxchg_relaxed */\n\n"
+ for order in "" "_acquire" "_release" "_relaxed"; do
+ gen_try_cmpxchg_order_fallback "${cmpxchg}" "${order}"
+ done
+}
+
+gen_cmpxchg_local_fallbacks()
+{
+ local cmpxchg="$1"; shift
+
+ printf "#define raw_${cmpxchg} arch_${cmpxchg}\n\n"
+ printf "#ifdef arch_try_${cmpxchg}\n"
+ printf "#define raw_try_${cmpxchg} arch_try_${cmpxchg}\n"
+ printf "#else\n"
+ gen_try_cmpxchg_fallback "${cmpxchg}" ""
+ printf "#endif\n\n"
}
cat << EOF
@@ -234,14 +297,24 @@ cat << EOF
EOF
-for xchg in "${ARCH}xchg" "${ARCH}cmpxchg" "${ARCH}cmpxchg64"; do
+for xchg in "xchg" "cmpxchg" "cmpxchg64" "cmpxchg128"; do
gen_xchg_fallbacks "${xchg}"
done
-gen_try_cmpxchg_fallbacks
+for cmpxchg in "cmpxchg" "cmpxchg64" "cmpxchg128"; do
+ gen_try_cmpxchg_fallbacks "${cmpxchg}"
+done
+
+for cmpxchg in "cmpxchg_local" "cmpxchg64_local" "cmpxchg128_local"; do
+ gen_cmpxchg_local_fallbacks "${cmpxchg}" ""
+done
+
+for cmpxchg in "sync_cmpxchg"; do
+ printf "#define raw_${cmpxchg} arch_${cmpxchg}\n\n"
+done
grep '^[a-z]' "$1" | while read name meta args; do
- gen_proto "${meta}" "${name}" "${ARCH}" "atomic" "int" ${args}
+ gen_proto "${meta}" "${name}" "atomic" "int" ${args}
done
cat <<EOF
@@ -252,7 +325,7 @@ cat <<EOF
EOF
grep '^[a-z]' "$1" | while read name meta args; do
- gen_proto "${meta}" "${name}" "${ARCH}" "atomic64" "s64" ${args}
+ gen_proto "${meta}" "${name}" "atomic64" "s64" ${args}
done
cat <<EOF
diff --git a/scripts/atomic/gen-atomic-instrumented.sh b/scripts/atomic/gen-atomic-instrumented.sh
index 5766ffcec7c5..8f8f8e3b20f9 100755
--- a/scripts/atomic/gen-atomic-instrumented.sh
+++ b/scripts/atomic/gen-atomic-instrumented.sh
@@ -34,6 +34,14 @@ gen_param_check()
gen_params_checks()
{
local meta="$1"; shift
+ local order="$1"; shift
+
+ if [ "${order}" = "_release" ]; then
+ printf "\tkcsan_release();\n"
+ elif [ -z "${order}" ] && ! meta_in "$meta" "slv"; then
+ # RMW with return value is fully ordered
+ printf "\tkcsan_mb();\n"
+ fi
while [ "$#" -gt 0 ]; do
gen_param_check "$meta" "$1"
@@ -41,34 +49,6 @@ gen_params_checks()
done
}
-# gen_guard(meta, atomic, pfx, name, sfx, order)
-gen_guard()
-{
- local meta="$1"; shift
- local atomic="$1"; shift
- local pfx="$1"; shift
- local name="$1"; shift
- local sfx="$1"; shift
- local order="$1"; shift
-
- local atomicname="arch_${atomic}_${pfx}${name}${sfx}${order}"
-
- local template="$(find_fallback_template "${pfx}" "${name}" "${sfx}" "${order}")"
-
- # We definitely need a preprocessor symbol for this atomic if it is an
- # ordering variant, or if there's a generic fallback.
- if [ ! -z "${order}" ] || [ ! -z "${template}" ]; then
- printf "defined(${atomicname})"
- return
- fi
-
- # If this is a base variant, but a relaxed variant *may* exist, then we
- # only have a preprocessor symbol if the relaxed variant isn't defined
- if meta_has_relaxed "${meta}"; then
- printf "!defined(${atomicname}_relaxed) || defined(${atomicname})"
- fi
-}
-
#gen_proto_order_variant(meta, pfx, name, sfx, order, atomic, int, arg...)
gen_proto_order_variant()
{
@@ -82,76 +62,72 @@ gen_proto_order_variant()
local atomicname="${atomic}_${pfx}${name}${sfx}${order}"
- local guard="$(gen_guard "${meta}" "${atomic}" "${pfx}" "${name}" "${sfx}" "${order}")"
-
local ret="$(gen_ret_type "${meta}" "${int}")"
local params="$(gen_params "${int}" "${atomic}" "$@")"
- local checks="$(gen_params_checks "${meta}" "$@")"
+ local checks="$(gen_params_checks "${meta}" "${order}" "$@")"
local args="$(gen_args "$@")"
local retstmt="$(gen_ret_stmt "${meta}")"
- [ ! -z "${guard}" ] && printf "#if ${guard}\n"
+ gen_kerneldoc "" "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "${atomic}" "${int}" "$@"
cat <<EOF
static __always_inline ${ret}
${atomicname}(${params})
{
${checks}
- ${retstmt}arch_${atomicname}(${args});
+ ${retstmt}raw_${atomicname}(${args});
}
-#define ${atomicname} ${atomicname}
EOF
- [ ! -z "${guard}" ] && printf "#endif\n"
-
printf "\n"
}
gen_xchg()
{
local xchg="$1"; shift
- local mult="$1"; shift
+ local order="$1"; shift
+
+ kcsan_barrier=""
+ if [ "${xchg%_local}" = "${xchg}" ]; then
+ case "$order" in
+ _release) kcsan_barrier="kcsan_release()" ;;
+ "") kcsan_barrier="kcsan_mb()" ;;
+ esac
+ fi
if [ "${xchg%${xchg#try_cmpxchg}}" = "try_cmpxchg" ] ; then
cat <<EOF
-#define ${xchg}(ptr, oldp, ...) \\
+#define ${xchg}${order}(ptr, oldp, ...) \\
({ \\
typeof(ptr) __ai_ptr = (ptr); \\
typeof(oldp) __ai_oldp = (oldp); \\
- instrument_atomic_write(__ai_ptr, ${mult}sizeof(*__ai_ptr)); \\
- instrument_atomic_write(__ai_oldp, ${mult}sizeof(*__ai_oldp)); \\
- arch_${xchg}(__ai_ptr, __ai_oldp, __VA_ARGS__); \\
+EOF
+[ -n "$kcsan_barrier" ] && printf "\t${kcsan_barrier}; \\\\\n"
+cat <<EOF
+ instrument_atomic_read_write(__ai_ptr, sizeof(*__ai_ptr)); \\
+ instrument_read_write(__ai_oldp, sizeof(*__ai_oldp)); \\
+ raw_${xchg}${order}(__ai_ptr, __ai_oldp, __VA_ARGS__); \\
})
EOF
else
cat <<EOF
-#define ${xchg}(ptr, ...) \\
+#define ${xchg}${order}(ptr, ...) \\
({ \\
typeof(ptr) __ai_ptr = (ptr); \\
- instrument_atomic_write(__ai_ptr, ${mult}sizeof(*__ai_ptr)); \\
- arch_${xchg}(__ai_ptr, __VA_ARGS__); \\
+EOF
+[ -n "$kcsan_barrier" ] && printf "\t${kcsan_barrier}; \\\\\n"
+cat <<EOF
+ instrument_atomic_read_write(__ai_ptr, sizeof(*__ai_ptr)); \\
+ raw_${xchg}${order}(__ai_ptr, __VA_ARGS__); \\
})
EOF
fi
}
-gen_optional_xchg()
-{
- local name="$1"; shift
- local sfx="$1"; shift
- local guard="defined(arch_${name}${sfx})"
-
- [ -z "${sfx}" ] && guard="!defined(arch_${name}_relaxed) || defined(arch_${name})"
-
- printf "#if ${guard}\n"
- gen_xchg "${name}${sfx}" ""
- printf "#endif\n\n"
-}
-
cat << EOF
// SPDX-License-Identifier: GPL-2.0
@@ -159,18 +135,13 @@ cat << EOF
// DO NOT MODIFY THIS FILE DIRECTLY
/*
- * This file provides wrappers with KASAN instrumentation for atomic operations.
- * To use this functionality an arch's atomic.h file needs to define all
- * atomic operations with arch_ prefix (e.g. arch_atomic_read()) and include
- * this file at the end. This file provides atomic_read() that forwards to
- * arch_atomic_read() for actual atomic operation.
- * Note: if an arch atomic operation is implemented by means of other atomic
- * operations (e.g. atomic_read()/atomic_cmpxchg() loop), then it needs to use
- * arch_ variants (i.e. arch_atomic_read()/arch_atomic_cmpxchg()) to avoid
- * double instrumentation.
+ * This file provoides atomic operations with explicit instrumentation (e.g.
+ * KASAN, KCSAN), which should be used unless it is necessary to avoid
+ * instrumentation. Where it is necessary to aovid instrumenation, the
+ * raw_atomic*() operations should be used.
*/
-#ifndef _ASM_GENERIC_ATOMIC_INSTRUMENTED_H
-#define _ASM_GENERIC_ATOMIC_INSTRUMENTED_H
+#ifndef _LINUX_ATOMIC_INSTRUMENTED_H
+#define _LINUX_ATOMIC_INSTRUMENTED_H
#include <linux/build_bug.h>
#include <linux/compiler.h>
@@ -186,24 +157,24 @@ grep '^[a-z]' "$1" | while read name meta args; do
gen_proto "${meta}" "${name}" "atomic64" "s64" ${args}
done
-for xchg in "xchg" "cmpxchg" "cmpxchg64" "try_cmpxchg"; do
+grep '^[a-z]' "$1" | while read name meta args; do
+ gen_proto "${meta}" "${name}" "atomic_long" "long" ${args}
+done
+
+
+for xchg in "xchg" "cmpxchg" "cmpxchg64" "cmpxchg128" "try_cmpxchg" "try_cmpxchg64" "try_cmpxchg128"; do
for order in "" "_acquire" "_release" "_relaxed"; do
- gen_optional_xchg "${xchg}" "${order}"
+ gen_xchg "${xchg}" "${order}"
+ printf "\n"
done
done
-for xchg in "cmpxchg_local" "cmpxchg64_local" "sync_cmpxchg"; do
+for xchg in "cmpxchg_local" "cmpxchg64_local" "cmpxchg128_local" "sync_cmpxchg" "try_cmpxchg_local" "try_cmpxchg64_local" "try_cmpxchg128_local"; do
gen_xchg "${xchg}" ""
printf "\n"
done
-gen_xchg "cmpxchg_double" "2 * "
-
-printf "\n\n"
-
-gen_xchg "cmpxchg_double_local" "2 * "
-
cat <<EOF
-#endif /* _ASM_GENERIC_ATOMIC_INSTRUMENTED_H */
+#endif /* _LINUX_ATOMIC_INSTRUMENTED_H */
EOF
diff --git a/scripts/atomic/gen-atomic-long.sh b/scripts/atomic/gen-atomic-long.sh
index e318d3f92e53..9826be3ba986 100755
--- a/scripts/atomic/gen-atomic-long.sh
+++ b/scripts/atomic/gen-atomic-long.sh
@@ -32,24 +32,34 @@ gen_args_cast()
done
}
-#gen_proto_order_variant(meta, pfx, name, sfx, order, atomic, int, arg...)
+#gen_proto_order_variant(meta, pfx, name, sfx, order, arg...)
gen_proto_order_variant()
{
local meta="$1"; shift
- local name="$1$2$3$4"; shift; shift; shift; shift
- local atomic="$1"; shift
- local int="$1"; shift
+ local pfx="$1"; shift
+ local name="$1"; shift
+ local sfx="$1"; shift
+ local order="$1"; shift
+
+ local atomicname="${pfx}${name}${sfx}${order}"
local ret="$(gen_ret_type "${meta}" "long")"
local params="$(gen_params "long" "atomic_long" "$@")"
- local argscast="$(gen_args_cast "${int}" "${atomic}" "$@")"
+ local argscast_32="$(gen_args_cast "int" "atomic" "$@")"
+ local argscast_64="$(gen_args_cast "s64" "atomic64" "$@")"
local retstmt="$(gen_ret_stmt "${meta}")"
+ gen_kerneldoc "raw_" "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "atomic_long" "long" "$@"
+
cat <<EOF
static __always_inline ${ret}
-atomic_long_${name}(${params})
+raw_atomic_long_${atomicname}(${params})
{
- ${retstmt}${atomic}_${name}(${argscast});
+#ifdef CONFIG_64BIT
+ ${retstmt}raw_atomic64_${atomicname}(${argscast_64});
+#else
+ ${retstmt}raw_atomic_${atomicname}(${argscast_32});
+#endif
}
EOF
@@ -61,8 +71,8 @@ cat << EOF
// Generated by $0
// DO NOT MODIFY THIS FILE DIRECTLY
-#ifndef _ASM_GENERIC_ATOMIC_LONG_H
-#define _ASM_GENERIC_ATOMIC_LONG_H
+#ifndef _LINUX_ATOMIC_LONG_H
+#define _LINUX_ATOMIC_LONG_H
#include <linux/compiler.h>
#include <asm/types.h>
@@ -79,24 +89,12 @@ typedef atomic_t atomic_long_t;
#define atomic_long_cond_read_relaxed atomic_cond_read_relaxed
#endif
-#ifdef CONFIG_64BIT
-
-EOF
-
-grep '^[a-z]' "$1" | while read name meta args; do
- gen_proto "${meta}" "${name}" "atomic64" "s64" ${args}
-done
-
-cat <<EOF
-#else /* CONFIG_64BIT */
-
EOF
grep '^[a-z]' "$1" | while read name meta args; do
- gen_proto "${meta}" "${name}" "atomic" "int" ${args}
+ gen_proto "${meta}" "${name}" ${args}
done
cat <<EOF
-#endif /* CONFIG_64BIT */
-#endif /* _ASM_GENERIC_ATOMIC_LONG_H */
+#endif /* _LINUX_ATOMIC_LONG_H */
EOF
diff --git a/scripts/atomic/gen-atomics.sh b/scripts/atomic/gen-atomics.sh
index d29e159ef489..5b98a8307693 100755
--- a/scripts/atomic/gen-atomics.sh
+++ b/scripts/atomic/gen-atomics.sh
@@ -8,10 +8,9 @@ ATOMICTBL=${ATOMICDIR}/atomics.tbl
LINUXDIR=${ATOMICDIR}/../..
cat <<EOF |
-gen-atomic-instrumented.sh asm-generic/atomic-instrumented.h
-gen-atomic-long.sh asm-generic/atomic-long.h
-gen-atomic-fallback.sh linux/atomic-arch-fallback.h arch_
-gen-atomic-fallback.sh linux/atomic-fallback.h
+gen-atomic-instrumented.sh linux/atomic/atomic-instrumented.h
+gen-atomic-long.sh linux/atomic/atomic-long.h
+gen-atomic-fallback.sh linux/atomic/atomic-arch-fallback.h
EOF
while read script header args; do
/bin/sh ${ATOMICDIR}/${script} ${ATOMICTBL} ${args} > ${LINUXDIR}/include/${header}
diff --git a/scripts/atomic/kerneldoc/add b/scripts/atomic/kerneldoc/add
new file mode 100644
index 000000000000..991f3dafceea
--- /dev/null
+++ b/scripts/atomic/kerneldoc/add
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic add with ${desc_order} ordering
+ * @i: ${int} value to add
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v + @i) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * ${desc_return}
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/add_negative b/scripts/atomic/kerneldoc/add_negative
new file mode 100644
index 000000000000..f4ca1f05d1d8
--- /dev/null
+++ b/scripts/atomic/kerneldoc/add_negative
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic add and test if negative with ${desc_order} ordering
+ * @i: ${int} value to add
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v + @i) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: @true if the resulting value of @v is negative, @false otherwise.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/add_unless b/scripts/atomic/kerneldoc/add_unless
new file mode 100644
index 000000000000..f828e5f6750c
--- /dev/null
+++ b/scripts/atomic/kerneldoc/add_unless
@@ -0,0 +1,18 @@
+if [ -z "${pfx}" ]; then
+ desc_return="Return: @true if @v was updated, @false otherwise."
+fi
+
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic add unless value with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ * @a: ${int} value to add
+ * @u: ${int} value to compare with
+ *
+ * If (@v != @u), atomically updates @v to (@v + @a) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * ${desc_return}
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/and b/scripts/atomic/kerneldoc/and
new file mode 100644
index 000000000000..a923574351fc
--- /dev/null
+++ b/scripts/atomic/kerneldoc/and
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic bitwise AND with ${desc_order} ordering
+ * @i: ${int} value
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v & @i) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * ${desc_return}
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/andnot b/scripts/atomic/kerneldoc/andnot
new file mode 100644
index 000000000000..64bb509f866b
--- /dev/null
+++ b/scripts/atomic/kerneldoc/andnot
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic bitwise AND NOT with ${desc_order} ordering
+ * @i: ${int} value
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v & ~@i) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * ${desc_return}
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/cmpxchg b/scripts/atomic/kerneldoc/cmpxchg
new file mode 100644
index 000000000000..3bce328f50cf
--- /dev/null
+++ b/scripts/atomic/kerneldoc/cmpxchg
@@ -0,0 +1,14 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic compare and exchange with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ * @old: ${int} value to compare with
+ * @new: ${int} value to assign
+ *
+ * If (@v == @old), atomically updates @v to @new with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: The original value of @v.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/dec b/scripts/atomic/kerneldoc/dec
new file mode 100644
index 000000000000..bbeecbc4c20a
--- /dev/null
+++ b/scripts/atomic/kerneldoc/dec
@@ -0,0 +1,12 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic decrement with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v - 1) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * ${desc_return}
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/dec_and_test b/scripts/atomic/kerneldoc/dec_and_test
new file mode 100644
index 000000000000..71bbd23ce4bc
--- /dev/null
+++ b/scripts/atomic/kerneldoc/dec_and_test
@@ -0,0 +1,12 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic decrement and test if zero with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v - 1) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: @true if the resulting value of @v is zero, @false otherwise.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/dec_if_positive b/scripts/atomic/kerneldoc/dec_if_positive
new file mode 100644
index 000000000000..04f1aed3cf83
--- /dev/null
+++ b/scripts/atomic/kerneldoc/dec_if_positive
@@ -0,0 +1,12 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic decrement if positive with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ *
+ * If (@v > 0), atomically updates @v to (@v - 1) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: The old value of (@v - 1), regardless of whether @v was updated.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/dec_unless_positive b/scripts/atomic/kerneldoc/dec_unless_positive
new file mode 100644
index 000000000000..ee73612f0354
--- /dev/null
+++ b/scripts/atomic/kerneldoc/dec_unless_positive
@@ -0,0 +1,12 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic decrement unless positive with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ *
+ * If (@v <= 0), atomically updates @v to (@v - 1) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: @true if @v was updated, @false otherwise.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/inc b/scripts/atomic/kerneldoc/inc
new file mode 100644
index 000000000000..9f14f1b3d2ef
--- /dev/null
+++ b/scripts/atomic/kerneldoc/inc
@@ -0,0 +1,12 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic increment with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v + 1) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * ${desc_return}
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/inc_and_test b/scripts/atomic/kerneldoc/inc_and_test
new file mode 100644
index 000000000000..971694d59bbd
--- /dev/null
+++ b/scripts/atomic/kerneldoc/inc_and_test
@@ -0,0 +1,12 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic increment and test if zero with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v + 1) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: @true if the resulting value of @v is zero, @false otherwise.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/inc_not_zero b/scripts/atomic/kerneldoc/inc_not_zero
new file mode 100644
index 000000000000..618be08e653e
--- /dev/null
+++ b/scripts/atomic/kerneldoc/inc_not_zero
@@ -0,0 +1,12 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic increment unless zero with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ *
+ * If (@v != 0), atomically updates @v to (@v + 1) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: @true if @v was updated, @false otherwise.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/inc_unless_negative b/scripts/atomic/kerneldoc/inc_unless_negative
new file mode 100644
index 000000000000..597f23d4dc8d
--- /dev/null
+++ b/scripts/atomic/kerneldoc/inc_unless_negative
@@ -0,0 +1,12 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic increment unless negative with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ *
+ * If (@v >= 0), atomically updates @v to (@v + 1) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: @true if @v was updated, @false otherwise.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/or b/scripts/atomic/kerneldoc/or
new file mode 100644
index 000000000000..55b33de50416
--- /dev/null
+++ b/scripts/atomic/kerneldoc/or
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic bitwise OR with ${desc_order} ordering
+ * @i: ${int} value
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v | @i) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * ${desc_return}
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/read b/scripts/atomic/kerneldoc/read
new file mode 100644
index 000000000000..89fe6147c964
--- /dev/null
+++ b/scripts/atomic/kerneldoc/read
@@ -0,0 +1,12 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic load with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically loads the value of @v with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: The value loaded from @v.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/set b/scripts/atomic/kerneldoc/set
new file mode 100644
index 000000000000..e82cb9ebbc42
--- /dev/null
+++ b/scripts/atomic/kerneldoc/set
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic set with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ * @i: ${int} value to assign
+ *
+ * Atomically sets @v to @i with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: Nothing.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/sub b/scripts/atomic/kerneldoc/sub
new file mode 100644
index 000000000000..3ba642d04407
--- /dev/null
+++ b/scripts/atomic/kerneldoc/sub
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic subtract with ${desc_order} ordering
+ * @i: ${int} value to subtract
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v - @i) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * ${desc_return}
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/sub_and_test b/scripts/atomic/kerneldoc/sub_and_test
new file mode 100644
index 000000000000..d3760f7749d4
--- /dev/null
+++ b/scripts/atomic/kerneldoc/sub_and_test
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic subtract and test if zero with ${desc_order} ordering
+ * @i: ${int} value to add
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v - @i) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: @true if the resulting value of @v is zero, @false otherwise.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/try_cmpxchg b/scripts/atomic/kerneldoc/try_cmpxchg
new file mode 100644
index 000000000000..296553206c06
--- /dev/null
+++ b/scripts/atomic/kerneldoc/try_cmpxchg
@@ -0,0 +1,15 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic compare and exchange with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ * @old: pointer to ${int} value to compare with
+ * @new: ${int} value to assign
+ *
+ * If (@v == @old), atomically updates @v to @new with ${desc_order} ordering.
+ * Otherwise, updates @old to the current value of @v.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: @true if the exchange occured, @false otherwise.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/xchg b/scripts/atomic/kerneldoc/xchg
new file mode 100644
index 000000000000..75f04c085f25
--- /dev/null
+++ b/scripts/atomic/kerneldoc/xchg
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic exchange with ${desc_order} ordering
+ * @v: pointer to ${atomic}_t
+ * @new: ${int} value to assign
+ *
+ * Atomically updates @v to @new with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * Return: The original value of @v.
+ */
+EOF
diff --git a/scripts/atomic/kerneldoc/xor b/scripts/atomic/kerneldoc/xor
new file mode 100644
index 000000000000..8837270f2806
--- /dev/null
+++ b/scripts/atomic/kerneldoc/xor
@@ -0,0 +1,13 @@
+cat <<EOF
+/**
+ * ${class}${atomicname}() - atomic bitwise XOR with ${desc_order} ordering
+ * @i: ${int} value
+ * @v: pointer to ${atomic}_t
+ *
+ * Atomically updates @v to (@v ^ @i) with ${desc_order} ordering.
+ *
+ * ${desc_noinstr}
+ *
+ * ${desc_return}
+ */
+EOF
diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore
index 98ae1f509592..07c195f605a1 100644
--- a/scripts/basic/.gitignore
+++ b/scripts/basic/.gitignore
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-fixdep
+/fixdep
+/randstruct.seed
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index eeb6a38c5551..dd289a6725ac 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -3,3 +3,14 @@
# fixdep: used to generate dependency information during build process
hostprogs-always-y += fixdep
+
+# randstruct: the seed is needed before building the gcc-plugin or
+# before running a Clang kernel build.
+gen-randstruct-seed := $(srctree)/scripts/gen-randstruct-seed.sh
+quiet_cmd_create_randstruct_seed = GENSEED $@
+cmd_create_randstruct_seed = \
+ $(CONFIG_SHELL) $(gen-randstruct-seed) \
+ $@ $(objtree)/include/generated/randstruct_hash.h
+$(obj)/randstruct.seed: $(gen-randstruct-seed) FORCE
+ $(call if_changed,create_randstruct_seed)
+always-$(CONFIG_RANDSTRUCT) += randstruct.seed
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index d98540552941..84b6efa849f4 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -34,7 +34,7 @@
* the config symbols are rebuilt.
*
* So if the user changes his CONFIG_HIS_DRIVER option, only the objects
- * which depend on "include/config/his/driver.h" will be rebuilt,
+ * which depend on "include/config/HIS_DRIVER" will be rebuilt,
* so most likely only his driver ;-)
*
* The idea above dates, by the way, back to Michael E Chastain, AFAIK.
@@ -70,11 +70,11 @@
*
* It first generates a line
*
- * cmd_<target> = <cmdline>
+ * savedcmd_<target> = <cmdline>
*
* and then basically copies the .<target>.d file to stdout, in the
* process filtering out the dependency on autoconf.h and adding
- * dependencies on include/config/my/option.h for every
+ * dependencies on include/config/MY_OPTION for every
* CONFIG_MY_OPTION encountered in any of the prerequisites.
*
* We don't even try to really parse the header files, but
@@ -94,7 +94,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
-#include <stdarg.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
@@ -105,57 +105,6 @@ static void usage(void)
exit(1);
}
-/*
- * In the intended usage of this program, the stdout is redirected to .*.cmd
- * files. The return value of printf() and putchar() must be checked to catch
- * any error, e.g. "No space left on device".
- */
-static void xprintf(const char *format, ...)
-{
- va_list ap;
- int ret;
-
- va_start(ap, format);
- ret = vprintf(format, ap);
- if (ret < 0) {
- perror("fixdep");
- exit(1);
- }
- va_end(ap);
-}
-
-static void xputchar(int c)
-{
- int ret;
-
- ret = putchar(c);
- if (ret == EOF) {
- perror("fixdep");
- exit(1);
- }
-}
-
-/*
- * Print out a dependency path from a symbol name
- */
-static void print_dep(const char *m, int slen, const char *dir)
-{
- int c, prev_c = '/', i;
-
- xprintf(" $(wildcard %s/", dir);
- for (i = 0; i < slen; i++) {
- c = m[i];
- if (c == '_')
- c = '/';
- else
- c = tolower(c);
- if (c != '/' || prev_c != '/')
- xputchar(c);
- prev_c = c;
- }
- xprintf(".h) \\\n");
-}
-
struct item {
struct item *next;
unsigned int len;
@@ -164,7 +113,7 @@ struct item {
};
#define HASHSZ 256
-static struct item *hashtab[HASHSZ];
+static struct item *config_hashtab[HASHSZ], *file_hashtab[HASHSZ];
static unsigned int strhash(const char *str, unsigned int sz)
{
@@ -177,24 +126,10 @@ static unsigned int strhash(const char *str, unsigned int sz)
}
/*
- * Lookup a value in the configuration string.
- */
-static int is_defined_config(const char *name, int len, unsigned int hash)
-{
- struct item *aux;
-
- for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
- if (aux->hash == hash && aux->len == len &&
- memcmp(aux->name, name, len) == 0)
- return 1;
- }
- return 0;
-}
-
-/*
* Add a new value to the configuration string.
*/
-static void define_config(const char *name, int len, unsigned int hash)
+static void add_to_hashtable(const char *name, int len, unsigned int hash,
+ struct item *hashtab[])
{
struct item *aux = malloc(sizeof(*aux) + len);
@@ -210,17 +145,35 @@ static void define_config(const char *name, int len, unsigned int hash)
}
/*
+ * Lookup a string in the hash table. If found, just return true.
+ * If not, add it to the hashtable and return false.
+ */
+static bool in_hashtable(const char *name, int len, struct item *hashtab[])
+{
+ struct item *aux;
+ unsigned int hash = strhash(name, len);
+
+ for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
+ if (aux->hash == hash && aux->len == len &&
+ memcmp(aux->name, name, len) == 0)
+ return true;
+ }
+
+ add_to_hashtable(name, len, hash, hashtab);
+
+ return false;
+}
+
+/*
* Record the use of a CONFIG_* word.
*/
static void use_config(const char *m, int slen)
{
- unsigned int hash = strhash(m, slen);
-
- if (is_defined_config(m, slen, hash))
- return;
+ if (in_hashtable(m, slen, config_hashtab))
+ return;
- define_config(m, slen, hash);
- print_dep(m, slen, "include/config");
+ /* Print out a dependency path from a symbol name. */
+ printf(" $(wildcard include/config/%.*s) \\\n", slen, m);
}
/* test if s ends in sub */
@@ -293,8 +246,16 @@ static void *read_file(const char *filename)
/* Ignore certain dependencies */
static int is_ignored_file(const char *s, int len)
{
- return str_ends_with(s, len, "include/generated/autoconf.h") ||
- str_ends_with(s, len, "include/generated/autoksyms.h");
+ return str_ends_with(s, len, "include/generated/autoconf.h");
+}
+
+/* Do not parse these files */
+static int is_no_parse_file(const char *s, int len)
+{
+ /* rustc may list binary files in dep-info */
+ return str_ends_with(s, len, ".rlib") ||
+ str_ends_with(s, len, ".rmeta") ||
+ str_ends_with(s, len, ".so");
}
/*
@@ -302,75 +263,144 @@ static int is_ignored_file(const char *s, int len)
* assignments are parsed not only by make, but also by the rather simple
* parser in scripts/mod/sumversion.c.
*/
-static void parse_dep_file(char *m, const char *target)
+static void parse_dep_file(char *p, const char *target)
{
- char *p;
- int is_last, is_target;
- int saw_any_target = 0;
- int is_first_dep = 0;
- void *buf;
-
- while (1) {
- /* Skip any "white space" */
- while (*m == ' ' || *m == '\\' || *m == '\n')
- m++;
-
- if (!*m)
+ bool saw_any_target = false;
+ bool is_target = true;
+ bool is_source = false;
+ bool need_parse;
+ char *q, saved_c;
+
+ while (*p) {
+ /* handle some special characters first. */
+ switch (*p) {
+ case '#':
+ /*
+ * skip comments.
+ * rustc may emit comments to dep-info.
+ */
+ p++;
+ while (*p != '\0' && *p != '\n') {
+ /*
+ * escaped newlines continue the comment across
+ * multiple lines.
+ */
+ if (*p == '\\')
+ p++;
+ p++;
+ }
+ continue;
+ case ' ':
+ case '\t':
+ /* skip whitespaces */
+ p++;
+ continue;
+ case '\\':
+ /*
+ * backslash/newline combinations continue the
+ * statement. Skip it just like a whitespace.
+ */
+ if (*(p + 1) == '\n') {
+ p += 2;
+ continue;
+ }
break;
-
- /* Find next "white space" */
- p = m;
- while (*p && *p != ' ' && *p != '\\' && *p != '\n')
+ case '\n':
+ /*
+ * Makefiles use a line-based syntax, where the newline
+ * is the end of a statement. After seeing a newline,
+ * we expect the next token is a target.
+ */
p++;
- is_last = (*p == '\0');
- /* Is the token we found a target name? */
- is_target = (*(p-1) == ':');
- /* Don't write any target names into the dependency file */
- if (is_target) {
- /* The /next/ file is the first dependency */
- is_first_dep = 1;
- } else if (!is_ignored_file(m, p - m)) {
- *p = '\0';
-
+ is_target = true;
+ continue;
+ case ':':
/*
- * Do not list the source file as dependency, so that
- * kbuild is not confused if a .c file is rewritten
- * into .S or vice versa. Storing it in source_* is
- * needed for modpost to compute srcversions.
+ * assume the first dependency after a colon as the
+ * source file.
*/
- if (is_first_dep) {
+ p++;
+ is_target = false;
+ is_source = true;
+ continue;
+ }
+
+ /* find the end of the token */
+ q = p;
+ while (*q != ' ' && *q != '\t' && *q != '\n' && *q != '#' && *q != ':') {
+ if (*q == '\\') {
/*
- * If processing the concatenation of multiple
- * dependency files, only process the first
- * target name, which will be the original
- * source name, and ignore any other target
- * names, which will be intermediate temporary
- * files.
+ * backslash/newline combinations work like as
+ * a whitespace, so this is the end of token.
*/
- if (!saw_any_target) {
- saw_any_target = 1;
- xprintf("source_%s := %s\n\n",
- target, m);
- xprintf("deps_%s := \\\n", target);
+ if (*(q + 1) == '\n')
+ break;
+
+ /* escaped special characters */
+ if (*(q + 1) == '#' || *(q + 1) == ':') {
+ memmove(p + 1, p, q - p);
+ p++;
}
- is_first_dep = 0;
- } else {
- xprintf(" %s \\\n", m);
+
+ q++;
}
- buf = read_file(m);
- parse_config_file(buf);
- free(buf);
+ if (*q == '\0')
+ break;
+ q++;
}
- if (is_last)
- break;
+ /* Just discard the target */
+ if (is_target) {
+ p = q;
+ continue;
+ }
+
+ saved_c = *q;
+ *q = '\0';
+ need_parse = false;
/*
- * Start searching for next token immediately after the first
- * "whitespace" character that follows this token.
+ * Do not list the source file as dependency, so that kbuild is
+ * not confused if a .c file is rewritten into .S or vice versa.
+ * Storing it in source_* is needed for modpost to compute
+ * srcversions.
*/
- m = p + 1;
+ if (is_source) {
+ /*
+ * The DT build rule concatenates multiple dep files.
+ * When processing them, only process the first source
+ * name, which will be the original one, and ignore any
+ * other source names, which will be intermediate
+ * temporary files.
+ *
+ * rustc emits the same dependency list for each
+ * emission type. It is enough to list the source name
+ * just once.
+ */
+ if (!saw_any_target) {
+ saw_any_target = true;
+ printf("source_%s := %s\n\n", target, p);
+ printf("deps_%s := \\\n", target);
+ need_parse = true;
+ }
+ } else if (!is_ignored_file(p, q - p) &&
+ !in_hashtable(p, q - p, file_hashtab)) {
+ printf(" %s \\\n", p);
+ need_parse = true;
+ }
+
+ if (need_parse && !is_no_parse_file(p, q - p)) {
+ void *buf;
+
+ buf = read_file(p);
+ parse_config_file(buf);
+ free(buf);
+ }
+
+ is_source = false;
+ *q = saved_c;
+ p = q;
}
if (!saw_any_target) {
@@ -378,8 +408,8 @@ static void parse_dep_file(char *m, const char *target)
exit(1);
}
- xprintf("\n%s: $(deps_%s)\n\n", target, target);
- xprintf("$(deps_%s):\n", target);
+ printf("\n%s: $(deps_%s)\n\n", target, target);
+ printf("$(deps_%s):\n", target);
}
int main(int argc, char *argv[])
@@ -394,11 +424,22 @@ int main(int argc, char *argv[])
target = argv[2];
cmdline = argv[3];
- xprintf("cmd_%s := %s\n\n", target, cmdline);
+ printf("savedcmd_%s := %s\n\n", target, cmdline);
buf = read_file(depfile);
parse_dep_file(buf, target);
free(buf);
+ fflush(stdout);
+
+ /*
+ * In the intended usage, the stdout is redirected to .*.cmd files.
+ * Call ferror() to catch errors such as "No space left on device".
+ */
+ if (ferror(stdout)) {
+ fprintf(stderr, "fixdep: not all data was written to the output\n");
+ exit(1);
+ }
+
return 0;
}
diff --git a/scripts/bin2c.c b/scripts/bin2c.c
deleted file mode 100644
index c3d7eef3ad06..000000000000
--- a/scripts/bin2c.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Unloved program to convert a binary on stdin to a C include on stdout
- *
- * Jan 1999 Matt Mackall <mpm@selenic.com>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#include <stdio.h>
-
-int main(int argc, char *argv[])
-{
- int ch, total = 0;
-
- if (argc > 1)
- printf("const char %s[] %s=\n",
- argv[1], argc > 2 ? argv[2] : "");
-
- do {
- printf("\t\"");
- while ((ch = getchar()) != EOF) {
- total++;
- printf("\\x%02x", ch);
- if (total % 16 == 0)
- break;
- }
- printf("\"\n");
- } while (ch != EOF);
-
- if (argc > 1)
- printf("\t;\n\n#include <linux/types.h>\n\nconst size_t %s_size = %d;\n",
- argv[1], total);
-
- return 0;
-}
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter
index dcd8d8750b8b..36303afa9dfc 100755
--- a/scripts/bloat-o-meter
+++ b/scripts/bloat-o-meter
@@ -7,24 +7,31 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-import sys, os, re
+import sys, os, re, argparse
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE, SIG_DFL)
-if len(sys.argv) < 3:
- sys.stderr.write("usage: %s [option] file1 file2\n" % sys.argv[0])
- sys.stderr.write("The options are:\n")
- sys.stderr.write("-c categorize output based on symbol type\n")
- sys.stderr.write("-d Show delta of Data Section\n")
- sys.stderr.write("-t Show delta of text Section\n")
- sys.exit(-1)
+parser = argparse.ArgumentParser(description="Simple script used to compare the symbol sizes of 2 object files")
+group = parser.add_mutually_exclusive_group()
+group.add_argument('-c', help='categorize output based on symbol type', action='store_true')
+group.add_argument('-d', help='Show delta of Data Section', action='store_true')
+group.add_argument('-t', help='Show delta of text Section', action='store_true')
+parser.add_argument('-p', dest='prefix', help='Arch prefix for the tool being used. Useful in cross build scenarios')
+parser.add_argument('file1', help='First file to compare')
+parser.add_argument('file2', help='Second file to compare')
+
+args = parser.parse_args()
re_NUMBER = re.compile(r'\.[0-9]+')
def getsizes(file, format):
sym = {}
- with os.popen("nm --size-sort " + file) as f:
+ nm = "nm"
+ if args.prefix:
+ nm = "{}nm".format(args.prefix)
+
+ with os.popen("{} --size-sort {}".format(nm, file)) as f:
for line in f:
if line.startswith("\n") or ":" in line:
continue
@@ -36,6 +43,7 @@ def getsizes(file, format):
if name.startswith("__se_compat_sys"): continue
if name.startswith("__addressable_"): continue
if name == "linux_banner": continue
+ if name == "vermagic": continue
# statics and some other optimizations adds random .NUMBER
name = re_NUMBER.sub('', name)
sym[name] = sym.get(name, 0) + int(size, 16)
@@ -72,13 +80,12 @@ def calc(oldfile, newfile, format):
if d<0: shrink, down = shrink+1, down-d
delta.append((d, name))
- delta.sort()
- delta.reverse()
+ delta.sort(reverse=True)
return grow, shrink, add, remove, up, down, delta, old, new, otot, ntot
-def print_result(symboltype, symbolformat, argc):
+def print_result(symboltype, symbolformat):
grow, shrink, add, remove, up, down, delta, old, new, otot, ntot = \
- calc(sys.argv[argc - 1], sys.argv[argc], symbolformat)
+ calc(args.file1, args.file2, symbolformat)
print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
(add, remove, grow, shrink, up, -down, up-down))
@@ -92,13 +99,13 @@ def print_result(symboltype, symbolformat, argc):
percent = 0
print("Total: Before=%d, After=%d, chg %+.2f%%" % (otot, ntot, percent))
-if sys.argv[1] == "-c":
- print_result("Function", "tT", 3)
- print_result("Data", "dDbB", 3)
- print_result("RO Data", "rR", 3)
-elif sys.argv[1] == "-d":
- print_result("Data", "dDbBrR", 3)
-elif sys.argv[1] == "-t":
- print_result("Function", "tT", 3)
+if args.c:
+ print_result("Function", "tT")
+ print_result("Data", "dDbB")
+ print_result("RO Data", "rR")
+elif args.d:
+ print_result("Data", "dDbBrR")
+elif args.t:
+ print_result("Function", "tT")
else:
- print_result("Function", "tTdDbBrR", 2)
+ print_result("Function", "tTdDbBrR")
diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_doc.py
index 867ada23281c..eaae2ce78381 100755
--- a/scripts/bpf_helpers_doc.py
+++ b/scripts/bpf_doc.py
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2018-2019 Netronome Systems, Inc.
+# Copyright (C) 2021 Isovalent, Inc.
# In case user attempts to run with Python 2.
from __future__ import print_function
@@ -9,10 +10,16 @@ from __future__ import print_function
import argparse
import re
import sys, os
+import subprocess
+
+helpersDocStart = 'Start of BPF helper function descriptions:'
class NoHelperFound(BaseException):
pass
+class NoSyscallCommandFound(BaseException):
+ pass
+
class ParsingError(BaseException):
def __init__(self, line='<line not provided>', reader=None):
if reader:
@@ -22,18 +29,31 @@ class ParsingError(BaseException):
else:
BaseException.__init__(self, 'Error parsing line: %s' % line)
-class Helper(object):
+
+class APIElement(object):
"""
- An object representing the description of an eBPF helper function.
- @proto: function prototype of the helper function
- @desc: textual description of the helper function
- @ret: description of the return value of the helper function
+ An object representing the description of an aspect of the eBPF API.
+ @proto: prototype of the API symbol
+ @desc: textual description of the symbol
+ @ret: (optional) description of any associated return value
"""
def __init__(self, proto='', desc='', ret=''):
self.proto = proto
self.desc = desc
self.ret = ret
+
+class Helper(APIElement):
+ """
+ An object representing the description of an eBPF helper function.
+ @proto: function prototype of the helper function
+ @desc: textual description of the helper function
+ @ret: description of the return value of the helper function
+ """
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.enum_val = None
+
def proto_break_down(self):
"""
Break down helper function protocol into smaller chunks: return type,
@@ -60,6 +80,7 @@ class Helper(object):
return res
+
class HeaderParser(object):
"""
An object used to parse a file in order to extract the documentation of a
@@ -72,13 +93,38 @@ class HeaderParser(object):
self.reader = open(filename, 'r')
self.line = ''
self.helpers = []
+ self.commands = []
+ self.desc_unique_helpers = set()
+ self.define_unique_helpers = []
+ self.helper_enum_vals = {}
+ self.helper_enum_pos = {}
+ self.desc_syscalls = []
+ self.enum_syscalls = []
+
+ def parse_element(self):
+ proto = self.parse_symbol()
+ desc = self.parse_desc(proto)
+ ret = self.parse_ret(proto)
+ return APIElement(proto=proto, desc=desc, ret=ret)
def parse_helper(self):
proto = self.parse_proto()
- desc = self.parse_desc()
- ret = self.parse_ret()
+ desc = self.parse_desc(proto)
+ ret = self.parse_ret(proto)
return Helper(proto=proto, desc=desc, ret=ret)
+ def parse_symbol(self):
+ p = re.compile(' \* ?(BPF\w+)$')
+ capture = p.match(self.line)
+ if not capture:
+ raise NoSyscallCommandFound
+ end_re = re.compile(' \* ?NOTES$')
+ end = end_re.match(self.line)
+ if end:
+ raise NoSyscallCommandFound
+ self.line = self.reader.readline()
+ return capture.group(1)
+
def parse_proto(self):
# Argument can be of shape:
# - "void"
@@ -94,16 +140,15 @@ class HeaderParser(object):
self.line = self.reader.readline()
return capture.group(1)
- def parse_desc(self):
+ def parse_desc(self, proto):
p = re.compile(' \* ?(?:\t| {5,8})Description$')
capture = p.match(self.line)
if not capture:
- # Helper can have empty description and we might be parsing another
- # attribute: return but do not consume.
- return ''
+ raise Exception("No description section found for " + proto)
# Description can be several lines, some of them possibly empty, and it
# stops when another subsection title is met.
desc = ''
+ desc_present = False
while True:
self.line = self.reader.readline()
if self.line == ' *\n':
@@ -112,21 +157,24 @@ class HeaderParser(object):
p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
capture = p.match(self.line)
if capture:
+ desc_present = True
desc += capture.group(1) + '\n'
else:
break
+
+ if not desc_present:
+ raise Exception("No description found for " + proto)
return desc
- def parse_ret(self):
+ def parse_ret(self, proto):
p = re.compile(' \* ?(?:\t| {5,8})Return$')
capture = p.match(self.line)
if not capture:
- # Helper can have empty retval and we might be parsing another
- # attribute: return but do not consume.
- return ''
+ raise Exception("No return section found for " + proto)
# Return value description can be several lines, some of them possibly
# empty, and it stops when another subsection title is met.
ret = ''
+ ret_present = False
while True:
self.line = self.reader.readline()
if self.line == ' *\n':
@@ -135,28 +183,142 @@ class HeaderParser(object):
p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
capture = p.match(self.line)
if capture:
+ ret_present = True
ret += capture.group(1) + '\n'
else:
break
+
+ if not ret_present:
+ raise Exception("No return found for " + proto)
return ret
- def run(self):
- # Advance to start of helper function descriptions.
- offset = self.reader.read().find('* Start of BPF helper function descriptions:')
+ def seek_to(self, target, help_message, discard_lines = 1):
+ self.reader.seek(0)
+ offset = self.reader.read().find(target)
if offset == -1:
- raise Exception('Could not find start of eBPF helper descriptions list')
+ raise Exception(help_message)
self.reader.seek(offset)
self.reader.readline()
- self.reader.readline()
+ for _ in range(discard_lines):
+ self.reader.readline()
self.line = self.reader.readline()
+ def parse_desc_syscall(self):
+ self.seek_to('* DOC: eBPF Syscall Commands',
+ 'Could not find start of eBPF syscall descriptions list')
+ while True:
+ try:
+ command = self.parse_element()
+ self.commands.append(command)
+ self.desc_syscalls.append(command.proto)
+
+ except NoSyscallCommandFound:
+ break
+
+ def parse_enum_syscall(self):
+ self.seek_to('enum bpf_cmd {',
+ 'Could not find start of bpf_cmd enum', 0)
+ # Searches for either one or more BPF\w+ enums
+ bpf_p = re.compile('\s*(BPF\w+)+')
+ # Searches for an enum entry assigned to another entry,
+ # for e.g. BPF_PROG_RUN = BPF_PROG_TEST_RUN, which is
+ # not documented hence should be skipped in check to
+ # determine if the right number of syscalls are documented
+ assign_p = re.compile('\s*(BPF\w+)\s*=\s*(BPF\w+)')
+ bpf_cmd_str = ''
+ while True:
+ capture = assign_p.match(self.line)
+ if capture:
+ # Skip line if an enum entry is assigned to another entry
+ self.line = self.reader.readline()
+ continue
+ capture = bpf_p.match(self.line)
+ if capture:
+ bpf_cmd_str += self.line
+ else:
+ break
+ self.line = self.reader.readline()
+ # Find the number of occurences of BPF\w+
+ self.enum_syscalls = re.findall('(BPF\w+)+', bpf_cmd_str)
+
+ def parse_desc_helpers(self):
+ self.seek_to(helpersDocStart,
+ 'Could not find start of eBPF helper descriptions list')
while True:
try:
helper = self.parse_helper()
self.helpers.append(helper)
+ proto = helper.proto_break_down()
+ self.desc_unique_helpers.add(proto['name'])
except NoHelperFound:
break
+ def parse_define_helpers(self):
+ # Parse FN(...) in #define ___BPF_FUNC_MAPPER to compare later with the
+ # number of unique function names present in description and use the
+ # correct enumeration value.
+ # Note: seek_to(..) discards the first line below the target search text,
+ # resulting in FN(unspec, 0, ##ctx) being skipped and not added to
+ # self.define_unique_helpers.
+ self.seek_to('#define ___BPF_FUNC_MAPPER(FN, ctx...)',
+ 'Could not find start of eBPF helper definition list')
+ # Searches for one FN(\w+) define or a backslash for newline
+ p = re.compile('\s*FN\((\w+), (\d+), ##ctx\)|\\\\')
+ fn_defines_str = ''
+ i = 0
+ while True:
+ capture = p.match(self.line)
+ if capture:
+ fn_defines_str += self.line
+ helper_name = capture.expand(r'bpf_\1')
+ self.helper_enum_vals[helper_name] = int(capture.group(2))
+ self.helper_enum_pos[helper_name] = i
+ i += 1
+ else:
+ break
+ self.line = self.reader.readline()
+ # Find the number of occurences of FN(\w+)
+ self.define_unique_helpers = re.findall('FN\(\w+, \d+, ##ctx\)', fn_defines_str)
+
+ def validate_helpers(self):
+ last_helper = ''
+ seen_helpers = set()
+ seen_enum_vals = set()
+ i = 0
+ for helper in self.helpers:
+ proto = helper.proto_break_down()
+ name = proto['name']
+ try:
+ enum_val = self.helper_enum_vals[name]
+ enum_pos = self.helper_enum_pos[name]
+ except KeyError:
+ raise Exception("Helper %s is missing from enum bpf_func_id" % name)
+
+ if name in seen_helpers:
+ if last_helper != name:
+ raise Exception("Helper %s has multiple descriptions which are not grouped together" % name)
+ continue
+
+ # Enforce current practice of having the descriptions ordered
+ # by enum value.
+ if enum_pos != i:
+ raise Exception("Helper %s (ID %d) comment order (#%d) must be aligned with its position (#%d) in enum bpf_func_id" % (name, enum_val, i + 1, enum_pos + 1))
+ if enum_val in seen_enum_vals:
+ raise Exception("Helper %s has duplicated value %d" % (name, enum_val))
+
+ seen_helpers.add(name)
+ last_helper = name
+ seen_enum_vals.add(enum_val)
+
+ helper.enum_val = enum_val
+ i += 1
+
+ def run(self):
+ self.parse_desc_syscall()
+ self.parse_enum_syscall()
+ self.parse_desc_helpers()
+ self.parse_define_helpers()
+ self.validate_helpers()
self.reader.close()
###############################################################################
@@ -165,10 +327,11 @@ class Printer(object):
"""
A generic class for printers. Printers should be created with an array of
Helper objects, and implement a way to print them in the desired fashion.
- @helpers: array of Helper objects to print to standard output
+ @parser: A HeaderParser with objects to print to standard output
"""
- def __init__(self, helpers):
- self.helpers = helpers
+ def __init__(self, parser):
+ self.parser = parser
+ self.elements = []
def print_header(self):
pass
@@ -181,49 +344,107 @@ class Printer(object):
def print_all(self):
self.print_header()
- for helper in self.helpers:
- self.print_one(helper)
+ for elem in self.elements:
+ self.print_one(elem)
self.print_footer()
+ def elem_number_check(self, desc_unique_elem, define_unique_elem, type, instance):
+ """
+ Checks the number of helpers/syscalls documented within the header file
+ description with those defined as part of enum/macro and raise an
+ Exception if they don't match.
+ """
+ nr_desc_unique_elem = len(desc_unique_elem)
+ nr_define_unique_elem = len(define_unique_elem)
+ if nr_desc_unique_elem != nr_define_unique_elem:
+ exception_msg = '''
+The number of unique %s in description (%d) doesn\'t match the number of unique %s defined in %s (%d)
+''' % (type, nr_desc_unique_elem, type, instance, nr_define_unique_elem)
+ if nr_desc_unique_elem < nr_define_unique_elem:
+ # Function description is parsed until no helper is found (which can be due to
+ # misformatting). Hence, only print the first missing/misformatted helper/enum.
+ exception_msg += '''
+The description for %s is not present or formatted correctly.
+''' % (define_unique_elem[nr_desc_unique_elem])
+ raise Exception(exception_msg)
+
class PrinterRST(Printer):
"""
- A printer for dumping collected information about helpers as a ReStructured
- Text page compatible with the rst2man program, which can be used to
- generate a manual page for the helpers.
- @helpers: array of Helper objects to print to standard output
+ A generic class for printers that print ReStructured Text. Printers should
+ be created with a HeaderParser object, and implement a way to print API
+ elements in the desired fashion.
+ @parser: A HeaderParser with objects to print to standard output
"""
- def print_header(self):
- header = '''\
+ def __init__(self, parser):
+ self.parser = parser
+
+ def print_license(self):
+ license = '''\
.. Copyright (C) All BPF authors and contributors from 2014 to present.
.. See git log include/uapi/linux/bpf.h in kernel tree for details.
..
-.. %%%LICENSE_START(VERBATIM)
-.. Permission is granted to make and distribute verbatim copies of this
-.. manual provided the copyright notice and this permission notice are
-.. preserved on all copies.
-..
-.. Permission is granted to copy and distribute modified versions of this
-.. manual under the conditions for verbatim copying, provided that the
-.. entire resulting derived work is distributed under the terms of a
-.. permission notice identical to this one.
-..
-.. Since the Linux kernel and libraries are constantly changing, this
-.. manual page may be incorrect or out-of-date. The author(s) assume no
-.. responsibility for errors or omissions, or for damages resulting from
-.. the use of the information contained herein. The author(s) may not
-.. have taken the same level of care in the production of this manual,
-.. which is licensed free of charge, as they might when working
-.. professionally.
-..
-.. Formatted or processed versions of this manual, if unaccompanied by
-.. the source, must acknowledge the copyright and authors of this work.
-.. %%%LICENSE_END
+.. SPDX-License-Identifier: Linux-man-pages-copyleft
..
.. Please do not edit this file. It was generated from the documentation
.. located in file include/uapi/linux/bpf.h of the Linux kernel sources
-.. (helpers description), and from scripts/bpf_helpers_doc.py in the same
+.. (helpers description), and from scripts/bpf_doc.py in the same
.. repository (header and footer).
+'''
+ print(license)
+
+ def print_elem(self, elem):
+ if (elem.desc):
+ print('\tDescription')
+ # Do not strip all newline characters: formatted code at the end of
+ # a section must be followed by a blank line.
+ for line in re.sub('\n$', '', elem.desc, count=1).split('\n'):
+ print('{}{}'.format('\t\t' if line else '', line))
+
+ if (elem.ret):
+ print('\tReturn')
+ for line in elem.ret.rstrip().split('\n'):
+ print('{}{}'.format('\t\t' if line else '', line))
+ print('')
+
+ def get_kernel_version(self):
+ try:
+ version = subprocess.run(['git', 'describe'], cwd=linuxRoot,
+ capture_output=True, check=True)
+ version = version.stdout.decode().rstrip()
+ except:
+ try:
+ version = subprocess.run(['make', 'kernelversion'], cwd=linuxRoot,
+ capture_output=True, check=True)
+ version = version.stdout.decode().rstrip()
+ except:
+ return 'Linux'
+ return 'Linux {version}'.format(version=version)
+
+ def get_last_doc_update(self, delimiter):
+ try:
+ cmd = ['git', 'log', '-1', '--pretty=format:%cs', '--no-patch',
+ '-L',
+ '/{}/,/\*\//:include/uapi/linux/bpf.h'.format(delimiter)]
+ date = subprocess.run(cmd, cwd=linuxRoot,
+ capture_output=True, check=True)
+ return date.stdout.decode().rstrip()
+ except:
+ return ''
+
+class PrinterHelpersRST(PrinterRST):
+ """
+ A printer for dumping collected information about helpers as a ReStructured
+ Text page compatible with the rst2man program, which can be used to
+ generate a manual page for the helpers.
+ @parser: A HeaderParser with Helper objects to print to standard output
+ """
+ def __init__(self, parser):
+ self.elements = parser.helpers
+ self.elem_number_check(parser.desc_unique_helpers, parser.define_unique_helpers, 'helper', '___BPF_FUNC_MAPPER')
+
+ def print_header(self):
+ header = '''\
===========
BPF-HELPERS
===========
@@ -232,6 +453,8 @@ list of eBPF helper functions
-------------------------------------------------------------------------------
:Manual section: 7
+:Version: {version}
+{date_field}{date}
DESCRIPTION
===========
@@ -264,7 +487,13 @@ kernel at the top).
HELPERS
=======
'''
- print(header)
+ kernelVersion = self.get_kernel_version()
+ lastUpdate = self.get_last_doc_update(helpersDocStart)
+
+ PrinterRST.print_license(self)
+ print(header.format(version=kernelVersion,
+ date_field = ':Date: ' if lastUpdate else '',
+ date=lastUpdate))
def print_footer(self):
footer = '''
@@ -380,27 +609,52 @@ SEE ALSO
def print_one(self, helper):
self.print_proto(helper)
+ self.print_elem(helper)
- if (helper.desc):
- print('\tDescription')
- # Do not strip all newline characters: formatted code at the end of
- # a section must be followed by a blank line.
- for line in re.sub('\n$', '', helper.desc, count=1).split('\n'):
- print('{}{}'.format('\t\t' if line else '', line))
- if (helper.ret):
- print('\tReturn')
- for line in helper.ret.rstrip().split('\n'):
- print('{}{}'.format('\t\t' if line else '', line))
+class PrinterSyscallRST(PrinterRST):
+ """
+ A printer for dumping collected information about the syscall API as a
+ ReStructured Text page compatible with the rst2man program, which can be
+ used to generate a manual page for the syscall.
+ @parser: A HeaderParser with APIElement objects to print to standard
+ output
+ """
+ def __init__(self, parser):
+ self.elements = parser.commands
+ self.elem_number_check(parser.desc_syscalls, parser.enum_syscalls, 'syscall', 'bpf_cmd')
+
+ def print_header(self):
+ header = '''\
+===
+bpf
+===
+-------------------------------------------------------------------------------
+Perform a command on an extended BPF object
+-------------------------------------------------------------------------------
+
+:Manual section: 2
+
+COMMANDS
+========
+'''
+ PrinterRST.print_license(self)
+ print(header)
+
+ def print_one(self, command):
+ print('**%s**' % (command.proto))
+ self.print_elem(command)
- print('')
class PrinterHelpers(Printer):
"""
A printer for dumping collected information about helpers as C header to
be included from BPF program.
- @helpers: array of Helper objects to print to standard output
+ @parser: A HeaderParser with Helper objects to print to standard output
"""
+ def __init__(self, parser):
+ self.elements = parser.helpers
+ self.elem_number_check(parser.desc_unique_helpers, parser.define_unique_helpers, 'helper', '___BPF_FUNC_MAPPER')
type_fwds = [
'struct bpf_fib_lookup',
@@ -429,7 +683,9 @@ class PrinterHelpers(Printer):
'struct tcp_timewait_sock',
'struct tcp_request_sock',
'struct udp6_sock',
+ 'struct unix_sock',
'struct task_struct',
+ 'struct cgroup',
'struct __sk_buff',
'struct sk_msg_md',
@@ -439,6 +695,11 @@ class PrinterHelpers(Printer):
'struct inode',
'struct socket',
'struct file',
+ 'struct bpf_timer',
+ 'struct mptcp_sock',
+ 'struct bpf_dynptr',
+ 'struct iphdr',
+ 'struct ipv6hdr',
]
known_types = {
'...',
@@ -480,12 +741,20 @@ class PrinterHelpers(Printer):
'struct tcp_timewait_sock',
'struct tcp_request_sock',
'struct udp6_sock',
+ 'struct unix_sock',
'struct task_struct',
+ 'struct cgroup',
'struct path',
'struct btf_ptr',
'struct inode',
'struct socket',
'struct file',
+ 'struct bpf_timer',
+ 'struct mptcp_sock',
+ 'struct bpf_dynptr',
+ 'const struct bpf_dynptr',
+ 'struct iphdr',
+ 'struct ipv6hdr',
}
mapped_types = {
'u8': '__u8',
@@ -511,7 +780,7 @@ class PrinterHelpers(Printer):
def print_header(self):
header = '''\
-/* This is auto-generated file. See bpf_helpers_doc.py for details. */
+/* This is auto-generated file. See bpf_doc.py for details. */
/* Forward declarations of BPF structs */'''
@@ -577,7 +846,7 @@ class PrinterHelpers(Printer):
comma = ', '
print(one_arg, end='')
- print(') = (void *) %d;' % len(self.seen_helpers))
+ print(') = (void *) %d;' % helper.enum_val)
print('')
###############################################################################
@@ -589,8 +858,13 @@ script = os.path.abspath(sys.argv[0])
linuxRoot = os.path.dirname(os.path.dirname(script))
bpfh = os.path.join(linuxRoot, 'include/uapi/linux/bpf.h')
+printers = {
+ 'helpers': PrinterHelpersRST,
+ 'syscall': PrinterSyscallRST,
+}
+
argParser = argparse.ArgumentParser(description="""
-Parse eBPF header file and generate documentation for eBPF helper functions.
+Parse eBPF header file and generate documentation for the eBPF API.
The RST-formatted output produced can be turned into a manual page with the
rst2man utility.
""")
@@ -601,6 +875,8 @@ if (os.path.isfile(bpfh)):
default=bpfh)
else:
argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h')
+argParser.add_argument('target', nargs='?', default='helpers',
+ choices=printers.keys(), help='eBPF API target')
args = argParser.parse_args()
# Parse file.
@@ -609,7 +885,9 @@ headerParser.run()
# Print formatted output to standard output.
if args.header:
- printer = PrinterHelpers(headerParser.helpers)
+ if args.target != 'helpers':
+ raise NotImplementedError('Only helpers header generation is supported')
+ printer = PrinterHelpers(headerParser)
else:
- printer = PrinterRST(headerParser.helpers)
+ printer = printers[args.target](headerParser)
printer.print_all()
diff --git a/scripts/cc-version.sh b/scripts/cc-version.sh
index 3f2ee885b116..a7e28b6a514e 100755
--- a/scripts/cc-version.sh
+++ b/scripts/cc-version.sh
@@ -1,31 +1,17 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
-# Print the compiler name and its version in a 5 or 6-digit form.
+# Print the C compiler name and its version in a 5 or 6-digit form.
# Also, perform the minimum version check.
set -e
-# When you raise the minimum compiler version, please update
-# Documentation/process/changes.rst as well.
-gcc_min_version=4.9.0
-clang_min_version=10.0.1
-icc_min_version=16.0.3 # temporary
-
-# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63293
-# https://lore.kernel.org/r/20210107111841.GN1551@shell.armlinux.org.uk
-if [ "$SRCARCH" = arm64 ]; then
- gcc_min_version=5.1.0
-fi
-
-# Print the compiler name and some version components.
-get_compiler_info()
+# Print the C compiler name and some version components.
+get_c_compiler_info()
{
cat <<- EOF | "$@" -E -P -x c - 2>/dev/null
#if defined(__clang__)
Clang __clang_major__ __clang_minor__ __clang_patchlevel__
- #elif defined(__INTEL_COMPILER)
- ICC __INTEL_COMPILER __INTEL_COMPILER_UPDATE
#elif defined(__GNUC__)
GCC __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
#else
@@ -44,25 +30,23 @@ get_canonical_version()
# $@ instead of $1 because multiple words might be given, e.g. CC="ccache gcc".
orig_args="$@"
-set -- $(get_compiler_info "$@")
+set -- $(get_c_compiler_info "$@")
name=$1
+min_tool_version=$(dirname $0)/min-tool-version.sh
+
case "$name" in
GCC)
version=$2.$3.$4
- min_version=$gcc_min_version
+ min_version=$($min_tool_version gcc)
;;
Clang)
version=$2.$3.$4
- min_version=$clang_min_version
- ;;
-ICC)
- version=$(($2 / 100)).$(($2 % 100)).$3
- min_version=$icc_min_version
+ min_version=$($min_tool_version llvm)
;;
*)
- echo "$orig_args: unknown compiler" >&2
+ echo "$orig_args: unknown C compiler" >&2
exit 1
;;
esac
@@ -72,7 +56,7 @@ min_cversion=$(get_canonical_version $min_version)
if [ "$cversion" -lt "$min_cversion" ]; then
echo >&2 "***"
- echo >&2 "*** Compiler is too old."
+ echo >&2 "*** C compiler is too old."
echo >&2 "*** Your $name version: $version"
echo >&2 "*** Minimum $name version: $min_version"
echo >&2 "***"
diff --git a/scripts/check-git b/scripts/check-git
new file mode 100755
index 000000000000..2ca6c5df10dd
--- /dev/null
+++ b/scripts/check-git
@@ -0,0 +1,14 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# succeed if we are in a git repository
+
+srctree="$(dirname $0)/.."
+
+if ! git -C "${srctree}" rev-parse --verify HEAD >/dev/null 2>/dev/null; then
+ exit 1
+fi
+
+if ! test -z $(git -C "${srctree}" rev-parse --show-cdup 2>/dev/null); then
+ exit 1
+fi
diff --git a/scripts/check-sysctl-docs b/scripts/check-sysctl-docs
index 8bcb9e26c7bc..4f163e0bf6a4 100755
--- a/scripts/check-sysctl-docs
+++ b/scripts/check-sysctl-docs
@@ -146,32 +146,6 @@ curtable && /\.procname[\t ]*=[\t ]*".+"/ {
children[curtable][curentry] = child
}
-/register_sysctl_table\(.*\)/ {
- match($0, /register_sysctl_table\(([^)]+)\)/, tables)
- if (debug) print "Registering table " tables[1]
- if (children[tables[1]][table]) {
- for (entry in entries[children[tables[1]][table]]) {
- printentry(entry)
- }
- }
-}
-
-/register_sysctl_paths\(.*\)/ {
- match($0, /register_sysctl_paths\(([^)]+), ([^)]+)\)/, tables)
- if (debug) print "Attaching table " tables[2] " to path " tables[1]
- if (paths[tables[1]] == table) {
- for (entry in entries[tables[2]]) {
- printentry(entry)
- }
- }
- split(paths[tables[1]], components, "/")
- if (length(components) > 1 && components[1] == table) {
- # Count the first subdirectory as seen
- seen[components[2]]++
- }
-}
-
-
END {
for (entry in documented) {
if (!seen[entry]) {
diff --git a/scripts/check_extable.sh b/scripts/check_extable.sh
index 93af93c7b346..4b380564cf74 100755
--- a/scripts/check_extable.sh
+++ b/scripts/check_extable.sh
@@ -4,7 +4,7 @@
obj=$1
-file ${obj} | grep -q ELF || (echo "${obj} is not and ELF file." 1>&2 ; exit 0)
+file ${obj} | grep -q ELF || (echo "${obj} is not an ELF file." 1>&2 ; exit 0)
# Bail out early if there isn't an __ex_table section in this object file.
objdump -hj __ex_table ${obj} 2> /dev/null > /dev/null
diff --git a/scripts/checkdeclares.pl b/scripts/checkdeclares.pl
new file mode 100755
index 000000000000..f6d551c84fc6
--- /dev/null
+++ b/scripts/checkdeclares.pl
@@ -0,0 +1,53 @@
+#!/usr/bin/env perl
+# SPDX-License-Identifier: GPL-2.0
+#
+# checkdeclares: find struct declared more than once
+#
+# Copyright 2021 Wan Jiabing<wanjiabing@vivo.com>
+# Inspired by checkincludes.pl
+#
+# This script checks for duplicate struct declares.
+# Note that this will not take into consideration macros so
+# you should run this only if you know you do have real dups
+# and do not have them under #ifdef's.
+# You could also just review the results.
+
+use strict;
+
+sub usage {
+ print "Usage: checkdeclares.pl file1.h ...\n";
+ print "Warns of struct declaration duplicates\n";
+ exit 1;
+}
+
+if ($#ARGV < 0) {
+ usage();
+}
+
+my $dup_counter = 0;
+
+foreach my $file (@ARGV) {
+ open(my $f, '<', $file)
+ or die "Cannot open $file: $!.\n";
+
+ my %declaredstructs = ();
+
+ while (<$f>) {
+ if (m/^\s*struct\s*(\w*);$/o) {
+ ++$declaredstructs{$1};
+ }
+ }
+
+ close($f);
+
+ foreach my $structname (keys %declaredstructs) {
+ if ($declaredstructs{$structname} > 1) {
+ print "$file: struct $structname is declared more than once.\n";
+ ++$dup_counter;
+ }
+ }
+}
+
+if ($dup_counter == 0) {
+ print "No duplicate struct declares found.\n";
+}
diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py
index 1548f9ce4682..36c920e71313 100755
--- a/scripts/checkkconfigsymbols.py
+++ b/scripts/checkkconfigsymbols.py
@@ -34,7 +34,6 @@ REGEX_SOURCE_SYMBOL = re.compile(SOURCE_SYMBOL)
REGEX_KCONFIG_DEF = re.compile(DEF)
REGEX_KCONFIG_EXPR = re.compile(EXPR)
REGEX_KCONFIG_STMT = re.compile(STMT)
-REGEX_KCONFIG_HELP = re.compile(r"^\s+help\s*$")
REGEX_FILTER_SYMBOLS = re.compile(r"[A-Za-z0-9]$")
REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+")
REGEX_QUOTES = re.compile("(\"(.*?)\")")
@@ -102,6 +101,9 @@ def parse_options():
"continue.")
if args.commit:
+ if args.commit.startswith('HEAD'):
+ sys.exit("The --commit option can't use the HEAD ref")
+
args.find = False
if args.ignore:
@@ -113,7 +115,7 @@ def parse_options():
return args
-def main():
+def print_undefined_symbols():
"""Main function of this module."""
args = parse_options()
@@ -329,7 +331,7 @@ def check_symbols_helper(pool, ignore):
if REGEX_FILE_KCONFIG.match(gitfile):
kconfig_files.append(gitfile)
else:
- if ignore and not re.match(ignore, gitfile):
+ if ignore and re.match(ignore, gitfile):
continue
# add source files that do not match the ignore pattern
source_files.append(gitfile)
@@ -432,7 +434,6 @@ def parse_kconfig_file(kfile):
lines = []
defined = []
references = []
- skip = False
if not os.path.exists(kfile):
return defined, references
@@ -448,12 +449,6 @@ def parse_kconfig_file(kfile):
if REGEX_KCONFIG_DEF.match(line):
symbol_def = REGEX_KCONFIG_DEF.findall(line)
defined.append(symbol_def[0])
- skip = False
- elif REGEX_KCONFIG_HELP.match(line):
- skip = True
- elif skip:
- # ignore content of help messages
- pass
elif REGEX_KCONFIG_STMT.match(line):
line = REGEX_QUOTES.sub("", line)
symbols = get_symbols_in_line(line)
@@ -472,5 +467,16 @@ def parse_kconfig_file(kfile):
return defined, references
+def main():
+ try:
+ print_undefined_symbols()
+ except BrokenPipeError:
+ # Python flushes standard streams on exit; redirect remaining output
+ # to devnull to avoid another BrokenPipeError at shutdown
+ devnull = os.open(os.devnull, os.O_WRONLY)
+ os.dup2(devnull, sys.stdout.fileno())
+ sys.exit(1) # Python exits with error code 1 on EPIPE
+
+
if __name__ == "__main__":
main()
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index df8b23dc1eb0..880fde13d9b8 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -23,6 +23,9 @@ my $V = '0.32';
use Getopt::Long qw(:config no_auto_abbrev);
my $quiet = 0;
+my $verbose = 0;
+my %verbose_messages = ();
+my %verbose_emitted = ();
my $tree = 1;
my $chk_signoff = 1;
my $chk_patch = 1;
@@ -60,7 +63,9 @@ my $min_conf_desc_length = 4;
my $spelling_file = "$D/spelling.txt";
my $codespell = 0;
my $codespellfile = "/usr/share/codespell/dictionary.txt";
+my $user_codespellfile = "";
my $conststructsfile = "$D/const_structs.checkpatch";
+my $docsfile = "$D/../Documentation/dev-tools/checkpatch.rst";
my $typedefsfile;
my $color = "auto";
my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE
@@ -78,6 +83,7 @@ Version: $V
Options:
-q, --quiet quiet
+ -v, --verbose verbose mode
--no-tree run without a kernel tree
--no-signoff do not check for 'Signed-off-by' line
--patch treat FILE as patchfile (default)
@@ -125,7 +131,7 @@ Options:
--ignore-perl-version override checking of perl version. expect
runtime errors.
--codespell Use the codespell dictionary for spelling/typos
- (default:/usr/share/codespell/dictionary.txt)
+ (default:$codespellfile)
--codespellfile Use this codespell dictionary
--typedefsfile Read additional types from this file
--color[=WHEN] Use colors 'always', 'never', or only when output
@@ -158,15 +164,51 @@ sub list_types {
my $text = <$script>;
close($script);
- my @types = ();
+ my %types = ();
# Also catch when type or level is passed through a variable
- for ($text =~ /(?:(?:\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) {
- push (@types, $_);
+ while ($text =~ /(?:(\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) {
+ if (defined($1)) {
+ if (exists($types{$2})) {
+ $types{$2} .= ",$1" if ($types{$2} ne $1);
+ } else {
+ $types{$2} = $1;
+ }
+ } else {
+ $types{$2} = "UNDETERMINED";
+ }
}
- @types = sort(uniq(@types));
+
print("#\tMessage type\n\n");
- foreach my $type (@types) {
+ if ($color) {
+ print(" ( Color coding: ");
+ print(RED . "ERROR" . RESET);
+ print(" | ");
+ print(YELLOW . "WARNING" . RESET);
+ print(" | ");
+ print(GREEN . "CHECK" . RESET);
+ print(" | ");
+ print("Multiple levels / Undetermined");
+ print(" )\n\n");
+ }
+
+ foreach my $type (sort keys %types) {
+ my $orig_type = $type;
+ if ($color) {
+ my $level = $types{$type};
+ if ($level eq "ERROR") {
+ $type = RED . $type . RESET;
+ } elsif ($level eq "WARN") {
+ $type = YELLOW . $type . RESET;
+ } elsif ($level eq "CHK") {
+ $type = GREEN . $type . RESET;
+ }
+ }
print(++$count . "\t" . $type . "\n");
+ if ($verbose && exists($verbose_messages{$orig_type})) {
+ my $message = $verbose_messages{$orig_type};
+ $message =~ s/\n/\n\t/g;
+ print("\t" . $message . "\n\n");
+ }
}
exit($exitcode);
@@ -198,6 +240,46 @@ if (-f $conf) {
unshift(@ARGV, @conf_args) if @conf_args;
}
+sub load_docs {
+ open(my $docs, '<', "$docsfile")
+ or warn "$P: Can't read the documentation file $docsfile $!\n";
+
+ my $type = '';
+ my $desc = '';
+ my $in_desc = 0;
+
+ while (<$docs>) {
+ chomp;
+ my $line = $_;
+ $line =~ s/\s+$//;
+
+ if ($line =~ /^\s*\*\*(.+)\*\*$/) {
+ if ($desc ne '') {
+ $verbose_messages{$type} = trim($desc);
+ }
+ $type = $1;
+ $desc = '';
+ $in_desc = 1;
+ } elsif ($in_desc) {
+ if ($line =~ /^(?:\s{4,}|$)/) {
+ $line =~ s/^\s{4}//;
+ $desc .= $line;
+ $desc .= "\n";
+ } else {
+ $verbose_messages{$type} = trim($desc);
+ $type = '';
+ $desc = '';
+ $in_desc = 0;
+ }
+ }
+ }
+
+ if ($desc ne '') {
+ $verbose_messages{$type} = trim($desc);
+ }
+ close($docs);
+}
+
# Perl's Getopt::Long allows options to take optional arguments after a space.
# Prevent --color by itself from consuming other arguments
foreach (@ARGV) {
@@ -208,6 +290,7 @@ foreach (@ARGV) {
GetOptions(
'q|quiet+' => \$quiet,
+ 'v|verbose!' => \$verbose,
'tree!' => \$tree,
'signoff!' => \$chk_signoff,
'patch!' => \$chk_patch,
@@ -235,7 +318,7 @@ GetOptions(
'debug=s' => \%debug,
'test-only=s' => \$tst_only,
'codespell!' => \$codespell,
- 'codespellfile=s' => \$codespellfile,
+ 'codespellfile=s' => \$user_codespellfile,
'typedefsfile=s' => \$typedefsfile,
'color=s' => \$color,
'no-color' => \$color, #keep old behaviors of -nocolor
@@ -243,17 +326,54 @@ GetOptions(
'kconfig-prefix=s' => \${CONFIG_},
'h|help' => \$help,
'version' => \$help
-) or help(1);
+) or $help = 2;
+
+if ($user_codespellfile) {
+ # Use the user provided codespell file unconditionally
+ $codespellfile = $user_codespellfile;
+} elsif (!(-f $codespellfile)) {
+ # If /usr/share/codespell/dictionary.txt is not present, try to find it
+ # under codespell's install directory: <codespell_root>/data/dictionary.txt
+ if (($codespell || $help) && which("python3") ne "") {
+ my $python_codespell_dict = << "EOF";
+
+import os.path as op
+import codespell_lib
+codespell_dir = op.dirname(codespell_lib.__file__)
+codespell_file = op.join(codespell_dir, 'data', 'dictionary.txt')
+print(codespell_file, end='')
+EOF
+
+ my $codespell_dict = `python3 -c "$python_codespell_dict" 2> /dev/null`;
+ $codespellfile = $codespell_dict if (-f $codespell_dict);
+ }
+}
+
+# $help is 1 if either -h, --help or --version is passed as option - exitcode: 0
+# $help is 2 if invalid option is passed - exitcode: 1
+help($help - 1) if ($help);
-help(0) if ($help);
+die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix));
+die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse);
+if ($color =~ /^[01]$/) {
+ $color = !$color;
+} elsif ($color =~ /^always$/i) {
+ $color = 1;
+} elsif ($color =~ /^never$/i) {
+ $color = 0;
+} elsif ($color =~ /^auto$/i) {
+ $color = (-t STDOUT);
+} else {
+ die "$P: Invalid color mode: $color\n";
+}
+
+load_docs() if ($verbose);
list_types(0) if ($list_types);
$fix = 1 if ($fix_inplace);
$check_orig = $check;
-die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix));
-
my $exit = 0;
my $perl_version_ok = 1;
@@ -268,18 +388,6 @@ if ($#ARGV < 0) {
push(@ARGV, '-');
}
-if ($color =~ /^[01]$/) {
- $color = !$color;
-} elsif ($color =~ /^always$/i) {
- $color = 1;
-} elsif ($color =~ /^never$/i) {
- $color = 0;
-} elsif ($color =~ /^auto$/i) {
- $color = (-t STDOUT);
-} else {
- die "$P: Invalid color mode: $color\n";
-}
-
# skip TAB size 1 to avoid additional checks on $tabsize - 1
die "$P: Invalid TAB size: $tabsize\n" if ($tabsize < 2);
@@ -405,7 +513,8 @@ our $Attribute = qr{
____cacheline_aligned|
____cacheline_aligned_in_smp|
____cacheline_internodealigned_in_smp|
- __weak
+ __weak|
+ __alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\)
}x;
our $Modifier;
our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__};
@@ -417,7 +526,7 @@ our $Binary = qr{(?i)0b[01]+$Int_type?};
our $Hex = qr{(?i)0x[0-9a-f]+$Int_type?};
our $Int = qr{[0-9]+$Int_type?};
our $Octal = qr{0[0-7]+$Int_type?};
-our $String = qr{"[X\t]*"};
+our $String = qr{(?:\b[Lu])?"[X\t]*"};
our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?};
our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?};
our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?};
@@ -467,10 +576,14 @@ our $typeKernelTypedefs = qr{(?x:
(?:__)?(?:u|s|be|le)(?:8|16|32|64)|
atomic_t
)};
+our $typeStdioTypedefs = qr{(?x:
+ FILE
+)};
our $typeTypedefs = qr{(?x:
$typeC99Typedefs\b|
$typeOtherOSTypedefs\b|
- $typeKernelTypedefs\b
+ $typeKernelTypedefs\b|
+ $typeStdioTypedefs\b
)};
our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b};
@@ -507,6 +620,22 @@ our $signature_tags = qr{(?xi:
Cc:
)};
+our @link_tags = qw(Link Closes);
+
+#Create a search and print patterns for all these strings to be used directly below
+our $link_tags_search = "";
+our $link_tags_print = "";
+foreach my $entry (@link_tags) {
+ if ($link_tags_search ne "") {
+ $link_tags_search .= '|';
+ $link_tags_print .= ' or ';
+ }
+ $entry .= ':';
+ $link_tags_search .= $entry;
+ $link_tags_print .= "'$entry'";
+}
+$link_tags_search = "(?:${link_tags_search})";
+
our $tracing_logging_tags = qr{(?xi:
[=-]*> |
<[=-]* |
@@ -589,6 +718,17 @@ sub find_standard_signature {
return "";
}
+our $obsolete_archives = qr{(?xi:
+ \Qfreedesktop.org/archives/dri-devel\E |
+ \Qlists.infradead.org\E |
+ \Qlkml.org\E |
+ \Qmail-archive.com\E |
+ \Qmailman.alsa-project.org/pipermail\E |
+ \Qmarc.info\E |
+ \Qozlabs.org/pipermail\E |
+ \Qspinics.net\E
+)};
+
our @typeListMisordered = (
qr{char\s+(?:un)?signed},
qr{int\s+(?:(?:un)?signed\s+)?short\s},
@@ -698,6 +838,10 @@ our %deprecated_apis = (
"rcu_barrier_sched" => "rcu_barrier",
"get_state_synchronize_sched" => "get_state_synchronize_rcu",
"cond_synchronize_sched" => "cond_synchronize_rcu",
+ "kmap" => "kmap_local_page",
+ "kunmap" => "kunmap_local",
+ "kmap_atomic" => "kmap_local_page",
+ "kunmap_atomic" => "kunmap_local",
);
#Create a search pattern for all these strings to speed up a loop below
@@ -933,7 +1077,8 @@ our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)};
our $declaration_macros = qr{(?x:
(?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(|
(?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(|
- (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(
+ (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(|
+ (?:$Storage\s+)?(?:XA_STATE|XA_STATE_ORDER)\s*\(
)};
our %allow_repeated_words = (
@@ -1000,10 +1145,10 @@ sub is_maintained_obsolete {
sub is_SPDX_License_valid {
my ($license) = @_;
- return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$gitroot"));
+ return 1 if (!$tree || which("python3") eq "" || !(-x "$root/scripts/spdxcheck.py") || !(-e "$gitroot"));
my $root_path = abs_path($root);
- my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`;
+ my $status = `cd "$root_path"; echo "$license" | scripts/spdxcheck.py -`;
return 0 if ($status ne "");
return 1;
}
@@ -1097,7 +1242,8 @@ sub git_commit_info {
# git log --format='%H %s' -1 $line |
# echo "commit $(cut -c 1-12,41-)"
# done
- } elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./) {
+ } elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./ ||
+ $lines[0] =~ /^fatal: bad object $commit/) {
$id = undef;
} else {
$id = substr($lines[0], 0, 12);
@@ -2209,7 +2355,16 @@ sub report {
splice(@lines, 1, 1);
$output = join("\n", @lines);
}
- $output = (split('\n', $output))[0] . "\n" if ($terse);
+
+ if ($terse) {
+ $output = (split('\n', $output))[0] . "\n";
+ }
+
+ if ($verbose && exists($verbose_messages{$type}) &&
+ !exists($verbose_emitted{$type})) {
+ $output .= $verbose_messages{$type} . "\n\n";
+ $verbose_emitted{$type} = 1;
+ }
push(our @report, $output);
@@ -2494,6 +2649,8 @@ sub process {
my $reported_maintainer_file = 0;
my $non_utf8_charset = 0;
+ my $last_git_commit_id_linenr = -1;
+
my $last_blank_line = 0;
my $last_coalesced_string_linenr = -1;
@@ -2816,10 +2973,10 @@ sub process {
my ($email_name, $email_comment, $email_address, $comment1) = parse_email($ctx);
my ($author_name, $author_comment, $author_address, $comment2) = parse_email($author);
- if ($email_address eq $author_address && $email_name eq $author_name) {
+ if (lc $email_address eq lc $author_address && $email_name eq $author_name) {
$author_sob = $ctx;
$authorsignoff = 2;
- } elsif ($email_address eq $author_address) {
+ } elsif (lc $email_address eq lc $author_address) {
$author_sob = $ctx;
$authorsignoff = 3;
} elsif ($email_name eq $author_name) {
@@ -3003,17 +3160,73 @@ sub process {
if ($sign_off =~ /^co-developed-by:$/i) {
if ($email eq $author) {
WARN("BAD_SIGN_OFF",
- "Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . "$here\n" . $rawline);
+ "Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . $herecurr);
}
if (!defined $lines[$linenr]) {
WARN("BAD_SIGN_OFF",
- "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline);
- } elsif ($rawlines[$linenr] !~ /^\s*signed-off-by:\s*(.*)/i) {
+ "Co-developed-by: must be immediately followed by Signed-off-by:\n" . $herecurr);
+ } elsif ($rawlines[$linenr] !~ /^signed-off-by:\s*(.*)/i) {
WARN("BAD_SIGN_OFF",
- "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]);
+ "Co-developed-by: must be immediately followed by Signed-off-by:\n" . $herecurr . $rawlines[$linenr] . "\n");
} elsif ($1 ne $email) {
WARN("BAD_SIGN_OFF",
- "Co-developed-by and Signed-off-by: name/email do not match \n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]);
+ "Co-developed-by and Signed-off-by: name/email do not match\n" . $herecurr . $rawlines[$linenr] . "\n");
+ }
+ }
+
+# check if Reported-by: is followed by a Closes: tag
+ if ($sign_off =~ /^reported(?:|-and-tested)-by:$/i) {
+ if (!defined $lines[$linenr]) {
+ WARN("BAD_REPORTED_BY_LINK",
+ "Reported-by: should be immediately followed by Closes: with a URL to the report\n" . $herecurr . "\n");
+ } elsif ($rawlines[$linenr] !~ /^closes:\s*/i) {
+ WARN("BAD_REPORTED_BY_LINK",
+ "Reported-by: should be immediately followed by Closes: with a URL to the report\n" . $herecurr . $rawlines[$linenr] . "\n");
+ }
+ }
+ }
+
+
+# Check Fixes: styles is correct
+ if (!$in_header_lines &&
+ $line =~ /^\s*fixes:?\s*(?:commit\s*)?[0-9a-f]{5,}\b/i) {
+ my $orig_commit = "";
+ my $id = "0123456789ab";
+ my $title = "commit title";
+ my $tag_case = 1;
+ my $tag_space = 1;
+ my $id_length = 1;
+ my $id_case = 1;
+ my $title_has_quotes = 0;
+
+ if ($line =~ /(\s*fixes:?)\s+([0-9a-f]{5,})\s+($balanced_parens)/i) {
+ my $tag = $1;
+ $orig_commit = $2;
+ $title = $3;
+
+ $tag_case = 0 if $tag eq "Fixes:";
+ $tag_space = 0 if ($line =~ /^fixes:? [0-9a-f]{5,} ($balanced_parens)/i);
+
+ $id_length = 0 if ($orig_commit =~ /^[0-9a-f]{12}$/i);
+ $id_case = 0 if ($orig_commit !~ /[A-F]/);
+
+ # Always strip leading/trailing parens then double quotes if existing
+ $title = substr($title, 1, -1);
+ if ($title =~ /^".*"$/) {
+ $title = substr($title, 1, -1);
+ $title_has_quotes = 1;
+ }
+ }
+
+ my ($cid, $ctitle) = git_commit_info($orig_commit, $id,
+ $title);
+
+ if ($ctitle ne $title || $tag_case || $tag_space ||
+ $id_length || $id_case || !$title_has_quotes) {
+ if (WARN("BAD_FIXES_TAG",
+ "Please use correct Fixes: style 'Fixes: <12 chars of sha1> (\"<title line>\")' - ie: 'Fixes: $cid (\"$ctitle\")'\n" . $herecurr) &&
+ $fix) {
+ $fixed[$fixlinenr] = "Fixes: $cid (\"$ctitle\")";
}
}
}
@@ -3051,10 +3264,10 @@ sub process {
length($line) > 75 &&
!($line =~ /^\s*[a-zA-Z0-9_\/\.]+\s+\|\s+\d+/ ||
# file delta changes
- $line =~ /^\s*(?:[\w\.\-]+\/)++[\w\.\-]+:/ ||
+ $line =~ /^\s*(?:[\w\.\-\+]*\/)++[\w\.\-\+]+:/ ||
# filename then :
- $line =~ /^\s*(?:Fixes:|Link:|$signature_tags)/i ||
- # A Fixes: or Link: line or signature tag line
+ $line =~ /^\s*(?:Fixes:|$link_tags_search|$signature_tags)/i ||
+ # A Fixes:, link or signature tag line
$commit_log_possible_stack_dump)) {
WARN("COMMIT_LOG_LONG_LINE",
"Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr);
@@ -3067,6 +3280,29 @@ sub process {
$commit_log_possible_stack_dump = 0;
}
+# Check for odd tags before a URI/URL
+ if ($in_commit_log &&
+ $line =~ /^\s*(\w+:)\s*http/ && $1 !~ /^$link_tags_search$/) {
+ if ($1 =~ /^v(?:ersion)?\d+/i) {
+ WARN("COMMIT_LOG_VERSIONING",
+ "Patch version information should be after the --- line\n" . $herecurr);
+ } else {
+ WARN("COMMIT_LOG_USE_LINK",
+ "Unknown link reference '$1', use $link_tags_print instead\n" . $herecurr);
+ }
+ }
+
+# Check for misuse of the link tags
+ if ($in_commit_log &&
+ $line =~ /^\s*(\w+:)\s*(\S+)/) {
+ my $tag = $1;
+ my $value = $2;
+ if ($tag =~ /^$link_tags_search$/ && $value !~ m{^https?://}) {
+ WARN("COMMIT_LOG_WRONG_LINK",
+ "'$tag' should be followed by a public http(s) link\n" . $herecurr);
+ }
+ }
+
# Check for lines starting with a #
if ($in_commit_log && $line =~ /^#/) {
if (WARN("COMMIT_COMMENT_SYMBOL",
@@ -3077,10 +3313,20 @@ sub process {
}
# Check for git id commit length and improperly formed commit descriptions
- if ($in_commit_log && !$commit_log_possible_stack_dump &&
+# A correctly formed commit description is:
+# commit <SHA-1 hash length 12+ chars> ("Complete commit subject")
+# with the commit subject '("' prefix and '")' suffix
+# This is a fairly compilicated block as it tests for what appears to be
+# bare SHA-1 hash with minimum length of 5. It also avoids several types of
+# possible SHA-1 matches.
+# A commit match can span multiple lines so this block attempts to find a
+# complete typical commit on a maximum of 3 lines
+ if ($perl_version_ok &&
+ $in_commit_log && !$commit_log_possible_stack_dump &&
$line !~ /^\s*(?:Link|Patchwork|http|https|BugLink|base-commit):/i &&
$line !~ /^This reverts commit [0-9a-f]{7,40}/ &&
- ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i ||
+ (($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i ||
+ ($line =~ /\bcommit\s*$/i && defined($rawlines[$linenr]) && $rawlines[$linenr] =~ /^\s*[0-9a-f]{5,}\b/i)) ||
($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i &&
$line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i &&
$line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) {
@@ -3090,49 +3336,62 @@ sub process {
my $long = 0;
my $case = 1;
my $space = 1;
- my $hasdesc = 0;
- my $hasparens = 0;
my $id = '0123456789ab';
my $orig_desc = "commit description";
my $description = "";
+ my $herectx = $herecurr;
+ my $has_parens = 0;
+ my $has_quotes = 0;
+
+ my $input = $line;
+ if ($line =~ /(?:\bcommit\s+[0-9a-f]{5,}|\bcommit\s*$)/i) {
+ for (my $n = 0; $n < 2; $n++) {
+ if ($input =~ /\bcommit\s+[0-9a-f]{5,}\s*($balanced_parens)/i) {
+ $orig_desc = $1;
+ $has_parens = 1;
+ # Always strip leading/trailing parens then double quotes if existing
+ $orig_desc = substr($orig_desc, 1, -1);
+ if ($orig_desc =~ /^".*"$/) {
+ $orig_desc = substr($orig_desc, 1, -1);
+ $has_quotes = 1;
+ }
+ last;
+ }
+ last if ($#lines < $linenr + $n);
+ $input .= " " . trim($rawlines[$linenr + $n]);
+ $herectx .= "$rawlines[$linenr + $n]\n";
+ }
+ $herectx = $herecurr if (!$has_parens);
+ }
- if ($line =~ /\b(c)ommit\s+([0-9a-f]{5,})\b/i) {
+ if ($input =~ /\b(c)ommit\s+([0-9a-f]{5,})\b/i) {
$init_char = $1;
$orig_commit = lc($2);
- } elsif ($line =~ /\b([0-9a-f]{12,40})\b/i) {
+ $short = 0 if ($input =~ /\bcommit\s+[0-9a-f]{12,40}/i);
+ $long = 1 if ($input =~ /\bcommit\s+[0-9a-f]{41,}/i);
+ $space = 0 if ($input =~ /\bcommit [0-9a-f]/i);
+ $case = 0 if ($input =~ /\b[Cc]ommit\s+[0-9a-f]{5,40}[^A-F]/);
+ } elsif ($input =~ /\b([0-9a-f]{12,40})\b/i) {
$orig_commit = lc($1);
}
- $short = 0 if ($line =~ /\bcommit\s+[0-9a-f]{12,40}/i);
- $long = 1 if ($line =~ /\bcommit\s+[0-9a-f]{41,}/i);
- $space = 0 if ($line =~ /\bcommit [0-9a-f]/i);
- $case = 0 if ($line =~ /\b[Cc]ommit\s+[0-9a-f]{5,40}[^A-F]/);
- if ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)"\)/i) {
- $orig_desc = $1;
- $hasparens = 1;
- } elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s*$/i &&
- defined $rawlines[$linenr] &&
- $rawlines[$linenr] =~ /^\s*\("([^"]+)"\)/) {
- $orig_desc = $1;
- $hasparens = 1;
- } elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("[^"]+$/i &&
- defined $rawlines[$linenr] &&
- $rawlines[$linenr] =~ /^\s*[^"]+"\)/) {
- $line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)$/i;
- $orig_desc = $1;
- $rawlines[$linenr] =~ /^\s*([^"]+)"\)/;
- $orig_desc .= " " . $1;
- $hasparens = 1;
- }
-
($id, $description) = git_commit_info($orig_commit,
$id, $orig_desc);
if (defined($id) &&
- ($short || $long || $space || $case || ($orig_desc ne $description) || !$hasparens)) {
+ ($short || $long || $space || $case || ($orig_desc ne $description) || !$has_quotes) &&
+ $last_git_commit_id_linenr != $linenr - 1) {
ERROR("GIT_COMMIT_ID",
- "Please use git commit description style 'commit <12+ chars of sha1> (\"<title line>\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herecurr);
+ "Please use git commit description style 'commit <12+ chars of sha1> (\"<title line>\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herectx);
}
+ #don't report the next line if this line ends in commit and the sha1 hash is the next line
+ $last_git_commit_id_linenr = $linenr if ($line =~ /\bcommit\s*$/i);
+ }
+
+# Check for mailing list archives other than lore.kernel.org
+ if ($rawline =~ m{http.*\b$obsolete_archives}) {
+ WARN("PREFER_LORE_ARCHIVE",
+ "Use lore.kernel.org archive links when possible - see https://lore.kernel.org/lists.html\n" . $herecurr);
}
# Check for added, moved or deleted files
@@ -3152,7 +3411,7 @@ sub process {
($line =~ /^new file mode\s*\d+\s*$/) &&
($realfile =~ m@^Documentation/devicetree/bindings/.*\.txt$@)) {
WARN("DT_SCHEMA_BINDING_PATCH",
- "DT bindings should be in DT schema format. See: Documentation/devicetree/writing-schema.rst\n");
+ "DT bindings should be in DT schema format. See: Documentation/devicetree/bindings/writing-schema.rst\n");
}
# Check for wrappage within a valid hunk of the file
@@ -3341,47 +3600,47 @@ sub process {
# Kconfig supports named choices), so use a word boundary
# (\b) rather than a whitespace character (\s)
$line =~ /^\+\s*(?:config|menuconfig|choice)\b/) {
- my $length = 0;
- my $cnt = $realcnt;
- my $ln = $linenr + 1;
- my $f;
- my $is_start = 0;
- my $is_end = 0;
- for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) {
- $f = $lines[$ln - 1];
- $cnt-- if ($lines[$ln - 1] !~ /^-/);
- $is_end = $lines[$ln - 1] =~ /^\+/;
+ my $ln = $linenr;
+ my $needs_help = 0;
+ my $has_help = 0;
+ my $help_length = 0;
+ while (defined $lines[$ln]) {
+ my $f = $lines[$ln++];
next if ($f =~ /^-/);
- last if (!$file && $f =~ /^\@\@/);
+ last if ($f !~ /^[\+ ]/); # !patch context
- if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) {
- $is_start = 1;
- } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) {
- $length = -1;
+ if ($f =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) {
+ $needs_help = 1;
+ next;
+ }
+ if ($f =~ /^\+\s*help\s*$/) {
+ $has_help = 1;
+ next;
}
- $f =~ s/^.//;
- $f =~ s/#.*//;
- $f =~ s/^\s+//;
- next if ($f =~ /^$/);
+ $f =~ s/^.//; # strip patch context [+ ]
+ $f =~ s/#.*//; # strip # directives
+ $f =~ s/^\s+//; # strip leading blanks
+ next if ($f =~ /^$/); # skip blank lines
+ # At the end of this Kconfig block:
# This only checks context lines in the patch
# and so hopefully shouldn't trigger false
# positives, even though some of these are
# common words in help texts
- if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice|
- if|endif|menu|endmenu|source)\b/x) {
- $is_end = 1;
+ if ($f =~ /^(?:config|menuconfig|choice|endchoice|
+ if|endif|menu|endmenu|source)\b/x) {
last;
}
- $length++;
+ $help_length++ if ($has_help);
}
- if ($is_start && $is_end && $length < $min_conf_desc_length) {
+ if ($needs_help &&
+ $help_length < $min_conf_desc_length) {
+ my $stat_real = get_stat_real($linenr, $ln - 1);
WARN("CONFIG_DESCRIPTION",
- "please write a paragraph that describes the config symbol fully\n" . $herecurr);
+ "please write a help paragraph that fully describes the config symbol\n" . "$here\n$stat_real\n");
}
- #print "is_start<$is_start> is_end<$is_end> length<$length>\n";
}
# check MAINTAINERS entries
@@ -3477,7 +3736,7 @@ sub process {
my $comment = "";
if ($realfile =~ /\.(h|s|S)$/) {
$comment = '/*';
- } elsif ($realfile =~ /\.(c|dts|dtsi)$/) {
+ } elsif ($realfile =~ /\.(c|rs|dts|dtsi)$/) {
$comment = '//';
} elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc|yaml)$/) {
$comment = '#';
@@ -3504,7 +3763,7 @@ sub process {
"'$spdx_license' is not supported in LICENSES/...\n" . $herecurr);
}
if ($realfile =~ m@^Documentation/devicetree/bindings/@ &&
- not $spdx_license =~ /GPL-2\.0.*BSD-2-Clause/) {
+ $spdx_license !~ /GPL-2\.0(?:-only)? OR BSD-2-Clause/) {
my $msg_level = \&WARN;
$msg_level = \&CHK if ($file);
if (&{$msg_level}("SPDX_LICENSE_TAG",
@@ -3514,18 +3773,23 @@ sub process {
$fixed[$fixlinenr] =~ s/SPDX-License-Identifier: .*/SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)/;
}
}
+ if ($realfile =~ m@^include/dt-bindings/@ &&
+ $spdx_license !~ /GPL-2\.0(?:-only)? OR \S+/) {
+ WARN("SPDX_LICENSE_TAG",
+ "DT binding headers should be licensed (GPL-2.0-only OR .*)\n" . $herecurr);
+ }
}
}
}
# check for embedded filenames
- if ($rawline =~ /^\+.*\Q$realfile\E/) {
+ if ($rawline =~ /^\+.*\b\Q$realfile\E\b/) {
WARN("EMBEDDED_FILENAME",
"It's generally not useful to have the filename in the file\n" . $herecurr);
}
# check we are in a valid source file if not then ignore this hunk
- next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/);
+ next if ($realfile !~ /\.(h|c|rs|s|S|sh|dtsi|dts)$/);
# check for using SPDX-License-Identifier on the wrong line number
if ($realline != $checklicenseline &&
@@ -3612,7 +3876,7 @@ sub process {
if ($realfile =~ /\.S$/ &&
$line =~ /^\+\s*(?:[A-Z]+_)?SYM_[A-Z]+_(?:START|END)(?:_[A-Z_]+)?\s*\(\s*\.L/) {
WARN("AVOID_L_PREFIX",
- "Avoid using '.L' prefixed local symbol names for denoting a range of code via 'SYM_*_START/END' annotations; see Documentation/asm-annotations.rst\n" . $herecurr);
+ "Avoid using '.L' prefixed local symbol names for denoting a range of code via 'SYM_*_START/END' annotations; see Documentation/core-api/asm-annotations.rst\n" . $herecurr);
}
# check we are in a valid source file C or perl if not then ignore this hunk
@@ -3788,7 +4052,7 @@ sub process {
if ($prevline =~ /^[\+ ]};?\s*$/ &&
$line =~ /^\+/ &&
!($line =~ /^\+\s*$/ ||
- $line =~ /^\+\s*EXPORT_SYMBOL/ ||
+ $line =~ /^\+\s*(?:EXPORT_SYMBOL|early_param)/ ||
$line =~ /^\+\s*MODULE_/i ||
$line =~ /^\+\s*\#\s*(?:end|elif|else)/ ||
$line =~ /^\+[a-z_]*init/ ||
@@ -4335,6 +4599,7 @@ sub process {
# XXX(foo);
# EXPORT_SYMBOL(something_foo);
my $name = $1;
+ $name =~ s/^\s*($Ident).*/$1/;
if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ &&
$name =~ /^${Ident}_$2/) {
#print "FOO C name<$name>\n";
@@ -4555,12 +4820,12 @@ sub process {
}
}
-# avoid BUG() or BUG_ON()
- if ($line =~ /\b(?:BUG|BUG_ON)\b/) {
+# do not use BUG() or variants
+ if ($line =~ /\b(?!AA_|BUILD_|DCCP_|IDA_|KVM_|RWLOCK_|snd_|SPIN_)(?:[a-zA-Z_]*_)?BUG(?:_ON)?(?:_[A-Z_]+)?\s*\(/) {
my $msg_level = \&WARN;
$msg_level = \&CHK if ($file);
&{$msg_level}("AVOID_BUG",
- "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr);
+ "Do not crash the kernel unless it is absolutely unavoidable--use WARN_ON_ONCE() plus recovery code (if feasible) instead of BUG() or variants\n" . $herecurr);
}
# avoid LINUX_VERSION_CODE
@@ -4781,7 +5046,7 @@ sub process {
if|for|while|switch|return|case|
volatile|__volatile__|
__attribute__|format|__extension__|
- asm|__asm__)$/x)
+ asm|__asm__|scoped_guard)$/x)
{
# cpp #define statements have non-optional spaces, ie
# if there is a space between the name and the open
@@ -5268,9 +5533,13 @@ sub process {
}
}
-#goto labels aren't indented, allow a single space however
- if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
- !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
+# check that goto labels aren't indented (allow a single space indentation)
+# and ignore bitfield definitions like foo:1
+# Strictly, labels can have whitespace after the identifier and before the :
+# but this is not allowed here as many ?: uses would appear to be labels
+ if ($sline =~ /^.\s+[A-Za-z_][A-Za-z\d_]*:(?!\s*\d+)/ &&
+ $sline !~ /^. [A-Za-z\d_][A-Za-z\d_]*:/ &&
+ $sline !~ /^.\s+default:/) {
if (WARN("INDENTED_LABEL",
"labels should not be indented\n" . $herecurr) &&
$fix) {
@@ -5365,7 +5634,7 @@ sub process {
# Return of what appears to be an errno should normally be negative
if ($sline =~ /\breturn(?:\s*\(+\s*|\s+)(E[A-Z]+)(?:\s*\)+\s*|\s*)[;:,]/) {
my $name = $1;
- if ($name ne 'EOF' && $name ne 'ERROR') {
+ if ($name ne 'EOF' && $name ne 'ERROR' && $name !~ /^EPOLL/) {
WARN("USE_NEGATIVE_ERRNO",
"return of an errno should typically be negative (ie: return -$1)\n" . $herecurr);
}
@@ -5408,6 +5677,7 @@ sub process {
defined($stat) && defined($cond) &&
$line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
my ($s, $c) = ($stat, $cond);
+ my $fixed_assign_in_if = 0;
if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
if (ERROR("ASSIGN_IN_IF",
@@ -5432,6 +5702,7 @@ sub process {
$newline .= ')';
$newline .= " {" if (defined($brace));
fix_insert_line($fixlinenr + 1, $newline);
+ $fixed_assign_in_if = 1;
}
}
}
@@ -5455,8 +5726,20 @@ sub process {
$stat_real = "[...]\n$stat_real";
}
- ERROR("TRAILING_STATEMENTS",
- "trailing statements should be on next line\n" . $herecurr . $stat_real);
+ if (ERROR("TRAILING_STATEMENTS",
+ "trailing statements should be on next line\n" . $herecurr . $stat_real) &&
+ !$fixed_assign_in_if &&
+ $cond_lines == 0 &&
+ $fix && $perl_version_ok &&
+ $fixed[$fixlinenr] =~ /^\+(\s*)((?:if|while|for)\s*$balanced_parens)\s*(.*)$/) {
+ my $indent = $1;
+ my $test = $2;
+ my $rest = rtrim($4);
+ if ($rest =~ /;$/) {
+ $fixed[$fixlinenr] = "\+$indent$test";
+ fix_insert_line($fixlinenr + 1, "$indent\t$rest");
+ }
+ }
}
}
@@ -5558,12 +5841,14 @@ sub process {
$var !~ /^(?:[A-Z]+_){1,5}[A-Z]{1,3}[a-z]/ &&
#Ignore Page<foo> variants
$var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
+#Ignore ETHTOOL_LINK_MODE_<foo> variants
+ $var !~ /^ETHTOOL_LINK_MODE_/ &&
#Ignore SI style variants like nS, mV and dB
#(ie: max_uV, regulator_min_uA_show, RANGE_mA_VALUE)
$var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ &&
#Ignore some three character SI units explicitly, like MiB and KHz
$var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) {
- while ($var =~ m{($Ident)}g) {
+ while ($var =~ m{\b($Ident)}g) {
my $word = $1;
next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/);
if ($check) {
@@ -5693,6 +5978,7 @@ sub process {
$dstat !~ /$exceptions/ &&
$dstat !~ /^\.$Ident\s*=/ && # .foo =
$dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo
+ $dstat !~ /^case\b/ && # case ...
$dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...)
$dstat !~ /^while\s*$Constant\s*$Constant\s*$/ && # while (...) {...}
$dstat !~ /^for\s*$Constant$/ && # for (...)
@@ -5736,7 +6022,7 @@ sub process {
next if ($arg =~ /\.\.\./);
next if ($arg =~ /^type$/i);
my $tmp_stmt = $define_stmt;
- $tmp_stmt =~ s/\b(sizeof|typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
+ $tmp_stmt =~ s/\b(__must_be_array|offsetof|sizeof|sizeof_field|__stringify|typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
$tmp_stmt =~ s/\#+\s*$arg\b//g;
$tmp_stmt =~ s/\b$arg\s*\#\#//g;
my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g;
@@ -6035,7 +6321,8 @@ sub process {
}
# concatenated string without spaces between elements
- if ($line =~ /$String[A-Za-z0-9_]/ || $line =~ /[A-Za-z0-9_]$String/) {
+ if ($line =~ /$String[A-Z_]/ ||
+ ($line =~ /([A-Za-z0-9_]+)$String/ && $1 !~ /^[Lu]$/)) {
if (CHK("CONCATENATED_STRING",
"Concatenated strings should use spaces between elements\n" . $herecurr) &&
$fix) {
@@ -6048,7 +6335,7 @@ sub process {
}
# uncoalesced string fragments
- if ($line =~ /$String\s*"/) {
+ if ($line =~ /$String\s*[Lu]?"/) {
if (WARN("STRING_FRAGMENTS",
"Consecutive strings are generally better as a single string\n" . $herecurr) &&
$fix) {
@@ -6135,6 +6422,15 @@ sub process {
}
}
+# check for soon-to-be-deprecated single-argument k[v]free_rcu() API
+ if ($line =~ /\bk[v]?free_rcu\s*\([^(]+\)/) {
+ if ($line =~ /\bk[v]?free_rcu\s*\([^,]+\)/) {
+ ERROR("DEPRECATED_API",
+ "Single-argument k[v]free_rcu() API is deprecated, please pass rcu_head object or call k[v]free_rcu_mightsleep()." . $herecurr);
+ }
+ }
+
+
# check for unnecessary "Out of Memory" messages
if ($line =~ /^\+.*\b$logFunctions\s*\(/ &&
$prevline =~ /^[ \+]\s*if\s*\(\s*(\!\s*|NULL\s*==\s*)?($Lval)(\s*==\s*NULL\s*)?\s*\)/ &&
@@ -6606,9 +6902,11 @@ sub process {
$specifier = $1;
$extension = $2;
$qualifier = $3;
- if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxtf]/ ||
+ if ($extension !~ /[4SsBKRraEehMmIiUDdgVCbGNOxtf]/ ||
($extension eq "f" &&
- defined $qualifier && $qualifier !~ /^w/)) {
+ defined $qualifier && $qualifier !~ /^w/) ||
+ ($extension eq "4" &&
+ defined $qualifier && $qualifier !~ /^cc/)) {
$bad_specifier = $specifier;
last;
}
@@ -6622,15 +6920,19 @@ sub process {
}
if ($bad_specifier ne "") {
my $stat_real = get_stat_real($linenr, $lc);
+ my $msg_level = \&WARN;
my $ext_type = "Invalid";
my $use = "";
if ($bad_specifier =~ /p[Ff]/) {
$use = " - use %pS instead";
$use =~ s/pS/ps/ if ($bad_specifier =~ /pf/);
+ } elsif ($bad_specifier =~ /pA/) {
+ $use = " - '%pA' is only intended to be used from Rust code";
+ $msg_level = \&ERROR;
}
- WARN("VSPRINTF_POINTER_EXTENSION",
- "$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n");
+ &{$msg_level}("VSPRINTF_POINTER_EXTENSION",
+ "$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n");
}
}
}
@@ -6695,10 +6997,22 @@ sub process {
# }
# }
+# strcpy uses that should likely be strscpy
+ if ($line =~ /\bstrcpy\s*\(/) {
+ WARN("STRCPY",
+ "Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88\n" . $herecurr);
+ }
+
# strlcpy uses that should likely be strscpy
if ($line =~ /\bstrlcpy\s*\(/) {
WARN("STRLCPY",
- "Prefer strscpy over strlcpy - see: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw\@mail.gmail.com/\n" . $herecurr);
+ "Prefer strscpy over strlcpy - see: https://github.com/KSPP/linux/issues/89\n" . $herecurr);
+ }
+
+# strncpy uses that should likely be strscpy or strscpy_pad
+ if ($line =~ /\bstrncpy\s*\(/) {
+ WARN("STRNCPY",
+ "Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr);
}
# typecasts on min/max could be min_t/max_t
@@ -6873,14 +7187,16 @@ sub process {
"Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr);
}
-# check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc
+# check for (kv|k)[mz]alloc with multiplies that could be kmalloc_array/kvmalloc_array/kvcalloc/kcalloc
if ($perl_version_ok &&
defined $stat &&
- $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
+ $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
my $oldfunc = $3;
my $a1 = $4;
my $a2 = $10;
my $newfunc = "kmalloc_array";
+ $newfunc = "kvmalloc_array" if ($oldfunc eq "kvmalloc");
+ $newfunc = "kvcalloc" if ($oldfunc eq "kvzalloc");
$newfunc = "kcalloc" if ($oldfunc eq "kzalloc");
my $r1 = $a1;
my $r2 = $a2;
@@ -6897,7 +7213,7 @@ sub process {
"Prefer $newfunc over $oldfunc with multiply\n" . $herectx) &&
$cnt == 1 &&
$fix) {
- $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e;
+ $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e;
}
}
}
@@ -6911,7 +7227,7 @@ sub process {
}
# check for alloc argument mismatch
- if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) {
+ if ($line =~ /\b((?:devm_)?((?:k|kv)?(calloc|malloc_array)(?:_node)?))\s*\(\s*sizeof\b/) {
WARN("ALLOC_ARRAY_ARGS",
"$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr);
}
@@ -7103,6 +7419,27 @@ sub process {
"Using $1 should generally have parentheses around the comparison\n" . $herecurr);
}
+# return sysfs_emit(foo, fmt, ...) fmt without newline
+ if ($line =~ /\breturn\s+sysfs_emit\s*\(\s*$FuncArg\s*,\s*($String)/ &&
+ substr($rawline, $-[6], $+[6] - $-[6]) !~ /\\n"$/) {
+ my $offset = $+[6] - 1;
+ if (WARN("SYSFS_EMIT",
+ "return sysfs_emit(...) formats should include a terminating newline\n" . $herecurr) &&
+ $fix) {
+ substr($fixed[$fixlinenr], $offset, 0) = '\\n';
+ }
+ }
+
+# check for array definition/declarations that should use flexible arrays instead
+ if ($sline =~ /^[\+ ]\s*\}(?:\s*__packed)?\s*;\s*$/ &&
+ $prevline =~ /^\+\s*(?:\}(?:\s*__packed\s*)?|$Type)\s*$Ident\s*\[\s*(0|1)\s*\]\s*;\s*$/) {
+ if (ERROR("FLEXIBLE_ARRAY",
+ "Use C99 flexible arrays - see https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays\n" . $hereprev) &&
+ $1 == '0' && $fix) {
+ $fixed[$fixlinenr - 1] =~ s/\[\s*0\s*\]/[]/;
+ }
+ }
+
# nested likely/unlikely calls
if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) {
WARN("LIKELY_MISUSE",
@@ -7261,6 +7598,13 @@ sub process {
WARN("MODULE_LICENSE",
"unknown module license " . $extracted_string . "\n" . $herecurr);
}
+ if (!$file && $extracted_string eq '"GPL v2"') {
+ if (WARN("MODULE_LICENSE",
+ "Prefer \"GPL\" over \"GPL v2\" - see commit bf7fbeeae6db (\"module: Cure the MODULE_LICENSE \"GPL\" vs. \"GPL v2\" bogosity\")\n" . $herecurr) &&
+ $fix) {
+ $fixed[$fixlinenr] =~ s/\bMODULE_LICENSE\s*\(\s*"GPL v2"\s*\)/MODULE_LICENSE("GPL")/;
+ }
+ }
}
# check for sysctl duplicate constants
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index d2c38584ece6..84f5fb7f1cec 100755
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -10,12 +10,12 @@
# Mips port by Juan Quintela <quintela@mandrakesoft.com>
# IA64 port via Andreas Dilger
# Arm port by Holger Schurig
-# sh64 port by Paul Mundt
# Random bits by Matt Mackall <mpm@selenic.com>
# M68k port by Geert Uytterhoeven and Andreas Schwab
# AArch64, PARISC ports by Kyle McMartin
# sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk>
# ppc64le port by Breno Leitao <leitao@debian.org>
+# riscv port by Wadim Mueller <wafgo01@gmail.com>
#
# Usage:
# objdump -d vmlinux | scripts/checkstack.pl [arch]
@@ -99,15 +99,12 @@ my (@stack, $re, $dre, $sub, $x, $xs, $funcre, $min_stack);
# 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15)
$re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})
(?:\(\%r15\))?$/ox;
- } elsif ($arch =~ /^sh64$/) {
- #XXX: we only check for the immediate case presently,
- # though we will want to check for the movi/sub
- # pair for larger users. -- PFM.
- #a00048e0: d4fc40f0 addi.l r15,-240,r15
- $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o;
} elsif ($arch eq 'sparc' || $arch eq 'sparc64') {
# f0019d10: 9d e3 bf 90 save %sp, -112, %sp
$re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o;
+ } elsif ($arch =~ /^riscv(64)?$/) {
+ #ffffffff8036e868: c2010113 addi sp,sp,-992
+ $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
} else {
print("wrong or unknown architecture \"$arch\"\n");
exit
diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh
index a18b47695f55..1e5d2eeb726d 100755
--- a/scripts/checksyscalls.sh
+++ b/scripts/checksyscalls.sh
@@ -40,6 +40,10 @@ cat << EOF
#define __IGNORE_setrlimit /* setrlimit */
#endif
+#ifndef __ARCH_WANT_MEMFD_SECRET
+#define __IGNORE_memfd_secret
+#endif
+
/* Missing flags argument */
#define __IGNORE_renameat /* renameat2 */
@@ -78,10 +82,8 @@ cat << EOF
#define __IGNORE_truncate64
#define __IGNORE_stat64
#define __IGNORE_lstat64
-#define __IGNORE_fstat64
#define __IGNORE_fcntl64
#define __IGNORE_fadvise64_64
-#define __IGNORE_fstatat64
#define __IGNORE_fstatfs64
#define __IGNORE_statfs64
#define __IGNORE_llseek
@@ -112,7 +114,6 @@ cat << EOF
#define __IGNORE_truncate
#define __IGNORE_stat
#define __IGNORE_lstat
-#define __IGNORE_fstat
#define __IGNORE_fcntl
#define __IGNORE_fadvise64
#define __IGNORE_newfstatat
@@ -249,6 +250,13 @@ cat << EOF
#define __IGNORE_getpmsg
#define __IGNORE_putpmsg
#define __IGNORE_vserver
+
+/* 64-bit ports never needed these, and new 32-bit ports can use statx */
+#define __IGNORE_fstat64
+#define __IGNORE_fstatat64
+
+/* Newer ports are not required to provide fstat in favor of statx */
+#define __IGNORE_fstat
EOF
}
@@ -262,4 +270,4 @@ syscall_list() {
}
(ignore_list && syscall_list $(dirname $0)/../arch/x86/entry/syscalls/syscall_32.tbl) | \
-$* -E -x c - > /dev/null
+$* -Wno-error -Wno-unused-macros -E -x c - > /dev/null
diff --git a/scripts/checkversion.pl b/scripts/checkversion.pl
index f67b125c5269..94cd49eff605 100755
--- a/scripts/checkversion.pl
+++ b/scripts/checkversion.pl
@@ -1,10 +1,10 @@
#! /usr/bin/env perl
# SPDX-License-Identifier: GPL-2.0
#
-# checkversion find uses of LINUX_VERSION_CODE or KERNEL_VERSION
-# without including <linux/version.h>, or cases of
-# including <linux/version.h> that don't need it.
-# Copyright (C) 2003, Randy Dunlap <rdunlap@xenotime.net>
+# checkversion finds uses of all macros in <linux/version.h>
+# where the source files do not #include <linux/version.h>; or cases
+# of including <linux/version.h> where it is not needed.
+# Copyright (C) 2003, Randy Dunlap <rdunlap@infradead.org>
use strict;
@@ -13,7 +13,8 @@ $| = 1;
my $debugging;
foreach my $file (@ARGV) {
- next if $file =~ "include/linux/version\.h";
+ next if $file =~ "include/generated/uapi/linux/version\.h";
+ next if $file =~ "usr/include/linux/version\.h";
# Open this file.
open( my $f, '<', $file )
or die "Can't open $file: $!\n";
@@ -41,8 +42,11 @@ foreach my $file (@ARGV) {
$iLinuxVersion = $. if m/^\s*#\s*include\s*<linux\/version\.h>/o;
}
- # Look for uses: LINUX_VERSION_CODE, KERNEL_VERSION, UTS_RELEASE
- if (($_ =~ /LINUX_VERSION_CODE/) || ($_ =~ /\WKERNEL_VERSION/)) {
+ # Look for uses: LINUX_VERSION_CODE, KERNEL_VERSION,
+ # LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL, LINUX_VERSION_SUBLEVEL
+ if (($_ =~ /LINUX_VERSION_CODE/) || ($_ =~ /\WKERNEL_VERSION/) ||
+ ($_ =~ /LINUX_VERSION_MAJOR/) || ($_ =~ /LINUX_VERSION_PATCHLEVEL/) ||
+ ($_ =~ /LINUX_VERSION_SUBLEVEL/)) {
$fUseVersion = 1;
last if $iLinuxVersion;
}
diff --git a/scripts/clang-tools/gen_compile_commands.py b/scripts/clang-tools/gen_compile_commands.py
index b7e9ecf16e56..a84cc5737c2c 100755
--- a/scripts/clang-tools/gen_compile_commands.py
+++ b/scripts/clang-tools/gen_compile_commands.py
@@ -13,12 +13,13 @@ import logging
import os
import re
import subprocess
+import sys
_DEFAULT_OUTPUT = 'compile_commands.json'
_DEFAULT_LOG_LEVEL = 'WARNING'
_FILENAME_PATTERN = r'^\..*\.cmd$'
-_LINE_PATTERN = r'^cmd_[^ ]*\.o := (.* )([^ ]*\.c)$'
+_LINE_PATTERN = r'^savedcmd_[^ ]*\.o := (.* )([^ ]*\.[cS]) *(;|$)'
_VALID_LOG_LEVELS = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
# The tools/ directory adopts a different build system, and produces .cmd
# files in a different format. Do not support it.
@@ -108,20 +109,6 @@ def to_cmdfile(path):
return os.path.join(dir, '.' + base + '.cmd')
-def cmdfiles_for_o(obj):
- """Generate the iterator of .cmd files associated with the object
-
- Yield the .cmd file used to build the given object
-
- Args:
- obj: The object path
-
- Yields:
- The path to .cmd file
- """
- yield to_cmdfile(obj)
-
-
def cmdfiles_for_a(archive, ar):
"""Generate the iterator of .cmd files associated with the archive.
@@ -151,15 +138,15 @@ def cmdfiles_for_modorder(modorder):
"""
with open(modorder) as f:
for line in f:
- ko = line.rstrip()
- base, ext = os.path.splitext(ko)
- if ext != '.ko':
- sys.exit('{}: module path must end with .ko'.format(ko))
+ obj = line.rstrip()
+ base, ext = os.path.splitext(obj)
+ if ext != '.o':
+ sys.exit('{}: module path must end with .o'.format(obj))
mod = base + '.mod'
- # The first line of *.mod lists the objects that compose the module.
+ # Read from *.mod, to get a list of objects that compose the module.
with open(mod) as m:
- for obj in m.readline().split():
- yield to_cmdfile(obj)
+ for mod_line in m:
+ yield to_cmdfile(mod_line.rstrip())
def process_line(root_directory, command_prefix, file_path):
@@ -210,13 +197,10 @@ def main():
for path in paths:
# If 'path' is a directory, handle all .cmd files under it.
# Otherwise, handle .cmd files associated with the file.
- # Most of built-in objects are linked via archives (built-in.a or lib.a)
- # but some objects are linked to vmlinux directly.
+ # built-in objects are linked via vmlinux.a
# Modules are listed in modules.order.
if os.path.isdir(path):
cmdfiles = cmdfiles_in_dir(path)
- elif path.endswith('.o'):
- cmdfiles = cmdfiles_for_o(path)
elif path.endswith('.a'):
cmdfiles = cmdfiles_for_a(path, ar)
elif path.endswith('modules.order'):
diff --git a/scripts/clang-tools/run-clang-tools.py b/scripts/clang-tools/run-clang-tools.py
index f754415af398..3266708a8658 100755
--- a/scripts/clang-tools/run-clang-tools.py
+++ b/scripts/clang-tools/run-clang-tools.py
@@ -12,7 +12,6 @@ compile_commands.json.
import argparse
import json
import multiprocessing
-import os
import subprocess
import sys
@@ -46,12 +45,14 @@ def init(l, a):
def run_analysis(entry):
# Disable all checks, then re-enable the ones we want
- checks = "-checks=-*,"
+ checks = []
+ checks.append("-checks=-*")
if args.type == "clang-tidy":
- checks += "linuxkernel-*"
+ checks.append("linuxkernel-*")
else:
- checks += "clang-analyzer-*"
- p = subprocess.run(["clang-tidy", "-p", args.path, checks, entry["file"]],
+ checks.append("clang-analyzer-*")
+ checks.append("-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling")
+ p = subprocess.run(["clang-tidy", "-p", args.path, ",".join(checks), entry["file"]],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
cwd=entry["directory"])
@@ -60,14 +61,21 @@ def run_analysis(entry):
def main():
- args = parse_arguments()
+ try:
+ args = parse_arguments()
- lock = multiprocessing.Lock()
- pool = multiprocessing.Pool(initializer=init, initargs=(lock, args))
- # Read JSON data into the datastore variable
- with open(args.path, "r") as f:
- datastore = json.load(f)
- pool.map(run_analysis, datastore)
+ lock = multiprocessing.Lock()
+ pool = multiprocessing.Pool(initializer=init, initargs=(lock, args))
+ # Read JSON data into the datastore variable
+ with open(args.path, "r") as f:
+ datastore = json.load(f)
+ pool.map(run_analysis, datastore)
+ except BrokenPipeError:
+ # Python flushes standard streams on exit; redirect remaining output
+ # to devnull to avoid another BrokenPipeError at shutdown
+ devnull = os.open(os.devnull, os.O_WRONLY)
+ os.dup2(devnull, sys.stdout.fileno())
+ sys.exit(1) # Python exits with error code 1 on EPIPE
if __name__ == "__main__":
diff --git a/scripts/coccicheck b/scripts/coccicheck
index 65fee63aeadb..e52cb43fede6 100755
--- a/scripts/coccicheck
+++ b/scripts/coccicheck
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0
# Linux kernel coccicheck
#
@@ -18,7 +18,7 @@ fi
SPATCH_VERSION=$($SPATCH --version | head -1 | awk '{print $3}')
USE_JOBS="no"
-$SPATCH --help | grep "\-\-jobs" > /dev/null && USE_JOBS="yes"
+$SPATCH --help | grep -e "--jobs" > /dev/null && USE_JOBS="yes"
# The verbosity may be set by the environmental parameter V=
# as for example with 'make V=1 coccicheck'
@@ -47,7 +47,7 @@ FLAGS="--very-quiet"
# inspected there.
#
# --profile will not output if --very-quiet is used, so avoid it.
-echo $SPFLAGS | egrep -e "--profile|--show-trying" 2>&1 > /dev/null
+echo $SPFLAGS | grep -E -e "--profile|--show-trying" 2>&1 > /dev/null
if [ $? -eq 0 ]; then
FLAGS="--quiet"
fi
@@ -87,7 +87,7 @@ else
fi
# Use only one thread per core by default if hyperthreading is enabled
- THREADS_PER_CORE=$(lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]")
+ THREADS_PER_CORE=$(LANG=C lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]")
if [ -z "$J" ]; then
NPROC=$(getconf _NPROCESSORS_ONLN)
if [ $THREADS_PER_CORE -gt 1 -a $NPROC -gt 4 ] ; then
diff --git a/scripts/coccinelle/api/alloc/zalloc-simple.cocci b/scripts/coccinelle/api/alloc/zalloc-simple.cocci
index b3d0c3c230c1..d66c45356691 100644
--- a/scripts/coccinelle/api/alloc/zalloc-simple.cocci
+++ b/scripts/coccinelle/api/alloc/zalloc-simple.cocci
@@ -10,7 +10,7 @@
// Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU.
// Copyright: (C) 2009-2010 Gilles Muller, INRIA/LiP6.
// Copyright: (C) 2017 Himanshu Jha
-// URL: http://coccinelle.lip6.fr/rules/kzalloc.html
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
//
// Keywords: kmalloc, kzalloc
diff --git a/scripts/coccinelle/api/atomic_as_refcounter.cocci b/scripts/coccinelle/api/atomic_as_refcounter.cocci
index 0f78d94abc35..bbe5b2932933 100644
--- a/scripts/coccinelle/api/atomic_as_refcounter.cocci
+++ b/scripts/coccinelle/api/atomic_as_refcounter.cocci
@@ -5,7 +5,7 @@
// Copyright (c) 2016-2017, Elena Reshetova, Intel Corporation
//
// Confidence: Moderate
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --include-headers --very-quiet
virtual report
@@ -55,7 +55,7 @@ identifier fname6 =~ ".*call_rcu.*";
p1 << r1.p1;
p2 << r1.p2;
@@
-msg = "atomic_dec_and_test variation before object free at line %s."
+msg = "WARNING: atomic_dec_and_test variation before object free at line %s."
coccilib.report.print_report(p1[0], msg % (p2[0].line))
@r4 exists@
@@ -88,7 +88,7 @@ fname@p2(y, ...);
p1 << r4.p1;
p2 << r4.p2;
@@
-msg = "atomic_dec_and_test variation before object free at line %s."
+msg = "WARNING: atomic_dec_and_test variation before object free at line %s."
coccilib.report.print_report(p1[0], msg % (p2[0].line))
@r2 exists@
@@ -107,7 +107,7 @@ atomic64_add_unless(&(a)->x,-1,1)@p1
@script:python depends on report@
p1 << r2.p1;
@@
-msg = "atomic_add_unless"
+msg = "WARNING: atomic_add_unless"
coccilib.report.print_report(p1[0], msg)
@r3 exists@
@@ -126,5 +126,5 @@ x = atomic64_add_return@p1(-1, ...);
@script:python depends on report@
p1 << r3.p1;
@@
-msg = "x = atomic_add_return(-1, ...)"
+msg = "WARNING: x = atomic_add_return(-1, ...)"
coccilib.report.print_report(p1[0], msg)
diff --git a/scripts/coccinelle/api/check_bq27xxx_data.cocci b/scripts/coccinelle/api/check_bq27xxx_data.cocci
index fae539ef0ce5..27366c6169ec 100644
--- a/scripts/coccinelle/api/check_bq27xxx_data.cocci
+++ b/scripts/coccinelle/api/check_bq27xxx_data.cocci
@@ -6,7 +6,7 @@
///
// Confidence: High
// Copyright: (C) 2017 Julia Lawall, Inria/LIP6,
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Requires: 1.0.7
// Keywords: BQ27XXX_DATA
diff --git a/scripts/coccinelle/api/d_find_alias.cocci b/scripts/coccinelle/api/d_find_alias.cocci
index 47e050166f20..3489001378ab 100644
--- a/scripts/coccinelle/api/d_find_alias.cocci
+++ b/scripts/coccinelle/api/d_find_alias.cocci
@@ -4,7 +4,7 @@
// Keywords: d_find_alias, dput
//
// Confidence: Moderate
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --include-headers
virtual context
diff --git a/scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci b/scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci
deleted file mode 100644
index 7c312310547c..000000000000
--- a/scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci
+++ /dev/null
@@ -1,68 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/// Use DEFINE_DEBUGFS_ATTRIBUTE rather than DEFINE_SIMPLE_ATTRIBUTE
-/// for debugfs files.
-///
-//# Rationale: DEFINE_SIMPLE_ATTRIBUTE + debugfs_create_file()
-//# imposes some significant overhead as compared to
-//# DEFINE_DEBUGFS_ATTRIBUTE + debugfs_create_file_unsafe().
-//
-// Copyright (C): 2016 Nicolai Stange
-// Options: --no-includes
-//
-
-virtual context
-virtual patch
-virtual org
-virtual report
-
-@dsa@
-declarer name DEFINE_SIMPLE_ATTRIBUTE;
-identifier dsa_fops;
-expression dsa_get, dsa_set, dsa_fmt;
-position p;
-@@
-DEFINE_SIMPLE_ATTRIBUTE@p(dsa_fops, dsa_get, dsa_set, dsa_fmt);
-
-@dcf@
-expression name, mode, parent, data;
-identifier dsa.dsa_fops;
-@@
-debugfs_create_file(name, mode, parent, data, &dsa_fops)
-
-
-@context_dsa depends on context && dcf@
-declarer name DEFINE_DEBUGFS_ATTRIBUTE;
-identifier dsa.dsa_fops;
-expression dsa.dsa_get, dsa.dsa_set, dsa.dsa_fmt;
-@@
-* DEFINE_SIMPLE_ATTRIBUTE(dsa_fops, dsa_get, dsa_set, dsa_fmt);
-
-
-@patch_dcf depends on patch expression@
-expression name, mode, parent, data;
-identifier dsa.dsa_fops;
-@@
-- debugfs_create_file(name, mode, parent, data, &dsa_fops)
-+ debugfs_create_file_unsafe(name, mode, parent, data, &dsa_fops)
-
-@patch_dsa depends on patch_dcf && patch@
-identifier dsa.dsa_fops;
-expression dsa.dsa_get, dsa.dsa_set, dsa.dsa_fmt;
-@@
-- DEFINE_SIMPLE_ATTRIBUTE(dsa_fops, dsa_get, dsa_set, dsa_fmt);
-+ DEFINE_DEBUGFS_ATTRIBUTE(dsa_fops, dsa_get, dsa_set, dsa_fmt);
-
-
-@script:python depends on org && dcf@
-fops << dsa.dsa_fops;
-p << dsa.p;
-@@
-msg="%s should be defined with DEFINE_DEBUGFS_ATTRIBUTE" % (fops)
-coccilib.org.print_todo(p[0], msg)
-
-@script:python depends on report && dcf@
-fops << dsa.dsa_fops;
-p << dsa.p;
-@@
-msg="WARNING: %s should be defined with DEFINE_DEBUGFS_ATTRIBUTE" % (fops)
-coccilib.report.print_report(p[0], msg)
diff --git a/scripts/coccinelle/api/err_cast.cocci b/scripts/coccinelle/api/err_cast.cocci
index 0e661c8d8d6f..7f9dc1212c74 100644
--- a/scripts/coccinelle/api/err_cast.cocci
+++ b/scripts/coccinelle/api/err_cast.cocci
@@ -6,7 +6,7 @@
// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2009, 2010 Julia Lawall, DIKU.
// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options:
//
// Keywords: ERR_PTR, PTR_ERR, ERR_CAST
diff --git a/scripts/coccinelle/api/kobj_to_dev.cocci b/scripts/coccinelle/api/kobj_to_dev.cocci
deleted file mode 100644
index cd5d31c6fe76..000000000000
--- a/scripts/coccinelle/api/kobj_to_dev.cocci
+++ /dev/null
@@ -1,45 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-///
-/// Use kobj_to_dev() instead of container_of()
-///
-// Confidence: High
-// Copyright: (C) 2020 Denis Efremov ISPRAS
-// Options: --no-includes --include-headers
-//
-// Keywords: kobj_to_dev, container_of
-//
-
-virtual context
-virtual report
-virtual org
-virtual patch
-
-
-@r depends on !patch@
-expression ptr;
-symbol kobj;
-position p;
-@@
-
-* container_of(ptr, struct device, kobj)@p
-
-
-@depends on patch@
-expression ptr;
-@@
-
-- container_of(ptr, struct device, kobj)
-+ kobj_to_dev(ptr)
-
-
-@script:python depends on report@
-p << r.p;
-@@
-
-coccilib.report.print_report(p[0], "WARNING opportunity for kobj_to_dev()")
-
-@script:python depends on org@
-p << r.p;
-@@
-
-coccilib.org.print_todo(p[0], "WARNING opportunity for kobj_to_dev()")
diff --git a/scripts/coccinelle/api/kstrdup.cocci b/scripts/coccinelle/api/kstrdup.cocci
index 3c6dc5469ee4..8a61534676da 100644
--- a/scripts/coccinelle/api/kstrdup.cocci
+++ b/scripts/coccinelle/api/kstrdup.cocci
@@ -5,7 +5,7 @@
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/api/kvmalloc.cocci b/scripts/coccinelle/api/kvmalloc.cocci
index c30dab718a49..5ddcb76b76b0 100644
--- a/scripts/coccinelle/api/kvmalloc.cocci
+++ b/scripts/coccinelle/api/kvmalloc.cocci
@@ -79,7 +79,7 @@ position p : script:python() { relevant(p) };
} else {
... when != krealloc(E, ...)
when any
-* \(kfree\|kzfree\)(E)
+* \(kfree\|kfree_sensitive\)(E)
...
}
diff --git a/scripts/coccinelle/api/memdup.cocci b/scripts/coccinelle/api/memdup.cocci
index 30b15df734e5..d28741c69873 100644
--- a/scripts/coccinelle/api/memdup.cocci
+++ b/scripts/coccinelle/api/memdup.cocci
@@ -5,7 +5,7 @@
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/api/memdup_user.cocci b/scripts/coccinelle/api/memdup_user.cocci
index e01e95108405..03e7afa09eee 100644
--- a/scripts/coccinelle/api/memdup_user.cocci
+++ b/scripts/coccinelle/api/memdup_user.cocci
@@ -6,7 +6,7 @@
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/api/pm_runtime.cocci b/scripts/coccinelle/api/pm_runtime.cocci
index 1ccce3fd00b8..4b9778874453 100644
--- a/scripts/coccinelle/api/pm_runtime.cocci
+++ b/scripts/coccinelle/api/pm_runtime.cocci
@@ -4,7 +4,7 @@
// Keywords: pm_runtime
// Confidence: Medium
// Copyright (C) 2013 Texas Instruments Incorporated -
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --include-headers
virtual patch
diff --git a/scripts/coccinelle/api/resource_size.cocci b/scripts/coccinelle/api/resource_size.cocci
index a9a571ac04ce..16857072d162 100644
--- a/scripts/coccinelle/api/resource_size.cocci
+++ b/scripts/coccinelle/api/resource_size.cocci
@@ -7,7 +7,7 @@
// Copyright: (C) 2009, 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2009, 2010 Julia Lawall, DIKU.
// Copyright: (C) 2009, 2010 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options:
//
// Keywords: resource_size
diff --git a/scripts/coccinelle/free/clk_put.cocci b/scripts/coccinelle/free/clk_put.cocci
index 7237b49496f6..3c732cb7210b 100644
--- a/scripts/coccinelle/free/clk_put.cocci
+++ b/scripts/coccinelle/free/clk_put.cocci
@@ -8,7 +8,7 @@
// Confidence: Moderate
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options:
diff --git a/scripts/coccinelle/free/devm_free.cocci b/scripts/coccinelle/free/devm_free.cocci
index da80050b91ff..0880729badbc 100644
--- a/scripts/coccinelle/free/devm_free.cocci
+++ b/scripts/coccinelle/free/devm_free.cocci
@@ -17,7 +17,7 @@
// Confidence: Moderate
// Copyright: (C) 2011 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2011 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/free/ifnulldev_put.cocci b/scripts/coccinelle/free/ifnulldev_put.cocci
new file mode 100644
index 000000000000..2bd2e8fae485
--- /dev/null
+++ b/scripts/coccinelle/free/ifnulldev_put.cocci
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/// Since commit b37a46683739 ("netdevice: add the case if dev is NULL"),
+/// NULL check before dev_{put, hold} functions is not needed.
+///
+/// Based on ifnullfree.cocci by Fabian Frederick.
+///
+// Copyright: (C) 2022 Ziyang Xuan.
+// Comments: -
+// Options: --no-includes --include-headers
+// Version min: 5.15
+
+virtual patch
+virtual org
+virtual report
+virtual context
+
+@r2 depends on patch@
+expression E;
+@@
+- if (E != NULL)
+(
+ __dev_put(E);
+|
+ dev_put(E);
+|
+ dev_put_track(E, ...);
+|
+ __dev_hold(E);
+|
+ dev_hold(E);
+|
+ dev_hold_track(E, ...);
+)
+
+@r depends on context || report || org @
+expression E;
+position p;
+@@
+
+* if (E != NULL)
+* \(__dev_put@p\|dev_put@p\|dev_put_track@p\|__dev_hold@p\|dev_hold@p\|
+* dev_hold_track@p\)(E, ...);
+
+@script:python depends on org@
+p << r.p;
+@@
+
+cocci.print_main("NULL check before dev_{put, hold} functions is not needed", p)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+msg = "WARNING: NULL check before dev_{put, hold} functions is not needed."
+coccilib.report.print_report(p[0], msg)
diff --git a/scripts/coccinelle/free/iounmap.cocci b/scripts/coccinelle/free/iounmap.cocci
index 63b81d0c97b6..90d85fa7bfdf 100644
--- a/scripts/coccinelle/free/iounmap.cocci
+++ b/scripts/coccinelle/free/iounmap.cocci
@@ -8,7 +8,7 @@
// Confidence: Moderate
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options:
diff --git a/scripts/coccinelle/free/kfree.cocci b/scripts/coccinelle/free/kfree.cocci
index 168568386034..6338bbac2f7f 100644
--- a/scripts/coccinelle/free/kfree.cocci
+++ b/scripts/coccinelle/free/kfree.cocci
@@ -9,7 +9,7 @@
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
@@ -22,9 +22,9 @@ position p1;
@@
(
-* kfree@p1(E)
+ kfree@p1(E)
|
-* kfree_sensitive@p1(E)
+ kfree_sensitive@p1(E)
)
@print expression@
@@ -66,9 +66,9 @@ position ok;
while (1) { ...
(
-* kfree@ok(E)
+ kfree@ok(E)
|
-* kfree_sensitive@ok(E)
+ kfree_sensitive@ok(E)
)
... when != break;
when != goto l;
@@ -84,9 +84,9 @@ position free.p1!=loop.ok,p2!={print.p,sz.p};
@@
(
-* kfree@p1(E,...)
+ kfree@p1(E,...)
|
-* kfree_sensitive@p1(E,...)
+ kfree_sensitive@p1(E,...)
)
...
(
diff --git a/scripts/coccinelle/free/kfreeaddr.cocci b/scripts/coccinelle/free/kfreeaddr.cocci
index 142af6337a04..85635a36f0ac 100644
--- a/scripts/coccinelle/free/kfreeaddr.cocci
+++ b/scripts/coccinelle/free/kfreeaddr.cocci
@@ -3,7 +3,7 @@
///
// Confidence: High
// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/free/pci_free_consistent.cocci b/scripts/coccinelle/free/pci_free_consistent.cocci
index d51e92556b42..e062b9ba09ff 100644
--- a/scripts/coccinelle/free/pci_free_consistent.cocci
+++ b/scripts/coccinelle/free/pci_free_consistent.cocci
@@ -3,7 +3,7 @@
///
// Confidence: Moderate
// Copyright: (C) 2013 Petr Strnad.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Keywords: pci_free_consistent, pci_alloc_consistent
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/iterators/device_node_continue.cocci b/scripts/coccinelle/iterators/device_node_continue.cocci
index f8cd14dfa604..5713c9cf59ff 100644
--- a/scripts/coccinelle/iterators/device_node_continue.cocci
+++ b/scripts/coccinelle/iterators/device_node_continue.cocci
@@ -4,7 +4,7 @@
///
// Confidence: High
// Copyright: (C) 2015 Julia Lawall, Inria.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
// Requires: 1.0.4
// Keywords: for_each_child_of_node, etc.
diff --git a/scripts/coccinelle/iterators/fen.cocci b/scripts/coccinelle/iterators/fen.cocci
deleted file mode 100644
index b69f9665f4fb..000000000000
--- a/scripts/coccinelle/iterators/fen.cocci
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/// These iterators only exit normally when the loop cursor is NULL, so there
-/// is no point to call of_node_put on the final value.
-///
-// Confidence: High
-// Copyright: (C) 2010-2012 Nicolas Palix.
-// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
-// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
-// Comments:
-// Options: --no-includes --include-headers
-
-virtual patch
-virtual context
-virtual org
-virtual report
-
-@depends on patch@
-iterator name for_each_node_by_name;
-expression np,E;
-identifier l;
-@@
-
-for_each_node_by_name(np,...) {
- ... when != break;
- when != goto l;
-}
-... when != np = E
-- of_node_put(np);
-
-@depends on patch@
-iterator name for_each_node_by_type;
-expression np,E;
-identifier l;
-@@
-
-for_each_node_by_type(np,...) {
- ... when != break;
- when != goto l;
-}
-... when != np = E
-- of_node_put(np);
-
-@depends on patch@
-iterator name for_each_compatible_node;
-expression np,E;
-identifier l;
-@@
-
-for_each_compatible_node(np,...) {
- ... when != break;
- when != goto l;
-}
-... when != np = E
-- of_node_put(np);
-
-@depends on patch@
-iterator name for_each_matching_node;
-expression np,E;
-identifier l;
-@@
-
-for_each_matching_node(np,...) {
- ... when != break;
- when != goto l;
-}
-... when != np = E
-- of_node_put(np);
-
-// ----------------------------------------------------------------------
-
-@r depends on !patch forall@
-//iterator name for_each_node_by_name;
-//iterator name for_each_node_by_type;
-//iterator name for_each_compatible_node;
-//iterator name for_each_matching_node;
-expression np,E;
-identifier l;
-position p1,p2;
-@@
-
-(
-*for_each_node_by_name@p1(np,...)
-{
- ... when != break;
- when != goto l;
-}
-|
-*for_each_node_by_type@p1(np,...)
-{
- ... when != break;
- when != goto l;
-}
-|
-*for_each_compatible_node@p1(np,...)
-{
- ... when != break;
- when != goto l;
-}
-|
-*for_each_matching_node@p1(np,...)
-{
- ... when != break;
- when != goto l;
-}
-)
-... when != np = E
-* of_node_put@p2(np);
-
-@script:python depends on org@
-p1 << r.p1;
-p2 << r.p2;
-@@
-
-cocci.print_main("unneeded of_node_put",p2)
-cocci.print_secs("iterator",p1)
-
-@script:python depends on report@
-p1 << r.p1;
-p2 << r.p2;
-@@
-
-msg = "ERROR: of_node_put not needed after iterator on line %s" % (p1[0].line)
-coccilib.report.print_report(p2[0], msg)
diff --git a/scripts/coccinelle/iterators/for_each_child.cocci b/scripts/coccinelle/iterators/for_each_child.cocci
index bc394615948e..2ea98a61a1f2 100644
--- a/scripts/coccinelle/iterators/for_each_child.cocci
+++ b/scripts/coccinelle/iterators/for_each_child.cocci
@@ -5,7 +5,7 @@
///
// Confidence: High
// Copyright: (C) 2020 Sumera Priyadarsini
-// URL: http://coccinelle.lip6.fr
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
virtual patch
diff --git a/scripts/coccinelle/iterators/itnull.cocci b/scripts/coccinelle/iterators/itnull.cocci
index 9b362b98d7a1..7d34802f2724 100644
--- a/scripts/coccinelle/iterators/itnull.cocci
+++ b/scripts/coccinelle/iterators/itnull.cocci
@@ -10,7 +10,7 @@
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/iterators/list_entry_update.cocci b/scripts/coccinelle/iterators/list_entry_update.cocci
index d62e8a16085f..9a7593667da6 100644
--- a/scripts/coccinelle/iterators/list_entry_update.cocci
+++ b/scripts/coccinelle/iterators/list_entry_update.cocci
@@ -8,7 +8,7 @@
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/iterators/use_after_iter.cocci b/scripts/coccinelle/iterators/use_after_iter.cocci
index 9be48b520879..f67110ba7290 100644
--- a/scripts/coccinelle/iterators/use_after_iter.cocci
+++ b/scripts/coccinelle/iterators/use_after_iter.cocci
@@ -10,7 +10,7 @@
// Confidence: Moderate
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LIP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
@@ -123,6 +123,8 @@ hlist_for_each_entry_safe(c,...) S
|
list_remove_head(x,c,...)
|
+list_entry_is_head(c,...)
+|
sizeof(<+...c...+>)
|
&c->member
diff --git a/scripts/coccinelle/locks/call_kern.cocci b/scripts/coccinelle/locks/call_kern.cocci
index 5ca0d81b0015..3720f86d67c5 100644
--- a/scripts/coccinelle/locks/call_kern.cocci
+++ b/scripts/coccinelle/locks/call_kern.cocci
@@ -8,7 +8,7 @@
// Copyright: (C) 2012 Nicolas Palix.
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/locks/double_lock.cocci b/scripts/coccinelle/locks/double_lock.cocci
index 9e88a578957c..619cfc714409 100644
--- a/scripts/coccinelle/locks/double_lock.cocci
+++ b/scripts/coccinelle/locks/double_lock.cocci
@@ -7,7 +7,7 @@
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/locks/flags.cocci b/scripts/coccinelle/locks/flags.cocci
index 7f990cd55f5a..44acf20a98dd 100644
--- a/scripts/coccinelle/locks/flags.cocci
+++ b/scripts/coccinelle/locks/flags.cocci
@@ -5,7 +5,7 @@
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/locks/mini_lock.cocci b/scripts/coccinelle/locks/mini_lock.cocci
index c3ad098f4a5b..71065d8a5d54 100644
--- a/scripts/coccinelle/locks/mini_lock.cocci
+++ b/scripts/coccinelle/locks/mini_lock.cocci
@@ -10,7 +10,7 @@
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/misc/boolreturn.cocci b/scripts/coccinelle/misc/boolreturn.cocci
deleted file mode 100644
index 29d2bf41e95d..000000000000
--- a/scripts/coccinelle/misc/boolreturn.cocci
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/// Return statements in functions returning bool should use
-/// true/false instead of 1/0.
-//
-// Confidence: High
-// Options: --no-includes --include-headers
-
-virtual patch
-virtual report
-virtual context
-
-@r1 depends on patch@
-identifier fn;
-typedef bool;
-symbol false;
-symbol true;
-@@
-
-bool fn ( ... )
-{
-<...
-return
-(
-- 0
-+ false
-|
-- 1
-+ true
-)
- ;
-...>
-}
-
-@r2 depends on report || context@
-identifier fn;
-position p;
-@@
-
-bool fn ( ... )
-{
-<...
-return
-(
-* 0@p
-|
-* 1@p
-)
- ;
-...>
-}
-
-
-@script:python depends on report@
-p << r2.p;
-fn << r2.fn;
-@@
-
-msg = "WARNING: return of 0/1 in function '%s' with return type bool" % fn
-coccilib.report.print_report(p[0], msg)
diff --git a/scripts/coccinelle/misc/bugon.cocci b/scripts/coccinelle/misc/bugon.cocci
deleted file mode 100644
index 8d595c358408..000000000000
--- a/scripts/coccinelle/misc/bugon.cocci
+++ /dev/null
@@ -1,63 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/// Use BUG_ON instead of a if condition followed by BUG.
-///
-//# This makes an effort to find cases where BUG() follows an if
-//# condition on an expression and replaces the if condition and BUG()
-//# with a BUG_ON having the conditional expression of the if statement
-//# as argument.
-//
-// Confidence: High
-// Copyright: (C) 2014 Himangi Saraogi.
-// Comments:
-// Options: --no-includes --include-headers
-
-virtual patch
-virtual context
-virtual org
-virtual report
-
-//----------------------------------------------------------
-// For context mode
-//----------------------------------------------------------
-
-@depends on context@
-expression e;
-@@
-
-*if (e) BUG();
-
-//----------------------------------------------------------
-// For patch mode
-//----------------------------------------------------------
-
-@depends on patch@
-expression e;
-@@
-
--if (e) BUG();
-+BUG_ON(e);
-
-//----------------------------------------------------------
-// For org and report mode
-//----------------------------------------------------------
-
-@r depends on (org || report)@
-expression e;
-position p;
-@@
-
- if (e) BUG@p ();
-
-@script:python depends on org@
-p << r.p;
-@@
-
-coccilib.org.print_todo(p[0], "WARNING use BUG_ON")
-
-@script:python depends on report@
-p << r.p;
-@@
-
-msg="WARNING: Use BUG_ON instead of if condition followed by BUG.\nPlease make sure the condition has no side effects (see conditional BUG_ON definition in include/asm-generic/bug.h)"
-coccilib.report.print_report(p[0], msg)
-
diff --git a/scripts/coccinelle/misc/cstptr.cocci b/scripts/coccinelle/misc/cstptr.cocci
index c52e3c8ca9b3..74acf34bee03 100644
--- a/scripts/coccinelle/misc/cstptr.cocci
+++ b/scripts/coccinelle/misc/cstptr.cocci
@@ -5,7 +5,7 @@
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/misc/do_div.cocci b/scripts/coccinelle/misc/do_div.cocci
new file mode 100644
index 000000000000..79db083c5208
--- /dev/null
+++ b/scripts/coccinelle/misc/do_div.cocci
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/// do_div() does a 64-by-32 division.
+/// When the divisor is long, unsigned long, u64, or s64,
+/// do_div() truncates it to 32 bits, this means it can test
+/// non-zero and be truncated to 0 for division on 64bit platforms.
+///
+//# This makes an effort to find those inappropriate do_div() calls.
+//
+// Confidence: Moderate
+// Copyright: (C) 2020 Wen Yang, Alibaba.
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual org
+virtual report
+
+@initialize:python@
+@@
+
+def get_digit_type_and_value(str):
+ is_digit = False
+ value = 0
+
+ try:
+ if (str.isdigit()):
+ is_digit = True
+ value = int(str, 0)
+ elif (str.upper().endswith('ULL')):
+ is_digit = True
+ value = int(str[:-3], 0)
+ elif (str.upper().endswith('LL')):
+ is_digit = True
+ value = int(str[:-2], 0)
+ elif (str.upper().endswith('UL')):
+ is_digit = True
+ value = int(str[:-2], 0)
+ elif (str.upper().endswith('L')):
+ is_digit = True
+ value = int(str[:-1], 0)
+ elif (str.upper().endswith('U')):
+ is_digit = True
+ value = int(str[:-1], 0)
+ except Exception as e:
+ print('Error:',e)
+ is_digit = False
+ value = 0
+ finally:
+ return is_digit, value
+
+def filter_out_safe_constants(str):
+ is_digit, value = get_digit_type_and_value(str)
+ if (is_digit):
+ if (value >= 0x100000000):
+ return True
+ else:
+ return False
+ else:
+ return True
+
+def construct_warnings(suggested_fun):
+ msg="WARNING: do_div() does a 64-by-32 division, please consider using %s instead."
+ return msg % suggested_fun
+
+@depends on context@
+expression f;
+long l: script:python() { filter_out_safe_constants(l) };
+unsigned long ul : script:python() { filter_out_safe_constants(ul) };
+u64 ul64 : script:python() { filter_out_safe_constants(ul64) };
+s64 sl64 : script:python() { filter_out_safe_constants(sl64) };
+
+@@
+(
+* do_div(f, l);
+|
+* do_div(f, ul);
+|
+* do_div(f, ul64);
+|
+* do_div(f, sl64);
+)
+
+@r depends on (org || report)@
+expression f;
+position p;
+long l: script:python() { filter_out_safe_constants(l) };
+unsigned long ul : script:python() { filter_out_safe_constants(ul) };
+u64 ul64 : script:python() { filter_out_safe_constants(ul64) };
+s64 sl64 : script:python() { filter_out_safe_constants(sl64) };
+@@
+(
+do_div@p(f, l);
+|
+do_div@p(f, ul);
+|
+do_div@p(f, ul64);
+|
+do_div@p(f, sl64);
+)
+
+@script:python depends on org@
+p << r.p;
+ul << r.ul;
+@@
+
+coccilib.org.print_todo(p[0], construct_warnings("div64_ul"))
+
+@script:python depends on org@
+p << r.p;
+l << r.l;
+@@
+
+coccilib.org.print_todo(p[0], construct_warnings("div64_long"))
+
+@script:python depends on org@
+p << r.p;
+ul64 << r.ul64;
+@@
+
+coccilib.org.print_todo(p[0], construct_warnings("div64_u64"))
+
+@script:python depends on org@
+p << r.p;
+sl64 << r.sl64;
+@@
+
+coccilib.org.print_todo(p[0], construct_warnings("div64_s64"))
+
+@script:python depends on report@
+p << r.p;
+ul << r.ul;
+@@
+
+coccilib.report.print_report(p[0], construct_warnings("div64_ul"))
+
+@script:python depends on report@
+p << r.p;
+l << r.l;
+@@
+
+coccilib.report.print_report(p[0], construct_warnings("div64_long"))
+
+@script:python depends on report@
+p << r.p;
+sl64 << r.sl64;
+@@
+
+coccilib.report.print_report(p[0], construct_warnings("div64_s64"))
+
+@script:python depends on report@
+p << r.p;
+ul64 << r.ul64;
+@@
+
+coccilib.report.print_report(p[0], construct_warnings("div64_u64"))
diff --git a/scripts/coccinelle/misc/doubleinit.cocci b/scripts/coccinelle/misc/doubleinit.cocci
index 2f80d3ab38dd..7dbfde3f44e1 100644
--- a/scripts/coccinelle/misc/doubleinit.cocci
+++ b/scripts/coccinelle/misc/doubleinit.cocci
@@ -7,7 +7,7 @@
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/misc/flexible_array.cocci b/scripts/coccinelle/misc/flexible_array.cocci
index 947fbaff82a9..f427fd68ed2d 100644
--- a/scripts/coccinelle/misc/flexible_array.cocci
+++ b/scripts/coccinelle/misc/flexible_array.cocci
@@ -51,21 +51,40 @@ position p : script:python() { relevant(p) };
};
)
+@only_field depends on patch@
+identifier name, array;
+type T;
+position q;
+@@
+
+(
+ struct name {@q
+ T array[0];
+ };
+|
+ struct {@q
+ T array[0];
+ };
+)
+
@depends on patch@
identifier name, array;
type T;
position p : script:python() { relevant(p) };
+// position @q with rule "only_field" simplifies
+// handling of bitfields, arrays, etc.
+position q != only_field.q;
@@
(
- struct name {
+ struct name {@q
...
T array@p[
- 0
];
};
|
- struct {
+ struct {@q
...
T array@p[
- 0
diff --git a/scripts/coccinelle/misc/ifcol.cocci b/scripts/coccinelle/misc/ifcol.cocci
index da0351ed5740..442742467c18 100644
--- a/scripts/coccinelle/misc/ifcol.cocci
+++ b/scripts/coccinelle/misc/ifcol.cocci
@@ -12,7 +12,7 @@
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/misc/irqf_oneshot.cocci b/scripts/coccinelle/misc/irqf_oneshot.cocci
index 7b48287b3dc1..9b6f404d07f2 100644
--- a/scripts/coccinelle/misc/irqf_oneshot.cocci
+++ b/scripts/coccinelle/misc/irqf_oneshot.cocci
@@ -103,11 +103,11 @@ devm_request_threaded_irq@p(dev, irq, NULL, ...)
@script:python depends on org@
p << match.p;
@@
-msg = "ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT"
+msg = "WARNING: Threaded IRQ with no primary handler requested without IRQF_ONESHOT (unless it is nested IRQ)"
coccilib.org.print_todo(p[0],msg)
@script:python depends on report@
p << match.p;
@@
-msg = "ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT"
+msg = "WARNING: Threaded IRQ with no primary handler requested without IRQF_ONESHOT (unless it is nested IRQ)"
coccilib.report.print_report(p[0],msg)
diff --git a/scripts/coccinelle/misc/minmax.cocci b/scripts/coccinelle/misc/minmax.cocci
new file mode 100644
index 000000000000..fcf908b34f27
--- /dev/null
+++ b/scripts/coccinelle/misc/minmax.cocci
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded min(), max() implementations.
+/// Generated patches sometimes require adding a cast to fix compile warning.
+/// Warnings/patches scope intentionally limited to a function body.
+///
+// Confidence: Medium
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: min, max
+//
+
+
+virtual report
+virtual org
+virtual context
+virtual patch
+
+@rmax depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+ <...
+* ((x) cmp@p (y) ? (x) : (y))
+ ...>
+}
+
+@rmaxif depends on !patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+ <...
+* if ((x) cmp@p (y)) {
+* max_val = (x);
+* } else {
+* max_val = (y);
+* }
+ ...>
+}
+
+@rmin depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+ <...
+* ((x) cmp@p (y) ? (x) : (y))
+ ...>
+}
+
+@rminif depends on !patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+ <...
+* if ((x) cmp@p (y)) {
+* min_val = (x);
+* } else {
+* min_val = (y);
+* }
+ ...>
+}
+
+@pmax depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>=, >};
+@@
+
+func(...)
+{
+ <...
+- ((x) cmp (y) ? (x) : (y))
++ max(x, y)
+ ...>
+}
+
+@pmaxif depends on patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>=, >};
+@@
+
+func(...)
+{
+ <...
+- if ((x) cmp (y)) {
+- max_val = x;
+- } else {
+- max_val = y;
+- }
++ max_val = max(x, y);
+ ...>
+}
+
+// Don't generate patches for errcode returns.
+@errcode depends on patch@
+position p;
+identifier func;
+expression x;
+binary operator cmp = {<, <=};
+@@
+
+func(...)
+{
+ <...
+ return ((x) cmp@p 0 ? (x) : 0);
+ ...>
+}
+
+@pmin depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<=, <};
+position p != errcode.p;
+@@
+
+func(...)
+{
+ <...
+- ((x) cmp@p (y) ? (x) : (y))
++ min(x, y)
+ ...>
+}
+
+@pminif depends on patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<=, <};
+@@
+
+func(...)
+{
+ <...
+- if ((x) cmp (y)) {
+- min_val = x;
+- } else {
+- min_val = y;
+- }
++ min_val = min(x, y);
+ ...>
+}
+
+@script:python depends on report@
+p << rmax.p;
+@@
+
+for p0 in p:
+ coccilib.report.print_report(p0, "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmax.p;
+@@
+
+for p0 in p:
+ coccilib.org.print_todo(p0, "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmaxif.p;
+@@
+
+for p0 in p:
+ coccilib.report.print_report(p0, "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmaxif.p;
+@@
+
+for p0 in p:
+ coccilib.org.print_todo(p0, "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmin.p;
+@@
+
+for p0 in p:
+ coccilib.report.print_report(p0, "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rmin.p;
+@@
+
+for p0 in p:
+ coccilib.org.print_todo(p0, "WARNING opportunity for min()")
+
+@script:python depends on report@
+p << rminif.p;
+@@
+
+for p0 in p:
+ coccilib.report.print_report(p0, "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rminif.p;
+@@
+
+for p0 in p:
+ coccilib.org.print_todo(p0, "WARNING opportunity for min()")
diff --git a/scripts/coccinelle/misc/newline_in_nl_msg.cocci b/scripts/coccinelle/misc/newline_in_nl_msg.cocci
index c175886e4015..9baffe55d917 100644
--- a/scripts/coccinelle/misc/newline_in_nl_msg.cocci
+++ b/scripts/coccinelle/misc/newline_in_nl_msg.cocci
@@ -5,7 +5,7 @@
///
// Confidence: Very High
// Copyright: (C) 2020 Intel Corporation
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
virtual context
diff --git a/scripts/coccinelle/misc/noderef.cocci b/scripts/coccinelle/misc/noderef.cocci
index 72de62a77a44..37ee7358d742 100644
--- a/scripts/coccinelle/misc/noderef.cocci
+++ b/scripts/coccinelle/misc/noderef.cocci
@@ -5,7 +5,7 @@
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/misc/orplus.cocci b/scripts/coccinelle/misc/orplus.cocci
index 52203dc2ca4b..3a1566f1aec9 100644
--- a/scripts/coccinelle/misc/orplus.cocci
+++ b/scripts/coccinelle/misc/orplus.cocci
@@ -6,7 +6,7 @@
// Confidence: Moderate
// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2013 Gilles Muller, INRIA/LIP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/misc/returnvar.cocci b/scripts/coccinelle/misc/returnvar.cocci
index ce0d9eebc7e1..7ffc55bf51f9 100644
--- a/scripts/coccinelle/misc/returnvar.cocci
+++ b/scripts/coccinelle/misc/returnvar.cocci
@@ -4,7 +4,7 @@
///
// Confidence: Moderate
// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments: Comments on code can be deleted if near code that is removed.
// "when strict" can be removed to get more hits, but adds false
// positives
diff --git a/scripts/coccinelle/misc/semicolon.cocci b/scripts/coccinelle/misc/semicolon.cocci
index a53edb026dad..4476bf873deb 100644
--- a/scripts/coccinelle/misc/semicolon.cocci
+++ b/scripts/coccinelle/misc/semicolon.cocci
@@ -4,7 +4,7 @@
///
// Confidence: Moderate
// Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments: Some false positives on empty default cases in switch statements.
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/misc/swap.cocci b/scripts/coccinelle/misc/swap.cocci
new file mode 100644
index 000000000000..c5e71b7ef7f5
--- /dev/null
+++ b/scripts/coccinelle/misc/swap.cocci
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded swap() implementation.
+///
+// Confidence: High
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: swap
+//
+
+virtual patch
+virtual org
+virtual report
+virtual context
+
+@rvar depends on !patch@
+identifier tmp;
+expression a, b;
+type T;
+position p;
+@@
+
+(
+* T tmp;
+|
+* T tmp = 0;
+|
+* T *tmp = NULL;
+)
+... when != tmp
+* tmp = a;
+* a = b;@p
+* b = tmp;
+... when != tmp
+
+@r depends on !patch@
+identifier tmp;
+expression a, b;
+position p != rvar.p;
+@@
+
+* tmp = a;
+* a = b;@p
+* b = tmp;
+
+@rpvar depends on patch@
+identifier tmp;
+expression a, b;
+type T;
+@@
+
+(
+- T tmp;
+|
+- T tmp = 0;
+|
+- T *tmp = NULL;
+)
+... when != tmp
+- tmp = a;
+- a = b;
+- b = tmp
++ swap(a, b)
+ ;
+... when != tmp
+
+@rp depends on patch@
+identifier tmp;
+expression a, b;
+@@
+
+- tmp = a;
+- a = b;
+- b = tmp
++ swap(a, b)
+ ;
+
+@depends on patch && (rpvar || rp)@
+@@
+
+(
+ for (...;...;...)
+- {
+ swap(...);
+- }
+|
+ while (...)
+- {
+ swap(...);
+- }
+|
+ if (...)
+- {
+ swap(...);
+- }
+)
+
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for swap()")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for swap()")
+
+@script:python depends on report@
+p << rvar.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for swap()")
+
+@script:python depends on org@
+p << rvar.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for swap()")
diff --git a/scripts/coccinelle/misc/ifaddr.cocci b/scripts/coccinelle/misc/test_addr.cocci
index fc92e8fcbfcb..d559b297476c 100644
--- a/scripts/coccinelle/misc/ifaddr.cocci
+++ b/scripts/coccinelle/misc/test_addr.cocci
@@ -4,7 +4,7 @@
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
@@ -14,12 +14,10 @@ virtual context
@r@
expression x;
-statement S1,S2;
position p;
@@
-*if@p (&x)
- S1 else S2
+*\(&x@p == NULL \| &x@p != NULL\)
@script:python depends on org@
p << r.p;
diff --git a/scripts/coccinelle/misc/uninitialized_var.cocci b/scripts/coccinelle/misc/uninitialized_var.cocci
index 8fa845cefe11..69bbaae47e73 100644
--- a/scripts/coccinelle/misc/uninitialized_var.cocci
+++ b/scripts/coccinelle/misc/uninitialized_var.cocci
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
///
/// Please, don't reintroduce uninitialized_var().
-/// From Documentation/process/deprecated.rst:
+///
+/// From Documentation/process/deprecated.rst,
+/// commit 4b19bec97c88 ("docs: deprecated.rst: Add uninitialized_var()"):
/// For any compiler warnings about uninitialized variables, just add
/// an initializer. Using warning-silencing tricks is dangerous as it
/// papers over real bugs (or can in the future), and suppresses unrelated
@@ -11,6 +13,11 @@
/// obviously redundant, the compiler's dead-store elimination pass will make
/// sure there are no needless variable writes.
///
+/// Later, commit 3942ea7a10c9 ("deprecated.rst: Remove now removed
+/// uninitialized_var") removed this section because all initializations of
+/// this kind were cleaned-up from the kernel. This cocci rule checks that
+/// the macro is not explicitly or implicitly reintroduced.
+///
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
@@ -40,12 +47,10 @@ position p;
p << r.p;
@@
-coccilib.report.print_report(p[0],
- "WARNING this kind of initialization is deprecated (https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
+coccilib.report.print_report(p[0], "WARNING this kind of initialization is deprecated")
@script:python depends on org@
p << r.p;
@@
-coccilib.org.print_todo(p[0],
- "WARNING this kind of initialization is deprecated (https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
+coccilib.org.print_todo(p[0], "WARNING this kind of initialization is deprecated")
diff --git a/scripts/coccinelle/misc/warn.cocci b/scripts/coccinelle/misc/warn.cocci
index e379661e240d..b5f428035d03 100644
--- a/scripts/coccinelle/misc/warn.cocci
+++ b/scripts/coccinelle/misc/warn.cocci
@@ -4,7 +4,7 @@
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/null/badzero.cocci b/scripts/coccinelle/null/badzero.cocci
index 882dd65313ab..35d443825c2a 100644
--- a/scripts/coccinelle/null/badzero.cocci
+++ b/scripts/coccinelle/null/badzero.cocci
@@ -10,7 +10,7 @@
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Requires: 1.0.0
// Options:
diff --git a/scripts/coccinelle/null/deref_null.cocci b/scripts/coccinelle/null/deref_null.cocci
index 98f1e7faf503..fdf098d4f522 100644
--- a/scripts/coccinelle/null/deref_null.cocci
+++ b/scripts/coccinelle/null/deref_null.cocci
@@ -7,7 +7,7 @@
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments: -I ... -all_includes can give more complete results
// Options:
diff --git a/scripts/coccinelle/null/eno.cocci b/scripts/coccinelle/null/eno.cocci
index 81584ff87956..7107d6c8db9e 100644
--- a/scripts/coccinelle/null/eno.cocci
+++ b/scripts/coccinelle/null/eno.cocci
@@ -5,7 +5,7 @@
// Copyright: (C) 2010-2012 Nicolas Palix.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/null/kmerr.cocci b/scripts/coccinelle/null/kmerr.cocci
index d0e004d4e130..68db20de62eb 100644
--- a/scripts/coccinelle/null/kmerr.cocci
+++ b/scripts/coccinelle/null/kmerr.cocci
@@ -9,7 +9,7 @@
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/tests/doublebitand.cocci b/scripts/coccinelle/tests/doublebitand.cocci
index 0f0b94e7debd..025436a15040 100644
--- a/scripts/coccinelle/tests/doublebitand.cocci
+++ b/scripts/coccinelle/tests/doublebitand.cocci
@@ -9,7 +9,7 @@
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/tests/doubletest.cocci b/scripts/coccinelle/tests/doubletest.cocci
index b35519cddb13..c3d94c31959f 100644
--- a/scripts/coccinelle/tests/doubletest.cocci
+++ b/scripts/coccinelle/tests/doubletest.cocci
@@ -8,7 +8,7 @@
// Copyright: (C) 2010 Nicolas Palix, DIKU.
// Copyright: (C) 2010 Julia Lawall, DIKU.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Comments:
// Options: --no-includes --include-headers
diff --git a/scripts/coccinelle/tests/odd_ptr_err.cocci b/scripts/coccinelle/tests/odd_ptr_err.cocci
index 11d4e2b6deb8..377436abe2d0 100644
--- a/scripts/coccinelle/tests/odd_ptr_err.cocci
+++ b/scripts/coccinelle/tests/odd_ptr_err.cocci
@@ -6,7 +6,7 @@
// Confidence: High
// Copyright: (C) 2012, 2015 Julia Lawall, INRIA.
// Copyright: (C) 2012, 2015 Gilles Muller, INRIA.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --no-includes --include-headers
virtual patch
diff --git a/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci b/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci
index 91e286ace54c..5e188c62d8a9 100644
--- a/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci
+++ b/scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci
@@ -13,7 +13,7 @@
///
// Confidence: Average
// Copyright: (C) 2015 Andrzej Hajda, Samsung Electronics Co., Ltd.
-// URL: http://coccinelle.lip6.fr/
+// URL: https://coccinelle.gitlabpages.inria.fr/website
// Options: --all-includes
virtual context
diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch
index 1aae4f4fdacc..dc39d938ea77 100644
--- a/scripts/const_structs.checkpatch
+++ b/scripts/const_structs.checkpatch
@@ -12,49 +12,70 @@ driver_info
drm_connector_funcs
drm_encoder_funcs
drm_encoder_helper_funcs
+dvb_frontend_ops
+dvb_tuner_ops
ethtool_ops
extent_io_ops
+fb_ops
file_lock_operations
file_operations
hv_ops
+hwmon_ops
+ib_device_ops
ide_dma_ops
ide_port_ops
+ieee80211_ops
+iio_buffer_setup_ops
inode_operations
intel_dvo_dev_ops
irq_domain_ops
item_operations
iwl_cfg
iwl_ops
+kernel_param_ops
kgdb_arch
kgdb_io
+kobj_type
kset_uevent_ops
lock_manager_operations
machine_desc
microcode_ops
mlxsw_reg_info
+mtd_ooblayout_ops
mtrr_ops
+nand_controller_ops
neigh_ops
net_device_ops
+nft_expr_ops
nlmsvc_binding
nvkm_device_chip
of_device_id
pci_raw_ops
phy_ops
+pinconf_ops
pinctrl_ops
pinmux_ops
pipe_buf_operations
platform_hibernation_ops
platform_suspend_ops
+proc_ops
proto_ops
+pwm_ops
regmap_access_table
regulator_ops
+reset_control_ops
rpc_pipe_ops
rtc_class_ops
sd_desc
+sdhci_ops
seq_operations
sirfsoc_padmux
snd_ac97_build_ops
+snd_pcm_ops
+snd_rawmidi_ops
snd_soc_component_driver
+snd_soc_dai_ops
+snd_soc_ops
soc_pcmcia_socket_ops
stacktrace_ops
sysfs_ops
@@ -63,6 +84,13 @@ uart_ops
usb_mon_operations
v4l2_ctrl_ops
v4l2_ioctl_ops
+v4l2_subdev_core_ops
+v4l2_subdev_internal_ops
+v4l2_subdev_ops
+v4l2_subdev_pad_ops
+v4l2_subdev_video_ops
+vb2_ops
vm_operations_struct
wacom_features
+watchdog_ops
wd_ops
diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh
index 90398347e366..564c5632e1a2 100755
--- a/scripts/decode_stacktrace.sh
+++ b/scripts/decode_stacktrace.sh
@@ -3,10 +3,17 @@
# (c) 2014, Sasha Levin <sasha.levin@oracle.com>
#set -x
-if [[ $# < 1 ]]; then
+usage() {
echo "Usage:"
- echo " $0 -r <release> | <vmlinux> [base path] [modules path]"
- exit 1
+ echo " $0 -r <release> | <vmlinux> [<base path>|auto] [<modules path>]"
+}
+
+# Try to find a Rust demangler
+if type llvm-cxxfilt >/dev/null 2>&1 ; then
+ cppfilt=llvm-cxxfilt
+elif type c++filt >/dev/null 2>&1 ; then
+ cppfilt=c++filt
+ cppfilt_opts=-i
fi
if [[ $1 == "-r" ]] ; then
@@ -24,6 +31,7 @@ if [[ $1 == "-r" ]] ; then
if [[ $vmlinux == "" ]] ; then
echo "ERROR! vmlinux image for release $release is not found" >&2
+ usage
exit 2
fi
else
@@ -31,12 +39,40 @@ else
basepath=${2-auto}
modpath=$3
release=""
+ debuginfod=
+
+ # Can we use debuginfod-find?
+ if type debuginfod-find >/dev/null 2>&1 ; then
+ debuginfod=${1-only}
+ fi
+
+ if [[ $vmlinux == "" && -z $debuginfod ]] ; then
+ echo "ERROR! vmlinux image must be specified" >&2
+ usage
+ exit 1
+ fi
fi
-declare -A cache
-declare -A modcache
+declare aarray_support=true
+declare -A cache 2>/dev/null
+if [[ $? != 0 ]]; then
+ aarray_support=false
+else
+ declare -A modcache
+fi
find_module() {
+ if [[ -n $debuginfod ]] ; then
+ if [[ -n $modbuildid ]] ; then
+ debuginfod-find debuginfo $modbuildid && return
+ fi
+
+ # Only using debuginfod so don't try to find vmlinux module path
+ if [[ $debuginfod == "only" ]] ; then
+ return
+ fi
+ fi
+
if [[ "$modpath" != "" ]] ; then
for fn in $(find "$modpath" -name "${module//_/[-_]}.ko*") ; do
if readelf -WS "$fn" | grep -qwF .debug_line ; then
@@ -51,7 +87,7 @@ find_module() {
find_module && return
if [[ $release == "" ]] ; then
- release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" | sed -n 's/\$1 = "\(.*\)".*/\1/p')
+ release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" 2>/dev/null | sed -n 's/\$1 = "\(.*\)".*/\1/p')
fi
for dn in {/usr/lib/debug,}/lib/modules/$release ; do
@@ -74,7 +110,7 @@ parse_symbol() {
if [[ $module == "" ]] ; then
local objfile=$vmlinux
- elif [[ "${modcache[$module]+isset}" == "isset" ]]; then
+ elif [[ $aarray_support == true && "${modcache[$module]+isset}" == "isset" ]]; then
local objfile=${modcache[$module]}
else
local objfile=$(find_module)
@@ -82,7 +118,9 @@ parse_symbol() {
echo "WARNING! Modules path isn't set, but is needed to parse this symbol" >&2
return
fi
- modcache[$module]=$objfile
+ if [[ $aarray_support == true ]]; then
+ modcache[$module]=$objfile
+ fi
fi
# Remove the englobing parenthesis
@@ -102,15 +140,17 @@ parse_symbol() {
# Use 'nm vmlinux' to figure out the base address of said symbol.
# It's actually faster to call it every time than to load it
# all into bash.
- if [[ "${cache[$module,$name]+isset}" == "isset" ]]; then
+ if [[ $aarray_support == true && "${cache[$module,$name]+isset}" == "isset" ]]; then
local base_addr=${cache[$module,$name]}
else
- local base_addr=$(nm "$objfile" | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}')
+ local base_addr=$(nm "$objfile" 2>/dev/null | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}')
if [[ $base_addr == "" ]] ; then
# address not found
return
fi
- cache[$module,$name]="$base_addr"
+ if [[ $aarray_support == true ]]; then
+ cache[$module,$name]="$base_addr"
+ fi
fi
# Let's start doing the math to get the exact address into the
# symbol. First, strip out the symbol total length.
@@ -126,11 +166,13 @@ parse_symbol() {
# Pass it to addr2line to get filename and line number
# Could get more than one result
- if [[ "${cache[$module,$address]+isset}" == "isset" ]]; then
+ if [[ $aarray_support == true && "${cache[$module,$address]+isset}" == "isset" ]]; then
local code=${cache[$module,$address]}
else
- local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address")
- cache[$module,$address]=$code
+ local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address" 2>/dev/null)
+ if [[ $aarray_support == true ]]; then
+ cache[$module,$address]=$code
+ fi
fi
# addr2line doesn't return a proper error code if it fails, so
@@ -146,10 +188,37 @@ parse_symbol() {
# In the case of inlines, move everything to same line
code=${code//$'\n'/' '}
+ # Demangle if the name looks like a Rust symbol and if
+ # we got a Rust demangler
+ if [[ $name =~ ^_R && $cppfilt != "" ]] ; then
+ name=$("$cppfilt" "$cppfilt_opts" "$name")
+ fi
+
# Replace old address with pretty line numbers
symbol="$segment$name ($code)"
}
+debuginfod_get_vmlinux() {
+ local vmlinux_buildid=${1##* }
+
+ if [[ $vmlinux != "" ]]; then
+ return
+ fi
+
+ if [[ $vmlinux_buildid =~ ^[0-9a-f]+ ]]; then
+ vmlinux=$(debuginfod-find debuginfo $vmlinux_buildid)
+ if [[ $? -ne 0 ]] ; then
+ echo "ERROR! vmlinux image not found via debuginfod-find" >&2
+ usage
+ exit 2
+ fi
+ return
+ fi
+ echo "ERROR! Build ID for vmlinux not found. Try passing -r or specifying vmlinux" >&2
+ usage
+ exit 2
+}
+
decode_code() {
local scripts=`dirname "${BASH_SOURCE[0]}"`
@@ -157,6 +226,14 @@ decode_code() {
}
handle_line() {
+ if [[ $basepath == "auto" && $vmlinux != "" ]] ; then
+ module=""
+ symbol="kernel_init+0x0/0x0"
+ parse_symbol
+ basepath=${symbol#kernel_init (}
+ basepath=${basepath%/init/main.c:*)}
+ fi
+
local words
# Tokenize
@@ -182,16 +259,28 @@ handle_line() {
fi
done
+ if [[ ${words[$last]} =~ ^[0-9a-f]+\] ]]; then
+ words[$last-1]="${words[$last-1]} ${words[$last]}"
+ unset words[$last]
+ last=$(( $last - 1 ))
+ fi
+
if [[ ${words[$last]} =~ \[([^]]+)\] ]]; then
module=${words[$last]}
module=${module#\[}
module=${module%\]}
+ modbuildid=${module#* }
+ module=${module% *}
+ if [[ $modbuildid == $module ]]; then
+ modbuildid=
+ fi
symbol=${words[$last-1]}
unset words[$last-1]
else
# The symbol is the last element, process it
symbol=${words[$last]}
module=
+ modbuildid=
fi
unset words[$last]
@@ -201,14 +290,6 @@ handle_line() {
echo "${words[@]}" "$symbol $module"
}
-if [[ $basepath == "auto" ]] ; then
- module=""
- symbol="kernel_init+0x0/0x0"
- parse_symbol
- basepath=${symbol#kernel_init (}
- basepath=${basepath%/init/main.c:*)}
-fi
-
while read line; do
# Let's see if we have an address in the line
if [[ $line =~ \[\<([^]]+)\>\] ]] ||
@@ -218,6 +299,9 @@ while read line; do
# Is it a code line?
elif [[ $line == *Code:* ]]; then
decode_code "$line"
+ # Is it a version line?
+ elif [[ -n $debuginfod && $line =~ PID:\ [0-9]+\ Comm: ]]; then
+ debuginfod_get_vmlinux "$line"
else
# Nothing special in this line, show it as is
echo "$line"
diff --git a/scripts/decodecode b/scripts/decodecode
index 31d884e35f2f..8fe71c292381 100755
--- a/scripts/decodecode
+++ b/scripts/decodecode
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Disassemble the Code: line in Linux oopses
# usage: decodecode < oops.file
@@ -8,6 +8,8 @@
# AFLAGS=--32 decodecode < 386.oops
# PC=hex - the PC (program counter) the oops points to
+faultlinenum=1
+
cleanup() {
rm -f $T $T.s $T.o $T.oo $T.aa $T.dis
exit 1
@@ -91,6 +93,11 @@ disas() {
${CROSS_COMPILE}strip $t.o
fi
+ if [ "$ARCH" = "riscv" ]; then
+ OBJDUMPFLAGS="-M no-aliases --section=.text -D"
+ ${CROSS_COMPILE}strip $t.o
+ fi
+
if [ $pc_sub -ne 0 ]; then
if [ $PC ]; then
adj_vma=$(( $PC - $pc_sub ))
@@ -102,45 +109,138 @@ disas() {
grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1
}
+# Match the maximum number of opcode bytes from @op_bytes contained within
+# @opline
+#
+# Params:
+# @op_bytes: The string of bytes from the Code: line
+# @opline: The disassembled line coming from objdump
+#
+# Returns:
+# The max number of opcode bytes from the beginning of @op_bytes which match
+# the opcode bytes in the objdump line.
+get_substr_opcode_bytes_num()
+{
+ local op_bytes=$1
+ local opline=$2
+
+ local retval=0
+ substr=""
+
+ for opc in $op_bytes;
+ do
+ substr+="$opc"
+
+ opcode="$substr"
+ if [ "$ARCH" = "riscv" ]; then
+ opcode=$(echo $opcode | tr ' ' '\n' | tac | tr -d '\n')
+ fi
+
+ # return if opcode bytes do not match @opline anymore
+ if ! echo $opline | grep -q "$opcode";
+ then
+ break
+ fi
+
+ # add trailing space
+ substr+=" "
+ retval=$((retval+1))
+ done
+
+ return $retval
+}
+
+# Return the line number in objdump output to where the IP marker in the Code:
+# line points to
+#
+# Params:
+# @all_code: code in bytes without the marker
+# @dis_file: disassembled file
+# @ip_byte: The byte to which the IP points to
+get_faultlinenum()
+{
+ local all_code="$1"
+ local dis_file="$2"
+
+ # num bytes including IP byte
+ local num_bytes_ip=$(( $3 + 1 * $width ))
+
+ # Add the two header lines (we're counting from 1).
+ local retval=3
+
+ # remove marker
+ all_code=$(echo $all_code | sed -e 's/[<>()]//g')
+
+ while read line
+ do
+ get_substr_opcode_bytes_num "$all_code" "$line"
+ ate_opcodes=$?
+
+ if ! (( $ate_opcodes )); then
+ continue
+ fi
+
+ num_bytes_ip=$((num_bytes_ip - ($ate_opcodes * $width) ))
+ if (( $num_bytes_ip <= 0 )); then
+ break
+ fi
+
+ # Delete matched opcode bytes from all_code. For that, compute
+ # how many chars those opcodes are represented by and include
+ # trailing space.
+ #
+ # a byte is 2 chars, ate_opcodes is also the number of trailing
+ # spaces
+ del_chars=$(( ($ate_opcodes * $width * 2) + $ate_opcodes ))
+
+ all_code=$(echo $all_code | sed -e "s!^.\{$del_chars\}!!")
+
+ let "retval+=1"
+
+ done < $dis_file
+
+ return $retval
+}
+
marker=`expr index "$code" "\<"`
if [ $marker -eq 0 ]; then
marker=`expr index "$code" "\("`
fi
-
touch $T.oo
if [ $marker -ne 0 ]; then
- # 2 opcode bytes and a single space
- pc_sub=$(( $marker / 3 ))
+ # How many bytes to subtract from the program counter
+ # in order to get to the beginning virtual address of the
+ # Code:
+ pc_sub=$(( (($marker - 1) / (2 * $width + 1)) * $width ))
echo All code >> $T.oo
echo ======== >> $T.oo
beforemark=`echo "$code"`
echo -n " .$type 0x" > $T.s
+
echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s
+
disas $T $pc_sub
+
cat $T.dis >> $T.oo
- rm -f $T.o $T.s $T.dis
-# and fix code at-and-after marker
+ get_faultlinenum "$code" "$T.dis" $pc_sub
+ faultlinenum=$?
+
+ # and fix code at-and-after marker
code=`echo "$code" | cut -c$((${marker} + 1))-`
+
+ rm -f $T.o $T.s $T.dis
fi
+
echo Code starting with the faulting instruction > $T.aa
echo =========================================== >> $T.aa
-code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`
+code=`echo $code | sed -e 's/\r//;s/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`
echo -n " .$type 0x" > $T.s
echo $code >> $T.s
disas $T 0
cat $T.dis >> $T.aa
-# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3,
-# i.e. the title + the "===..=" line (sed is counting from 1, 0 address is
-# special)
-faultlinenum=$(( $(wc -l $T.oo | cut -d" " -f1) - \
- $(wc -l $T.aa | cut -d" " -f1) + 3))
-
-faultline=`cat $T.dis | head -1 | cut -d":" -f2-`
-faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
-
cat $T.oo | sed -e "${faultlinenum}s/^\([^:]*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/"
echo
cat $T.aa
diff --git a/scripts/depmod.sh b/scripts/depmod.sh
index 3643b4f896ed..1fbc4872b8f4 100755
--- a/scripts/depmod.sh
+++ b/scripts/depmod.sh
@@ -23,6 +23,12 @@ if [ -z $(command -v $DEPMOD) ]; then
exit 0
fi
+if [ -z $(command -v $DEPMOD) ]; then
+ echo "'make modules_install' requires $DEPMOD. Please install it." >&2
+ echo "This is probably in the kmod package." >&2
+ exit 1
+fi
+
# older versions of depmod require the version string to start with three
# numbers, so we cheat with a symlink here
depmod_hack_needed=true
diff --git a/scripts/diffconfig b/scripts/diffconfig
index d5da5fa05d1d..43f0f3d273ae 100755
--- a/scripts/diffconfig
+++ b/scripts/diffconfig
@@ -65,7 +65,7 @@ def print_config(op, config, value, new_value):
else:
print(" %s %s -> %s" % (config, value, new_value))
-def main():
+def show_diff():
global merge_style
# parse command line args
@@ -129,4 +129,16 @@ def main():
for config in new:
print_config("+", config, None, b[config])
-main()
+def main():
+ try:
+ show_diff()
+ except BrokenPipeError:
+ # Python flushes standard streams on exit; redirect remaining output
+ # to devnull to avoid another BrokenPipeError at shutdown
+ devnull = os.open(os.devnull, os.O_WRONLY)
+ os.dup2(devnull, sys.stdout.fileno())
+ sys.exit(1) # Python exits with error code 1 on EPIPE
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/documentation-file-ref-check b/scripts/documentation-file-ref-check
index c71832b2312b..68083f2f1122 100755
--- a/scripts/documentation-file-ref-check
+++ b/scripts/documentation-file-ref-check
@@ -24,7 +24,7 @@ my $help = 0;
my $fix = 0;
my $warn = 0;
-if (! -d ".git") {
+if (! -e ".git") {
printf "Warning: can't check if file exists, as this is not a git tree\n";
exit 0;
}
@@ -94,6 +94,9 @@ while (<IN>) {
# Makefiles and scripts contain nasty expressions to parse docs
next if ($f =~ m/Makefile/ || $f =~ m/\.sh$/);
+ # It doesn't make sense to parse hidden files
+ next if ($f =~ m#/\.#);
+
# Skip this script
next if ($f eq $scriptname);
@@ -144,6 +147,7 @@ while (<IN>) {
if ($f =~ m/tools/) {
my $path = $f;
$path =~ s,(.*)/.*,$1,;
+ $path =~ s,testing/selftests/bpf,bpf/bpftool,;
next if (grep -e, glob("$path/$ref $path/../$ref $path/$fulref"));
}
diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore
index 8a8b62bf3d3c..e0b5c1d2464a 100644
--- a/scripts/dtc/.gitignore
+++ b/scripts/dtc/.gitignore
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-dtc
-fdtoverlay
+/dtc
+/fdtoverlay
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile
index 95aaf7431bff..4d32b9497da9 100644
--- a/scripts/dtc/Makefile
+++ b/scripts/dtc/Makefile
@@ -17,20 +17,7 @@ fdtoverlay-objs := $(libfdt) fdtoverlay.o util.o
# Source files need to get at the userspace version of libfdt_env.h to compile
HOST_EXTRACFLAGS += -I $(srctree)/$(src)/libfdt
-
-ifeq ($(shell pkg-config --exists yaml-0.1 2>/dev/null && echo yes),)
-ifneq ($(CHECK_DT_BINDING)$(CHECK_DTBS),)
-$(error dtc needs libyaml for DT schema validation support. \
- Install the necessary libyaml development package.)
-endif
HOST_EXTRACFLAGS += -DNO_YAML
-else
-dtc-objs += yamltree.o
-# To include <yaml.h> installed in a non-default path
-HOSTCFLAGS_yamltree.o := $(shell pkg-config --cflags yaml-0.1)
-# To link libyaml installed in a non-default path
-HOSTLDLIBS_dtc := $(shell pkg-config yaml-0.1 --libs)
-endif
# Generated files need one more search path to include headers in source tree
HOSTCFLAGS_dtc-lexer.lex.o := -I $(srctree)/$(src)
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
index 17cb6890d45a..9f31d2607182 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -143,6 +143,14 @@ static void check_nodes_props(struct check *c, struct dt_info *dti, struct node
check_nodes_props(c, dti, child);
}
+static bool is_multiple_of(int multiple, int divisor)
+{
+ if (divisor == 0)
+ return multiple == 0;
+ else
+ return (multiple % divisor) == 0;
+}
+
static bool run_check(struct check *c, struct dt_info *dti)
{
struct node *dt = dti->dt;
@@ -297,19 +305,20 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define DIGITS "0123456789"
-#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
+#define NODECHARS LOWERCASE UPPERCASE DIGITS ",._+-@"
+#define PROPCHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
#define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-"
static void check_node_name_chars(struct check *c, struct dt_info *dti,
struct node *node)
{
- int n = strspn(node->name, c->data);
+ size_t n = strspn(node->name, c->data);
if (n < strlen(node->name))
FAIL(c, dti, node, "Bad character '%c' in node name",
node->name[n]);
}
-ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
+ERROR(node_name_chars, check_node_name_chars, NODECHARS);
static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
struct node *node)
@@ -330,6 +339,20 @@ static void check_node_name_format(struct check *c, struct dt_info *dti,
}
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
+static void check_node_name_vs_property_name(struct check *c,
+ struct dt_info *dti,
+ struct node *node)
+{
+ if (!node->parent)
+ return;
+
+ if (get_property(node->parent, node->name)) {
+ FAIL(c, dti, node, "node name and property name conflict");
+ }
+}
+WARNING(node_name_vs_property_name, check_node_name_vs_property_name,
+ NULL, &node_name_chars);
+
static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
struct node *node)
{
@@ -363,14 +386,14 @@ static void check_property_name_chars(struct check *c, struct dt_info *dti,
struct property *prop;
for_each_property(node, prop) {
- int n = strspn(prop->name, c->data);
+ size_t n = strspn(prop->name, c->data);
if (n < strlen(prop->name))
FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name",
prop->name[n]);
}
}
-ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
+ERROR(property_name_chars, check_property_name_chars, PROPCHARS);
static void check_property_name_chars_strict(struct check *c,
struct dt_info *dti,
@@ -380,7 +403,7 @@ static void check_property_name_chars_strict(struct check *c,
for_each_property(node, prop) {
const char *name = prop->name;
- int n = strspn(name, c->data);
+ size_t n = strspn(name, c->data);
if (n == strlen(prop->name))
continue;
@@ -497,7 +520,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
phandle = propval_cell(prop);
- if ((phandle == 0) || (phandle == -1)) {
+ if (!phandle_is_valid(phandle)) {
FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property",
phandle, prop->name);
return 0;
@@ -556,7 +579,7 @@ static void check_name_properties(struct check *c, struct dt_info *dti,
if (!prop)
return; /* No name property, that's fine */
- if ((prop->val.len != node->basenamelen+1)
+ if ((prop->val.len != node->basenamelen + 1U)
|| (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead"
" of base node name)", prop->val.val);
@@ -657,7 +680,6 @@ ERROR(omit_unused_nodes, fixup_omit_unused_nodes, NULL, &phandle_references, &pa
*/
WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells");
WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells");
-WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells");
WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
WARNING_IF_NOT_STRING(model_is_string, "model");
@@ -672,8 +694,7 @@ static void check_names_is_string_list(struct check *c, struct dt_info *dti,
struct property *prop;
for_each_property(node, prop) {
- const char *s = strrchr(prop->name, '-');
- if (!s || !streq(s, "-names"))
+ if (!strends(prop->name, "-names"))
continue;
c->data = prop->name;
@@ -753,7 +774,7 @@ static void check_reg_format(struct check *c, struct dt_info *dti,
size_cells = node_size_cells(node->parent);
entrylen = (addr_cells + size_cells) * sizeof(cell_t);
- if (!entrylen || (prop->val.len % entrylen) != 0)
+ if (!is_multiple_of(prop->val.len, entrylen))
FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) "
"(#address-cells == %d, #size-cells == %d)",
prop->val.len, addr_cells, size_cells);
@@ -794,7 +815,7 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
"#size-cells (%d) differs from %s (%d)",
ranges, c_size_cells, node->parent->fullpath,
p_size_cells);
- } else if ((prop->val.len % entrylen) != 0) {
+ } else if (!is_multiple_of(prop->val.len, entrylen)) {
FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) "
"(parent #address-cells == %d, child #address-cells == %d, "
"#size-cells == %d)", ranges, prop->val.len,
@@ -871,7 +892,7 @@ static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struc
} else {
cells = (cell_t *)prop->val.val;
min_bus = fdt32_to_cpu(cells[0]);
- max_bus = fdt32_to_cpu(cells[0]);
+ max_bus = fdt32_to_cpu(cells[1]);
}
if ((bus_num < min_bus) || (bus_num > max_bus))
FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)",
@@ -1361,15 +1382,15 @@ struct provider {
};
static void check_property_phandle_args(struct check *c,
- struct dt_info *dti,
- struct node *node,
- struct property *prop,
- const struct provider *provider)
+ struct dt_info *dti,
+ struct node *node,
+ struct property *prop,
+ const struct provider *provider)
{
struct node *root = dti->dt;
- int cell, cellsize = 0;
+ unsigned int cell, cellsize = 0;
- if (prop->val.len % sizeof(cell_t)) {
+ if (!is_multiple_of(prop->val.len, sizeof(cell_t))) {
FAIL_PROP(c, dti, node, prop,
"property size (%d) is invalid, expected multiple of %zu",
prop->val.len, sizeof(cell_t));
@@ -1379,14 +1400,15 @@ static void check_property_phandle_args(struct check *c,
for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) {
struct node *provider_node;
struct property *cellprop;
- int phandle;
+ cell_t phandle;
+ unsigned int expected;
phandle = propval_cell_n(prop, cell);
/*
* Some bindings use a cell value 0 or -1 to skip over optional
* entries when each index position has a specific definition.
*/
- if (phandle == 0 || phandle == -1) {
+ if (!phandle_is_valid(phandle)) {
/* Give up if this is an overlay with external references */
if (dti->dtsflags & DTSF_PLUGIN)
break;
@@ -1429,10 +1451,12 @@ static void check_property_phandle_args(struct check *c,
break;
}
- if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) {
+ expected = (cell + cellsize + 1) * sizeof(cell_t);
+ if ((expected <= cell) || prop->val.len < expected) {
FAIL_PROP(c, dti, node, prop,
- "property size (%d) too small for cell size %d",
+ "property size (%d) too small for cell size %u",
prop->val.len, cellsize);
+ break;
}
}
}
@@ -1452,7 +1476,8 @@ static void check_provider_cells_property(struct check *c,
}
#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \
static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \
- WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references);
+ WARNING_IF_NOT_CELL(nm##_is_cell, cells_name); \
+ WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &nm##_is_cell, &phandle_references);
WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells");
WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells");
@@ -1473,24 +1498,17 @@ WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sen
static bool prop_is_gpio(struct property *prop)
{
- char *str;
-
/*
* *-gpios and *-gpio can appear in property names,
* so skip over any false matches (only one known ATM)
*/
- if (strstr(prop->name, "nr-gpio"))
+ if (strends(prop->name, ",nr-gpios"))
return false;
- str = strrchr(prop->name, '-');
- if (str)
- str++;
- else
- str = prop->name;
- if (!(streq(str, "gpios") || streq(str, "gpio")))
- return false;
-
- return true;
+ return strends(prop->name, "-gpios") ||
+ streq(prop->name, "gpios") ||
+ strends(prop->name, "-gpio") ||
+ streq(prop->name, "gpio");
}
static void check_gpios_property(struct check *c,
@@ -1525,13 +1543,10 @@ static void check_deprecated_gpio_property(struct check *c,
struct property *prop;
for_each_property(node, prop) {
- char *str;
-
if (!prop_is_gpio(prop))
continue;
- str = strstr(prop->name, "gpio");
- if (!streq(str, "gpio"))
+ if (!strends(prop->name, "gpio"))
continue;
FAIL_PROP(c, dti, node, prop,
@@ -1561,21 +1576,106 @@ static void check_interrupt_provider(struct check *c,
struct node *node)
{
struct property *prop;
+ bool irq_provider = node_is_interrupt_provider(node);
- if (!node_is_interrupt_provider(node))
+ prop = get_property(node, "#interrupt-cells");
+ if (irq_provider && !prop) {
+ FAIL(c, dti, node,
+ "Missing '#interrupt-cells' in interrupt provider");
return;
+ }
- prop = get_property(node, "#interrupt-cells");
- if (!prop)
+ if (!irq_provider && prop) {
FAIL(c, dti, node,
- "Missing #interrupt-cells in interrupt provider");
+ "'#interrupt-cells' found, but node is not an interrupt provider");
+ return;
+ }
+}
+WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell);
- prop = get_property(node, "#address-cells");
- if (!prop)
+static void check_interrupt_map(struct check *c,
+ struct dt_info *dti,
+ struct node *node)
+{
+ struct node *root = dti->dt;
+ struct property *prop, *irq_map_prop;
+ size_t cellsize, cell, map_cells;
+
+ irq_map_prop = get_property(node, "interrupt-map");
+ if (!irq_map_prop)
+ return;
+
+ if (node->addr_cells < 0) {
FAIL(c, dti, node,
- "Missing #address-cells in interrupt provider");
+ "Missing '#address-cells' in interrupt-map provider");
+ return;
+ }
+ cellsize = node_addr_cells(node);
+ cellsize += propval_cell(get_property(node, "#interrupt-cells"));
+
+ prop = get_property(node, "interrupt-map-mask");
+ if (prop && (prop->val.len != (cellsize * sizeof(cell_t))))
+ FAIL_PROP(c, dti, node, prop,
+ "property size (%d) is invalid, expected %zu",
+ prop->val.len, cellsize * sizeof(cell_t));
+
+ if (!is_multiple_of(irq_map_prop->val.len, sizeof(cell_t))) {
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "property size (%d) is invalid, expected multiple of %zu",
+ irq_map_prop->val.len, sizeof(cell_t));
+ return;
+ }
+
+ map_cells = irq_map_prop->val.len / sizeof(cell_t);
+ for (cell = 0; cell < map_cells; ) {
+ struct node *provider_node;
+ struct property *cellprop;
+ int phandle;
+ size_t parent_cellsize;
+
+ if ((cell + cellsize) >= map_cells) {
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "property size (%d) too small, expected > %zu",
+ irq_map_prop->val.len, (cell + cellsize) * sizeof(cell_t));
+ break;
+ }
+ cell += cellsize;
+
+ phandle = propval_cell_n(irq_map_prop, cell);
+ if (!phandle_is_valid(phandle)) {
+ /* Give up if this is an overlay with external references */
+ if (!(dti->dtsflags & DTSF_PLUGIN))
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "Cell %zu is not a phandle(%d)",
+ cell, phandle);
+ break;
+ }
+
+ provider_node = get_node_by_phandle(root, phandle);
+ if (!provider_node) {
+ FAIL_PROP(c, dti, node, irq_map_prop,
+ "Could not get phandle(%d) node for (cell %zu)",
+ phandle, cell);
+ break;
+ }
+
+ cellprop = get_property(provider_node, "#interrupt-cells");
+ if (cellprop) {
+ parent_cellsize = propval_cell(cellprop);
+ } else {
+ FAIL(c, dti, node, "Missing property '#interrupt-cells' in node %s or bad phandle (referred from interrupt-map[%zu])",
+ provider_node->fullpath, cell);
+ break;
+ }
+
+ cellprop = get_property(provider_node, "#address-cells");
+ if (cellprop)
+ parent_cellsize += propval_cell(cellprop);
+
+ cell += 1 + parent_cellsize;
+ }
}
-WARNING(interrupt_provider, check_interrupt_provider, NULL);
+WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider);
static void check_interrupts_property(struct check *c,
struct dt_info *dti,
@@ -1584,13 +1684,13 @@ static void check_interrupts_property(struct check *c,
struct node *root = dti->dt;
struct node *irq_node = NULL, *parent = node;
struct property *irq_prop, *prop = NULL;
- int irq_cells, phandle;
+ cell_t irq_cells, phandle;
irq_prop = get_property(node, "interrupts");
if (!irq_prop)
return;
- if (irq_prop->val.len % sizeof(cell_t))
+ if (!is_multiple_of(irq_prop->val.len, sizeof(cell_t)))
FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu",
irq_prop->val.len, sizeof(cell_t));
@@ -1603,7 +1703,7 @@ static void check_interrupts_property(struct check *c,
prop = get_property(parent, "interrupt-parent");
if (prop) {
phandle = propval_cell(prop);
- if ((phandle == 0) || (phandle == -1)) {
+ if (!phandle_is_valid(phandle)) {
/* Give up if this is an overlay with
* external references */
if (dti->dtsflags & DTSF_PLUGIN)
@@ -1639,7 +1739,7 @@ static void check_interrupts_property(struct check *c,
}
irq_cells = propval_cell(prop);
- if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) {
+ if (!is_multiple_of(irq_prop->val.len, irq_cells * sizeof(cell_t))) {
FAIL_PROP(c, dti, node, prop,
"size is (%d), expected multiple of %d",
irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)));
@@ -1750,7 +1850,7 @@ WARNING(graph_port, check_graph_port, NULL, &graph_nodes);
static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
struct node *endpoint)
{
- int phandle;
+ cell_t phandle;
struct node *node;
struct property *prop;
@@ -1760,7 +1860,7 @@ static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti,
phandle = propval_cell(prop);
/* Give up if this is an overlay with external references */
- if (phandle == 0 || phandle == -1)
+ if (!phandle_is_valid(phandle))
return NULL;
node = get_node_by_phandle(dti->dt, phandle);
@@ -1796,7 +1896,7 @@ WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names,
&node_name_chars, &node_name_format, &property_name_chars,
- &name_is_string, &name_properties,
+ &name_is_string, &name_properties, &node_name_vs_property_name,
&duplicate_label,
@@ -1804,7 +1904,7 @@ static struct check *check_table[] = {
&phandle_references, &path_references,
&omit_unused_nodes,
- &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
+ &address_cells_is_cell, &size_cells_is_cell,
&device_type_is_string, &model_is_string, &status_is_string,
&label_is_string,
@@ -1839,26 +1939,43 @@ static struct check *check_table[] = {
&chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
&clocks_property,
+ &clocks_is_cell,
&cooling_device_property,
+ &cooling_device_is_cell,
&dmas_property,
+ &dmas_is_cell,
&hwlocks_property,
+ &hwlocks_is_cell,
&interrupts_extended_property,
+ &interrupts_extended_is_cell,
&io_channels_property,
+ &io_channels_is_cell,
&iommus_property,
+ &iommus_is_cell,
&mboxes_property,
+ &mboxes_is_cell,
&msi_parent_property,
+ &msi_parent_is_cell,
&mux_controls_property,
+ &mux_controls_is_cell,
&phys_property,
+ &phys_is_cell,
&power_domains_property,
+ &power_domains_is_cell,
&pwms_property,
+ &pwms_is_cell,
&resets_property,
+ &resets_is_cell,
&sound_dai_property,
+ &sound_dai_is_cell,
&thermal_sensors_property,
+ &thermal_sensors_is_cell,
&deprecated_gpio_property,
&gpios_property,
&interrupts_property,
&interrupt_provider,
+ &interrupt_map,
&alias_paths,
@@ -1882,7 +1999,7 @@ static void enable_warning_error(struct check *c, bool warn, bool error)
static void disable_warning_error(struct check *c, bool warn, bool error)
{
- int i;
+ unsigned int i;
/* Lowering level, also lower it for things this is the prereq
* for */
@@ -1903,7 +2020,7 @@ static void disable_warning_error(struct check *c, bool warn, bool error)
void parse_checks_option(bool warn, bool error, const char *arg)
{
- int i;
+ unsigned int i;
const char *name = arg;
bool enable = true;
@@ -1930,7 +2047,7 @@ void parse_checks_option(bool warn, bool error, const char *arg)
void process_checks(bool force, struct dt_info *dti)
{
- int i;
+ unsigned int i;
int error = 0;
for (i = 0; i < ARRAY_SIZE(check_table); i++) {
diff --git a/scripts/dtc/dt-extract-compatibles b/scripts/dtc/dt-extract-compatibles
new file mode 100755
index 000000000000..a1119762ed08
--- /dev/null
+++ b/scripts/dtc/dt-extract-compatibles
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+
+import os
+import glob
+import re
+import argparse
+
+
+def parse_of_declare_macros(data):
+ """ Find all compatible strings in OF_DECLARE() style macros """
+ compat_list = []
+ # CPU_METHOD_OF_DECLARE does not have a compatible string
+ for m in re.finditer(r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)', data):
+ try:
+ compat = re.search(r'"(.*?)"', m[0])[1]
+ except:
+ # Fails on compatible strings in #define, so just skip
+ continue
+ compat_list += [compat]
+
+ return compat_list
+
+
+def parse_of_device_id(data):
+ """ Find all compatible strings in of_device_id structs """
+ compat_list = []
+ for m in re.finditer(r'of_device_id\s+[a-zA-Z0-9_]+\[\]\s*=\s*({.*?);', data):
+ compat_list += re.findall(r'\.compatible\s+=\s+"([a-zA-Z0-9_\-,]+)"', m[1])
+
+ return compat_list
+
+
+def parse_compatibles(file):
+ with open(file, 'r', encoding='utf-8') as f:
+ data = f.read().replace('\n', '')
+
+ compat_list = parse_of_declare_macros(data)
+ compat_list += parse_of_device_id(data)
+
+ return compat_list
+
+def print_compat(filename, compatibles):
+ if not compatibles:
+ return
+ if show_filename:
+ compat_str = ' '.join(compatibles)
+ print(filename + ": compatible(s): " + compat_str)
+ else:
+ print(*compatibles, sep='\n')
+
+show_filename = False
+
+if __name__ == "__main__":
+ ap = argparse.ArgumentParser()
+ ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse")
+ ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true")
+ args = ap.parse_args()
+
+ show_filename = args.with_filename
+
+ for f in args.cfile:
+ if os.path.isdir(f):
+ for filename in glob.iglob(f + "/**/*.c", recursive=True):
+ compat_list = parse_compatibles(filename)
+ print_compat(filename, compat_list)
+ else:
+ compat_list = parse_compatibles(f)
+ print_compat(f, compat_list)
diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
index b3b7270300de..de60a70b6bdb 100644
--- a/scripts/dtc/dtc-lexer.l
+++ b/scripts/dtc/dtc-lexer.l
@@ -57,7 +57,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
push_input_file(name);
}
-<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
+<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* {
char *line, *fnstart, *fnend;
struct data fn;
/* skip text before line # */
@@ -200,7 +200,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
return DT_LABEL_REF;
}
-<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
+<*>"&{"{PATHCHAR}*\} { /* new-style path reference */
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = xstrdup(yytext+2);
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
index a0316a3cc309..bff1337ec266 100644
--- a/scripts/dtc/dtc-parser.y
+++ b/scripts/dtc/dtc-parser.y
@@ -23,6 +23,12 @@ extern void yyerror(char const *s);
extern struct dt_info *parser_output;
extern bool treesource_error;
+
+static bool is_ref_relative(const char *ref)
+{
+ return ref[0] != '/' && strchr(&ref[1], '/');
+}
+
%}
%union {
@@ -169,6 +175,8 @@ devicetree:
*/
if (!($<flags>-1 & DTSF_PLUGIN))
ERROR(&@2, "Label or path %s not found", $1);
+ else if (is_ref_relative($1))
+ ERROR(&@2, "Label-relative reference %s not supported in plugin", $1);
$$ = add_orphan_node(
name_node(build_node(NULL, NULL, NULL),
""),
@@ -178,6 +186,9 @@ devicetree:
{
struct node *target = get_node_by_ref($1, $3);
+ if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3))
+ ERROR(&@2, "Label-relative reference %s not supported in plugin", $3);
+
if (target) {
add_label(&target->labels, $2);
merge_nodes(target, $4);
@@ -193,6 +204,8 @@ devicetree:
* so $-1 is what we want (plugindecl)
*/
if ($<flags>-1 & DTSF_PLUGIN) {
+ if (is_ref_relative($2))
+ ERROR(&@2, "Label-relative reference %s not supported in plugin", $2);
add_orphan_node($1, $3, $2);
} else {
struct node *target = get_node_by_ref($1, $2);
@@ -391,9 +404,14 @@ arrayprefix:
* within the mask to one (i.e. | in the
* mask), all bits are one.
*/
- if (($2 > mask) && (($2 | mask) != -1ULL))
- ERROR(&@2, "Value out of range for"
- " %d-bit array element", $1.bits);
+ if (($2 > mask) && (($2 | mask) != -1ULL)) {
+ char *loc = srcpos_string(&@2);
+ fprintf(stderr,
+ "WARNING: %s: Value 0x%016" PRIx64
+ " truncated to 0x%0*" PRIx64 "\n",
+ loc, $2, $1.bits / 4, ($2 & mask));
+ free(loc);
+ }
}
$$.data = data_append_integer($1.data, $2, $1.bits);
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index 838c5df96c00..bc786c543b7e 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -12,7 +12,7 @@
* Command line options
*/
int quiet; /* Level of quietness */
-int reservenum; /* Number of memory reservation slots */
+unsigned int reservenum;/* Number of memory reservation slots */
int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int alignsize; /* Additional padding to blob accroding to the alignsize */
@@ -197,7 +197,7 @@ int main(int argc, char *argv[])
depname = optarg;
break;
case 'R':
- reservenum = strtol(optarg, NULL, 0);
+ reservenum = strtoul(optarg, NULL, 0);
break;
case 'S':
minsize = strtol(optarg, NULL, 0);
@@ -359,8 +359,6 @@ int main(int argc, char *argv[])
#endif
} else if (streq(outform, "dtb")) {
dt_to_blob(outf, dti, outversion);
- } else if (streq(outform, "dtbo")) {
- dt_to_blob(outf, dti, outversion);
} else if (streq(outform, "asm")) {
dt_to_asm(outf, dti, outversion);
} else if (streq(outform, "null")) {
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index d3e82fb8e3db..0a1f54991026 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -35,7 +35,7 @@
* Command line options
*/
extern int quiet; /* Level of quietness */
-extern int reservenum; /* Number of memory reservation slots */
+extern unsigned int reservenum; /* Number of memory reservation slots */
extern int minsize; /* Minimum blob size */
extern int padsize; /* Additional padding to blob */
extern int alignsize; /* Additional padding to blob accroding to the alignsize */
@@ -51,6 +51,11 @@ extern int annotate; /* annotate .dts with input source location */
typedef uint32_t cell_t;
+static inline bool phandle_is_valid(cell_t phandle)
+{
+ return phandle != 0 && phandle != ~0U;
+}
+
static inline uint16_t dtb_ld16(const void *p)
{
const uint8_t *bp = (const uint8_t *)p;
@@ -86,6 +91,16 @@ static inline uint64_t dtb_ld64(const void *p)
#define streq(a, b) (strcmp((a), (b)) == 0)
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
#define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0))
+static inline bool strends(const char *str, const char *suffix)
+{
+ unsigned int len, suffix_len;
+
+ len = strlen(str);
+ suffix_len = strlen(suffix);
+ if (len < suffix_len)
+ return false;
+ return streq(str + len - suffix_len, suffix);
+}
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
@@ -101,6 +116,12 @@ enum markertype {
TYPE_UINT64,
TYPE_STRING,
};
+
+static inline bool is_type_marker(enum markertype type)
+{
+ return type >= TYPE_UINT8;
+}
+
extern const char *markername(enum markertype markertype);
struct marker {
@@ -125,7 +146,22 @@ struct data {
for_each_marker(m) \
if ((m)->type == (t))
-size_t type_marker_length(struct marker *m);
+static inline struct marker *next_type_marker(struct marker *m)
+{
+ for_each_marker(m)
+ if (is_type_marker(m->type))
+ break;
+ return m;
+}
+
+static inline size_t type_marker_length(struct marker *m)
+{
+ struct marker *next = next_type_marker(m->next);
+
+ if (next)
+ return next->offset - m->offset;
+ return 0;
+}
void data_free(struct data d);
diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff
index d3422ee15e30..f2bbde4bba86 100755
--- a/scripts/dtc/dtx_diff
+++ b/scripts/dtc/dtx_diff
@@ -59,12 +59,8 @@ Otherwise DTx is treated as a dts source file (aka .dts).
or '/include/' to be processed.
If DTx_1 and DTx_2 are in different architectures, then this script
- may not work since \${ARCH} is part of the include path. Two possible
- workarounds:
-
- `basename $0` \\
- <(ARCH=arch_of_dtx_1 `basename $0` DTx_1) \\
- <(ARCH=arch_of_dtx_2 `basename $0` DTx_2)
+ may not work since \${ARCH} is part of the include path. The following
+ workaround can be used:
`basename $0` ARCH=arch_of_dtx_1 DTx_1 >tmp_dtx_1.dts
`basename $0` ARCH=arch_of_dtx_2 DTx_2 >tmp_dtx_2.dts
diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
index 4659afbfcbab..95e43d32c3e6 100644
--- a/scripts/dtc/flattree.c
+++ b/scripts/dtc/flattree.c
@@ -124,7 +124,8 @@ static void asm_emit_cell(void *e, cell_t val)
{
FILE *f = e;
- fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
+ fprintf(f, "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n"
+ "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n",
(val >> 24) & 0xff, (val >> 16) & 0xff,
(val >> 8) & 0xff, val & 0xff);
}
@@ -134,9 +135,9 @@ static void asm_emit_string(void *e, const char *str, int len)
FILE *f = e;
if (len != 0)
- fprintf(f, "\t.string\t\"%.*s\"\n", len, str);
+ fprintf(f, "\t.asciz\t\"%.*s\"\n", len, str);
else
- fprintf(f, "\t.string\t\"%s\"\n", str);
+ fprintf(f, "\t.asciz\t\"%s\"\n", str);
}
static void asm_emit_align(void *e, int a)
@@ -295,7 +296,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
{
struct reserve_info *re;
struct data d = empty_data;
- int j;
+ unsigned int j;
for (re = reservelist; re; re = re->next) {
d = data_append_re(d, re->address, re->size);
@@ -438,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
while (p < (strbuf.val + strbuf.len)) {
len = strlen(p);
- fprintf(f, "\t.string \"%s\"\n", p);
+ fprintf(f, "\t.asciz \"%s\"\n", p);
p += len+1;
}
}
diff --git a/scripts/dtc/include-prefixes/c6x b/scripts/dtc/include-prefixes/c6x
deleted file mode 120000
index 49ded4cae2be..000000000000
--- a/scripts/dtc/include-prefixes/c6x
+++ /dev/null
@@ -1 +0,0 @@
-../../../arch/c6x/boot/dts \ No newline at end of file
diff --git a/scripts/dtc/include-prefixes/h8300 b/scripts/dtc/include-prefixes/h8300
deleted file mode 120000
index 3bdaa332c54c..000000000000
--- a/scripts/dtc/include-prefixes/h8300
+++ /dev/null
@@ -1 +0,0 @@
-../../../arch/h8300/boot/dts \ No newline at end of file
diff --git a/scripts/dtc/include-prefixes/riscv b/scripts/dtc/include-prefixes/riscv
new file mode 120000
index 000000000000..202509418938
--- /dev/null
+++ b/scripts/dtc/include-prefixes/riscv
@@ -0,0 +1 @@
+../../../arch/riscv/boot/dts \ No newline at end of file
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index 3e893073da05..20c6415b9ced 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -90,6 +90,10 @@ int fdt_check_header(const void *fdt)
{
size_t hdrsize;
+ /* The device tree must be at an 8-byte aligned address */
+ if ((uintptr_t)fdt & 7)
+ return -FDT_ERR_ALIGNMENT;
+
if (fdt_magic(fdt) != FDT_MAGIC)
return -FDT_ERR_BADMAGIC;
if (!can_assume(LATEST)) {
@@ -102,7 +106,6 @@ int fdt_check_header(const void *fdt)
}
hdrsize = fdt_header_size(fdt);
if (!can_assume(VALID_DTB)) {
-
if ((fdt_totalsize(fdt) < hdrsize)
|| (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED;
@@ -111,9 +114,7 @@ int fdt_check_header(const void *fdt)
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_mem_rsvmap(fdt)))
return -FDT_ERR_TRUNCATED;
- }
- if (!can_assume(VALID_DTB)) {
/* Bounds check structure block */
if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
if (!check_off_(hdrsize, fdt_totalsize(fdt),
@@ -161,7 +162,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
{
const fdt32_t *tagp, *lenp;
- uint32_t tag;
+ uint32_t tag, len, sum;
int offset = startoffset;
const char *p;
@@ -187,12 +188,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (!can_assume(VALID_DTB) && !lenp)
return FDT_END; /* premature end */
+
+ len = fdt32_to_cpu(*lenp);
+ sum = len + offset;
+ if (!can_assume(VALID_DTB) &&
+ (INT_MAX <= sum || sum < (uint32_t) offset))
+ return FDT_END; /* premature end */
+
/* skip-name offset, length and value */
- offset += sizeof(struct fdt_property) - FDT_TAGSIZE
- + fdt32_to_cpu(*lenp);
+ offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len;
+
if (!can_assume(LATEST) &&
- fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
- ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
+ fdt_version(fdt) < 0x10 && len >= 8 &&
+ ((offset - len) % 8) != 0)
offset += 4;
break;
diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h
index f2e68807f277..0c91aa7f67b5 100644
--- a/scripts/dtc/libfdt/fdt.h
+++ b/scripts/dtc/libfdt/fdt.h
@@ -35,14 +35,14 @@ struct fdt_reserve_entry {
struct fdt_node_header {
fdt32_t tag;
- char name[0];
+ char name[];
};
struct fdt_property {
fdt32_t tag;
fdt32_t len;
fdt32_t nameoff;
- char data[0];
+ char data[];
};
#endif /* !__ASSEMBLY */
diff --git a/scripts/dtc/libfdt/fdt_addresses.c b/scripts/dtc/libfdt/fdt_addresses.c
index 9a82cd0ba2f9..c40ba094f1f8 100644
--- a/scripts/dtc/libfdt/fdt_addresses.c
+++ b/scripts/dtc/libfdt/fdt_addresses.c
@@ -73,7 +73,7 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
/* check validity of address */
prop = data;
if (addr_cells == 1) {
- if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
+ if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size))
return -FDT_ERR_BADVALUE;
fdt32_st(prop, (uint32_t)addr);
diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c
index d217e79b6722..5c0c3981b89d 100644
--- a/scripts/dtc/libfdt/fdt_overlay.c
+++ b/scripts/dtc/libfdt/fdt_overlay.c
@@ -40,37 +40,22 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
return fdt32_to_cpu(*val);
}
-/**
- * overlay_get_target - retrieves the offset of a fragment's target
- * @fdt: Base device tree blob
- * @fdto: Device tree overlay blob
- * @fragment: node offset of the fragment in the overlay
- * @pathp: pointer which receives the path of the target (or NULL)
- *
- * overlay_get_target() retrieves the target offset in the base
- * device tree of a fragment, no matter how the actual targeting is
- * done (through a phandle or a path)
- *
- * returns:
- * the targeted node offset in the base device tree
- * Negative error code on error
- */
-static int overlay_get_target(const void *fdt, const void *fdto,
- int fragment, char const **pathp)
+int fdt_overlay_target_offset(const void *fdt, const void *fdto,
+ int fragment_offset, char const **pathp)
{
uint32_t phandle;
const char *path = NULL;
int path_len = 0, ret;
/* Try first to do a phandle based lookup */
- phandle = overlay_get_target_phandle(fdto, fragment);
+ phandle = overlay_get_target_phandle(fdto, fragment_offset);
if (phandle == (uint32_t)-1)
return -FDT_ERR_BADPHANDLE;
/* no phandle, try path */
if (!phandle) {
/* And then a path based lookup */
- path = fdt_getprop(fdto, fragment, "target-path", &path_len);
+ path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len);
if (path)
ret = fdt_path_offset(fdt, path);
else
@@ -636,7 +621,7 @@ static int overlay_merge(void *fdt, void *fdto)
if (overlay < 0)
return overlay;
- target = overlay_get_target(fdt, fdto, fragment, NULL);
+ target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
if (target < 0)
return target;
@@ -779,7 +764,7 @@ static int overlay_symbol_update(void *fdt, void *fdto)
return -FDT_ERR_BADOVERLAY;
/* get the target of the fragment */
- ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+ ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
if (ret < 0)
return ret;
target = ret;
@@ -801,7 +786,7 @@ static int overlay_symbol_update(void *fdt, void *fdto)
if (!target_path) {
/* again in case setprop_placeholder changed it */
- ret = overlay_get_target(fdt, fdto, fragment, &target_path);
+ ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
if (ret < 0)
return ret;
target = ret;
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index 17584da25760..9f6c551a22c2 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -481,12 +481,12 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
if (!can_assume(VALID_INPUT)) {
name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
&namelen);
+ *namep = name;
if (!name) {
if (lenp)
*lenp = namelen;
return NULL;
}
- *namep = name;
} else {
*namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
}
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
index f13458d165d4..3621d3651d3f 100644
--- a/scripts/dtc/libfdt/fdt_rw.c
+++ b/scripts/dtc/libfdt/fdt_rw.c
@@ -349,7 +349,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
return offset;
/* Try to place the new node after the parent's properties */
- fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+ tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
+ /* the fdt_subnode_offset_namelen() should ensure this never hits */
+ if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE))
+ return -FDT_ERR_INTERNAL;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
@@ -391,7 +394,9 @@ int fdt_del_node(void *fdt, int nodeoffset)
}
static void fdt_packblocks_(const char *old, char *new,
- int mem_rsv_size, int struct_size)
+ int mem_rsv_size,
+ int struct_size,
+ int strings_size)
{
int mem_rsv_off, struct_off, strings_off;
@@ -406,8 +411,7 @@ static void fdt_packblocks_(const char *old, char *new,
fdt_set_off_dt_struct(new, struct_off);
fdt_set_size_dt_struct(new, struct_size);
- memmove(new + strings_off, old + fdt_off_dt_strings(old),
- fdt_size_dt_strings(old));
+ memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size);
fdt_set_off_dt_strings(new, strings_off);
fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
}
@@ -467,7 +471,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return -FDT_ERR_NOSPACE;
}
- fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
+ fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size,
+ fdt_size_dt_strings(fdt));
memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC);
@@ -487,7 +492,8 @@ int fdt_pack(void *fdt)
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
- fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+ fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt),
+ fdt_size_dt_strings(fdt));
fdt_set_totalsize(fdt, fdt_data_size_(fdt));
return 0;
diff --git a/scripts/dtc/libfdt/fdt_strerror.c b/scripts/dtc/libfdt/fdt_strerror.c
index b4356931b06d..d852b77e81e7 100644
--- a/scripts/dtc/libfdt/fdt_strerror.c
+++ b/scripts/dtc/libfdt/fdt_strerror.c
@@ -39,6 +39,7 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
+ FDT_ERRTABENT(FDT_ERR_ALIGNMENT),
};
#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])))
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
index c42807a7663e..77ccff19911e 100644
--- a/scripts/dtc/libfdt/libfdt.h
+++ b/scripts/dtc/libfdt/libfdt.h
@@ -131,6 +131,13 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
* to work even with unaligned pointers on platforms (such as ARMv5) that don't
* like unaligned loads and stores.
*/
+static inline uint16_t fdt16_ld(const fdt16_t *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint16_t)bp[0] << 8) | bp[1];
+}
+
static inline uint32_t fdt32_ld(const fdt32_t *p)
{
const uint8_t *bp = (const uint8_t *)p;
@@ -653,6 +660,13 @@ int fdt_next_property_offset(const void *fdt, int offset);
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
int offset,
int *lenp);
+static inline struct fdt_property *fdt_get_property_by_offset_w(void *fdt,
+ int offset,
+ int *lenp)
+{
+ return (struct fdt_property *)(uintptr_t)
+ fdt_get_property_by_offset(fdt, offset, lenp);
+}
/**
* fdt_get_property_namelen - find a property based on substring
@@ -2109,6 +2123,24 @@ int fdt_del_node(void *fdt, int nodeoffset);
*/
int fdt_overlay_apply(void *fdt, void *fdto);
+/**
+ * fdt_overlay_target_offset - retrieves the offset of a fragment's target
+ * @fdt: Base device tree blob
+ * @fdto: Device tree overlay blob
+ * @fragment_offset: node offset of the fragment in the overlay
+ * @pathp: pointer which receives the path of the target (or NULL)
+ *
+ * fdt_overlay_target_offset() retrieves the target offset in the base
+ * device tree of a fragment, no matter how the actual targeting is
+ * done (through a phandle or a path)
+ *
+ * returns:
+ * the targeted node offset in the base device tree
+ * Negative error code on error
+ */
+int fdt_overlay_target_offset(const void *fdt, const void *fdto,
+ int fragment_offset, char const **pathp);
+
/**********************************************************************/
/* Debugging / informational functions */
/**********************************************************************/
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c
index 7eacd0248641..f46a098d5ada 100644
--- a/scripts/dtc/livetree.c
+++ b/scripts/dtc/livetree.c
@@ -526,7 +526,7 @@ struct node *get_node_by_path(struct node *tree, const char *path)
p = strchr(path, '/');
for_each_child(tree, child) {
- if (p && strprefixeq(path, p - path, child->name))
+ if (p && strprefixeq(path, (size_t)(p - path), child->name))
return get_node_by_path(child, p+1);
else if (!p && streq(path, child->name))
return child;
@@ -559,7 +559,7 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
{
struct node *child, *node;
- if ((phandle == 0) || (phandle == -1)) {
+ if (!phandle_is_valid(phandle)) {
assert(generate_fixups);
return NULL;
}
@@ -581,12 +581,39 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
struct node *get_node_by_ref(struct node *tree, const char *ref)
{
+ struct node *target = tree;
+ const char *label = NULL, *path = NULL;
+
if (streq(ref, "/"))
return tree;
- else if (ref[0] == '/')
- return get_node_by_path(tree, ref);
+
+ if (ref[0] == '/')
+ path = ref;
else
- return get_node_by_label(tree, ref);
+ label = ref;
+
+ if (label) {
+ const char *slash = strchr(label, '/');
+ char *buf = NULL;
+
+ if (slash) {
+ buf = xstrndup(label, slash - label);
+ label = buf;
+ path = slash + 1;
+ }
+
+ target = get_node_by_label(tree, label);
+
+ free(buf);
+
+ if (!target)
+ return NULL;
+ }
+
+ if (path)
+ target = get_node_by_path(target, path);
+
+ return target;
}
cell_t get_node_phandle(struct node *root, struct node *node)
@@ -594,7 +621,7 @@ cell_t get_node_phandle(struct node *root, struct node *node)
static cell_t phandle = 1; /* FIXME: ick, static local */
struct data d = empty_data;
- if ((node->phandle != 0) && (node->phandle != -1))
+ if (phandle_is_valid(node->phandle))
return node->phandle;
while (get_node_by_phandle(root, phandle))
@@ -892,6 +919,12 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
/* m->ref can only be a REF_PHANDLE, but check anyway */
assert(m->type == REF_PHANDLE);
+ /* The format only permits fixups for references to label, not
+ * references to path */
+ if (strchr(m->ref, '/'))
+ die("Can't generate fixup for reference to path &{%s}\n",
+ m->ref);
+
/* there shouldn't be any ':' in the arguments */
if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
die("arguments should not contain ':'\n");
diff --git a/scripts/dtc/of_unittest_expect b/scripts/dtc/of_unittest_expect
new file mode 100755
index 000000000000..0a535a8e9821
--- /dev/null
+++ b/scripts/dtc/of_unittest_expect
@@ -0,0 +1,541 @@
+#!/usr/bin/perl
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright 2020, 2022 Sony Corporation
+#
+# Author: Frank Rowand
+
+# This program is meant to be an aid to reading the verbose output of
+# on the console log that results from executing the Linux kernel
+# devicetree unittest (drivers/of/unitest.c).
+
+$VUFX = "230211a";
+
+use strict 'refs';
+use strict subs;
+
+use Getopt::Long;
+use Text::Wrap;
+
+# strip off everything before final "/"
+(undef, $script_name) = split(/^.*\//, $0);
+
+# following /usr/include/sysexits.h
+$EX_OK=0;
+$EX_USAGE=64;
+
+
+#______________________________________________________________________________
+sub compare {
+ my ($expect, $got) = @_;
+ my $expect_next;
+ my $expect_next_lit;
+ my $got_next;
+ my $type;
+
+ while ($expect) {
+
+ ($expect_next, $type) = split(/<</, $expect);
+ ($type) = split(/>>/, $type);
+ $expect =~ s/^.*?>>//; # '?' is non-greedy, minimal match
+
+ # literal, ignore all metacharacters when used in a regex
+ $expect_next_lit = quotemeta($expect_next);
+
+ $got_next = $got;
+ $got_next =~ s/^($expect_next_lit).*/\1/;
+ $got =~ s/^$expect_next_lit//;
+
+ if ($expect_next ne $got_next) {
+ return 0;
+ }
+
+ if ($type eq "int") {
+ if ($got =~ /^[+-]*[0-9]+/) {
+ $got =~ s/^[+-]*[0-9]+//;
+ } else {
+ return 0;
+ }
+ } elsif ($type eq "hex") {
+ if ($got =~ /^(0x)*[0-9a-f]+/) {
+ $got =~ s/^(0x)*[0-9a-f]+//;
+ } else {
+ return 0;
+ }
+ } elsif ($type eq "all") {
+ return 1;
+ } elsif ($type eq "") {
+ if ($expect_next ne $got_next) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ $internal_err++;
+ print "** ERROR: special pattern not recognized: <<$type>>, CONSOLE_LOG line: $.\n";
+ return 0;
+ }
+
+ }
+
+ # should not get here
+ $internal_err++;
+ print "** ERROR: $script_name internal error, at end of compare(), CONSOLE_LOG line: $.\n";
+
+ return 0;
+}
+
+
+#______________________________________________________________________________
+sub usage {
+
+# ***** when editing, be careful to not put tabs in the string printed:
+
+ print STDERR
+"
+usage:
+
+ $script_name CONSOLE_LOG
+
+ -h print program usage
+ --help print program usage
+ --hide-expect suppress output of EXPECTed lines
+ --line-num report line number of CONSOLE_LOG
+ --no-expect-stats do not report EXPECT statistics
+ --no-strip-ts do not strip leading console timestamps
+ --verbose do not suppress EXPECT begin and end lines
+ --version print program version and exit
+
+
+ Process a console log for EXPECTed test related messages to either
+ highlight expected devicetree unittest related messages or suppress
+ the messages. Leading console timestamps will be stripped.
+
+ Various unittests may trigger kernel messages from outside the
+ unittest code. The unittest annotates that it expects the message
+ to occur with an 'EXPECT \\ : text' (begin) before triggering the
+ message, and an 'EXPECT / : text' (end) after triggering the message.
+
+ If an expected message does not occur, that will be reported.
+
+ For each expected message, the 'EXPECT \\ : text' (begin) and
+ 'EXPECT / : text' (end), 'text' will contain the message text.
+
+ If 'EXPECT \\' (begin) and 'EXPECT /' (end) lines do not contain
+ matching 'text', that will be reported.
+
+ If EXPECT lines are nested, 'EXPECT /' (end) lines must be in the
+ reverse order of the corresponding 'EXPECT \\' (begin) lines.
+
+ 'EXPECT \\ : text' (begin) and 'EXPECT / : text' (end) lines can
+ contain special patterns in 'text':
+
+ <<int>> matches: [+-]*[0-9]+
+ <<hex>> matches: (0x)*[0-9a-f]+
+ <<all>> matches: anything to end of line
+
+ 'EXPECT \\' (begin) and 'EXPECT /' (end) lines are suppressed.
+
+ A prefix is added to every line of output:
+
+ 'ok ' Line matches an enclosing EXPECT begin/end pair
+
+ '** ' Line reports $script_name warning or error
+
+ '-> ' Line reports start or end of the unittests
+
+ '>> ' Line reports a unittest test FAIL
+
+ ' ' Lines that are not otherwise prefixed
+
+ Issues detected in CONSOLE_LOG are reported to STDOUT, not to STDERR.
+
+ Known Issues:
+
+ --line-num causes the CONSOLE_LOG line number to be printed in 4 columns.
+ If CONSOLE_LOG contains more than 9999 lines then more columns will be
+ used to report the line number for lines greater than 9999 (eg for
+ lines 10000 - 99999, 5 columns will be used).
+";
+
+ return {};
+}
+
+#______________________________________________________________________________
+#______________________________________________________________________________
+
+if (!GetOptions(
+ "h" => \$help,
+ "help" => \$help,
+ "hide-expect" => \$hide_expect,
+ "line-num" => \$print_line_num,
+ "no-expect-stats" => \$no_expect_stats,
+ "no-strip-ts" => \$no_strip_ts,
+ "verbose" => \$verbose,
+ "version" => \$version,
+ )) {
+ print STDERR "\n";
+ print STDERR "ERROR processing command line options\n";
+ print STDERR "\n";
+ print STDERR "For help, type '$script_name --help'\n";
+ print STDERR "\n";
+
+ exit $EX_OK;
+}
+
+
+if ($no_strip_ts) {
+ $strip_ts = 1;
+ $no_strip_ts = 0;
+} else {
+ $strip_ts = 0;
+ $no_strip_ts = 1;
+}
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+if ($help){
+
+ &usage;
+
+ exit $EX_OK;
+}
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+if ($version) {
+ print STDERR "\n$script_name $VUFX\n\n";
+ print STDERR "\n";
+
+ exit $EX_OK;
+}
+
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+if ($#ARGV != 0) {
+
+ # Limit input files to exactly one.
+ #
+ # 'while ($line = <ARGV>) {' in the code below supports multiple file
+ # names on the command line, but the EXPECT statistics are reported
+ # once for all input - it is not an expected use case to generate one
+ # set of statistics for multiple input files.
+
+ print STDERR "\n";
+ print STDERR "Required arguments: CONSOLE_LOG\n";
+ print STDERR "\n";
+
+ exit $EX_USAGE;
+}
+
+
+#______________________________________________________________________________
+
+# Patterns to match 'EXPECT \ : ' (begin) and 'EXPECT / : ' (end)
+#
+# $exp_* are used as regex match patterns,
+# so '\\\\' in $exp_begin matches a single '\'
+# quotemeta() does not do the right thing in this case
+#
+# $pr_fmt is the prefix that unittest prints for every message
+
+$pr_fmt = "### dt-test ### ";
+$exp_begin = "${pr_fmt}EXPECT \\\\ : ";
+$exp_end = "${pr_fmt}EXPECT / : ";
+$expnot_begin = "${pr_fmt}EXPECT_NOT \\\\ : ";
+$expnot_end = "${pr_fmt}EXPECT_NOT / : ";
+
+
+$line_num = "";
+$timestamp = "";
+
+LINE:
+while ($line = <ARGV>) {
+
+ chomp $line;
+
+ $suppress_line = 0;
+
+ $prefix = " "; ## 2 characters
+
+
+ if ($strip_ts) {
+
+ $timestamp = $line;
+
+ if ($timestamp =~ /^\[\s*[0-9]+\.[0-9]*\] /) {
+ ($timestamp, $null) = split(/]/, $line);
+ $timestamp = $timestamp . "] ";
+
+ } else {
+ $timestamp = "";
+ }
+ }
+
+ $line =~ s/^\[\s*[0-9]+\.[0-9]*\] //;
+
+
+ # ----- find EXPECT begin
+
+ if ($line =~ /^\s*$exp_begin/) {
+ $data = $line;
+ $data =~ s/^\s*$exp_begin//;
+ push @exp_begin_stack, $data;
+
+ if ($verbose) {
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+ printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
+ }
+
+ next LINE;
+ }
+
+
+ # ----- find EXPECT end
+
+ if ($line =~ /^\s*$exp_end/) {
+ $data = $line;
+ $data =~ s/^\s*$exp_end//;
+
+ if ($verbose) {
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+ printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
+ }
+
+ $found = 0;
+ $no_begin = 0;
+ if (@exp_found_or_begin > 0) {
+ $begin = pop @exp_found_or_begin;
+ if (compare($data, $begin)) {
+ $found = 1;
+ $exp_found++;
+ }
+ } elsif (@begin > 0) {
+ $begin = pop @exp_begin_stack;
+ } else {
+ $no_begin = 1;
+ }
+
+ if ($no_begin) {
+
+ $exp_missing_begin++;
+ print "** ERROR: EXPECT end without matching EXPECT begin:\n";
+ print " end ---> $line\n";
+
+ } elsif (! $found) {
+
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+
+ $exp_missing++;
+ printf "** %s%s$script_name WARNING - not found ---> %s\n",
+ $line_num, $timestamp, $data;
+
+ } elsif (! compare($data, $begin) and ($data ne $begin)) {
+
+ $exp_missing_end++;
+ print "** ERROR: EXPECT end does not match EXPECT begin:\n";
+ print " begin -> $begin\n";
+ print " end ---> $line\n";
+
+ }
+
+ next LINE;
+ }
+
+
+ # ----- find EXPECT_NOT begin
+
+ if ($line =~ /^\s*$expnot_begin/) {
+ $data = $line;
+ $data =~ s/^\s*$expnot_begin//;
+ push @expnot_begin_stack, $data;
+
+ if ($verbose) {
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+ printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
+ }
+
+ next LINE;
+ }
+
+
+ # ----- find EXPECT_NOT end
+
+ if ($line =~ /^\s*$expnot_end/) {
+ $data = $line;
+ $data =~ s/^\s*$expnot_end//;
+
+ if ($verbose) {
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+ printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
+ }
+
+ $found = 0;
+ $no_begin = 0;
+ if (@expnot_found_or_begin > 0) {
+ $begin = pop @expnot_found_or_begin;
+ if (compare($data, $begin)) {
+ $found = 1;
+ $expnot_found++;
+ }
+ } elsif (@expnot_begin_stack <= 0) {
+ $no_begin = 1;
+ }
+
+ if ($no_begin) {
+
+ $expnot_missing_begin++;
+ print "** ERROR: EXPECT_NOT end without matching EXPECT_NOT begin:\n";
+ print " end ---> $line\n";
+
+ }
+
+ if ($found) {
+
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+
+ printf "** %s%s$script_name WARNING - next line matches EXPECT_NOT\n",
+ $line_num, $timestamp;
+ printf "** %s%s%s\n", $line_num, $timestamp, $line;
+
+ } else {
+
+ $expnot_missing++;
+
+ }
+
+ if (@expnot_begin_stack > 0) {
+ $begin = pop @expnot_begin_stack;
+
+ if (! compare($data, $begin) and ($data ne $begin)) {
+
+ $expnot_missing_end++;
+ print "** ERROR: EXPECT_NOT end does not match EXPECT_NOT begin:\n";
+ print " begin -> $begin\n";
+ print " end ---> $line\n";
+
+ }
+ }
+
+ next LINE;
+ }
+
+
+ # ----- not an EXPECT line
+
+ if (($line =~ /^${pr_fmt}start of unittest - you will see error messages$/) ||
+ ($line =~ /^${pr_fmt}end of unittest - [0-9]+ passed, [0-9]+ failed$/ ) ) {
+ $prefix = "->"; # 2 characters
+ } elsif ($line =~ /^${pr_fmt}FAIL /) {
+ $unittest_fail++;
+ $prefix = ">>"; # 2 characters
+ }
+
+ $found = 0;
+ foreach $begin (@exp_begin_stack) {
+ if (compare($begin, $line)) {
+ $found = 1;
+ last;
+ }
+ }
+
+ if ($found) {
+ $begin = shift @exp_begin_stack;
+ while (! compare($begin, $line)) {
+ push @exp_found_or_begin, $begin;
+ $begin = shift @exp_begin_stack;
+ }
+ push @exp_found_or_begin, $line;
+
+ if ($hide_expect) {
+ $suppress_line = 1;
+ }
+ $prefix = "ok"; # 2 characters
+ }
+
+
+ $found = 0;
+ foreach $begin (@expnot_begin_stack) {
+ if (compare($begin, $line)) {
+ $found = 1;
+ last;
+ }
+ }
+
+ if ($found) {
+ $begin = shift @begin;
+ while (! compare($begin, $line)) {
+ push @expnot_found_or_begin, $begin;
+ $begin = shift @begin;
+ }
+ push @expnot_found_or_begin, $line;
+
+ if ($hide_expect) {
+ $suppress_line = 1;
+ }
+ $prefix = "**"; # 2 characters
+ }
+
+
+ if ($suppress_line) {
+ next LINE;
+ }
+
+ if ($print_line_num) {
+ $line_num = sprintf("%4s ", $.);
+ }
+
+ printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
+}
+
+if (! $no_expect_stats) {
+ print "\n";
+ print "** EXPECT statistics:\n";
+ print "**\n";
+ printf "** non-zero values expected:\n";
+ print "**\n";
+ printf "** EXPECT found : %4i\n", $exp_found;
+ printf "** EXPECT_NOT not found : %4i\n", $expnot_missing;
+ print "**\n";
+ printf "** zero values expected:\n";
+ print "**\n";
+ printf "** EXPECT not found : %4i\n", $exp_missing;
+ printf "** missing EXPECT begin : %4i\n", $exp_missing_begin;
+ printf "** missing EXPECT end : %4i\n", $exp_missing_end;
+ print "**\n";
+ printf "** EXPECT_NOT found : %4i\n", $expnot_found;
+ printf "** missing EXPECT_NOT begin : %4i\n", $expnot_missing_begin;
+ printf "** missing EXPECT_NOT end : %4i\n", $expnot_missing_end;
+ print "**\n";
+ printf "** unittest FAIL : %4i\n", $unittest_fail;
+ printf "** internal error : %4i\n", $internal_err;
+}
+
+if (@exp_begin_stack) {
+ print "** ERROR: EXPECT begin without matching EXPECT end:\n";
+ print " This list may be misleading.\n";
+ foreach $begin (@exp_begin_stack) {
+ print " begin ---> $begin\n";
+ }
+}
+
+if (@expnot_begin_stack) {
+ print "** ERROR: EXPECT_NOT begin without matching EXPECT_NOT end:\n";
+ print " This list may be misleading.\n";
+ foreach $begin (@expnot_begin_stack) {
+ print " begin ---> $begin\n";
+ }
+}
diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c
index 061ba8c9c5e8..33fedee82d58 100644
--- a/scripts/dtc/treesource.c
+++ b/scripts/dtc/treesource.c
@@ -124,27 +124,6 @@ static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
}
}
-static bool has_data_type_information(struct marker *m)
-{
- return m->type >= TYPE_UINT8;
-}
-
-static struct marker *next_type_marker(struct marker *m)
-{
- while (m && !has_data_type_information(m))
- m = m->next;
- return m;
-}
-
-size_t type_marker_length(struct marker *m)
-{
- struct marker *next = next_type_marker(m->next);
-
- if (next)
- return next->offset - m->offset;
- return 0;
-}
-
static const char *delim_start[] = {
[TYPE_UINT8] = "[",
[TYPE_UINT16] = "/bits/ 16 <",
@@ -229,26 +208,39 @@ static void write_propval(FILE *f, struct property *prop)
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
size_t data_len = type_marker_length(m) ? : len - m->offset;
const char *p = &prop->val.val[m->offset];
+ struct marker *m_phandle;
- if (has_data_type_information(m)) {
+ if (is_type_marker(m->type)) {
emit_type = m->type;
fprintf(f, " %s", delim_start[emit_type]);
} else if (m->type == LABEL)
fprintf(f, " %s:", m->ref);
- else if (m->offset)
- fputc(' ', f);
- if (emit_type == TYPE_NONE) {
- assert(chunk_len == 0);
+ if (emit_type == TYPE_NONE || chunk_len == 0)
continue;
- }
switch(emit_type) {
case TYPE_UINT16:
write_propval_int(f, p, chunk_len, 2);
break;
case TYPE_UINT32:
- write_propval_int(f, p, chunk_len, 4);
+ m_phandle = prop->val.markers;
+ for_each_marker_of_type(m_phandle, REF_PHANDLE)
+ if (m->offset == m_phandle->offset)
+ break;
+
+ if (m_phandle) {
+ if (m_phandle->ref[0] == '/')
+ fprintf(f, "&{%s}", m_phandle->ref);
+ else
+ fprintf(f, "&%s", m_phandle->ref);
+ if (chunk_len > 4) {
+ fputc(' ', f);
+ write_propval_int(f, p + 4, chunk_len - 4, 4);
+ }
+ } else {
+ write_propval_int(f, p, chunk_len, 4);
+ }
break;
case TYPE_UINT64:
write_propval_int(f, p, chunk_len, 8);
diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh
index 32ff17ffd089..94627541533e 100755
--- a/scripts/dtc/update-dtc-source.sh
+++ b/scripts/dtc/update-dtc-source.sh
@@ -32,7 +32,7 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc
DTC_LINUX_PATH=`pwd`/scripts/dtc
DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \
- srcpos.h treesource.c util.c util.h version_gen.h yamltree.c \
+ srcpos.h treesource.c util.c util.h version_gen.h \
dtc-lexer.l dtc-parser.y"
LIBFDT_SOURCE="fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \
fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \
diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c
index 40274fb79236..507f0120cd13 100644
--- a/scripts/dtc/util.c
+++ b/scripts/dtc/util.c
@@ -33,6 +33,17 @@ char *xstrdup(const char *s)
return d;
}
+char *xstrndup(const char *s, size_t n)
+{
+ size_t len = strnlen(s, n) + 1;
+ char *d = xmalloc(len);
+
+ memcpy(d, s, len - 1);
+ d[len - 1] = '\0';
+
+ return d;
+}
+
int xavsprintf_append(char **strp, const char *fmt, va_list ap)
{
int n, size = 0; /* start with 128 bytes */
@@ -353,11 +364,11 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size)
}
/* we should now have a type */
- if ((*fmt == '\0') || !strchr("iuxs", *fmt))
+ if ((*fmt == '\0') || !strchr("iuxsr", *fmt))
return -1;
/* convert qualifier (bhL) to byte size */
- if (*fmt != 's')
+ if (*fmt != 's' && *fmt != 'r')
*size = qualifier == 'b' ? 1 :
qualifier == 'h' ? 2 :
qualifier == 'l' ? 4 : -1;
diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h
index a771b4654c76..9d38edee9736 100644
--- a/scripts/dtc/util.h
+++ b/scripts/dtc/util.h
@@ -13,10 +13,10 @@
*/
#ifdef __GNUC__
-#ifdef __clang__
-#define PRINTF(i, j) __attribute__((format (printf, i, j)))
-#else
+#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
#define PRINTF(i, j) __attribute__((format (gnu_printf, i, j)))
+#else
+#define PRINTF(i, j) __attribute__((format (printf, i, j)))
#endif
#define NORETURN __attribute__((noreturn))
#else
@@ -61,6 +61,7 @@ static inline void *xrealloc(void *p, size_t len)
}
extern char *xstrdup(const char *s);
+extern char *xstrndup(const char *s, size_t len);
extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...);
@@ -143,6 +144,7 @@ int utilfdt_write_err(const char *filename, const void *blob);
* i signed integer
* u unsigned integer
* x hex
+ * r raw
*
* TODO: Implement ll modifier (8 bytes)
* TODO: Implement o type (octal)
@@ -160,7 +162,7 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size);
*/
#define USAGE_TYPE_MSG \
- "<type>\ts=string, i=int, u=unsigned, x=hex\n" \
+ "<type>\ts=string, i=int, u=unsigned, x=hex, r=raw\n" \
"\tOptional modifier prefix:\n" \
"\t\thh or b=byte, h=2 byte, l=4 byte (default)";
diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
index 73a7839603f1..99614ec1a289 100644
--- a/scripts/dtc/version_gen.h
+++ b/scripts/dtc/version_gen.h
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.6.0-g183df9e9"
+#define DTC_VERSION "DTC 1.6.1-gabbd523b"
diff --git a/scripts/dtc/yamltree.c b/scripts/dtc/yamltree.c
index e63d32fe142a..55908c829c98 100644
--- a/scripts/dtc/yamltree.c
+++ b/scripts/dtc/yamltree.c
@@ -29,11 +29,12 @@ char *yaml_error_name[] = {
(emitter)->problem, __func__, __LINE__); \
})
-static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, unsigned int len, int width)
+static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers,
+ char *data, unsigned int seq_offset, unsigned int len, int width)
{
yaml_event_t event;
void *tag;
- unsigned int off, start_offset = markers->offset;
+ unsigned int off;
switch(width) {
case 1: tag = "!u8"; break;
@@ -66,7 +67,7 @@ static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, ch
m = markers;
is_phandle = false;
for_each_marker_of_type(m, REF_PHANDLE) {
- if (m->offset == (start_offset + off)) {
+ if (m->offset == (seq_offset + off)) {
is_phandle = true;
break;
}
@@ -114,6 +115,7 @@ static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
yaml_event_t event;
unsigned int len = prop->val.len;
struct marker *m = prop->val.markers;
+ struct marker *markers = prop->val.markers;
/* Emit the property name */
yaml_scalar_event_initialize(&event, NULL,
@@ -151,19 +153,19 @@ static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
switch(m->type) {
case TYPE_UINT16:
- yaml_propval_int(emitter, m, data, chunk_len, 2);
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2);
break;
case TYPE_UINT32:
- yaml_propval_int(emitter, m, data, chunk_len, 4);
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4);
break;
case TYPE_UINT64:
- yaml_propval_int(emitter, m, data, chunk_len, 8);
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 8);
break;
case TYPE_STRING:
yaml_propval_string(emitter, data, chunk_len);
break;
default:
- yaml_propval_int(emitter, m, data, chunk_len, 1);
+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1);
break;
}
}
diff --git a/scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h b/scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/scripts/dummy-tools/dummy-plugin-dir/include/plugin-version.h
diff --git a/scripts/dummy-tools/gcc b/scripts/dummy-tools/gcc
index 5c113cad5601..07f6dc4c5cf6 100755
--- a/scripts/dummy-tools/gcc
+++ b/scripts/dummy-tools/gcc
@@ -57,9 +57,9 @@ if arg_contain --version "$@"; then
fi
if arg_contain -E "$@"; then
- # For scripts/gcc-version.sh; This emulates GCC 20.0.0
+ # For scripts/cc-version.sh; This emulates GCC 20.0.0
if arg_contain - "$@"; then
- sed 's/^__GNUC__$/20/; s/^__GNUC_MINOR__$/0/; s/^__GNUC_PATCHLEVEL__$/0/'
+ sed -n '/^GCC/{s/__GNUC__/20/; s/__GNUC_MINOR__/0/; s/__GNUC_PATCHLEVEL__/0/; p;}; s/__LONG_DOUBLE_128__/1/ p'
exit 0
else
echo "no input files" >&2
@@ -67,21 +67,40 @@ if arg_contain -E "$@"; then
fi
fi
+# To set CONFIG_AS_IS_GNU
+if arg_contain -Wa,--version "$@"; then
+ echo "GNU assembler (scripts/dummy-tools) 2.50"
+ exit 0
+fi
+
if arg_contain -S "$@"; then
# For scripts/gcc-x86-*-has-stack-protector.sh
if arg_contain -fstack-protector "$@"; then
- echo "%gs"
+ if arg_contain -mstack-protector-guard-reg=fs "$@"; then
+ echo "%fs"
+ else
+ echo "%gs"
+ fi
+ exit 0
+ fi
+
+ # For arch/powerpc/tools/gcc-check-mprofile-kernel.sh
+ if arg_contain -m64 "$@" && arg_contain -mprofile-kernel "$@"; then
+ if ! test -t 0 && ! grep -q notrace; then
+ echo "_mcount"
+ fi
exit 0
fi
fi
# To set GCC_PLUGINS
if arg_contain -print-file-name=plugin "$@"; then
- plugin_dir=$(mktemp -d)
-
- mkdir -p $plugin_dir/include
- touch $plugin_dir/include/plugin-version.h
-
- echo $plugin_dir
+ # Use $0 to find the in-tree dummy directory
+ echo "$(dirname "$(readlink -f "$0")")/dummy-plugin-dir"
exit 0
fi
+
+# inverted return value
+if arg_contain -D__SIZEOF_INT128__=0 "$@"; then
+ exit 1
+fi
diff --git a/scripts/dummy-tools/pahole b/scripts/dummy-tools/pahole
new file mode 100755
index 000000000000..53501a36fa71
--- /dev/null
+++ b/scripts/dummy-tools/pahole
@@ -0,0 +1,4 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+
+echo v99.99
diff --git a/scripts/extract-cert.c b/scripts/extract-cert.c
deleted file mode 100644
index 3bc48c726c41..000000000000
--- a/scripts/extract-cert.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/* Extract X.509 certificate in DER form from PKCS#11 or PEM.
- *
- * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved.
- * Copyright © 2015 Intel Corporation.
- *
- * Authors: David Howells <dhowells@redhat.com>
- * David Woodhouse <dwmw2@infradead.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * of the licence, or (at your option) any later version.
- */
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <err.h>
-#include <openssl/bio.h>
-#include <openssl/pem.h>
-#include <openssl/err.h>
-#include <openssl/engine.h>
-
-#define PKEY_ID_PKCS7 2
-
-static __attribute__((noreturn))
-void format(void)
-{
- fprintf(stderr,
- "Usage: scripts/extract-cert <source> <dest>\n");
- exit(2);
-}
-
-static void display_openssl_errors(int l)
-{
- const char *file;
- char buf[120];
- int e, line;
-
- if (ERR_peek_error() == 0)
- return;
- fprintf(stderr, "At main.c:%d:\n", l);
-
- while ((e = ERR_get_error_line(&file, &line))) {
- ERR_error_string(e, buf);
- fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
- }
-}
-
-static void drain_openssl_errors(void)
-{
- const char *file;
- int line;
-
- if (ERR_peek_error() == 0)
- return;
- while (ERR_get_error_line(&file, &line)) {}
-}
-
-#define ERR(cond, fmt, ...) \
- do { \
- bool __cond = (cond); \
- display_openssl_errors(__LINE__); \
- if (__cond) { \
- err(1, fmt, ## __VA_ARGS__); \
- } \
- } while(0)
-
-static const char *key_pass;
-static BIO *wb;
-static char *cert_dst;
-static int kbuild_verbose;
-
-static void write_cert(X509 *x509)
-{
- char buf[200];
-
- if (!wb) {
- wb = BIO_new_file(cert_dst, "wb");
- ERR(!wb, "%s", cert_dst);
- }
- X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf));
- ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst);
- if (kbuild_verbose)
- fprintf(stderr, "Extracted cert: %s\n", buf);
-}
-
-int main(int argc, char **argv)
-{
- char *cert_src;
-
- OpenSSL_add_all_algorithms();
- ERR_load_crypto_strings();
- ERR_clear_error();
-
- kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0");
-
- key_pass = getenv("KBUILD_SIGN_PIN");
-
- if (argc != 3)
- format();
-
- cert_src = argv[1];
- cert_dst = argv[2];
-
- if (!cert_src[0]) {
- /* Invoked with no input; create empty file */
- FILE *f = fopen(cert_dst, "wb");
- ERR(!f, "%s", cert_dst);
- fclose(f);
- exit(0);
- } else if (!strncmp(cert_src, "pkcs11:", 7)) {
- ENGINE *e;
- struct {
- const char *cert_id;
- X509 *cert;
- } parms;
-
- parms.cert_id = cert_src;
- parms.cert = NULL;
-
- ENGINE_load_builtin_engines();
- drain_openssl_errors();
- e = ENGINE_by_id("pkcs11");
- ERR(!e, "Load PKCS#11 ENGINE");
- if (ENGINE_init(e))
- drain_openssl_errors();
- else
- ERR(1, "ENGINE_init");
- if (key_pass)
- ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
- ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1);
- ERR(!parms.cert, "Get X.509 from PKCS#11");
- write_cert(parms.cert);
- } else {
- BIO *b;
- X509 *x509;
-
- b = BIO_new_file(cert_src, "rb");
- ERR(!b, "%s", cert_src);
-
- while (1) {
- x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
- if (wb && !x509) {
- unsigned long err = ERR_peek_last_error();
- if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
- ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
- ERR_clear_error();
- break;
- }
- }
- ERR(!x509, "%s", cert_src);
- write_cert(x509);
- }
- }
-
- BIO_free(wb);
-
- return 0;
-}
diff --git a/scripts/extract-ikconfig b/scripts/extract-ikconfig
index 3b42f255e2ba..8df33e7d6daa 100755
--- a/scripts/extract-ikconfig
+++ b/scripts/extract-ikconfig
@@ -62,6 +62,7 @@ try_decompress 'BZh' xy bunzip2
try_decompress '\135\0\0\0' xxx unlzma
try_decompress '\211\114\132' xy 'lzop -d'
try_decompress '\002\041\114\030' xyy 'lz4 -d -l'
+try_decompress '\050\265\057\375' xxx unzstd
# Bail out:
echo "$me: Cannot find kernel config." >&2
diff --git a/scripts/faddr2line b/scripts/faddr2line
index 6c6439f69a72..0e73aca4f908 100755
--- a/scripts/faddr2line
+++ b/scripts/faddr2line
@@ -44,17 +44,6 @@
set -o errexit
set -o nounset
-READELF="${CROSS_COMPILE:-}readelf"
-ADDR2LINE="${CROSS_COMPILE:-}addr2line"
-SIZE="${CROSS_COMPILE:-}size"
-NM="${CROSS_COMPILE:-}nm"
-
-command -v awk >/dev/null 2>&1 || die "awk isn't installed"
-command -v ${READELF} >/dev/null 2>&1 || die "readelf isn't installed"
-command -v ${ADDR2LINE} >/dev/null 2>&1 || die "addr2line isn't installed"
-command -v ${SIZE} >/dev/null 2>&1 || die "size isn't installed"
-command -v ${NM} >/dev/null 2>&1 || die "nm isn't installed"
-
usage() {
echo "usage: faddr2line [--list] <object file> <func+offset> <func+offset>..." >&2
exit 1
@@ -69,6 +58,15 @@ die() {
exit 1
}
+READELF="${CROSS_COMPILE:-}readelf"
+ADDR2LINE="${CROSS_COMPILE:-}addr2line"
+AWK="awk"
+GREP="grep"
+
+command -v ${AWK} >/dev/null 2>&1 || die "${AWK} isn't installed"
+command -v ${READELF} >/dev/null 2>&1 || die "${READELF} isn't installed"
+command -v ${ADDR2LINE} >/dev/null 2>&1 || die "${ADDR2LINE} isn't installed"
+
# Try to figure out the source directory prefix so we can remove it from the
# addr2line output. HACK ALERT: This assumes that start_kernel() is in
# init/main.c! This only works for vmlinux. Otherwise it falls back to
@@ -76,7 +74,8 @@ die() {
find_dir_prefix() {
local objfile=$1
- local start_kernel_addr=$(${READELF} -sW $objfile | awk '$8 == "start_kernel" {printf "0x%s", $2}')
+ local start_kernel_addr=$(${READELF} --symbols --wide $objfile | sed 's/\[.*\]//' |
+ ${AWK} '$8 == "start_kernel" {printf "0x%s", $2}')
[[ -z $start_kernel_addr ]] && return
local file_line=$(${ADDR2LINE} -e $objfile $start_kernel_addr)
@@ -97,86 +96,158 @@ __faddr2line() {
local dir_prefix=$3
local print_warnings=$4
- local func=${func_addr%+*}
- local offset=${func_addr#*+}
- offset=${offset%/*}
- local size=
- [[ $func_addr =~ "/" ]] && size=${func_addr#*/}
+ local sym_name=${func_addr%+*}
+ local func_offset=${func_addr#*+}
+ func_offset=${func_offset%/*}
+ local user_size=
+ local file_type
+ local is_vmlinux=0
+ [[ $func_addr =~ "/" ]] && user_size=${func_addr#*/}
- if [[ -z $func ]] || [[ -z $offset ]] || [[ $func = $func_addr ]]; then
+ if [[ -z $sym_name ]] || [[ -z $func_offset ]] || [[ $sym_name = $func_addr ]]; then
warn "bad func+offset $func_addr"
DONE=1
return
fi
+ # vmlinux uses absolute addresses in the section table rather than
+ # section offsets.
+ local file_type=$(${READELF} --file-header $objfile |
+ ${AWK} '$1 == "Type:" { print $2; exit }')
+ if [[ $file_type = "EXEC" ]] || [[ $file_type == "DYN" ]]; then
+ is_vmlinux=1
+ fi
+
# Go through each of the object's symbols which match the func name.
- # In rare cases there might be duplicates.
- file_end=$(${SIZE} -Ax $objfile | awk '$1 == ".text" {print $2}')
- while read symbol; do
- local fields=($symbol)
- local sym_base=0x${fields[0]}
- local sym_type=${fields[1]}
- local sym_end=${fields[3]}
-
- # calculate the size
- local sym_size=$(($sym_end - $sym_base))
+ # In rare cases there might be duplicates, in which case we print all
+ # matches.
+ while read line; do
+ local fields=($line)
+ local sym_addr=0x${fields[1]}
+ local sym_elf_size=${fields[2]}
+ local sym_sec=${fields[6]}
+ local sec_size
+ local sec_name
+
+ # Get the section size:
+ sec_size=$(${READELF} --section-headers --wide $objfile |
+ sed 's/\[ /\[/' |
+ ${AWK} -v sec=$sym_sec '$1 == "[" sec "]" { print "0x" $6; exit }')
+
+ if [[ -z $sec_size ]]; then
+ warn "bad section size: section: $sym_sec"
+ DONE=1
+ return
+ fi
+
+ # Get the section name:
+ sec_name=$(${READELF} --section-headers --wide $objfile |
+ sed 's/\[ /\[/' |
+ ${AWK} -v sec=$sym_sec '$1 == "[" sec "]" { print $2; exit }')
+
+ if [[ -z $sec_name ]]; then
+ warn "bad section name: section: $sym_sec"
+ DONE=1
+ return
+ fi
+
+ # Calculate the symbol size.
+ #
+ # Unfortunately we can't use the ELF size, because kallsyms
+ # also includes the padding bytes in its size calculation. For
+ # kallsyms, the size calculation is the distance between the
+ # symbol and the next symbol in a sorted list.
+ local sym_size
+ local cur_sym_addr
+ local found=0
+ while read line; do
+ local fields=($line)
+ cur_sym_addr=0x${fields[1]}
+ local cur_sym_elf_size=${fields[2]}
+ local cur_sym_name=${fields[7]:-}
+
+ if [[ $cur_sym_addr = $sym_addr ]] &&
+ [[ $cur_sym_elf_size = $sym_elf_size ]] &&
+ [[ $cur_sym_name = $sym_name ]]; then
+ found=1
+ continue
+ fi
+
+ if [[ $found = 1 ]]; then
+ sym_size=$(($cur_sym_addr - $sym_addr))
+ [[ $sym_size -lt $sym_elf_size ]] && continue;
+ found=2
+ break
+ fi
+ done < <(${READELF} --symbols --wide $objfile | sed 's/\[.*\]//' | ${AWK} -v sec=$sym_sec '$7 == sec' | sort --key=2)
+
+ if [[ $found = 0 ]]; then
+ warn "can't find symbol: sym_name: $sym_name sym_sec: $sym_sec sym_addr: $sym_addr sym_elf_size: $sym_elf_size"
+ DONE=1
+ return
+ fi
+
+ # If nothing was found after the symbol, assume it's the last
+ # symbol in the section.
+ [[ $found = 1 ]] && sym_size=$(($sec_size - $sym_addr))
+
if [[ -z $sym_size ]] || [[ $sym_size -le 0 ]]; then
- warn "bad symbol size: base: $sym_base end: $sym_end"
+ warn "bad symbol size: sym_addr: $sym_addr cur_sym_addr: $cur_sym_addr"
DONE=1
return
fi
+
sym_size=0x$(printf %x $sym_size)
- # calculate the address
- local addr=$(($sym_base + $offset))
+ # Calculate the address from user-supplied offset:
+ local addr=$(($sym_addr + $func_offset))
if [[ -z $addr ]] || [[ $addr = 0 ]]; then
- warn "bad address: $sym_base + $offset"
+ warn "bad address: $sym_addr + $func_offset"
DONE=1
return
fi
addr=0x$(printf %x $addr)
- # weed out non-function symbols
- if [[ $sym_type != t ]] && [[ $sym_type != T ]]; then
+ # If the user provided a size, make sure it matches the symbol's size:
+ if [[ -n $user_size ]] && [[ $user_size -ne $sym_size ]]; then
[[ $print_warnings = 1 ]] &&
- echo "skipping $func address at $addr due to non-function symbol of type '$sym_type'"
- continue
- fi
-
- # if the user provided a size, make sure it matches the symbol's size
- if [[ -n $size ]] && [[ $size -ne $sym_size ]]; then
- [[ $print_warnings = 1 ]] &&
- echo "skipping $func address at $addr due to size mismatch ($size != $sym_size)"
+ echo "skipping $sym_name address at $addr due to size mismatch ($user_size != $sym_size)"
continue;
fi
- # make sure the provided offset is within the symbol's range
- if [[ $offset -gt $sym_size ]]; then
+ # Make sure the provided offset is within the symbol's range:
+ if [[ $func_offset -gt $sym_size ]]; then
[[ $print_warnings = 1 ]] &&
- echo "skipping $func address at $addr due to size mismatch ($offset > $sym_size)"
+ echo "skipping $sym_name address at $addr due to size mismatch ($func_offset > $sym_size)"
continue
fi
- # separate multiple entries with a blank line
+ # In case of duplicates or multiple addresses specified on the
+ # cmdline, separate multiple entries with a blank line:
[[ $FIRST = 0 ]] && echo
FIRST=0
- # pass real address to addr2line
- echo "$func+$offset/$sym_size:"
- local file_lines=$(${ADDR2LINE} -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;")
- [[ -z $file_lines ]] && return
+ echo "$sym_name+$func_offset/$sym_size:"
+ # Pass section address to addr2line and strip absolute paths
+ # from the output:
+ local args="--functions --pretty-print --inlines --exe=$objfile"
+ [[ $is_vmlinux = 0 ]] && args="$args --section=$sec_name"
+ local output=$(${ADDR2LINE} $args $addr | sed "s; $dir_prefix\(\./\)*; ;")
+ [[ -z $output ]] && continue
+
+ # Default output (non --list):
if [[ $LIST = 0 ]]; then
- echo "$file_lines" | while read -r line
+ echo "$output" | while read -r line
do
echo $line
done
DONE=1;
- return
+ continue
fi
- # show each line with context
- echo "$file_lines" | while read -r line
+ # For --list, show each line with its corresponding source code:
+ echo "$output" | while read -r line
do
echo
echo $line
@@ -184,12 +255,12 @@ __faddr2line() {
n1=$[$n-5]
n2=$[$n+5]
f=$(echo $line | sed 's/.*at \(.\+\):.*/\1/g')
- awk 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f
+ ${AWK} 'NR>=strtonum("'$n1'") && NR<=strtonum("'$n2'") { if (NR=='$n') printf(">%d<", NR); else printf(" %d ", NR); printf("\t%s\n", $0)}' $f
done
DONE=1
- done < <(${NM} -n $objfile | awk -v fn=$func -v end=$file_end '$3 == fn { found=1; line=$0; start=$1; next } found == 1 { found=0; print line, "0x"$1 } END {if (found == 1) print line, end; }')
+ done < <(${READELF} --symbols --wide $objfile | sed 's/\[.*\]//' | ${AWK} -v fn=$sym_name '$4 == "FUNC" && $8 == fn')
}
[[ $# -lt 2 ]] && usage
@@ -202,6 +273,8 @@ LIST=0
[[ ! -f $objfile ]] && die "can't find objfile $objfile"
shift
+${READELF} --section-headers --wide $objfile | ${GREP} -q '\.debug_info' || die "CONFIG_DEBUG_INFO not enabled"
+
DIR_PREFIX=supercalifragilisticexpialidocious
find_dir_prefix $objfile
diff --git a/scripts/gcc-goto.sh b/scripts/gcc-goto.sh
deleted file mode 100755
index 8b980fb2270a..000000000000
--- a/scripts/gcc-goto.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Test for gcc 'asm goto' support
-# Copyright (C) 2010, Jason Baron <jbaron@redhat.com>
-
-cat << "END" | $@ -x c - -fno-PIE -c -o /dev/null
-int main(void)
-{
-#if defined(__arm__) || defined(__aarch64__)
- /*
- * Not related to asm goto, but used by jump label
- * and broken on some ARM GCC versions (see GCC Bug 48637).
- */
- static struct { int dummy; int state; } tp;
- asm (".long %c0" :: "i" (&tp.state));
-#endif
-
-entry:
- asm goto ("" :::: entry);
- return 0;
-}
-END
diff --git a/scripts/gcc-ld b/scripts/gcc-ld
deleted file mode 100755
index 997b818c3962..000000000000
--- a/scripts/gcc-ld
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# run gcc with ld options
-# used as a wrapper to execute link time optimizations
-# yes virginia, this is not pretty
-
-ARGS="-nostdlib"
-
-while [ "$1" != "" ] ; do
- case "$1" in
- -save-temps|-m32|-m64) N="$1" ;;
- -r) N="$1" ;;
- -[Wg]*) N="$1" ;;
- -[olv]|-[Ofd]*|-nostdlib) N="$1" ;;
- --end-group|--start-group)
- N="-Wl,$1" ;;
- -[RTFGhIezcbyYu]*|\
---script|--defsym|-init|-Map|--oformat|-rpath|\
--rpath-link|--sort-section|--section-start|-Tbss|-Tdata|-Ttext|\
---version-script|--dynamic-list|--version-exports-symbol|--wrap|-m)
- A="$1" ; shift ; N="-Wl,$A,$1" ;;
- -[m]*) N="$1" ;;
- -*) N="-Wl,$1" ;;
- *) N="$1" ;;
- esac
- ARGS="$ARGS $N"
- shift
-done
-
-exec $CC $ARGS
diff --git a/scripts/gcc-plugins/.gitignore b/scripts/gcc-plugins/.gitignore
index b04e0f0f033e..5cc385b9eb97 100644
--- a/scripts/gcc-plugins/.gitignore
+++ b/scripts/gcc-plugins/.gitignore
@@ -1,2 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-randomize_layout_seed.h
+/randomize_layout_seed.h
diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig
index ab9eb4cbe33a..e383cda05367 100644
--- a/scripts/gcc-plugins/Kconfig
+++ b/scripts/gcc-plugins/Kconfig
@@ -19,24 +19,10 @@ menuconfig GCC_PLUGINS
if GCC_PLUGINS
-config GCC_PLUGIN_CYC_COMPLEXITY
- bool "Compute the cyclomatic complexity of a function" if EXPERT
- depends on !COMPILE_TEST # too noisy
- help
- The complexity M of a function's control flow graph is defined as:
- M = E - N + 2P
- where
-
- E = the number of edges
- N = the number of nodes
- P = the number of connected components (exit nodes).
-
- Enabling this plugin reports the complexity to stderr during the
- build. It mainly serves as a simple example of how to create a
- gcc plugin for the kernel.
-
config GCC_PLUGIN_SANCOV
bool
+ # Plugin can be removed once the kernel only supports GCC 6+
+ depends on !CC_HAS_SANCOV_TRACE_PC
help
This plugin inserts a __sanitizer_cov_trace_pc() call at the start of
basic blocks. It supports all gcc versions with plugin support (from
@@ -60,46 +46,6 @@ config GCC_PLUGIN_LATENT_ENTROPY
* https://grsecurity.net/
* https://pax.grsecurity.net/
-config GCC_PLUGIN_RANDSTRUCT
- bool "Randomize layout of sensitive kernel structures"
- select MODVERSIONS if MODULES
- help
- If you say Y here, the layouts of structures that are entirely
- function pointers (and have not been manually annotated with
- __no_randomize_layout), or structures that have been explicitly
- marked with __randomize_layout, will be randomized at compile-time.
- This can introduce the requirement of an additional information
- exposure vulnerability for exploits targeting these structure
- types.
-
- Enabling this feature will introduce some performance impact,
- slightly increase memory usage, and prevent the use of forensic
- tools like Volatility against the system (unless the kernel
- source tree isn't cleaned after kernel installation).
-
- The seed used for compilation is located at
- scripts/gcc-plugins/randomize_layout_seed.h. It remains after
- a make clean to allow for external modules to be compiled with
- the existing seed and will be removed by a make mrproper or
- make distclean.
-
- Note that the implementation requires gcc 4.7 or newer.
-
- This plugin was ported from grsecurity/PaX. More information at:
- * https://grsecurity.net/
- * https://pax.grsecurity.net/
-
-config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE
- bool "Use cacheline-aware structure randomization"
- depends on GCC_PLUGIN_RANDSTRUCT
- depends on !COMPILE_TEST # do not reduce test coverage
- help
- If you say Y here, the RANDSTRUCT randomization will make a
- best effort at restricting randomization to cacheline-sized
- groups of elements. It will further not randomize bitfields
- in structures. This reduces the performance hit of RANDSTRUCT
- at the cost of weakened randomization.
-
config GCC_PLUGIN_ARM_SSP_PER_TASK
bool
depends on GCC_PLUGINS && ARM
diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile
index b5487cce69e8..320afd3cf8e8 100644
--- a/scripts/gcc-plugins/Makefile
+++ b/scripts/gcc-plugins/Makefile
@@ -1,12 +1,17 @@
# SPDX-License-Identifier: GPL-2.0
-$(obj)/randomize_layout_plugin.so: $(objtree)/$(obj)/randomize_layout_seed.h
-quiet_cmd_create_randomize_layout_seed = GENSEED $@
+$(obj)/randomize_layout_plugin.so: $(obj)/randomize_layout_seed.h
+quiet_cmd_create_randomize_layout_seed = SEEDHDR $@
cmd_create_randomize_layout_seed = \
- $(CONFIG_SHELL) $(srctree)/$(src)/gen-random-seed.sh $@ $(objtree)/include/generated/randomize_layout_hash.h
-$(objtree)/$(obj)/randomize_layout_seed.h: FORCE
+ SEED=$$(cat $(filter-out FORCE,$^) </dev/null); \
+ echo '/*' > $@; \
+ echo ' * This file is automatically generated. Keep it private.' >> $@; \
+ echo ' * Exposing this value will expose the layout of randomized structures.' >> $@; \
+ echo ' */' >> $@; \
+ echo "const char *randstruct_seed = \"$$SEED\";" >> $@
+$(obj)/randomize_layout_seed.h: $(objtree)/scripts/basic/randstruct.seed FORCE
$(call if_changed,create_randomize_layout_seed)
-targets += randomize_layout_seed.h randomize_layout_hash.h
+targets += randomize_layout_seed.h
# Build rules for plugins
#
@@ -22,10 +27,12 @@ always-y += $(GCC_PLUGIN)
GCC_PLUGINS_DIR = $(shell $(CC) -print-file-name=plugin)
plugin_cxxflags = -Wp,-MMD,$(depfile) $(KBUILD_HOSTCXXFLAGS) -fPIC \
- -I $(GCC_PLUGINS_DIR)/include -I $(obj) -std=gnu++11 \
- -fno-rtti -fno-exceptions -fasynchronous-unwind-tables \
- -ggdb -Wno-narrowing -Wno-unused-variable \
- -Wno-format-diag
+ -include $(srctree)/include/linux/compiler-version.h \
+ -DPLUGIN_VERSION=$(call stringify,$(KERNELVERSION)) \
+ -I $(GCC_PLUGINS_DIR)/include -I $(obj) \
+ -fno-rtti -fno-exceptions -fasynchronous-unwind-tables \
+ -ggdb -Wno-narrowing -Wno-unused-variable \
+ -Wno-format-diag
plugin_ldflags = -shared
diff --git a/scripts/gcc-plugins/arm_ssp_per_task_plugin.c b/scripts/gcc-plugins/arm_ssp_per_task_plugin.c
index 8c1af9bdcb1b..7328d037f975 100644
--- a/scripts/gcc-plugins/arm_ssp_per_task_plugin.c
+++ b/scripts/gcc-plugins/arm_ssp_per_task_plugin.c
@@ -4,7 +4,7 @@
__visible int plugin_is_GPL_compatible;
-static unsigned int sp_mask, canary_offset;
+static unsigned int canary_offset;
static unsigned int arm_pertask_ssp_rtl_execute(void)
{
@@ -13,7 +13,7 @@ static unsigned int arm_pertask_ssp_rtl_execute(void)
for (insn = get_insns(); insn; insn = NEXT_INSN(insn)) {
const char *sym;
rtx body;
- rtx mask, masked_sp;
+ rtx current;
/*
* Find a SET insn involving a SYMBOL_REF to __stack_chk_guard
@@ -30,19 +30,13 @@ static unsigned int arm_pertask_ssp_rtl_execute(void)
/*
* Replace the source of the SET insn with an expression that
- * produces the address of the copy of the stack canary value
- * stored in struct thread_info
+ * produces the address of the current task's stack canary value
*/
- mask = GEN_INT(sext_hwi(sp_mask, GET_MODE_PRECISION(Pmode)));
- masked_sp = gen_reg_rtx(Pmode);
+ current = gen_reg_rtx(Pmode);
- emit_insn_before(gen_rtx_set(masked_sp,
- gen_rtx_AND(Pmode,
- stack_pointer_rtx,
- mask)),
- insn);
+ emit_insn_before(gen_load_tp_hard(current), insn);
- SET_SRC(body) = gen_rtx_PLUS(Pmode, masked_sp,
+ SET_SRC(body) = gen_rtx_PLUS(Pmode, current,
GEN_INT(canary_offset));
}
return 0;
@@ -72,7 +66,6 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
const char * const plugin_name = plugin_info->base_name;
const int argc = plugin_info->argc;
const struct plugin_argument *argv = plugin_info->argv;
- int tso = 0;
int i;
if (!plugin_default_version_check(version, &gcc_version)) {
@@ -91,11 +84,6 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
return 1;
}
- if (!strcmp(argv[i].key, "tso")) {
- tso = atoi(argv[i].value);
- continue;
- }
-
if (!strcmp(argv[i].key, "offset")) {
canary_offset = atoi(argv[i].value);
continue;
@@ -105,9 +93,6 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
return 1;
}
- /* create the mask that produces the base of the stack */
- sp_mask = ~((1U << (12 + tso)) - 1);
-
PASS_INFO(arm_pertask_ssp_rtl, "expand", 1, PASS_POS_INSERT_AFTER);
register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP,
diff --git a/scripts/gcc-plugins/cyc_complexity_plugin.c b/scripts/gcc-plugins/cyc_complexity_plugin.c
deleted file mode 100644
index 73124c2b3edd..000000000000
--- a/scripts/gcc-plugins/cyc_complexity_plugin.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
- * Licensed under the GPL v2, or (at your option) v3
- *
- * Homepage:
- * https://github.com/ephox-gcc-plugins/cyclomatic_complexity
- *
- * https://en.wikipedia.org/wiki/Cyclomatic_complexity
- * The complexity M is then defined as:
- * M = E - N + 2P
- * where
- *
- * E = the number of edges of the graph
- * N = the number of nodes of the graph
- * P = the number of connected components (exit nodes).
- *
- * Usage (4.5 - 5):
- * $ make clean; make run
- */
-
-#include "gcc-common.h"
-
-__visible int plugin_is_GPL_compatible;
-
-static struct plugin_info cyc_complexity_plugin_info = {
- .version = "20160225",
- .help = "Cyclomatic Complexity\n",
-};
-
-static unsigned int cyc_complexity_execute(void)
-{
- int complexity;
- expanded_location xloc;
-
- /* M = E - N + 2P */
- complexity = n_edges_for_fn(cfun) - n_basic_blocks_for_fn(cfun) + 2;
-
- xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
- fprintf(stderr, "Cyclomatic Complexity %d %s:%s\n", complexity,
- xloc.file, DECL_NAME_POINTER(current_function_decl));
-
- return 0;
-}
-
-#define PASS_NAME cyc_complexity
-
-#define NO_GATE
-#define TODO_FLAGS_FINISH TODO_dump_func
-
-#include "gcc-generate-gimple-pass.h"
-
-__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
-{
- const char * const plugin_name = plugin_info->base_name;
-
- PASS_INFO(cyc_complexity, "ssa", 1, PASS_POS_INSERT_AFTER);
-
- if (!plugin_default_version_check(version, &gcc_version)) {
- error(G_("incompatible gcc/plugin versions"));
- return 1;
- }
-
- register_callback(plugin_name, PLUGIN_INFO, NULL,
- &cyc_complexity_plugin_info);
- register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
- &cyc_complexity_pass_info);
-
- return 0;
-}
diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h
index 0c087614fc3e..84c730da36dd 100644
--- a/scripts/gcc-plugins/gcc-common.h
+++ b/scripts/gcc-plugins/gcc-common.h
@@ -27,9 +27,7 @@
#include "except.h"
#include "function.h"
#include "toplev.h"
-#if BUILDING_GCC_VERSION >= 5000
#include "expr.h"
-#endif
#include "basic-block.h"
#include "intl.h"
#include "ggc.h"
@@ -39,11 +37,7 @@
#include "params.h"
#endif
-#if BUILDING_GCC_VERSION <= 4009
-#include "pointer-set.h"
-#else
#include "hash-map.h"
-#endif
#if BUILDING_GCC_VERSION >= 7000
#include "memmodel.h"
@@ -77,7 +71,9 @@
#include "varasm.h"
#include "stor-layout.h"
#include "internal-fn.h"
+#include "gimple.h"
#include "gimple-expr.h"
+#include "gimple-iterator.h"
#include "gimple-fold.h"
#include "context.h"
#include "tree-ssa-alias.h"
@@ -91,17 +87,12 @@
#include "tree-eh.h"
#include "stmt.h"
#include "gimplify.h"
-#include "gimple.h"
-#include "tree-ssa-operands.h"
#include "tree-phinodes.h"
#include "tree-cfg.h"
-#include "gimple-iterator.h"
#include "gimple-ssa.h"
#include "ssa-iterators.h"
-#if BUILDING_GCC_VERSION >= 5000
#include "builtins.h"
-#endif
/* missing from basic_block.h... */
void debug_dominance_info(enum cdi_direction dir);
@@ -152,125 +143,6 @@ struct register_pass_info NAME##_pass_info = { \
#define TODO_dump_func 0
#define TODO_dump_cgraph 0
-#if BUILDING_GCC_VERSION <= 4009
-#define TODO_verify_il 0
-#define AVAIL_INTERPOSABLE AVAIL_OVERWRITABLE
-
-#define section_name_prefix LTO_SECTION_NAME_PREFIX
-#define fatal_error(loc, gmsgid, ...) fatal_error((gmsgid), __VA_ARGS__)
-
-rtx emit_move_insn(rtx x, rtx y);
-
-typedef struct rtx_def rtx_insn;
-
-static inline const char *get_decl_section_name(const_tree decl)
-{
- if (DECL_SECTION_NAME(decl) == NULL_TREE)
- return NULL;
-
- return TREE_STRING_POINTER(DECL_SECTION_NAME(decl));
-}
-
-static inline void set_decl_section_name(tree node, const char *value)
-{
- if (value)
- DECL_SECTION_NAME(node) = build_string(strlen(value) + 1, value);
- else
- DECL_SECTION_NAME(node) = NULL;
-}
-#endif
-
-#if BUILDING_GCC_VERSION == 4009
-typedef struct gimple_statement_asm gasm;
-typedef struct gimple_statement_base gassign;
-typedef struct gimple_statement_call gcall;
-typedef struct gimple_statement_base gcond;
-typedef struct gimple_statement_base gdebug;
-typedef struct gimple_statement_base ggoto;
-typedef struct gimple_statement_phi gphi;
-typedef struct gimple_statement_base greturn;
-
-static inline gasm *as_a_gasm(gimple stmt)
-{
- return as_a<gasm>(stmt);
-}
-
-static inline const gasm *as_a_const_gasm(const_gimple stmt)
-{
- return as_a<const gasm>(stmt);
-}
-
-static inline gassign *as_a_gassign(gimple stmt)
-{
- return stmt;
-}
-
-static inline const gassign *as_a_const_gassign(const_gimple stmt)
-{
- return stmt;
-}
-
-static inline gcall *as_a_gcall(gimple stmt)
-{
- return as_a<gcall>(stmt);
-}
-
-static inline const gcall *as_a_const_gcall(const_gimple stmt)
-{
- return as_a<const gcall>(stmt);
-}
-
-static inline gcond *as_a_gcond(gimple stmt)
-{
- return stmt;
-}
-
-static inline const gcond *as_a_const_gcond(const_gimple stmt)
-{
- return stmt;
-}
-
-static inline gdebug *as_a_gdebug(gimple stmt)
-{
- return stmt;
-}
-
-static inline const gdebug *as_a_const_gdebug(const_gimple stmt)
-{
- return stmt;
-}
-
-static inline ggoto *as_a_ggoto(gimple stmt)
-{
- return stmt;
-}
-
-static inline const ggoto *as_a_const_ggoto(const_gimple stmt)
-{
- return stmt;
-}
-
-static inline gphi *as_a_gphi(gimple stmt)
-{
- return as_a<gphi>(stmt);
-}
-
-static inline const gphi *as_a_const_gphi(const_gimple stmt)
-{
- return as_a<const gphi>(stmt);
-}
-
-static inline greturn *as_a_greturn(gimple stmt)
-{
- return stmt;
-}
-
-static inline const greturn *as_a_const_greturn(const_gimple stmt)
-{
- return stmt;
-}
-#endif
-
#define TODO_ggc_collect 0
#define NODE_SYMBOL(node) (node)
#define NODE_DECL(node) (node)->decl
@@ -282,7 +154,7 @@ static inline opt_pass *get_pass_for_id(int id)
return g->get_passes()->get_pass_for_id(id);
}
-#if BUILDING_GCC_VERSION >= 5000 && BUILDING_GCC_VERSION < 6000
+#if BUILDING_GCC_VERSION < 6000
/* gimple related */
template <>
template <>
@@ -292,7 +164,6 @@ inline bool is_a_helper<const gassign *>::test(const_gimple gs)
}
#endif
-#if BUILDING_GCC_VERSION >= 5000
#define TODO_verify_ssa TODO_verify_il
#define TODO_verify_flow TODO_verify_il
#define TODO_verify_stmts TODO_verify_il
@@ -533,7 +404,6 @@ static inline void ipa_remove_stmt_references(symtab_node *referring_node, gimpl
{
referring_node->remove_stmt_references(stmt);
}
-#endif
#if BUILDING_GCC_VERSION < 6000
#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \
diff --git a/scripts/gcc-plugins/gcc-generate-gimple-pass.h b/scripts/gcc-plugins/gcc-generate-gimple-pass.h
index 51780828734e..503c07496396 100644
--- a/scripts/gcc-plugins/gcc-generate-gimple-pass.h
+++ b/scripts/gcc-plugins/gcc-generate-gimple-pass.h
@@ -78,17 +78,6 @@ static const pass_data _PASS_NAME_PASS_DATA = {
.type = GIMPLE_PASS,
.name = _PASS_NAME_NAME,
.optinfo_flags = OPTGROUP_NONE,
-#if BUILDING_GCC_VERSION >= 5000
-#elif BUILDING_GCC_VERSION == 4009
- .has_gate = _HAS_GATE,
- .has_execute = _HAS_EXECUTE,
-#else
- .gate = _GATE,
- .execute = _EXECUTE,
- .sub = NULL,
- .next = NULL,
- .static_pass_number = 0,
-#endif
.tv_id = TV_NONE,
.properties_required = PROPERTIES_REQUIRED,
.properties_provided = PROPERTIES_PROVIDED,
@@ -102,21 +91,13 @@ public:
_PASS_NAME_PASS() : gimple_opt_pass(_PASS_NAME_PASS_DATA, g) {}
#ifndef NO_GATE
-#if BUILDING_GCC_VERSION >= 5000
virtual bool gate(function *) { return _GATE(); }
-#else
- virtual bool gate(void) { return _GATE(); }
-#endif
#endif
virtual opt_pass * clone () { return new _PASS_NAME_PASS(); }
#ifndef NO_EXECUTE
-#if BUILDING_GCC_VERSION >= 5000
virtual unsigned int execute(function *) { return _EXECUTE(); }
-#else
- virtual unsigned int execute(void) { return _EXECUTE(); }
-#endif
};
}
diff --git a/scripts/gcc-plugins/gcc-generate-ipa-pass.h b/scripts/gcc-plugins/gcc-generate-ipa-pass.h
index c34ffec035bf..1e7f064e8f6e 100644
--- a/scripts/gcc-plugins/gcc-generate-ipa-pass.h
+++ b/scripts/gcc-plugins/gcc-generate-ipa-pass.h
@@ -146,17 +146,6 @@ static const pass_data _PASS_NAME_PASS_DATA = {
.type = IPA_PASS,
.name = _PASS_NAME_NAME,
.optinfo_flags = OPTGROUP_NONE,
-#if BUILDING_GCC_VERSION >= 5000
-#elif BUILDING_GCC_VERSION == 4009
- .has_gate = _HAS_GATE,
- .has_execute = _HAS_EXECUTE,
-#else
- .gate = _GATE,
- .execute = _EXECUTE,
- .sub = NULL,
- .next = NULL,
- .static_pass_number = 0,
-#endif
.tv_id = TV_NONE,
.properties_required = PROPERTIES_REQUIRED,
.properties_provided = PROPERTIES_PROVIDED,
@@ -180,20 +169,12 @@ public:
_VARIABLE_TRANSFORM) {}
#ifndef NO_GATE
-#if BUILDING_GCC_VERSION >= 5000
virtual bool gate(function *) { return _GATE(); }
-#else
- virtual bool gate(void) { return _GATE(); }
-#endif
virtual opt_pass *clone() { return new _PASS_NAME_PASS(); }
#ifndef NO_EXECUTE
-#if BUILDING_GCC_VERSION >= 5000
virtual unsigned int execute(function *) { return _EXECUTE(); }
-#else
- virtual unsigned int execute(void) { return _EXECUTE(); }
-#endif
#endif
};
}
diff --git a/scripts/gcc-plugins/gcc-generate-rtl-pass.h b/scripts/gcc-plugins/gcc-generate-rtl-pass.h
index d14614f4b139..7cd46e8d5049 100644
--- a/scripts/gcc-plugins/gcc-generate-rtl-pass.h
+++ b/scripts/gcc-plugins/gcc-generate-rtl-pass.h
@@ -78,17 +78,6 @@ static const pass_data _PASS_NAME_PASS_DATA = {
.type = RTL_PASS,
.name = _PASS_NAME_NAME,
.optinfo_flags = OPTGROUP_NONE,
-#if BUILDING_GCC_VERSION >= 5000
-#elif BUILDING_GCC_VERSION == 4009
- .has_gate = _HAS_GATE,
- .has_execute = _HAS_EXECUTE,
-#else
- .gate = _GATE,
- .execute = _EXECUTE,
- .sub = NULL,
- .next = NULL,
- .static_pass_number = 0,
-#endif
.tv_id = TV_NONE,
.properties_required = PROPERTIES_REQUIRED,
.properties_provided = PROPERTIES_PROVIDED,
@@ -102,21 +91,13 @@ public:
_PASS_NAME_PASS() : rtl_opt_pass(_PASS_NAME_PASS_DATA, g) {}
#ifndef NO_GATE
-#if BUILDING_GCC_VERSION >= 5000
virtual bool gate(function *) { return _GATE(); }
-#else
- virtual bool gate(void) { return _GATE(); }
-#endif
#endif
virtual opt_pass *clone() { return new _PASS_NAME_PASS(); }
#ifndef NO_EXECUTE
-#if BUILDING_GCC_VERSION >= 5000
virtual unsigned int execute(function *) { return _EXECUTE(); }
-#else
- virtual unsigned int execute(void) { return _EXECUTE(); }
-#endif
#endif
};
}
diff --git a/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h b/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
index ef6f4c2cb6fa..33093ccc947a 100644
--- a/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
+++ b/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
@@ -78,17 +78,6 @@ static const pass_data _PASS_NAME_PASS_DATA = {
.type = SIMPLE_IPA_PASS,
.name = _PASS_NAME_NAME,
.optinfo_flags = OPTGROUP_NONE,
-#if BUILDING_GCC_VERSION >= 5000
-#elif BUILDING_GCC_VERSION == 4009
- .has_gate = _HAS_GATE,
- .has_execute = _HAS_EXECUTE,
-#else
- .gate = _GATE,
- .execute = _EXECUTE,
- .sub = NULL,
- .next = NULL,
- .static_pass_number = 0,
-#endif
.tv_id = TV_NONE,
.properties_required = PROPERTIES_REQUIRED,
.properties_provided = PROPERTIES_PROVIDED,
@@ -102,21 +91,13 @@ public:
_PASS_NAME_PASS() : simple_ipa_opt_pass(_PASS_NAME_PASS_DATA, g) {}
#ifndef NO_GATE
-#if BUILDING_GCC_VERSION >= 5000
virtual bool gate(function *) { return _GATE(); }
-#else
- virtual bool gate(void) { return _GATE(); }
-#endif
#endif
virtual opt_pass *clone() { return new _PASS_NAME_PASS(); }
#ifndef NO_EXECUTE
-#if BUILDING_GCC_VERSION >= 5000
virtual unsigned int execute(function *) { return _EXECUTE(); }
-#else
- virtual unsigned int execute(void) { return _EXECUTE(); }
-#endif
#endif
};
}
diff --git a/scripts/gcc-plugins/gen-random-seed.sh b/scripts/gcc-plugins/gen-random-seed.sh
deleted file mode 100644
index 68af5cc20a64..000000000000
--- a/scripts/gcc-plugins/gen-random-seed.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-
-if [ ! -f "$1" ]; then
- SEED=`od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n'`
- echo "const char *randstruct_seed = \"$SEED\";" > "$1"
- HASH=`echo -n "$SEED" | sha256sum | cut -d" " -f1 | tr -d ' \n'`
- echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2"
-fi
diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c
index 9dced66d158e..39e86be60dd2 100644
--- a/scripts/gcc-plugins/latent_entropy_plugin.c
+++ b/scripts/gcc-plugins/latent_entropy_plugin.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2012-2016 by the PaX Team <pageexec@freemail.hu>
* Copyright 2016 by Emese Revfy <re.emese@gmail.com>
- * Licensed under the GPL v2
*
* Note: the choice of the license means that the compilation process is
* NOT 'eligible' as defined by gcc's library exception to the GPL v3,
@@ -82,29 +82,35 @@ __visible int plugin_is_GPL_compatible;
static GTY(()) tree latent_entropy_decl;
static struct plugin_info latent_entropy_plugin_info = {
- .version = "201606141920vanilla",
+ .version = PLUGIN_VERSION,
.help = "disable\tturn off latent entropy instrumentation\n",
};
-static unsigned HOST_WIDE_INT seed;
-/*
- * get_random_seed() (this is a GCC function) generates the seed.
- * This is a simple random generator without any cryptographic security because
- * the entropy doesn't come from here.
- */
+static unsigned HOST_WIDE_INT deterministic_seed;
+static unsigned HOST_WIDE_INT rnd_buf[32];
+static size_t rnd_idx = ARRAY_SIZE(rnd_buf);
+static int urandom_fd = -1;
+
static unsigned HOST_WIDE_INT get_random_const(void)
{
- unsigned int i;
- unsigned HOST_WIDE_INT ret = 0;
-
- for (i = 0; i < 8 * sizeof(ret); i++) {
- ret = (ret << 1) | (seed & 1);
- seed >>= 1;
- if (ret & 1)
- seed ^= 0xD800000000000000ULL;
+ if (deterministic_seed) {
+ unsigned HOST_WIDE_INT w = deterministic_seed;
+ w ^= w << 13;
+ w ^= w >> 7;
+ w ^= w << 17;
+ deterministic_seed = w;
+ return deterministic_seed;
}
- return ret;
+ if (urandom_fd < 0) {
+ urandom_fd = open("/dev/urandom", O_RDONLY);
+ gcc_assert(urandom_fd >= 0);
+ }
+ if (rnd_idx >= ARRAY_SIZE(rnd_buf)) {
+ gcc_assert(read(urandom_fd, rnd_buf, sizeof(rnd_buf)) == sizeof(rnd_buf));
+ rnd_idx = 0;
+ }
+ return rnd_buf[rnd_idx++];
}
static tree tree_get_random_const(tree type)
@@ -524,7 +530,7 @@ static unsigned int latent_entropy_execute(void)
while (bb != EXIT_BLOCK_PTR_FOR_FN(cfun)) {
perturb_local_entropy(bb, local_entropy);
bb = bb->next_bb;
- };
+ }
/* 4. mix local entropy into the global entropy variable */
perturb_latent_entropy(local_entropy);
@@ -537,8 +543,6 @@ static void latent_entropy_start_unit(void *gcc_data __unused,
tree type, id;
int quals;
- seed = get_random_seed(false);
-
if (in_lto_p)
return;
@@ -573,6 +577,12 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
const struct plugin_argument * const argv = plugin_info->argv;
int i;
+ /*
+ * Call get_random_seed() with noinit=true, so that this returns
+ * 0 in the case where no seed has been passed via -frandom-seed.
+ */
+ deterministic_seed = get_random_seed(true);
+
static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = {
{
.base = &latent_entropy_decl,
diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index 334741a31d0a..951b74ba1b24 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -34,29 +34,11 @@ __visible int plugin_is_GPL_compatible;
static int performance_mode;
static struct plugin_info randomize_layout_plugin_info = {
- .version = "201402201816vanilla",
+ .version = PLUGIN_VERSION,
.help = "disable\t\t\tdo not activate plugin\n"
"performance-mode\tenable cacheline-aware layout randomization\n"
};
-struct whitelist_entry {
- const char *pathname;
- const char *lhs;
- const char *rhs;
-};
-
-static const struct whitelist_entry whitelist[] = {
- /* NIU overloads mapping with page struct */
- { "drivers/net/ethernet/sun/niu.c", "page", "address_space" },
- /* unix_skb_parms via UNIXCB() buffer */
- { "net/unix/af_unix.c", "unix_skb_parms", "char" },
- /* big_key payload.data struct splashing */
- { "security/keys/big_key.c", "path", "void *" },
- /* walk struct security_hook_heads as an array of struct hlist_head */
- { "security/security.c", "hlist_head", "security_hook_heads" },
- { }
-};
-
/* from old Linux dcache.h */
static inline unsigned long
partial_name_hash(unsigned long c, unsigned long prevhash)
@@ -742,60 +724,6 @@ static void handle_local_var_initializers(void)
}
}
-static bool type_name_eq(gimple stmt, const_tree type_tree, const char *wanted_name)
-{
- const char *type_name;
-
- if (type_tree == NULL_TREE)
- return false;
-
- switch (TREE_CODE(type_tree)) {
- case RECORD_TYPE:
- type_name = TYPE_NAME_POINTER(type_tree);
- break;
- case INTEGER_TYPE:
- if (TYPE_PRECISION(type_tree) == CHAR_TYPE_SIZE)
- type_name = "char";
- else {
- INFORM(gimple_location(stmt), "found non-char INTEGER_TYPE cast comparison: %qT\n", type_tree);
- debug_tree(type_tree);
- return false;
- }
- break;
- case POINTER_TYPE:
- if (TREE_CODE(TREE_TYPE(type_tree)) == VOID_TYPE) {
- type_name = "void *";
- break;
- } else {
- INFORM(gimple_location(stmt), "found non-void POINTER_TYPE cast comparison %qT\n", type_tree);
- debug_tree(type_tree);
- return false;
- }
- default:
- INFORM(gimple_location(stmt), "unhandled cast comparison: %qT\n", type_tree);
- debug_tree(type_tree);
- return false;
- }
-
- return strcmp(type_name, wanted_name) == 0;
-}
-
-static bool whitelisted_cast(gimple stmt, const_tree lhs_tree, const_tree rhs_tree)
-{
- const struct whitelist_entry *entry;
- expanded_location xloc = expand_location(gimple_location(stmt));
-
- for (entry = whitelist; entry->pathname; entry++) {
- if (!strstr(xloc.file, entry->pathname))
- continue;
-
- if (type_name_eq(stmt, lhs_tree, entry->lhs) && type_name_eq(stmt, rhs_tree, entry->rhs))
- return true;
- }
-
- return false;
-}
-
/*
* iterate over all statements to find "bad" casts:
* those where the address of the start of a structure is cast
@@ -872,10 +800,7 @@ static unsigned int find_bad_casts_execute(void)
#ifndef __DEBUG_PLUGIN
if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type)))
#endif
- {
- if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type))
- MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type);
- }
+ MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type);
continue;
}
@@ -898,10 +823,7 @@ static unsigned int find_bad_casts_execute(void)
#ifndef __DEBUG_PLUGIN
if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type)))
#endif
- {
- if (!whitelisted_cast(stmt, ptr_lhs_type, op0_type))
- MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type);
- }
+ MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type);
} else {
const_tree ssa_name_var = SSA_NAME_VAR(rhs1);
/* skip bogus type casts introduced by container_of */
@@ -911,10 +833,7 @@ static unsigned int find_bad_casts_execute(void)
#ifndef __DEBUG_PLUGIN
if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type)))
#endif
- {
- if (!whitelisted_cast(stmt, ptr_lhs_type, ptr_rhs_type))
- MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type);
- }
+ MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type);
}
}
diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c
index 23bd023a283b..b76cb9c42cec 100644
--- a/scripts/gcc-plugins/sancov_plugin.c
+++ b/scripts/gcc-plugins/sancov_plugin.c
@@ -26,7 +26,7 @@ __visible int plugin_is_GPL_compatible;
tree sancov_fndecl;
static struct plugin_info sancov_plugin_info = {
- .version = "20160402",
+ .version = PLUGIN_VERSION,
.help = "sancov plugin\n",
};
diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c
index e9db7dcb3e5f..c5c2ce113c92 100644
--- a/scripts/gcc-plugins/stackleak_plugin.c
+++ b/scripts/gcc-plugins/stackleak_plugin.c
@@ -1,7 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2011-2017 by the PaX Team <pageexec@freemail.hu>
* Modified by Alexander Popov <alex.popov@linux.com>
- * Licensed under the GPL v2
*
* Note: the choice of the license means that the compilation process is
* NOT 'eligible' as defined by gcc's library exception to the GPL v3,
@@ -44,7 +44,7 @@ static bool verbose = false;
static GTY(()) tree track_function_decl;
static struct plugin_info stackleak_plugin_info = {
- .version = "201707101337",
+ .version = PLUGIN_VERSION,
.help = "track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n"
"arch=target_arch\tspecify target build arch\n"
"disable\t\tdo not activate the plugin\n"
@@ -429,6 +429,23 @@ static unsigned int stackleak_cleanup_execute(void)
return 0;
}
+/*
+ * STRING_CST may or may not be NUL terminated:
+ * https://gcc.gnu.org/onlinedocs/gccint/Constant-expressions.html
+ */
+static inline bool string_equal(tree node, const char *string, int length)
+{
+ if (TREE_STRING_LENGTH(node) < length)
+ return false;
+ if (TREE_STRING_LENGTH(node) > length + 1)
+ return false;
+ if (TREE_STRING_LENGTH(node) == length + 1 &&
+ TREE_STRING_POINTER(node)[length] != '\0')
+ return false;
+ return !memcmp(TREE_STRING_POINTER(node), string, length);
+}
+#define STRING_EQUAL(node, str) string_equal(node, str, strlen(str))
+
static bool stackleak_gate(void)
{
tree section;
@@ -438,13 +455,17 @@ static bool stackleak_gate(void)
if (section && TREE_VALUE(section)) {
section = TREE_VALUE(TREE_VALUE(section));
- if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10))
+ if (STRING_EQUAL(section, ".init.text"))
+ return false;
+ if (STRING_EQUAL(section, ".devinit.text"))
+ return false;
+ if (STRING_EQUAL(section, ".cpuinit.text"))
return false;
- if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13))
+ if (STRING_EQUAL(section, ".meminit.text"))
return false;
- if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13))
+ if (STRING_EQUAL(section, ".noinstr.text"))
return false;
- if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13))
+ if (STRING_EQUAL(section, ".entry.text"))
return false;
}
diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c
index 29b480c33a8d..d8c744233832 100644
--- a/scripts/gcc-plugins/structleak_plugin.c
+++ b/scripts/gcc-plugins/structleak_plugin.c
@@ -1,6 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2013-2017 by PaX Team <pageexec@freemail.hu>
- * Licensed under the GPL v2
*
* Note: the choice of the license means that the compilation process is
* NOT 'eligible' as defined by gcc's library exception to the GPL v3,
@@ -37,7 +37,7 @@
__visible int plugin_is_GPL_compatible;
static struct plugin_info structleak_plugin_info = {
- .version = "20190125vanilla",
+ .version = PLUGIN_VERSION,
.help = "disable\tdo not activate plugin\n"
"byref\tinit structs passed by reference\n"
"byref-all\tinit anything passed by reference\n"
@@ -103,10 +103,8 @@ static void finish_type(void *event_data, void *data)
if (type == NULL_TREE || type == error_mark_node)
return;
-#if BUILDING_GCC_VERSION >= 5000
if (TREE_CODE(type) == ENUMERAL_TYPE)
return;
-#endif
if (TYPE_USERSPACE(type))
return;
@@ -170,7 +168,6 @@ static void initialize(tree var)
static unsigned int structleak_execute(void)
{
basic_block bb;
- unsigned int ret = 0;
tree var;
unsigned int i;
@@ -200,7 +197,7 @@ static unsigned int structleak_execute(void)
initialize(var);
}
- return ret;
+ return 0;
}
#define PASS_NAME structleak
diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh
index f5c119495254..825c75c5b715 100755
--- a/scripts/gcc-x86_32-has-stack-protector.sh
+++ b/scripts/gcc-x86_32-has-stack-protector.sh
@@ -1,4 +1,8 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
-echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32 -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
+# This requires GCC 8.1 or better. Specifically, we require
+# -mstack-protector-guard-reg, added by
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81708
+
+echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32 -O0 -fstack-protector -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard - -o - 2> /dev/null | grep -q "%fs"
diff --git a/scripts/gdb/linux/clk.py b/scripts/gdb/linux/clk.py
index 061aecfa294e..7a01fdc3e844 100644
--- a/scripts/gdb/linux/clk.py
+++ b/scripts/gdb/linux/clk.py
@@ -41,6 +41,8 @@ are cached and potentially out of date"""
self.show_subtree(child, level + 1)
def invoke(self, arg, from_tty):
+ if utils.gdb_eval_or_none("clk_root_list") is None:
+ raise gdb.GdbError("No clocks registered")
gdb.write(" enable prepare protect \n")
gdb.write(" clock count count count rate \n")
gdb.write("------------------------------------------------------------------------\n")
diff --git a/scripts/gdb/linux/config.py b/scripts/gdb/linux/config.py
index 90e1565b1967..8843ab3cbadd 100644
--- a/scripts/gdb/linux/config.py
+++ b/scripts/gdb/linux/config.py
@@ -24,9 +24,9 @@ class LxConfigDump(gdb.Command):
filename = arg
try:
- py_config_ptr = gdb.parse_and_eval("kernel_config_data + 8")
- py_config_size = gdb.parse_and_eval(
- "sizeof(kernel_config_data) - 1 - 8 * 2")
+ py_config_ptr = gdb.parse_and_eval("&kernel_config_data")
+ py_config_ptr_end = gdb.parse_and_eval("&kernel_config_data_end")
+ py_config_size = py_config_ptr_end - py_config_ptr
except gdb.error as e:
raise gdb.GdbError("Can't find config, enable CONFIG_IKCONFIG?")
diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
index 2efbec6b6b8d..fab74ca9df6f 100644
--- a/scripts/gdb/linux/constants.py.in
+++ b/scripts/gdb/linux/constants.py.in
@@ -15,8 +15,10 @@
#include <linux/clk-provider.h>
#include <linux/fs.h>
#include <linux/hrtimer.h>
+#include <linux/irq.h>
#include <linux/mount.h>
#include <linux/of_fdt.h>
+#include <linux/radix-tree.h>
#include <linux/threads.h>
/* We need to stringify expanded macros so that they can be parsed */
@@ -39,21 +41,33 @@
import gdb
+LX_CONFIG(CONFIG_DEBUG_INFO_REDUCED)
+
/* linux/clk-provider.h */
if IS_BUILTIN(CONFIG_COMMON_CLK):
LX_GDBPARSED(CLK_GET_RATE_NOCACHE)
/* linux/fs.h */
-LX_VALUE(SB_RDONLY)
-LX_VALUE(SB_SYNCHRONOUS)
-LX_VALUE(SB_MANDLOCK)
-LX_VALUE(SB_DIRSYNC)
-LX_VALUE(SB_NOATIME)
-LX_VALUE(SB_NODIRATIME)
+LX_GDBPARSED(SB_RDONLY)
+LX_GDBPARSED(SB_SYNCHRONOUS)
+LX_GDBPARSED(SB_MANDLOCK)
+LX_GDBPARSED(SB_DIRSYNC)
+LX_GDBPARSED(SB_NOATIME)
+LX_GDBPARSED(SB_NODIRATIME)
/* linux/htimer.h */
LX_GDBPARSED(hrtimer_resolution)
+/* linux/irq.h */
+LX_GDBPARSED(IRQD_LEVEL)
+LX_GDBPARSED(IRQ_HIDDEN)
+
+/* linux/module.h */
+LX_GDBPARSED(MOD_TEXT)
+LX_GDBPARSED(MOD_DATA)
+LX_GDBPARSED(MOD_RODATA)
+LX_GDBPARSED(MOD_RO_AFTER_INIT)
+
/* linux/mount.h */
LX_VALUE(MNT_NOSUID)
LX_VALUE(MNT_NODEV)
@@ -68,6 +82,13 @@ LX_VALUE(NR_CPUS)
/* linux/of_fdt.h> */
LX_VALUE(OF_DT_HEADER)
+/* linux/radix-tree.h */
+LX_GDBPARSED(RADIX_TREE_ENTRY_MASK)
+LX_GDBPARSED(RADIX_TREE_INTERNAL_NODE)
+LX_GDBPARSED(RADIX_TREE_MAP_SIZE)
+LX_GDBPARSED(RADIX_TREE_MAP_SHIFT)
+LX_GDBPARSED(RADIX_TREE_MAP_MASK)
+
/* Kernel Configs */
LX_CONFIG(CONFIG_GENERIC_CLOCKEVENTS)
LX_CONFIG(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
@@ -75,3 +96,12 @@ LX_CONFIG(CONFIG_HIGH_RES_TIMERS)
LX_CONFIG(CONFIG_NR_CPUS)
LX_CONFIG(CONFIG_OF)
LX_CONFIG(CONFIG_TICK_ONESHOT)
+LX_CONFIG(CONFIG_GENERIC_IRQ_SHOW_LEVEL)
+LX_CONFIG(CONFIG_X86_LOCAL_APIC)
+LX_CONFIG(CONFIG_SMP)
+LX_CONFIG(CONFIG_X86_THERMAL_VECTOR)
+LX_CONFIG(CONFIG_X86_MCE_THRESHOLD)
+LX_CONFIG(CONFIG_X86_MCE_AMD)
+LX_CONFIG(CONFIG_X86_MCE)
+LX_CONFIG(CONFIG_X86_IO_APIC)
+LX_CONFIG(CONFIG_HAVE_KVM)
diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py
index 008e62f3190d..255dc18cb9da 100644
--- a/scripts/gdb/linux/cpus.py
+++ b/scripts/gdb/linux/cpus.py
@@ -16,6 +16,9 @@ import gdb
from linux import tasks, utils
+task_type = utils.CachedType("struct task_struct")
+
+
MAX_CPUS = 4096
@@ -156,6 +159,29 @@ Note that VAR has to be quoted as string."""
PerCpu()
+def get_current_task(cpu):
+ task_ptr_type = task_type.get_type().pointer()
+
+ if utils.is_target_arch("x86"):
+ if gdb.lookup_global_symbol("cpu_tasks"):
+ # This is a UML kernel, which stores the current task
+ # differently than other x86 sub architectures
+ var_ptr = gdb.parse_and_eval("(struct task_struct *)cpu_tasks[0].task")
+ return var_ptr.dereference()
+ else:
+ var_ptr = gdb.parse_and_eval("&pcpu_hot.current_task")
+ return per_cpu(var_ptr, cpu).dereference()
+ elif utils.is_target_arch("aarch64"):
+ current_task_addr = gdb.parse_and_eval("$SP_EL0")
+ if (current_task_addr >> 63) != 0:
+ current_task = current_task_addr.cast(task_ptr_type)
+ return current_task.dereference()
+ else:
+ raise gdb.GdbError("Sorry, obtaining the current task is not allowed "
+ "while running in userspace(EL0)")
+ else:
+ raise gdb.GdbError("Sorry, obtaining the current task is not yet "
+ "supported with this arch")
class LxCurrentFunc(gdb.Function):
"""Return current task.
@@ -167,8 +193,7 @@ number. If CPU is omitted, the CPU of the current context is used."""
super(LxCurrentFunc, self).__init__("lx_current")
def invoke(self, cpu=-1):
- var_ptr = gdb.parse_and_eval("&current_task")
- return per_cpu(var_ptr, cpu).dereference()
+ return get_current_task(cpu)
LxCurrentFunc()
diff --git a/scripts/gdb/linux/dmesg.py b/scripts/gdb/linux/dmesg.py
index a92c55bd8de5..c771831eb077 100644
--- a/scripts/gdb/linux/dmesg.py
+++ b/scripts/gdb/linux/dmesg.py
@@ -22,7 +22,6 @@ prb_desc_type = utils.CachedType("struct prb_desc")
prb_desc_ring_type = utils.CachedType("struct prb_desc_ring")
prb_data_ring_type = utils.CachedType("struct prb_data_ring")
printk_ringbuffer_type = utils.CachedType("struct printk_ringbuffer")
-atomic_long_type = utils.CachedType("atomic_long_t")
class LxDmesg(gdb.Command):
"""Print Linux kernel log buffer."""
@@ -44,19 +43,17 @@ class LxDmesg(gdb.Command):
sz = prb_desc_ring_type.get_type().sizeof
desc_ring = utils.read_memoryview(inf, addr, sz).tobytes()
- # read in descriptor array
+ # read in descriptor count, size, and address
off = prb_desc_ring_type.get_type()['count_bits'].bitpos // 8
desc_ring_count = 1 << utils.read_u32(desc_ring, off)
desc_sz = prb_desc_type.get_type().sizeof
off = prb_desc_ring_type.get_type()['descs'].bitpos // 8
- addr = utils.read_ulong(desc_ring, off)
- descs = utils.read_memoryview(inf, addr, desc_sz * desc_ring_count).tobytes()
+ desc_addr = utils.read_ulong(desc_ring, off)
- # read in info array
+ # read in info size and address
info_sz = printk_info_type.get_type().sizeof
off = prb_desc_ring_type.get_type()['infos'].bitpos // 8
- addr = utils.read_ulong(desc_ring, off)
- infos = utils.read_memoryview(inf, addr, info_sz * desc_ring_count).tobytes()
+ info_addr = utils.read_ulong(desc_ring, off)
# read in text data ring structure
off = printk_ringbuffer_type.get_type()['text_data_ring'].bitpos // 8
@@ -64,14 +61,11 @@ class LxDmesg(gdb.Command):
sz = prb_data_ring_type.get_type().sizeof
text_data_ring = utils.read_memoryview(inf, addr, sz).tobytes()
- # read in text data
+ # read in text data size and address
off = prb_data_ring_type.get_type()['size_bits'].bitpos // 8
text_data_sz = 1 << utils.read_u32(text_data_ring, off)
off = prb_data_ring_type.get_type()['data'].bitpos // 8
- addr = utils.read_ulong(text_data_ring, off)
- text_data = utils.read_memoryview(inf, addr, text_data_sz).tobytes()
-
- counter_off = atomic_long_type.get_type()['counter'].bitpos // 8
+ text_data_addr = utils.read_ulong(text_data_ring, off)
sv_off = prb_desc_type.get_type()['state_var'].bitpos // 8
@@ -92,9 +86,9 @@ class LxDmesg(gdb.Command):
# read in tail and head descriptor ids
off = prb_desc_ring_type.get_type()['tail_id'].bitpos // 8
- tail_id = utils.read_u64(desc_ring, off + counter_off)
+ tail_id = utils.read_atomic_long(desc_ring, off)
off = prb_desc_ring_type.get_type()['head_id'].bitpos // 8
- head_id = utils.read_u64(desc_ring, off + counter_off)
+ head_id = utils.read_atomic_long(desc_ring, off)
did = tail_id
while True:
@@ -102,17 +96,20 @@ class LxDmesg(gdb.Command):
desc_off = desc_sz * ind
info_off = info_sz * ind
+ desc = utils.read_memoryview(inf, desc_addr + desc_off, desc_sz).tobytes()
+
# skip non-committed record
- state = 3 & (utils.read_u64(descs, desc_off + sv_off +
- counter_off) >> desc_flags_shift)
+ state = 3 & (utils.read_atomic_long(desc, sv_off) >> desc_flags_shift)
if state != desc_committed and state != desc_finalized:
if did == head_id:
break
did = (did + 1) & desc_id_mask
continue
- begin = utils.read_ulong(descs, desc_off + begin_off) % text_data_sz
- end = utils.read_ulong(descs, desc_off + next_off) % text_data_sz
+ begin = utils.read_ulong(desc, begin_off) % text_data_sz
+ end = utils.read_ulong(desc, next_off) % text_data_sz
+
+ info = utils.read_memoryview(inf, info_addr + info_off, info_sz).tobytes()
# handle data-less record
if begin & 1 == 1:
@@ -125,16 +122,17 @@ class LxDmesg(gdb.Command):
# skip over descriptor id
text_start = begin + utils.get_long_type().sizeof
- text_len = utils.read_u16(infos, info_off + len_off)
+ text_len = utils.read_u16(info, len_off)
# handle truncated message
if end - text_start < text_len:
text_len = end - text_start
- text = text_data[text_start:text_start + text_len].decode(
- encoding='utf8', errors='replace')
+ text_data = utils.read_memoryview(inf, text_data_addr + text_start,
+ text_len).tobytes()
+ text = text_data[0:text_len].decode(encoding='utf8', errors='replace')
- time_stamp = utils.read_u64(infos, info_off + ts_off)
+ time_stamp = utils.read_u64(info, ts_off)
for line in text.splitlines():
msg = u"[{time:12.6f}] {line}\n".format(
diff --git a/scripts/gdb/linux/genpd.py b/scripts/gdb/linux/genpd.py
index 39cd1abd8559..b53649c0a77a 100644
--- a/scripts/gdb/linux/genpd.py
+++ b/scripts/gdb/linux/genpd.py
@@ -5,7 +5,7 @@
import gdb
import sys
-from linux.utils import CachedType
+from linux.utils import CachedType, gdb_eval_or_none
from linux.lists import list_for_each_entry
generic_pm_domain_type = CachedType('struct generic_pm_domain')
@@ -70,6 +70,8 @@ Output is similar to /sys/kernel/debug/pm_genpd/pm_genpd_summary'''
gdb.write(' %-50s %s\n' % (kobj_path, rtpm_status_str(dev)))
def invoke(self, arg, from_tty):
+ if gdb_eval_or_none("&gpd_list") is None:
+ raise gdb.GdbError("No power domain(s) registered")
gdb.write('domain status children\n');
gdb.write(' /device runtime status\n');
gdb.write('----------------------------------------------------------------------\n');
diff --git a/scripts/gdb/linux/interrupts.py b/scripts/gdb/linux/interrupts.py
new file mode 100644
index 000000000000..ef478e273791
--- /dev/null
+++ b/scripts/gdb/linux/interrupts.py
@@ -0,0 +1,232 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright 2023 Broadcom
+
+import gdb
+
+from linux import constants
+from linux import cpus
+from linux import utils
+from linux import radixtree
+
+irq_desc_type = utils.CachedType("struct irq_desc")
+
+def irq_settings_is_hidden(desc):
+ return desc['status_use_accessors'] & constants.LX_IRQ_HIDDEN
+
+def irq_desc_is_chained(desc):
+ return desc['action'] and desc['action'] == gdb.parse_and_eval("&chained_action")
+
+def irqd_is_level(desc):
+ return desc['irq_data']['common']['state_use_accessors'] & constants.LX_IRQD_LEVEL
+
+def show_irq_desc(prec, irq):
+ text = ""
+
+ desc = radixtree.lookup(gdb.parse_and_eval("&irq_desc_tree"), irq)
+ if desc is None:
+ return text
+
+ desc = desc.cast(irq_desc_type.get_type())
+ if desc is None:
+ return text
+
+ if irq_settings_is_hidden(desc):
+ return text
+
+ any_count = 0
+ if desc['kstat_irqs']:
+ for cpu in cpus.each_online_cpu():
+ any_count += cpus.per_cpu(desc['kstat_irqs'], cpu)
+
+ if (desc['action'] == 0 or irq_desc_is_chained(desc)) and any_count == 0:
+ return text;
+
+ text += "%*d: " % (prec, irq)
+ for cpu in cpus.each_online_cpu():
+ if desc['kstat_irqs']:
+ count = cpus.per_cpu(desc['kstat_irqs'], cpu)
+ else:
+ count = 0
+ text += "%10u" % (count)
+
+ name = "None"
+ if desc['irq_data']['chip']:
+ chip = desc['irq_data']['chip']
+ if chip['name']:
+ name = chip['name'].string()
+ else:
+ name = "-"
+
+ text += " %8s" % (name)
+
+ if desc['irq_data']['domain']:
+ text += " %*lu" % (prec, desc['irq_data']['hwirq'])
+ else:
+ text += " %*s" % (prec, "")
+
+ if constants.LX_CONFIG_GENERIC_IRQ_SHOW_LEVEL:
+ text += " %-8s" % ("Level" if irqd_is_level(desc) else "Edge")
+
+ if desc['name']:
+ text += "-%-8s" % (desc['name'].string())
+
+ """ Some toolchains may not be able to provide information about irqaction """
+ try:
+ gdb.lookup_type("struct irqaction")
+ action = desc['action']
+ if action is not None:
+ text += " %s" % (action['name'].string())
+ while True:
+ action = action['next']
+ if action is not None:
+ break
+ if action['name']:
+ text += ", %s" % (action['name'].string())
+ except:
+ pass
+
+ text += "\n"
+
+ return text
+
+def show_irq_err_count(prec):
+ cnt = utils.gdb_eval_or_none("irq_err_count")
+ text = ""
+ if cnt is not None:
+ text += "%*s: %10u\n" % (prec, "ERR", cnt['counter'])
+ return text
+
+def x86_show_irqstat(prec, pfx, field, desc):
+ irq_stat = gdb.parse_and_eval("&irq_stat")
+ text = "%*s: " % (prec, pfx)
+ for cpu in cpus.each_online_cpu():
+ stat = cpus.per_cpu(irq_stat, cpu)
+ text += "%10u " % (stat[field])
+ text += " %s\n" % (desc)
+ return text
+
+def x86_show_mce(prec, var, pfx, desc):
+ pvar = gdb.parse_and_eval(var)
+ text = "%*s: " % (prec, pfx)
+ for cpu in cpus.each_online_cpu():
+ text += "%10u " % (cpus.per_cpu(pvar, cpu))
+ text += " %s\n" % (desc)
+ return text
+
+def x86_show_interupts(prec):
+ text = x86_show_irqstat(prec, "NMI", '__nmi_count', 'Non-maskable interrupts')
+
+ if constants.LX_CONFIG_X86_LOCAL_APIC:
+ text += x86_show_irqstat(prec, "LOC", 'apic_timer_irqs', "Local timer interrupts")
+ text += x86_show_irqstat(prec, "SPU", 'irq_spurious_count', "Spurious interrupts")
+ text += x86_show_irqstat(prec, "PMI", 'apic_perf_irqs', "Performance monitoring interrupts")
+ text += x86_show_irqstat(prec, "IWI", 'apic_irq_work_irqs', "IRQ work interrupts")
+ text += x86_show_irqstat(prec, "RTR", 'icr_read_retry_count', "APIC ICR read retries")
+ if utils.gdb_eval_or_none("x86_platform_ipi_callback") is not None:
+ text += x86_show_irqstat(prec, "PLT", 'x86_platform_ipis', "Platform interrupts")
+
+ if constants.LX_CONFIG_SMP:
+ text += x86_show_irqstat(prec, "RES", 'irq_resched_count', "Rescheduling interrupts")
+ text += x86_show_irqstat(prec, "CAL", 'irq_call_count', "Function call interrupts")
+ text += x86_show_irqstat(prec, "TLB", 'irq_tlb_count', "TLB shootdowns")
+
+ if constants.LX_CONFIG_X86_THERMAL_VECTOR:
+ text += x86_show_irqstat(prec, "TRM", 'irq_thermal_count', "Thermal events interrupts")
+
+ if constants.LX_CONFIG_X86_MCE_THRESHOLD:
+ text += x86_show_irqstat(prec, "THR", 'irq_threshold_count', "Threshold APIC interrupts")
+
+ if constants.LX_CONFIG_X86_MCE_AMD:
+ text += x86_show_irqstat(prec, "DFR", 'irq_deferred_error_count', "Deferred Error APIC interrupts")
+
+ if constants.LX_CONFIG_X86_MCE:
+ text += x86_show_mce(prec, "&mce_exception_count", "MCE", "Machine check exceptions")
+ text == x86_show_mce(prec, "&mce_poll_count", "MCP", "Machine check polls")
+
+ text += show_irq_err_count(prec)
+
+ if constants.LX_CONFIG_X86_IO_APIC:
+ cnt = utils.gdb_eval_or_none("irq_mis_count")
+ if cnt is not None:
+ text += "%*s: %10u\n" % (prec, "MIS", cnt['counter'])
+
+ if constants.LX_CONFIG_HAVE_KVM:
+ text += x86_show_irqstat(prec, "PIN", 'kvm_posted_intr_ipis', 'Posted-interrupt notification event')
+ text += x86_show_irqstat(prec, "NPI", 'kvm_posted_intr_nested_ipis', 'Nested posted-interrupt event')
+ text += x86_show_irqstat(prec, "PIW", 'kvm_posted_intr_wakeup_ipis', 'Posted-interrupt wakeup event')
+
+ return text
+
+def arm_common_show_interrupts(prec):
+ text = ""
+ nr_ipi = utils.gdb_eval_or_none("nr_ipi")
+ ipi_desc = utils.gdb_eval_or_none("ipi_desc")
+ ipi_types = utils.gdb_eval_or_none("ipi_types")
+ if nr_ipi is None or ipi_desc is None or ipi_types is None:
+ return text
+
+ if prec >= 4:
+ sep = " "
+ else:
+ sep = ""
+
+ for ipi in range(nr_ipi):
+ text += "%*s%u:%s" % (prec - 1, "IPI", ipi, sep)
+ desc = ipi_desc[ipi].cast(irq_desc_type.get_type().pointer())
+ if desc == 0:
+ continue
+ for cpu in cpus.each_online_cpu():
+ text += "%10u" % (cpus.per_cpu(desc['kstat_irqs'], cpu))
+ text += " %s" % (ipi_types[ipi].string())
+ text += "\n"
+ return text
+
+def aarch64_show_interrupts(prec):
+ text = arm_common_show_interrupts(prec)
+ text += "%*s: %10lu\n" % (prec, "ERR", gdb.parse_and_eval("irq_err_count"))
+ return text
+
+def arch_show_interrupts(prec):
+ text = ""
+ if utils.is_target_arch("x86"):
+ text += x86_show_interupts(prec)
+ elif utils.is_target_arch("aarch64"):
+ text += aarch64_show_interrupts(prec)
+ elif utils.is_target_arch("arm"):
+ text += arm_common_show_interrupts(prec)
+ elif utils.is_target_arch("mips"):
+ text += show_irq_err_count(prec)
+ else:
+ raise gdb.GdbError("Unsupported architecture: {}".format(target_arch))
+
+ return text
+
+class LxInterruptList(gdb.Command):
+ """Print /proc/interrupts"""
+
+ def __init__(self):
+ super(LxInterruptList, self).__init__("lx-interruptlist", gdb.COMMAND_DATA)
+
+ def invoke(self, arg, from_tty):
+ nr_irqs = gdb.parse_and_eval("nr_irqs")
+ prec = 3
+ j = 1000
+ while prec < 10 and j <= nr_irqs:
+ prec += 1
+ j *= 10
+
+ gdb.write("%*s" % (prec + 8, ""))
+ for cpu in cpus.each_online_cpu():
+ gdb.write("CPU%-8d" % cpu)
+ gdb.write("\n")
+
+ if utils.gdb_eval_or_none("&irq_desc_tree") is None:
+ return
+
+ for irq in range(nr_irqs):
+ gdb.write(show_irq_desc(prec, irq))
+ gdb.write(arch_show_interrupts(prec))
+
+
+LxInterruptList()
diff --git a/scripts/gdb/linux/mm.py b/scripts/gdb/linux/mm.py
new file mode 100644
index 000000000000..30d837f3dfae
--- /dev/null
+++ b/scripts/gdb/linux/mm.py
@@ -0,0 +1,222 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# gdb helper commands and functions for Linux kernel debugging
+#
+# routines to introspect page table
+#
+# Authors:
+# Dmitrii Bundin <dmitrii.bundin.a@gmail.com>
+#
+
+import gdb
+
+from linux import utils
+
+PHYSICAL_ADDRESS_MASK = gdb.parse_and_eval('0xfffffffffffff')
+
+
+def page_mask(level=1):
+ # 4KB
+ if level == 1:
+ return gdb.parse_and_eval('(u64) ~0xfff')
+ # 2MB
+ elif level == 2:
+ return gdb.parse_and_eval('(u64) ~0x1fffff')
+ # 1GB
+ elif level == 3:
+ return gdb.parse_and_eval('(u64) ~0x3fffffff')
+ else:
+ raise Exception(f'Unknown page level: {level}')
+
+
+#page_offset_base in case CONFIG_DYNAMIC_MEMORY_LAYOUT is disabled
+POB_NO_DYNAMIC_MEM_LAYOUT = '0xffff888000000000'
+def _page_offset_base():
+ pob_symbol = gdb.lookup_global_symbol('page_offset_base')
+ pob = pob_symbol.name if pob_symbol else POB_NO_DYNAMIC_MEM_LAYOUT
+ return gdb.parse_and_eval(pob)
+
+
+def is_bit_defined_tupled(data, offset):
+ return offset, bool(data >> offset & 1)
+
+def content_tupled(data, bit_start, bit_end):
+ return (bit_start, bit_end), data >> bit_start & ((1 << (1 + bit_end - bit_start)) - 1)
+
+def entry_va(level, phys_addr, translating_va):
+ def start_bit(level):
+ if level == 5:
+ return 48
+ elif level == 4:
+ return 39
+ elif level == 3:
+ return 30
+ elif level == 2:
+ return 21
+ elif level == 1:
+ return 12
+ else:
+ raise Exception(f'Unknown level {level}')
+
+ entry_offset = ((translating_va >> start_bit(level)) & 511) * 8
+ entry_va = _page_offset_base() + phys_addr + entry_offset
+ return entry_va
+
+class Cr3():
+ def __init__(self, cr3, page_levels):
+ self.cr3 = cr3
+ self.page_levels = page_levels
+ self.page_level_write_through = is_bit_defined_tupled(cr3, 3)
+ self.page_level_cache_disabled = is_bit_defined_tupled(cr3, 4)
+ self.next_entry_physical_address = cr3 & PHYSICAL_ADDRESS_MASK & page_mask()
+
+ def next_entry(self, va):
+ next_level = self.page_levels
+ return PageHierarchyEntry(entry_va(next_level, self.next_entry_physical_address, va), next_level)
+
+ def mk_string(self):
+ return f"""\
+cr3:
+ {'cr3 binary data': <30} {hex(self.cr3)}
+ {'next entry physical address': <30} {hex(self.next_entry_physical_address)}
+ ---
+ {'bit' : <4} {self.page_level_write_through[0]: <10} {'page level write through': <30} {self.page_level_write_through[1]}
+ {'bit' : <4} {self.page_level_cache_disabled[0]: <10} {'page level cache disabled': <30} {self.page_level_cache_disabled[1]}
+"""
+
+
+class PageHierarchyEntry():
+ def __init__(self, address, level):
+ data = int.from_bytes(
+ memoryview(gdb.selected_inferior().read_memory(address, 8)),
+ "little"
+ )
+ if level == 1:
+ self.is_page = True
+ self.entry_present = is_bit_defined_tupled(data, 0)
+ self.read_write = is_bit_defined_tupled(data, 1)
+ self.user_access_allowed = is_bit_defined_tupled(data, 2)
+ self.page_level_write_through = is_bit_defined_tupled(data, 3)
+ self.page_level_cache_disabled = is_bit_defined_tupled(data, 4)
+ self.entry_was_accessed = is_bit_defined_tupled(data, 5)
+ self.dirty = is_bit_defined_tupled(data, 6)
+ self.pat = is_bit_defined_tupled(data, 7)
+ self.global_translation = is_bit_defined_tupled(data, 8)
+ self.page_physical_address = data & PHYSICAL_ADDRESS_MASK & page_mask(level)
+ self.next_entry_physical_address = None
+ self.hlat_restart_with_ordinary = is_bit_defined_tupled(data, 11)
+ self.protection_key = content_tupled(data, 59, 62)
+ self.executed_disable = is_bit_defined_tupled(data, 63)
+ else:
+ page_size = is_bit_defined_tupled(data, 7)
+ page_size_bit = page_size[1]
+ self.is_page = page_size_bit
+ self.entry_present = is_bit_defined_tupled(data, 0)
+ self.read_write = is_bit_defined_tupled(data, 1)
+ self.user_access_allowed = is_bit_defined_tupled(data, 2)
+ self.page_level_write_through = is_bit_defined_tupled(data, 3)
+ self.page_level_cache_disabled = is_bit_defined_tupled(data, 4)
+ self.entry_was_accessed = is_bit_defined_tupled(data, 5)
+ self.page_size = page_size
+ self.dirty = is_bit_defined_tupled(
+ data, 6) if page_size_bit else None
+ self.global_translation = is_bit_defined_tupled(
+ data, 8) if page_size_bit else None
+ self.pat = is_bit_defined_tupled(
+ data, 12) if page_size_bit else None
+ self.page_physical_address = data & PHYSICAL_ADDRESS_MASK & page_mask(level) if page_size_bit else None
+ self.next_entry_physical_address = None if page_size_bit else data & PHYSICAL_ADDRESS_MASK & page_mask()
+ self.hlat_restart_with_ordinary = is_bit_defined_tupled(data, 11)
+ self.protection_key = content_tupled(data, 59, 62) if page_size_bit else None
+ self.executed_disable = is_bit_defined_tupled(data, 63)
+ self.address = address
+ self.page_entry_binary_data = data
+ self.page_hierarchy_level = level
+
+ def next_entry(self, va):
+ if self.is_page or not self.entry_present[1]:
+ return None
+
+ next_level = self.page_hierarchy_level - 1
+ return PageHierarchyEntry(entry_va(next_level, self.next_entry_physical_address, va), next_level)
+
+
+ def mk_string(self):
+ if not self.entry_present[1]:
+ return f"""\
+level {self.page_hierarchy_level}:
+ {'entry address': <30} {hex(self.address)}
+ {'page entry binary data': <30} {hex(self.page_entry_binary_data)}
+ ---
+ PAGE ENTRY IS NOT PRESENT!
+"""
+ elif self.is_page:
+ def page_size_line(ps_bit, ps, level):
+ return "" if level == 1 else f"{'bit': <3} {ps_bit: <5} {'page size': <30} {ps}"
+
+ return f"""\
+level {self.page_hierarchy_level}:
+ {'entry address': <30} {hex(self.address)}
+ {'page entry binary data': <30} {hex(self.page_entry_binary_data)}
+ {'page size': <30} {'1GB' if self.page_hierarchy_level == 3 else '2MB' if self.page_hierarchy_level == 2 else '4KB' if self.page_hierarchy_level == 1 else 'Unknown page size for level:' + self.page_hierarchy_level}
+ {'page physical address': <30} {hex(self.page_physical_address)}
+ ---
+ {'bit': <4} {self.entry_present[0]: <10} {'entry present': <30} {self.entry_present[1]}
+ {'bit': <4} {self.read_write[0]: <10} {'read/write access allowed': <30} {self.read_write[1]}
+ {'bit': <4} {self.user_access_allowed[0]: <10} {'user access allowed': <30} {self.user_access_allowed[1]}
+ {'bit': <4} {self.page_level_write_through[0]: <10} {'page level write through': <30} {self.page_level_write_through[1]}
+ {'bit': <4} {self.page_level_cache_disabled[0]: <10} {'page level cache disabled': <30} {self.page_level_cache_disabled[1]}
+ {'bit': <4} {self.entry_was_accessed[0]: <10} {'entry has been accessed': <30} {self.entry_was_accessed[1]}
+ {"" if self.page_hierarchy_level == 1 else f"{'bit': <4} {self.page_size[0]: <10} {'page size': <30} {self.page_size[1]}"}
+ {'bit': <4} {self.dirty[0]: <10} {'page dirty': <30} {self.dirty[1]}
+ {'bit': <4} {self.global_translation[0]: <10} {'global translation': <30} {self.global_translation[1]}
+ {'bit': <4} {self.hlat_restart_with_ordinary[0]: <10} {'restart to ordinary': <30} {self.hlat_restart_with_ordinary[1]}
+ {'bit': <4} {self.pat[0]: <10} {'pat': <30} {self.pat[1]}
+ {'bits': <4} {str(self.protection_key[0]): <10} {'protection key': <30} {self.protection_key[1]}
+ {'bit': <4} {self.executed_disable[0]: <10} {'execute disable': <30} {self.executed_disable[1]}
+"""
+ else:
+ return f"""\
+level {self.page_hierarchy_level}:
+ {'entry address': <30} {hex(self.address)}
+ {'page entry binary data': <30} {hex(self.page_entry_binary_data)}
+ {'next entry physical address': <30} {hex(self.next_entry_physical_address)}
+ ---
+ {'bit': <4} {self.entry_present[0]: <10} {'entry present': <30} {self.entry_present[1]}
+ {'bit': <4} {self.read_write[0]: <10} {'read/write access allowed': <30} {self.read_write[1]}
+ {'bit': <4} {self.user_access_allowed[0]: <10} {'user access allowed': <30} {self.user_access_allowed[1]}
+ {'bit': <4} {self.page_level_write_through[0]: <10} {'page level write through': <30} {self.page_level_write_through[1]}
+ {'bit': <4} {self.page_level_cache_disabled[0]: <10} {'page level cache disabled': <30} {self.page_level_cache_disabled[1]}
+ {'bit': <4} {self.entry_was_accessed[0]: <10} {'entry has been accessed': <30} {self.entry_was_accessed[1]}
+ {'bit': <4} {self.page_size[0]: <10} {'page size': <30} {self.page_size[1]}
+ {'bit': <4} {self.hlat_restart_with_ordinary[0]: <10} {'restart to ordinary': <30} {self.hlat_restart_with_ordinary[1]}
+ {'bit': <4} {self.executed_disable[0]: <10} {'execute disable': <30} {self.executed_disable[1]}
+"""
+
+
+class TranslateVM(gdb.Command):
+ """Prints the entire paging structure used to translate a given virtual address.
+
+Having an address space of the currently executed process translates the virtual address
+and prints detailed information of all paging structure levels used for the transaltion.
+Currently supported arch: x86"""
+
+ def __init__(self):
+ super(TranslateVM, self).__init__('translate-vm', gdb.COMMAND_USER)
+
+ def invoke(self, arg, from_tty):
+ if utils.is_target_arch("x86"):
+ vm_address = gdb.parse_and_eval(f'{arg}')
+ cr3_data = gdb.parse_and_eval('$cr3')
+ cr4 = gdb.parse_and_eval('$cr4')
+ page_levels = 5 if cr4 & (1 << 12) else 4
+ page_entry = Cr3(cr3_data, page_levels)
+ while page_entry:
+ gdb.write(page_entry.mk_string())
+ page_entry = page_entry.next_entry(vm_address)
+ else:
+ gdb.GdbError("Virtual address translation is not"
+ "supported for this arch")
+
+
+TranslateVM()
diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py
index 441b23239896..f76a43bfa15f 100644
--- a/scripts/gdb/linux/modules.py
+++ b/scripts/gdb/linux/modules.py
@@ -13,7 +13,7 @@
import gdb
-from linux import cpus, utils, lists
+from linux import cpus, utils, lists, constants
module_type = utils.CachedType("struct module")
@@ -73,11 +73,17 @@ class LxLsmod(gdb.Command):
" " if utils.get_long_type().sizeof == 8 else ""))
for module in module_list():
- layout = module['core_layout']
+ text = module['mem'][constants.LX_MOD_TEXT]
+ text_addr = str(text['base']).split()[0]
+ total_size = 0
+
+ for i in range(constants.LX_MOD_TEXT, constants.LX_MOD_RO_AFTER_INIT + 1):
+ total_size += module['mem'][i]['size']
+
gdb.write("{address} {name:<19} {size:>8} {ref}".format(
- address=str(layout['base']).split()[0],
+ address=text_addr,
name=module['name'].string(),
- size=str(layout['size']),
+ size=str(total_size),
ref=str(module['refcnt']['counter'] - 1)))
t = self._module_use_type.get_type().pointer()
diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
index 09cd871925a5..43c687e7a69d 100644
--- a/scripts/gdb/linux/proc.py
+++ b/scripts/gdb/linux/proc.py
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# gdb helper commands and functions for Linux kernel debugging
#
@@ -16,6 +17,7 @@ from linux import constants
from linux import utils
from linux import tasks
from linux import lists
+from linux import vfs
from struct import *
@@ -170,16 +172,16 @@ values of that process namespace"""
gdb.write("{:^18} {:^15} {:>9} {} {} options\n".format(
"mount", "super_block", "devname", "pathname", "fstype"))
- for vfs in lists.list_for_each_entry(namespace['list'],
+ for mnt in lists.list_for_each_entry(namespace['list'],
mount_ptr_type, "mnt_list"):
- devname = vfs['mnt_devname'].string()
+ devname = mnt['mnt_devname'].string()
devname = devname if devname else "none"
pathname = ""
- parent = vfs
+ parent = mnt
while True:
mntpoint = parent['mnt_mountpoint']
- pathname = utils.dentry_name(mntpoint) + pathname
+ pathname = vfs.dentry_name(mntpoint) + pathname
if (parent == parent['mnt_parent']):
break
parent = parent['mnt_parent']
@@ -187,14 +189,14 @@ values of that process namespace"""
if (pathname == ""):
pathname = "/"
- superblock = vfs['mnt']['mnt_sb']
+ superblock = mnt['mnt']['mnt_sb']
fstype = superblock['s_type']['name'].string()
s_flags = int(superblock['s_flags'])
- m_flags = int(vfs['mnt']['mnt_flags'])
+ m_flags = int(mnt['mnt']['mnt_flags'])
rd = "ro" if (s_flags & constants.LX_SB_RDONLY) else "rw"
gdb.write("{} {} {} {} {} {}{}{} 0 0\n".format(
- vfs.format_string(), superblock.format_string(), devname,
+ mnt.format_string(), superblock.format_string(), devname,
pathname, fstype, rd, info_opts(FS_INFO, s_flags),
info_opts(MNT_INFO, m_flags)))
diff --git a/scripts/gdb/linux/radixtree.py b/scripts/gdb/linux/radixtree.py
new file mode 100644
index 000000000000..074543ac763d
--- /dev/null
+++ b/scripts/gdb/linux/radixtree.py
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Radix Tree Parser
+#
+# Copyright (c) 2016 Linaro Ltd
+# Copyright (c) 2023 Broadcom
+#
+# Authors:
+# Kieran Bingham <kieran.bingham@linaro.org>
+# Florian Fainelli <f.fainelli@gmail.com>
+
+import gdb
+
+from linux import utils
+from linux import constants
+
+radix_tree_root_type = utils.CachedType("struct xarray")
+radix_tree_node_type = utils.CachedType("struct xa_node")
+
+def is_internal_node(node):
+ long_type = utils.get_long_type()
+ return ((node.cast(long_type) & constants.LX_RADIX_TREE_ENTRY_MASK) == constants.LX_RADIX_TREE_INTERNAL_NODE)
+
+def entry_to_node(node):
+ long_type = utils.get_long_type()
+ node_type = node.type
+ indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INTERNAL_NODE
+ return indirect_ptr.cast(radix_tree_node_type.get_type().pointer())
+
+def node_maxindex(node):
+ return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1
+
+def lookup(root, index):
+ if root.type == radix_tree_root_type.get_type().pointer():
+ node = root.dereference()
+ elif root.type != radix_tree_root_type.get_type():
+ raise gdb.GdbError("must be {} not {}"
+ .format(radix_tree_root_type.get_type(), root.type))
+
+ node = root['xa_head']
+ if node == 0:
+ return None
+
+ if not (is_internal_node(node)):
+ if (index > 0):
+ return None
+ return node
+
+ node = entry_to_node(node)
+ maxindex = node_maxindex(node)
+
+ if (index > maxindex):
+ return None
+
+ shift = node['shift'] + constants.LX_RADIX_TREE_MAP_SHIFT
+
+ while True:
+ offset = (index >> node['shift']) & constants.LX_RADIX_TREE_MAP_MASK
+ slot = node['slots'][offset]
+
+ if slot == 0:
+ return None
+
+ node = slot.cast(node.type.pointer()).dereference()
+ if node == 0:
+ return None
+
+ shift -= constants.LX_RADIX_TREE_MAP_SHIFT
+ if (shift <= 0):
+ break
+
+ return node
+
+class LxRadixTree(gdb.Function):
+ """ Lookup and return a node from a RadixTree.
+
+$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index.
+If index is omitted, the root node is dereference and returned."""
+
+ def __init__(self):
+ super(LxRadixTree, self).__init__("lx_radix_tree_lookup")
+
+ def invoke(self, root, index=0):
+ result = lookup(root, index)
+ if result is None:
+ raise gdb.GdbError("No entry in tree at index {}".format(index))
+
+ return result
+
+LxRadixTree()
diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py
index 1be9763cf8bb..fdad3f32c747 100644
--- a/scripts/gdb/linux/symbols.py
+++ b/scripts/gdb/linux/symbols.py
@@ -15,7 +15,7 @@ import gdb
import os
import re
-from linux import modules, utils
+from linux import modules, utils, constants
if hasattr(gdb, 'Breakpoint'):
@@ -109,7 +109,7 @@ lx-symbols command."""
def load_module_symbols(self, module):
module_name = module['name'].string()
- module_addr = str(module['core_layout']['base']).split()[0]
+ module_addr = str(module['mem'][constants.LX_MOD_TEXT]['base']).split()[0]
module_file = self._get_module_file(module_name)
if not module_file and not self.module_files_updated:
@@ -148,7 +148,8 @@ lx-symbols command."""
# drop all current symbols and reload vmlinux
orig_vmlinux = 'vmlinux'
for obj in gdb.objfiles():
- if obj.filename.endswith('vmlinux'):
+ if (obj.filename.endswith('vmlinux') or
+ obj.filename.endswith('vmlinux.debug')):
orig_vmlinux = obj.filename
gdb.execute("symbol-file", to_string=True)
gdb.execute("symbol-file {0}".format(orig_vmlinux))
@@ -164,7 +165,8 @@ lx-symbols command."""
saved_state['breakpoint'].enabled = saved_state['enabled']
def invoke(self, arg, from_tty):
- self.module_paths = [os.path.expanduser(p) for p in arg.split()]
+ self.module_paths = [os.path.abspath(os.path.expanduser(p))
+ for p in arg.split()]
self.module_paths.append(os.getcwd())
# enforce update
@@ -178,7 +180,7 @@ lx-symbols command."""
self.breakpoint.delete()
self.breakpoint = None
self.breakpoint = LoadModuleBreakpoint(
- "kernel/module.c:do_init_module", self)
+ "kernel/module/main.c:do_init_module", self)
else:
gdb.write("Note: symbol update on module loading not supported "
"with this gdb version\n")
diff --git a/scripts/gdb/linux/timerlist.py b/scripts/gdb/linux/timerlist.py
index 071d0dd5a634..64bc87191003 100644
--- a/scripts/gdb/linux/timerlist.py
+++ b/scripts/gdb/linux/timerlist.py
@@ -43,8 +43,7 @@ def print_timer(rb_node, idx):
def print_active_timers(base):
- curr = base['active']['next']['node']
- curr = curr.address.cast(rbtree.rb_node_type.get_type().pointer())
+ curr = base['active']['rb_root']['rb_leftmost']
idx = 0
while curr:
yield print_timer(curr, idx)
@@ -73,7 +72,7 @@ def print_cpu(hrtimer_bases, cpu, max_clock_bases):
ts = cpus.per_cpu(tick_sched_ptr, cpu)
text = "cpu: {}\n".format(cpu)
- for i in xrange(max_clock_bases):
+ for i in range(max_clock_bases):
text += " clock {}:\n".format(i)
text += print_base(cpu_base['clock_base'][i])
@@ -158,6 +157,8 @@ def pr_cpumask(mask):
num_bytes = (nr_cpu_ids + 7) / 8
buf = utils.read_memoryview(inf, bits, num_bytes).tobytes()
buf = binascii.b2a_hex(buf)
+ if type(buf) is not str:
+ buf=buf.decode()
chunks = []
i = num_bytes
@@ -173,7 +174,7 @@ def pr_cpumask(mask):
if 0 < extra <= 4:
chunks[0] = chunks[0][0] # Cut off the first 0
- return "".join(chunks)
+ return "".join(str(chunks))
class LxTimerList(gdb.Command):
@@ -187,7 +188,8 @@ class LxTimerList(gdb.Command):
max_clock_bases = gdb.parse_and_eval("HRTIMER_MAX_CLOCK_BASES")
text = "Timer List Version: gdb scripts\n"
- text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(max_clock_bases)
+ text += "HRTIMER_MAX_CLOCK_BASES: {}\n".format(
+ max_clock_bases.type.fields()[max_clock_bases].enumval)
text += "now at {} nsecs\n".format(ktime_get())
for cpu in cpus.each_online_cpu():
diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py
index ff7c1799d588..9f44df13761e 100644
--- a/scripts/gdb/linux/utils.py
+++ b/scripts/gdb/linux/utils.py
@@ -35,13 +35,12 @@ class CachedType:
long_type = CachedType("long")
-
+atomic_long_type = CachedType("atomic_long_t")
def get_long_type():
global long_type
return long_type.get_type()
-
def offset_of(typeobj, field):
element = gdb.Value(0).cast(typeobj)
return int(str(element[field].address).split()[0], 16)
@@ -89,7 +88,10 @@ def get_target_endianness():
def read_memoryview(inf, start, length):
- return memoryview(inf.read_memory(start, length))
+ m = inf.read_memory(start, length)
+ if type(m) is memoryview:
+ return m
+ return memoryview(m)
def read_u16(buffer, offset):
@@ -129,6 +131,17 @@ def read_ulong(buffer, offset):
else:
return read_u32(buffer, offset)
+atomic_long_counter_offset = atomic_long_type.get_type()['counter'].bitpos
+atomic_long_counter_sizeof = atomic_long_type.get_type()['counter'].type.sizeof
+
+def read_atomic_long(buffer, offset):
+ global atomic_long_counter_offset
+ global atomic_long_counter_sizeof
+
+ if atomic_long_counter_sizeof == 8:
+ return read_u64(buffer, offset + atomic_long_counter_offset)
+ else:
+ return read_u32(buffer, offset + atomic_long_counter_offset)
target_arch = None
@@ -183,11 +196,3 @@ def gdb_eval_or_none(expresssion):
return gdb.parse_and_eval(expresssion)
except gdb.error:
return None
-
-
-def dentry_name(d):
- parent = d['d_parent']
- if parent == d or parent == 0:
- return ""
- p = dentry_name(d['d_parent']) + "/"
- return p + d['d_iname'].string()
diff --git a/scripts/gdb/linux/vfs.py b/scripts/gdb/linux/vfs.py
new file mode 100644
index 000000000000..c77b9ce75f6d
--- /dev/null
+++ b/scripts/gdb/linux/vfs.py
@@ -0,0 +1,59 @@
+#
+# gdb helper commands and functions for Linux kernel debugging
+#
+# VFS tools
+#
+# Copyright (c) 2023 Glenn Washburn
+# Copyright (c) 2016 Linaro Ltd
+#
+# Authors:
+# Glenn Washburn <development@efficientek.com>
+# Kieran Bingham <kieran.bingham@linaro.org>
+#
+# This work is licensed under the terms of the GNU GPL version 2.
+#
+
+import gdb
+from linux import utils
+
+
+def dentry_name(d):
+ parent = d['d_parent']
+ if parent == d or parent == 0:
+ return ""
+ p = dentry_name(d['d_parent']) + "/"
+ return p + d['d_iname'].string()
+
+class DentryName(gdb.Function):
+ """Return string of the full path of a dentry.
+
+$lx_dentry_name(PTR): Given PTR to a dentry struct, return a string
+of the full path of the dentry."""
+
+ def __init__(self):
+ super(DentryName, self).__init__("lx_dentry_name")
+
+ def invoke(self, dentry_ptr):
+ return dentry_name(dentry_ptr)
+
+DentryName()
+
+
+dentry_type = utils.CachedType("struct dentry")
+
+class InodeDentry(gdb.Function):
+ """Return dentry pointer for inode.
+
+$lx_i_dentry(PTR): Given PTR to an inode struct, return a pointer to
+the associated dentry struct, if there is one."""
+
+ def __init__(self):
+ super(InodeDentry, self).__init__("lx_i_dentry")
+
+ def invoke(self, inode_ptr):
+ d_u = inode_ptr["i_dentry"]["first"]
+ if d_u == 0:
+ return ""
+ return utils.container_of(d_u, dentry_type.get_type().pointer(), "d_u")
+
+InodeDentry()
diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py
index 4136dc2c59df..2d32308c3f7a 100644
--- a/scripts/gdb/vmlinux-gdb.py
+++ b/scripts/gdb/vmlinux-gdb.py
@@ -13,7 +13,7 @@
import os
-sys.path.insert(0, os.path.dirname(__file__) + "/scripts/gdb")
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + "/scripts/gdb")
try:
gdb.parse_and_eval("0")
@@ -22,6 +22,10 @@ except:
gdb.write("NOTE: gdb 7.2 or later required for Linux helper scripts to "
"work.\n")
else:
+ import linux.constants
+ if linux.constants.LX_CONFIG_DEBUG_INFO_REDUCED:
+ raise gdb.GdbError("Reduced debug information will prevent GDB "
+ "from having complete types.\n")
import linux.utils
import linux.symbols
import linux.modules
@@ -32,8 +36,11 @@ else:
import linux.lists
import linux.rbtree
import linux.proc
- import linux.constants
import linux.timerlist
import linux.clk
import linux.genpd
import linux.device
+ import linux.vfs
+ import linux.mm
+ import linux.radixtree
+ import linux.interrupts
diff --git a/scripts/gen-randstruct-seed.sh b/scripts/gen-randstruct-seed.sh
new file mode 100755
index 000000000000..61017b36c464
--- /dev/null
+++ b/scripts/gen-randstruct-seed.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+SEED=$(od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n')
+echo "$SEED" > "$1"
+HASH=$(echo -n "$SEED" | sha256sum | cut -d" " -f1)
+echo "#define RANDSTRUCT_HASHED_SEED \"$HASH\"" > "$2"
diff --git a/scripts/gen_autoksyms.sh b/scripts/gen_autoksyms.sh
deleted file mode 100755
index da320151e7c3..000000000000
--- a/scripts/gen_autoksyms.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0-only
-
-# Create an autoksyms.h header file from the list of all module's needed symbols
-# as recorded on the second line of *.mod files and the user-provided symbol
-# whitelist.
-
-set -e
-
-output_file="$1"
-
-# Use "make V=1" to debug this script.
-case "$KBUILD_VERBOSE" in
-*1*)
- set -x
- ;;
-esac
-
-# We need access to CONFIG_ symbols
-. include/config/auto.conf
-
-needed_symbols=
-
-# Special case for modversions (see modpost.c)
-if [ -n "$CONFIG_MODVERSIONS" ]; then
- needed_symbols="$needed_symbols module_layout"
-fi
-
-# With CONFIG_LTO_CLANG, LLVM bitcode has not yet been compiled into a binary
-# when the .mod files are generated, which means they don't yet contain
-# references to certain symbols that will be present in the final binaries.
-if [ -n "$CONFIG_LTO_CLANG" ]; then
- # intrinsic functions
- needed_symbols="$needed_symbols memcpy memmove memset"
- # ftrace
- needed_symbols="$needed_symbols _mcount"
- # stack protector symbols
- needed_symbols="$needed_symbols __stack_chk_fail __stack_chk_guard"
-fi
-
-ksym_wl=
-if [ -n "$CONFIG_UNUSED_KSYMS_WHITELIST" ]; then
- # Use 'eval' to expand the whitelist path and check if it is relative
- eval ksym_wl="$CONFIG_UNUSED_KSYMS_WHITELIST"
- [ "${ksym_wl}" != "${ksym_wl#/}" ] || ksym_wl="$abs_srctree/$ksym_wl"
- if [ ! -f "$ksym_wl" ] || [ ! -r "$ksym_wl" ]; then
- echo "ERROR: '$ksym_wl' whitelist file not found" >&2
- exit 1
- fi
-fi
-
-# Generate a new ksym list file with symbols needed by the current
-# set of modules.
-cat > "$output_file" << EOT
-/*
- * Automatically generated file; DO NOT EDIT.
- */
-
-EOT
-
-[ -f modules.order ] && modlist=modules.order || modlist=/dev/null
-
-{
- sed 's/ko$/mod/' $modlist | xargs -n1 sed -n -e '2p'
- echo "$needed_symbols"
- [ -n "$ksym_wl" ] && cat "$ksym_wl"
-} | sed -e 's/ /\n/g' | sed -n -e '/^$/!p' |
-# Remove the dot prefix for ppc64; symbol names with a dot (.) hold entry
-# point addresses.
-sed -e 's/^\.//' |
-sort -u |
-sed -e 's/\(.*\)/#define __KSYM_\1 1/' >> "$output_file"
diff --git a/scripts/gen_ksymdeps.sh b/scripts/gen_ksymdeps.sh
deleted file mode 100755
index 1324986e1362..000000000000
--- a/scripts/gen_ksymdeps.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-
-set -e
-
-# List of exported symbols
-ksyms=$($NM $1 | sed -n 's/.*__ksym_marker_\(.*\)/\1/p' | tr A-Z a-z)
-
-if [ -z "$ksyms" ]; then
- exit 0
-fi
-
-echo
-echo "ksymdeps_$1 := \\"
-
-for s in $ksyms
-do
- echo $s | sed -e 's:^_*: $(wildcard include/ksym/:' \
- -e 's:__*:/:g' -e 's/$/.h) \\/'
-done
-
-echo
-echo "$1: \$(ksymdeps_$1)"
-echo
-echo "\$(ksymdeps_$1):"
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
new file mode 100755
index 000000000000..946e250c1b2a
--- /dev/null
+++ b/scripts/generate_rust_analyzer.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+"""generate_rust_analyzer - Generates the `rust-project.json` file for `rust-analyzer`.
+"""
+
+import argparse
+import json
+import logging
+import pathlib
+import sys
+
+def generate_crates(srctree, objtree, sysroot_src):
+ # Generate the configuration list.
+ cfg = []
+ with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
+ for line in fd:
+ line = line.replace("--cfg=", "")
+ line = line.replace("\n", "")
+ cfg.append(line)
+
+ # Now fill the crates list -- dependencies need to come first.
+ #
+ # Avoid O(n^2) iterations by keeping a map of indexes.
+ crates = []
+ crates_indexes = {}
+
+ def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False):
+ crates_indexes[display_name] = len(crates)
+ crates.append({
+ "display_name": display_name,
+ "root_module": str(root_module),
+ "is_workspace_member": is_workspace_member,
+ "is_proc_macro": is_proc_macro,
+ "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps],
+ "cfg": cfg,
+ "edition": "2021",
+ "env": {
+ "RUST_MODFILE": "This is only for rust-analyzer"
+ }
+ })
+
+ # First, the ones in `rust/` since they are a bit special.
+ append_crate(
+ "core",
+ sysroot_src / "core" / "src" / "lib.rs",
+ [],
+ is_workspace_member=False,
+ )
+
+ append_crate(
+ "compiler_builtins",
+ srctree / "rust" / "compiler_builtins.rs",
+ [],
+ )
+
+ append_crate(
+ "alloc",
+ srctree / "rust" / "alloc" / "lib.rs",
+ ["core", "compiler_builtins"],
+ )
+
+ append_crate(
+ "macros",
+ srctree / "rust" / "macros" / "lib.rs",
+ [],
+ is_proc_macro=True,
+ )
+ crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so"
+
+ append_crate(
+ "build_error",
+ srctree / "rust" / "build_error.rs",
+ ["core", "compiler_builtins"],
+ )
+
+ append_crate(
+ "bindings",
+ srctree / "rust"/ "bindings" / "lib.rs",
+ ["core"],
+ cfg=cfg,
+ )
+ crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
+
+ append_crate(
+ "kernel",
+ srctree / "rust" / "kernel" / "lib.rs",
+ ["core", "alloc", "macros", "build_error", "bindings"],
+ cfg=cfg,
+ )
+ crates[-1]["source"] = {
+ "include_dirs": [
+ str(srctree / "rust" / "kernel"),
+ str(objtree / "rust")
+ ],
+ "exclude_dirs": [],
+ }
+
+ # Then, the rest outside of `rust/`.
+ #
+ # We explicitly mention the top-level folders we want to cover.
+ for folder in ("samples", "drivers"):
+ for path in (srctree / folder).rglob("*.rs"):
+ logging.info("Checking %s", path)
+ name = path.name.replace(".rs", "")
+
+ # Skip those that are not crate roots.
+ try:
+ if f"{name}.o" not in open(path.parent / "Makefile").read():
+ continue
+ except FileNotFoundError:
+ continue
+
+ logging.info("Adding %s", name)
+ append_crate(
+ name,
+ path,
+ ["core", "alloc", "kernel"],
+ cfg=cfg,
+ )
+
+ return crates
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--verbose', '-v', action='store_true')
+ parser.add_argument("srctree", type=pathlib.Path)
+ parser.add_argument("objtree", type=pathlib.Path)
+ parser.add_argument("sysroot_src", type=pathlib.Path)
+ args = parser.parse_args()
+
+ logging.basicConfig(
+ format="[%(asctime)s] [%(levelname)s] %(message)s",
+ level=logging.INFO if args.verbose else logging.WARNING
+ )
+
+ rust_project = {
+ "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src),
+ "sysroot_src": str(args.sysroot_src),
+ }
+
+ json.dump(rust_project, sys.stdout, sort_keys=True, indent=4)
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs
new file mode 100644
index 000000000000..3c6cbe2b278d
--- /dev/null
+++ b/scripts/generate_rust_target.rs
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! The custom target specification file generator for `rustc`.
+//!
+//! To configure a target from scratch, a JSON-encoded file has to be passed
+//! to `rustc` (introduced in [RFC 131]). These options and the file itself are
+//! unstable. Eventually, `rustc` should provide a way to do this in a stable
+//! manner. For instance, via command-line arguments. Therefore, this file
+//! should avoid using keys which can be set via `-C` or `-Z` options.
+//!
+//! [RFC 131]: https://rust-lang.github.io/rfcs/0131-target-specification.html
+
+use std::{
+ collections::HashMap,
+ fmt::{Display, Formatter, Result},
+ io::BufRead,
+};
+
+enum Value {
+ Boolean(bool),
+ Number(i32),
+ String(String),
+ Object(Object),
+}
+
+type Object = Vec<(String, Value)>;
+
+/// Minimal "almost JSON" generator (e.g. no `null`s, no arrays, no escaping),
+/// enough for this purpose.
+impl Display for Value {
+ fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
+ match self {
+ Value::Boolean(boolean) => write!(formatter, "{}", boolean),
+ Value::Number(number) => write!(formatter, "{}", number),
+ Value::String(string) => write!(formatter, "\"{}\"", string),
+ Value::Object(object) => {
+ formatter.write_str("{")?;
+ if let [ref rest @ .., ref last] = object[..] {
+ for (key, value) in rest {
+ write!(formatter, "\"{}\": {},", key, value)?;
+ }
+ write!(formatter, "\"{}\": {}", last.0, last.1)?;
+ }
+ formatter.write_str("}")
+ }
+ }
+ }
+}
+
+struct TargetSpec(Object);
+
+impl TargetSpec {
+ fn new() -> TargetSpec {
+ TargetSpec(Vec::new())
+ }
+}
+
+trait Push<T> {
+ fn push(&mut self, key: &str, value: T);
+}
+
+impl Push<bool> for TargetSpec {
+ fn push(&mut self, key: &str, value: bool) {
+ self.0.push((key.to_string(), Value::Boolean(value)));
+ }
+}
+
+impl Push<i32> for TargetSpec {
+ fn push(&mut self, key: &str, value: i32) {
+ self.0.push((key.to_string(), Value::Number(value)));
+ }
+}
+
+impl Push<String> for TargetSpec {
+ fn push(&mut self, key: &str, value: String) {
+ self.0.push((key.to_string(), Value::String(value)));
+ }
+}
+
+impl Push<&str> for TargetSpec {
+ fn push(&mut self, key: &str, value: &str) {
+ self.push(key, value.to_string());
+ }
+}
+
+impl Push<Object> for TargetSpec {
+ fn push(&mut self, key: &str, value: Object) {
+ self.0.push((key.to_string(), Value::Object(value)));
+ }
+}
+
+impl Display for TargetSpec {
+ fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
+ // We add some newlines for clarity.
+ formatter.write_str("{\n")?;
+ if let [ref rest @ .., ref last] = self.0[..] {
+ for (key, value) in rest {
+ write!(formatter, " \"{}\": {},\n", key, value)?;
+ }
+ write!(formatter, " \"{}\": {}\n", last.0, last.1)?;
+ }
+ formatter.write_str("}")
+ }
+}
+
+struct KernelConfig(HashMap<String, String>);
+
+impl KernelConfig {
+ /// Parses `include/config/auto.conf` from `stdin`.
+ fn from_stdin() -> KernelConfig {
+ let mut result = HashMap::new();
+
+ let stdin = std::io::stdin();
+ let mut handle = stdin.lock();
+ let mut line = String::new();
+
+ loop {
+ line.clear();
+
+ if handle.read_line(&mut line).unwrap() == 0 {
+ break;
+ }
+
+ if line.starts_with('#') {
+ continue;
+ }
+
+ let (key, value) = line.split_once('=').expect("Missing `=` in line.");
+ result.insert(key.to_string(), value.trim_end_matches('\n').to_string());
+ }
+
+ KernelConfig(result)
+ }
+
+ /// Does the option exist in the configuration (any value)?
+ ///
+ /// The argument must be passed without the `CONFIG_` prefix.
+ /// This avoids repetition and it also avoids `fixdep` making us
+ /// depend on it.
+ fn has(&self, option: &str) -> bool {
+ let option = "CONFIG_".to_owned() + option;
+ self.0.contains_key(&option)
+ }
+}
+
+fn main() {
+ let cfg = KernelConfig::from_stdin();
+ let mut ts = TargetSpec::new();
+
+ // `llvm-target`s are taken from `scripts/Makefile.clang`.
+ if cfg.has("X86_64") {
+ ts.push("arch", "x86_64");
+ ts.push(
+ "data-layout",
+ "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
+ );
+ let mut features = "-3dnow,-3dnowa,-mmx,+soft-float".to_string();
+ if cfg.has("RETPOLINE") {
+ features += ",+retpoline-external-thunk";
+ }
+ ts.push("features", features);
+ ts.push("llvm-target", "x86_64-linux-gnu");
+ ts.push("target-pointer-width", "64");
+ } else {
+ panic!("Unsupported architecture");
+ }
+
+ ts.push("emit-debug-gdb-scripts", false);
+ ts.push("frame-pointer", "may-omit");
+ ts.push(
+ "stack-probes",
+ vec![("kind".to_string(), Value::String("none".to_string()))],
+ );
+
+ // Everything else is LE, whether `CPU_LITTLE_ENDIAN` is declared or not
+ // (e.g. x86). It is also `rustc`'s default.
+ if cfg.has("CPU_BIG_ENDIAN") {
+ ts.push("target-endian", "big");
+ }
+
+ println!("{}", ts);
+}
diff --git a/scripts/genksyms/.gitignore b/scripts/genksyms/.gitignore
index 999af710f83d..0b275abf9405 100644
--- a/scripts/genksyms/.gitignore
+++ b/scripts/genksyms/.gitignore
@@ -1,2 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-genksyms
+/genksyms
diff --git a/scripts/genksyms/Makefile b/scripts/genksyms/Makefile
index ce4f99935de5..d6a422a63b6a 100644
--- a/scripts/genksyms/Makefile
+++ b/scripts/genksyms/Makefile
@@ -22,7 +22,7 @@ $(obj)/pars%.tab.c $(obj)/pars%.tab.h: $(src)/pars%.y FORCE
endif
-# -I needed for generated C source (shipped source)
+# -I needed for generated C source to include headers in source tree
HOSTCFLAGS_parse.tab.o := -I $(srctree)/$(src)
HOSTCFLAGS_lex.lex.o := -I $(srctree)/$(src)
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index 4827c5abe5b7..f5dfdb9d80e9 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -33,7 +33,7 @@ char *cur_filename;
int in_source_file;
static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
- flag_preserve, flag_warnings, flag_rel_crcs;
+ flag_preserve, flag_warnings;
static int errors;
static int nsyms;
@@ -680,11 +680,7 @@ void export_symbol(const char *name)
if (flag_dump_defs)
fputs(">\n", debugfile);
- /* Used as a linker script. */
- printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" :
- "SECTIONS { .rodata : ALIGN(4) { "
- "__crc_%s = .; LONG(0x%08lx); } }\n",
- name, crc);
+ printf("#SYMVER %s 0x%08lx\n", name, crc);
}
}
@@ -733,7 +729,6 @@ static void genksyms_usage(void)
" -q, --quiet Disable warnings (default)\n"
" -h, --help Print this message\n"
" -V, --version Print the release version\n"
- " -R, --relative-crc Emit section relative symbol CRCs\n"
#else /* __GNU_LIBRARY__ */
" -s Select symbol prefix\n"
" -d Increment the debug level (repeatable)\n"
@@ -745,7 +740,6 @@ static void genksyms_usage(void)
" -q Disable warnings (default)\n"
" -h Print this message\n"
" -V Print the release version\n"
- " -R Emit section relative symbol CRCs\n"
#endif /* __GNU_LIBRARY__ */
, stderr);
}
@@ -766,14 +760,13 @@ int main(int argc, char **argv)
{"preserve", 0, 0, 'p'},
{"version", 0, 0, 'V'},
{"help", 0, 0, 'h'},
- {"relative-crc", 0, 0, 'R'},
{0, 0, 0, 0}
};
- while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
+ while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
&long_opts[0], NULL)) != EOF)
#else /* __GNU_LIBRARY__ */
- while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
+ while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
#endif /* __GNU_LIBRARY__ */
switch (o) {
case 'd':
@@ -813,9 +806,6 @@ int main(int argc, char **argv)
case 'h':
genksyms_usage();
return 0;
- case 'R':
- flag_rel_crcs = 1;
- break;
default:
genksyms_usage();
return 1;
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
index 92d9aa6cc4f5..0ffd5531242a 100755
--- a/scripts/get_abi.pl
+++ b/scripts/get_abi.pl
@@ -1,19 +1,37 @@
#!/usr/bin/env perl
# SPDX-License-Identifier: GPL-2.0
+BEGIN { $Pod::Usage::Formatter = 'Pod::Text::Termcap'; }
+
use strict;
use warnings;
use utf8;
-use Pod::Usage;
+use Pod::Usage qw(pod2usage);
use Getopt::Long;
use File::Find;
+use IO::Handle;
use Fcntl ':mode';
+use Cwd 'abs_path';
+use Data::Dumper;
my $help = 0;
+my $hint = 0;
my $man = 0;
my $debug = 0;
my $enable_lineno = 0;
+my $show_warnings = 1;
my $prefix="Documentation/ABI";
+my $sysfs_prefix="/sys";
+my $search_string;
+
+# Debug options
+my $dbg_what_parsing = 1;
+my $dbg_what_open = 2;
+my $dbg_dump_abi_structs = 4;
+my $dbg_undefined = 8;
+
+$Data::Dumper::Indent = 1;
+$Data::Dumper::Terse = 1;
#
# If true, assumes that the description is formatted with ReST
@@ -21,25 +39,27 @@ my $prefix="Documentation/ABI";
my $description_is_rst = 1;
GetOptions(
- "debug|d+" => \$debug,
+ "debug=i" => \$debug,
"enable-lineno" => \$enable_lineno,
"rst-source!" => \$description_is_rst,
"dir=s" => \$prefix,
'help|?' => \$help,
+ "show-hints" => \$hint,
+ "search-string=s" => \$search_string,
man => \$man
) or pod2usage(2);
pod2usage(1) if $help;
-pod2usage(-exitstatus => 0, -verbose => 2) if $man;
+pod2usage(-exitstatus => 0, -noperldoc, -verbose => 2) if $man;
pod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2);
my ($cmd, $arg) = @ARGV;
-pod2usage(2) if ($cmd ne "search" && $cmd ne "rest" && $cmd ne "validate");
+pod2usage(2) if ($cmd ne "search" && $cmd ne "rest" && $cmd ne "validate" && $cmd ne "undefined");
pod2usage(2) if ($cmd eq "search" && !$arg);
-require Data::Dumper if ($debug);
+require Data::Dumper if ($debug & $dbg_dump_abi_structs);
my %data;
my %symbols;
@@ -50,6 +70,8 @@ my %symbols;
sub parse_error($$$$) {
my ($file, $ln, $msg, $data) = @_;
+ return if (!$show_warnings);
+
$data =~ s/\s+$/\n/;
print STDERR "Warning: file $file#$ln:\n\t$msg";
@@ -70,6 +92,7 @@ sub parse_abi {
my $mode = (stat($file))[2];
return if ($mode & S_IFDIR);
return if ($file =~ m,/README,);
+ return if ($file =~ m,/\.,);
my $name = $file;
$name =~ s,.*/,,;
@@ -97,7 +120,7 @@ sub parse_abi {
my @labels;
my $label = "";
- print STDERR "Opening $file\n" if ($debug > 1);
+ print STDERR "Opening $file\n" if ($debug & $dbg_what_open);
open IN, $file;
while(<IN>) {
$ln++;
@@ -129,12 +152,12 @@ sub parse_abi {
push @{$symbols{$content}->{file}}, " $file:" . ($ln - 1);
if ($tag =~ m/what/) {
- $what .= ", " . $content;
+ $what .= "\xac" . $content;
} else {
if ($what) {
parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
- foreach my $w(split /, /, $what) {
+ foreach my $w(split /\xac/, $what) {
$symbols{$w}->{xref} = $what;
};
}
@@ -164,12 +187,13 @@ sub parse_abi {
$data{$what}->{file} = $name;
$data{$what}->{filepath} = $file;
} else {
+ $data{$what}->{description} .= "\n\n" if (defined($data{$what}->{description}));
if ($name ne $data{$what}->{file}) {
$data{$what}->{file} .= " " . $name;
$data{$what}->{filepath} .= " " . $file;
}
}
- print STDERR "\twhat: $what\n" if ($debug > 1);
+ print STDERR "\twhat: $what\n" if ($debug & $dbg_what_parsing);
$data{$what}->{line_no} = $ln;
} else {
$data{$what}->{line_no} = $ln if (!defined($data{$what}->{line_no}));
@@ -239,7 +263,7 @@ sub parse_abi {
if ($what) {
parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
- foreach my $w(split /, /,$what) {
+ foreach my $w(split /\xac/,$what) {
$symbols{$w}->{xref} = $what;
};
}
@@ -281,8 +305,12 @@ sub create_labels {
# Outputs the book on ReST format
#
-# \b doesn't work well with paths. So, we need to define something else
-my $bondary = qr { (?<![\w\/\`\{])(?=[\w\/\`\{])|(?<=[\w\/\`\{])(?![\w\/\`\{]) }x;
+# \b doesn't work well with paths. So, we need to define something else:
+# Boundaries are punct characters, spaces and end-of-line
+my $start = qr {(^|\s|\() }x;
+my $bondary = qr { ([,.:;\)\s]|\z) }x;
+my $xref_match = qr { $start(\/(sys|config|proc|dev|kvd)\/[^,.:;\)\s]+)$bondary }x;
+my $symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x2f\x3a-\x40\x7b-\xff]) }x;
sub output_rest {
create_labels();
@@ -299,13 +327,12 @@ sub output_rest {
my @filepath = split / /, $data{$what}->{filepath};
if ($enable_lineno) {
- printf "#define LINENO %s%s#%s\n\n",
+ printf ".. LINENO %s%s#%s\n\n",
$prefix, $file[0],
$data{$what}->{line_no};
}
my $w = $what;
- $w =~ s/([\(\)\_\-\*\=\^\~\\])/\\$1/g;
if ($type ne "File") {
my $cur_part = $what;
@@ -325,10 +352,11 @@ sub output_rest {
printf ".. _%s:\n\n", $data{$what}->{label};
- my @names = split /, /,$w;
+ my @names = split /\xac/,$w;
my $len = 0;
foreach my $name (@names) {
+ $name =~ s/$symbols/\\$1/g;
$name = "**$name**";
$len = length($name) if (length($name) > $len);
}
@@ -377,32 +405,60 @@ sub output_rest {
# Enrich text by creating cross-references
- $desc =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g;
+ my $new_desc = "";
+ my $init_indent = -1;
+ my $literal_indent = -1;
+
+ open(my $fh, "+<", \$desc);
+ while (my $d = <$fh>) {
+ my $indent = $d =~ m/^(\s+)/;
+ my $spaces = length($indent);
+ $init_indent = $indent if ($init_indent < 0);
+ if ($literal_indent >= 0) {
+ if ($spaces > $literal_indent) {
+ $new_desc .= $d;
+ next;
+ } else {
+ $literal_indent = -1;
+ }
+ } else {
+ if ($d =~ /()::$/ && !($d =~ /^\s*\.\./)) {
+ $literal_indent = $spaces;
+ }
+ }
- my @matches = $desc =~ m,Documentation/ABI/([\w\/\-]+),;
- foreach my $f (@matches) {
- my $xref = $f;
- my $path = $f;
- $path =~ s,.*/(.*/.*),$1,;;
- $path =~ s,[/\-],_,g;;
- $xref .= " <abi_file_" . $path . ">";
- $desc =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g;
- }
+ $d =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g;
- @matches = $desc =~ m,$bondary(/sys/[^\s\.\,\;\:\*\s\`\'\(\)]+)$bondary,;
+ my @matches = $d =~ m,Documentation/ABI/([\w\/\-]+),g;
+ foreach my $f (@matches) {
+ my $xref = $f;
+ my $path = $f;
+ $path =~ s,.*/(.*/.*),$1,;;
+ $path =~ s,[/\-],_,g;;
+ $xref .= " <abi_file_" . $path . ">";
+ $d =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g;
+ }
- foreach my $s (@matches) {
- if (defined($data{$s}) && defined($data{$s}->{label})) {
- my $xref = $s;
+ # Seek for cross reference symbols like /sys/...
+ @matches = $d =~ m/$xref_match/g;
- $xref =~ s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g;
- $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`";
+ foreach my $s (@matches) {
+ next if (!($s =~ m,/,));
+ if (defined($data{$s}) && defined($data{$s}->{label})) {
+ my $xref = $s;
- $desc =~ s,$bondary$s$bondary,$xref,g;
+ $xref =~ s/$symbols/\\$1/g;
+ $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`";
+
+ $d =~ s,$start$s$bondary,$1$xref$2,g;
+ }
}
+ $new_desc .= $d;
}
+ close $fh;
+
- print "$desc\n\n";
+ print "$new_desc\n\n";
} else {
$desc =~ s/^\s+//;
@@ -460,6 +516,7 @@ sub search_symbols {
my $file = $data{$what}->{filepath};
+ $what =~ s/\xac/, /g;
my $bar = $what;
$bar =~ s/./-/g;
@@ -489,22 +546,420 @@ sub search_symbols {
}
}
+# Exclude /sys/kernel/debug and /sys/kernel/tracing from the search path
+sub dont_parse_special_attributes {
+ if (($File::Find::dir =~ m,^/sys/kernel,)) {
+ return grep {!/(debug|tracing)/ } @_;
+ }
+
+ if (($File::Find::dir =~ m,^/sys/fs,)) {
+ return grep {!/(pstore|bpf|fuse)/ } @_;
+ }
+
+ return @_
+}
+
+my %leaf;
+my %aliases;
+my @files;
+my %root;
+
+sub graph_add_file {
+ my $file = shift;
+ my $type = shift;
+
+ my $dir = $file;
+ $dir =~ s,^(.*/).*,$1,;
+ $file =~ s,.*/,,;
+
+ my $name;
+ my $file_ref = \%root;
+ foreach my $edge(split "/", $dir) {
+ $name .= "$edge/";
+ if (!defined ${$file_ref}{$edge}) {
+ ${$file_ref}{$edge} = { };
+ }
+ $file_ref = \%{$$file_ref{$edge}};
+ ${$file_ref}{"__name"} = [ $name ];
+ }
+ $name .= "$file";
+ ${$file_ref}{$file} = {
+ "__name" => [ $name ]
+ };
+
+ return \%{$$file_ref{$file}};
+}
+
+sub graph_add_link {
+ my $file = shift;
+ my $link = shift;
+
+ # Traverse graph to find the reference
+ my $file_ref = \%root;
+ foreach my $edge(split "/", $file) {
+ $file_ref = \%{$$file_ref{$edge}} || die "Missing node!";
+ }
+
+ # do a BFS
+
+ my @queue;
+ my %seen;
+ my $st;
+
+ push @queue, $file_ref;
+ $seen{$start}++;
+
+ while (@queue) {
+ my $v = shift @queue;
+ my @child = keys(%{$v});
+
+ foreach my $c(@child) {
+ next if $seen{$$v{$c}};
+ next if ($c eq "__name");
+
+ if (!defined($$v{$c}{"__name"})) {
+ printf STDERR "Error: Couldn't find a non-empty name on a children of $file/.*: ";
+ print STDERR Dumper(%{$v});
+ exit;
+ }
+
+ # Add new name
+ my $name = @{$$v{$c}{"__name"}}[0];
+ if ($name =~ s#^$file/#$link/#) {
+ push @{$$v{$c}{"__name"}}, $name;
+ }
+ # Add child to the queue and mark as seen
+ push @queue, $$v{$c};
+ $seen{$c}++;
+ }
+ }
+}
+
+my $escape_symbols = qr { ([\x01-\x08\x0e-\x1f\x21-\x29\x2b-\x2d\x3a-\x40\x7b-\xfe]) }x;
+sub parse_existing_sysfs {
+ my $file = $File::Find::name;
+
+ my $mode = (lstat($file))[2];
+ my $abs_file = abs_path($file);
+
+ my @tmp;
+ push @tmp, $file;
+ push @tmp, $abs_file if ($abs_file ne $file);
+
+ foreach my $f(@tmp) {
+ # Ignore cgroup, as this is big and has zero docs under ABI
+ return if ($f =~ m#^/sys/fs/cgroup/#);
+
+ # Ignore firmware as it is documented elsewhere
+ # Either ACPI or under Documentation/devicetree/bindings/
+ return if ($f =~ m#^/sys/firmware/#);
+
+ # Ignore some sysfs nodes that aren't actually part of ABI
+ return if ($f =~ m#/sections|notes/#);
+
+ # Would need to check at
+ # Documentation/admin-guide/kernel-parameters.txt, but this
+ # is not easily parseable.
+ return if ($f =~ m#/parameters/#);
+ }
+
+ if (S_ISLNK($mode)) {
+ $aliases{$file} = $abs_file;
+ return;
+ }
+
+ return if (S_ISDIR($mode));
+
+ # Trivial: file is defined exactly the same way at ABI What:
+ return if (defined($data{$file}));
+ return if (defined($data{$abs_file}));
+
+ push @files, graph_add_file($abs_file, "file");
+}
+
+sub get_leave($)
+{
+ my $what = shift;
+ my $leave;
+
+ my $l = $what;
+ my $stop = 1;
+
+ $leave = $l;
+ $leave =~ s,/$,,;
+ $leave =~ s,.*/,,;
+ $leave =~ s/[\(\)]//g;
+
+ # $leave is used to improve search performance at
+ # check_undefined_symbols, as the algorithm there can seek
+ # for a small number of "what". It also allows giving a
+ # hint about a leave with the same name somewhere else.
+ # However, there are a few occurences where the leave is
+ # either a wildcard or a number. Just group such cases
+ # altogether.
+ if ($leave =~ m/\.\*/ || $leave eq "" || $leave =~ /\\d/) {
+ $leave = "others";
+ }
+
+ return $leave;
+}
+
+my @not_found;
+
+sub check_file($$)
+{
+ my $file_ref = shift;
+ my $names_ref = shift;
+ my @names = @{$names_ref};
+ my $file = $names[0];
+
+ my $found_string;
+
+ my $leave = get_leave($file);
+ if (!defined($leaf{$leave})) {
+ $leave = "others";
+ }
+ my @expr = @{$leaf{$leave}->{expr}};
+ die ("\rmissing rules for $leave") if (!defined($leaf{$leave}));
+
+ my $path = $file;
+ $path =~ s,(.*/).*,$1,;
+
+ if ($search_string) {
+ return if (!($file =~ m#$search_string#));
+ $found_string = 1;
+ }
+
+ for (my $i = 0; $i < @names; $i++) {
+ if ($found_string && $hint) {
+ if (!$i) {
+ print STDERR "--> $names[$i]\n";
+ } else {
+ print STDERR " $names[$i]\n";
+ }
+ }
+ foreach my $re (@expr) {
+ print STDERR "$names[$i] =~ /^$re\$/\n" if ($debug && $dbg_undefined);
+ if ($names[$i] =~ $re) {
+ return;
+ }
+ }
+ }
+
+ if ($leave ne "others") {
+ my @expr = @{$leaf{"others"}->{expr}};
+ for (my $i = 0; $i < @names; $i++) {
+ foreach my $re (@expr) {
+ print STDERR "$names[$i] =~ /^$re\$/\n" if ($debug && $dbg_undefined);
+ if ($names[$i] =~ $re) {
+ return;
+ }
+ }
+ }
+ }
+
+ push @not_found, $file if (!$search_string || $found_string);
+
+ if ($hint && (!$search_string || $found_string)) {
+ my $what = $leaf{$leave}->{what};
+ $what =~ s/\xac/\n\t/g;
+ if ($leave ne "others") {
+ print STDERR "\r more likely regexes:\n\t$what\n";
+ } else {
+ print STDERR "\r tested regexes:\n\t$what\n";
+ }
+ }
+}
+
+sub check_undefined_symbols {
+ my $num_files = scalar @files;
+ my $next_i = 0;
+ my $start_time = times;
+
+ @files = sort @files;
+
+ my $last_time = $start_time;
+
+ # When either debug or hint is enabled, there's no sense showing
+ # progress, as the progress will be overriden.
+ if ($hint || ($debug && $dbg_undefined)) {
+ $next_i = $num_files;
+ }
+
+ my $is_console;
+ $is_console = 1 if (-t STDERR);
+
+ for (my $i = 0; $i < $num_files; $i++) {
+ my $file_ref = $files[$i];
+ my @names = @{$$file_ref{"__name"}};
+
+ check_file($file_ref, \@names);
+
+ my $cur_time = times;
+
+ if ($i == $next_i || $cur_time > $last_time + 1) {
+ my $percent = $i * 100 / $num_files;
+
+ my $tm = $cur_time - $start_time;
+ my $time = sprintf "%d:%02d", int($tm), 60 * ($tm - int($tm));
+
+ printf STDERR "\33[2K\r", if ($is_console);
+ printf STDERR "%s: processing sysfs files... %i%%: $names[0]", $time, $percent;
+ printf STDERR "\n", if (!$is_console);
+ STDERR->flush();
+
+ $next_i = int (($percent + 1) * $num_files / 100);
+ $last_time = $cur_time;
+ }
+ }
+
+ my $cur_time = times;
+ my $tm = $cur_time - $start_time;
+ my $time = sprintf "%d:%02d", int($tm), 60 * ($tm - int($tm));
+
+ printf STDERR "\33[2K\r", if ($is_console);
+ printf STDERR "%s: processing sysfs files... done\n", $time;
+
+ foreach my $file (@not_found) {
+ print "$file not found.\n";
+ }
+}
+
+sub undefined_symbols {
+ print STDERR "Reading $sysfs_prefix directory contents...";
+ find({
+ wanted =>\&parse_existing_sysfs,
+ preprocess =>\&dont_parse_special_attributes,
+ no_chdir => 1
+ }, $sysfs_prefix);
+ print STDERR "done.\n";
+
+ $leaf{"others"}->{what} = "";
+
+ print STDERR "Converting ABI What fields into regexes...";
+ foreach my $w (sort keys %data) {
+ foreach my $what (split /\xac/,$w) {
+ next if (!($what =~ m/^$sysfs_prefix/));
+
+ # Convert what into regular expressions
+
+ # Escape dot characters
+ $what =~ s/\./\xf6/g;
+
+ # Temporarily change [0-9]+ type of patterns
+ $what =~ s/\[0\-9\]\+/\xff/g;
+
+ # Temporarily change [\d+-\d+] type of patterns
+ $what =~ s/\[0\-\d+\]/\xff/g;
+ $what =~ s/\[(\d+)\]/\xf4$1\xf5/g;
+
+ # Temporarily change [0-9] type of patterns
+ $what =~ s/\[(\d)\-(\d)\]/\xf4$1-$2\xf5/g;
+
+ # Handle multiple option patterns
+ $what =~ s/[\{\<\[]([\w_]+)(?:[,|]+([\w_]+)){1,}[\}\>\]]/($1|$2)/g;
+
+ # Handle wildcards
+ $what =~ s,\*,.*,g;
+ $what =~ s,/\xf6..,/.*,g;
+ $what =~ s/\<[^\>]+\>/.*/g;
+ $what =~ s/\{[^\}]+\}/.*/g;
+ $what =~ s/\[[^\]]+\]/.*/g;
+
+ $what =~ s/[XYZ]/.*/g;
+
+ # Recover [0-9] type of patterns
+ $what =~ s/\xf4/[/g;
+ $what =~ s/\xf5/]/g;
+
+ # Remove duplicated spaces
+ $what =~ s/\s+/ /g;
+
+ # Special case: this ABI has a parenthesis on it
+ $what =~ s/sqrt\(x^2\+y^2\+z^2\)/sqrt\(x^2\+y^2\+z^2\)/;
+
+ # Special case: drop comparition as in:
+ # What: foo = <something>
+ # (this happens on a few IIO definitions)
+ $what =~ s,\s*\=.*$,,;
+
+ # Escape all other symbols
+ $what =~ s/$escape_symbols/\\$1/g;
+ $what =~ s/\\\\/\\/g;
+ $what =~ s/\\([\[\]\(\)\|])/$1/g;
+ $what =~ s/(\d+)\\(-\d+)/$1$2/g;
+
+ $what =~ s/\xff/\\d+/g;
+
+ # Special case: IIO ABI which a parenthesis.
+ $what =~ s/sqrt(.*)/sqrt\(.*\)/;
+
+ # Simplify regexes with multiple .*
+ $what =~ s#(?:\.\*){2,}##g;
+# $what =~ s#\.\*/\.\*#.*#g;
+
+ # Recover dot characters
+ $what =~ s/\xf6/\./g;
+
+ my $leave = get_leave($what);
+
+ my $added = 0;
+ foreach my $l (split /\|/, $leave) {
+ if (defined($leaf{$l})) {
+ next if ($leaf{$l}->{what} =~ m/\b$what\b/);
+ $leaf{$l}->{what} .= "\xac" . $what;
+ $added = 1;
+ } else {
+ $leaf{$l}->{what} = $what;
+ $added = 1;
+ }
+ }
+ if ($search_string && $added) {
+ print STDERR "What: $what\n" if ($what =~ m#$search_string#);
+ }
+
+ }
+ }
+ # Compile regexes
+ foreach my $l (sort keys %leaf) {
+ my @expr;
+ foreach my $w(sort split /\xac/, $leaf{$l}->{what}) {
+ push @expr, qr /^$w$/;
+ }
+ $leaf{$l}->{expr} = \@expr;
+ }
+
+ # Take links into account
+ foreach my $link (sort keys %aliases) {
+ my $abs_file = $aliases{$link};
+ graph_add_link($abs_file, $link);
+ }
+ print STDERR "done.\n";
+
+ check_undefined_symbols;
+}
+
# Ensure that the prefix will always end with a slash
# While this is not needed for find, it makes the patch nicer
# with --enable-lineno
$prefix =~ s,/?$,/,;
+if ($cmd eq "undefined" || $cmd eq "search") {
+ $show_warnings = 0;
+}
#
# Parses all ABI files located at $prefix dir
#
find({wanted =>\&parse_abi, no_chdir => 1}, $prefix);
-print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
+print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug & $dbg_dump_abi_structs);
#
# Handles the command
#
-if ($cmd eq "search") {
+if ($cmd eq "undefined") {
+ undefined_symbols;
+} elsif ($cmd eq "search") {
search_symbols;
} else {
if ($cmd eq "rest") {
@@ -526,22 +981,27 @@ __END__
=head1 NAME
-abi_book.pl - parse the Linux ABI files and produce a ReST book.
+get_abi.pl - parse the Linux ABI files and produce a ReST book.
=head1 SYNOPSIS
-B<abi_book.pl> [--debug] [--enable-lineno] [--man] [--help]
- [--(no-)rst-source] [--dir=<dir>] <COMAND> [<ARGUMENT>]
+B<get_abi.pl> [--debug <level>] [--enable-lineno] [--man] [--help]
+ [--(no-)rst-source] [--dir=<dir>] [--show-hints]
+ [--search-string <regex>]
+ <COMMAND> [<ARGUMENT>]
-Where <COMMAND> can be:
+Where B<COMMAND> can be:
=over 8
-B<search> [SEARCH_REGEX] - search for [SEARCH_REGEX] inside ABI
+B<search> I<SEARCH_REGEX> - search for I<SEARCH_REGEX> inside ABI
-B<rest> - output the ABI in ReST markup language
+B<rest> - output the ABI in ReST markup language
-B<validate> - validate the ABI contents
+B<validate> - validate the ABI contents
+
+B<undefined> - existing symbols at the system that aren't
+ defined at Documentation/ABI
=back
@@ -557,18 +1017,32 @@ the Documentation/ABI directory.
=item B<--rst-source> and B<--no-rst-source>
The input file may be using ReST syntax or not. Those two options allow
-selecting between a rst-compliant source ABI (--rst-source), or a
+selecting between a rst-compliant source ABI (B<--rst-source>), or a
plain text that may be violating ReST spec, so it requres some escaping
-logic (--no-rst-source).
+logic (B<--no-rst-source>).
=item B<--enable-lineno>
-Enable output of #define LINENO lines.
+Enable output of .. LINENO lines.
+
+=item B<--debug> I<debug level>
+
+Print debug information according with the level, which is given by the
+following bitmask:
+
+ - 1: Debug parsing What entries from ABI files;
+ - 2: Shows what files are opened from ABI files;
+ - 4: Dump the structs used to store the contents of the ABI files.
+
+=item B<--show-hints>
+
+Show hints about possible definitions for the missing ABI symbols.
+Used only when B<undefined>.
-=item B<--debug>
+=item B<--search-string> I<regex string>
-Put the script in verbose mode, useful for debugging. Can be called multiple
-times, to increase verbosity.
+Show only occurences that match a search string.
+Used only when B<undefined>.
=item B<--help>
@@ -614,11 +1088,11 @@ $ scripts/get_abi.pl rest --dir Documentation/ABI/obsolete
=head1 BUGS
-Report bugs to Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+Report bugs to Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
=head1 COPYRIGHT
-Copyright (c) 2016-2019 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>.
+Copyright (c) 2016-2021 by Mauro Carvalho Chehab <mchehab+huawei@kernel.org>.
License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
diff --git a/scripts/get_feat.pl b/scripts/get_feat.pl
index 457712355676..5c5397eeb237 100755
--- a/scripts/get_feat.pl
+++ b/scripts/get_feat.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/env perl
# SPDX-License-Identifier: GPL-2.0
use strict;
@@ -13,6 +13,7 @@ my $man;
my $debug;
my $arch;
my $feat;
+my $enable_fname;
my $basename = abs_path($0);
$basename =~ s,/[^/]+$,/,;
@@ -31,6 +32,7 @@ GetOptions(
'arch=s' => \$arch,
'feat=s' => \$feat,
'feature=s' => \$feat,
+ "enable-fname" => \$enable_fname,
man => \$man
) or pod2usage(2);
@@ -95,6 +97,10 @@ sub parse_feat {
return if ($file =~ m,($prefix)/arch-support.txt,);
return if (!($file =~ m,arch-support.txt$,));
+ if ($enable_fname) {
+ printf ".. FILE %s\n", abs_path($file);
+ }
+
my $subsys = "";
$subsys = $2 if ( m,.*($prefix)/([^/]+).*,);
@@ -580,6 +586,11 @@ Output features for a single specific feature.
Changes the location of the Feature files. By default, it uses
the Documentation/features directory.
+=item B<--enable-fname>
+
+Prints the file name of the feature files. This can be used in order to
+track dependencies during documentation build.
+
=item B<--debug>
Put the script in verbose mode, useful for debugging. Can be called multiple
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index 2075db0c08b8..ab123b498fd9 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -983,6 +983,7 @@ sub get_maintainers {
}
foreach my $email (@file_emails) {
+ $email = mailmap_email($email);
my ($name, $address) = parse_email($email);
my $tmp_email = format_email($name, $address, $email_usename);
@@ -1718,7 +1719,7 @@ sub vcs_exists {
%VCS_cmds = %VCS_cmds_hg;
return 2 if eval $VCS_cmds{"available"};
%VCS_cmds = ();
- if (!$printed_novcs) {
+ if (!$printed_novcs && $email_git) {
warn("$P: No supported VCS found. Add --nogit to options?\n");
warn("Using a git repository produces better results.\n");
warn("Try Linus Torvalds' latest git repository using:\n");
diff --git a/scripts/gfp-translate b/scripts/gfp-translate
index b2ce416d944b..6c9aed17cf56 100755
--- a/scripts/gfp-translate
+++ b/scripts/gfp-translate
@@ -63,11 +63,11 @@ fi
# Extract GFP flags from the kernel source
TMPFILE=`mktemp -t gfptranslate-XXXXXX` || exit 1
-grep -q ___GFP $SOURCE/include/linux/gfp.h
+grep -q ___GFP $SOURCE/include/linux/gfp_types.h
if [ $? -eq 0 ]; then
- grep "^#define ___GFP" $SOURCE/include/linux/gfp.h | sed -e 's/u$//' | grep -v GFP_BITS > $TMPFILE
+ grep "^#define ___GFP" $SOURCE/include/linux/gfp_types.h | sed -e 's/u$//' | grep -v GFP_BITS > $TMPFILE
else
- grep "^#define __GFP" $SOURCE/include/linux/gfp.h | sed -e 's/(__force gfp_t)//' | sed -e 's/u)/)/' | grep -v GFP_BITS | sed -e 's/)\//) \//' > $TMPFILE
+ grep "^#define __GFP" $SOURCE/include/linux/gfp_types.h | sed -e 's/(__force gfp_t)//' | sed -e 's/u)/)/' | grep -v GFP_BITS | sed -e 's/)\//) \//' > $TMPFILE
fi
# Parse the flags
diff --git a/scripts/head-object-list.txt b/scripts/head-object-list.txt
new file mode 100644
index 000000000000..26359968744e
--- /dev/null
+++ b/scripts/head-object-list.txt
@@ -0,0 +1,45 @@
+# Head objects
+#
+# The objects listed here are placed at the head of vmlinux. A typical use-case
+# is an object that contains the entry point. This is kept for compatibility
+# with head-y, which Kbuild used to support.
+#
+# A counter approach is to control the section placement by the linker script.
+# The code marked as __HEAD goes into the ".head.text" section, which is placed
+# before the normal ".text" section.
+#
+# If you can achieve the correct code ordering by linker script, please delete
+# the entry from this file.
+#
+arch/alpha/kernel/head.o
+arch/arc/kernel/head.o
+arch/arm/kernel/head-nommu.o
+arch/arm/kernel/head.o
+arch/csky/kernel/head.o
+arch/hexagon/kernel/head.o
+arch/ia64/kernel/head.o
+arch/loongarch/kernel/head.o
+arch/m68k/68000/head.o
+arch/m68k/coldfire/head.o
+arch/m68k/kernel/head.o
+arch/m68k/kernel/sun3-head.o
+arch/microblaze/kernel/head.o
+arch/mips/kernel/head.o
+arch/nios2/kernel/head.o
+arch/openrisc/kernel/head.o
+arch/parisc/kernel/head.o
+arch/powerpc/kernel/head_40x.o
+arch/powerpc/kernel/head_44x.o
+arch/powerpc/kernel/head_64.o
+arch/powerpc/kernel/head_8xx.o
+arch/powerpc/kernel/head_85xx.o
+arch/powerpc/kernel/head_book3s_32.o
+arch/powerpc/kernel/prom_entry_64.o
+arch/powerpc/kernel/fpu.o
+arch/powerpc/kernel/vector.o
+arch/powerpc/kernel/prom_init.o
+arch/s390/kernel/head64.o
+arch/sh/kernel/head_32.o
+arch/sparc/kernel/head_32.o
+arch/sparc/kernel/head_64.o
+arch/xtensa/kernel/head.o
diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl
deleted file mode 100755
index b6aec5e4365f..000000000000
--- a/scripts/headers_check.pl
+++ /dev/null
@@ -1,171 +0,0 @@
-#!/usr/bin/env perl
-# SPDX-License-Identifier: GPL-2.0
-#
-# headers_check.pl execute a number of trivial consistency checks
-#
-# Usage: headers_check.pl dir arch [files...]
-# dir: dir to look for included files
-# arch: architecture
-# files: list of files to check
-#
-# The script reads the supplied files line by line and:
-#
-# 1) for each include statement it checks if the
-# included file actually exists.
-# Only include files located in asm* and linux* are checked.
-# The rest are assumed to be system include files.
-#
-# 2) It is checked that prototypes does not use "extern"
-#
-# 3) Check for leaked CONFIG_ symbols
-
-use warnings;
-use strict;
-use File::Basename;
-
-my ($dir, $arch, @files) = @ARGV;
-
-my $ret = 0;
-my $line;
-my $lineno = 0;
-my $filename;
-
-foreach my $file (@files) {
- $filename = $file;
-
- open(my $fh, '<', $filename)
- or die "$filename: $!\n";
- $lineno = 0;
- while ($line = <$fh>) {
- $lineno++;
- &check_include();
- &check_asm_types();
- &check_sizetypes();
- &check_declarations();
- # Dropped for now. Too much noise &check_config();
- }
- close $fh;
-}
-exit $ret;
-
-sub check_include
-{
- if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) {
- my $inc = $1;
- my $found;
- $found = stat($dir . "/" . $inc);
- if (!$found) {
- $inc =~ s#asm/#asm-$arch/#;
- $found = stat($dir . "/" . $inc);
- }
- if (!$found) {
- printf STDERR "$filename:$lineno: included file '$inc' is not exported\n";
- $ret = 1;
- }
- }
-}
-
-sub check_declarations
-{
- # soundcard.h is what it is
- if ($line =~ m/^void seqbuf_dump\(void\);/) {
- return;
- }
- # drm headers are being C++ friendly
- if ($line =~ m/^extern "C"/) {
- return;
- }
- if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) {
- printf STDERR "$filename:$lineno: " .
- "userspace cannot reference function or " .
- "variable defined in the kernel\n";
- }
-}
-
-sub check_config
-{
- if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) {
- printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n";
- }
-}
-
-my $linux_asm_types;
-sub check_asm_types
-{
- if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
- return;
- }
- if ($lineno == 1) {
- $linux_asm_types = 0;
- } elsif ($linux_asm_types >= 1) {
- return;
- }
- if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) {
- $linux_asm_types = 1;
- printf STDERR "$filename:$lineno: " .
- "include of <linux/types.h> is preferred over <asm/types.h>\n"
- # Warn until headers are all fixed
- #$ret = 1;
- }
-}
-
-my $linux_types;
-my %import_stack = ();
-sub check_include_typesh
-{
- my $path = $_[0];
- my $import_path;
-
- my $fh;
- my @file_paths = ($path, $dir . "/" . $path, dirname($filename) . "/" . $path);
- for my $possible ( @file_paths ) {
- if (not $import_stack{$possible} and open($fh, '<', $possible)) {
- $import_path = $possible;
- $import_stack{$import_path} = 1;
- last;
- }
- }
- if (eof $fh) {
- return;
- }
-
- my $line;
- while ($line = <$fh>) {
- if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
- $linux_types = 1;
- last;
- }
- if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
- check_include_typesh($included);
- }
- }
- close $fh;
- delete $import_stack{$import_path};
-}
-
-sub check_sizetypes
-{
- if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
- return;
- }
- if ($lineno == 1) {
- $linux_types = 0;
- } elsif ($linux_types >= 1) {
- return;
- }
- if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
- $linux_types = 1;
- return;
- }
- if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
- check_include_typesh($included);
- }
- if ($line =~ m/__[us](8|16|32|64)\b/) {
- printf STDERR "$filename:$lineno: " .
- "found __[us]{8,16,32,64} type " .
- "without #include <linux/types.h>\n";
- $linux_types = 2;
- # Warn until headers are all fixed
- #$ret = 1;
- }
-}
diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh
index dd554bd436cc..36b56b746fce 100755
--- a/scripts/headers_install.sh
+++ b/scripts/headers_install.sh
@@ -70,7 +70,6 @@ configs=$(sed -e '
#
# The format is <file-name>:<CONFIG-option> in each line.
config_leak_ignores="
-arch/alpha/include/uapi/asm/setup.h:CONFIG_ALPHA_LEGACY_START_ADDRESS
arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_16K
arch/arc/include/uapi/asm/page.h:CONFIG_ARC_PAGE_SIZE_4K
arch/arc/include/uapi/asm/swab.h:CONFIG_ARC_HAS_SWAPE
@@ -84,11 +83,6 @@ arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT
arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION
arch/x86/include/uapi/asm/auxvec.h:CONFIG_X86_64
arch/x86/include/uapi/asm/mman.h:CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
-include/uapi/asm-generic/fcntl.h:CONFIG_64BIT
-include/uapi/linux/atmdev.h:CONFIG_COMPAT
-include/uapi/linux/eventpoll.h:CONFIG_PM_SLEEP
-include/uapi/linux/hw_breakpoint.h:CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
-include/uapi/linux/pktcdvd.h:CONFIG_CDROM_PKTCDVD_WCACHE
"
for c in $configs
diff --git a/scripts/install.sh b/scripts/install.sh
new file mode 100755
index 000000000000..9bb0fb44f04a
--- /dev/null
+++ b/scripts/install.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+# Common code factored out by Masahiro Yamada
+
+set -e
+
+# Make sure the files actually exist
+for file in "${KBUILD_IMAGE}" System.map
+do
+ if [ ! -f "${file}" ]; then
+ echo >&2
+ echo >&2 " *** Missing file: ${file}"
+ echo >&2 ' *** You need to run "make" before "make install".'
+ echo >&2
+ exit 1
+ fi
+done
+
+# User/arch may have a custom install script
+for file in "${HOME}/bin/${INSTALLKERNEL}" \
+ "/sbin/${INSTALLKERNEL}" \
+ "${srctree}/arch/${SRCARCH}/install.sh" \
+ "${srctree}/arch/${SRCARCH}/boot/install.sh"
+do
+ if [ ! -x "${file}" ]; then
+ continue
+ fi
+
+ # installkernel(8) says the parameters are like follows:
+ #
+ # installkernel version zImage System.map [directory]
+ exec "${file}" "${KERNELRELEASE}" "${KBUILD_IMAGE}" System.map "${INSTALL_PATH}"
+done
+
+echo "No install script found" >&2
+exit 1
diff --git a/scripts/is_rust_module.sh b/scripts/is_rust_module.sh
new file mode 100755
index 000000000000..464761a7cf7f
--- /dev/null
+++ b/scripts/is_rust_module.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# is_rust_module.sh module.ko
+#
+# Returns `0` if `module.ko` is a Rust module, `1` otherwise.
+
+set -e
+
+# Using the `16_` prefix ensures other symbols with the same substring
+# are not picked up (even if it would be unlikely). The last part is
+# used just in case LLVM decides to use the `.` suffix.
+#
+# In the future, checking for the `.comment` section may be another
+# option, see https://github.com/rust-lang/rust/pull/97550.
+${NM} "$*" | grep -qE '^[0-9a-fA-F]+ [Rr] _R[^[:space:]]+16___IS_RUST_MODULE[^[:space:]]*$'
diff --git a/scripts/jobserver-exec b/scripts/jobserver-exec
index 48d141e3ec56..7eca035472d3 100755
--- a/scripts/jobserver-exec
+++ b/scripts/jobserver-exec
@@ -10,7 +10,7 @@ from __future__ import print_function
import os, sys, errno
import subprocess
-# Extract and prepare jobserver file descriptors from envirnoment.
+# Extract and prepare jobserver file descriptors from environment.
claim = 0
jobs = b""
try:
@@ -23,12 +23,23 @@ try:
opts = [x for x in flags.split(" ") if x.startswith("--jobserver")]
# Parse out R,W file descriptor numbers and set them nonblocking.
- fds = opts[0].split("=", 1)[1]
- reader, writer = [int(x) for x in fds.split(",", 1)]
- # Open a private copy of reader to avoid setting nonblocking
- # on an unexpecting process with the same reader fd.
- reader = os.open("/proc/self/fd/%d" % (reader),
- os.O_RDONLY | os.O_NONBLOCK)
+ # If the MAKEFLAGS variable contains multiple instances of the
+ # --jobserver-auth= option, the last one is relevant.
+ fds = opts[-1].split("=", 1)[1]
+
+ # Starting with GNU Make 4.4, named pipes are used for reader and writer.
+ # Example argument: --jobserver-auth=fifo:/tmp/GMfifo8134
+ _, _, path = fds.partition('fifo:')
+
+ if path:
+ reader = os.open(path, os.O_RDONLY | os.O_NONBLOCK)
+ writer = os.open(path, os.O_WRONLY)
+ else:
+ reader, writer = [int(x) for x in fds.split(",", 1)]
+ # Open a private copy of reader to avoid setting nonblocking
+ # on an unexpecting process with the same reader fd.
+ reader = os.open("/proc/self/fd/%d" % (reader),
+ os.O_RDONLY | os.O_NONBLOCK)
# Read out as many jobserver slots as possible.
while True:
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 54ad86d13784..653b92f6d4c8 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -5,7 +5,8 @@
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
- * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S
+ * Usage: kallsyms [--all-symbols] [--absolute-percpu]
+ * [--base-relative] [--lto-clang] in.map > out.S
*
* 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,6 +19,8 @@
*
*/
+#include <errno.h>
+#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -27,11 +30,12 @@
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
-#define KSYM_NAME_LEN 128
+#define KSYM_NAME_LEN 512
struct sym_entry {
unsigned long long addr;
unsigned int len;
+ unsigned int seq;
unsigned int start_pos;
unsigned int percpu_absolute;
unsigned char sym[];
@@ -60,6 +64,7 @@ static unsigned int table_size, table_cnt;
static int all_symbols;
static int absolute_percpu;
static int base_relative;
+static int lto_clang;
static int token_profit[0x10000];
@@ -70,8 +75,8 @@ static unsigned char best_table_len[256];
static void usage(void)
{
- fprintf(stderr, "Usage: kallsyms [--all-symbols] "
- "[--base-relative] < in.map > out.S\n");
+ fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] "
+ "[--base-relative] [--lto-clang] in.map > out.S\n");
exit(1);
}
@@ -82,86 +87,7 @@ static char *sym_name(const struct sym_entry *s)
static bool is_ignored_symbol(const char *name, char type)
{
- /* Symbol names that exactly match to the following are ignored.*/
- static const char * const ignored_symbols[] = {
- /*
- * Symbols which vary between passes. Passes 1 and 2 must have
- * identical symbol lists. The kallsyms_* symbols below are
- * only added after pass 1, they would be included in pass 2
- * when --all-symbols is specified so exclude them to get a
- * stable symbol list.
- */
- "kallsyms_addresses",
- "kallsyms_offsets",
- "kallsyms_relative_base",
- "kallsyms_num_syms",
- "kallsyms_names",
- "kallsyms_markers",
- "kallsyms_token_table",
- "kallsyms_token_index",
- /* Exclude linker generated symbols which vary between passes */
- "_SDA_BASE_", /* ppc */
- "_SDA2_BASE_", /* ppc */
- NULL
- };
-
- /* Symbol names that begin with the following are ignored.*/
- static const char * const ignored_prefixes[] = {
- "$", /* local symbols for ARM, MIPS, etc. */
- ".LASANPC", /* s390 kasan local symbols */
- "__crc_", /* modversions */
- "__efistub_", /* arm64 EFI stub namespace */
- "__kvm_nvhe_", /* arm64 non-VHE KVM namespace */
- "__AArch64ADRPThunk_", /* arm64 lld */
- "__ARMV5PILongThunk_", /* arm lld */
- "__ARMV7PILongThunk_",
- "__ThumbV7PILongThunk_",
- "__LA25Thunk_", /* mips lld */
- "__microLA25Thunk_",
- NULL
- };
-
- /* Symbol names that end with the following are ignored.*/
- static const char * const ignored_suffixes[] = {
- "_from_arm", /* arm */
- "_from_thumb", /* arm */
- "_veneer", /* arm */
- NULL
- };
-
- /* Symbol names that contain the following are ignored.*/
- static const char * const ignored_matches[] = {
- ".long_branch.", /* ppc stub */
- ".plt_branch.", /* ppc stub */
- NULL
- };
-
- const char * const *p;
-
- for (p = ignored_symbols; *p; p++)
- if (!strcmp(name, *p))
- return true;
-
- for (p = ignored_prefixes; *p; p++)
- if (!strncmp(name, *p, strlen(*p)))
- return true;
-
- for (p = ignored_suffixes; *p; p++) {
- int l = strlen(name) - strlen(*p);
-
- if (l >= 0 && !strcmp(name + l, *p))
- return true;
- }
-
- for (p = ignored_matches; *p; p++) {
- if (strstr(name, *p))
- return true;
- }
-
- if (type == 'U' || type == 'u')
- return true;
- /* exclude debugging symbols */
- if (type == 'N' || type == 'n')
+ if (type == 'u' || type == 'n')
return true;
if (toupper(type) == 'A') {
@@ -195,24 +121,41 @@ static void check_symbol_range(const char *sym, unsigned long long addr,
}
}
-static struct sym_entry *read_symbol(FILE *in)
+static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
{
- char name[500], type;
+ char *name, type, *p;
unsigned long long addr;
- unsigned int len;
+ size_t len;
+ ssize_t readlen;
struct sym_entry *sym;
- int rc;
- rc = fscanf(in, "%llx %c %499s\n", &addr, &type, name);
- if (rc != 3) {
- if (rc != EOF && fgets(name, 500, in) == NULL)
- fprintf(stderr, "Read error or end of file.\n");
+ errno = 0;
+ readlen = getline(buf, buf_len, in);
+ if (readlen < 0) {
+ if (errno) {
+ perror("read_symbol");
+ exit(EXIT_FAILURE);
+ }
return NULL;
}
- if (strlen(name) >= KSYM_NAME_LEN) {
+
+ 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",
- name, strlen(name), KSYM_NAME_LEN);
+ name, len, KSYM_NAME_LEN);
return NULL;
}
@@ -228,8 +171,7 @@ static struct sym_entry *read_symbol(FILE *in)
/* include the type field in the symbol name, so that it gets
* compressed together */
-
- len = strlen(name) + 1;
+ len++;
sym = malloc(sizeof(*sym) + len + 1);
if (!sym) {
@@ -312,12 +254,21 @@ static void shrink_table(void)
}
}
-static void read_map(FILE *in)
+static void read_map(const char *in)
{
+ FILE *fp;
struct sym_entry *sym;
+ char *buf = NULL;
+ size_t buflen = 0;
- while (!feof(in)) {
- sym = read_symbol(in);
+ fp = fopen(in, "r");
+ if (!fp) {
+ perror(in);
+ exit(1);
+ }
+
+ while (!feof(fp)) {
+ sym = read_symbol(fp, &buf, &buflen);
if (!sym)
continue;
@@ -328,12 +279,16 @@ static void read_map(FILE *in)
table = realloc(table, sizeof(*table) * table_size);
if (!table) {
fprintf(stderr, "out of memory\n");
+ fclose(fp);
exit (1);
}
}
table[table_cnt++] = sym;
}
+
+ free(buf);
+ fclose(fp);
}
static void output_label(const char *label)
@@ -384,6 +339,50 @@ static int symbol_absolute(const struct sym_entry *s)
return s->percpu_absolute;
}
+static void cleanup_symbol_name(char *s)
+{
+ char *p;
+
+ /*
+ * ASCII[.] = 2e
+ * ASCII[0-9] = 30,39
+ * ASCII[A-Z] = 41,5a
+ * ASCII[_] = 5f
+ * ASCII[a-z] = 61,7a
+ *
+ * As above, replacing the first '.' in ".llvm." with '\0' does not
+ * affect the main sorting, but it helps us with subsorting.
+ */
+ p = strstr(s, ".llvm.");
+ if (p)
+ *p = '\0';
+}
+
+static int compare_names(const void *a, const void *b)
+{
+ int ret;
+ 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));
+ if (!ret) {
+ if (sa->addr > sb->addr)
+ return 1;
+ else if (sa->addr < sb->addr)
+ return -1;
+
+ /* keep old order */
+ return (int)(sa->seq - sb->seq);
+ }
+
+ return ret;
+}
+
+static void sort_symbols_by_name(void)
+{
+ qsort(table, table_cnt, sizeof(table[0]), compare_names);
+}
+
static void write_src(void)
{
unsigned int i, k, off;
@@ -402,6 +401,89 @@ static void write_src(void)
printf("\t.section .rodata, \"a\"\n");
+ output_label("kallsyms_num_syms");
+ printf("\t.long\t%u\n", table_cnt);
+ printf("\n");
+
+ /* table of offset markers, that give the offset in the compressed stream
+ * every 256 symbols */
+ markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
+ if (!markers) {
+ fprintf(stderr, "kallsyms failure: "
+ "unable to allocate required memory\n");
+ exit(EXIT_FAILURE);
+ }
+
+ output_label("kallsyms_names");
+ off = 0;
+ for (i = 0; i < table_cnt; i++) {
+ if ((i & 0xFF) == 0)
+ markers[i >> 8] = off;
+ table[i]->seq = i;
+
+ /* There cannot be any symbol of length zero. */
+ if (table[i]->len == 0) {
+ fprintf(stderr, "kallsyms failure: "
+ "unexpected zero symbol length\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Only lengths that fit in up-to-two-byte ULEB128 are supported. */
+ if (table[i]->len > 0x3FFF) {
+ fprintf(stderr, "kallsyms failure: "
+ "unexpected huge symbol length\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* 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);
+ 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);
+ off += table[i]->len + 2;
+ }
+ for (k = 0; k < table[i]->len; k++)
+ printf(", 0x%02x", table[i]->sym[k]);
+ printf("\n");
+ }
+ printf("\n");
+
+ /*
+ * Now that we wrote out the compressed symbol names, restore the
+ * original names, which are needed in some of the later steps.
+ */
+ for (i = 0; i < table_cnt; i++) {
+ expand_symbol(table[i]->sym, table[i]->len, buf);
+ strcpy((char *)table[i]->sym, buf);
+ }
+
+ output_label("kallsyms_markers");
+ for (i = 0; i < ((table_cnt + 255) >> 8); i++)
+ printf("\t.long\t%u\n", markers[i]);
+ printf("\n");
+
+ free(markers);
+
+ output_label("kallsyms_token_table");
+ 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);
+ off += strlen(buf) + 1;
+ }
+ printf("\n");
+
+ output_label("kallsyms_token_index");
+ for (i = 0; i < 256; i++)
+ printf("\t.short\t%d\n", best_idx[i]);
+ printf("\n");
+
if (!base_relative)
output_label("kallsyms_addresses");
else
@@ -436,7 +518,7 @@ static void write_src(void)
table[i]->addr);
exit(EXIT_FAILURE);
}
- printf("\t.long\t%#x\n", (int)offset);
+ printf("\t.long\t%#x /* %s */\n", (int)offset, table[i]->sym);
} else if (!symbol_absolute(table[i])) {
output_address(table[i]->addr);
} else {
@@ -451,54 +533,17 @@ static void write_src(void)
printf("\n");
}
- output_label("kallsyms_num_syms");
- printf("\t.long\t%u\n", table_cnt);
- printf("\n");
-
- /* table of offset markers, that give the offset in the compressed stream
- * every 256 symbols */
- markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
- if (!markers) {
- fprintf(stderr, "kallsyms failure: "
- "unable to allocate required memory\n");
- exit(EXIT_FAILURE);
- }
-
- output_label("kallsyms_names");
- off = 0;
- for (i = 0; i < table_cnt; i++) {
- if ((i & 0xFF) == 0)
- markers[i >> 8] = off;
-
- printf("\t.byte 0x%02x", table[i]->len);
- for (k = 0; k < table[i]->len; k++)
- printf(", 0x%02x", table[i]->sym[k]);
- printf("\n");
-
- off += table[i]->len + 1;
- }
- printf("\n");
-
- output_label("kallsyms_markers");
- for (i = 0; i < ((table_cnt + 255) >> 8); i++)
- printf("\t.long\t%u\n", markers[i]);
- printf("\n");
+ if (lto_clang)
+ for (i = 0; i < table_cnt; i++)
+ cleanup_symbol_name((char *)table[i]->sym);
- free(markers);
-
- output_label("kallsyms_token_table");
- 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);
- off += strlen(buf) + 1;
- }
- printf("\n");
-
- output_label("kallsyms_token_index");
- for (i = 0; i < 256; i++)
- printf("\t.short\t%d\n", best_idx[i]);
+ 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\n",
+ (unsigned char)(table[i]->seq >> 16),
+ (unsigned char)(table[i]->seq >> 8),
+ (unsigned char)(table[i]->seq >> 0));
printf("\n");
}
@@ -524,7 +569,7 @@ static void forget_symbol(const unsigned char *symbol, int len)
}
/* do the initial token count */
-static void build_initial_tok_table(void)
+static void build_initial_token_table(void)
{
unsigned int i;
@@ -649,7 +694,7 @@ static void insert_real_symbols_in_table(void)
static void optimize_token_table(void)
{
- build_initial_tok_table();
+ build_initial_token_table();
insert_real_symbols_in_table();
@@ -764,22 +809,27 @@ static void record_relative_base(void)
int main(int argc, char **argv)
{
- if (argc >= 2) {
- int i;
- for (i = 1; i < argc; i++) {
- if(strcmp(argv[i], "--all-symbols") == 0)
- all_symbols = 1;
- else if (strcmp(argv[i], "--absolute-percpu") == 0)
- absolute_percpu = 1;
- else if (strcmp(argv[i], "--base-relative") == 0)
- base_relative = 1;
- else
- usage();
- }
- } else if (argc != 1)
+ while (1) {
+ static const struct option long_options[] = {
+ {"all-symbols", no_argument, &all_symbols, 1},
+ {"absolute-percpu", no_argument, &absolute_percpu, 1},
+ {"base-relative", no_argument, &base_relative, 1},
+ {"lto-clang", no_argument, &lto_clang, 1},
+ {},
+ };
+
+ int c = getopt_long(argc, argv, "", long_options, NULL);
+
+ if (c == -1)
+ break;
+ if (c != 0)
+ usage();
+ }
+
+ if (optind >= argc)
usage();
- read_map(stdin);
+ read_map(argv[optind]);
shrink_table();
if (absolute_percpu)
make_percpus_absolute();
diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore
index c3d537cd0275..0b2ff775b2e3 100644
--- a/scripts/kconfig/.gitignore
+++ b/scripts/kconfig/.gitignore
@@ -1,12 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
+/conf
+/[gmnq]conf
+/[gmnq]conf-bin
+/[gmnq]conf-cflags
+/[gmnq]conf-libs
/qconf-moc.cc
-*conf-cfg
-
-#
-# configuration programs
-#
-conf
-mconf
-nconf
-qconf
-gconf
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 8c19b82c6035..af1c96198f49 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -9,10 +9,24 @@ else
Kconfig := Kconfig
endif
+ifndef KBUILD_DEFCONFIG
+KBUILD_DEFCONFIG := defconfig
+endif
+
ifeq ($(quiet),silent_)
silent := -s
endif
+export KCONFIG_DEFCONFIG_LIST :=
+ifndef cross_compiling
+kernel-release := $(shell uname -r)
+KCONFIG_DEFCONFIG_LIST += \
+ /lib/modules/$(kernel-release)/.config \
+ /etc/kernel-config \
+ /boot/config-$(kernel-release)
+endif
+KCONFIG_DEFCONFIG_LIST += arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)
+
# We need this, in case the user has it in its environment
unexport CONFIG_
@@ -55,7 +69,7 @@ localyesconfig localmodconfig: $(obj)/conf
# deprecated for external use
simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \
alldefconfig randconfig listnewconfig olddefconfig syncconfig \
- helpnewconfig yes2modconfig mod2yesconfig
+ helpnewconfig yes2modconfig mod2yesconfig mod2noconfig
PHONY += $(simple-targets)
@@ -88,7 +102,8 @@ configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/c
PHONY += tinyconfig
tinyconfig:
- $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config
+ $(Q)KCONFIG_ALLCONFIG=kernel/configs/tiny-base.config $(MAKE) -f $(srctree)/Makefile allnoconfig
+ $(Q)$(MAKE) -f $(srctree)/Makefile tiny.config
# CHECK: -o cache_dir=<path> working?
PHONY += testconfig
@@ -119,6 +134,7 @@ help:
@echo ' randconfig - New config with random answer to all options'
@echo ' yes2modconfig - Change answers from yes to mod if possible'
@echo ' mod2yesconfig - Change answers from mod to yes if possible'
+ @echo ' mod2noconfig - Change answers from mod to no if possible'
@echo ' listnewconfig - List new options'
@echo ' helpnewconfig - List new options and help text'
@echo ' olddefconfig - Same as oldconfig but sets new symbols to their'
@@ -128,8 +144,8 @@ help:
# ===========================================================================
# object files used by all kconfig flavours
-common-objs := confdata.o expr.o lexer.lex.o parser.tab.o preprocess.o \
- symbol.o util.o
+common-objs := confdata.o expr.o lexer.lex.o menu.o parser.tab.o \
+ preprocess.o symbol.o util.o
$(obj)/lexer.lex.o: $(obj)/parser.tab.h
HOSTCFLAGS_lexer.lex.o := -I $(srctree)/$(src)
@@ -143,11 +159,12 @@ conf-objs := conf.o $(common-objs)
hostprogs += nconf
nconf-objs := nconf.o nconf.gui.o $(common-objs)
-HOSTLDLIBS_nconf = $(shell . $(obj)/nconf-cfg && echo $$libs)
-HOSTCFLAGS_nconf.o = $(shell . $(obj)/nconf-cfg && echo $$cflags)
-HOSTCFLAGS_nconf.gui.o = $(shell . $(obj)/nconf-cfg && echo $$cflags)
+HOSTLDLIBS_nconf = $(call read-file, $(obj)/nconf-libs)
+HOSTCFLAGS_nconf.o = $(call read-file, $(obj)/nconf-cflags)
+HOSTCFLAGS_nconf.gui.o = $(call read-file, $(obj)/nconf-cflags)
-$(obj)/nconf.o $(obj)/nconf.gui.o: $(obj)/nconf-cfg
+$(obj)/nconf: | $(obj)/nconf-libs
+$(obj)/nconf.o $(obj)/nconf.gui.o: | $(obj)/nconf-cflags
# mconf: Used for the menuconfig target based on lxdialog
hostprogs += mconf
@@ -155,27 +172,28 @@ lxdialog := $(addprefix lxdialog/, \
checklist.o inputbox.o menubox.o textbox.o util.o yesno.o)
mconf-objs := mconf.o $(lxdialog) $(common-objs)
-HOSTLDLIBS_mconf = $(shell . $(obj)/mconf-cfg && echo $$libs)
+HOSTLDLIBS_mconf = $(call read-file, $(obj)/mconf-libs)
$(foreach f, mconf.o $(lxdialog), \
- $(eval HOSTCFLAGS_$f = $$(shell . $(obj)/mconf-cfg && echo $$$$cflags)))
+ $(eval HOSTCFLAGS_$f = $$(call read-file, $(obj)/mconf-cflags)))
-$(addprefix $(obj)/, mconf.o $(lxdialog)): $(obj)/mconf-cfg
+$(obj)/mconf: | $(obj)/mconf-libs
+$(addprefix $(obj)/, mconf.o $(lxdialog)): | $(obj)/mconf-cflags
# qconf: Used for the xconfig target based on Qt
hostprogs += qconf
qconf-cxxobjs := qconf.o qconf-moc.o
qconf-objs := images.o $(common-objs)
-HOSTLDLIBS_qconf = $(shell . $(obj)/qconf-cfg && echo $$libs)
-HOSTCXXFLAGS_qconf.o = $(shell . $(obj)/qconf-cfg && echo $$cflags)
-HOSTCXXFLAGS_qconf-moc.o = $(shell . $(obj)/qconf-cfg && echo $$cflags)
-
-$(obj)/qconf.o: $(obj)/qconf-cfg
+HOSTLDLIBS_qconf = $(call read-file, $(obj)/qconf-libs)
+HOSTCXXFLAGS_qconf.o = -std=c++11 -fPIC $(call read-file, $(obj)/qconf-cflags)
+HOSTCXXFLAGS_qconf-moc.o = -std=c++11 -fPIC $(call read-file, $(obj)/qconf-cflags)
+$(obj)/qconf: | $(obj)/qconf-libs
+$(obj)/qconf.o $(obj)/qconf-moc.o: | $(obj)/qconf-cflags
quiet_cmd_moc = MOC $@
- cmd_moc = $(shell . $(obj)/qconf-cfg && echo $$moc) $< -o $@
+ cmd_moc = $(call read-file, $(obj)/qconf-bin)/moc $< -o $@
-$(obj)/qconf-moc.cc: $(src)/qconf.h $(obj)/qconf-cfg FORCE
+$(obj)/qconf-moc.cc: $(src)/qconf.h FORCE | $(obj)/qconf-bin
$(call if_changed,moc)
targets += qconf-moc.cc
@@ -184,15 +202,16 @@ targets += qconf-moc.cc
hostprogs += gconf
gconf-objs := gconf.o images.o $(common-objs)
-HOSTLDLIBS_gconf = $(shell . $(obj)/gconf-cfg && echo $$libs)
-HOSTCFLAGS_gconf.o = $(shell . $(obj)/gconf-cfg && echo $$cflags)
+HOSTLDLIBS_gconf = $(call read-file, $(obj)/gconf-libs)
+HOSTCFLAGS_gconf.o = $(call read-file, $(obj)/gconf-cflags)
-$(obj)/gconf.o: $(obj)/gconf-cfg
+$(obj)/gconf: | $(obj)/gconf-libs
+$(obj)/gconf.o: | $(obj)/gconf-cflags
# check if necessary packages are available, and configure build flags
-filechk_conf_cfg = $(CONFIG_SHELL) $<
+cmd_conf_cfg = $< $(addprefix $(obj)/$*conf-, cflags libs bin); touch $(obj)/$*conf-bin
-$(obj)/%conf-cfg: $(src)/%conf-cfg.sh FORCE
- $(call filechk,conf_cfg)
+$(obj)/%conf-cflags $(obj)/%conf-libs $(obj)/%conf-bin: $(src)/%conf-cfg.sh
+ $(call cmd,conf_cfg)
-clean-files += *conf-cfg
+clean-files += *conf-cflags *conf-libs *conf-bin
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 957d2a0832f7..33d19e419908 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -35,9 +35,10 @@ enum input_mode {
olddefconfig,
yes2modconfig,
mod2yesconfig,
+ mod2noconfig,
};
static enum input_mode input_mode = oldaskconfig;
-
+static int input_mode_opt;
static int indent = 1;
static int tty_stdio;
static int sync_kconfig;
@@ -82,6 +83,237 @@ static void xfgets(char *str, int size, FILE *in)
printf("%s", str);
}
+static void set_randconfig_seed(void)
+{
+ unsigned int seed;
+ char *env;
+ bool seed_set = false;
+
+ env = getenv("KCONFIG_SEED");
+ if (env && *env) {
+ char *endp;
+
+ seed = strtol(env, &endp, 0);
+ if (*endp == '\0')
+ seed_set = true;
+ }
+
+ if (!seed_set) {
+ struct timeval now;
+
+ /*
+ * Use microseconds derived seed, compensate for systems where it may
+ * be zero.
+ */
+ gettimeofday(&now, NULL);
+ seed = (now.tv_sec + 1) * (now.tv_usec + 1);
+ }
+
+ printf("KCONFIG_SEED=0x%X\n", seed);
+ srand(seed);
+}
+
+static bool randomize_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+ int cnt, def;
+
+ /*
+ * If choice is mod then we may have more items selected
+ * and if no then no-one.
+ * In both cases stop.
+ */
+ if (csym->curr.tri != yes)
+ return false;
+
+ prop = sym_get_choice_prop(csym);
+
+ /* count entries in choice block */
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym)
+ cnt++;
+
+ /*
+ * find a random value and set it to yes,
+ * set the rest to no so we have only one set
+ */
+ def = rand() % cnt;
+
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (def == cnt++) {
+ sym->def[S_DEF_USER].tri = yes;
+ csym->def[S_DEF_USER].val = sym;
+ } else {
+ sym->def[S_DEF_USER].tri = no;
+ }
+ sym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ sym->flags &= ~SYMBOL_VALID;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~SYMBOL_VALID;
+
+ return true;
+}
+
+enum conf_def_mode {
+ def_default,
+ def_yes,
+ def_mod,
+ def_no,
+ def_random
+};
+
+static bool conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+ struct symbol *sym, *csym;
+ int i, cnt;
+ /*
+ * can't go as the default in switch-case below, otherwise gcc whines
+ * about -Wmaybe-uninitialized
+ */
+ int pby = 50; /* probability of bool = y */
+ int pty = 33; /* probability of tristate = y */
+ int ptm = 33; /* probability of tristate = m */
+ bool has_changed = false;
+
+ if (mode == def_random) {
+ int n, p[3];
+ char *env = getenv("KCONFIG_PROBABILITY");
+
+ n = 0;
+ while (env && *env) {
+ char *endp;
+ int tmp = strtol(env, &endp, 10);
+
+ if (tmp >= 0 && tmp <= 100) {
+ p[n++] = tmp;
+ } else {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ env = (*endp == ':') ? endp + 1 : endp;
+ if (n >= 3)
+ break;
+ }
+ switch (n) {
+ case 1:
+ pby = p[0];
+ ptm = pby / 2;
+ pty = pby - ptm;
+ break;
+ case 2:
+ pty = p[0];
+ ptm = p[1];
+ pby = pty + ptm;
+ break;
+ case 3:
+ pby = p[0];
+ pty = p[1];
+ ptm = p[2];
+ break;
+ }
+
+ if (pty + ptm > 100) {
+ errno = ERANGE;
+ perror("KCONFIG_PROBABILITY");
+ exit(1);
+ }
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) || sym->flags & SYMBOL_VALID)
+ continue;
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ has_changed = true;
+ switch (mode) {
+ case def_yes:
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ case def_mod:
+ sym->def[S_DEF_USER].tri = mod;
+ break;
+ case def_no:
+ sym->def[S_DEF_USER].tri = no;
+ break;
+ case def_random:
+ sym->def[S_DEF_USER].tri = no;
+ cnt = rand() % 100;
+ if (sym->type == S_TRISTATE) {
+ if (cnt < pty)
+ sym->def[S_DEF_USER].tri = yes;
+ else if (cnt < pty + ptm)
+ sym->def[S_DEF_USER].tri = mod;
+ } else if (cnt < pby)
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ default:
+ continue;
+ }
+ if (!(sym_is_choice(sym) && mode == def_random))
+ sym->flags |= SYMBOL_DEF_USER;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ sym_clear_all_valid();
+
+ /*
+ * We have different type of choice blocks.
+ * If curr.tri equals to mod then we can select several
+ * choice symbols in one block.
+ * In this case we do nothing.
+ * If curr.tri equals yes then only one symbol can be
+ * selected in a choice block and we set it to yes,
+ * and the rest to no.
+ */
+ if (mode != def_random) {
+ for_all_symbols(i, csym) {
+ if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
+ sym_is_choice_value(csym))
+ csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
+ }
+ }
+
+ for_all_symbols(i, csym) {
+ if (sym_has_value(csym) || !sym_is_choice(csym))
+ continue;
+
+ sym_calc_value(csym);
+ if (mode == def_random)
+ has_changed |= randomize_choice_values(csym);
+ else {
+ set_all_choice_values(csym);
+ has_changed = true;
+ }
+ }
+
+ return has_changed;
+}
+
+static void conf_rewrite_tristates(tristate old_val, tristate new_val)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym) {
+ if (sym_get_type(sym) == S_TRISTATE &&
+ sym->def[S_DEF_USER].tri == old_val)
+ sym->def[S_DEF_USER].tri = new_val;
+ }
+ sym_clear_all_valid();
+}
+
static int conf_askvalue(struct symbol *sym, const char *def)
{
if (!sym_has_value(sym))
@@ -319,7 +551,7 @@ static int conf_choice(struct menu *menu)
print_help(child);
continue;
}
- sym_set_choice_value(sym, child->sym);
+ sym_set_tristate_value(child->sym, yes);
for (child = child->list; child; child = child->next) {
indent += 2;
conf(child);
@@ -411,19 +643,8 @@ static void check_conf(struct menu *menu)
switch (input_mode) {
case listnewconfig:
- if (sym->name) {
- const char *str;
-
- if (sym->type == S_STRING) {
- str = sym_get_string_value(sym);
- str = sym_escape_string_value(str);
- printf("%s%s=%s\n", CONFIG_, sym->name, str);
- free((void *)str);
- } else {
- str = sym_get_string_value(sym);
- printf("%s%s=%s\n", CONFIG_, sym->name, str);
- }
- }
+ if (sym->name)
+ print_symbol_for_listconfig(sym);
break;
case helpnewconfig:
printf("-----\n");
@@ -443,30 +664,37 @@ static void check_conf(struct menu *menu)
check_conf(child);
}
-static struct option long_opts[] = {
- {"oldaskconfig", no_argument, NULL, oldaskconfig},
- {"oldconfig", no_argument, NULL, oldconfig},
- {"syncconfig", no_argument, NULL, syncconfig},
- {"defconfig", required_argument, NULL, defconfig},
- {"savedefconfig", required_argument, NULL, savedefconfig},
- {"allnoconfig", no_argument, NULL, allnoconfig},
- {"allyesconfig", no_argument, NULL, allyesconfig},
- {"allmodconfig", no_argument, NULL, allmodconfig},
- {"alldefconfig", no_argument, NULL, alldefconfig},
- {"randconfig", no_argument, NULL, randconfig},
- {"listnewconfig", no_argument, NULL, listnewconfig},
- {"helpnewconfig", no_argument, NULL, helpnewconfig},
- {"olddefconfig", no_argument, NULL, olddefconfig},
- {"yes2modconfig", no_argument, NULL, yes2modconfig},
- {"mod2yesconfig", no_argument, NULL, mod2yesconfig},
+static const struct option long_opts[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"silent", no_argument, NULL, 's'},
+ {"oldaskconfig", no_argument, &input_mode_opt, oldaskconfig},
+ {"oldconfig", no_argument, &input_mode_opt, oldconfig},
+ {"syncconfig", no_argument, &input_mode_opt, syncconfig},
+ {"defconfig", required_argument, &input_mode_opt, defconfig},
+ {"savedefconfig", required_argument, &input_mode_opt, savedefconfig},
+ {"allnoconfig", no_argument, &input_mode_opt, allnoconfig},
+ {"allyesconfig", no_argument, &input_mode_opt, allyesconfig},
+ {"allmodconfig", no_argument, &input_mode_opt, allmodconfig},
+ {"alldefconfig", no_argument, &input_mode_opt, alldefconfig},
+ {"randconfig", no_argument, &input_mode_opt, randconfig},
+ {"listnewconfig", no_argument, &input_mode_opt, listnewconfig},
+ {"helpnewconfig", no_argument, &input_mode_opt, helpnewconfig},
+ {"olddefconfig", no_argument, &input_mode_opt, olddefconfig},
+ {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig},
+ {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig},
+ {"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig},
{NULL, 0, NULL, 0}
};
static void conf_usage(const char *progname)
{
-
- printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
- printf("[option] is _one_ of the following:\n");
+ printf("Usage: %s [options] <kconfig-file>\n", progname);
+ printf("\n");
+ printf("Generic options:\n");
+ printf(" -h, --help Print this message and exit.\n");
+ printf(" -s, --silent Do not print log.\n");
+ printf("\n");
+ printf("Mode options:\n");
printf(" --listnewconfig List new options\n");
printf(" --helpnewconfig List new options and help text\n");
printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
@@ -483,6 +711,7 @@ static void conf_usage(const char *progname)
printf(" --randconfig New config with random answer to all options\n");
printf(" --yes2modconfig Change answers from yes to mod if possible\n");
printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
+ printf(" --mod2noconfig Change answers from mod to no if possible\n");
printf(" (If none of the above is given, --oldaskconfig is the default)\n");
}
@@ -496,65 +725,38 @@ int main(int ac, char **av)
tty_stdio = isatty(0) && isatty(1);
while ((opt = getopt_long(ac, av, "hs", long_opts, NULL)) != -1) {
- if (opt == 's') {
- conf_set_message_callback(NULL);
- continue;
- }
- input_mode = (enum input_mode)opt;
switch (opt) {
- case syncconfig:
- /*
- * syncconfig is invoked during the build stage.
- * Suppress distracting "configuration written to ..."
- */
- conf_set_message_callback(NULL);
- sync_kconfig = 1;
- break;
- case defconfig:
- case savedefconfig:
- defconfig_file = optarg;
- break;
- case randconfig:
- {
- struct timeval now;
- unsigned int seed;
- char *seed_env;
-
- /*
- * Use microseconds derived seed,
- * compensate for systems where it may be zero
- */
- gettimeofday(&now, NULL);
- seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
-
- seed_env = getenv("KCONFIG_SEED");
- if( seed_env && *seed_env ) {
- char *endp;
- int tmp = (int)strtol(seed_env, &endp, 0);
- if (*endp == '\0') {
- seed = tmp;
- }
- }
- fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
- srand(seed);
- break;
- }
- case oldaskconfig:
- case oldconfig:
- case allnoconfig:
- case allyesconfig:
- case allmodconfig:
- case alldefconfig:
- case listnewconfig:
- case helpnewconfig:
- case olddefconfig:
- case yes2modconfig:
- case mod2yesconfig:
- break;
case 'h':
conf_usage(progname);
exit(1);
break;
+ case 's':
+ conf_set_message_callback(NULL);
+ break;
+ case 0:
+ input_mode = input_mode_opt;
+ switch (input_mode) {
+ case syncconfig:
+ /*
+ * syncconfig is invoked during the build stage.
+ * Suppress distracting
+ * "configuration written to ..."
+ */
+ conf_set_message_callback(NULL);
+ sync_kconfig = 1;
+ break;
+ case defconfig:
+ case savedefconfig:
+ defconfig_file = optarg;
+ break;
+ case randconfig:
+ set_randconfig_seed();
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
}
}
if (ac == optind) {
@@ -562,8 +764,7 @@ int main(int ac, char **av)
conf_usage(progname);
exit(1);
}
- name = av[optind];
- conf_parse(name);
+ conf_parse(av[optind]);
//zconfdump(stdout);
switch (input_mode) {
@@ -586,6 +787,7 @@ int main(int ac, char **av)
case olddefconfig:
case yes2modconfig:
case mod2yesconfig:
+ case mod2noconfig:
conf_read(NULL);
break;
case allnoconfig:
@@ -660,10 +862,13 @@ int main(int ac, char **av)
case savedefconfig:
break;
case yes2modconfig:
- conf_rewrite_mod_or_yes(def_y2m);
+ conf_rewrite_tristates(yes, mod);
break;
case mod2yesconfig:
- conf_rewrite_mod_or_yes(def_m2y);
+ conf_rewrite_tristates(mod, yes);
+ break;
+ case mod2noconfig:
+ conf_rewrite_tristates(mod, no);
break;
case oldaskconfig:
rootEntry = &rootmenu;
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 2568dbe16ed6..992575f1e976 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -33,7 +34,7 @@ static bool is_dir(const char *path)
struct stat st;
if (stat(path, &st))
- return 0;
+ return false;
return S_ISDIR(st.st_mode);
}
@@ -129,46 +130,22 @@ static size_t depfile_prefix_len;
/* touch depfile for symbol 'name' */
static int conf_touch_dep(const char *name)
{
- int fd, ret;
- const char *s;
- char *d, c;
+ int fd;
- /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */
- if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path))
+ /* check overflow: prefix + name + '\0' must fit in buffer. */
+ if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path))
return -1;
- d = depfile_path + depfile_prefix_len;
- s = name;
-
- while ((c = *s++))
- *d++ = (c == '_') ? '/' : tolower(c);
- strcpy(d, ".h");
+ strcpy(depfile_path + depfile_prefix_len, name);
- /* Assume directory path already exists. */
fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1) {
- if (errno != ENOENT)
- return -1;
-
- ret = make_parent_dir(depfile_path);
- if (ret)
- return ret;
-
- /* Try it again. */
- fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1)
- return -1;
- }
+ if (fd == -1)
+ return -1;
close(fd);
return 0;
}
-struct conf_printer {
- void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
- void (*print_comment)(FILE *, const char *, void *);
-};
-
static void conf_warning(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
@@ -232,6 +209,20 @@ static const char *conf_get_autoconfig_name(void)
return name ? name : "include/config/auto.conf";
}
+static const char *conf_get_autoheader_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOHEADER");
+
+ return name ? name : "include/generated/autoconf.h";
+}
+
+static const char *conf_get_rustccfg_name(void)
+{
+ char *name = getenv("KCONFIG_RUSTCCFG");
+
+ return name ? name : "include/generated/rustc_cfg";
+}
+
static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
{
char *p2;
@@ -260,19 +251,21 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
p, sym->name);
return 1;
case S_STRING:
- if (*p++ != '"')
- break;
- for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
- if (*p2 == '"') {
- *p2 = 0;
+ /* No escaping for S_DEF_AUTO (include/config/auto.conf) */
+ if (def != S_DEF_AUTO) {
+ if (*p++ != '"')
break;
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
}
- memmove(p2, p2 + 1, strlen(p2));
- }
- if (!p2) {
- if (def != S_DEF_AUTO)
+ if (!p2) {
conf_warning("invalid string found");
- return 1;
+ return 1;
+ }
}
/* fall through */
case S_INT:
@@ -360,28 +353,46 @@ int conf_read_simple(const char *name, int def)
if (name) {
in = zconf_fopen(name);
} else {
- struct property *prop;
+ char *env;
name = conf_get_configname();
in = zconf_fopen(name);
if (in)
goto load;
- sym_add_change_count(1);
- if (!sym_defconfig_list)
+ conf_set_changed(true);
+
+ env = getenv("KCONFIG_DEFCONFIG_LIST");
+ if (!env)
return 1;
- for_all_defaults(sym_defconfig_list, prop) {
- if (expr_calc_value(prop->visible.expr) == no ||
- prop->expr->type != E_SYMBOL)
- continue;
- sym_calc_value(prop->expr->left.sym);
- name = sym_get_string_value(prop->expr->left.sym);
- in = zconf_fopen(name);
+ while (1) {
+ bool is_last;
+
+ while (isspace(*env))
+ env++;
+
+ if (!*env)
+ break;
+
+ p = env;
+ while (*p && !isspace(*p))
+ p++;
+
+ is_last = (*p == '\0');
+
+ *p = '\0';
+
+ in = zconf_fopen(env);
if (in) {
conf_message("using defaults found in %s",
- name);
+ env);
goto load;
}
+
+ if (is_last)
+ break;
+
+ env = p + 1;
}
}
if (!in)
@@ -426,7 +437,7 @@ load:
if (def == S_DEF_USER) {
sym = sym_find(line + 2 + strlen(CONFIG_));
if (!sym) {
- sym_add_change_count(1);
+ conf_set_changed(true);
continue;
}
} else {
@@ -465,11 +476,11 @@ load:
* Reading from include/config/auto.conf
* If CONFIG_FOO previously existed in
* auto.conf but it is missing now,
- * include/config/foo.h must be touched.
+ * include/config/FOO must be touched.
*/
conf_touch_dep(line + strlen(CONFIG_));
else
- sym_add_change_count(1);
+ conf_set_changed(true);
continue;
}
@@ -517,7 +528,7 @@ int conf_read(const char *name)
int conf_unsaved = 0;
int i;
- sym_set_change_count(0);
+ conf_set_changed(false);
if (conf_read_simple(name, S_DEF_USER)) {
sym_calc_value(modules_sym);
@@ -575,174 +586,232 @@ int conf_read(const char *name)
}
}
- sym_add_change_count(conf_warnings || conf_unsaved);
+ if (conf_warnings || conf_unsaved)
+ conf_set_changed(true);
return 0;
}
-/*
- * Kconfig configuration printer
- *
- * This printer is used when generating the resulting configuration after
- * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
- * passing a non-NULL argument to the printer.
- *
- */
-static void
-kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+struct comment_style {
+ const char *decoration;
+ const char *prefix;
+ const char *postfix;
+};
+
+static const struct comment_style comment_style_pound = {
+ .decoration = "#",
+ .prefix = "#",
+ .postfix = "#",
+};
+
+static const struct comment_style comment_style_c = {
+ .decoration = " *",
+ .prefix = "/*",
+ .postfix = " */",
+};
+
+static void conf_write_heading(FILE *fp, const struct comment_style *cs)
{
+ if (!cs)
+ return;
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (*value == 'n') {
- bool skip_unset = (arg != NULL);
+ fprintf(fp, "%s\n", cs->prefix);
- if (!skip_unset)
- fprintf(fp, "# %s%s is not set\n",
- CONFIG_, sym->name);
- return;
- }
- break;
- default:
- break;
- }
+ fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n",
+ cs->decoration);
+
+ fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text);
- fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
+ fprintf(fp, "%s\n", cs->postfix);
}
-static void
-kconfig_print_comment(FILE *fp, const char *value, void *arg)
+/* The returned pointer must be freed on the caller side */
+static char *escape_string_value(const char *in)
{
- const char *p = value;
- size_t l;
+ const char *p;
+ char *out;
+ size_t len;
- for (;;) {
- l = strcspn(p, "\n");
- fprintf(fp, "#");
- if (l) {
- fprintf(fp, " ");
- xfwrite(p, l, 1, fp);
- p += l;
- }
- fprintf(fp, "\n");
- if (*p++ == '\0')
+ len = strlen(in) + strlen("\"\"") + 1;
+
+ p = in;
+ while (1) {
+ p += strcspn(p, "\"\\");
+
+ if (p[0] == '\0')
break;
+
+ len++;
+ p++;
}
+
+ out = xmalloc(len);
+ out[0] = '\0';
+
+ strcat(out, "\"");
+
+ p = in;
+ while (1) {
+ len = strcspn(p, "\"\\");
+ strncat(out, p, len);
+ p += len;
+
+ if (p[0] == '\0')
+ break;
+
+ strcat(out, "\\");
+ strncat(out, p++, 1);
+ }
+
+ strcat(out, "\"");
+
+ return out;
}
-static struct conf_printer kconfig_printer_cb =
+enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE };
+
+static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
+ bool escape_string)
{
- .print_symbol = kconfig_print_symbol,
- .print_comment = kconfig_print_comment,
-};
+ const char *val;
+ char *escaped = NULL;
-/*
- * Header printer
- *
- * This printer is used when generating the `include/generated/autoconf.h' file.
- */
-static void
-header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
+
+ if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
+ output_n != OUTPUT_N && *val == 'n') {
+ if (output_n == OUTPUT_N_AS_UNSET)
+ fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name);
+ return;
+ }
+
+ if (sym->type == S_STRING && escape_string) {
+ escaped = escape_string_value(val);
+ val = escaped;
+ }
+
+ fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+}
+
+static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
+}
+
+static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
+{
+ __print_symbol(fp, sym, OUTPUT_N_NONE, false);
+}
+
+void print_symbol_for_listconfig(struct symbol *sym)
{
+ __print_symbol(stdout, sym, OUTPUT_N, true);
+}
+
+static void print_symbol_for_c(FILE *fp, struct symbol *sym)
+{
+ const char *val;
+ const char *sym_suffix = "";
+ const char *val_prefix = "";
+ char *escaped = NULL;
+
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
switch (sym->type) {
case S_BOOLEAN:
- case S_TRISTATE: {
- const char *suffix = "";
-
- switch (*value) {
+ case S_TRISTATE:
+ switch (*val) {
case 'n':
- break;
+ return;
case 'm':
- suffix = "_MODULE";
+ sym_suffix = "_MODULE";
/* fall through */
default:
- fprintf(fp, "#define %s%s%s 1\n",
- CONFIG_, sym->name, suffix);
+ val = "1";
}
break;
- }
- case S_HEX: {
- const char *prefix = "";
-
- if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
- prefix = "0x";
- fprintf(fp, "#define %s%s %s%s\n",
- CONFIG_, sym->name, prefix, value);
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
break;
- }
case S_STRING:
- case S_INT:
- fprintf(fp, "#define %s%s %s\n",
- CONFIG_, sym->name, value);
- break;
+ escaped = escape_string_value(val);
+ val = escaped;
default:
break;
}
-}
-
-static void
-header_print_comment(FILE *fp, const char *value, void *arg)
-{
- const char *p = value;
- size_t l;
+ fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix,
+ val_prefix, val);
- fprintf(fp, "/*\n");
- for (;;) {
- l = strcspn(p, "\n");
- fprintf(fp, " *");
- if (l) {
- fprintf(fp, " ");
- xfwrite(p, l, 1, fp);
- p += l;
- }
- fprintf(fp, "\n");
- if (*p++ == '\0')
- break;
- }
- fprintf(fp, " */\n");
+ free(escaped);
}
-static struct conf_printer header_printer_cb =
+static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym)
{
- .print_symbol = header_print_symbol,
- .print_comment = header_print_comment,
-};
+ const char *val;
+ const char *val_prefix = "";
+ char *val_prefixed = NULL;
+ size_t val_prefixed_len;
+ char *escaped = NULL;
-static void conf_write_symbol(FILE *fp, struct symbol *sym,
- struct conf_printer *printer, void *printer_arg)
-{
- const char *str;
+ if (sym->type == S_UNKNOWN)
+ return;
+
+ val = sym_get_string_value(sym);
switch (sym->type) {
- case S_UNKNOWN:
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /*
+ * We do not care about disabled ones, i.e. no need for
+ * what otherwise are "comments" in other printers.
+ */
+ if (*val == 'n')
+ return;
+
+ /*
+ * To have similar functionality to the C macro `IS_ENABLED()`
+ * we provide an empty `--cfg CONFIG_X` here in both `y`
+ * and `m` cases.
+ *
+ * Then, the common `fprintf()` below will also give us
+ * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can
+ * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`.
+ */
+ fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name);
break;
- case S_STRING:
- str = sym_get_string_value(sym);
- str = sym_escape_string_value(str);
- printer->print_symbol(fp, sym, str, printer_arg);
- free((void *)str);
+ case S_HEX:
+ if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ val_prefix = "0x";
break;
default:
- str = sym_get_string_value(sym);
- printer->print_symbol(fp, sym, str, printer_arg);
+ break;
}
-}
-static void
-conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
-{
- char buf[256];
+ if (strlen(val_prefix) > 0) {
+ val_prefixed_len = strlen(val) + strlen(val_prefix) + 1;
+ val_prefixed = xmalloc(val_prefixed_len);
+ snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val);
+ val = val_prefixed;
+ }
- snprintf(buf, sizeof(buf),
- "\n"
- "Automatically generated file; DO NOT EDIT.\n"
- "%s\n",
- rootmenu.prompt->text);
+ /* All values get escaped: the `--cfg` option only takes strings */
+ escaped = escape_string_value(val);
+ val = escaped;
- printer->print_comment(fp, buf, printer_arg);
+ fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val);
+
+ free(escaped);
+ free(val_prefixed);
}
/*
@@ -801,7 +870,7 @@ int conf_write_defconfig(const char *filename)
goto next_menu;
}
}
- conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+ print_symbol_for_dotconfig(out, sym);
}
next_menu:
if (menu->list != NULL) {
@@ -861,7 +930,7 @@ int conf_write(const char *name)
if (!out)
return 1;
- conf_write_heading(out, &kconfig_printer_cb, NULL);
+ conf_write_heading(out, &comment_style_pound);
if (!conf_get_changed())
sym_clear_all_valid();
@@ -888,7 +957,7 @@ int conf_write(const char *name)
need_newline = false;
}
sym->flags |= SYMBOL_WRITTEN;
- conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+ print_symbol_for_dotconfig(out, sym);
}
next:
@@ -896,19 +965,20 @@ next:
menu = menu->list;
continue;
}
- if (menu->next)
+
+end_check:
+ if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu &&
+ menu->prompt->type == P_MENU) {
+ fprintf(out, "# end of %s\n", menu_get_prompt(menu));
+ need_newline = true;
+ }
+
+ if (menu->next) {
menu = menu->next;
- else while ((menu = menu->parent)) {
- if (!menu->sym && menu_is_visible(menu) &&
- menu != &rootmenu) {
- str = menu_get_prompt(menu);
- fprintf(out, "# end of %s\n", str);
- need_newline = true;
- }
- if (menu->next) {
- menu = menu->next;
- break;
- }
+ } else {
+ menu = menu->parent;
+ if (menu)
+ goto end_check;
}
}
fclose(out);
@@ -920,7 +990,7 @@ next:
if (is_same(name, tmpname)) {
conf_message("No change to %s", name);
unlink(tmpname);
- sym_set_change_count(0);
+ conf_set_changed(false);
return 0;
}
@@ -932,51 +1002,75 @@ next:
conf_message("configuration written to %s", name);
- sym_set_change_count(0);
+ conf_set_changed(false);
return 0;
}
/* write a dependency file as used by kbuild to track dependencies */
-static int conf_write_dep(const char *name)
+static int conf_write_autoconf_cmd(const char *autoconf_name)
{
+ char name[PATH_MAX], tmp[PATH_MAX];
struct file *file;
FILE *out;
+ int ret;
- out = fopen("..config.tmp", "w");
- if (!out)
- return 1;
- fprintf(out, "deps_config := \\\n");
- for (file = file_list; file; file = file->next) {
- if (file->next)
- fprintf(out, "\t%s \\\n", file->name);
- else
- fprintf(out, "\t%s\n", file->name);
+ ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
+ if (ret >= sizeof(name)) /* check truncation */
+ return -1;
+
+ if (make_parent_dir(name))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ out = fopen(tmp, "w");
+ if (!out) {
+ perror("fopen");
+ return -1;
}
- fprintf(out, "\n%s: \\\n"
- "\t$(deps_config)\n\n", conf_get_autoconfig_name());
- env_write_dep(out, conf_get_autoconfig_name());
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+
+ fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name);
+
+ env_write_dep(out, autoconf_name);
fprintf(out, "\n$(deps_config): ;\n");
+
+ fflush(out);
+ ret = ferror(out); /* error check for all fprintf() calls */
fclose(out);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, name)) {
+ perror("rename");
+ return -1;
+ }
- if (make_parent_dir(name))
- return 1;
- rename("..config.tmp", name);
return 0;
}
static int conf_touch_deps(void)
{
- const char *name;
+ const char *name, *tmp;
struct symbol *sym;
int res, i;
- strcpy(depfile_path, "include/config/");
- depfile_prefix_len = strlen(depfile_path);
-
name = conf_get_autoconfig_name();
+ tmp = strrchr(name, '/');
+ depfile_prefix_len = tmp ? tmp - name + 1 : 0;
+ if (depfile_prefix_len + 1 > sizeof(depfile_path))
+ return -1;
+
+ strncpy(depfile_path, name, depfile_prefix_len);
+ depfile_path[depfile_prefix_len] = 0;
+
conf_read_simple(name, S_DEF_AUTO);
sym_calc_value(modules_sym);
@@ -1039,87 +1133,110 @@ static int conf_touch_deps(void)
return 0;
}
+static int __conf_write_autoconf(const char *filename,
+ void (*print_symbol)(FILE *, struct symbol *),
+ const struct comment_style *comment_style)
+{
+ char tmp[PATH_MAX];
+ FILE *file;
+ struct symbol *sym;
+ int ret, i;
+
+ if (make_parent_dir(filename))
+ return -1;
+
+ ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
+ if (ret >= sizeof(tmp)) /* check truncation */
+ return -1;
+
+ file = fopen(tmp, "w");
+ if (!file) {
+ perror("fopen");
+ return -1;
+ }
+
+ conf_write_heading(file, comment_style);
+
+ for_all_symbols(i, sym)
+ if ((sym->flags & SYMBOL_WRITE) && sym->name)
+ print_symbol(file, sym);
+
+ fflush(file);
+ /* check possible errors in conf_write_heading() and print_symbol() */
+ ret = ferror(file);
+ fclose(file);
+ if (ret)
+ return -1;
+
+ if (rename(tmp, filename)) {
+ perror("rename");
+ return -1;
+ }
+
+ return 0;
+}
+
int conf_write_autoconf(int overwrite)
{
struct symbol *sym;
- const char *name;
const char *autoconf_name = conf_get_autoconfig_name();
- FILE *out, *out_h;
- int i;
+ int ret, i;
if (!overwrite && is_present(autoconf_name))
return 0;
- conf_write_dep("include/config/auto.conf.cmd");
+ ret = conf_write_autoconf_cmd(autoconf_name);
+ if (ret)
+ return -1;
if (conf_touch_deps())
return 1;
- out = fopen(".tmpconfig", "w");
- if (!out)
- return 1;
-
- out_h = fopen(".tmpconfig.h", "w");
- if (!out_h) {
- fclose(out);
- return 1;
- }
-
- conf_write_heading(out, &kconfig_printer_cb, NULL);
- conf_write_heading(out_h, &header_printer_cb, NULL);
-
- for_all_symbols(i, sym) {
+ for_all_symbols(i, sym)
sym_calc_value(sym);
- if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
- continue;
- /* write symbols to auto.conf and autoconf.h */
- conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
- conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
- }
- fclose(out);
- fclose(out_h);
+ ret = __conf_write_autoconf(conf_get_autoheader_name(),
+ print_symbol_for_c,
+ &comment_style_c);
+ if (ret)
+ return ret;
- name = getenv("KCONFIG_AUTOHEADER");
- if (!name)
- name = "include/generated/autoconf.h";
- if (make_parent_dir(name))
- return 1;
- if (rename(".tmpconfig.h", name))
- return 1;
+ ret = __conf_write_autoconf(conf_get_rustccfg_name(),
+ print_symbol_for_rustccfg,
+ NULL);
+ if (ret)
+ return ret;
- if (make_parent_dir(autoconf_name))
- return 1;
/*
- * This must be the last step, kbuild has a dependency on auto.conf
- * and this marks the successful completion of the previous steps.
+ * Create include/config/auto.conf. This must be the last step because
+ * Kbuild has a dependency on auto.conf and this marks the successful
+ * completion of the previous steps.
*/
- if (rename(".tmpconfig", autoconf_name))
- return 1;
+ ret = __conf_write_autoconf(conf_get_autoconfig_name(),
+ print_symbol_for_autoconf,
+ &comment_style_pound);
+ if (ret)
+ return ret;
return 0;
}
-static int sym_change_count;
+static bool conf_changed;
static void (*conf_changed_callback)(void);
-void sym_set_change_count(int count)
+void conf_set_changed(bool val)
{
- int _sym_change_count = sym_change_count;
- sym_change_count = count;
- if (conf_changed_callback &&
- (bool)_sym_change_count != (bool)count)
- conf_changed_callback();
-}
+ bool changed = conf_changed != val;
-void sym_add_change_count(int count)
-{
- sym_set_change_count(count + sym_change_count);
+ conf_changed = val;
+
+ if (conf_changed_callback && changed)
+ conf_changed_callback();
}
bool conf_get_changed(void)
{
- return sym_change_count;
+ return conf_changed;
}
void conf_set_changed_callback(void (*fn)(void))
@@ -1127,54 +1244,6 @@ void conf_set_changed_callback(void (*fn)(void))
conf_changed_callback = fn;
}
-static bool randomize_choice_values(struct symbol *csym)
-{
- struct property *prop;
- struct symbol *sym;
- struct expr *e;
- int cnt, def;
-
- /*
- * If choice is mod then we may have more items selected
- * and if no then no-one.
- * In both cases stop.
- */
- if (csym->curr.tri != yes)
- return false;
-
- prop = sym_get_choice_prop(csym);
-
- /* count entries in choice block */
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym)
- cnt++;
-
- /*
- * find a random value and set it to yes,
- * set the rest to no so we have only one set
- */
- def = (rand() % cnt);
-
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym) {
- if (def == cnt++) {
- sym->def[S_DEF_USER].tri = yes;
- csym->def[S_DEF_USER].val = sym;
- }
- else {
- sym->def[S_DEF_USER].tri = no;
- }
- sym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- sym->flags &= ~SYMBOL_VALID;
- }
- csym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- csym->flags &= ~(SYMBOL_VALID);
-
- return true;
-}
-
void set_all_choice_values(struct symbol *csym)
{
struct property *prop;
@@ -1194,146 +1263,3 @@ void set_all_choice_values(struct symbol *csym)
/* clear VALID to get value calculated */
csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
}
-
-bool conf_set_all_new_symbols(enum conf_def_mode mode)
-{
- struct symbol *sym, *csym;
- int i, cnt, pby, pty, ptm; /* pby: probability of bool = y
- * pty: probability of tristate = y
- * ptm: probability of tristate = m
- */
-
- pby = 50; pty = ptm = 33; /* can't go as the default in switch-case
- * below, otherwise gcc whines about
- * -Wmaybe-uninitialized */
- if (mode == def_random) {
- int n, p[3];
- char *env = getenv("KCONFIG_PROBABILITY");
- n = 0;
- while( env && *env ) {
- char *endp;
- int tmp = strtol( env, &endp, 10 );
- if( tmp >= 0 && tmp <= 100 ) {
- p[n++] = tmp;
- } else {
- errno = ERANGE;
- perror( "KCONFIG_PROBABILITY" );
- exit( 1 );
- }
- env = (*endp == ':') ? endp+1 : endp;
- if( n >=3 ) {
- break;
- }
- }
- switch( n ) {
- case 1:
- pby = p[0]; ptm = pby/2; pty = pby-ptm;
- break;
- case 2:
- pty = p[0]; ptm = p[1]; pby = pty + ptm;
- break;
- case 3:
- pby = p[0]; pty = p[1]; ptm = p[2];
- break;
- }
-
- if( pty+ptm > 100 ) {
- errno = ERANGE;
- perror( "KCONFIG_PROBABILITY" );
- exit( 1 );
- }
- }
- bool has_changed = false;
-
- for_all_symbols(i, sym) {
- if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
- continue;
- switch (sym_get_type(sym)) {
- case S_BOOLEAN:
- case S_TRISTATE:
- has_changed = true;
- switch (mode) {
- case def_yes:
- sym->def[S_DEF_USER].tri = yes;
- break;
- case def_mod:
- sym->def[S_DEF_USER].tri = mod;
- break;
- case def_no:
- if (sym->flags & SYMBOL_ALLNOCONFIG_Y)
- sym->def[S_DEF_USER].tri = yes;
- else
- sym->def[S_DEF_USER].tri = no;
- break;
- case def_random:
- sym->def[S_DEF_USER].tri = no;
- cnt = rand() % 100;
- if (sym->type == S_TRISTATE) {
- if (cnt < pty)
- sym->def[S_DEF_USER].tri = yes;
- else if (cnt < (pty+ptm))
- sym->def[S_DEF_USER].tri = mod;
- } else if (cnt < pby)
- sym->def[S_DEF_USER].tri = yes;
- break;
- default:
- continue;
- }
- if (!(sym_is_choice(sym) && mode == def_random))
- sym->flags |= SYMBOL_DEF_USER;
- break;
- default:
- break;
- }
-
- }
-
- sym_clear_all_valid();
-
- /*
- * We have different type of choice blocks.
- * If curr.tri equals to mod then we can select several
- * choice symbols in one block.
- * In this case we do nothing.
- * If curr.tri equals yes then only one symbol can be
- * selected in a choice block and we set it to yes,
- * and the rest to no.
- */
- if (mode != def_random) {
- for_all_symbols(i, csym) {
- if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
- sym_is_choice_value(csym))
- csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
- }
- }
-
- for_all_symbols(i, csym) {
- if (sym_has_value(csym) || !sym_is_choice(csym))
- continue;
-
- sym_calc_value(csym);
- if (mode == def_random)
- has_changed |= randomize_choice_values(csym);
- else {
- set_all_choice_values(csym);
- has_changed = true;
- }
- }
-
- return has_changed;
-}
-
-void conf_rewrite_mod_or_yes(enum conf_def_mode mode)
-{
- struct symbol *sym;
- int i;
- tristate old_val = (mode == def_y2m) ? yes : mod;
- tristate new_val = (mode == def_y2m) ? mod : yes;
-
- for_all_symbols(i, sym) {
- if (sym_get_type(sym) == S_TRISTATE &&
- sym->def[S_DEF_USER].tri == old_val)
- sym->def[S_DEF_USER].tri = new_val;
- }
- sym_clear_all_valid();
-}
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 5c3443692f34..9c9caca5bd5f 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -156,9 +156,6 @@ struct symbol {
/* choice values need to be set before calculating this symbol value */
#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000
-/* Set symbol to y if allnoconfig; used for symbols that hide others */
-#define SYMBOL_ALLNOCONFIG_Y 0x200000
-
#define SYMBOL_MAXLENGTH 256
#define SYMBOL_HASHSIZE 9973
@@ -281,15 +278,12 @@ struct jump_key {
int index;
};
-#define JUMP_NB 9
-
extern struct file *file_list;
extern struct file *current_file;
struct file *lookup_file(const char *name);
extern struct symbol symbol_yes, symbol_no, symbol_mod;
extern struct symbol *modules_sym;
-extern struct symbol *sym_defconfig_list;
extern int cdebug;
struct expr *expr_alloc_symbol(struct symbol *sym);
struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
diff --git a/scripts/kconfig/gconf-cfg.sh b/scripts/kconfig/gconf-cfg.sh
index 480ecd8b9f41..040d8f338820 100755
--- a/scripts/kconfig/gconf-cfg.sh
+++ b/scripts/kconfig/gconf-cfg.sh
@@ -1,16 +1,19 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+cflags=$1
+libs=$2
+
PKG="gtk+-2.0 gmodule-2.0 libglade-2.0"
-if [ -z "$(command -v pkg-config)" ]; then
+if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then
echo >&2 "*"
- echo >&2 "* 'make gconfig' requires 'pkg-config'. Please install it."
+ echo >&2 "* 'make gconfig' requires '${HOSTPKG_CONFIG}'. Please install it."
echo >&2 "*"
exit 1
fi
-if ! pkg-config --exists $PKG; then
+if ! ${HOSTPKG_CONFIG} --exists $PKG; then
echo >&2 "*"
echo >&2 "* Unable to find the GTK+ installation. Please make sure that"
echo >&2 "* the GTK+ 2.0 development package is correctly installed."
@@ -19,12 +22,12 @@ if ! pkg-config --exists $PKG; then
exit 1
fi
-if ! pkg-config --atleast-version=2.0.0 gtk+-2.0; then
+if ! ${HOSTPKG_CONFIG} --atleast-version=2.0.0 gtk+-2.0; then
echo >&2 "*"
echo >&2 "* GTK+ is present but version >= 2.0.0 is required."
echo >&2 "*"
exit 1
fi
-echo cflags=\"$(pkg-config --cflags $PKG)\"
-echo libs=\"$(pkg-config --libs $PKG)\"
+${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags}
+${HOSTPKG_CONFIG} --libs ${PKG} > ${libs}
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index 5527482c3077..9709aca3a30f 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -3,10 +3,6 @@
* Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
*/
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include <stdlib.h>
#include "lkc.h"
#include "images.h"
@@ -640,7 +636,7 @@ void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
GtkWidget *dialog;
const gchar *intro_text =
- "Welcome to gkc, the GTK+ graphical configuration tool\n"
+ "Welcome to gconfig, the GTK+ graphical configuration tool.\n"
"For each option, a blank box indicates the feature is disabled, a\n"
"check indicates it is enabled, and a dot indicates that it is to\n"
"be compiled as a module. Clicking on the box will cycle through the three states.\n"
@@ -651,10 +647,7 @@ void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
"Although there is no cross reference yet to help you figure out\n"
"what other options must be enabled to support the option you\n"
"are interested in, you can still view the help of a grayed-out\n"
- "option.\n"
- "\n"
- "Toggling Show Debug Info under the Options menu will show \n"
- "the dependencies, which you can then match by examining other options.";
+ "option.";
dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -671,7 +664,7 @@ void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
GtkWidget *dialog;
const gchar *about_text =
- "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
+ "gconfig is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
"Based on the source code from Roman Zippel.\n";
dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
@@ -689,7 +682,7 @@ void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
{
GtkWidget *dialog;
const gchar *license_text =
- "gkc is released under the terms of the GNU GPL v2.\n"
+ "gconfig is released under the terms of the GNU GPL v2.\n"
"For more information, please see the source code or\n"
"visit http://www.fsf.org/licenses/licenses.html\n";
@@ -1048,8 +1041,13 @@ static gchar **fill_row(struct menu *menu)
g_free(row[i]);
bzero(row, sizeof(row));
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+
row[COL_OPTION] =
- g_strdup_printf("%s %s", menu_get_prompt(menu),
+ g_strdup_printf("%s %s %s %s",
+ ptype == P_COMMENT ? "***" : "",
+ menu_get_prompt(menu),
+ ptype == P_COMMENT ? "***" : "",
sym && !sym_has_value(sym) ? "(NEW)" : "");
if (opt_mode == OPT_ALL && !menu_is_visible(menu))
@@ -1060,7 +1058,6 @@ static gchar **fill_row(struct menu *menu)
else
row[COL_COLOR] = g_strdup("Black");
- ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
switch (ptype) {
case P_MENU:
row[COL_PIXBUF] = (gchar *) xpm_menu;
@@ -1452,9 +1449,6 @@ int main(int ac, char *av[])
gtk_init(&ac, &av);
glade_init();
- //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
- //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
-
/* Determine GUI path */
env = getenv(SRCTREE);
if (env)
diff --git a/scripts/kconfig/internal.h b/scripts/kconfig/internal.h
new file mode 100644
index 000000000000..2f7298c21b64
--- /dev/null
+++ b/scripts/kconfig/internal.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef INTERNAL_H
+#define INTERNAL_H
+
+struct menu;
+
+extern struct menu *current_menu, *current_entry;
+
+#endif /* INTERNAL_H */
diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l
index 9c22cb554673..cc386e443683 100644
--- a/scripts/kconfig/lexer.l
+++ b/scripts/kconfig/lexer.l
@@ -84,14 +84,12 @@ static void warn_ignored_character(char chr)
n [A-Za-z0-9_-]
%%
- int str = 0;
- int ts, i;
+ char open_quote = 0;
#.* /* ignore comment */
[ \t]* /* whitespaces */
\\\n /* escaped new line */
\n return T_EOL;
-"allnoconfig_y" return T_ALLNOCONFIG_Y;
"bool" return T_BOOL;
"choice" return T_CHOICE;
"comment" return T_COMMENT;
@@ -99,7 +97,6 @@ n [A-Za-z0-9_-]
"def_bool" return T_DEF_BOOL;
"def_tristate" return T_DEF_TRISTATE;
"default" return T_DEFAULT;
-"defconfig_list" return T_DEFCONFIG_LIST;
"depends" return T_DEPENDS;
"endchoice" return T_ENDCHOICE;
"endif" return T_ENDIF;
@@ -114,7 +111,6 @@ n [A-Za-z0-9_-]
"menuconfig" return T_MENUCONFIG;
"modules" return T_MODULES;
"on" return T_ON;
-"option" return T_OPTION;
"optional" return T_OPTIONAL;
"prompt" return T_PROMPT;
"range" return T_RANGE;
@@ -137,7 +133,7 @@ n [A-Za-z0-9_-]
":=" return T_COLON_EQUAL;
"+=" return T_PLUS_EQUAL;
\"|\' {
- str = yytext[0];
+ open_quote = yytext[0];
new_string();
BEGIN(STRING);
}
@@ -174,7 +170,7 @@ n [A-Za-z0-9_-]
append_string(yytext + 1, yyleng - 1);
}
\'|\" {
- if (str == yytext[0]) {
+ if (open_quote == yytext[0]) {
BEGIN(INITIAL);
yylval.string = text;
return T_WORD_QUOTE;
@@ -199,6 +195,8 @@ n [A-Za-z0-9_-]
<HELP>{
[ \t]+ {
+ int ts, i;
+
ts = 0;
for (i = 0; i < yyleng; i++) {
if (yytext[i] == '\t')
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index bee2413bda63..e7118d62a45f 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -20,10 +20,6 @@ extern "C" {
#define SRCTREE "srctree"
-#ifndef PACKAGE
-#define PACKAGE "linux"
-#endif
-
#ifndef CONFIG_
#define CONFIG_ "CONFIG_"
#endif
@@ -34,16 +30,6 @@ static inline const char *CONFIG_prefix(void)
#undef CONFIG_
#define CONFIG_ CONFIG_prefix()
-enum conf_def_mode {
- def_default,
- def_yes,
- def_mod,
- def_y2m,
- def_m2y,
- def_no,
- def_random
-};
-
extern int yylineno;
void zconfdump(FILE *out);
void zconf_starthelp(void);
@@ -55,10 +41,6 @@ const char *zconf_curname(void);
/* confdata.c */
const char *conf_get_configname(void);
-void sym_set_change_count(int count);
-void sym_add_change_count(int count);
-bool conf_set_all_new_symbols(enum conf_def_mode mode);
-void conf_rewrite_mod_or_yes(enum conf_def_mode mode);
void set_all_choice_values(struct symbol *csym);
/* confdata.c and expr.c */
@@ -94,7 +76,7 @@ struct gstr str_new(void);
void str_free(struct gstr *gs);
void str_append(struct gstr *gs, const char *s);
void str_printf(struct gstr *gs, const char *fmt, ...);
-const char *str_get(struct gstr *gs);
+char *str_get(struct gstr *gs);
/* menu.c */
void _menu_init(void);
@@ -107,9 +89,6 @@ void menu_add_visibility(struct expr *dep);
struct property *menu_add_prompt(enum prop_type type, 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_add_option_modules(void);
-void menu_add_option_defconfig_list(void);
-void menu_add_option_allnoconfig_y(void);
void menu_finalize(struct menu *parent);
void menu_set_type(int type);
@@ -119,7 +98,6 @@ bool menu_is_empty(struct menu *menu);
bool menu_is_visible(struct menu *menu);
bool menu_has_prompt(struct menu *menu);
const char *menu_get_prompt(struct menu *menu);
-struct menu *menu_get_root_menu(struct menu *menu);
struct menu *menu_get_parent_menu(struct menu *menu);
bool menu_has_help(struct menu *menu);
const char *menu_get_help(struct menu *menu);
@@ -145,11 +123,6 @@ static inline struct symbol *sym_get_choice_value(struct symbol *sym)
return (struct symbol *)sym->curr.val;
}
-static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
-{
- return sym_set_tristate_value(chval, yes);
-}
-
static inline bool sym_is_choice(struct symbol *sym)
{
return sym->flags & SYMBOL_CHOICE ? true : false;
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 9e81be33c40f..edd1e617b25c 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -8,6 +8,7 @@ int conf_read_simple(const char *name, int);
int conf_write_defconfig(const char *name);
int conf_write(const char *name);
int conf_write_autoconf(int overwrite);
+void conf_set_changed(bool val);
bool conf_get_changed(void);
void conf_set_changed_callback(void (*fn)(void));
void conf_set_message_callback(void (*fn)(const char *s));
@@ -17,7 +18,7 @@ extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
struct symbol * sym_lookup(const char *name, int flags);
struct symbol * sym_find(const char *name);
-const char * sym_escape_string_value(const char *in);
+void print_symbol_for_listconfig(struct symbol *sym);
struct symbol ** sym_re_search(const char *pattern);
const char * sym_type_name(enum symbol_type type);
void sym_calc_value(struct symbol *sym);
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index 68b565e3c495..347daf25fdc8 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -18,22 +18,6 @@
#endif
#include <ncurses.h>
-/*
- * Colors in ncurses 1.9.9e do not work properly since foreground and
- * background colors are OR'd rather than separately masked. This version
- * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
- * with standard curses. The simplest fix (to make this work with standard
- * curses) uses the wbkgdset() function, not used in the original hack.
- * Turn it off if we're building with 1.9.9e, since it just confuses things.
- */
-#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
-#define OLD_NCURSES 1
-#undef wbkgdset
-#define wbkgdset(w,p) /*nothing */
-#else
-#define OLD_NCURSES 0
-#endif
-
#define TR(params) _tracef params
#define KEY_ESC 27
@@ -225,14 +209,3 @@ int dialog_checklist(const char *title, const char *prompt, int height,
int width, int list_height);
int dialog_inputbox(const char *title, const char *prompt, int height,
int width, const char *init);
-
-/*
- * This is the base for fictitious keys, which activate
- * the buttons.
- *
- * Mouse-generated keys are the following:
- * -- the first 32 are used as numbers, in addition to '0'-'9'
- * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
- * -- uppercase chars are used to invoke the button (M_EVENT + 'O')
- */
-#define M_EVENT (KEY_MAX+1)
diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c
index 58c2f8afe59b..0e333284e947 100644
--- a/scripts/kconfig/lxdialog/menubox.c
+++ b/scripts/kconfig/lxdialog/menubox.c
@@ -63,15 +63,7 @@ static void do_print_item(WINDOW * win, const char *item, int line_y,
/* Clear 'residue' of last item */
wattrset(win, dlg.menubox.atr);
wmove(win, line_y, 0);
-#if OLD_NCURSES
- {
- int i;
- for (i = 0; i < menu_width; i++)
- waddch(win, ' ');
- }
-#else
wclrtoeol(win);
-#endif
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
mvwaddstr(win, line_y, item_x, menu_item);
if (hotkey) {
diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c
index 4e339b12664e..bc4d4fb1dc75 100644
--- a/scripts/kconfig/lxdialog/textbox.c
+++ b/scripts/kconfig/lxdialog/textbox.c
@@ -8,19 +8,137 @@
#include "dialog.h"
-static void back_lines(int n);
-static void print_page(WINDOW *win, int height, int width, update_text_fn
- update_text, void *data);
-static void print_line(WINDOW *win, int row, int width);
-static char *get_line(void);
-static void print_position(WINDOW * win);
-
static int hscroll;
static int begin_reached, end_reached, page_length;
static char *buf;
static char *page;
/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+ int i;
+
+ begin_reached = 0;
+ /* Go back 'n' lines */
+ for (i = 0; i < n; i++) {
+ if (*page == '\0') {
+ if (end_reached) {
+ end_reached = 0;
+ continue;
+ }
+ }
+ if (page == buf) {
+ begin_reached = 1;
+ return;
+ }
+ page--;
+ do {
+ if (page == buf) {
+ begin_reached = 1;
+ return;
+ }
+ page--;
+ } while (*page != '\n');
+ page++;
+ }
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+ int i = 0;
+ static char line[MAX_LEN + 1];
+
+ end_reached = 0;
+ while (*page != '\n') {
+ if (*page == '\0') {
+ end_reached = 1;
+ break;
+ } else if (i < MAX_LEN)
+ line[i++] = *(page++);
+ else {
+ /* Truncate lines longer than MAX_LEN characters */
+ if (i == MAX_LEN)
+ line[i++] = '\0';
+ page++;
+ }
+ }
+ if (i <= MAX_LEN)
+ line[i] = '\0';
+ if (!end_reached)
+ page++; /* move past '\n' */
+
+ return line;
+}
+
+/*
+ * Print a new line of text.
+ */
+static void print_line(WINDOW *win, int row, int width)
+{
+ char *line;
+
+ line = get_line();
+ line += MIN(strlen(line), hscroll); /* Scroll horizontally */
+ wmove(win, row, 0); /* move cursor to correct line */
+ waddch(win, ' ');
+ waddnstr(win, line, MIN(strlen(line), width - 2));
+
+ /* Clear 'residue' of previous line */
+ wclrtoeol(win);
+}
+
+/*
+ * Print a new page of text.
+ */
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+ update_text, void *data)
+{
+ int i, passed_end = 0;
+
+ if (update_text) {
+ char *end;
+
+ for (i = 0; i < height; i++)
+ get_line();
+ end = page;
+ back_lines(height);
+ update_text(buf, page - buf, end - buf, data);
+ }
+
+ page_length = 0;
+ for (i = 0; i < height; i++) {
+ print_line(win, i, width);
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+ wnoutrefresh(win);
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW *win)
+{
+ int percent;
+
+ wattrset(win, dlg.position_indicator.atr);
+ wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+ percent = (page - buf) * 100 / strlen(buf);
+ wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+ wprintw(win, "(%3d%%)", percent);
+}
+
+/*
* refresh window content
*/
static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
@@ -33,7 +151,6 @@ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
wrefresh(dialog);
}
-
/*
* Display text from a file in a dialog box.
*
@@ -259,137 +376,3 @@ do_resize:
*_hscroll = hscroll;
return key;
}
-
-/*
- * Go back 'n' lines in text. Called by dialog_textbox().
- * 'page' will be updated to point to the desired line in 'buf'.
- */
-static void back_lines(int n)
-{
- int i;
-
- begin_reached = 0;
- /* Go back 'n' lines */
- for (i = 0; i < n; i++) {
- if (*page == '\0') {
- if (end_reached) {
- end_reached = 0;
- continue;
- }
- }
- if (page == buf) {
- begin_reached = 1;
- return;
- }
- page--;
- do {
- if (page == buf) {
- begin_reached = 1;
- return;
- }
- page--;
- } while (*page != '\n');
- page++;
- }
-}
-
-/*
- * Print a new page of text.
- */
-static void print_page(WINDOW *win, int height, int width, update_text_fn
- update_text, void *data)
-{
- int i, passed_end = 0;
-
- if (update_text) {
- char *end;
-
- for (i = 0; i < height; i++)
- get_line();
- end = page;
- back_lines(height);
- update_text(buf, page - buf, end - buf, data);
- }
-
- page_length = 0;
- for (i = 0; i < height; i++) {
- print_line(win, i, width);
- if (!passed_end)
- page_length++;
- if (end_reached && !passed_end)
- passed_end = 1;
- }
- wnoutrefresh(win);
-}
-
-/*
- * Print a new line of text.
- */
-static void print_line(WINDOW * win, int row, int width)
-{
- char *line;
-
- line = get_line();
- line += MIN(strlen(line), hscroll); /* Scroll horizontally */
- wmove(win, row, 0); /* move cursor to correct line */
- waddch(win, ' ');
- waddnstr(win, line, MIN(strlen(line), width - 2));
-
- /* Clear 'residue' of previous line */
-#if OLD_NCURSES
- {
- int x = getcurx(win);
- int i;
- for (i = 0; i < width - x; i++)
- waddch(win, ' ');
- }
-#else
- wclrtoeol(win);
-#endif
-}
-
-/*
- * Return current line of text. Called by dialog_textbox() and print_line().
- * 'page' should point to start of current line before calling, and will be
- * updated to point to start of next line.
- */
-static char *get_line(void)
-{
- int i = 0;
- static char line[MAX_LEN + 1];
-
- end_reached = 0;
- while (*page != '\n') {
- if (*page == '\0') {
- end_reached = 1;
- break;
- } else if (i < MAX_LEN)
- line[i++] = *(page++);
- else {
- /* Truncate lines longer than MAX_LEN characters */
- if (i == MAX_LEN)
- line[i++] = '\0';
- page++;
- }
- }
- if (i <= MAX_LEN)
- line[i] = '\0';
- if (!end_reached)
- page++; /* move past '\n' */
-
- return line;
-}
-
-/*
- * Print current position
- */
-static void print_position(WINDOW * win)
-{
- int percent;
-
- wattrset(win, dlg.position_indicator.atr);
- wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
- percent = (page - buf) * 100 / strlen(buf);
- wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
- wprintw(win, "(%3d%%)", percent);
-}
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
index 1b490d4af0d3..3f78fb265136 100644
--- a/scripts/kconfig/lxdialog/util.c
+++ b/scripts/kconfig/lxdialog/util.c
@@ -363,7 +363,7 @@ void print_title(WINDOW *dialog, const char *title, int width)
/*
* Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
- * characters '\n' are propperly processed. We start on a new line
+ * characters '\n' are properly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*/
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
@@ -541,7 +541,7 @@ int first_alpha(const char *string, const char *exempt)
* lxdialog suggest <ESC> <ESC> which is correctly translated to two
* times esc. But then we need to ignore the second esc to avoid stepping
* out one menu too much. Filter away all escaped key sequences since
- * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * keypad(FALSE) turn off ncurses support for escape sequences - and that's
* needed to make notimeout() do as expected.
*/
int on_key_esc(WINDOW *win)
diff --git a/scripts/kconfig/mconf-cfg.sh b/scripts/kconfig/mconf-cfg.sh
index b520e407a8eb..1e61f50a5905 100755
--- a/scripts/kconfig/mconf-cfg.sh
+++ b/scripts/kconfig/mconf-cfg.sh
@@ -1,19 +1,22 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+cflags=$1
+libs=$2
+
PKG="ncursesw"
PKG2="ncurses"
-if [ -n "$(command -v pkg-config)" ]; then
- if pkg-config --exists $PKG; then
- echo cflags=\"$(pkg-config --cflags $PKG)\"
- echo libs=\"$(pkg-config --libs $PKG)\"
+if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then
+ if ${HOSTPKG_CONFIG} --exists $PKG; then
+ ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags}
+ ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs}
exit 0
fi
- if pkg-config --exists $PKG2; then
- echo cflags=\"$(pkg-config --cflags $PKG2)\"
- echo libs=\"$(pkg-config --libs $PKG2)\"
+ if ${HOSTPKG_CONFIG} --exists ${PKG2}; then
+ ${HOSTPKG_CONFIG} --cflags ${PKG2} > ${cflags}
+ ${HOSTPKG_CONFIG} --libs ${PKG2} > ${libs}
exit 0
fi
fi
@@ -22,22 +25,22 @@ fi
# (Even if it is installed, some distributions such as openSUSE cannot
# find ncurses by pkg-config.)
if [ -f /usr/include/ncursesw/ncurses.h ]; then
- echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\"
- echo libs=\"-lncursesw\"
+ echo -D_GNU_SOURCE -I/usr/include/ncursesw > ${cflags}
+ echo -lncursesw > ${libs}
exit 0
fi
if [ -f /usr/include/ncurses/ncurses.h ]; then
- echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\"
- echo libs=\"-lncurses\"
+ echo -D_GNU_SOURCE -I/usr/include/ncurses > ${cflags}
+ echo -lncurses > ${libs}
exit 0
fi
# As a final fallback before giving up, check if $HOSTCC knows of a default
# ncurses installation (e.g. from a vendor-specific sysroot).
if echo '#include <ncurses.h>' | ${HOSTCC} -E - >/dev/null 2>&1; then
- echo cflags=\"-D_GNU_SOURCE\"
- echo libs=\"-lncurses\"
+ echo -D_GNU_SOURCE > ${cflags}
+ echo -lncurses > ${libs}
exit 0
fi
@@ -46,7 +49,7 @@ echo >&2 "* Unable to find the ncurses package."
echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
echo >&2 "* depending on your distribution)."
echo >&2 "*"
-echo >&2 "* You may also need to install pkg-config to find the"
+echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the"
echo >&2 "* ncurses installed in a non-default location."
echo >&2 "*"
exit 1
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 4063dbc1b927..53d8834d12fe 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -22,6 +22,8 @@
#include "lkc.h"
#include "lxdialog/dialog.h"
+#define JUMP_NB 9
+
static const char mconf_readme[] =
"Overview\n"
"--------\n"
@@ -159,6 +161,12 @@ static const char mconf_readme[] =
"(especially with a larger number of unrolled categories) than the\n"
"default mode.\n"
"\n"
+
+"Search\n"
+"-------\n"
+"Pressing the forward-slash (/) anywhere brings up a search dialog box.\n"
+"\n"
+
"Different color themes available\n"
"--------------------------------\n"
"It is possible to select different color themes using the variable\n"
@@ -282,32 +290,17 @@ static int save_and_exit;
static int silent;
static void conf(struct menu *menu, struct menu *active_menu);
-static void conf_choice(struct menu *menu);
-static void conf_string(struct menu *menu);
-static void conf_load(void);
-static void conf_save(void);
-static int show_textbox_ext(const char *title, char *text, int r, int c,
- int *keys, int *vscroll, int *hscroll,
- update_text_fn update_text, void *data);
-static void show_textbox(const char *title, const char *text, int r, int c);
-static void show_helptext(const char *title, const char *text);
-static void show_help(struct menu *menu);
static char filename[PATH_MAX+1];
static void set_config_filename(const char *config_filename)
{
static char menu_backtitle[PATH_MAX+128];
- int size;
- size = snprintf(menu_backtitle, sizeof(menu_backtitle),
- "%s - %s", config_filename, rootmenu.prompt->text);
- if (size >= sizeof(menu_backtitle))
- menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+ snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s",
+ config_filename, rootmenu.prompt->text);
set_dialog_backtitle(menu_backtitle);
- size = snprintf(filename, sizeof(filename), "%s", config_filename);
- if (size >= sizeof(filename))
- filename[sizeof(filename)-1] = '\0';
+ snprintf(filename, sizeof(filename), "%s", config_filename);
}
struct subtitle_part {
@@ -355,6 +348,37 @@ static void reset_subtitle(void)
set_dialog_subtitles(subtitles);
}
+static int show_textbox_ext(const char *title, char *text, int r, int c, int
+ *keys, int *vscroll, int *hscroll, update_text_fn
+ update_text, void *data)
+{
+ dialog_clear();
+ return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
+ update_text, data);
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+ show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
+ NULL, NULL);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+ show_textbox(title, text, 0, 0);
+}
+
+static void show_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ help.max_width = getmaxx(stdscr) - 10;
+ menu_get_ext_help(menu, &help);
+
+ show_helptext(menu_get_prompt(menu), str_get(&help));
+ str_free(&help);
+}
+
struct search_data {
struct list_head *head;
struct menu **targets;
@@ -443,9 +467,8 @@ again:
res = get_relations_str(sym_arr, &head);
set_subtitle();
- dres = show_textbox_ext("Search Results", (char *)
- str_get(&res), 0, 0, keys, &vscroll,
- &hscroll, &update_text, (void *)
+ dres = show_textbox_ext("Search Results", str_get(&res), 0, 0,
+ keys, &vscroll, &hscroll, &update_text,
&data);
again = false;
for (i = 0; i < JUMP_NB && keys[i]; i++)
@@ -641,158 +664,6 @@ conf_childs:
indent -= doint;
}
-static void conf(struct menu *menu, struct menu *active_menu)
-{
- struct menu *submenu;
- const char *prompt = menu_get_prompt(menu);
- struct subtitle_part stpart;
- struct symbol *sym;
- int res;
- int s_scroll = 0;
-
- if (menu != &rootmenu)
- stpart.text = menu_get_prompt(menu);
- else
- stpart.text = NULL;
- list_add_tail(&stpart.entries, &trail);
-
- while (1) {
- item_reset();
- current_menu = menu;
- build_conf(menu);
- if (!child_count)
- break;
- set_subtitle();
- dialog_clear();
- res = dialog_menu(prompt ? prompt : "Main Menu",
- menu_instructions,
- active_menu, &s_scroll);
- if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
- break;
- if (item_count() != 0) {
- if (!item_activate_selected())
- continue;
- if (!item_tag())
- continue;
- }
- submenu = item_data();
- active_menu = item_data();
- if (submenu)
- sym = submenu->sym;
- else
- sym = NULL;
-
- switch (res) {
- case 0:
- switch (item_tag()) {
- case 'm':
- if (single_menu_mode)
- submenu->data = (void *) (long) !submenu->data;
- else
- conf(submenu, NULL);
- break;
- case 't':
- if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
- conf_choice(submenu);
- else if (submenu->prompt->type == P_MENU)
- conf(submenu, NULL);
- break;
- case 's':
- conf_string(submenu);
- break;
- }
- break;
- case 2:
- if (sym)
- show_help(submenu);
- else {
- reset_subtitle();
- show_helptext("README", mconf_readme);
- }
- break;
- case 3:
- reset_subtitle();
- conf_save();
- break;
- case 4:
- reset_subtitle();
- conf_load();
- break;
- case 5:
- if (item_is_tag('t')) {
- if (sym_set_tristate_value(sym, yes))
- break;
- if (sym_set_tristate_value(sym, mod))
- show_textbox(NULL, setmod_text, 6, 74);
- }
- break;
- case 6:
- if (item_is_tag('t'))
- sym_set_tristate_value(sym, no);
- break;
- case 7:
- if (item_is_tag('t'))
- sym_set_tristate_value(sym, mod);
- break;
- case 8:
- if (item_is_tag('t'))
- sym_toggle_tristate_value(sym);
- else if (item_is_tag('m'))
- conf(submenu, NULL);
- break;
- case 9:
- search_conf();
- break;
- case 10:
- show_all_options = !show_all_options;
- break;
- }
- }
-
- list_del(trail.prev);
-}
-
-static int show_textbox_ext(const char *title, char *text, int r, int c, int
- *keys, int *vscroll, int *hscroll, update_text_fn
- update_text, void *data)
-{
- dialog_clear();
- return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
- update_text, data);
-}
-
-static void show_textbox(const char *title, const char *text, int r, int c)
-{
- show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
- NULL, NULL);
-}
-
-static void show_helptext(const char *title, const char *text)
-{
- show_textbox(title, text, 0, 0);
-}
-
-static void conf_message_callback(const char *s)
-{
- if (save_and_exit) {
- if (!silent)
- printf("%s", s);
- } else {
- show_textbox(NULL, s, 6, 60);
- }
-}
-
-static void show_help(struct menu *menu)
-{
- struct gstr help = str_new();
-
- help.max_width = getmaxx(stdscr) - 10;
- menu_get_ext_help(menu, &help);
-
- show_helptext(menu_get_prompt(menu), str_get(&help));
- str_free(&help);
-}
-
static void conf_choice(struct menu *menu)
{
const char *prompt = menu_get_prompt(menu);
@@ -908,7 +779,7 @@ static void conf_load(void)
return;
if (!conf_read(dialog_input_result)) {
set_config_filename(dialog_input_result);
- sym_set_change_count(1);
+ conf_set_changed(true);
return;
}
show_textbox(NULL, "File does not exist!", 5, 38);
@@ -948,6 +819,127 @@ static void conf_save(void)
}
}
+static void conf(struct menu *menu, struct menu *active_menu)
+{
+ struct menu *submenu;
+ const char *prompt = menu_get_prompt(menu);
+ struct subtitle_part stpart;
+ struct symbol *sym;
+ int res;
+ int s_scroll = 0;
+
+ if (menu != &rootmenu)
+ stpart.text = menu_get_prompt(menu);
+ else
+ stpart.text = NULL;
+ list_add_tail(&stpart.entries, &trail);
+
+ while (1) {
+ item_reset();
+ current_menu = menu;
+ build_conf(menu);
+ if (!child_count)
+ break;
+ set_subtitle();
+ dialog_clear();
+ res = dialog_menu(prompt ? prompt : "Main Menu",
+ menu_instructions,
+ active_menu, &s_scroll);
+ if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+ break;
+ if (item_count() != 0) {
+ if (!item_activate_selected())
+ continue;
+ if (!item_tag())
+ continue;
+ }
+ submenu = item_data();
+ active_menu = item_data();
+ if (submenu)
+ sym = submenu->sym;
+ else
+ sym = NULL;
+
+ switch (res) {
+ case 0:
+ switch (item_tag()) {
+ case 'm':
+ if (single_menu_mode)
+ submenu->data = (void *) (long) !submenu->data;
+ else
+ conf(submenu, NULL);
+ break;
+ case 't':
+ if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+ conf_choice(submenu);
+ else if (submenu->prompt->type == P_MENU)
+ conf(submenu, NULL);
+ break;
+ case 's':
+ conf_string(submenu);
+ break;
+ }
+ break;
+ case 2:
+ if (sym)
+ show_help(submenu);
+ else {
+ reset_subtitle();
+ show_helptext("README", mconf_readme);
+ }
+ break;
+ case 3:
+ reset_subtitle();
+ conf_save();
+ break;
+ case 4:
+ reset_subtitle();
+ conf_load();
+ break;
+ case 5:
+ if (item_is_tag('t')) {
+ if (sym_set_tristate_value(sym, yes))
+ break;
+ if (sym_set_tristate_value(sym, mod))
+ show_textbox(NULL, setmod_text, 6, 74);
+ }
+ break;
+ case 6:
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, no);
+ break;
+ case 7:
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, mod);
+ break;
+ case 8:
+ if (item_is_tag('t'))
+ sym_toggle_tristate_value(sym);
+ else if (item_is_tag('m'))
+ conf(submenu, NULL);
+ break;
+ case 9:
+ search_conf();
+ break;
+ case 10:
+ show_all_options = !show_all_options;
+ break;
+ }
+ }
+
+ list_del(trail.prev);
+}
+
+static void conf_message_callback(const char *s)
+{
+ if (save_and_exit) {
+ if (!silent)
+ printf("%s", s);
+ } else {
+ show_textbox(NULL, s, 6, 60);
+ }
+}
+
static int handle_exit(void)
{
int res;
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index a5fbd6ccc006..b90fff833588 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -9,6 +9,7 @@
#include <string.h>
#include "lkc.h"
+#include "internal.h"
static const char nohelp_text[] = "There is no help available for this option.";
@@ -211,28 +212,6 @@ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
menu_add_prop(type, expr_alloc_symbol(sym), dep);
}
-void menu_add_option_modules(void)
-{
- if (modules_sym)
- zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'",
- current_entry->sym->name, modules_sym->name);
- modules_sym = current_entry->sym;
-}
-
-void menu_add_option_defconfig_list(void)
-{
- if (!sym_defconfig_list)
- sym_defconfig_list = current_entry->sym;
- else if (sym_defconfig_list != current_entry->sym)
- zconf_error("trying to redefine defconfig symbol");
- sym_defconfig_list->flags |= SYMBOL_NO_WRITE;
-}
-
-void menu_add_option_allnoconfig_y(void)
-{
- current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
-}
-
static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
{
return sym2->type == S_INT || sym2->type == S_HEX ||
@@ -682,11 +661,6 @@ const char *menu_get_prompt(struct menu *menu)
return NULL;
}
-struct menu *menu_get_root_menu(struct menu *menu)
-{
- return &rootmenu;
-}
-
struct menu *menu_get_parent_menu(struct menu *menu)
{
enum prop_type type;
@@ -748,27 +722,16 @@ static void get_prompt_str(struct gstr *r, struct property *prop,
if (!expr_eq(prop->menu->dep, prop->visible.expr))
get_dep_str(r, prop->visible.expr, " Visible if: ");
- menu = prop->menu->parent;
+ menu = prop->menu;
for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
- bool accessible = menu_is_visible(menu);
-
submenu[i++] = menu;
- if (location == NULL && accessible)
+ if (location == NULL && menu_is_visible(menu))
location = menu;
}
if (head && location) {
jump = xmalloc(sizeof(struct jump_key));
- if (menu_is_visible(prop->menu)) {
- /*
- * There is not enough room to put the hint at the
- * beginning of the "Prompt" line. Put the hint on the
- * last "Location" line even when it would belong on
- * the former.
- */
- jump->target = prop->menu;
- } else
- jump->target = location;
+ jump->target = location;
if (list_empty(head))
jump->index = 0;
@@ -779,21 +742,18 @@ static void get_prompt_str(struct gstr *r, struct property *prop,
list_add_tail(&jump->entries, head);
}
- if (i > 0) {
- str_printf(r, " Location:\n");
- for (j = 4; --i >= 0; j += 2) {
- menu = submenu[i];
- if (jump && menu == location)
- jump->offset = strlen(r->s);
- str_printf(r, "%*c-> %s", j, ' ',
- menu_get_prompt(menu));
- if (menu->sym) {
- str_printf(r, " (%s [=%s])", menu->sym->name ?
- menu->sym->name : "<choice>",
- sym_get_string_value(menu->sym));
- }
- str_append(r, "\n");
+ str_printf(r, " Location:\n");
+ for (j = 4; --i >= 0; j += 2) {
+ menu = submenu[i];
+ if (jump && menu == location)
+ jump->offset = strlen(r->s);
+ str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
+ if (menu->sym) {
+ str_printf(r, " (%s [=%s])", menu->sym->name ?
+ menu->sym->name : "<choice>",
+ sym_get_string_value(menu->sym));
}
+ str_append(r, "\n");
}
}
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 63c8565206a4..902eb429b9db 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -28,6 +28,8 @@ usage() {
echo " -r list redundant entries when merging fragments"
echo " -y make builtin have precedence over modules"
echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead."
+ echo " -s strict mode. Fail if the fragment redefines any value."
+ echo " -Q disable warning messages for overridden options."
echo
echo "Used prefix: '$CONFIG_PREFIX'. You can redefine it with \$CONFIG_ environment variable."
}
@@ -37,7 +39,9 @@ ALLTARGET=alldefconfig
WARNREDUN=false
BUILTIN=false
OUTPUT=.
+STRICT=false
CONFIG_PREFIX=${CONFIG_-CONFIG_}
+WARNOVERRIDE=echo
while true; do
case $1 in
@@ -75,6 +79,16 @@ while true; do
shift 2
continue
;;
+ "-s")
+ STRICT=true
+ shift
+ continue
+ ;;
+ "-Q")
+ WARNOVERRIDE=true
+ shift
+ continue
+ ;;
*)
break
;;
@@ -131,18 +145,21 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
NEW_VAL=$(grep -w $CFG $MERGE_FILE)
BUILTIN_FLAG=false
if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] && [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then
- echo Previous value: $PREV_VAL
- echo New value: $NEW_VAL
- echo -y passed, will not demote y to m
- echo
+ ${WARNOVERRIDE} Previous value: $PREV_VAL
+ ${WARNOVERRIDE} New value: $NEW_VAL
+ ${WARNOVERRIDE} -y passed, will not demote y to m
+ ${WARNOVERRIDE}
BUILTIN_FLAG=true
elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
- echo Value of $CFG is redefined by fragment $ORIG_MERGE_FILE:
- echo Previous value: $PREV_VAL
- echo New value: $NEW_VAL
- echo
+ ${WARNOVERRIDE} Value of $CFG is redefined by fragment $ORIG_MERGE_FILE:
+ ${WARNOVERRIDE} Previous value: $PREV_VAL
+ ${WARNOVERRIDE} New value: $NEW_VAL
+ ${WARNOVERRIDE}
+ if [ "$STRICT" = "true" ]; then
+ STRICT_MODE_VIOLATED=true
+ fi
elif [ "$WARNREDUN" = "true" ]; then
- echo Value of $CFG is redundant by fragment $ORIG_MERGE_FILE:
+ ${WARNOVERRIDE} Value of $CFG is redundant by fragment $ORIG_MERGE_FILE:
fi
if [ "$BUILTIN_FLAG" = "false" ]; then
sed -i "/$CFG[ =]/d" $TMP_FILE
@@ -153,6 +170,11 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
cat $MERGE_FILE >> $TMP_FILE
done
+if [ "$STRICT_MODE_VIOLATED" = "true" ]; then
+ echo "The fragment redefined a value and strict mode had been passed."
+ exit 1
+fi
+
if [ "$RUNMAKE" = "false" ]; then
cp -T -- "$TMP_FILE" "$KCONFIG_CONFIG"
echo "#"
diff --git a/scripts/kconfig/nconf-cfg.sh b/scripts/kconfig/nconf-cfg.sh
index c212255070c0..f871a2160e36 100755
--- a/scripts/kconfig/nconf-cfg.sh
+++ b/scripts/kconfig/nconf-cfg.sh
@@ -1,19 +1,22 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+cflags=$1
+libs=$2
+
PKG="ncursesw menuw panelw"
PKG2="ncurses menu panel"
-if [ -n "$(command -v pkg-config)" ]; then
- if pkg-config --exists $PKG; then
- echo cflags=\"$(pkg-config --cflags $PKG)\"
- echo libs=\"$(pkg-config --libs $PKG)\"
+if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then
+ if ${HOSTPKG_CONFIG} --exists $PKG; then
+ ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags}
+ ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs}
exit 0
fi
- if pkg-config --exists $PKG2; then
- echo cflags=\"$(pkg-config --cflags $PKG2)\"
- echo libs=\"$(pkg-config --libs $PKG2)\"
+ if ${HOSTPKG_CONFIG} --exists $PKG2; then
+ ${HOSTPKG_CONFIG} --cflags ${PKG2} > ${cflags}
+ ${HOSTPKG_CONFIG} --libs ${PKG2} > ${libs}
exit 0
fi
fi
@@ -22,20 +25,20 @@ fi
# (Even if it is installed, some distributions such as openSUSE cannot
# find ncurses by pkg-config.)
if [ -f /usr/include/ncursesw/ncurses.h ]; then
- echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\"
- echo libs=\"-lncursesw -lmenuw -lpanelw\"
+ echo -D_GNU_SOURCE -I/usr/include/ncursesw > ${cflags}
+ echo -lncursesw -lmenuw -lpanelw > ${libs}
exit 0
fi
if [ -f /usr/include/ncurses/ncurses.h ]; then
- echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\"
- echo libs=\"-lncurses -lmenu -lpanel\"
+ echo -D_GNU_SOURCE -I/usr/include/ncurses > ${cflags}
+ echo -lncurses -lmenu -lpanel > ${libs}
exit 0
fi
if [ -f /usr/include/ncurses.h ]; then
- echo cflags=\"-D_GNU_SOURCE\"
- echo libs=\"-lncurses -lmenu -lpanel\"
+ echo -D_GNU_SOURCE > ${cflags}
+ echo -lncurses -lmenu -lpanel > ${libs}
exit 0
fi
@@ -44,7 +47,7 @@ echo >&2 "* Unable to find the ncurses package."
echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
echo >&2 "* depending on your distribution)."
echo >&2 "*"
-echo >&2 "* You may also need to install pkg-config to find the"
+echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the"
echo >&2 "* ncurses installed in a non-default location."
echo >&2 "*"
exit 1
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
index e0f965529166..3ba8b1af390f 100644
--- a/scripts/kconfig/nconf.c
+++ b/scripts/kconfig/nconf.c
@@ -52,8 +52,8 @@ static const char nconf_global_help[] =
"\n"
"Menu navigation keys\n"
"----------------------------------------------------------------------\n"
-"Linewise up <Up>\n"
-"Linewise down <Down>\n"
+"Linewise up <Up> <k>\n"
+"Linewise down <Down> <j>\n"
"Pagewise up <Page Up>\n"
"Pagewise down <Page Down>\n"
"First entry <Home>\n"
@@ -268,7 +268,7 @@ static int mwin_max_cols;
static MENU *curses_menu;
static ITEM *curses_menu_items[MAX_MENU_ITEMS];
static struct mitem k_menu_items[MAX_MENU_ITEMS];
-static int items_num;
+static unsigned int items_num;
static int global_exit;
/* the currently selected button */
static const char *current_instructions = menu_instructions;
@@ -370,18 +370,18 @@ static void print_function_line(void)
int lines = getmaxy(stdscr);
for (i = 0; i < function_keys_num; i++) {
- (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+ wattrset(main_window, attr_function_highlight);
mvwprintw(main_window, lines-3, offset,
"%s",
function_keys[i].key_str);
- (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
+ wattrset(main_window, attr_function_text);
offset += strlen(function_keys[i].key_str);
mvwprintw(main_window, lines-3,
offset, "%s",
function_keys[i].func);
offset += strlen(function_keys[i].func) + skip;
}
- (void) wattrset(main_window, attributes[NORMAL]);
+ wattrset(main_window, attr_normal);
}
/* help */
@@ -496,16 +496,20 @@ typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
/* return the index of the matched item, or -1 if no such item exists */
static int get_mext_match(const char *match_str, match_f flag)
{
- int match_start = item_index(current_item(curses_menu));
- int index;
+ int match_start, index;
+
+ /* Do not search if the menu is empty (i.e. items_num == 0) */
+ match_start = item_index(current_item(curses_menu));
+ if (match_start == ERR)
+ return -1;
if (flag == FIND_NEXT_MATCH_DOWN)
++match_start;
else if (flag == FIND_NEXT_MATCH_UP)
--match_start;
+ match_start = (match_start + items_num) % items_num;
index = match_start;
- index = (index + items_num) % items_num;
while (true) {
char *str = k_menu_items[index].str;
if (strcasestr(str, match_str) != NULL)
@@ -627,19 +631,12 @@ static int item_is_tag(char tag)
static char filename[PATH_MAX+1];
static char menu_backtitle[PATH_MAX+128];
-static const char *set_config_filename(const char *config_filename)
+static void set_config_filename(const char *config_filename)
{
- int size;
+ snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s",
+ config_filename, rootmenu.prompt->text);
- size = snprintf(menu_backtitle, sizeof(menu_backtitle),
- "%s - %s", config_filename, rootmenu.prompt->text);
- if (size >= sizeof(menu_backtitle))
- menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
-
- size = snprintf(filename, sizeof(filename), "%s", config_filename);
- if (size >= sizeof(filename))
- filename[sizeof(filename)-1] = '\0';
- return menu_backtitle;
+ snprintf(filename, sizeof(filename), "%s", config_filename);
}
/* return = 0 means we are successful.
@@ -956,16 +953,15 @@ static void show_menu(const char *prompt, const char *instructions,
current_instructions = instructions;
clear();
- (void) wattrset(main_window, attributes[NORMAL]);
- print_in_middle(stdscr, 1, 0, getmaxx(stdscr),
+ print_in_middle(stdscr, 1, getmaxx(stdscr),
menu_backtitle,
- attributes[MAIN_HEADING]);
+ attr_main_heading);
- (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
+ wattrset(main_window, attr_main_menu_box);
box(main_window, 0, 0);
- (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+ wattrset(main_window, attr_main_menu_heading);
mvwprintw(main_window, 0, 3, " %s ", prompt);
- (void) wattrset(main_window, attributes[NORMAL]);
+ wattrset(main_window, attr_normal);
set_menu_items(curses_menu, curses_menu_items);
@@ -1068,7 +1064,6 @@ static int do_match(int key, struct match_state *state, int *ans)
static void conf(struct menu *menu)
{
struct menu *submenu = NULL;
- const char *prompt = menu_get_prompt(menu);
struct symbol *sym;
int res;
int current_index = 0;
@@ -1086,9 +1081,8 @@ static void conf(struct menu *menu)
if (!child_count)
break;
- show_menu(prompt ? prompt : "Main Menu",
- menu_instructions,
- current_index, &last_top_row);
+ show_menu(menu_get_prompt(menu), menu_instructions,
+ current_index, &last_top_row);
keypad((menu_win(curses_menu)), TRUE);
while (!global_exit) {
if (match_state.in_search) {
@@ -1111,9 +1105,11 @@ static void conf(struct menu *menu)
break;
switch (res) {
case KEY_DOWN:
+ case 'j':
menu_driver(curses_menu, REQ_DOWN_ITEM);
break;
case KEY_UP:
+ case 'k':
menu_driver(curses_menu, REQ_UP_ITEM);
break;
case KEY_NPAGE:
@@ -1293,9 +1289,11 @@ static void conf_choice(struct menu *menu)
break;
switch (res) {
case KEY_DOWN:
+ case 'j':
menu_driver(curses_menu, REQ_DOWN_ITEM);
break;
case KEY_UP:
+ case 'k':
menu_driver(curses_menu, REQ_UP_ITEM);
break;
case KEY_NPAGE:
@@ -1404,7 +1402,7 @@ static void conf_load(void)
return;
if (!conf_read(dialog_input_result)) {
set_config_filename(dialog_input_result);
- sym_set_change_count(1);
+ conf_set_changed(true);
return;
}
btn_dialog(main_window, "File does not exist!", 0);
@@ -1523,9 +1521,9 @@ int main(int ac, char **av)
menu_opts_on(curses_menu, O_NONCYCLIC);
menu_opts_on(curses_menu, O_IGNORECASE);
set_menu_mark(curses_menu, " ");
- set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
- set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
- set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
+ set_menu_fore(curses_menu, attr_main_menu_fore);
+ set_menu_back(curses_menu, attr_main_menu_back);
+ set_menu_grey(curses_menu, attr_main_menu_grey);
set_config_filename(conf_get_configname());
setup_windows();
diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c
index 77f525a8617c..9aedf40f1dc0 100644
--- a/scripts/kconfig/nconf.gui.c
+++ b/scripts/kconfig/nconf.gui.c
@@ -7,169 +7,120 @@
#include "nconf.h"
#include "lkc.h"
-/* a list of all the different widgets we use */
-attributes_t attributes[ATTR_MAX+1] = {0};
-
-/* available colors:
- COLOR_BLACK 0
- COLOR_RED 1
- COLOR_GREEN 2
- COLOR_YELLOW 3
- COLOR_BLUE 4
- COLOR_MAGENTA 5
- COLOR_CYAN 6
- COLOR_WHITE 7
- */
-static void set_normal_colors(void)
-{
- init_pair(NORMAL, -1, -1);
- init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
-
- /* FORE is for the selected item */
- init_pair(MAIN_MENU_FORE, -1, -1);
- /* BACK for all the rest */
- init_pair(MAIN_MENU_BACK, -1, -1);
- init_pair(MAIN_MENU_GREY, -1, -1);
- init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
- init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
-
- init_pair(SCROLLWIN_TEXT, -1, -1);
- init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
- init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
-
- init_pair(DIALOG_TEXT, -1, -1);
- init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
- init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
- init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
-
- init_pair(INPUT_BOX, COLOR_YELLOW, -1);
- init_pair(INPUT_HEADING, COLOR_GREEN, -1);
- init_pair(INPUT_TEXT, -1, -1);
- init_pair(INPUT_FIELD, -1, -1);
-
- init_pair(FUNCTION_HIGHLIGHT, -1, -1);
- init_pair(FUNCTION_TEXT, COLOR_YELLOW, -1);
-}
-
-/* available attributes:
- A_NORMAL Normal display (no highlight)
- A_STANDOUT Best highlighting mode of the terminal.
- A_UNDERLINE Underlining
- A_REVERSE Reverse video
- A_BLINK Blinking
- A_DIM Half bright
- A_BOLD Extra bright or bold
- A_PROTECT Protected mode
- A_INVIS Invisible or blank mode
- A_ALTCHARSET Alternate character set
- A_CHARTEXT Bit-mask to extract a character
- COLOR_PAIR(n) Color-pair number n
- */
-static void normal_color_theme(void)
-{
- /* automatically add color... */
-#define mkattr(name, attr) do { \
-attributes[name] = attr | COLOR_PAIR(name); } while (0)
- mkattr(NORMAL, NORMAL);
- mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
-
- mkattr(MAIN_MENU_FORE, A_REVERSE);
- mkattr(MAIN_MENU_BACK, A_NORMAL);
- mkattr(MAIN_MENU_GREY, A_NORMAL);
- mkattr(MAIN_MENU_HEADING, A_BOLD);
- mkattr(MAIN_MENU_BOX, A_NORMAL);
-
- mkattr(SCROLLWIN_TEXT, A_NORMAL);
- mkattr(SCROLLWIN_HEADING, A_BOLD);
- mkattr(SCROLLWIN_BOX, A_BOLD);
-
- mkattr(DIALOG_TEXT, A_BOLD);
- mkattr(DIALOG_BOX, A_BOLD);
- mkattr(DIALOG_MENU_FORE, A_STANDOUT);
- mkattr(DIALOG_MENU_BACK, A_NORMAL);
-
- mkattr(INPUT_BOX, A_NORMAL);
- mkattr(INPUT_HEADING, A_BOLD);
- mkattr(INPUT_TEXT, A_NORMAL);
- mkattr(INPUT_FIELD, A_UNDERLINE);
-
- mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
- mkattr(FUNCTION_TEXT, A_REVERSE);
-}
-
-static void no_colors_theme(void)
-{
- /* automatically add highlight, no color */
-#define mkattrn(name, attr) { attributes[name] = attr; }
-
- mkattrn(NORMAL, NORMAL);
- mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
-
- mkattrn(MAIN_MENU_FORE, A_STANDOUT);
- mkattrn(MAIN_MENU_BACK, A_NORMAL);
- mkattrn(MAIN_MENU_GREY, A_NORMAL);
- mkattrn(MAIN_MENU_HEADING, A_BOLD);
- mkattrn(MAIN_MENU_BOX, A_NORMAL);
-
- mkattrn(SCROLLWIN_TEXT, A_NORMAL);
- mkattrn(SCROLLWIN_HEADING, A_BOLD);
- mkattrn(SCROLLWIN_BOX, A_BOLD);
-
- mkattrn(DIALOG_TEXT, A_NORMAL);
- mkattrn(DIALOG_BOX, A_BOLD);
- mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
- mkattrn(DIALOG_MENU_BACK, A_NORMAL);
-
- mkattrn(INPUT_BOX, A_BOLD);
- mkattrn(INPUT_HEADING, A_BOLD);
- mkattrn(INPUT_TEXT, A_NORMAL);
- mkattrn(INPUT_FIELD, A_UNDERLINE);
-
- mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
- mkattrn(FUNCTION_TEXT, A_REVERSE);
-}
+int attr_normal;
+int attr_main_heading;
+int attr_main_menu_box;
+int attr_main_menu_fore;
+int attr_main_menu_back;
+int attr_main_menu_grey;
+int attr_main_menu_heading;
+int attr_scrollwin_text;
+int attr_scrollwin_heading;
+int attr_scrollwin_box;
+int attr_dialog_text;
+int attr_dialog_menu_fore;
+int attr_dialog_menu_back;
+int attr_dialog_box;
+int attr_input_box;
+int attr_input_heading;
+int attr_input_text;
+int attr_input_field;
+int attr_function_text;
+int attr_function_highlight;
+
+#define COLOR_ATTR(_at, _fg, _bg, _hl) \
+ { .attr = &(_at), .has_color = true, .color_fg = _fg, .color_bg = _bg, .highlight = _hl }
+#define NO_COLOR_ATTR(_at, _hl) \
+ { .attr = &(_at), .has_color = false, .highlight = _hl }
+#define COLOR_DEFAULT -1
+
+struct nconf_attr_param {
+ int *attr;
+ bool has_color;
+ int color_fg;
+ int color_bg;
+ int highlight;
+};
+
+static const struct nconf_attr_param color_theme_params[] = {
+ COLOR_ATTR(attr_normal, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
+ COLOR_ATTR(attr_main_heading, COLOR_MAGENTA, COLOR_DEFAULT, A_BOLD | A_UNDERLINE),
+ COLOR_ATTR(attr_main_menu_box, COLOR_YELLOW, COLOR_DEFAULT, A_NORMAL),
+ COLOR_ATTR(attr_main_menu_fore, COLOR_DEFAULT, COLOR_DEFAULT, A_REVERSE),
+ COLOR_ATTR(attr_main_menu_back, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
+ COLOR_ATTR(attr_main_menu_grey, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
+ COLOR_ATTR(attr_main_menu_heading, COLOR_GREEN, COLOR_DEFAULT, A_BOLD),
+ COLOR_ATTR(attr_scrollwin_text, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
+ COLOR_ATTR(attr_scrollwin_heading, COLOR_GREEN, COLOR_DEFAULT, A_BOLD),
+ COLOR_ATTR(attr_scrollwin_box, COLOR_YELLOW, COLOR_DEFAULT, A_BOLD),
+ COLOR_ATTR(attr_dialog_text, COLOR_DEFAULT, COLOR_DEFAULT, A_BOLD),
+ COLOR_ATTR(attr_dialog_menu_fore, COLOR_RED, COLOR_DEFAULT, A_STANDOUT),
+ COLOR_ATTR(attr_dialog_menu_back, COLOR_YELLOW, COLOR_DEFAULT, A_NORMAL),
+ COLOR_ATTR(attr_dialog_box, COLOR_YELLOW, COLOR_DEFAULT, A_BOLD),
+ COLOR_ATTR(attr_input_box, COLOR_YELLOW, COLOR_DEFAULT, A_NORMAL),
+ COLOR_ATTR(attr_input_heading, COLOR_GREEN, COLOR_DEFAULT, A_BOLD),
+ COLOR_ATTR(attr_input_text, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
+ COLOR_ATTR(attr_input_field, COLOR_DEFAULT, COLOR_DEFAULT, A_UNDERLINE),
+ COLOR_ATTR(attr_function_text, COLOR_YELLOW, COLOR_DEFAULT, A_REVERSE),
+ COLOR_ATTR(attr_function_highlight, COLOR_DEFAULT, COLOR_DEFAULT, A_BOLD),
+ { /* sentinel */ }
+};
+
+static const struct nconf_attr_param no_color_theme_params[] = {
+ NO_COLOR_ATTR(attr_normal, A_NORMAL),
+ NO_COLOR_ATTR(attr_main_heading, A_BOLD | A_UNDERLINE),
+ NO_COLOR_ATTR(attr_main_menu_box, A_NORMAL),
+ NO_COLOR_ATTR(attr_main_menu_fore, A_STANDOUT),
+ NO_COLOR_ATTR(attr_main_menu_back, A_NORMAL),
+ NO_COLOR_ATTR(attr_main_menu_grey, A_NORMAL),
+ NO_COLOR_ATTR(attr_main_menu_heading, A_BOLD),
+ NO_COLOR_ATTR(attr_scrollwin_text, A_NORMAL),
+ NO_COLOR_ATTR(attr_scrollwin_heading, A_BOLD),
+ NO_COLOR_ATTR(attr_scrollwin_box, A_BOLD),
+ NO_COLOR_ATTR(attr_dialog_text, A_NORMAL),
+ NO_COLOR_ATTR(attr_dialog_menu_fore, A_STANDOUT),
+ NO_COLOR_ATTR(attr_dialog_menu_back, A_NORMAL),
+ NO_COLOR_ATTR(attr_dialog_box, A_BOLD),
+ NO_COLOR_ATTR(attr_input_box, A_BOLD),
+ NO_COLOR_ATTR(attr_input_heading, A_BOLD),
+ NO_COLOR_ATTR(attr_input_text, A_NORMAL),
+ NO_COLOR_ATTR(attr_input_field, A_UNDERLINE),
+ NO_COLOR_ATTR(attr_function_text, A_REVERSE),
+ NO_COLOR_ATTR(attr_function_highlight, A_BOLD),
+ { /* sentinel */ }
+};
void set_colors(void)
{
- start_color();
- use_default_colors();
- set_normal_colors();
+ const struct nconf_attr_param *p;
+ int pair = 0;
+
if (has_colors()) {
- normal_color_theme();
+ start_color();
+ use_default_colors();
+ p = color_theme_params;
} else {
- /* give defaults */
- no_colors_theme();
+ p = no_color_theme_params;
}
-}
+ for (; p->attr; p++) {
+ int attr = p->highlight;
+
+ if (p->has_color) {
+ pair++;
+ init_pair(pair, p->color_fg, p->color_bg);
+ attr |= COLOR_PAIR(pair);
+ }
+
+ *p->attr = attr;
+ }
+}
/* this changes the windows attributes !!! */
-void print_in_middle(WINDOW *win,
- int starty,
- int startx,
- int width,
- const char *string,
- chtype color)
-{ int length, x, y;
- float temp;
-
-
- if (win == NULL)
- win = stdscr;
- getyx(win, y, x);
- if (startx != 0)
- x = startx;
- if (starty != 0)
- y = starty;
- if (width == 0)
- width = 80;
-
- length = strlen(string);
- temp = (width - length) / 2;
- x = startx + (int)temp;
- (void) wattrset(win, color);
- mvwprintw(win, y, x, "%s", string);
- refresh();
+void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs)
+{
+ wattrset(win, attrs);
+ mvwprintw(win, y, (width - strlen(str)) / 2, "%s", str);
}
int get_line_no(const char *text)
@@ -294,14 +245,14 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
msg_win = derwin(win, win_rows-2, msg_width, 1,
1+(total_width+2-msg_width)/2);
- set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
- set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
+ set_menu_fore(menu, attr_dialog_menu_fore);
+ set_menu_back(menu, attr_dialog_menu_back);
- (void) wattrset(win, attributes[DIALOG_BOX]);
+ wattrset(win, attr_dialog_box);
box(win, 0, 0);
/* print message */
- (void) wattrset(msg_win, attributes[DIALOG_TEXT]);
+ wattrset(msg_win, attr_dialog_text);
fill_window(msg_win, msg);
set_menu_win(menu, win);
@@ -405,16 +356,16 @@ int dialog_inputbox(WINDOW *main_window,
form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
keypad(form_win, TRUE);
- (void) wattrset(form_win, attributes[INPUT_FIELD]);
+ wattrset(form_win, attr_input_field);
- (void) wattrset(win, attributes[INPUT_BOX]);
+ wattrset(win, attr_input_box);
box(win, 0, 0);
- (void) wattrset(win, attributes[INPUT_HEADING]);
+ wattrset(win, attr_input_heading);
if (title)
mvwprintw(win, 0, 3, "%s", title);
/* print message */
- (void) wattrset(prompt_win, attributes[INPUT_TEXT]);
+ wattrset(prompt_win, attr_input_text);
fill_window(prompt_win, prompt);
mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
@@ -576,7 +527,7 @@ void show_scroll_win(WINDOW *main_window,
/* create the pad */
pad = newpad(total_lines+10, total_cols+10);
- (void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
+ wattrset(pad, attr_scrollwin_text);
fill_window(pad, text);
win_lines = min(total_lines+4, lines-2);
@@ -591,9 +542,9 @@ void show_scroll_win(WINDOW *main_window,
win = newwin(win_lines, win_cols, y, x);
keypad(win, TRUE);
/* show the help in the help window, and show the help panel */
- (void) wattrset(win, attributes[SCROLLWIN_BOX]);
+ wattrset(win, attr_scrollwin_box);
box(win, 0, 0);
- (void) wattrset(win, attributes[SCROLLWIN_HEADING]);
+ wattrset(win, attr_scrollwin_heading);
mvwprintw(win, 0, 3, " %s ", title);
panel = new_panel(win);
@@ -604,10 +555,9 @@ void show_scroll_win(WINDOW *main_window,
text_cols, 0);
print_in_middle(win,
text_lines+2,
- 0,
text_cols,
"<OK>",
- attributes[DIALOG_MENU_FORE]);
+ attr_dialog_menu_fore);
wrefresh(win);
res = wgetch(win);
diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h
index fa5245eb93a7..6f925bc74eb3 100644
--- a/scripts/kconfig/nconf.h
+++ b/scripts/kconfig/nconf.h
@@ -32,30 +32,26 @@
typeof(b) _b = b;\
_a < _b ? _a : _b; })
-typedef enum {
- NORMAL = 1,
- MAIN_HEADING,
- MAIN_MENU_BOX,
- MAIN_MENU_FORE,
- MAIN_MENU_BACK,
- MAIN_MENU_GREY,
- MAIN_MENU_HEADING,
- SCROLLWIN_TEXT,
- SCROLLWIN_HEADING,
- SCROLLWIN_BOX,
- DIALOG_TEXT,
- DIALOG_MENU_FORE,
- DIALOG_MENU_BACK,
- DIALOG_BOX,
- INPUT_BOX,
- INPUT_HEADING,
- INPUT_TEXT,
- INPUT_FIELD,
- FUNCTION_TEXT,
- FUNCTION_HIGHLIGHT,
- ATTR_MAX
-} attributes_t;
-extern attributes_t attributes[];
+extern int attr_normal;
+extern int attr_main_heading;
+extern int attr_main_menu_box;
+extern int attr_main_menu_fore;
+extern int attr_main_menu_back;
+extern int attr_main_menu_grey;
+extern int attr_main_menu_heading;
+extern int attr_scrollwin_text;
+extern int attr_scrollwin_heading;
+extern int attr_scrollwin_box;
+extern int attr_dialog_text;
+extern int attr_dialog_menu_fore;
+extern int attr_dialog_menu_back;
+extern int attr_dialog_box;
+extern int attr_input_box;
+extern int attr_input_heading;
+extern int attr_input_text;
+extern int attr_input_field;
+extern int attr_function_text;
+extern int attr_function_highlight;
typedef enum {
F_HELP = 1,
@@ -72,12 +68,7 @@ typedef enum {
void set_colors(void);
/* this changes the windows attributes !!! */
-void print_in_middle(WINDOW *win,
- int starty,
- int startx,
- int width,
- const char *string,
- chtype color);
+void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs);
int get_line_length(const char *line);
int get_line_no(const char *text);
const char *get_line(const char *text, int line_no);
diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y
index 190f1117f35a..2af7ce4e1531 100644
--- a/scripts/kconfig/parser.y
+++ b/scripts/kconfig/parser.y
@@ -12,6 +12,7 @@
#include <stdbool.h>
#include "lkc.h"
+#include "internal.h"
#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
@@ -28,7 +29,7 @@ static bool zconf_endtoken(const char *tokenname,
struct symbol *symbol_hash[SYMBOL_HASHSIZE];
-static struct menu *current_menu, *current_entry;
+struct menu *current_menu, *current_entry;
%}
@@ -45,7 +46,6 @@ static struct menu *current_menu, *current_entry;
%token <string> T_HELPTEXT
%token <string> T_WORD
%token <string> T_WORD_QUOTE
-%token T_ALLNOCONFIG_Y
%token T_BOOL
%token T_CHOICE
%token T_CLOSE_PAREN
@@ -53,7 +53,6 @@ static struct menu *current_menu, *current_entry;
%token T_COMMENT
%token T_CONFIG
%token T_DEFAULT
-%token T_DEFCONFIG_LIST
%token T_DEF_BOOL
%token T_DEF_TRISTATE
%token T_DEPENDS
@@ -71,7 +70,6 @@ static struct menu *current_menu, *current_entry;
%token T_MODULES
%token T_ON
%token T_OPEN_PAREN
-%token T_OPTION
%token T_OPTIONAL
%token T_PLUS_EQUAL
%token T_PROMPT
@@ -218,19 +216,12 @@ config_option: T_RANGE symbol symbol if_expr T_EOL
printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
};
-config_option: T_OPTION T_MODULES T_EOL
+config_option: T_MODULES T_EOL
{
- menu_add_option_modules();
-};
-
-config_option: T_OPTION T_DEFCONFIG_LIST T_EOL
-{
- menu_add_option_defconfig_list();
-};
-
-config_option: T_OPTION T_ALLNOCONFIG_Y T_EOL
-{
- menu_add_option_allnoconfig_y();
+ if (modules_sym)
+ zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'",
+ current_entry->sym->name, modules_sym->name);
+ modules_sym = current_entry->sym;
};
/* choice entry */
@@ -517,7 +508,7 @@ void conf_parse(const char *name)
}
if (yynerrs)
exit(1);
- sym_set_change_count(1);
+ conf_set_changed(true);
}
static bool zconf_endtoken(const char *tokenname,
@@ -723,5 +714,3 @@ void zconfdump(FILE *out)
}
}
}
-
-#include "menu.c"
diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c
index 0590f86df6e4..d1f5bcff4b62 100644
--- a/scripts/kconfig/preprocess.c
+++ b/scripts/kconfig/preprocess.c
@@ -141,7 +141,7 @@ static char *do_lineno(int argc, char *argv[])
static char *do_shell(int argc, char *argv[])
{
FILE *p;
- char buf[256];
+ char buf[4096];
char *cmd;
size_t nread;
int i;
@@ -396,6 +396,9 @@ static char *eval_clause(const char *str, size_t len, int argc, char *argv[])
p++;
}
+
+ if (new_argc >= FUNCTION_MAX_ARGS)
+ pperror("too many function arguments");
new_argv[new_argc++] = prev;
/*
diff --git a/scripts/kconfig/qconf-cfg.sh b/scripts/kconfig/qconf-cfg.sh
index fa564cd795b7..117f36e568fc 100755
--- a/scripts/kconfig/qconf-cfg.sh
+++ b/scripts/kconfig/qconf-cfg.sh
@@ -1,24 +1,29 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+cflags=$1
+libs=$2
+bin=$3
+
PKG="Qt5Core Qt5Gui Qt5Widgets"
-if [ -z "$(command -v pkg-config)" ]; then
+if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then
echo >&2 "*"
- echo >&2 "* 'make xconfig' requires 'pkg-config'. Please install it."
+ echo >&2 "* 'make xconfig' requires '${HOSTPKG_CONFIG}'. Please install it."
echo >&2 "*"
exit 1
fi
-if pkg-config --exists $PKG; then
- echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags $PKG)\"
- echo libs=\"$(pkg-config --libs $PKG)\"
- echo moc=\"$(pkg-config --variable=host_bins Qt5Core)/moc\"
+if ${HOSTPKG_CONFIG} --exists $PKG; then
+ ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags}
+ ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs}
+ ${HOSTPKG_CONFIG} --variable=host_bins Qt5Core > ${bin}
exit 0
fi
echo >&2 "*"
-echo >&2 "* Could not find Qt5 via pkg-config."
+echo >&2 "* Could not find Qt5 via ${HOSTPKG_CONFIG}."
echo >&2 "* Please install Qt5 and make sure it's in PKG_CONFIG_PATH"
+echo >&2 "* You need $PKG"
echo >&2 "*"
exit 1
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index d000869b787c..78087b2d9ac6 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -122,6 +122,7 @@ void ConfigItem::updateMenu(void)
goto set_prompt;
case P_COMMENT:
setIcon(promptColIdx, QIcon());
+ prompt = "*** " + prompt + " ***";
goto set_prompt;
default:
;
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
index 1c78ba49ca99..d51cd7ac15d2 100755
--- a/scripts/kconfig/streamline_config.pl
+++ b/scripts/kconfig/streamline_config.pl
@@ -21,7 +21,7 @@
# 1. Boot up the kernel that you want to stream line the config on.
# 2. Change directory to the directory holding the source of the
# kernel that you just booted.
-# 3. Copy the configuraton file to this directory as .config
+# 3. Copy the configuration file to this directory as .config
# 4. Have all your devices that you need modules for connected and
# operational (make sure that their corresponding modules are loaded)
# 5. Run this script redirecting the output to some other file
@@ -170,7 +170,7 @@ sub read_kconfig {
$source =~ s/\$\($env\)/$ENV{$env}/;
}
- open(my $kinfile, '<', $source) || die "Can't open $kconfig";
+ open(my $kinfile, '<', $source) || die "Can't open $source";
while (<$kinfile>) {
chomp;
@@ -317,7 +317,7 @@ foreach my $makefile (@makefiles) {
$_ = convert_vars($_, %make_vars);
# collect objects after obj-$(CONFIG_FOO_BAR)
- if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) {
+ if (/obj-\$[({](CONFIG_[^})]*)[)}]\s*[+:]?=\s*(.*)/) {
$var = $1;
$objs = $2;
@@ -481,7 +481,7 @@ sub parse_config_depends
# The idea is we look at all the configs that select it. If one
# is already in our list of configs to enable, then there's nothing
# else to do. If there isn't, we pick the first config that was
-# enabled in the orignal config and use that.
+# enabled in the original config and use that.
sub parse_config_selects
{
my ($config, $p) = @_;
@@ -601,12 +601,12 @@ if (defined($ENV{'LMC_KEEP'})) {
sub in_preserved_kconfigs {
my $kconfig = $config2kfile{$_[0]};
if (!defined($kconfig)) {
- return 0;
+ return 0;
}
foreach my $excl (@preserved_kconfigs) {
- if($kconfig =~ /^$excl/) {
- return 1;
- }
+ if($kconfig =~ /^$excl/) {
+ return 1;
+ }
}
return 0;
}
@@ -629,52 +629,52 @@ foreach my $line (@config_file) {
}
if (/CONFIG_MODULE_SIG_KEY="(.+)"/) {
- my $orig_cert = $1;
- my $default_cert = "certs/signing_key.pem";
-
- # Check that the logic in this script still matches the one in Kconfig
- if (!defined($depends{"MODULE_SIG_KEY"}) ||
- $depends{"MODULE_SIG_KEY"} !~ /"\Q$default_cert\E"/) {
- print STDERR "WARNING: MODULE_SIG_KEY assertion failure, ",
- "update needed to ", __FILE__, " line ", __LINE__, "\n";
- print;
- } elsif ($orig_cert ne $default_cert && ! -f $orig_cert) {
- print STDERR "Module signature verification enabled but ",
- "module signing key \"$orig_cert\" not found. Resetting ",
- "signing key to default value.\n";
- print "CONFIG_MODULE_SIG_KEY=\"$default_cert\"\n";
- } else {
- print;
- }
- next;
+ my $orig_cert = $1;
+ my $default_cert = "certs/signing_key.pem";
+
+ # Check that the logic in this script still matches the one in Kconfig
+ if (!defined($depends{"MODULE_SIG_KEY"}) ||
+ $depends{"MODULE_SIG_KEY"} !~ /"\Q$default_cert\E"/) {
+ print STDERR "WARNING: MODULE_SIG_KEY assertion failure, ",
+ "update needed to ", __FILE__, " line ", __LINE__, "\n";
+ print;
+ } elsif ($orig_cert ne $default_cert && ! -f $orig_cert) {
+ print STDERR "Module signature verification enabled but ",
+ "module signing key \"$orig_cert\" not found. Resetting ",
+ "signing key to default value.\n";
+ print "CONFIG_MODULE_SIG_KEY=\"$default_cert\"\n";
+ } else {
+ print;
+ }
+ next;
}
if (/CONFIG_SYSTEM_TRUSTED_KEYS="(.+)"/) {
- my $orig_keys = $1;
-
- if (! -f $orig_keys) {
- print STDERR "System keyring enabled but keys \"$orig_keys\" ",
- "not found. Resetting keys to default value.\n";
- print "CONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n";
- } else {
- print;
- }
- next;
+ my $orig_keys = $1;
+
+ if (! -f $orig_keys) {
+ print STDERR "System keyring enabled but keys \"$orig_keys\" ",
+ "not found. Resetting keys to default value.\n";
+ print "CONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n";
+ } else {
+ print;
+ }
+ next;
}
if (/^(CONFIG.*)=(m|y)/) {
- if (in_preserved_kconfigs($1)) {
- dprint "Preserve config $1";
- print;
- next;
- }
+ if (in_preserved_kconfigs($1)) {
+ dprint "Preserve config $1";
+ print;
+ next;
+ }
if (defined($configs{$1})) {
if ($localyesconfig) {
- $setconfigs{$1} = 'y';
+ $setconfigs{$1} = 'y';
print "$1=y\n";
next;
} else {
- $setconfigs{$1} = $2;
+ $setconfigs{$1} = $2;
}
} elsif ($2 eq "m") {
print "# $1 is not set\n";
@@ -702,3 +702,5 @@ foreach my $module (keys(%modules)) {
print STDERR "\n";
}
}
+
+# vim: softtabstop=4
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index fe38e6fd2c2a..0572330bf8a7 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -35,7 +35,6 @@ static struct symbol symbol_empty = {
.flags = SYMBOL_VALID,
};
-struct symbol *sym_defconfig_list;
struct symbol *modules_sym;
static tristate modules_val;
@@ -473,7 +472,7 @@ void sym_clear_all_valid(void)
for_all_symbols(i, sym)
sym->flags &= ~SYMBOL_VALID;
- sym_add_change_count(1);
+ conf_set_changed(true);
sym_calc_value(modules_sym);
}
@@ -872,49 +871,6 @@ struct symbol *sym_find(const char *name)
return symbol;
}
-const char *sym_escape_string_value(const char *in)
-{
- const char *p;
- size_t reslen;
- char *res;
- size_t l;
-
- reslen = strlen(in) + strlen("\"\"") + 1;
-
- p = in;
- for (;;) {
- l = strcspn(p, "\"\\");
- p += l;
-
- if (p[0] == '\0')
- break;
-
- reslen++;
- p++;
- }
-
- res = xmalloc(reslen);
- res[0] = '\0';
-
- strcat(res, "\"");
-
- p = in;
- for (;;) {
- l = strcspn(p, "\"\\");
- strncat(res, p, l);
- p += l;
-
- if (p[0] == '\0')
- break;
-
- strcat(res, "\\");
- strncat(res, p++, 1);
- }
-
- strcat(res, "\"");
- return res;
-}
-
struct sym_match {
struct symbol *sym;
off_t so, eo;
diff --git a/scripts/kconfig/tests/choice/Kconfig b/scripts/kconfig/tests/choice/Kconfig
index a412205b1b0c..0930eb65e932 100644
--- a/scripts/kconfig/tests/choice/Kconfig
+++ b/scripts/kconfig/tests/choice/Kconfig
@@ -2,7 +2,7 @@
config MODULES
bool "Enable loadable module support"
- option modules
+ modules
default y
choice
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig b/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
index 7106c26bb3a8..bd970cec07d6 100644
--- a/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
@@ -2,7 +2,7 @@
config MODULES
def_bool y
- option modules
+ modules
config DEP
tristate
diff --git a/scripts/kconfig/tests/conftest.py b/scripts/kconfig/tests/conftest.py
index 0345ef6e3273..af8774a5697c 100644
--- a/scripts/kconfig/tests/conftest.py
+++ b/scripts/kconfig/tests/conftest.py
@@ -53,6 +53,10 @@ 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'] = ''
+
# Run Kconfig in a temporary directory.
# This directory is automatically removed when done.
with tempfile.TemporaryDirectory() as temp_dir:
diff --git a/scripts/kconfig/tests/inter_choice/Kconfig b/scripts/kconfig/tests/inter_choice/Kconfig
index 5698a4018dd0..26c25f68695b 100644
--- a/scripts/kconfig/tests/inter_choice/Kconfig
+++ b/scripts/kconfig/tests/inter_choice/Kconfig
@@ -2,7 +2,7 @@
config MODULES
def_bool y
- option modules
+ modules
choice
prompt "Choice"
diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c
index 29585394df71..b78f114ad48c 100644
--- a/scripts/kconfig/util.c
+++ b/scripts/kconfig/util.c
@@ -74,7 +74,7 @@ void str_printf(struct gstr *gs, const char *fmt, ...)
}
/* Retrieve value of growable string */
-const char *str_get(struct gstr *gs)
+char *str_get(struct gstr *gs)
{
return gs->s;
}
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 8b5bc7bf4bb8..d0116c6939dc 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -12,202 +12,46 @@ use strict;
## ##
## #define enhancements by Armin Kuster <akuster@mvista.com> ##
## Copyright (c) 2000 MontaVista Software, Inc. ##
-## ##
-## This software falls under the GNU General Public License. ##
-## Please read the COPYING file for more information ##
+#
+# Copyright (C) 2022 Tomasz Warniełło (POD)
-# 18/01/2001 - Cleanups
-# Functions prototyped as foo(void) same as foo()
-# Stop eval'ing where we don't need to.
-# -- huggie@earth.li
+use Pod::Usage qw/pod2usage/;
-# 27/06/2001 - Allowed whitespace after initial "/**" and
-# allowed comments before function declarations.
-# -- Christian Kreibich <ck@whoop.org>
+=head1 NAME
-# Still to do:
-# - add perldoc documentation
-# - Look more closely at some of the scarier bits :)
+kernel-doc - Print formatted kernel documentation to stdout
-# 26/05/2001 - Support for separate source and object trees.
-# Return error code.
-# Keith Owens <kaos@ocs.com.au>
+=head1 SYNOPSIS
-# 23/09/2001 - Added support for typedefs, structs, enums and unions
-# Support for Context section; can be terminated using empty line
-# Small fixes (like spaces vs. \s in regex)
-# -- Tim Jansen <tim@tjansen.de>
+ kernel-doc [-h] [-v] [-Werror] [-Wall] [-Wreturn] [-Wshort-description] [-Wcontents-before-sections]
+ [ -man |
+ -rst [-sphinx-version VERSION] [-enable-lineno] |
+ -none
+ ]
+ [
+ -export |
+ -internal |
+ [-function NAME] ... |
+ [-nosymbol NAME] ...
+ ]
+ [-no-doc-sections]
+ [-export-file FILE] ...
+ FILE ...
-# 25/07/2012 - Added support for HTML5
-# -- Dan Luedtke <mail@danrl.de>
+Run `kernel-doc -h` for details.
-sub usage {
- my $message = <<"EOF";
-Usage: $0 [OPTION ...] FILE ...
+=head1 DESCRIPTION
Read C language source or header FILEs, extract embedded documentation comments,
and print formatted documentation to standard output.
-The documentation comments are identified by "/**" opening comment mark. See
-Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax.
-
-Output format selection (mutually exclusive):
- -man Output troff manual page format. This is the default.
- -rst Output reStructuredText format.
- -none Do not output documentation, only warnings.
-
-Output format selection modifier (affects only ReST output):
-
- -sphinx-version Use the ReST C domain dialect compatible with an
- specific Sphinx Version.
- If not specified, kernel-doc will auto-detect using
- the sphinx-build version found on PATH.
-
-Output selection (mutually exclusive):
- -export Only output documentation for symbols that have been
- exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
- in any input FILE or -export-file FILE.
- -internal Only output documentation for symbols that have NOT been
- exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
- in any input FILE or -export-file FILE.
- -function NAME Only output documentation for the given function(s)
- or DOC: section title(s). All other functions and DOC:
- sections are ignored. May be specified multiple times.
- -nosymbol NAME Exclude the specified symbols from the output
- documentation. May be specified multiple times.
-
-Output selection modifiers:
- -no-doc-sections Do not output DOC: sections.
- -enable-lineno Enable output of #define LINENO lines. Only works with
- reStructuredText format.
- -export-file FILE Specify an additional FILE in which to look for
- EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL(). To be used with
- -export or -internal. May be specified multiple times.
-
-Other parameters:
- -v Verbose output, more warnings and other information.
- -h Print this help.
- -Werror Treat warnings as errors.
-
-EOF
- print $message;
- exit 1;
-}
+The documentation comments are identified by the "/**" opening comment mark.
-#
-# format of comments.
-# In the following table, (...)? signifies optional structure.
-# (...)* signifies 0 or more structure elements
-# /**
-# * function_name(:)? (- short description)?
-# (* @parameterx: (description of parameter x)?)*
-# (* a blank line)?
-# * (Description:)? (Description of function)?
-# * (section header: (section description)? )*
-# (*)?*/
-#
-# So .. the trivial example would be:
-#
-# /**
-# * my_function
-# */
-#
-# If the Description: header tag is omitted, then there must be a blank line
-# after the last parameter specification.
-# e.g.
-# /**
-# * my_function - does my stuff
-# * @my_arg: its mine damnit
-# *
-# * Does my stuff explained.
-# */
-#
-# or, could also use:
-# /**
-# * my_function - does my stuff
-# * @my_arg: its mine damnit
-# * Description: Does my stuff explained.
-# */
-# etc.
-#
-# Besides functions you can also write documentation for structs, unions,
-# enums and typedefs. Instead of the function name you must write the name
-# of the declaration; the struct/union/enum/typedef must always precede
-# the name. Nesting of declarations is not supported.
-# Use the argument mechanism to document members or constants.
-# e.g.
-# /**
-# * struct my_struct - short description
-# * @a: first member
-# * @b: second member
-# *
-# * Longer description
-# */
-# struct my_struct {
-# int a;
-# int b;
-# /* private: */
-# int c;
-# };
-#
-# All descriptions can be multiline, except the short function description.
-#
-# For really longs structs, you can also describe arguments inside the
-# body of the struct.
-# eg.
-# /**
-# * struct my_struct - short description
-# * @a: first member
-# * @b: second member
-# *
-# * Longer description
-# */
-# struct my_struct {
-# int a;
-# int b;
-# /**
-# * @c: This is longer description of C
-# *
-# * You can use paragraphs to describe arguments
-# * using this method.
-# */
-# int c;
-# };
-#
-# This should be use only for struct/enum members.
-#
-# You can also add additional sections. When documenting kernel functions you
-# should document the "Context:" of the function, e.g. whether the functions
-# can be called form interrupts. Unlike other sections you can end it with an
-# empty line.
-# A non-void function should have a "Return:" section describing the return
-# value(s).
-# Example-sections should contain the string EXAMPLE so that they are marked
-# appropriately in DocBook.
-#
-# Example:
-# /**
-# * user_function - function that can only be called in user context
-# * @a: some argument
-# * Context: !in_interrupt()
-# *
-# * Some description
-# * Example:
-# * user_function(22);
-# */
-# ...
-#
-#
-# All descriptive text is further processed, scanning for the following special
-# patterns, which are highlighted appropriately.
-#
-# 'funcname()' - function
-# '$ENVVAR' - environmental variable
-# '&struct_name' - name of a structure (up to two words including 'struct')
-# '&struct_name.member' - name of a structure member
-# '@parameter' - name of a parameter
-# '%CONST' - name of a constant.
-# '``LITERAL``' - literal string without any spaces on it.
+See Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax.
+
+=cut
+
+# more perldoc at the end of the file
## init lots of data
@@ -220,7 +64,7 @@ my $type_constant = '\b``([^\`]+)``\b';
my $type_constant2 = '\%([-_\w]+)';
my $type_func = '(\w+)\(\)';
my $type_param = '\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)';
-my $type_param_ref = '([\!]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)';
+my $type_param_ref = '([\!~]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)';
my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params
my $type_fp_param2 = '\@(\w+->\S+)\(\)'; # Special RST handling for structs with func ptr params
my $type_env = '(\$\w+)';
@@ -273,7 +117,13 @@ my $blankline_rst = "\n";
# read arguments
if ($#ARGV == -1) {
- usage();
+ pod2usage(
+ -message => "No arguments!\n",
+ -exitval => 1,
+ -verbose => 99,
+ -sections => 'SYNOPSIS',
+ -output => \*STDERR,
+ );
}
my $kernelversion;
@@ -283,6 +133,9 @@ my $dohighlight = "";
my $verbose = 0;
my $Werror = 0;
+my $Wreturn = 0;
+my $Wshort_desc = 0;
+my $Wcontents_before_sections = 0;
my $output_mode = "rst";
my $output_preformatted = 0;
my $no_doc_sections = 0;
@@ -325,12 +178,8 @@ my $declaration_start_line;
my ($type, $declaration_name, $return_type);
my ($newsection, $newcontents, $prototype, $brcount, %source_map);
-if (defined($ENV{'KBUILD_VERBOSE'})) {
- $verbose = "$ENV{'KBUILD_VERBOSE'}";
-}
-
-if (defined($ENV{'KDOC_WERROR'})) {
- $Werror = "$ENV{'KDOC_WERROR'}";
+if (defined($ENV{'KBUILD_VERBOSE'}) && $ENV{'KBUILD_VERBOSE'} =~ '1') {
+ $verbose = 1;
}
if (defined($ENV{'KCFLAGS'})) {
@@ -341,6 +190,15 @@ if (defined($ENV{'KCFLAGS'})) {
}
}
+# reading this variable is for backwards compat just in case
+# someone was calling it with the variable from outside the
+# kernel's build system
+if (defined($ENV{'KDOC_WERROR'})) {
+ $Werror = "$ENV{'KDOC_WERROR'}";
+}
+# other environment variables are converted to command-line
+# arguments in cmd_checkdoc in the build system
+
# Generated docbook code is inserted in a template at a point where
# docbook v3.1 requires a non-zero sequence of RefEntry's; see:
# https://www.oasis-open.org/docbook/documentation/reference/html/refentry.html
@@ -391,8 +249,14 @@ my $doc_com = '\s*\*\s*';
my $doc_com_body = '\s*\* ?';
my $doc_decl = $doc_com . '(\w+)';
# @params and a strictly limited set of supported section names
+# Specifically:
+# Match @word:
+# @...:
+# @{section-name}:
+# while trying to not match literal block starts like "example::"
+#
my $doc_sect = $doc_com .
- '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:(.*)';
+ '\s*(\@[.\w]+|\@\.\.\.|description|context|returns?|notes?|examples?)\s*:([^:].*)?$';
my $doc_content = $doc_com_body . '(.*)';
my $doc_block = $doc_com . 'DOC:\s*(.*)?';
my $doc_inline_start = '^\s*/\*\*\s*$';
@@ -400,6 +264,9 @@ my $doc_inline_sect = '\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)';
my $doc_inline_end = '^\s*\*/\s*$';
my $doc_inline_oneline = '^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$';
my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;';
+my $export_symbol_ns = '^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*\w+\)\s*;';
+my $function_pointer = qr{([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)};
+my $attribute = qr{__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)}i;
my %parameterdescs;
my %parameterdesc_start_lines;
@@ -459,8 +326,18 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
$verbose = 1;
} elsif ($cmd eq "Werror") {
$Werror = 1;
+ } elsif ($cmd eq "Wreturn") {
+ $Wreturn = 1;
+ } elsif ($cmd eq "Wshort-desc") {
+ $Wshort_desc = 1;
+ } elsif ($cmd eq "Wcontents-before-sections") {
+ $Wcontents_before_sections = 1;
+ } elsif ($cmd eq "Wall") {
+ $Wreturn = 1;
+ $Wshort_desc = 1;
+ $Wcontents_before_sections = 1;
} elsif (($cmd eq "h") || ($cmd eq "help")) {
- usage();
+ pod2usage(-exitval => 0, -verbose => 2);
} elsif ($cmd eq 'no-doc-sections') {
$no_doc_sections = 1;
} elsif ($cmd eq 'enable-lineno') {
@@ -486,7 +363,22 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
}
} else {
# Unknown argument
- usage();
+ pod2usage(
+ -message => "Argument unknown!\n",
+ -exitval => 1,
+ -verbose => 99,
+ -sections => 'SYNOPSIS',
+ -output => \*STDERR,
+ );
+ }
+ if ($#ARGV < 0){
+ pod2usage(
+ -message => "FILE argument missing\n",
+ -exitval => 1,
+ -verbose => 99,
+ -sections => 'SYNOPSIS',
+ -output => \*STDERR,
+ );
}
}
@@ -551,9 +443,16 @@ sub get_kernel_version() {
sub print_lineno {
my $lineno = shift;
if ($enable_lineno && defined($lineno)) {
- print "#define LINENO " . $lineno . "\n";
+ print ".. LINENO " . $lineno . "\n";
}
}
+
+sub emit_warning {
+ my $location = shift;
+ my $msg = shift;
+ print STDERR "$location: warning: $msg";
+ ++$warnings;
+}
##
# dumps section contents to arrays/hashes intended for that purpose.
#
@@ -578,8 +477,7 @@ sub dump_section {
if (defined($sections{$name}) && ($sections{$name} ne "")) {
# Only warn on user specified duplicate section names.
if ($name ne $section_default) {
- print STDERR "${file}:$.: warning: duplicate section name '$name'\n";
- ++$warnings;
+ emit_warning("${file}:$.", "duplicate section name '$name'\n");
}
$sections{$name} .= $contents;
} else {
@@ -688,7 +586,7 @@ sub output_function_man(%) {
$post = ");";
}
$type = $args{'parametertypes'}{$parameter};
- if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ if ($type =~ m/$function_pointer/) {
# pointer-to-function
print ".BI \"" . $parenth . $1 . "\" " . " \") (" . $2 . ")" . $post . "\"\n";
} else {
@@ -968,7 +866,7 @@ sub output_function_rst(%) {
$count++;
$type = $args{'parametertypes'}{$parameter};
- if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ if ($type =~ m/$function_pointer/) {
# pointer-to-function
print $1 . $parameter . ") (" . $2 . ")";
} else {
@@ -987,48 +885,53 @@ sub output_function_rst(%) {
print "\n";
}
- print "**Parameters**\n\n";
+ #
+ # Put our descriptive text into a container (thus an HTML <div>) to help
+ # set the function prototypes apart.
+ #
+ print ".. container:: kernelindent\n\n";
$lineprefix = " ";
+ print $lineprefix . "**Parameters**\n\n";
foreach $parameter (@{$args{'parameterlist'}}) {
my $parameter_name = $parameter;
$parameter_name =~ s/\[.*//;
$type = $args{'parametertypes'}{$parameter};
if ($type ne "") {
- print "``$type``\n";
+ print $lineprefix . "``$type``\n";
} else {
- print "``$parameter``\n";
+ print $lineprefix . "``$parameter``\n";
}
print_lineno($parameterdesc_start_lines{$parameter_name});
+ $lineprefix = " ";
if (defined($args{'parameterdescs'}{$parameter_name}) &&
$args{'parameterdescs'}{$parameter_name} ne $undescribed) {
output_highlight_rst($args{'parameterdescs'}{$parameter_name});
} else {
- print " *undescribed*\n";
+ print $lineprefix . "*undescribed*\n";
}
+ $lineprefix = " ";
print "\n";
}
- $lineprefix = $oldprefix;
output_section_rst(@_);
+ $lineprefix = $oldprefix;
}
sub output_section_rst(%) {
my %args = %{$_[0]};
my $section;
my $oldprefix = $lineprefix;
- $lineprefix = "";
foreach $section (@{$args{'sectionlist'}}) {
- print "**$section**\n\n";
+ print $lineprefix . "**$section**\n\n";
print_lineno($section_start_lines{$section});
output_highlight_rst($args{'sections'}{$section});
print "\n";
}
print "\n";
- $lineprefix = $oldprefix;
}
sub output_enum_rst(%) {
@@ -1036,6 +939,7 @@ sub output_enum_rst(%) {
my ($parameter);
my $oldprefix = $lineprefix;
my $count;
+ my $outer;
if ($sphinx_major < 3) {
my $name = "enum " . $args{'enum'};
@@ -1045,22 +949,25 @@ sub output_enum_rst(%) {
print "\n\n.. c:enum:: " . $name . "\n\n";
}
print_lineno($declaration_start_line);
- $lineprefix = " ";
+ $lineprefix = " ";
output_highlight_rst($args{'purpose'});
print "\n";
- print "**Constants**\n\n";
- $lineprefix = " ";
+ print ".. container:: kernelindent\n\n";
+ $outer = $lineprefix . " ";
+ $lineprefix = $outer . " ";
+ print $outer . "**Constants**\n\n";
foreach $parameter (@{$args{'parameterlist'}}) {
- print "``$parameter``\n";
+ print $outer . "``$parameter``\n";
+
if ($args{'parameterdescs'}{$parameter} ne $undescribed) {
output_highlight_rst($args{'parameterdescs'}{$parameter});
} else {
- print " *undescribed*\n";
+ print $lineprefix . "*undescribed*\n";
}
print "\n";
}
-
+ print "\n";
$lineprefix = $oldprefix;
output_section_rst(@_);
}
@@ -1103,18 +1010,19 @@ sub output_struct_rst(%) {
}
}
print_lineno($declaration_start_line);
- $lineprefix = " ";
+ $lineprefix = " ";
output_highlight_rst($args{'purpose'});
print "\n";
- print "**Definition**\n\n";
- print "::\n\n";
+ print ".. container:: kernelindent\n\n";
+ print $lineprefix . "**Definition**::\n\n";
my $declaration = $args{'definition'};
- $declaration =~ s/\t/ /g;
- print " " . $args{'type'} . " " . $args{'struct'} . " {\n$declaration };\n\n";
+ $lineprefix = $lineprefix . " ";
+ $declaration =~ s/\t/$lineprefix/g;
+ print $lineprefix . $args{'type'} . " " . $args{'struct'} . " {\n$declaration" . $lineprefix . "};\n\n";
- print "**Members**\n\n";
$lineprefix = " ";
+ print $lineprefix . "**Members**\n\n";
foreach $parameter (@{$args{'parameterlist'}}) {
($parameter =~ /^#/) && next;
@@ -1124,8 +1032,10 @@ sub output_struct_rst(%) {
($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
$type = $args{'parametertypes'}{$parameter};
print_lineno($parameterdesc_start_lines{$parameter_name});
- print "``" . $parameter . "``\n";
+ print $lineprefix . "``" . $parameter . "``\n";
+ $lineprefix = " ";
output_highlight_rst($args{'parameterdescs'}{$parameter_name});
+ $lineprefix = " ";
print "\n";
}
print "\n";
@@ -1201,14 +1111,27 @@ sub dump_union($$) {
sub dump_struct($$) {
my $x = shift;
my $file = shift;
-
- if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
- my $decl_type = $1;
+ my $decl_type;
+ my $members;
+ my $type = qr{struct|union};
+ # For capturing struct/union definition body, i.e. "{members*}qualifiers*"
+ my $qualifiers = qr{$attribute|__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned};
+ my $definition_body = qr{\{(.*)\}\s*$qualifiers*};
+ my $struct_members = qr{($type)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;};
+
+ if ($x =~ /($type)\s+(\w+)\s*$definition_body/) {
+ $decl_type = $1;
$declaration_name = $2;
- my $members = $3;
+ $members = $3;
+ } elsif ($x =~ /typedef\s+($type)\s*$definition_body\s*(\w+)\s*;/) {
+ $decl_type = $1;
+ $declaration_name = $3;
+ $members = $2;
+ }
+ if ($members) {
if ($identifier ne $declaration_name) {
- print STDERR "${file}:$.: warning: expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n";
+ emit_warning("${file}:$.", "expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n");
return;
}
@@ -1218,27 +1141,37 @@ sub dump_struct($$) {
# strip comments:
$members =~ s/\/\*.*?\*\///gos;
# strip attributes
- $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)/ /gi;
+ $members =~ s/\s*$attribute/ /gi;
$members =~ s/\s*__aligned\s*\([^;]*\)/ /gos;
$members =~ s/\s*__packed\s*/ /gos;
$members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos;
$members =~ s/\s*____cacheline_aligned_in_smp/ /gos;
$members =~ s/\s*____cacheline_aligned/ /gos;
-
+ # unwrap struct_group():
+ # - first eat non-declaration parameters and rewrite for final match
+ # - then remove macro, outer parens, and trailing semicolon
+ $members =~ s/\bstruct_group\s*\(([^,]*,)/STRUCT_GROUP(/gos;
+ $members =~ s/\bstruct_group_(attr|tagged)\s*\(([^,]*,){2}/STRUCT_GROUP(/gos;
+ $members =~ s/\b__struct_group\s*\(([^,]*,){3}/STRUCT_GROUP(/gos;
+ $members =~ s/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/$2/gos;
+
+ my $args = qr{([^,)]+)};
# replace DECLARE_BITMAP
$members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos;
- $members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
+ $members =~ s/DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, PHY_INTERFACE_MODE_MAX)/gos;
+ $members =~ s/DECLARE_BITMAP\s*\($args,\s*$args\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
# replace DECLARE_HASHTABLE
- $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
+ $members =~ s/DECLARE_HASHTABLE\s*\($args,\s*$args\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
# replace DECLARE_KFIFO
- $members =~ s/DECLARE_KFIFO\s*\(([^,)]+),\s*([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos;
+ $members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos;
# replace DECLARE_KFIFO_PTR
- $members =~ s/DECLARE_KFIFO_PTR\s*\(([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos;
-
+ $members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos;
+ # replace DECLARE_FLEX_ARRAY
+ $members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos;
my $declaration = $members;
# Split nested struct/union elements as newer ones
- while ($members =~ m/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/) {
+ while ($members =~ m/$struct_members/) {
my $newmember;
my $maintype = $1;
my $ids = $4;
@@ -1298,7 +1231,7 @@ sub dump_struct($$) {
}
}
}
- $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/;
+ $members =~ s/$struct_members/$newmember/;
}
# Ignore other nested elements, like enums
@@ -1386,6 +1319,9 @@ sub dump_enum($$) {
my $file = shift;
my $members;
+ # ignore members marked private:
+ $x =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi;
+ $x =~ s/\/\*\s*private:.*}/}/gosi;
$x =~ s@/\*.*?\*/@@gos; # strip comments.
# strip #define macros inside enums
@@ -1401,9 +1337,14 @@ sub dump_enum($$) {
if ($members) {
if ($identifier ne $declaration_name) {
- print STDERR "${file}:$.: warning: expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n";
+ if ($identifier eq "") {
+ emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n");
+ } else {
+ emit_warning("${file}:$.", "expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n");
+ }
return;
}
+ $declaration_name = "(anonymous)" if ($declaration_name eq "");
my %_members;
@@ -1415,7 +1356,7 @@ sub dump_enum($$) {
if (!$parameterdescs{$arg}) {
$parameterdescs{$arg} = $undescribed;
if (show_warnings("enum", $declaration_name)) {
- print STDERR "${file}:$.: warning: Enum value '$arg' not described in enum '$declaration_name'\n";
+ emit_warning("${file}:$.", "Enum value '$arg' not described in enum '$declaration_name'\n");
}
}
$_members{$arg} = 1;
@@ -1424,7 +1365,7 @@ sub dump_enum($$) {
while (my ($k, $v) = each %parameterdescs) {
if (!exists($_members{$k})) {
if (show_warnings("enum", $declaration_name)) {
- print STDERR "${file}:$.: warning: Excess enum value '$k' description in '$declaration_name'\n";
+ emit_warning("${file}:$.", "Excess enum value '$k' description in '$declaration_name'\n");
}
}
}
@@ -1466,7 +1407,7 @@ sub dump_typedef($$) {
$return_type =~ s/^\s+//;
if ($identifier ne $declaration_name) {
- print STDERR "${file}:$.: warning: expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n";
+ emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n");
return;
}
@@ -1497,7 +1438,7 @@ sub dump_typedef($$) {
$declaration_name = $1;
if ($identifier ne $declaration_name) {
- print STDERR "${file}:$.: warning: expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n";
+ emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n");
return;
}
@@ -1533,13 +1474,16 @@ sub create_parameterlist($$$$) {
my $param;
# temporarily replace commas inside function pointer definition
- while ($args =~ /(\([^\),]+),/) {
- $args =~ s/(\([^\),]+),/$1#/g;
+ my $arg_expr = qr{\([^\),]+};
+ while ($args =~ /$arg_expr,/) {
+ $args =~ s/($arg_expr),/$1#/g;
}
foreach my $arg (split($splitter, $args)) {
# strip comments
$arg =~ s/\/\*.*\*\///;
+ # ignore argument attributes
+ $arg =~ s/\sPOS0?\s/ /;
# strip leading/trailing spaces
$arg =~ s/^\s*//;
$arg =~ s/\s*$//;
@@ -1652,9 +1596,7 @@ sub push_parameter($$$$$) {
$parameterdescs{$param} = $undescribed;
if (show_warnings($type, $declaration_name) && $param !~ /\./) {
- print STDERR
- "${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n";
- ++$warnings;
+ emit_warning("${file}:$.", "Function parameter or member '$param' not described in '$declaration_name'\n");
}
}
@@ -1685,7 +1627,7 @@ sub check_sections($$$$$) {
foreach $px (0 .. $#prms) {
$prm_clean = $prms[$px];
$prm_clean =~ s/\[.*\]//;
- $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
+ $prm_clean =~ s/$attribute//i;
# ignore array size in a parameter string;
# however, the original param string may contain
# spaces, e.g.: addr[6 + 2]
@@ -1702,11 +1644,10 @@ sub check_sections($$$$$) {
}
if ($err) {
if ($decl_type eq "function") {
- print STDERR "${file}:$.: warning: " .
+ emit_warning("${file}:$.",
"Excess function parameter " .
"'$sects[$sx]' " .
- "description in '$decl_name'\n";
- ++$warnings;
+ "description in '$decl_name'\n");
}
}
}
@@ -1727,10 +1668,9 @@ sub check_return_section {
if (!defined($sections{$section_return}) ||
$sections{$section_return} eq "") {
- print STDERR "${file}:$.: warning: " .
+ emit_warning("${file}:$.",
"No description found for return value of " .
- "'$declaration_name'\n";
- ++$warnings;
+ "'$declaration_name'\n");
}
}
@@ -1753,14 +1693,20 @@ sub dump_function($$) {
$prototype =~ s/^__inline +//;
$prototype =~ s/^__always_inline +//;
$prototype =~ s/^noinline +//;
+ $prototype =~ s/^__FORTIFY_INLINE +//;
$prototype =~ s/__init +//;
$prototype =~ s/__init_or_module +//;
+ $prototype =~ s/__deprecated +//;
+ $prototype =~ s/__flatten +//;
$prototype =~ s/__meminit +//;
$prototype =~ s/__must_check +//;
$prototype =~ s/__weak +//;
$prototype =~ s/__sched +//;
$prototype =~ s/__printf\s*\(\s*\d*\s*,\s*\d*\s*\) +//;
+ $prototype =~ s/__(?:re)?alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) +//;
+ $prototype =~ s/__diagnose_as\s*\(\s*\S+\s*(?:,\s*\d+\s*)*\) +//;
my $define = $prototype =~ s/^#\s*define\s+//; #ak added
+ $prototype =~ s/__attribute_const__ +//;
$prototype =~ s/__attribute__\s*\(\(
(?:
[\w\s]++ # attribute name
@@ -1784,8 +1730,14 @@ sub dump_function($$) {
# - parport_register_device (function pointer parameters)
# - atomic_set (macro)
# - pci_match_device, __copy_to_user (long return type)
-
- if ($define && $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s+/) {
+ my $name = qr{[a-zA-Z0-9_~:]+};
+ my $prototype_end1 = qr{[^\(]*};
+ my $prototype_end2 = qr{[^\{]*};
+ my $prototype_end = qr{\(($prototype_end1|$prototype_end2)\)};
+ my $type1 = qr{[\w\s]+};
+ my $type2 = qr{$type1\*+};
+
+ if ($define && $prototype =~ m/^()($name)\s+/) {
# This is an object-like macro, it has no return type and no parameter
# list.
# Function-like macros are not allowed to have spaces between
@@ -1793,35 +1745,21 @@ sub dump_function($$) {
$return_type = $1;
$declaration_name = $2;
$noret = 1;
- } elsif ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
- $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
- $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
- $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s*\*+\s*\w+\s*\*+\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) {
+ } elsif ($prototype =~ m/^()($name)\s*$prototype_end/ ||
+ $prototype =~ m/^($type1)\s+($name)\s*$prototype_end/ ||
+ $prototype =~ m/^($type2+)\s*($name)\s*$prototype_end/) {
$return_type = $1;
$declaration_name = $2;
my $args = $3;
create_parameterlist($args, ',', $file, $declaration_name);
} else {
- print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n";
+ emit_warning("${file}:$.", "cannot understand function prototype: '$prototype'\n");
return;
}
if ($identifier ne $declaration_name) {
- print STDERR "${file}:$.: warning: expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n";
+ emit_warning("${file}:$.", "expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n");
return;
}
@@ -1831,9 +1769,9 @@ sub dump_function($$) {
# This check emits a lot of warnings at the moment, because many
# functions don't have a 'Return' doc section. So until the number
# of warnings goes sufficiently down, the check is only performed in
- # verbose mode.
+ # -Wreturn mode.
# TODO: always perform the check.
- if ($verbose && !$noret) {
+ if ($Wreturn && !$noret) {
check_return_section($file, $declaration_name, $return_type);
}
@@ -1903,8 +1841,8 @@ sub tracepoint_munge($) {
$tracepointargs = $1;
}
if (($tracepointname eq 0) || ($tracepointargs eq 0)) {
- print STDERR "${file}:$.: warning: Unrecognized tracepoint format: \n".
- "$prototype\n";
+ emit_warning("${file}:$.", "Unrecognized tracepoint format: \n".
+ "$prototype\n");
} else {
$prototype = "static inline void trace_$tracepointname($tracepointargs)";
$identifier = "trace_$identifier";
@@ -2048,6 +1986,10 @@ sub process_export_file($) {
next if (defined($nosymbol_table{$2}));
$function_table{$2} = 1;
}
+ if (/$export_symbol_ns/) {
+ next if (defined($nosymbol_table{$2}));
+ $function_table{$2} = 1;
+ }
}
close(IN);
@@ -2085,15 +2027,28 @@ sub process_name($$) {
}
} elsif (/$doc_decl/o) {
$identifier = $1;
- if (/\s*([\w\s]+?)(\(\))?\s*([-:].*)?$/) {
+ my $is_kernel_comment = 0;
+ my $decl_start = qr{$doc_com};
+ # test for pointer declaration type, foo * bar() - desc
+ my $fn_type = qr{\w+\s*\*\s*};
+ my $parenthesis = qr{\(\w*\)};
+ my $decl_end = qr{[-:].*};
+ if (/^$decl_start([\w\s]+?)$parenthesis?\s*$decl_end?$/) {
$identifier = $1;
}
if ($identifier =~ m/^(struct|union|enum|typedef)\b\s*(\S*)/) {
$decl_type = $1;
$identifier = $2;
- } else {
+ $is_kernel_comment = 1;
+ }
+ # Look for foo() or static void foo() - description; or misspelt
+ # identifier
+ elsif (/^$decl_start$fn_type?(\w+)\s*$parenthesis?\s*$decl_end?$/ ||
+ /^$decl_start$fn_type?(\w+.*)$parenthesis?\s*$decl_end$/) {
+ $identifier = $1;
$decl_type = 'function';
$identifier =~ s/^define\s+//;
+ $is_kernel_comment = 1;
}
$identifier =~ s/\s+$//;
@@ -2115,16 +2070,17 @@ sub process_name($$) {
$declaration_purpose = "";
}
- if (($declaration_purpose eq "") && $verbose) {
- print STDERR "${file}:$.: warning: missing initial short description on line:\n";
- print STDERR $_;
- ++$warnings;
+ if (!$is_kernel_comment) {
+ emit_warning("${file}:$.", "This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n$_");
+ $state = STATE_NORMAL;
}
- if ($identifier eq "") {
- print STDERR "${file}:$.: warning: wrong kernel-doc identifier on line:\n";
- print STDERR $_;
- ++$warnings;
+ if (($declaration_purpose eq "") && $Wshort_desc) {
+ emit_warning("${file}:$.", "missing initial short description on line:\n$_");
+ }
+
+ if ($identifier eq "" && $decl_type ne "enum") {
+ emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n$_");
$state = STATE_NORMAL;
}
@@ -2132,9 +2088,7 @@ sub process_name($$) {
print STDERR "${file}:$.: info: Scanning doc for $decl_type $identifier\n";
}
} else {
- print STDERR "${file}:$.: warning: Cannot understand $_ on line $.",
- " - I thought it was a doc line\n";
- ++$warnings;
+ emit_warning("${file}:$.", "Cannot understand $_ on line $. - I thought it was a doc line\n");
$state = STATE_NORMAL;
}
}
@@ -2146,18 +2100,6 @@ sub process_name($$) {
sub process_body($$) {
my $file = shift;
- # Until all named variable macro parameters are
- # documented using the bare name (`x`) rather than with
- # dots (`x...`), strip the dots:
- if ($section =~ /\w\.\.\.$/) {
- $section =~ s/\.\.\.$//;
-
- if ($verbose) {
- print STDERR "${file}:$.: warning: Variable macro arguments should be documented without dots\n";
- ++$warnings;
- }
- }
-
if ($state == STATE_BODY_WITH_BLANK_LINE && /^\s*\*\s?\S/) {
dump_section($file, $section, $contents);
$section = $section_default;
@@ -2182,9 +2124,8 @@ sub process_body($$) {
}
if (($contents ne "") && ($contents ne "\n")) {
- if (!$in_doc_sect && $verbose) {
- print STDERR "${file}:$.: warning: contents before sections\n";
- ++$warnings;
+ if (!$in_doc_sect && $Wcontents_before_sections) {
+ emit_warning("${file}:$.", "contents before sections\n");
}
dump_section($file, $section, $contents);
$section = $section_default;
@@ -2210,8 +2151,7 @@ sub process_body($$) {
}
# look for doc_com + <text> + doc_end:
if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') {
- print STDERR "${file}:$.: warning: suspicious ending line: $_";
- ++$warnings;
+ emit_warning("${file}:$.", "suspicious ending line: $_");
}
$prototype = "";
@@ -2255,8 +2195,7 @@ sub process_body($$) {
}
} else {
# i dont know - bad line? ignore.
- print STDERR "${file}:$.: warning: bad line: $_";
- ++$warnings;
+ emit_warning("${file}:$.", "bad line: $_");
}
}
@@ -2350,9 +2289,7 @@ sub process_inline($$) {
}
} elsif ($inline_doc_state == STATE_INLINE_NAME) {
$inline_doc_state = STATE_INLINE_ERROR;
- print STDERR "${file}:$.: warning: ";
- print STDERR "Incorrect use of kernel-doc format: $_";
- ++$warnings;
+ emit_warning("${file}:$.", "Incorrect use of kernel-doc format: $_");
}
}
}
@@ -2401,11 +2338,11 @@ sub process_file($) {
if ($initial_section_counter == $section_counter && $
output_mode ne "none") {
if ($output_selection == OUTPUT_INCLUDE) {
- print STDERR "${file}:1: warning: '$_' not found\n"
+ emit_warning("${file}:1", "'$_' not found\n")
for keys %function_table;
}
else {
- print STDERR "${file}:1: warning: no structured comments found\n";
+ emit_warning("${file}:1", "no structured comments found\n");
}
}
close IN_FILE;
@@ -2468,3 +2405,117 @@ if ($Werror && $warnings) {
} else {
exit($output_mode eq "none" ? 0 : $errors)
}
+
+__END__
+
+=head1 OPTIONS
+
+=head2 Output format selection (mutually exclusive):
+
+=over 8
+
+=item -man
+
+Output troff manual page format.
+
+=item -rst
+
+Output reStructuredText format. This is the default.
+
+=item -none
+
+Do not output documentation, only warnings.
+
+=back
+
+=head2 Output format modifiers
+
+=head3 reStructuredText only
+
+=over 8
+
+=item -sphinx-version VERSION
+
+Use the ReST C domain dialect compatible with a specific Sphinx Version.
+
+If not specified, kernel-doc will auto-detect using the sphinx-build version
+found on PATH.
+
+=back
+
+=head2 Output selection (mutually exclusive):
+
+=over 8
+
+=item -export
+
+Only output documentation for the symbols that have been exported using
+EXPORT_SYMBOL() and related macros in any input FILE or -export-file FILE.
+
+=item -internal
+
+Only output documentation for the symbols that have NOT been exported using
+EXPORT_SYMBOL() and related macros in any input FILE or -export-file FILE.
+
+=item -function NAME
+
+Only output documentation for the given function or DOC: section title.
+All other functions and DOC: sections are ignored.
+
+May be specified multiple times.
+
+=item -nosymbol NAME
+
+Exclude the specified symbol from the output documentation.
+
+May be specified multiple times.
+
+=back
+
+=head2 Output selection modifiers:
+
+=over 8
+
+=item -no-doc-sections
+
+Do not output DOC: sections.
+
+=item -export-file FILE
+
+Specify an additional FILE in which to look for EXPORT_SYMBOL information.
+
+To be used with -export or -internal.
+
+May be specified multiple times.
+
+=back
+
+=head3 reStructuredText only
+
+=over 8
+
+=item -enable-lineno
+
+Enable output of .. LINENO lines.
+
+=back
+
+=head2 Other parameters:
+
+=over 8
+
+=item -h, -help
+
+Print this help.
+
+=item -v
+
+Verbose output, more warnings and other information.
+
+=item -Werror
+
+Treat warnings as errors.
+
+=back
+
+=cut
diff --git a/scripts/ld-version.sh b/scripts/ld-version.sh
index a463273509b5..a78b804b680c 100755
--- a/scripts/ld-version.sh
+++ b/scripts/ld-version.sh
@@ -6,11 +6,6 @@
set -e
-# When you raise the minimum linker version, please update
-# Documentation/process/changes.rst as well.
-bfd_min_version=2.23.0
-lld_min_version=10.0.1
-
# Convert the version string x.y.z to a canonical 5 or 6-digit form.
get_canonical_version()
{
@@ -29,29 +24,37 @@ orig_args="$@"
# Get the first line of the --version output.
IFS='
'
-set -- $("$@" --version)
+set -- $(LC_ALL=C "$@" --version)
# Split the line on spaces.
IFS=' '
set -- $1
+min_tool_version=$(dirname $0)/min-tool-version.sh
+
if [ "$1" = GNU -a "$2" = ld ]; then
shift $(($# - 1))
version=$1
- min_version=$bfd_min_version
+ min_version=$($min_tool_version binutils)
name=BFD
disp_name="GNU ld"
elif [ "$1" = GNU -a "$2" = gold ]; then
echo "gold linker is not supported as it is not capable of linking the kernel proper." >&2
exit 1
-elif [ "$1" = LLD ]; then
- version=$2
- min_version=$lld_min_version
- name=LLD
- disp_name=LLD
else
- echo "$orig_args: unknown linker" >&2
- exit 1
+ while [ $# -gt 1 -a "$1" != "LLD" ]; do
+ shift
+ done
+
+ if [ "$1" = LLD ]; then
+ version=$2
+ min_version=$($min_tool_version llvm)
+ name=LLD
+ disp_name=LLD
+ else
+ echo "$orig_args: unknown linker" >&2
+ exit 1
+ fi
fi
# Some distributions append a package release number, as in 2.34-4.fc32
diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl
index b2d8b8aa2d99..e695634d153d 100755
--- a/scripts/leaking_addresses.pl
+++ b/scripts/leaking_addresses.pl
@@ -61,6 +61,7 @@ my @skip_abs = (
'/proc/device-tree',
'/proc/1/syscall',
'/sys/firmware/devicetree',
+ '/sys/kernel/tracing/trace_pipe',
'/sys/kernel/debug/tracing/trace_pipe',
'/sys/kernel/security/apparmor/revision');
@@ -455,8 +456,9 @@ sub parse_file
open my $fh, "<", $file or return;
while ( <$fh> ) {
+ chomp;
if (may_leak_address($_)) {
- print $file . ': ' . $_;
+ printf("$file: $_\n");
}
}
close $fh;
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 3b261b0f74f0..a432b171be82 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -3,17 +3,15 @@
#
# link vmlinux
#
-# vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_OBJS) and
-# $(KBUILD_VMLINUX_LIBS). Most are built-in.a files from top-level directories
-# in the kernel tree, others are specified in arch/$(ARCH)/Makefile.
+# vmlinux is linked from the objects in vmlinux.a and $(KBUILD_VMLINUX_LIBS).
+# vmlinux.a contains objects that are linked unconditionally.
# $(KBUILD_VMLINUX_LIBS) are archives which are linked conditionally
# (not within --whole-archive), and do not require symbol indexes added.
#
# vmlinux
# ^
# |
-# +--< $(KBUILD_VMLINUX_OBJS)
-# | +--< init/built-in.a drivers/built-in.a mm/built-in.a + more
+# +--< vmlinux.a
# |
# +--< $(KBUILD_VMLINUX_LIBS)
# | +--< lib/lib.a + more
@@ -34,177 +32,76 @@ LD="$1"
KBUILD_LDFLAGS="$2"
LDFLAGS_vmlinux="$3"
+is_enabled() {
+ grep -q "^$1=y" include/config/auto.conf
+}
+
# Nice output in kbuild format
# Will be supressed by "make -s"
info()
{
- if [ "${quiet}" != "silent_" ]; then
- printf " %-7s %s\n" "${1}" "${2}"
- fi
+ printf " %-7s %s\n" "${1}" "${2}"
}
-# Generate a linker script to ensure correct ordering of initcalls.
-gen_initcalls()
+# Link of vmlinux
+# ${1} - output file
+# ${2}, ${3}, ... - optional extra .o files
+vmlinux_link()
{
- info GEN .tmp_initcalls.lds
+ local output=${1}
+ local objs
+ local libs
+ local ld
+ local ldflags
+ local ldlibs
- ${PYTHON} ${srctree}/scripts/jobserver-exec \
- ${PERL} ${srctree}/scripts/generate_initcall_order.pl \
- ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS} \
- > .tmp_initcalls.lds
-}
+ info LD ${output}
-# If CONFIG_LTO_CLANG is selected, collect generated symbol versions into
-# .tmp_symversions.lds
-gen_symversions()
-{
- info GEN .tmp_symversions.lds
- rm -f .tmp_symversions.lds
-
- for o in ${KBUILD_VMLINUX_OBJS} ${KBUILD_VMLINUX_LIBS}; do
- if [ -f ${o}.symversions ]; then
- cat ${o}.symversions >> .tmp_symversions.lds
- fi
- done
-}
+ # skip output file argument
+ shift
-# Link of vmlinux.o used for section mismatch analysis
-# ${1} output file
-modpost_link()
-{
- local objects
- local lds=""
-
- objects="--whole-archive \
- ${KBUILD_VMLINUX_OBJS} \
- --no-whole-archive \
- --start-group \
- ${KBUILD_VMLINUX_LIBS} \
- --end-group"
-
- if [ -n "${CONFIG_LTO_CLANG}" ]; then
- gen_initcalls
- lds="-T .tmp_initcalls.lds"
-
- if [ -n "${CONFIG_MODVERSIONS}" ]; then
- gen_symversions
- lds="${lds} -T .tmp_symversions.lds"
- fi
-
- # This might take a while, so indicate that we're doing
- # an LTO link
- info LTO ${1}
+ if is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT; then
+ # Use vmlinux.o instead of performing the slow LTO link again.
+ objs=vmlinux.o
+ libs=
else
- info LD ${1}
+ objs=vmlinux.a
+ libs="${KBUILD_VMLINUX_LIBS}"
fi
- ${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${lds} ${objects}
-}
-
-objtool_link()
-{
- local objtoolcmd;
- local objtoolopt;
-
- if [ "${CONFIG_LTO_CLANG} ${CONFIG_STACK_VALIDATION}" = "y y" ]; then
- # Don't perform vmlinux validation unless explicitly requested,
- # but run objtool on vmlinux.o now that we have an object file.
- if [ -n "${CONFIG_UNWINDER_ORC}" ]; then
- objtoolcmd="orc generate"
- fi
-
- objtoolopt="${objtoolopt} --duplicate"
-
- if [ -n "${CONFIG_FTRACE_MCOUNT_USE_OBJTOOL}" ]; then
- objtoolopt="${objtoolopt} --mcount"
- fi
+ if is_enabled CONFIG_MODULES; then
+ objs="${objs} .vmlinux.export.o"
fi
- if [ -n "${CONFIG_VMLINUX_VALIDATION}" ]; then
- objtoolopt="${objtoolopt} --noinstr"
- fi
+ objs="${objs} init/version-timestamp.o"
- if [ -n "${objtoolopt}" ]; then
- if [ -z "${objtoolcmd}" ]; then
- objtoolcmd="check"
- fi
- objtoolopt="${objtoolopt} --vmlinux"
- if [ -z "${CONFIG_FRAME_POINTER}" ]; then
- objtoolopt="${objtoolopt} --no-fp"
- fi
- if [ -n "${CONFIG_GCOV_KERNEL}" ] || [ -n "${CONFIG_LTO_CLANG}" ]; then
- objtoolopt="${objtoolopt} --no-unreachable"
- fi
- if [ -n "${CONFIG_RETPOLINE}" ]; then
- objtoolopt="${objtoolopt} --retpoline"
- fi
- if [ -n "${CONFIG_X86_SMAP}" ]; then
- objtoolopt="${objtoolopt} --uaccess"
- fi
- info OBJTOOL ${1}
- tools/objtool/objtool ${objtoolcmd} ${objtoolopt} ${1}
+ if [ "${SRCARCH}" = "um" ]; then
+ wl=-Wl,
+ ld="${CC}"
+ ldflags="${CFLAGS_vmlinux}"
+ ldlibs="-lutil -lrt -lpthread"
+ else
+ wl=
+ ld="${LD}"
+ ldflags="${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux}"
+ ldlibs=
fi
-}
-# Link of vmlinux
-# ${1} - output file
-# ${2}, ${3}, ... - optional extra .o files
-vmlinux_link()
-{
- local lds="${objtree}/${KBUILD_LDS}"
- local output=${1}
- local objects
- local strip_debug
-
- info LD ${output}
-
- # skip output file argument
- shift
+ ldflags="${ldflags} ${wl}--script=${objtree}/${KBUILD_LDS}"
# The kallsyms linking does not need debug symbols included.
if [ "$output" != "${output#.tmp_vmlinux.kallsyms}" ] ; then
- strip_debug=-Wl,--strip-debug
+ ldflags="${ldflags} ${wl}--strip-debug"
fi
- if [ "${SRCARCH}" != "um" ]; then
- if [ -n "${CONFIG_LTO_CLANG}" ]; then
- # Use vmlinux.o instead of performing the slow LTO
- # link again.
- objects="--whole-archive \
- vmlinux.o \
- --no-whole-archive \
- ${@}"
- else
- objects="--whole-archive \
- ${KBUILD_VMLINUX_OBJS} \
- --no-whole-archive \
- --start-group \
- ${KBUILD_VMLINUX_LIBS} \
- --end-group \
- ${@}"
- fi
-
- ${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} \
- ${strip_debug#-Wl,} \
- -o ${output} \
- -T ${lds} ${objects}
- else
- objects="-Wl,--whole-archive \
- ${KBUILD_VMLINUX_OBJS} \
- -Wl,--no-whole-archive \
- -Wl,--start-group \
- ${KBUILD_VMLINUX_LIBS} \
- -Wl,--end-group \
- ${@}"
-
- ${CC} ${CFLAGS_vmlinux} \
- ${strip_debug} \
- -o ${output} \
- -Wl,-T,${lds} \
- ${objects} \
- -lutil -lrt -lpthread
- rm -f linux
+ if is_enabled CONFIG_VMLINUX_MAP; then
+ ldflags="${ldflags} ${wl}-Map=${output}.map"
fi
+
+ ${ld} ${ldflags} -o ${output} \
+ ${wl}--whole-archive ${objs} ${wl}--no-whole-archive \
+ ${wl}--start-group ${libs} ${wl}--end-group \
+ $@ ${ldlibs}
}
# generate .BTF typeinfo from DWARF debuginfo
@@ -228,7 +125,7 @@ gen_btf()
vmlinux_link ${1}
info "BTF" ${2}
- LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1}
+ LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1}
# Create ${2} which contains just .BTF section but no symbols. Add
# SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all
@@ -247,20 +144,24 @@ kallsyms()
{
local kallsymopt;
- if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then
+ if is_enabled CONFIG_KALLSYMS_ALL; then
kallsymopt="${kallsymopt} --all-symbols"
fi
- if [ -n "${CONFIG_KALLSYMS_ABSOLUTE_PERCPU}" ]; then
+ if is_enabled CONFIG_KALLSYMS_ABSOLUTE_PERCPU; then
kallsymopt="${kallsymopt} --absolute-percpu"
fi
- if [ -n "${CONFIG_KALLSYMS_BASE_RELATIVE}" ]; then
+ if is_enabled CONFIG_KALLSYMS_BASE_RELATIVE; then
kallsymopt="${kallsymopt} --base-relative"
fi
+ if is_enabled CONFIG_LTO_CLANG; then
+ kallsymopt="${kallsymopt} --lto-clang"
+ fi
+
info KSYMS ${2}
- ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2}
+ scripts/kallsyms ${kallsymopt} ${1} > ${2}
}
# Perform one step in kallsyms generation, including temporary linking of
@@ -273,7 +174,8 @@ kallsyms_step()
kallsyms_S=${kallsyms_vmlinux}.S
vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o}
- kallsyms ${kallsyms_vmlinux} ${kallsyms_S}
+ mksysmap ${kallsyms_vmlinux} ${kallsyms_vmlinux}.syms ${kallsymso_prev}
+ kallsyms ${kallsyms_vmlinux}.syms ${kallsyms_S}
info AS ${kallsyms_S}
${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \
@@ -285,7 +187,8 @@ kallsyms_step()
# See mksymap for additional details
mksysmap()
{
- ${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2}
+ info NM ${2}
+ ${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2} ${3}
}
sorttable()
@@ -297,29 +200,11 @@ sorttable()
cleanup()
{
rm -f .btf.*
- rm -f .tmp_System.map
- rm -f .tmp_initcalls.lds
- rm -f .tmp_symversions.lds
- rm -f .tmp_vmlinux*
rm -f System.map
rm -f vmlinux
- rm -f vmlinux.o
+ rm -f vmlinux.map
}
-on_exit()
-{
- if [ $? -ne 0 ]; then
- cleanup
- fi
-}
-trap on_exit EXIT
-
-on_signals()
-{
- exit 1
-}
-trap on_signals HUP INT QUIT TERM
-
# Use "make V=1" to debug this script
case "${KBUILD_VERBOSE}" in
*1*)
@@ -332,38 +217,10 @@ if [ "$1" = "clean" ]; then
exit 0
fi
-# We need access to CONFIG_ symbols
-. include/config/auto.conf
-
-# Update version
-info GEN .version
-if [ -r .version ]; then
- VERSION=$(expr 0$(cat .version) + 1)
- echo $VERSION > .version
-else
- rm -f .version
- echo 1 > .version
-fi;
-
-# final build of init/
-${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1
-
-#link vmlinux.o
-modpost_link vmlinux.o
-objtool_link vmlinux.o
-
-# modpost vmlinux.o to check for section mismatches
-${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1
-
-info MODINFO modules.builtin.modinfo
-${OBJCOPY} -j .modinfo -O binary vmlinux.o modules.builtin.modinfo
-info GEN modules.builtin
-# The second line aids cases where multiple modules share the same object.
-tr '\0' '\n' < modules.builtin.modinfo | sed -n 's/^[[:alnum:]:_]*\.file=//p' |
- tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$/.ko/' > modules.builtin
+${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init init/version-timestamp.o
btf_vmlinux_bin_o=""
-if [ -n "${CONFIG_DEBUG_INFO_BTF}" ]; then
+if is_enabled CONFIG_DEBUG_INFO_BTF; then
btf_vmlinux_bin_o=.btf.vmlinux.bin.o
if ! gen_btf .tmp_vmlinux.btf $btf_vmlinux_bin_o ; then
echo >&2 "Failed to generate BTF for vmlinux"
@@ -375,19 +232,19 @@ fi
kallsymso=""
kallsymso_prev=""
kallsyms_vmlinux=""
-if [ -n "${CONFIG_KALLSYMS}" ]; then
+if is_enabled CONFIG_KALLSYMS; then
# kallsyms support
# Generate section listing all symbols and add it into vmlinux
# It's a three step process:
- # 1) Link .tmp_vmlinux1 so it has all symbols and sections,
+ # 1) Link .tmp_vmlinux.kallsyms1 so it has all symbols and sections,
# but __kallsyms is empty.
# Running kallsyms on that gives us .tmp_kallsyms1.o with
# the right size
- # 2) Link .tmp_vmlinux2 so it now has a __kallsyms section of
+ # 2) Link .tmp_vmlinux.kallsyms2 so it now has a __kallsyms section of
# the right size, but due to the added section, some
# addresses have shifted.
- # From here, we generate a correct .tmp_kallsyms2.o
+ # From here, we generate a correct .tmp_vmlinux.kallsyms2.o
# 3) That link may have expanded the kernel image enough that
# more linker branch stubs / trampolines had to be added, which
# introduces new names, which further expands kallsyms. Do another
@@ -415,12 +272,14 @@ fi
vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o}
# fill in BTF IDs
-if [ -n "${CONFIG_DEBUG_INFO_BTF}" -a -n "${CONFIG_BPF}" ]; then
+if is_enabled CONFIG_DEBUG_INFO_BTF && is_enabled CONFIG_BPF; then
info BTFIDS vmlinux
${RESOLVE_BTFIDS} vmlinux
fi
-if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then
+mksysmap vmlinux System.map ${kallsymso}
+
+if is_enabled CONFIG_BUILDTIME_TABLE_SORT; then
info SORTTAB vmlinux
if ! sorttable vmlinux; then
echo >&2 Failed to sort kernel tables
@@ -428,16 +287,14 @@ if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then
fi
fi
-info SYSMAP System.map
-mksysmap vmlinux System.map
-
# step a (see comment above)
-if [ -n "${CONFIG_KALLSYMS}" ]; then
- mksysmap ${kallsyms_vmlinux} .tmp_System.map
-
- if ! cmp -s System.map .tmp_System.map; then
+if is_enabled CONFIG_KALLSYMS; then
+ if ! cmp -s System.map ${kallsyms_vmlinux}.syms; then
echo >&2 Inconsistent kallsyms data
- echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround
+ echo >&2 'Try "make KALLSYMS_EXTRA_PASS=1" as a workaround'
exit 1
fi
fi
+
+# For fixdep
+echo "vmlinux: $0" > .vmlinux.d
diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh
new file mode 100755
index 000000000000..2ade63149466
--- /dev/null
+++ b/scripts/min-tool-version.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Print the minimum supported version of the given tool.
+# When you raise the minimum version, please update
+# Documentation/process/changes.rst as well.
+
+set -e
+
+if [ $# != 1 ]; then
+ echo "Usage: $0 toolname" >&2
+ exit 1
+fi
+
+case "$1" in
+binutils)
+ echo 2.25.0
+ ;;
+gcc)
+ if [ "$ARCH" = parisc64 ]; then
+ echo 12.0.0
+ else
+ echo 5.1.0
+ fi
+ ;;
+llvm)
+ if [ "$SRCARCH" = s390 ]; then
+ echo 15.0.0
+ else
+ echo 11.0.0
+ fi
+ ;;
+rustc)
+ echo 1.68.2
+ ;;
+bindgen)
+ echo 0.56.0
+ ;;
+*)
+ echo "$1: unknown tool" >&2
+ exit 1
+ ;;
+esac
diff --git a/scripts/misc-check b/scripts/misc-check
new file mode 100755
index 000000000000..d40d5484e0c5
--- /dev/null
+++ b/scripts/misc-check
@@ -0,0 +1,19 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+
+set -e
+
+# Detect files that are tracked but ignored by git. This is checked only when
+# ${KBUILD_EXTRA_WARN} contains 1, git is installed, and the source tree is
+# tracked by git.
+check_tracked_ignored_files () {
+ case "${KBUILD_EXTRA_WARN}" in
+ *1*) ;;
+ *) return;;
+ esac
+
+ git -C ${srctree:-.} ls-files -i -c --exclude-per-directory=.gitignore 2>/dev/null |
+ sed 's/$/: warning: ignored by one of the .gitignore files/' >&2
+}
+
+check_tracked_ignored_files
diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
index 4ae735039daf..2596f78e52ef 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -1,34 +1,10 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
-TARGET=$1
-ARCH=$2
-SMP=$3
-PREEMPT=$4
-PREEMPT_RT=$5
-CC_VERSION="$6"
-LD=$7
+UTS_MACHINE=$1
+CC_VERSION="$2"
+LD=$3
-vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; }
-
-# Do not expand names
-set -f
-
-# Fix the language to get consistent output
-LC_ALL=C
-export LC_ALL
-
-if [ -z "$KBUILD_BUILD_VERSION" ]; then
- VERSION=$(cat .version 2>/dev/null || echo 1)
-else
- VERSION=$KBUILD_BUILD_VERSION
-fi
-
-if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
- TIMESTAMP=`date`
-else
- TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
-fi
if test -z "$KBUILD_BUILD_USER"; then
LINUX_COMPILE_BY=$(whoami | sed 's/\\/\\\\/')
else
@@ -40,49 +16,12 @@ else
LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST
fi
-UTS_VERSION="#$VERSION"
-CONFIG_FLAGS=""
-if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi
-if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi
-if [ -n "$PREEMPT_RT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT_RT"; fi
-
-# Truncate to maximum length
-UTS_LEN=64
-UTS_VERSION="$(echo $UTS_VERSION $CONFIG_FLAGS $TIMESTAMP | cut -b -$UTS_LEN)"
+LD_VERSION=$(LC_ALL=C $LD -v | head -n1 |
+ sed -e 's/(compatible with [^)]*)//' -e 's/[[:space:]]*$//')
-# Generate a temporary compile.h
-
-{ echo /\* This file is auto generated, version $VERSION \*/
- if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi
-
- echo \#define UTS_MACHINE \"$ARCH\"
-
- echo \#define UTS_VERSION \"$UTS_VERSION\"
-
- printf '#define LINUX_COMPILE_BY "%s"\n' "$LINUX_COMPILE_BY"
- echo \#define LINUX_COMPILE_HOST \"$LINUX_COMPILE_HOST\"
-
- LD_VERSION=$($LD -v | head -n1 | sed 's/(compatible with [^)]*)//' \
- | sed 's/[[:space:]]*$//')
- printf '#define LINUX_COMPILER "%s"\n' "$CC_VERSION, $LD_VERSION"
-} > .tmpcompile
-
-# Only replace the real compile.h if the new one is different,
-# in order to preserve the timestamp and avoid unnecessary
-# recompilations.
-# We don't consider the file changed if only the date/time changed.
-# A kernel config change will increase the generation number, thus
-# causing compile.h to be updated (including date/time) due to the
-# changed comment in the
-# first line.
-
-if [ -r $TARGET ] && \
- grep -v 'UTS_VERSION' $TARGET > .tmpver.1 && \
- grep -v 'UTS_VERSION' .tmpcompile > .tmpver.2 && \
- cmp -s .tmpver.1 .tmpver.2; then
- rm -f .tmpcompile
-else
- vecho " UPD $TARGET"
- mv -f .tmpcompile $TARGET
-fi
-rm -f .tmpver.1 .tmpver.2
+cat <<EOF
+#define UTS_MACHINE "${UTS_MACHINE}"
+#define LINUX_COMPILE_BY "${LINUX_COMPILE_BY}"
+#define LINUX_COMPILE_HOST "${LINUX_COMPILE_HOST}"
+#define LINUX_COMPILER "${CC_VERSION}, ${LD_VERSION}"
+EOF
diff --git a/scripts/mkmakefile b/scripts/mkmakefile
deleted file mode 100755
index 1cb174751429..000000000000
--- a/scripts/mkmakefile
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Generates a small Makefile used in the root of the output
-# directory, to allow make to be started from there.
-# The Makefile also allow for more convinient build of external modules
-
-# Usage
-# $1 - Kernel src directory
-
-if [ "${quiet}" != "silent_" ]; then
- echo " GEN Makefile"
-fi
-
-cat << EOF > Makefile
-# Automatically generated by $0: don't edit
-include $1/Makefile
-EOF
diff --git a/scripts/mksysmap b/scripts/mksysmap
index 9aa23d15862a..9ba1c9da0a40 100755
--- a/scripts/mksysmap
+++ b/scripts/mksysmap
@@ -4,41 +4,110 @@
# tools to retrieve the actual addresses of symbols in the kernel.
#
# Usage
-# mksysmap vmlinux System.map
+# mksysmap vmlinux System.map [exclude]
#####
# Generate System.map (actual filename passed as second argument)
-
-# $NM produces the following output:
-# f0081e80 T alloc_vfsmnt
-
-# The second row specify the type of the symbol:
-# A = Absolute
-# B = Uninitialised data (.bss)
-# C = Common symbol
-# D = Initialised data
-# G = Initialised data for small objects
-# I = Indirect reference to another symbol
-# N = Debugging symbol
-# R = Read only
-# S = Uninitialised data for small objects
-# T = Text code symbol
-# U = Undefined symbol
-# V = Weak symbol
-# W = Weak symbol
-# Corresponding small letters are local symbols
-
-# For System.map filter away:
-# a - local absolute symbols
-# U - undefined global symbols
-# N - debugging symbols
-# w - local weak symbols
+# The following refers to the symbol type as per nm(1).
# readprofile starts reading symbols when _stext is found, and
# continue until it finds a symbol which is not either of 'T', 't',
-# 'W' or 'w'. __crc_ are 'A' and placed in the middle
-# so we just ignore them to let readprofile continue to work.
-# (At least sparc64 has __crc_ in the middle).
+# 'W' or 'w'.
+#
+
+${NM} -n ${1} | sed >${2} -e "
+# ---------------------------------------------------------------------------
+# Ignored symbol types
+#
+
+# a: local absolute symbols
+# N: debugging symbols
+# U: undefined global symbols
+# w: local weak symbols
+/ [aNUw] /d
+
+# ---------------------------------------------------------------------------
+# Ignored prefixes
+# (do not forget a space before each pattern)
+
+# local symbols for ARM, MIPS, etc.
+/ \\$/d
+
+# local labels, .LBB, .Ltmpxxx, .L__unnamed_xx, .LASANPC, etc.
+/ \.L/d
+
+# arm64 EFI stub namespace
+/ __efistub_/d
+
+# arm64 local symbols in PIE namespace
+/ __pi_\\$/d
+/ __pi_\.L/d
+
+# arm64 local symbols in non-VHE KVM namespace
+/ __kvm_nvhe_\\$/d
+/ __kvm_nvhe_\.L/d
+
+# arm64 lld
+/ __AArch64ADRPThunk_/d
+
+# arm lld
+/ __ARMV5PILongThunk_/d
+/ __ARMV7PILongThunk_/d
+/ __ThumbV7PILongThunk_/d
-$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)\|\( \.L\)' > $2
+# mips lld
+/ __LA25Thunk_/d
+/ __microLA25Thunk_/d
+
+# CFI type identifiers
+/ __kcfi_typeid_/d
+/ __kvm_nvhe___kcfi_typeid_/d
+/ __pi___kcfi_typeid_/d
+
+# CRC from modversions
+/ __crc_/d
+
+# EXPORT_SYMBOL (symbol name)
+/ __kstrtab_/d
+
+# EXPORT_SYMBOL (namespace)
+/ __kstrtabns_/d
+
+# ---------------------------------------------------------------------------
+# Ignored suffixes
+# (do not forget '$' after each pattern)
+
+# arm
+/_from_arm$/d
+/_from_thumb$/d
+/_veneer$/d
+
+# ---------------------------------------------------------------------------
+# Ignored symbols (exact match)
+# (do not forget a space before and '$' after each pattern)
+
+# for LoongArch?
+/ L0$/d
+
+# ppc
+/ _SDA_BASE_$/d
+/ _SDA2_BASE_$/d
+
+# ---------------------------------------------------------------------------
+# Ignored patterns
+# (symbols that contain the pattern are ignored)
+
+# ppc stub
+/\.long_branch\./d
+/\.plt_branch\./d
+
+# ---------------------------------------------------------------------------
+# Ignored kallsyms symbols
+#
+# If the 3rd parameter exists, symbols from it will be omitted from the output.
+# This makes kallsyms have the identical symbol lists in the step 1 and 2.
+# Without this, the step2 would get new symbols generated by scripts/kallsyms.c
+# when CONFIG_KALLSYMS_ALL is enabled. That might require one more pass.
+$(if [ $# -ge 3 ]; then ${NM} ${3} | sed -n '/ U /!s:.* \([^ ]*\)$:/ \1$/d:p'; fi)
+"
diff --git a/scripts/mod/.gitignore b/scripts/mod/.gitignore
index 07e4a39f90a6..0465ec33c9bf 100644
--- a/scripts/mod/.gitignore
+++ b/scripts/mod/.gitignore
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-elfconfig.h
-mk_elfconfig
-modpost
-devicetable-offsets.h
+/devicetable-offsets.h
+/elfconfig.h
+/mk_elfconfig
+/modpost
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index 9bb6c7edccc4..abe65f8968dd 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -42,6 +42,7 @@ int main(void)
DEVID_FIELD(pci_device_id, subdevice);
DEVID_FIELD(pci_device_id, class);
DEVID_FIELD(pci_device_id, class_mask);
+ DEVID_FIELD(pci_device_id, override_only);
DEVID(ccw_device_id);
DEVID_FIELD(ccw_device_id, match_flags);
@@ -258,5 +259,13 @@ int main(void)
DEVID_FIELD(dfl_device_id, type);
DEVID_FIELD(dfl_device_id, feature_id);
+ DEVID(ishtp_device_id);
+ DEVID_FIELD(ishtp_device_id, guid);
+
+ DEVID(cdx_device_id);
+ DEVID_FIELD(cdx_device_id, vendor);
+ DEVID_FIELD(cdx_device_id, device);
+ DEVID_FIELD(cdx_device_id, override_only);
+
return 0;
}
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 7c97fa8e36bc..38120f932b0d 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -34,19 +34,23 @@ typedef Elf64_Addr kernel_ulong_t;
typedef uint32_t __u32;
typedef uint16_t __u16;
typedef unsigned char __u8;
+
+/* UUID types for backward compatibility, don't use in new code */
typedef struct {
__u8 b[16];
} guid_t;
-/* backwards compatibility, don't use in new code */
-typedef struct {
- __u8 b[16];
-} uuid_le;
typedef struct {
__u8 b[16];
} uuid_t;
+
#define UUID_STRING_LEN 36
+/* MEI UUID type, don't use anywhere else */
+typedef struct {
+ __u8 b[16];
+} uuid_le;
+
/* Big exception to the "don't include kernel headers into userspace, which
* even potentially has different endianness and word sizes, since
* we handle those differences explicitly below */
@@ -115,6 +119,17 @@ static inline void add_uuid(char *str, uuid_le uuid)
uuid.b[12], uuid.b[13], uuid.b[14], uuid.b[15]);
}
+static inline void add_guid(char *str, guid_t guid)
+{
+ int len = strlen(str);
+
+ sprintf(str + len, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ guid.b[3], guid.b[2], guid.b[1], guid.b[0],
+ guid.b[5], guid.b[4], guid.b[7], guid.b[6],
+ guid.b[8], guid.b[9], guid.b[10], guid.b[11],
+ guid.b[12], guid.b[13], guid.b[14], guid.b[15]);
+}
+
/**
* Check that sizeof(device_id type) are consistent with size of section
* in .o file. If in-consistent then userspace and kernel does not agree
@@ -129,25 +144,22 @@ static void device_id_check(const char *modname, const char *device_id,
int i;
if (size % id_size || size < id_size) {
- fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo "
- "of the size of "
- "section __mod_%s__<identifier>_device_table=%lu.\n"
- "Fix definition of struct %s_device_id "
- "in mod_devicetable.h\n",
+ fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo of the size of section __mod_%s__<identifier>_device_table=%lu.\n"
+ "Fix definition of struct %s_device_id in mod_devicetable.h\n",
modname, device_id, id_size, device_id, size, device_id);
}
/* Verify last one is a terminator */
for (i = 0; i < id_size; i++ ) {
if (*(uint8_t*)(symval+size-id_size+i)) {
- fprintf(stderr,"%s: struct %s_device_id is %lu bytes. "
- "The last of %lu is:\n",
+ fprintf(stderr,
+ "%s: struct %s_device_id is %lu bytes. The last of %lu is:\n",
modname, device_id, id_size, size / id_size);
for (i = 0; i < id_size; i++ )
fprintf(stderr,"0x%02x ",
*(uint8_t*)(symval+size-id_size+i) );
fprintf(stderr,"\n");
- fatal("%s: struct %s_device_id is not terminated "
- "with a NULL entry!\n", modname, device_id);
+ fatal("%s: struct %s_device_id is not terminated with a NULL entry!\n",
+ modname, device_id);
}
}
}
@@ -426,7 +438,7 @@ static int do_ieee1394_entry(const char *filename,
return 1;
}
-/* Looks like: pci:vNdNsvNsdNbcNscNiN. */
+/* Looks like: pci:vNdNsvNsdNbcNscNiN or <prefix>_pci:vNdNsvNsdNbcNscNiN. */
static int do_pci_entry(const char *filename,
void *symval, char *alias)
{
@@ -440,8 +452,21 @@ static int do_pci_entry(const char *filename,
DEF_FIELD(symval, pci_device_id, subdevice);
DEF_FIELD(symval, pci_device_id, class);
DEF_FIELD(symval, pci_device_id, class_mask);
+ DEF_FIELD(symval, pci_device_id, override_only);
+
+ switch (override_only) {
+ case 0:
+ strcpy(alias, "pci:");
+ break;
+ case PCI_ID_F_VFIO_DRIVER_OVERRIDE:
+ strcpy(alias, "vfio_pci:");
+ break;
+ default:
+ warn("Unknown PCI driver_override alias %08X\n",
+ override_only);
+ return 0;
+ }
- strcpy(alias, "pci:");
ADD(alias, "v", vendor != PCI_ANY_ID, vendor);
ADD(alias, "d", device != PCI_ANY_ID, device);
ADD(alias, "sv", subvendor != PCI_ANY_ID, subvendor);
@@ -710,8 +735,6 @@ static int do_vio_entry(const char *filename, void *symval,
return 1;
}
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
static void do_input(char *alias,
kernel_ulong_t *arr, unsigned int min, unsigned int max)
{
@@ -1132,8 +1155,7 @@ static int do_amba_entry(const char *filename,
DEF_FIELD(symval, amba_id, mask);
if ((id & mask) != id)
- fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: "
- "id=0x%08X, mask=0x%08X. Please fix this driver.\n",
+ fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: id=0x%08X, mask=0x%08X. Please fix this driver.\n",
filename, id, mask);
p += sprintf(alias, "amba:d");
@@ -1367,6 +1389,27 @@ static int do_mhi_entry(const char *filename, void *symval, char *alias)
return 1;
}
+/* Looks like: mhi_ep:S */
+static int do_mhi_ep_entry(const char *filename, void *symval, char *alias)
+{
+ DEF_FIELD_ADDR(symval, mhi_device_id, chan);
+ sprintf(alias, MHI_EP_DEVICE_MODALIAS_FMT, *chan);
+
+ return 1;
+}
+
+/* Looks like: ishtp:{guid} */
+static int do_ishtp_entry(const char *filename, void *symval, char *alias)
+{
+ DEF_FIELD(symval, ishtp_device_id, guid);
+
+ strcpy(alias, ISHTP_MODULE_PREFIX "{");
+ add_guid(alias, guid);
+ strcat(alias, "}");
+
+ return 1;
+}
+
static int do_auxiliary_entry(const char *filename, void *symval, char *alias)
{
DEF_FIELD_ADDR(symval, auxiliary_device_id, name);
@@ -1409,6 +1452,32 @@ static int do_dfl_entry(const char *filename, void *symval, char *alias)
return 1;
}
+/* Looks like: cdx:vNdN */
+static int do_cdx_entry(const char *filename, void *symval,
+ char *alias)
+{
+ DEF_FIELD(symval, cdx_device_id, vendor);
+ DEF_FIELD(symval, cdx_device_id, device);
+ DEF_FIELD(symval, cdx_device_id, override_only);
+
+ switch (override_only) {
+ case 0:
+ strcpy(alias, "cdx:");
+ break;
+ case CDX_ID_F_VFIO_DRIVER_OVERRIDE:
+ strcpy(alias, "vfio_cdx:");
+ break;
+ default:
+ warn("Unknown CDX driver_override alias %08X\n",
+ override_only);
+ return 0;
+ }
+
+ ADD(alias, "v", vendor != CDX_ANY_ID, vendor);
+ ADD(alias, "d", device != CDX_ANY_ID, device);
+ return 1;
+}
+
/* Does namelen bytes of name exactly match the symbol? */
static bool sym_is(const char *name, unsigned namelen, const char *symbol)
{
@@ -1483,9 +1552,12 @@ static const struct devtable devtable[] = {
{"tee", SIZE_tee_client_device_id, do_tee_entry},
{"wmi", SIZE_wmi_device_id, do_wmi_entry},
{"mhi", SIZE_mhi_device_id, do_mhi_entry},
+ {"mhi_ep", SIZE_mhi_device_id, do_mhi_ep_entry},
{"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry},
{"ssam", SIZE_ssam_device_id, do_ssam_entry},
{"dfl", SIZE_dfl_device_id, do_dfl_entry},
+ {"ishtp", SIZE_ishtp_device_id, do_ishtp_entry},
+ {"cdx", SIZE_cdx_device_id, do_cdx_entry},
};
/* Create MODULE_ALIAS() statements.
@@ -1526,9 +1598,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
zeros = calloc(1, sym->st_size);
symval = zeros;
} else {
- symval = (void *)info->hdr
- + info->sechdrs[get_secindex(info, sym)].sh_offset
- + sym->st_value;
+ symval = sym_get_data(info, sym);
}
/* First handle the "special" cases */
diff --git a/scripts/mod/list.h b/scripts/mod/list.h
new file mode 100644
index 000000000000..a924a6c4aa4d
--- /dev/null
+++ b/scripts/mod/list.h
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LIST_H
+#define LIST_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/* Are two types/vars the same type (ignoring qualifiers)? */
+#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ void *__mptr = (void *)(ptr); \
+ _Static_assert(__same_type(*(ptr), ((type *)0)->member) || \
+ __same_type(*(ptr), void), \
+ "pointer type mismatch in container_of()"); \
+ ((type *)(__mptr - offsetof(type, member))); })
+
+#define LIST_POISON1 ((void *) 0x100)
+#define LIST_POISON2 ((void *) 0x122)
+
+/*
+ * Circular doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+/**
+ * INIT_LIST_HEAD - Initialize a list_head structure
+ * @list: list_head structure to be initialized.
+ *
+ * Initializes the list_head to point to itself. If it is a list header,
+ * the result is an empty list.
+ */
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static inline void __list_del_entry(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del_entry(entry);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_is_head - tests whether @list is the list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_head(const struct list_head *list, const struct list_head *head)
+{
+ return list == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_next_entry - get the next element in list
+ * @pos: the type * to cursor
+ * @member: the name of the list_head within the struct.
+ */
+#define list_next_entry(pos, member) \
+ list_entry((pos)->member.next, typeof(*(pos)), member)
+
+/**
+ * list_entry_is_head - test if the entry points to the head of the list
+ * @pos: the type * to cursor
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_entry_is_head(pos, head, member) \
+ (&pos->member == (head))
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_first_entry(head, typeof(*pos), member); \
+ !list_entry_is_head(pos, head, member); \
+ pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type. Safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_head within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_first_entry(head, typeof(*pos), member), \
+ n = list_next_entry(pos, member); \
+ !list_entry_is_head(pos, head, member); \
+ pos = n, n = list_next_entry(n, member))
+
+#endif /* LIST_H */
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 24725e50c7b4..ba981f22908a 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -13,39 +13,46 @@
#define _GNU_SOURCE
#include <elf.h>
+#include <fnmatch.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
+#include <stdbool.h>
#include <errno.h>
#include "modpost.h"
#include "../../include/linux/license.h"
+#include "../../include/linux/module_symbol.h"
/* Are we using CONFIG_MODVERSIONS? */
-static int modversions = 0;
-/* Warn about undefined symbols? (do so if we have vmlinux) */
-static int have_vmlinux = 0;
+static bool modversions;
/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
-static int all_versions = 0;
+static bool all_versions;
/* If we are modposting external module set to 1 */
-static int external_module = 0;
+static bool external_module;
/* Only warn about unresolved symbols */
-static int warn_unresolved = 0;
-/* How a symbol is exported */
-static int sec_mismatch_count = 0;
-static int sec_mismatch_warn_only = true;
+static bool warn_unresolved;
+
+static int sec_mismatch_count;
+static bool sec_mismatch_warn_only = true;
+/* Trim EXPORT_SYMBOLs that are unused by in-tree modules */
+static bool trim_unused_exports;
+
/* ignore missing files */
-static int ignore_missing_files;
+static bool ignore_missing_files;
/* If set to 1, only warn (instead of error) about missing ns imports */
-static int allow_missing_ns_imports;
+static bool allow_missing_ns_imports;
static bool error_occurred;
-enum export {
- export_plain,
- export_gpl,
- export_unknown
-};
+static bool extra_warn;
+
+/*
+ * Cut off the warnings when there are too many. This typically occurs when
+ * vmlinux is missing. ('make modules' without building vmlinux.)
+ */
+#define MAX_UNRESOLVED_REPORTS 10
+static unsigned int nr_unresolved;
/* In kernel, this size is defined in linux/module.h;
* here we use Elf_Addr instead of long for covering cross-compile
@@ -84,6 +91,14 @@ modpost_log(enum loglevel loglevel, const char *fmt, ...)
error_occurred = true;
}
+static inline bool strends(const char *str, const char *postfix)
+{
+ if (strlen(str) < strlen(postfix))
+ return false;
+
+ return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
+}
+
void *do_nofail(void *ptr, const char *expr)
{
if (!ptr)
@@ -151,34 +166,43 @@ char *get_line(char **stringp)
}
/* A list of all modules we processed */
-static struct module *modules;
+LIST_HEAD(modules);
static struct module *find_module(const char *modname)
{
struct module *mod;
- for (mod = modules; mod; mod = mod->next)
+ list_for_each_entry(mod, &modules, list) {
if (strcmp(mod->name, modname) == 0)
- break;
- return mod;
+ return mod;
+ }
+ return NULL;
}
-static struct module *new_module(const char *modname)
+static struct module *new_module(const char *name, size_t namelen)
{
struct module *mod;
- mod = NOFAIL(malloc(sizeof(*mod) + strlen(modname) + 1));
+ mod = NOFAIL(malloc(sizeof(*mod) + namelen + 1));
memset(mod, 0, sizeof(*mod));
- /* add to list */
- strcpy(mod->name, modname);
- mod->is_vmlinux = (strcmp(modname, "vmlinux") == 0);
- mod->gpl_compatible = -1;
- mod->next = modules;
- modules = mod;
+ INIT_LIST_HEAD(&mod->exported_symbols);
+ INIT_LIST_HEAD(&mod->unresolved_symbols);
+ INIT_LIST_HEAD(&mod->missing_namespaces);
+ INIT_LIST_HEAD(&mod->imported_namespaces);
- if (mod->is_vmlinux)
- have_vmlinux = 1;
+ memcpy(mod->name, name, namelen);
+ mod->name[namelen] = '\0';
+ mod->is_vmlinux = (strcmp(mod->name, "vmlinux") == 0);
+
+ /*
+ * Set mod->is_gpl_compatible to true by default. If MODULE_LICENSE()
+ * is missing, do not check the use for EXPORT_SYMBOL_GPL() becasue
+ * modpost will exit wiht error anyway.
+ */
+ mod->is_gpl_compatible = true;
+
+ list_add_tail(&mod->list, &modules);
return mod;
}
@@ -190,19 +214,21 @@ static struct module *new_module(const char *modname)
struct symbol {
struct symbol *next;
+ struct list_head list; /* link to module::exported_symbols or module::unresolved_symbols */
struct module *module;
- unsigned int crc;
- int crc_valid;
char *namespace;
- unsigned int weak:1;
- unsigned int is_static:1; /* 1 if symbol is not global */
- enum export export; /* Type of export */
+ unsigned int crc;
+ bool crc_valid;
+ bool weak;
+ bool is_func;
+ bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */
+ bool used; /* there exists a user of this symbol */
char name[];
};
static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
-/* This is based on the hash agorithm from gdbm, via tdb */
+/* This is based on the hash algorithm from gdbm, via tdb */
static inline unsigned int tdb_hash(const char *name)
{
unsigned value; /* Used to compute the hash value. */
@@ -219,32 +245,37 @@ static inline unsigned int tdb_hash(const char *name)
* Allocate a new symbols for use in the hash of exported symbols or
* the list of unresolved symbols per module
**/
-static struct symbol *alloc_symbol(const char *name, unsigned int weak,
- struct symbol *next)
+static struct symbol *alloc_symbol(const char *name)
{
struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
memset(s, 0, sizeof(*s));
strcpy(s->name, name);
- s->weak = weak;
- s->next = next;
- s->is_static = 1;
+
return s;
}
/* For the hash of exported symbols */
-static struct symbol *new_symbol(const char *name, struct module *module,
- enum export export)
+static void hash_add_symbol(struct symbol *sym)
{
unsigned int hash;
- hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
- symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
+ hash = tdb_hash(sym->name) % SYMBOL_HASH_SIZE;
+ sym->next = symbolhash[hash];
+ symbolhash[hash] = sym;
+}
+
+static void sym_add_unresolved(const char *name, struct module *mod, bool weak)
+{
+ struct symbol *sym;
- return symbolhash[hash];
+ sym = alloc_symbol(name);
+ sym->weak = weak;
+
+ list_add_tail(&sym->list, &mod->unresolved_symbols);
}
-static struct symbol *find_symbol(const char *name)
+static struct symbol *sym_find_with_module(const char *name, struct module *mod)
{
struct symbol *s;
@@ -253,67 +284,51 @@ static struct symbol *find_symbol(const char *name)
name++;
for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) {
- if (strcmp(s->name, name) == 0)
+ if (strcmp(s->name, name) == 0 && (!mod || s->module == mod))
return s;
}
return NULL;
}
-static bool contains_namespace(struct namespace_list *list,
- const char *namespace)
+static struct symbol *find_symbol(const char *name)
{
- for (; list; list = list->next)
- if (!strcmp(list->namespace, namespace))
- return true;
-
- return false;
+ return sym_find_with_module(name, NULL);
}
-static void add_namespace(struct namespace_list **list, const char *namespace)
-{
- struct namespace_list *ns_entry;
-
- if (!contains_namespace(*list, namespace)) {
- ns_entry = NOFAIL(malloc(sizeof(struct namespace_list) +
- strlen(namespace) + 1));
- strcpy(ns_entry->namespace, namespace);
- ns_entry->next = *list;
- *list = ns_entry;
- }
-}
+struct namespace_list {
+ struct list_head list;
+ char namespace[];
+};
-static bool module_imports_namespace(struct module *module,
- const char *namespace)
+static bool contains_namespace(struct list_head *head, const char *namespace)
{
- return contains_namespace(module->imported_namespaces, namespace);
-}
+ struct namespace_list *list;
-static const struct {
- const char *str;
- enum export export;
-} export_list[] = {
- { .str = "EXPORT_SYMBOL", .export = export_plain },
- { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl },
- { .str = "(unknown)", .export = export_unknown },
-};
+ /*
+ * The default namespace is null string "", which is always implicitly
+ * contained.
+ */
+ if (!namespace[0])
+ return true;
+ list_for_each_entry(list, head, list) {
+ if (!strcmp(list->namespace, namespace))
+ return true;
+ }
-static const char *export_str(enum export ex)
-{
- return export_list[ex].str;
+ return false;
}
-static enum export export_no(const char *s)
+static void add_namespace(struct list_head *head, const char *namespace)
{
- int i;
+ struct namespace_list *ns_entry;
- if (!s)
- return export_unknown;
- for (i = 0; export_list[i].export != export_unknown; i++) {
- if (strcmp(export_list[i].str, s) == 0)
- return export_list[i].export;
+ if (!contains_namespace(head, namespace)) {
+ ns_entry = NOFAIL(malloc(sizeof(*ns_entry) +
+ strlen(namespace) + 1));
+ strcpy(ns_entry->namespace, namespace);
+ list_add_tail(&ns_entry->list, head);
}
- return export_unknown;
}
static void *sym_get_data_by_offset(const struct elf_info *info,
@@ -321,13 +336,10 @@ static void *sym_get_data_by_offset(const struct elf_info *info,
{
Elf_Shdr *sechdr = &info->sechdrs[secindex];
- if (info->hdr->e_type != ET_REL)
- offset -= sechdr->sh_addr;
-
return (void *)info->hdr + sechdr->sh_offset + offset;
}
-static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
+void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
{
return sym_get_data_by_offset(info, get_secindex(info, sym),
sym->st_value);
@@ -339,98 +351,46 @@ static const char *sech_name(const struct elf_info *info, Elf_Shdr *sechdr)
sechdr->sh_name);
}
-static const char *sec_name(const struct elf_info *info, int secindex)
-{
- return sech_name(info, &info->sechdrs[secindex]);
-}
-
-#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
-
-static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
-{
- const char *secname = sec_name(elf, sec);
-
- if (strstarts(secname, "___ksymtab+"))
- return export_plain;
- else if (strstarts(secname, "___ksymtab_gpl+"))
- return export_gpl;
- else
- return export_unknown;
-}
-
-static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
-{
- if (sec == elf->export_sec)
- return export_plain;
- else if (sec == elf->export_gpl_sec)
- return export_gpl;
- else
- return export_unknown;
-}
-
-static const char *namespace_from_kstrtabns(const struct elf_info *info,
- const Elf_Sym *sym)
-{
- const char *value = sym_get_data(info, sym);
- return value[0] ? value : NULL;
-}
-
-static void sym_update_namespace(const char *symname, const char *namespace)
+static const char *sec_name(const struct elf_info *info, unsigned int secindex)
{
- struct symbol *s = find_symbol(symname);
-
/*
- * That symbol should have been created earlier and thus this is
- * actually an assertion.
+ * If sym->st_shndx is a special section index, there is no
+ * corresponding section header.
+ * Return "" if the index is out of range of info->sechdrs[] array.
*/
- if (!s) {
- error("Could not update namespace(%s) for symbol %s\n",
- namespace, symname);
- return;
- }
+ if (secindex >= info->num_sections)
+ return "";
- free(s->namespace);
- s->namespace =
- namespace && namespace[0] ? NOFAIL(strdup(namespace)) : NULL;
+ return sech_name(info, &info->sechdrs[secindex]);
}
-/**
- * Add an exported symbol - it may have already been added without a
- * CRC, in this case just update the CRC
- **/
+#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
+
static struct symbol *sym_add_exported(const char *name, struct module *mod,
- enum export export)
+ bool gpl_only, const char *namespace)
{
struct symbol *s = find_symbol(name);
- if (!s) {
- s = new_symbol(name, mod, export);
- } else if (!external_module || s->module->is_vmlinux ||
- s->module == mod) {
- warn("%s: '%s' exported twice. Previous export was in %s%s\n",
- mod->name, name, s->module->name,
- s->module->is_vmlinux ? "" : ".ko");
- return s;
+ if (s && (!external_module || s->module->is_vmlinux || s->module == mod)) {
+ error("%s: '%s' exported twice. Previous export was in %s%s\n",
+ mod->name, name, s->module->name,
+ s->module->is_vmlinux ? "" : ".ko");
}
+ s = alloc_symbol(name);
s->module = mod;
- s->export = export;
+ s->is_gpl_only = gpl_only;
+ s->namespace = NOFAIL(strdup(namespace));
+ list_add_tail(&s->list, &mod->exported_symbols);
+ hash_add_symbol(s);
+
return s;
}
-static void sym_set_crc(const char *name, unsigned int crc)
+static void sym_set_crc(struct symbol *sym, unsigned int crc)
{
- struct symbol *s = find_symbol(name);
-
- /*
- * Ignore stand-alone __crc_*, which might be auto-generated symbols
- * such as __*_veneer in ARM ELF.
- */
- if (!s)
- return;
-
- s->crc = crc;
- s->crc_valid = 1;
+ sym->crc = crc;
+ sym->crc_valid = true;
}
static void *grab_file(const char *filename, size_t *size)
@@ -509,6 +469,10 @@ static int parse_elf(struct elf_info *info, const char *filename)
sechdrs = (void *)hdr + hdr->e_shoff;
info->sechdrs = sechdrs;
+ /* modpost only works for relocatable objects */
+ if (hdr->e_type != ET_REL)
+ fatal("%s: not relocatable object.", filename);
+
/* Check if file offset is correct */
if (hdr->e_shoff > info->size) {
fatal("section header offset=%lu in file '%s' is bigger than filesize=%zu\n",
@@ -553,9 +517,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
int nobits = sechdrs[i].sh_type == SHT_NOBITS;
if (!nobits && sechdrs[i].sh_offset > info->size) {
- fatal("%s is truncated. sechdrs[i].sh_offset=%lu > "
- "sizeof(*hrd)=%zu\n", filename,
- (unsigned long)sechdrs[i].sh_offset,
+ fatal("%s is truncated. sechdrs[i].sh_offset=%lu > sizeof(*hrd)=%zu\n",
+ filename, (unsigned long)sechdrs[i].sh_offset,
sizeof(*hdr));
return 0;
}
@@ -565,10 +528,9 @@ static int parse_elf(struct elf_info *info, const char *filename)
fatal("%s has NOBITS .modinfo\n", filename);
info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
info->modinfo_len = sechdrs[i].sh_size;
- } else if (strcmp(secname, "__ksymtab") == 0)
- info->export_sec = i;
- else if (strcmp(secname, "__ksymtab_gpl") == 0)
- info->export_gpl_sec = i;
+ } else if (!strcmp(secname, ".export_symbol")) {
+ info->export_symbol_secndx = i;
+ }
if (sechdrs[i].sh_type == SHT_SYMTAB) {
unsigned int sh_link_idx;
@@ -647,45 +609,18 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
strstarts(symname, "_savevr_") ||
strcmp(symname, ".TOC.") == 0)
return 1;
+
+ if (info->hdr->e_machine == EM_S390)
+ /* Expoline thunks are linked on all kernel modules during final link of .ko */
+ if (strstarts(symname, "__s390_indirect_jump_r"))
+ return 1;
/* Do not ignore this symbol */
return 0;
}
-static void handle_modversion(const struct module *mod,
- const struct elf_info *info,
- const Elf_Sym *sym, const char *symname)
-{
- unsigned int crc;
-
- if (sym->st_shndx == SHN_UNDEF) {
- warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n",
- symname, mod->name, mod->is_vmlinux ? "" : ".ko");
- return;
- }
-
- if (sym->st_shndx == SHN_ABS) {
- crc = sym->st_value;
- } else {
- unsigned int *crcp;
-
- /* symbol points to the CRC in the ELF object */
- crcp = sym_get_data(info, sym);
- crc = TO_NATIVE(*crcp);
- }
- sym_set_crc(symname, crc);
-}
-
static void handle_symbol(struct module *mod, struct elf_info *info,
const Elf_Sym *sym, const char *symname)
{
- enum export export;
- const char *name;
-
- if (strstarts(symname, "__ksymtab"))
- export = export_from_secname(info, get_secindex(info, sym));
- else
- export = export_from_sec(info, get_secindex(info, sym));
-
switch (sym->st_shndx) {
case SHN_COMMON:
if (strstarts(symname, "__gnu_lto_")) {
@@ -713,20 +648,14 @@ static void handle_symbol(struct module *mod, struct elf_info *info,
}
}
- mod->unres = alloc_symbol(symname,
- ELF_ST_BIND(sym->st_info) == STB_WEAK,
- mod->unres);
+ sym_add_unresolved(symname, mod,
+ ELF_ST_BIND(sym->st_info) == STB_WEAK);
break;
default:
- /* All exported symbols */
- if (strstarts(symname, "__ksymtab_")) {
- name = symname + strlen("__ksymtab_");
- sym_add_exported(name, mod, export);
- }
if (strcmp(symname, "init_module") == 0)
- mod->has_init = 1;
+ mod->has_init = true;
if (strcmp(symname, "cleanup_module") == 0)
- mod->has_cleanup = 1;
+ mod->has_cleanup = true;
break;
}
}
@@ -778,29 +707,6 @@ static char *get_modinfo(struct elf_info *info, const char *tag)
return get_next_modinfo(info, tag, NULL);
}
-/**
- * Test if string s ends in string sub
- * return 0 if match
- **/
-static int strrcmp(const char *s, const char *sub)
-{
- int slen, sublen;
-
- if (!s || !sub)
- return 1;
-
- slen = strlen(s);
- sublen = strlen(sub);
-
- if ((slen == 0) || (sublen == 0))
- return 1;
-
- if (sublen > slen)
- return 1;
-
- return memcmp(s + slen - sublen, sub, sublen);
-}
-
static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
{
if (sym)
@@ -809,54 +715,36 @@ static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
return "(unknown)";
}
-/* The pattern is an array of simple patterns.
- * "foo" will match an exact string equal to "foo"
- * "*foo" will match a string that ends with "foo"
- * "foo*" will match a string that begins with "foo"
- * "*foo*" will match a string that contains "foo"
+/*
+ * Check whether the 'string' argument matches one of the 'patterns',
+ * an array of shell wildcard patterns (glob).
+ *
+ * Return true is there is a match.
*/
-static int match(const char *sym, const char * const pat[])
+static bool match(const char *string, const char *const patterns[])
{
- const char *p;
- while (*pat) {
- p = *pat++;
- const char *endp = p + strlen(p) - 1;
-
- /* "*foo*" */
- if (*p == '*' && *endp == '*') {
- char *bare = NOFAIL(strndup(p + 1, strlen(p) - 2));
- char *here = strstr(sym, bare);
+ const char *pattern;
- free(bare);
- if (here != NULL)
- return 1;
- }
- /* "*foo" */
- else if (*p == '*') {
- if (strrcmp(sym, p + 1) == 0)
- return 1;
- }
- /* "foo*" */
- else if (*endp == '*') {
- if (strncmp(sym, p, strlen(p) - 1) == 0)
- return 1;
- }
- /* no wildcards */
- else {
- if (strcmp(p, sym) == 0)
- return 1;
- }
+ while ((pattern = *patterns++)) {
+ if (!fnmatch(pattern, string, 0))
+ return true;
}
- /* no match */
- return 0;
+
+ return false;
}
+/* useful to pass patterns to match() directly */
+#define PATTERNS(...) \
+ ({ \
+ static const char *const patterns[] = {__VA_ARGS__, NULL}; \
+ patterns; \
+ })
+
/* sections that we do not want to do full section mismatch check on */
static const char *const section_white_list[] =
{
".comment*",
".debug*",
- ".cranges", /* sh64 */
".zdebug*", /* Compressed debug sections. */
".GCC.command.line", /* record-gcc-switches */
".mdebug*", /* alpha, score, mips etc. */
@@ -922,11 +810,11 @@ static void check_section(const char *modname, struct elf_info *elf,
#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
#define DATA_SECTIONS ".data", ".data.rel"
-#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
+#define TEXT_SECTIONS ".text", ".text.*", ".sched.text", \
".kprobes.text", ".cpuidle.text", ".noinstr.text"
#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
- ".fixup", ".entry.text", ".exception.text", ".text.*", \
- ".coldtext"
+ ".fixup", ".entry.text", ".exception.text", \
+ ".coldtext", ".softirqentry.text"
#define INIT_SECTIONS ".init.*"
#define MEM_INIT_SECTIONS ".meminit.*"
@@ -937,55 +825,19 @@ static void check_section(const char *modname, struct elf_info *elf,
#define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
TEXT_SECTIONS, OTHER_TEXT_SECTIONS
-/* init data sections */
-static const char *const init_data_sections[] =
- { ALL_INIT_DATA_SECTIONS, NULL };
-
-/* all init sections */
-static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
-
-/* All init and exit sections (code + data) */
-static const char *const init_exit_sections[] =
- {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
-
-/* all text sections */
-static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
-
-/* data section */
-static const char *const data_sections[] = { DATA_SECTIONS, NULL };
-
-
-/* symbols in .data that may refer to init/exit sections */
-#define DEFAULT_SYMBOL_WHITE_LIST \
- "*driver", \
- "*_template", /* scsi uses *_template a lot */ \
- "*_timer", /* arm uses ops structures named _timer a lot */ \
- "*_sht", /* scsi also used *_sht to some extent */ \
- "*_ops", \
- "*_probe", \
- "*_probe_one", \
- "*_console"
-
-static const char *const head_sections[] = { ".head.text*", NULL };
-static const char *const linker_symbols[] =
- { "__init_begin", "_sinittext", "_einittext", NULL };
-static const char *const optim_symbols[] = { "*.constprop.*", NULL };
-
enum mismatch {
TEXT_TO_ANY_INIT,
DATA_TO_ANY_INIT,
- TEXT_TO_ANY_EXIT,
- DATA_TO_ANY_EXIT,
+ TEXTDATA_TO_ANY_EXIT,
XXXINIT_TO_SOME_INIT,
XXXEXIT_TO_SOME_EXIT,
ANY_INIT_TO_ANY_EXIT,
ANY_EXIT_TO_ANY_INIT,
- EXPORT_TO_INIT_EXIT,
EXTABLE_TO_NON_TEXT,
};
/**
- * Describe how to match sections on different criterias:
+ * Describe how to match sections on different criteria:
*
* @fromsec: Array of sections to be matched.
*
@@ -993,34 +845,17 @@ enum mismatch {
* this array is forbidden (black-list). Can be empty.
*
* @good_tosec: Relocations applied to a section in @fromsec must be
- * targetting sections in this array (white-list). Can be empty.
+ * targeting sections in this array (white-list). Can be empty.
*
* @mismatch: Type of mismatch.
- *
- * @symbol_white_list: Do not match a relocation to a symbol in this list
- * even if it is targetting a section in @bad_to_sec.
- *
- * @handler: Specific handler to call when a match is found. If NULL,
- * default_mismatch_handler() will be called.
- *
*/
struct sectioncheck {
const char *fromsec[20];
const char *bad_tosec[20];
const char *good_tosec[20];
enum mismatch mismatch;
- const char *symbol_white_list[20];
- void (*handler)(const char *modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec);
-
};
-static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela *r, Elf_Sym *sym,
- const char *fromsec);
-
static const struct sectioncheck sectioncheck[] = {
/* Do not reference init/exit code/data from
* normal code and data
@@ -1029,75 +864,45 @@ static const struct sectioncheck sectioncheck[] = {
.fromsec = { TEXT_SECTIONS, NULL },
.bad_tosec = { ALL_INIT_SECTIONS, NULL },
.mismatch = TEXT_TO_ANY_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { DATA_SECTIONS, NULL },
- .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL },
+ .bad_tosec = { ALL_XXXINIT_SECTIONS, INIT_SECTIONS, NULL },
.mismatch = DATA_TO_ANY_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
- .fromsec = { DATA_SECTIONS, NULL },
- .bad_tosec = { INIT_SECTIONS, NULL },
- .mismatch = DATA_TO_ANY_INIT,
- .symbol_white_list = {
- "*_template", "*_timer", "*_sht", "*_ops",
- "*_probe", "*_probe_one", "*_console", NULL
- },
-},
-{
- .fromsec = { TEXT_SECTIONS, NULL },
+ .fromsec = { TEXT_SECTIONS, DATA_SECTIONS, NULL },
.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = TEXT_TO_ANY_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
-},
-{
- .fromsec = { DATA_SECTIONS, NULL },
- .bad_tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = DATA_TO_ANY_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+ .mismatch = TEXTDATA_TO_ANY_EXIT,
},
/* Do not reference init code/data from meminit code/data */
{
.fromsec = { ALL_XXXINIT_SECTIONS, NULL },
.bad_tosec = { INIT_SECTIONS, NULL },
.mismatch = XXXINIT_TO_SOME_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not reference exit code/data from memexit code/data */
{
.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
.bad_tosec = { EXIT_SECTIONS, NULL },
.mismatch = XXXEXIT_TO_SOME_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not use exit code/data from init code */
{
.fromsec = { ALL_INIT_SECTIONS, NULL },
.bad_tosec = { ALL_EXIT_SECTIONS, NULL },
.mismatch = ANY_INIT_TO_ANY_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not use init code/data from exit code */
{
.fromsec = { ALL_EXIT_SECTIONS, NULL },
.bad_tosec = { ALL_INIT_SECTIONS, NULL },
.mismatch = ANY_EXIT_TO_ANY_INIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { ALL_PCI_INIT_SECTIONS, NULL },
.bad_tosec = { INIT_SECTIONS, NULL },
.mismatch = ANY_INIT_TO_ANY_EXIT,
- .symbol_white_list = { NULL },
-},
-/* Do not export init/exit functions or data */
-{
- .fromsec = { "__ksymtab*", NULL },
- .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
- .mismatch = EXPORT_TO_INIT_EXIT,
- .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { "__ex_table", NULL },
@@ -1107,7 +912,6 @@ static const struct sectioncheck sectioncheck[] = {
.bad_tosec = { ".altinstr_replacement", NULL },
.good_tosec = {ALL_TEXT_SECTIONS , NULL},
.mismatch = EXTABLE_TO_NON_TEXT,
- .handler = extable_mismatch_handler,
}
};
@@ -1115,8 +919,6 @@ static const struct sectioncheck *section_mismatch(
const char *fromsec, const char *tosec)
{
int i;
- int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
- const struct sectioncheck *check = &sectioncheck[0];
/*
* The target section could be the SHT_NUL section when we're
@@ -1127,14 +929,15 @@ static const struct sectioncheck *section_mismatch(
if (*tosec == '\0')
return NULL;
- for (i = 0; i < elems; i++) {
+ for (i = 0; i < ARRAY_SIZE(sectioncheck); i++) {
+ const struct sectioncheck *check = &sectioncheck[i];
+
if (match(fromsec, check->fromsec)) {
if (check->bad_tosec[0] && match(tosec, check->bad_tosec))
return check;
if (check->good_tosec[0] && !match(tosec, check->good_tosec))
return check;
}
- check++;
}
return NULL;
}
@@ -1159,15 +962,6 @@ static const struct sectioncheck *section_mismatch(
* fromsec = .data*
* atsym = __param_ops_*
*
- * Pattern 2:
- * Many drivers utilise a *driver container with references to
- * add, remove, probe functions etc.
- * the pattern is identified by:
- * tosec = init or exit section
- * fromsec = data section
- * atsym = *driver, *_template, *_sht, *_ops, *_probe,
- * *probe_one, *_console, *_timer
- *
* Pattern 3:
* Whitelist all references from .head.text to any init section
*
@@ -1191,68 +985,61 @@ static const struct sectioncheck *section_mismatch(
* fromsec = text section
* refsymname = *.constprop.*
*
- * Pattern 6:
- * Hide section mismatch warnings for ELF local symbols. The goal
- * is to eliminate false positive modpost warnings caused by
- * compiler-generated ELF local symbol names such as ".LANCHOR1".
- * Autogenerated symbol names bypass modpost's "Pattern 2"
- * whitelisting, which relies on pattern-matching against symbol
- * names to work. (One situation where gcc can autogenerate ELF
- * local symbols is when "-fsection-anchors" is used.)
**/
-static int secref_whitelist(const struct sectioncheck *mismatch,
- const char *fromsec, const char *fromsym,
+static int secref_whitelist(const char *fromsec, const char *fromsym,
const char *tosec, const char *tosym)
{
/* Check for pattern 1 */
- if (match(tosec, init_data_sections) &&
- match(fromsec, data_sections) &&
+ if (match(tosec, PATTERNS(ALL_INIT_DATA_SECTIONS)) &&
+ match(fromsec, PATTERNS(DATA_SECTIONS)) &&
strstarts(fromsym, "__param"))
return 0;
/* Check for pattern 1a */
if (strcmp(tosec, ".init.text") == 0 &&
- match(fromsec, data_sections) &&
+ match(fromsec, PATTERNS(DATA_SECTIONS)) &&
strstarts(fromsym, "__param_ops_"))
return 0;
- /* Check for pattern 2 */
- if (match(tosec, init_exit_sections) &&
- match(fromsec, data_sections) &&
- match(fromsym, mismatch->symbol_white_list))
+ /* symbols in data sections that may refer to any init/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*_template", // scsi uses *_template a lot
+ "*_timer", // arm uses ops structures named _timer a lot
+ "*_sht", // scsi also used *_sht to some extent
+ "*_ops",
+ "*_probe",
+ "*_probe_one",
+ "*_console")))
+ return 0;
+
+ /* symbols in data sections that may refer to meminit/exit sections */
+ if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_XXXINIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*driver")))
return 0;
/* Check for pattern 3 */
- if (match(fromsec, head_sections) &&
- match(tosec, init_sections))
+ if (strstarts(fromsec, ".head.text") &&
+ match(tosec, PATTERNS(ALL_INIT_SECTIONS)))
return 0;
/* Check for pattern 4 */
- if (match(tosym, linker_symbols))
+ if (match(tosym, PATTERNS("__init_begin", "_sinittext", "_einittext")))
return 0;
/* Check for pattern 5 */
- if (match(fromsec, text_sections) &&
- match(tosec, init_sections) &&
- match(fromsym, optim_symbols))
- return 0;
-
- /* Check for pattern 6 */
- if (strstarts(fromsym, ".L"))
+ if (match(fromsec, PATTERNS(ALL_TEXT_SECTIONS)) &&
+ match(tosec, PATTERNS(ALL_INIT_SECTIONS)) &&
+ match(fromsym, PATTERNS("*.constprop.*")))
return 0;
return 1;
}
-static inline int is_arm_mapping_symbol(const char *str)
-{
- return str[0] == '$' && strchr("axtd", str[1])
- && (str[2] == '\0' || str[2] == '.');
-}
-
/*
* If there's no name there, ignore it; likewise, ignore it if it's
- * one of the magic symbols emitted used by current ARM tools.
+ * one of the magic symbols emitted used by current tools.
*
* Otherwise if find_symbols_between() returns those symbols, they'll
* fail the whitelist tests and cause lots of false alarms ... fixable
@@ -1265,475 +1052,222 @@ static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
if (!name || !strlen(name))
return 0;
- return !is_arm_mapping_symbol(name);
+ return !is_mapping_symbol(name);
}
-/**
- * Find symbol based on relocation record info.
- * In some cases the symbol supplied is a valid symbol so
- * return refsym. If st_name != 0 we assume this is a valid symbol.
- * In other cases the symbol needs to be looked up in the symbol table
- * based on section and address.
- * **/
-static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr,
- Elf_Sym *relsym)
+/* Look up the nearest symbol based on the section and the address */
+static Elf_Sym *find_nearest_sym(struct elf_info *elf, Elf_Addr addr,
+ unsigned int secndx, bool allow_negative,
+ Elf_Addr min_distance)
{
Elf_Sym *sym;
Elf_Sym *near = NULL;
- Elf64_Sword distance = 20;
- Elf64_Sword d;
- unsigned int relsym_secindex;
-
- if (relsym->st_name != 0)
- return relsym;
+ Elf_Addr sym_addr, distance;
+ bool is_arm = (elf->hdr->e_machine == EM_ARM);
- relsym_secindex = get_secindex(elf, relsym);
for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
- if (get_secindex(elf, sym) != relsym_secindex)
- continue;
- if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
+ if (get_secindex(elf, sym) != secndx)
continue;
if (!is_valid_name(elf, sym))
continue;
- if (sym->st_value == addr)
- return sym;
- /* Find a symbol nearby - addr are maybe negative */
- d = sym->st_value - addr;
- if (d < 0)
- d = addr - sym->st_value;
- if (d < distance) {
- distance = d;
- near = sym;
- }
- }
- /* We need a close match */
- if (distance < 20)
- return near;
- else
- return NULL;
-}
-/*
- * Find symbols before or equal addr and after addr - in the section sec.
- * If we find two symbols with equal offset prefer one with a valid name.
- * The ELF format may have a better way to detect what type of symbol
- * it is, but this works for now.
- **/
-static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,
- const char *sec)
-{
- Elf_Sym *sym;
- Elf_Sym *near = NULL;
- Elf_Addr distance = ~0;
+ sym_addr = sym->st_value;
- for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
- const char *symsec;
+ /*
+ * For ARM Thumb instruction, the bit 0 of st_value is set
+ * if the symbol is STT_FUNC type. Mask it to get the address.
+ */
+ if (is_arm && ELF_ST_TYPE(sym->st_info) == STT_FUNC)
+ sym_addr &= ~1;
- if (is_shndx_special(sym->st_shndx))
- continue;
- symsec = sec_name(elf, get_secindex(elf, sym));
- if (strcmp(symsec, sec) != 0)
- continue;
- if (!is_valid_name(elf, sym))
+ if (addr >= sym_addr)
+ distance = addr - sym_addr;
+ else if (allow_negative)
+ distance = sym_addr - addr;
+ else
continue;
- if (sym->st_value <= addr) {
- if ((addr - sym->st_value) < distance) {
- distance = addr - sym->st_value;
- near = sym;
- } else if ((addr - sym->st_value) == distance) {
- near = sym;
- }
+
+ if (distance <= min_distance) {
+ min_distance = distance;
+ near = sym;
}
- }
- return near;
-}
-/*
- * Convert a section name to the function/data attribute
- * .init.text => __init
- * .memexitconst => __memconst
- * etc.
- *
- * The memory of returned value has been allocated on a heap. The user of this
- * method should free it after usage.
-*/
-static char *sec2annotation(const char *s)
-{
- if (match(s, init_exit_sections)) {
- char *p = NOFAIL(malloc(20));
- char *r = p;
-
- *p++ = '_';
- *p++ = '_';
- if (*s == '.')
- s++;
- while (*s && *s != '.')
- *p++ = *s++;
- *p = '\0';
- if (*s == '.')
- s++;
- if (strstr(s, "rodata") != NULL)
- strcat(p, "const ");
- else if (strstr(s, "data") != NULL)
- strcat(p, "data ");
- else
- strcat(p, " ");
- return r;
- } else {
- return NOFAIL(strdup(""));
+ if (min_distance == 0)
+ break;
}
+ return near;
}
-static int is_function(Elf_Sym *sym)
+static Elf_Sym *find_fromsym(struct elf_info *elf, Elf_Addr addr,
+ unsigned int secndx)
{
- if (sym)
- return ELF_ST_TYPE(sym->st_info) == STT_FUNC;
- else
- return -1;
+ return find_nearest_sym(elf, addr, secndx, false, ~0);
}
-static void print_section_list(const char * const list[20])
+static Elf_Sym *find_tosym(struct elf_info *elf, Elf_Addr addr, Elf_Sym *sym)
{
- const char *const *s = list;
+ /* If the supplied symbol has a valid name, return it */
+ if (is_valid_name(elf, sym))
+ return sym;
- while (*s) {
- fprintf(stderr, "%s", *s);
- s++;
- if (*s)
- fprintf(stderr, ", ");
- }
- fprintf(stderr, "\n");
+ /*
+ * Strive to find a better symbol name, but the resulting name may not
+ * match the symbol referenced in the original code.
+ */
+ return find_nearest_sym(elf, addr, get_secindex(elf, sym), true, 20);
}
-static inline void get_pretty_name(int is_func, const char** name, const char** name_p)
+static bool is_executable_section(struct elf_info *elf, unsigned int secndx)
{
- switch (is_func) {
- case 0: *name = "variable"; *name_p = ""; break;
- case 1: *name = "function"; *name_p = "()"; break;
- default: *name = "(unknown reference)"; *name_p = ""; break;
- }
-}
-
-/*
- * Print a warning about a section mismatch.
- * Try to find symbols near it so user can find it.
- * Check whitelist before warning - it may be a false positive.
- */
-static void report_sec_mismatch(const char *modname,
- const struct sectioncheck *mismatch,
- const char *fromsec,
- unsigned long long fromaddr,
- const char *fromsym,
- int from_is_func,
- const char *tosec, const char *tosym,
- int to_is_func)
-{
- const char *from, *from_p;
- const char *to, *to_p;
- char *prl_from;
- char *prl_to;
-
- sec_mismatch_count++;
+ if (secndx >= elf->num_sections)
+ return false;
- get_pretty_name(from_is_func, &from, &from_p);
- get_pretty_name(to_is_func, &to, &to_p);
-
- warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s "
- "to the %s %s:%s%s\n",
- modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
- tosym, to_p);
-
- switch (mismatch->mismatch) {
- case TEXT_TO_ANY_INIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The function %s%s() references\n"
- "the %s %s%s%s.\n"
- "This is often because %s lacks a %s\n"
- "annotation or the annotation of %s is wrong.\n",
- prl_from, fromsym,
- to, prl_to, tosym, to_p,
- fromsym, prl_to, tosym);
- free(prl_from);
- free(prl_to);
- break;
- case DATA_TO_ANY_INIT: {
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The variable %s references\n"
- "the %s %s%s%s\n"
- "If the reference is valid then annotate the\n"
- "variable with __init* or __refdata (see linux/init.h) "
- "or name the variable:\n",
- fromsym, to, prl_to, tosym, to_p);
- print_section_list(mismatch->symbol_white_list);
- free(prl_to);
- break;
- }
- case TEXT_TO_ANY_EXIT:
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The function %s() references a %s in an exit section.\n"
- "Often the %s %s%s has valid usage outside the exit section\n"
- "and the fix is to remove the %sannotation of %s.\n",
- fromsym, to, to, tosym, to_p, prl_to, tosym);
- free(prl_to);
- break;
- case DATA_TO_ANY_EXIT: {
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The variable %s references\n"
- "the %s %s%s%s\n"
- "If the reference is valid then annotate the\n"
- "variable with __exit* (see linux/init.h) or "
- "name the variable:\n",
- fromsym, to, prl_to, tosym, to_p);
- print_section_list(mismatch->symbol_white_list);
- free(prl_to);
- break;
- }
- case XXXINIT_TO_SOME_INIT:
- case XXXEXIT_TO_SOME_EXIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The %s %s%s%s references\n"
- "a %s %s%s%s.\n"
- "If %s is only used by %s then\n"
- "annotate %s with a matching annotation.\n",
- from, prl_from, fromsym, from_p,
- to, prl_to, tosym, to_p,
- tosym, fromsym, tosym);
- free(prl_from);
- free(prl_to);
- break;
- case ANY_INIT_TO_ANY_EXIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The %s %s%s%s references\n"
- "a %s %s%s%s.\n"
- "This is often seen when error handling "
- "in the init function\n"
- "uses functionality in the exit path.\n"
- "The fix is often to remove the %sannotation of\n"
- "%s%s so it may be used outside an exit section.\n",
- from, prl_from, fromsym, from_p,
- to, prl_to, tosym, to_p,
- prl_to, tosym, to_p);
- free(prl_from);
- free(prl_to);
- break;
- case ANY_EXIT_TO_ANY_INIT:
- prl_from = sec2annotation(fromsec);
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The %s %s%s%s references\n"
- "a %s %s%s%s.\n"
- "This is often seen when error handling "
- "in the exit function\n"
- "uses functionality in the init path.\n"
- "The fix is often to remove the %sannotation of\n"
- "%s%s so it may be used outside an init section.\n",
- from, prl_from, fromsym, from_p,
- to, prl_to, tosym, to_p,
- prl_to, tosym, to_p);
- free(prl_from);
- free(prl_to);
- break;
- case EXPORT_TO_INIT_EXIT:
- prl_to = sec2annotation(tosec);
- fprintf(stderr,
- "The symbol %s is exported and annotated %s\n"
- "Fix this by removing the %sannotation of %s "
- "or drop the export.\n",
- tosym, prl_to, prl_to, tosym);
- free(prl_to);
- break;
- case EXTABLE_TO_NON_TEXT:
- fatal("There's a special handler for this mismatch type, "
- "we should never get here.");
- break;
- }
- fprintf(stderr, "\n");
+ return (elf->sechdrs[secndx].sh_flags & SHF_EXECINSTR) != 0;
}
static void default_mismatch_handler(const char *modname, struct elf_info *elf,
const struct sectioncheck* const mismatch,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+ Elf_Sym *tsym,
+ unsigned int fsecndx, const char *fromsec, Elf_Addr faddr,
+ const char *tosec, Elf_Addr taddr)
{
- const char *tosec;
- Elf_Sym *to;
Elf_Sym *from;
const char *tosym;
const char *fromsym;
- from = find_elf_symbol2(elf, r->r_offset, fromsec);
+ from = find_fromsym(elf, faddr, fsecndx);
fromsym = sym_name(elf, from);
- if (strstarts(fromsym, "reference___initcall"))
+ tsym = find_tosym(elf, taddr, tsym);
+ tosym = sym_name(elf, tsym);
+
+ /* check whitelist - we may ignore it */
+ if (!secref_whitelist(fromsec, fromsym, tosec, tosym))
return;
- tosec = sec_name(elf, get_secindex(elf, sym));
- to = find_elf_symbol(elf, r->r_addend, sym);
- tosym = sym_name(elf, to);
+ sec_mismatch_count++;
+
+ warn("%s: section mismatch in reference: %s+0x%x (section: %s) -> %s (section: %s)\n",
+ modname, fromsym, (unsigned int)(faddr - from->st_value), fromsec, tosym, tosec);
- /* check whitelist - we may ignore it */
- if (secref_whitelist(mismatch,
- fromsec, fromsym, tosec, tosym)) {
- report_sec_mismatch(modname, mismatch,
- fromsec, r->r_offset, fromsym,
- is_function(from), tosec, tosym,
- is_function(to));
+ if (mismatch->mismatch == EXTABLE_TO_NON_TEXT) {
+ if (match(tosec, mismatch->bad_tosec))
+ fatal("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is black-listed.\n"
+ "Something is seriously wrong and should be fixed.\n"
+ "You might get more information about where this is\n"
+ "coming from by using scripts/check_extable.sh %s\n",
+ fromsec, (long)faddr, tosec, modname);
+ else if (is_executable_section(elf, get_secindex(elf, tsym)))
+ warn("The relocation at %s+0x%lx references\n"
+ "section \"%s\" which is not in the list of\n"
+ "authorized sections. If you're adding a new section\n"
+ "and/or if this reference is valid, add \"%s\" to the\n"
+ "list of authorized sections to jump to on fault.\n"
+ "This can be achieved by adding \"%s\" to\n"
+ "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
+ fromsec, (long)faddr, tosec, tosec, tosec);
+ else
+ error("%s+0x%lx references non-executable section '%s'\n",
+ fromsec, (long)faddr, tosec);
}
}
-static int is_executable_section(struct elf_info* elf, unsigned int section_index)
+static void check_export_symbol(struct module *mod, struct elf_info *elf,
+ Elf_Addr faddr, const char *secname,
+ Elf_Sym *sym)
{
- if (section_index > elf->num_sections)
- fatal("section_index is outside elf->num_sections!\n");
+ static const char *prefix = "__export_symbol_";
+ const char *label_name, *name, *data;
+ Elf_Sym *label;
+ struct symbol *s;
+ bool is_gpl;
- return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
-}
+ label = find_fromsym(elf, faddr, elf->export_symbol_secndx);
+ label_name = sym_name(elf, label);
+
+ if (!strstarts(label_name, prefix)) {
+ error("%s: .export_symbol section contains strange symbol '%s'\n",
+ mod->name, label_name);
+ return;
+ }
+
+ if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
+ ELF_ST_BIND(sym->st_info) != STB_WEAK) {
+ error("%s: local symbol '%s' was exported\n", mod->name,
+ label_name + strlen(prefix));
+ return;
+ }
+
+ name = sym_name(elf, sym);
+ if (strcmp(label_name + strlen(prefix), name)) {
+ error("%s: .export_symbol section references '%s', but it does not seem to be an export symbol\n",
+ mod->name, name);
+ return;
+ }
+
+ data = sym_get_data(elf, label); /* license */
+ if (!strcmp(data, "GPL")) {
+ is_gpl = true;
+ } else if (!strcmp(data, "")) {
+ is_gpl = false;
+ } else {
+ error("%s: unknown license '%s' was specified for '%s'\n",
+ mod->name, data, name);
+ return;
+ }
+
+ data += strlen(data) + 1; /* namespace */
+ s = sym_add_exported(name, mod, is_gpl, data);
-/*
- * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
- * to know the sizeof(struct exception_table_entry) for the target architecture.
- */
-static unsigned int extable_entry_size = 0;
-static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
-{
/*
- * If we're currently checking the second relocation within __ex_table,
- * that relocation offset tells us the offsetof(struct
- * exception_table_entry, fixup) which is equal to sizeof(struct
- * exception_table_entry) divided by two. We use that to our advantage
- * since there's no portable way to get that size as every architecture
- * seems to go with different sized types. Not pretty but better than
- * hard-coding the size for every architecture..
+ * We need to be aware whether we are exporting a function or
+ * a data on some architectures.
*/
- if (!extable_entry_size)
- extable_entry_size = r->r_offset * 2;
-}
+ s->is_func = (ELF_ST_TYPE(sym->st_info) == STT_FUNC);
-static inline bool is_extable_fault_address(Elf_Rela *r)
-{
/*
- * extable_entry_size is only discovered after we've handled the
- * _second_ relocation in __ex_table, so only abort when we're not
- * handling the first reloc and extable_entry_size is zero.
+ * For parisc64, symbols prefixed $$ from the library have the symbol type
+ * STT_LOPROC. They should be handled as functions too.
*/
- if (r->r_offset && extable_entry_size == 0)
- fatal("extable_entry size hasn't been discovered!\n");
-
- return ((r->r_offset == 0) ||
- (r->r_offset % extable_entry_size == 0));
-}
-
-#define is_second_extable_reloc(Start, Cur, Sec) \
- (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
-
-static void report_extable_warnings(const char* modname, struct elf_info* elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela* r, Elf_Sym* sym,
- const char* fromsec, const char* tosec)
-{
- Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
- const char* fromsym_name = sym_name(elf, fromsym);
- Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
- const char* tosym_name = sym_name(elf, tosym);
- const char* from_pretty_name;
- const char* from_pretty_name_p;
- const char* to_pretty_name;
- const char* to_pretty_name_p;
-
- get_pretty_name(is_function(fromsym),
- &from_pretty_name, &from_pretty_name_p);
- get_pretty_name(is_function(tosym),
- &to_pretty_name, &to_pretty_name_p);
-
- warn("%s(%s+0x%lx): Section mismatch in reference"
- " from the %s %s%s to the %s %s:%s%s\n",
- modname, fromsec, (long)r->r_offset, from_pretty_name,
- fromsym_name, from_pretty_name_p,
- to_pretty_name, tosec, tosym_name, to_pretty_name_p);
-
- if (!match(tosec, mismatch->bad_tosec) &&
- is_executable_section(elf, get_secindex(elf, sym)))
- fprintf(stderr,
- "The relocation at %s+0x%lx references\n"
- "section \"%s\" which is not in the list of\n"
- "authorized sections. If you're adding a new section\n"
- "and/or if this reference is valid, add \"%s\" to the\n"
- "list of authorized sections to jump to on fault.\n"
- "This can be achieved by adding \"%s\" to \n"
- "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
- fromsec, (long)r->r_offset, tosec, tosec, tosec);
-}
-
-static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
- const struct sectioncheck* const mismatch,
- Elf_Rela* r, Elf_Sym* sym,
- const char *fromsec)
-{
- const char* tosec = sec_name(elf, get_secindex(elf, sym));
+ if (elf->hdr->e_ident[EI_CLASS] == ELFCLASS64 &&
+ elf->hdr->e_machine == EM_PARISC &&
+ ELF_ST_TYPE(sym->st_info) == STT_LOPROC)
+ s->is_func = true;
- sec_mismatch_count++;
-
- report_extable_warnings(modname, elf, mismatch, r, sym, fromsec, tosec);
-
- if (match(tosec, mismatch->bad_tosec))
- fatal("The relocation at %s+0x%lx references\n"
- "section \"%s\" which is black-listed.\n"
- "Something is seriously wrong and should be fixed.\n"
- "You might get more information about where this is\n"
- "coming from by using scripts/check_extable.sh %s\n",
- fromsec, (long)r->r_offset, tosec, modname);
- else if (!is_executable_section(elf, get_secindex(elf, sym))) {
- if (is_extable_fault_address(r))
- fatal("The relocation at %s+0x%lx references\n"
- "section \"%s\" which is not executable, IOW\n"
- "it is not possible for the kernel to fault\n"
- "at that address. Something is seriously wrong\n"
- "and should be fixed.\n",
- fromsec, (long)r->r_offset, tosec);
- else
- fatal("The relocation at %s+0x%lx references\n"
- "section \"%s\" which is not executable, IOW\n"
- "the kernel will fault if it ever tries to\n"
- "jump to it. Something is seriously wrong\n"
- "and should be fixed.\n",
- fromsec, (long)r->r_offset, tosec);
- }
+ if (match(secname, PATTERNS(INIT_SECTIONS)))
+ warn("%s: %s: EXPORT_SYMBOL used for init symbol. Remove __init or EXPORT_SYMBOL.\n",
+ mod->name, name);
+ else if (match(secname, PATTERNS(EXIT_SECTIONS)))
+ warn("%s: %s: EXPORT_SYMBOL used for exit symbol. Remove __exit or EXPORT_SYMBOL.\n",
+ mod->name, name);
}
-static void check_section_mismatch(const char *modname, struct elf_info *elf,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+static void check_section_mismatch(struct module *mod, struct elf_info *elf,
+ Elf_Sym *sym,
+ unsigned int fsecndx, const char *fromsec,
+ Elf_Addr faddr, Elf_Addr taddr)
{
const char *tosec = sec_name(elf, get_secindex(elf, sym));
- const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec);
+ const struct sectioncheck *mismatch;
- if (mismatch) {
- if (mismatch->handler)
- mismatch->handler(modname, elf, mismatch,
- r, sym, fromsec);
- else
- default_mismatch_handler(modname, elf, mismatch,
- r, sym, fromsec);
+ if (elf->export_symbol_secndx == fsecndx) {
+ check_export_symbol(mod, elf, faddr, tosec, sym);
+ return;
}
-}
-static unsigned int *reloc_location(struct elf_info *elf,
- Elf_Shdr *sechdr, Elf_Rela *r)
-{
- return sym_get_data_by_offset(elf, sechdr->sh_info, r->r_offset);
+ mismatch = section_mismatch(fromsec, tosec);
+ if (!mismatch)
+ return;
+
+ default_mismatch_handler(mod->name, elf, mismatch, sym,
+ fsecndx, fromsec, faddr,
+ tosec, taddr);
}
-static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+static int addend_386_rel(uint32_t *location, Elf_Rela *r)
{
unsigned int r_typ = ELF_R_TYPE(r->r_info);
- unsigned int *location = reloc_location(elf, sechdr, r);
switch (r_typ) {
case R_386_32:
@@ -1741,10 +1275,9 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
break;
case R_386_PC32:
r->r_addend = TO_NATIVE(*location) + 4;
- /* For CONFIG_RELOCATABLE=y */
- if (elf->hdr->e_type == ET_EXEC)
- r->r_addend += r->r_offset;
break;
+ default:
+ r->r_addend = (Elf_Addr)(-1);
}
return 0;
}
@@ -1762,45 +1295,131 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
#ifndef R_ARM_THM_JUMP24
#define R_ARM_THM_JUMP24 30
#endif
+
+#ifndef R_ARM_MOVW_ABS_NC
+#define R_ARM_MOVW_ABS_NC 43
+#endif
+
+#ifndef R_ARM_MOVT_ABS
+#define R_ARM_MOVT_ABS 44
+#endif
+
+#ifndef R_ARM_THM_MOVW_ABS_NC
+#define R_ARM_THM_MOVW_ABS_NC 47
+#endif
+
+#ifndef R_ARM_THM_MOVT_ABS
+#define R_ARM_THM_MOVT_ABS 48
+#endif
+
#ifndef R_ARM_THM_JUMP19
#define R_ARM_THM_JUMP19 51
#endif
-static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+static int32_t sign_extend32(int32_t value, int index)
+{
+ uint8_t shift = 31 - index;
+
+ return (int32_t)(value << shift) >> shift;
+}
+
+static int addend_arm_rel(void *loc, Elf_Sym *sym, Elf_Rela *r)
{
unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ uint32_t inst, upper, lower, sign, j1, j2;
+ int32_t offset;
switch (r_typ) {
case R_ARM_ABS32:
- /* From ARM ABI: (S + A) | T */
- r->r_addend = (int)(long)
- (elf->symtab_start + ELF_R_SYM(r->r_info));
+ case R_ARM_REL32:
+ inst = TO_NATIVE(*(uint32_t *)loc);
+ r->r_addend = inst + sym->st_value;
+ break;
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ inst = TO_NATIVE(*(uint32_t *)loc);
+ offset = sign_extend32(((inst & 0xf0000) >> 4) | (inst & 0xfff),
+ 15);
+ r->r_addend = offset + sym->st_value;
break;
case R_ARM_PC24:
case R_ARM_CALL:
case R_ARM_JUMP24:
+ inst = TO_NATIVE(*(uint32_t *)loc);
+ offset = sign_extend32((inst & 0x00ffffff) << 2, 25);
+ r->r_addend = offset + sym->st_value + 8;
+ break;
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ upper = TO_NATIVE(*(uint16_t *)loc);
+ lower = TO_NATIVE(*((uint16_t *)loc + 1));
+ offset = sign_extend32(((upper & 0x000f) << 12) |
+ ((upper & 0x0400) << 1) |
+ ((lower & 0x7000) >> 4) |
+ (lower & 0x00ff),
+ 15);
+ r->r_addend = offset + sym->st_value;
+ break;
+ case R_ARM_THM_JUMP19:
+ /*
+ * Encoding T3:
+ * S = upper[10]
+ * imm6 = upper[5:0]
+ * J1 = lower[13]
+ * J2 = lower[11]
+ * imm11 = lower[10:0]
+ * imm32 = SignExtend(S:J2:J1:imm6:imm11:'0')
+ */
+ upper = TO_NATIVE(*(uint16_t *)loc);
+ lower = TO_NATIVE(*((uint16_t *)loc + 1));
+
+ sign = (upper >> 10) & 1;
+ j1 = (lower >> 13) & 1;
+ j2 = (lower >> 11) & 1;
+ offset = sign_extend32((sign << 20) | (j2 << 19) | (j1 << 18) |
+ ((upper & 0x03f) << 12) |
+ ((lower & 0x07ff) << 1),
+ 20);
+ r->r_addend = offset + sym->st_value + 4;
+ break;
case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
- case R_ARM_THM_JUMP19:
- /* From ARM ABI: ((S + A) | T) - P */
- r->r_addend = (int)(long)(elf->hdr +
- sechdr->sh_offset +
- (r->r_offset - sechdr->sh_addr));
+ /*
+ * Encoding T4:
+ * S = upper[10]
+ * imm10 = upper[9:0]
+ * J1 = lower[13]
+ * J2 = lower[11]
+ * imm11 = lower[10:0]
+ * I1 = NOT(J1 XOR S)
+ * I2 = NOT(J2 XOR S)
+ * imm32 = SignExtend(S:I1:I2:imm10:imm11:'0')
+ */
+ upper = TO_NATIVE(*(uint16_t *)loc);
+ lower = TO_NATIVE(*((uint16_t *)loc + 1));
+
+ sign = (upper >> 10) & 1;
+ j1 = (lower >> 13) & 1;
+ j2 = (lower >> 11) & 1;
+ offset = sign_extend32((sign << 24) |
+ ((~(j1 ^ sign) & 1) << 23) |
+ ((~(j2 ^ sign) & 1) << 22) |
+ ((upper & 0x03ff) << 12) |
+ ((lower & 0x07ff) << 1),
+ 24);
+ r->r_addend = offset + sym->st_value + 4;
break;
default:
- return 1;
+ r->r_addend = (Elf_Addr)(-1);
}
return 0;
}
-static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
+static int addend_mips_rel(uint32_t *location, Elf_Rela *r)
{
unsigned int r_typ = ELF_R_TYPE(r->r_info);
- unsigned int *location = reloc_location(elf, sechdr, r);
- unsigned int inst;
+ uint32_t inst;
- if (r_typ == R_MIPS_HI16)
- return 1; /* skip this */
inst = TO_NATIVE(*location);
switch (r_typ) {
case R_MIPS_LO16:
@@ -1812,24 +1431,39 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
case R_MIPS_32:
r->r_addend = inst;
break;
+ default:
+ r->r_addend = (Elf_Addr)(-1);
}
return 0;
}
-static void section_rela(const char *modname, struct elf_info *elf,
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
+
+#ifndef R_RISCV_SUB32
+#define R_RISCV_SUB32 39
+#endif
+
+#ifndef EM_LOONGARCH
+#define EM_LOONGARCH 258
+#endif
+
+#ifndef R_LARCH_SUB32
+#define R_LARCH_SUB32 55
+#endif
+
+static void section_rela(struct module *mod, struct elf_info *elf,
Elf_Shdr *sechdr)
{
- Elf_Sym *sym;
Elf_Rela *rela;
Elf_Rela r;
unsigned int r_sym;
- const char *fromsec;
-
+ unsigned int fsecndx = sechdr->sh_info;
+ const char *fromsec = sec_name(elf, fsecndx);
Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset;
Elf_Rela *stop = (void *)start + sechdr->sh_size;
- fromsec = sech_name(elf, sechdr);
- fromsec += strlen(".rela");
/* if from section (name) is know good then skip it */
if (match(fromsec, section_white_list))
return;
@@ -1852,35 +1486,43 @@ static void section_rela(const char *modname, struct elf_info *elf,
r_sym = ELF_R_SYM(r.r_info);
#endif
r.r_addend = TO_NATIVE(rela->r_addend);
- sym = elf->symtab_start + r_sym;
- /* Skip special sections */
- if (is_shndx_special(sym->st_shndx))
- continue;
- if (is_second_extable_reloc(start, rela, fromsec))
- find_extable_entry_size(fromsec, &r);
- check_section_mismatch(modname, elf, &r, sym, fromsec);
+ switch (elf->hdr->e_machine) {
+ case EM_RISCV:
+ if (!strcmp("__ex_table", fromsec) &&
+ ELF_R_TYPE(r.r_info) == R_RISCV_SUB32)
+ continue;
+ break;
+ case EM_LOONGARCH:
+ if (!strcmp("__ex_table", fromsec) &&
+ ELF_R_TYPE(r.r_info) == R_LARCH_SUB32)
+ continue;
+ break;
+ }
+
+ check_section_mismatch(mod, elf, elf->symtab_start + r_sym,
+ fsecndx, fromsec, r.r_offset, r.r_addend);
}
}
-static void section_rel(const char *modname, struct elf_info *elf,
+static void section_rel(struct module *mod, struct elf_info *elf,
Elf_Shdr *sechdr)
{
- Elf_Sym *sym;
Elf_Rel *rel;
Elf_Rela r;
unsigned int r_sym;
- const char *fromsec;
-
+ unsigned int fsecndx = sechdr->sh_info;
+ const char *fromsec = sec_name(elf, fsecndx);
Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset;
Elf_Rel *stop = (void *)start + sechdr->sh_size;
- fromsec = sech_name(elf, sechdr);
- fromsec += strlen(".rel");
/* if from section (name) is know good then skip it */
if (match(fromsec, section_white_list))
return;
for (rel = start; rel < stop; rel++) {
+ Elf_Sym *tsym;
+ void *loc;
+
r.r_offset = TO_NATIVE(rel->r_offset);
#if KERNEL_ELFCLASS == ELFCLASS64
if (elf->hdr->e_machine == EM_MIPS) {
@@ -1898,27 +1540,26 @@ static void section_rel(const char *modname, struct elf_info *elf,
r_sym = ELF_R_SYM(r.r_info);
#endif
r.r_addend = 0;
+
+ loc = sym_get_data_by_offset(elf, fsecndx, r.r_offset);
+ tsym = elf->symtab_start + r_sym;
+
switch (elf->hdr->e_machine) {
case EM_386:
- if (addend_386_rel(elf, sechdr, &r))
- continue;
+ addend_386_rel(loc, &r);
break;
case EM_ARM:
- if (addend_arm_rel(elf, sechdr, &r))
- continue;
+ addend_arm_rel(loc, tsym, &r);
break;
case EM_MIPS:
- if (addend_mips_rel(elf, sechdr, &r))
- continue;
+ addend_mips_rel(loc, &r);
break;
+ default:
+ fatal("Please add code to calculate addend for this architecture\n");
}
- sym = elf->symtab_start + r_sym;
- /* Skip special sections */
- if (is_shndx_special(sym->st_shndx))
- continue;
- if (is_second_extable_reloc(start, rel, fromsec))
- find_extable_entry_size(fromsec, &r);
- check_section_mismatch(modname, elf, &r, sym, fromsec);
+
+ check_section_mismatch(mod, elf, tsym,
+ fsecndx, fromsec, r.r_offset, r.r_addend);
}
}
@@ -1934,20 +1575,19 @@ static void section_rel(const char *modname, struct elf_info *elf,
* to find all references to a section that reference a section that will
* be discarded and warns about it.
**/
-static void check_sec_ref(struct module *mod, const char *modname,
- struct elf_info *elf)
+static void check_sec_ref(struct module *mod, struct elf_info *elf)
{
int i;
Elf_Shdr *sechdrs = elf->sechdrs;
/* Walk through all sections */
for (i = 0; i < elf->num_sections; i++) {
- check_section(modname, elf, &elf->sechdrs[i]);
+ check_section(mod->name, elf, &elf->sechdrs[i]);
/* We want to process only relocation sections and not .init */
if (sechdrs[i].sh_type == SHT_RELA)
- section_rela(modname, elf, &elf->sechdrs[i]);
+ section_rela(mod, elf, &elf->sechdrs[i]);
else if (sechdrs[i].sh_type == SHT_REL)
- section_rel(modname, elf, &elf->sechdrs[i]);
+ section_rel(mod, elf, &elf->sechdrs[i]);
}
}
@@ -1957,16 +1597,110 @@ static char *remove_dot(char *s)
if (n && s[n]) {
size_t m = strspn(s + n + 1, "0123456789");
- if (m && (s[n + m] == '.' || s[n + m] == 0))
+ if (m && (s[n + m + 1] == '.' || s[n + m + 1] == 0))
s[n] = 0;
-
- /* strip trailing .lto */
- if (strends(s, ".lto"))
- s[strlen(s) - 4] = '\0';
}
return s;
}
+/*
+ * The CRCs are recorded in .*.cmd files in the form of:
+ * #SYMVER <name> <crc>
+ */
+static void extract_crcs_for_object(const char *object, struct module *mod)
+{
+ char cmd_file[PATH_MAX];
+ char *buf, *p;
+ const char *base;
+ int dirlen, ret;
+
+ base = strrchr(object, '/');
+ if (base) {
+ base++;
+ dirlen = base - object;
+ } else {
+ dirlen = 0;
+ base = object;
+ }
+
+ ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd",
+ dirlen, object, base);
+ if (ret >= sizeof(cmd_file)) {
+ error("%s: too long path was truncated\n", cmd_file);
+ return;
+ }
+
+ buf = read_text_file(cmd_file);
+ p = buf;
+
+ while ((p = strstr(p, "\n#SYMVER "))) {
+ char *name;
+ size_t namelen;
+ unsigned int crc;
+ struct symbol *sym;
+
+ name = p + strlen("\n#SYMVER ");
+
+ p = strchr(name, ' ');
+ if (!p)
+ break;
+
+ namelen = p - name;
+ p++;
+
+ if (!isdigit(*p))
+ continue; /* skip this line */
+
+ crc = strtoul(p, &p, 0);
+ if (*p != '\n')
+ continue; /* skip this line */
+
+ name[namelen] = '\0';
+
+ /*
+ * sym_find_with_module() may return NULL here.
+ * It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y.
+ * Since commit e1327a127703, genksyms calculates CRCs of all
+ * symbols, including trimmed ones. Ignore orphan CRCs.
+ */
+ sym = sym_find_with_module(name, mod);
+ if (sym)
+ sym_set_crc(sym, crc);
+ }
+
+ free(buf);
+}
+
+/*
+ * The symbol versions (CRC) are recorded in the .*.cmd files.
+ * Parse them to retrieve CRCs for the current module.
+ */
+static void mod_set_crcs(struct module *mod)
+{
+ char objlist[PATH_MAX];
+ char *buf, *p, *obj;
+ int ret;
+
+ if (mod->is_vmlinux) {
+ strcpy(objlist, ".vmlinux.objs");
+ } else {
+ /* objects for a module are listed in the *.mod file. */
+ ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name);
+ if (ret >= sizeof(objlist)) {
+ error("%s: too long path was truncated\n", objlist);
+ return;
+ }
+ }
+
+ buf = read_text_file(objlist);
+ p = buf;
+
+ while ((obj = strsep(&p, "\n")) && obj[0])
+ extract_crcs_for_object(obj, mod);
+
+ free(buf);
+}
+
static void read_symbols(const char *modname)
{
const char *symname;
@@ -1980,28 +1714,21 @@ static void read_symbols(const char *modname)
if (!parse_elf(&info, modname))
return;
- {
- char *tmp;
-
- /* strip trailing .o */
- tmp = NOFAIL(strdup(modname));
- tmp[strlen(tmp) - 2] = '\0';
- /* strip trailing .lto */
- if (strends(tmp, ".lto"))
- tmp[strlen(tmp) - 4] = '\0';
- mod = new_module(tmp);
- free(tmp);
+ if (!strends(modname, ".o")) {
+ error("%s: filename must be suffixed with .o\n", modname);
+ return;
}
+ /* strip trailing .o */
+ mod = new_module(modname, strlen(modname) - strlen(".o"));
+
if (!mod->is_vmlinux) {
license = get_modinfo(&info, "license");
if (!license)
error("missing MODULE_LICENSE() in %s\n", modname);
while (license) {
- if (license_is_gpl_compatible(license))
- mod->gpl_compatible = 1;
- else {
- mod->gpl_compatible = 0;
+ if (!license_is_gpl_compatible(license)) {
+ mod->is_gpl_compatible = false;
break;
}
license = get_next_modinfo(&info, "license", license);
@@ -2015,6 +1742,8 @@ static void read_symbols(const char *modname)
}
}
+ if (extra_warn && !get_modinfo(&info, "description"))
+ warn("missing MODULE_DESCRIPTION() in %s\n", modname);
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
symname = remove_dot(info.strtab + sym->st_name);
@@ -2022,51 +1751,28 @@ static void read_symbols(const char *modname)
handle_moddevtable(mod, &info, sym, symname);
}
- for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
- symname = remove_dot(info.strtab + sym->st_name);
-
- /* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
- if (strstarts(symname, "__kstrtabns_"))
- sym_update_namespace(symname + strlen("__kstrtabns_"),
- namespace_from_kstrtabns(&info,
- sym));
-
- if (strstarts(symname, "__crc_"))
- handle_modversion(mod, &info, sym,
- symname + strlen("__crc_"));
- }
-
- // check for static EXPORT_SYMBOL_* functions && global vars
- for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
- unsigned char bind = ELF_ST_BIND(sym->st_info);
-
- if (bind == STB_GLOBAL || bind == STB_WEAK) {
- struct symbol *s =
- find_symbol(remove_dot(info.strtab +
- sym->st_name));
-
- if (s)
- s->is_static = 0;
- }
- }
-
- check_sec_ref(mod, modname, &info);
+ check_sec_ref(mod, &info);
if (!mod->is_vmlinux) {
version = get_modinfo(&info, "version");
if (version || all_versions)
- get_src_version(modname, mod->srcversion,
+ get_src_version(mod->name, mod->srcversion,
sizeof(mod->srcversion) - 1);
}
parse_elf_finish(&info);
- /* Our trick to get versioning for module struct etc. - it's
- * never passed as an argument to an exported function, so
- * the automatic versioning doesn't pick it up, but it's really
- * important anyhow */
- if (modversions)
- mod->unres = alloc_symbol("module_layout", 0, mod->unres);
+ if (modversions) {
+ /*
+ * Our trick to get versioning for module struct etc. - it's
+ * never passed as an argument to an exported function, so
+ * the automatic versioning doesn't pick it up, but it's really
+ * important anyhow.
+ */
+ sym_add_unresolved("module_layout", mod, false);
+
+ mod_set_crcs(mod);
+ }
}
static void read_symbols_from_files(const char *filename)
@@ -2074,11 +1780,9 @@ static void read_symbols_from_files(const char *filename)
FILE *in = stdin;
char fname[PATH_MAX];
- if (strcmp(filename, "-") != 0) {
- in = fopen(filename, "r");
- if (!in)
- fatal("Can't open filenames file %s: %m", filename);
- }
+ in = fopen(filename, "r");
+ if (!in)
+ fatal("Can't open filenames file %s: %m", filename);
while (fgets(fname, PATH_MAX, in) != NULL) {
if (strends(fname, "\n"))
@@ -2086,8 +1790,7 @@ static void read_symbols_from_files(const char *filename)
read_symbols(fname);
}
- if (in != stdin)
- fclose(in);
+ fclose(in);
}
#define SZ 500
@@ -2119,53 +1822,67 @@ void buf_write(struct buffer *buf, const char *s, int len)
buf->pos += len;
}
-static void check_for_gpl_usage(enum export exp, const char *m, const char *s)
-{
- switch (exp) {
- case export_gpl:
- error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
- m, s);
- break;
- case export_plain:
- case export_unknown:
- /* ignore */
- break;
- }
-}
-
static void check_exports(struct module *mod)
{
struct symbol *s, *exp;
- for (s = mod->unres; s; s = s->next) {
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
const char *basename;
exp = find_symbol(s->name);
- if (!exp || exp->module == mod) {
- if (have_vmlinux && !s->weak)
+ if (!exp) {
+ if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS)
modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR,
"\"%s\" [%s.ko] undefined!\n",
s->name, mod->name);
continue;
}
+ if (exp->module == mod) {
+ error("\"%s\" [%s.ko] was exported without definition\n",
+ s->name, mod->name);
+ continue;
+ }
+
+ exp->used = true;
+ s->module = exp->module;
+ s->crc_valid = exp->crc_valid;
+ s->crc = exp->crc;
+
basename = strrchr(mod->name, '/');
if (basename)
basename++;
else
basename = mod->name;
- if (exp->namespace &&
- !module_imports_namespace(mod, exp->namespace)) {
+ if (!contains_namespace(&mod->imported_namespaces, exp->namespace)) {
modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR,
"module %s uses symbol %s from namespace %s, but does not import it.\n",
basename, exp->name, exp->namespace);
add_namespace(&mod->missing_namespaces, exp->namespace);
}
- if (!mod->gpl_compatible)
- check_for_gpl_usage(exp->export, basename, exp->name);
+ if (!mod->is_gpl_compatible && exp->is_gpl_only)
+ error("GPL-incompatible module %s.ko uses GPL-only symbol '%s'\n",
+ basename, exp->name);
}
}
+static void handle_white_list_exports(const char *white_list)
+{
+ char *buf, *p, *name;
+
+ buf = read_text_file(white_list);
+ p = buf;
+
+ while ((name = strsep(&p, "\n"))) {
+ struct symbol *sym = find_symbol(name);
+
+ if (sym)
+ sym->used = true;
+ }
+
+ free(buf);
+}
+
static void check_modname_len(struct module *mod)
{
const char *mod_name;
@@ -2191,10 +1908,18 @@ static void add_header(struct buffer *b, struct module *mod)
*/
buf_printf(b, "#define INCLUDE_VERMAGIC\n");
buf_printf(b, "#include <linux/build-salt.h>\n");
+ buf_printf(b, "#include <linux/elfnote-lto.h>\n");
+ buf_printf(b, "#include <linux/export-internal.h>\n");
buf_printf(b, "#include <linux/vermagic.h>\n");
buf_printf(b, "#include <linux/compiler.h>\n");
buf_printf(b, "\n");
+ buf_printf(b, "#ifdef CONFIG_UNWINDER_ORC\n");
+ buf_printf(b, "#include <asm/orc_header.h>\n");
+ buf_printf(b, "ORC_HEADER;\n");
+ buf_printf(b, "#endif\n");
+ buf_printf(b, "\n");
buf_printf(b, "BUILD_SALT;\n");
+ buf_printf(b, "BUILD_LTO_INFO;\n");
buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
@@ -2210,26 +1935,56 @@ static void add_header(struct buffer *b, struct module *mod)
"#endif\n");
buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
buf_printf(b, "};\n");
-}
-static void add_intree_flag(struct buffer *b, int is_intree)
-{
- if (is_intree)
+ if (!external_module)
buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
-}
-/* Cannot check for assembler */
-static void add_retpoline(struct buffer *b)
-{
- buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n");
- buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
- buf_printf(b, "#endif\n");
+ buf_printf(b,
+ "\n"
+ "#ifdef CONFIG_RETPOLINE\n"
+ "MODULE_INFO(retpoline, \"Y\");\n"
+ "#endif\n");
+
+ if (strstarts(mod->name, "drivers/staging"))
+ buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+
+ if (strstarts(mod->name, "tools/testing"))
+ buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n");
}
-static void add_staging_flag(struct buffer *b, const char *name)
+static void add_exported_symbols(struct buffer *buf, struct module *mod)
{
- if (strstarts(name, "drivers/staging"))
- buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+ struct symbol *sym;
+
+ /* generate struct for exported symbols */
+ buf_printf(buf, "\n");
+ list_for_each_entry(sym, &mod->exported_symbols, list) {
+ if (trim_unused_exports && !sym->used)
+ continue;
+
+ buf_printf(buf, "KSYMTAB_%s(%s, \"%s\", \"%s\");\n",
+ sym->is_func ? "FUNC" : "DATA", sym->name,
+ sym->is_gpl_only ? "_gpl" : "", sym->namespace);
+ }
+
+ if (!modversions)
+ return;
+
+ /* record CRCs for exported symbols */
+ buf_printf(buf, "\n");
+ list_for_each_entry(sym, &mod->exported_symbols, list) {
+ if (trim_unused_exports && !sym->used)
+ continue;
+
+ if (!sym->crc_valid)
+ warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
+ "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
+ sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
+ sym->name);
+
+ buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n",
+ sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : "");
+ }
}
/**
@@ -2237,16 +1992,7 @@ static void add_staging_flag(struct buffer *b, const char *name)
**/
static void add_versions(struct buffer *b, struct module *mod)
{
- struct symbol *s, *exp;
-
- for (s = mod->unres; s; s = s->next) {
- exp = find_symbol(s->name);
- if (!exp || exp->module == mod)
- continue;
- s->module = exp->module;
- s->crc_valid = exp->crc_valid;
- s->crc = exp->crc;
- }
+ struct symbol *s;
if (!modversions)
return;
@@ -2255,7 +2001,7 @@ static void add_versions(struct buffer *b, struct module *mod)
buf_printf(b, "static const struct modversion_info ____versions[]\n");
buf_printf(b, "__used __section(\"__versions\") = {\n");
- for (s = mod->unres; s; s = s->next) {
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
if (!s->module)
continue;
if (!s->crc_valid) {
@@ -2281,13 +2027,14 @@ static void add_depends(struct buffer *b, struct module *mod)
int first = 1;
/* Clear ->seen flag of modules that own symbols needed by this. */
- for (s = mod->unres; s; s = s->next)
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
if (s->module)
s->module->seen = s->module->is_vmlinux;
+ }
buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(depends, \"");
- for (s = mod->unres; s; s = s->next) {
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
const char *p;
if (!s->module)
continue;
@@ -2295,7 +2042,7 @@ static void add_depends(struct buffer *b, struct module *mod)
if (s->module->seen)
continue;
- s->module->seen = 1;
+ s->module->seen = true;
p = strrchr(s->module->name, '/');
if (p)
p++;
@@ -2320,6 +2067,9 @@ static void write_buf(struct buffer *b, const char *fname)
{
FILE *file;
+ if (error_occurred)
+ return;
+
file = fopen(fname, "w");
if (!file) {
perror(fname);
@@ -2370,6 +2120,44 @@ static void write_if_changed(struct buffer *b, const char *fname)
write_buf(b, fname);
}
+static void write_vmlinux_export_c_file(struct module *mod)
+{
+ struct buffer buf = { };
+
+ buf_printf(&buf,
+ "#include <linux/export-internal.h>\n");
+
+ add_exported_symbols(&buf, mod);
+ write_if_changed(&buf, ".vmlinux.export.c");
+ free(buf.p);
+}
+
+/* do sanity checks, and generate *.mod.c file */
+static void write_mod_c_file(struct module *mod)
+{
+ struct buffer buf = { };
+ char fname[PATH_MAX];
+ int ret;
+
+ add_header(&buf, mod);
+ add_exported_symbols(&buf, mod);
+ add_versions(&buf, mod);
+ add_depends(&buf, mod);
+ add_moddevtable(&buf, mod);
+ add_srcversion(&buf, mod);
+
+ ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
+ if (ret >= sizeof(fname)) {
+ error("%s: too long path was truncated\n", fname);
+ goto free;
+ }
+
+ write_if_changed(&buf, fname);
+
+free:
+ free(buf.p);
+}
+
/* parse Module.symvers file. line format:
* 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
**/
@@ -2389,6 +2177,7 @@ static void read_dump(const char *fname)
unsigned int crc;
struct module *mod;
struct symbol *s;
+ bool gpl_only;
if (!(symname = strchr(line, '\t')))
goto fail;
@@ -2406,15 +2195,23 @@ static void read_dump(const char *fname)
crc = strtoul(line, &d, 16);
if (*symname == '\0' || *modname == '\0' || *d != '\0')
goto fail;
+
+ if (!strcmp(export, "EXPORT_SYMBOL_GPL")) {
+ gpl_only = true;
+ } else if (!strcmp(export, "EXPORT_SYMBOL")) {
+ gpl_only = false;
+ } else {
+ error("%s: unknown license %s. skip", symname, export);
+ continue;
+ }
+
mod = find_module(modname);
if (!mod) {
- mod = new_module(modname);
- mod->from_dump = 1;
+ mod = new_module(modname, strlen(modname));
+ mod->from_dump = true;
}
- s = sym_add_exported(symname, mod, export_no(export));
- s->is_static = 0;
- sym_set_crc(symname, crc);
- sym_update_namespace(symname, namespace);
+ s = sym_add_exported(symname, mod, gpl_only, namespace);
+ sym_set_crc(s, crc);
}
free(buf);
return;
@@ -2423,38 +2220,23 @@ fail:
fatal("parse error in symbol dump file\n");
}
-/* For normal builds always dump all symbols.
- * For external modules only dump symbols
- * that are not read from kernel Module.symvers.
- **/
-static int dump_sym(struct symbol *sym)
-{
- if (!external_module)
- return 1;
- if (sym->module->from_dump)
- return 0;
- return 1;
-}
-
static void write_dump(const char *fname)
{
struct buffer buf = { };
- struct symbol *symbol;
- const char *namespace;
- int n;
-
- for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
- symbol = symbolhash[n];
- while (symbol) {
- if (dump_sym(symbol)) {
- namespace = symbol->namespace;
- buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
- symbol->crc, symbol->name,
- symbol->module->name,
- export_str(symbol->export),
- namespace ? namespace : "");
- }
- symbol = symbol->next;
+ struct module *mod;
+ struct symbol *sym;
+
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->from_dump)
+ continue;
+ list_for_each_entry(sym, &mod->exported_symbols, list) {
+ if (trim_unused_exports && !sym->used)
+ continue;
+
+ buf_printf(&buf, "0x%08x\t%s\t%s\tEXPORT_SYMBOL%s\t%s\n",
+ sym->crc, sym->name, mod->name,
+ sym->is_gpl_only ? "_GPL" : "",
+ sym->namespace);
}
}
write_buf(&buf, fname);
@@ -2467,14 +2249,14 @@ static void write_namespace_deps_files(const char *fname)
struct namespace_list *ns;
struct buffer ns_deps_buf = {};
- for (mod = modules; mod; mod = mod->next) {
+ list_for_each_entry(mod, &modules, list) {
- if (mod->from_dump || !mod->missing_namespaces)
+ if (mod->from_dump || list_empty(&mod->missing_namespaces))
continue;
buf_printf(&ns_deps_buf, "%s.ko:", mod->name);
- for (ns = mod->missing_namespaces; ns; ns = ns->next)
+ list_for_each_entry(ns, &mod->missing_namespaces, list)
buf_printf(&ns_deps_buf, " %s", ns->namespace);
buf_printf(&ns_deps_buf, "\n");
@@ -2485,55 +2267,62 @@ static void write_namespace_deps_files(const char *fname)
}
struct dump_list {
- struct dump_list *next;
+ struct list_head list;
const char *file;
};
int main(int argc, char **argv)
{
struct module *mod;
- struct buffer buf = { };
char *missing_namespace_deps = NULL;
+ char *unused_exports_white_list = NULL;
char *dump_write = NULL, *files_source = NULL;
int opt;
- int n;
- struct dump_list *dump_read_start = NULL;
- struct dump_list **dump_read_iter = &dump_read_start;
+ LIST_HEAD(dump_lists);
+ struct dump_list *dl, *dl2;
- while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) {
+ while ((opt = getopt(argc, argv, "ei:mnT:to:au:WwENd:")) != -1) {
switch (opt) {
case 'e':
- external_module = 1;
+ external_module = true;
break;
case 'i':
- *dump_read_iter =
- NOFAIL(calloc(1, sizeof(**dump_read_iter)));
- (*dump_read_iter)->file = optarg;
- dump_read_iter = &(*dump_read_iter)->next;
+ dl = NOFAIL(malloc(sizeof(*dl)));
+ dl->file = optarg;
+ list_add_tail(&dl->list, &dump_lists);
break;
case 'm':
- modversions = 1;
+ modversions = true;
break;
case 'n':
- ignore_missing_files = 1;
+ ignore_missing_files = true;
break;
case 'o':
dump_write = optarg;
break;
case 'a':
- all_versions = 1;
+ all_versions = true;
break;
case 'T':
files_source = optarg;
break;
+ case 't':
+ trim_unused_exports = true;
+ break;
+ case 'u':
+ unused_exports_white_list = optarg;
+ break;
+ case 'W':
+ extra_warn = true;
+ break;
case 'w':
- warn_unresolved = 1;
+ warn_unresolved = true;
break;
case 'E':
sec_mismatch_warn_only = false;
break;
case 'N':
- allow_missing_ns_imports = 1;
+ allow_missing_ns_imports = true;
break;
case 'd':
missing_namespace_deps = optarg;
@@ -2543,13 +2332,10 @@ int main(int argc, char **argv)
}
}
- while (dump_read_start) {
- struct dump_list *tmp;
-
- read_dump(dump_read_start->file);
- tmp = dump_read_start->next;
- free(dump_read_start);
- dump_read_start = tmp;
+ list_for_each_entry_safe(dl, dl2, &dump_lists, list) {
+ read_dump(dl->file);
+ list_del(&dl->list);
+ free(dl);
}
while (optind < argc)
@@ -2558,35 +2344,25 @@ int main(int argc, char **argv)
if (files_source)
read_symbols_from_files(files_source);
- /*
- * When there's no vmlinux, don't print warnings about
- * unresolved symbols (since there'll be too many ;)
- */
- if (!have_vmlinux)
- warn("Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped.\n");
-
- for (mod = modules; mod; mod = mod->next) {
- char fname[PATH_MAX];
-
- if (mod->is_vmlinux || mod->from_dump)
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->from_dump || mod->is_vmlinux)
continue;
- buf.pos = 0;
-
check_modname_len(mod);
check_exports(mod);
+ }
- add_header(&buf, mod);
- add_intree_flag(&buf, !external_module);
- add_retpoline(&buf);
- add_staging_flag(&buf, mod->name);
- add_versions(&buf, mod);
- add_depends(&buf, mod);
- add_moddevtable(&buf, mod);
- add_srcversion(&buf, mod);
+ if (unused_exports_white_list)
+ handle_white_list_exports(unused_exports_white_list);
- sprintf(fname, "%s.mod.c", mod->name);
- write_if_changed(&buf, fname);
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->from_dump)
+ continue;
+
+ if (mod->is_vmlinux)
+ write_vmlinux_export_c_file(mod);
+ else
+ write_mod_c_file(mod);
}
if (missing_namespace_deps)
@@ -2597,18 +2373,10 @@ int main(int argc, char **argv)
if (sec_mismatch_count && !sec_mismatch_warn_only)
error("Section mismatches detected.\n"
"Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n");
- for (n = 0; n < SYMBOL_HASH_SIZE; n++) {
- struct symbol *s;
- for (s = symbolhash[n]; s; s = s->next) {
- if (s->is_static)
- error("\"%s\" [%s] is a static %s\n",
- s->name, s->module->name,
- export_str(s->export));
- }
- }
-
- free(buf.p);
+ if (nr_unresolved > MAX_UNRESOLVED_REPORTS)
+ warn("suppressed %u unresolved symbol warnings because there were too many)\n",
+ nr_unresolved - MAX_UNRESOLVED_REPORTS);
return error_occurred ? 1 : 0;
}
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index c1a895c0d682..dfdb9484e325 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -11,6 +11,7 @@
#include <unistd.h>
#include <elf.h>
+#include "list.h"
#include "elfconfig.h"
/* On BSD-alike OSes elf.h defines these according to host's word size */
@@ -25,7 +26,6 @@
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Addr Elf32_Addr
-#define Elf_Sword Elf64_Sword
#define Elf_Section Elf32_Half
#define ELF_ST_BIND ELF32_ST_BIND
#define ELF_ST_TYPE ELF32_ST_TYPE
@@ -40,7 +40,6 @@
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Addr Elf64_Addr
-#define Elf_Sword Elf64_Sxword
#define Elf_Section Elf64_Half
#define ELF_ST_BIND ELF64_ST_BIND
#define ELF_ST_TYPE ELF64_ST_TYPE
@@ -96,6 +95,9 @@ static inline void __endian(const void *src, void *dest, unsigned int size)
#endif
#define NOFAIL(ptr) do_nofail((ptr), #ptr)
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
void *do_nofail(void *ptr, const char *expr);
struct buffer {
@@ -110,26 +112,22 @@ buf_printf(struct buffer *buf, const char *fmt, ...);
void
buf_write(struct buffer *buf, const char *s, int len);
-struct namespace_list {
- struct namespace_list *next;
- char namespace[];
-};
-
struct module {
- struct module *next;
- int gpl_compatible;
- struct symbol *unres;
- int from_dump; /* 1 if module was loaded from *.symvers */
- int is_vmlinux;
- int seen;
- int has_init;
- int has_cleanup;
+ struct list_head list;
+ struct list_head exported_symbols;
+ struct list_head unresolved_symbols;
+ bool is_gpl_compatible;
+ bool from_dump; /* true if module was loaded from *.symvers */
+ bool is_vmlinux;
+ bool seen;
+ bool has_init;
+ bool has_cleanup;
struct buffer dev_table_buf;
char srcversion[25];
// Missing namespace dependencies
- struct namespace_list *missing_namespaces;
+ struct list_head missing_namespaces;
// Actual imported namespaces
- struct namespace_list *imported_namespaces;
+ struct list_head imported_namespaces;
char name[];
};
@@ -139,8 +137,7 @@ struct elf_info {
Elf_Shdr *sechdrs;
Elf_Sym *symtab_start;
Elf_Sym *symtab_stop;
- Elf_Section export_sec;
- Elf_Section export_gpl_sec;
+ unsigned int export_symbol_secndx; /* .export_symbol section */
char *strtab;
char *modinfo;
unsigned int modinfo_len;
@@ -155,39 +152,31 @@ struct elf_info {
Elf32_Word *symtab_shndx_stop;
};
-static inline int is_shndx_special(unsigned int i)
-{
- return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
-}
-
-/*
- * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
- * the way to -256..-1, to avoid conflicting with real section
- * indices.
- */
-#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
-
/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
static inline unsigned int get_secindex(const struct elf_info *info,
const Elf_Sym *sym)
{
- if (is_shndx_special(sym->st_shndx))
- return SPECIAL(sym->st_shndx);
- if (sym->st_shndx != SHN_XINDEX)
- return sym->st_shndx;
- return info->symtab_shndx_start[sym - info->symtab_start];
-}
-
-static inline bool strends(const char *str, const char *postfix)
-{
- if (strlen(str) < strlen(postfix))
- return false;
-
- return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
+ unsigned int index = sym->st_shndx;
+
+ /*
+ * Elf{32,64}_Sym::st_shndx is 2 byte. Big section numbers are available
+ * in the .symtab_shndx section.
+ */
+ if (index == SHN_XINDEX)
+ return info->symtab_shndx_start[sym - info->symtab_start];
+
+ /*
+ * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
+ * the way to UINT_MAX-255..UINT_MAX, to avoid conflicting with real
+ * section indices.
+ */
+ if (index >= SHN_LORESERVE && index <= SHN_HIRESERVE)
+ return index - SHN_HIRESERVE - 1;
+
+ return index;
}
/* file2alias.c */
-extern unsigned int cross_build;
void handle_moddevtable(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname);
void add_moddevtable(struct buffer *buf, struct module *mod);
@@ -198,6 +187,7 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen);
/* from modpost.c */
char *read_text_file(const char *filename);
char *get_line(char **stringp);
+void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym);
enum loglevel {
LOG_WARN,
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
index 760e6baa7eda..31066bfdba04 100644
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -153,7 +153,7 @@ static void md4_transform(uint32_t *hash, uint32_t const *in)
static inline void md4_transform_helper(struct md4_ctx *ctx)
{
- le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t));
+ le32_to_cpu_array(ctx->block, ARRAY_SIZE(ctx->block));
md4_transform(ctx->hash, ctx->block);
}
@@ -216,7 +216,7 @@ static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)
le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
sizeof(uint64_t)) / sizeof(uint32_t));
md4_transform(mctx->hash, mctx->block);
- cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t));
+ cpu_to_le32_array(mctx->hash, ARRAY_SIZE(mctx->hash));
snprintf(out, len, "%08X%08X%08X%08X",
mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]);
@@ -290,13 +290,11 @@ static int parse_file(const char *fname, struct md4_ctx *md)
return 1;
}
/* Check whether the file is a static library or not */
-static int is_static_library(const char *objfile)
+static bool is_static_library(const char *objfile)
{
int len = strlen(objfile);
- if (objfile[len - 2] == '.' && objfile[len - 1] == 'a')
- return 1;
- else
- return 0;
+
+ return objfile[len - 2] == '.' && objfile[len - 1] == 'a';
}
/* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line
@@ -387,30 +385,18 @@ out_file:
/* Calc and record src checksum. */
void get_src_version(const char *modname, char sum[], unsigned sumlen)
{
- char *buf, *pos, *firstline;
+ char *buf;
struct md4_ctx md;
char *fname;
char filelist[PATH_MAX + 1];
- int postfix_len = 1;
-
- if (strends(modname, ".lto.o"))
- postfix_len = 5;
/* objects for a module are listed in the first line of *.mod file. */
- snprintf(filelist, sizeof(filelist), "%.*smod",
- (int)strlen(modname) - postfix_len, modname);
+ snprintf(filelist, sizeof(filelist), "%s.mod", modname);
buf = read_text_file(filelist);
- pos = buf;
- firstline = get_line(&pos);
- if (!firstline) {
- warn("bad ending versions file for %s\n", modname);
- goto free;
- }
-
md4_init(&md);
- while ((fname = strsep(&firstline, " "))) {
+ while ((fname = strsep(&buf, "\n"))) {
if (!*fname)
continue;
if (!(is_static_library(fname)) &&
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 168cd27e6122..bf5bcf2836d8 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -3,6 +3,12 @@
* Archs are free to supply their own linker scripts. ld will
* combine them automatically.
*/
+#ifdef CONFIG_UNWIND_TABLES
+#define DISCARD_EH_FRAME
+#else
+#define DISCARD_EH_FRAME *(.eh_frame)
+#endif
+
SECTIONS {
/DISCARD/ : {
*(.discard)
@@ -14,12 +20,20 @@ SECTIONS {
__kcrctab 0 : { *(SORT(___kcrctab+*)) }
__kcrctab_gpl 0 : { *(SORT(___kcrctab_gpl+*)) }
+ .ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) }
.init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) }
+ .altinstructions 0 : ALIGN(8) { KEEP(*(.altinstructions)) }
+ __bug_table 0 : ALIGN(8) { KEEP(*(__bug_table)) }
__jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) }
__patchable_function_entries : { *(__patchable_function_entries) }
+#ifdef CONFIG_ARCH_USES_CFI_TRAPS
+ __kcfi_traps : { KEEP(*(.kcfi_traps)) }
+#endif
+
+#ifdef CONFIG_LTO_CLANG
/*
* With CONFIG_LTO_CLANG, LLD always enables -fdata-sections and
* -ffunction-sections, which increases the size of the final module.
@@ -39,8 +53,7 @@ SECTIONS {
*(.rodata .rodata.[0-9a-zA-Z_]*)
*(.rodata..L*)
}
-
- .text : { *(.text .text.[0-9a-zA-Z_]*) }
+#endif
}
/* bring in arch-specific sections */
diff --git a/scripts/modules-check.sh b/scripts/modules-check.sh
index 43de226071ae..4c8da90de78e 100755
--- a/scripts/modules-check.sh
+++ b/scripts/modules-check.sh
@@ -13,10 +13,10 @@ exit_code=0
# Check uniqueness of module names
check_same_name_modules()
{
- for m in $(sed 's:.*/::' $1 | sort | uniq -d)
+ for m in $(sed 's:.*/::' "$1" | sort | uniq -d)
do
echo "error: the following would cause module name conflict:" >&2
- sed -n "/\/$m/s:^: :p" modules.order >&2
+ sed -n "/\/$m/s:^\(.*\)\.o\$: \1.ko:p" "$1" >&2
exit_code=1
done
}
diff --git a/scripts/nsdeps b/scripts/nsdeps
index e8ce2a4d704a..f1718cc0d700 100644
--- a/scripts/nsdeps
+++ b/scripts/nsdeps
@@ -34,9 +34,8 @@ generate_deps() {
local mod=${1%.ko:}
shift
local namespaces="$*"
- local mod_source_files="`cat $mod.mod | sed -n 1p \
- | sed -e 's/\.o/\.c/g' \
- | sed "s|[^ ]* *|${src_prefix}&|g"`"
+ local mod_source_files=$(sed "s|^\(.*\)\.o$|${src_prefix}\1.c|" $mod.mod)
+
for ns in $namespaces; do
echo "Adding namespace $ns to module $mod.ko."
generate_deps_for_ns $ns "$mod_source_files"
@@ -44,7 +43,7 @@ generate_deps() {
for source_file in $mod_source_files; do
sed '/MODULE_IMPORT_NS/Q' $source_file > ${source_file}.tmp
offset=$(wc -l ${source_file}.tmp | awk '{print $1;}')
- cat $source_file | grep MODULE_IMPORT_NS | LANG=C sort -u >> ${source_file}.tmp
+ cat $source_file | grep MODULE_IMPORT_NS | LC_ALL=C sort -u >> ${source_file}.tmp
tail -n +$((offset +1)) ${source_file} | grep -v MODULE_IMPORT_NS >> ${source_file}.tmp
if ! diff -q ${source_file} ${source_file}.tmp; then
mv ${source_file}.tmp ${source_file}
diff --git a/scripts/objdiff b/scripts/objdiff
index 72b0b63c3fe1..0685bc3ce3df 100755
--- a/scripts/objdiff
+++ b/scripts/objdiff
@@ -20,10 +20,10 @@
# $ ./scripts/objdiff diff COMMIT_A COMMIT_B
# $
-# And to clean up (everything is in .tmp_objdiff/*)
+# And to clean up (everything is in .objdiff/*)
# $ ./scripts/objdiff clean all
#
-# Note: 'make mrproper' will also remove .tmp_objdiff
+# Note: 'make mrproper' will also remove .objdiff
SRCTREE=$(cd $(git rev-parse --show-toplevel 2>/dev/null); pwd)
@@ -32,7 +32,7 @@ if [ -z "$SRCTREE" ]; then
exit 1
fi
-TMPD=$SRCTREE/.tmp_objdiff
+TMPD=$SRCTREE/.objdiff
usage() {
echo >&2 "Usage: $0 <command> <args>"
diff --git a/scripts/objdump-func b/scripts/objdump-func
new file mode 100755
index 000000000000..7b15b873d0e2
--- /dev/null
+++ b/scripts/objdump-func
@@ -0,0 +1,45 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Disassemble a single function.
+#
+# usage: objdump-func <file> <func> [<func> ...]
+
+set -o errexit
+set -o nounset
+
+OBJDUMP="${CROSS_COMPILE:-}objdump"
+
+command -v gawk >/dev/null 2>&1 || die "gawk isn't installed"
+
+usage() {
+ echo "usage: objdump-func <file> <func> [<func> ...]" >&2
+ exit 1
+}
+
+[[ $# -lt 2 ]] && usage
+
+OBJ=$1; shift
+FUNCS=("$@")
+
+${OBJDUMP} -wdr $OBJ | gawk -M -v _funcs="${FUNCS[*]}" '
+ BEGIN { split(_funcs, funcs); }
+ /^$/ { func_match=0; }
+ /<.*>:/ {
+ f = gensub(/.*<(.*)>:/, "\\1", 1);
+ for (i in funcs) {
+ # match compiler-added suffixes like ".cold", etc
+ if (f ~ "^" funcs[i] "(\\..*)?") {
+ func_match = 1;
+ base = strtonum("0x" $1);
+ break;
+ }
+ }
+ }
+ {
+ if (func_match) {
+ addr = strtonum("0x" $1);
+ printf("%04x ", addr - base);
+ print;
+ }
+ }'
diff --git a/scripts/orc_hash.sh b/scripts/orc_hash.sh
new file mode 100644
index 000000000000..466611aa0053
--- /dev/null
+++ b/scripts/orc_hash.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+set -e
+
+printf '%s' '#define ORC_HASH '
+
+awk '
+/^#define ORC_(REG|TYPE)_/ { print }
+/^struct orc_entry {$/ { p=1 }
+p { print }
+/^}/ { p=0 }' |
+ sha1sum |
+ cut -d " " -f 1 |
+ sed 's/\([0-9a-f]\{2\}\)/0x\1,/g'
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 91a502bb97e8..032774eb061e 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -42,19 +42,123 @@ create_package() {
else
chown -R root:root "$pdir"
fi
- chmod -R go-w "$pdir"
- # in case we are in a restrictive umask environment like 0077
- chmod -R a+rX "$pdir"
- # in case we build in a setuid/setgid directory
- chmod -R ug-s "$pdir"
+ # a+rX in case we are in a restrictive umask environment like 0077
+ # ug-s in case we build in a setuid/setgid directory
+ chmod -R go-w,a+rX,ug-s "$pdir"
# Create the package
dpkg-gencontrol -p$pname -P"$pdir"
dpkg-deb $dpkg_deb_opts ${KDEB_COMPRESS:+-Z$KDEB_COMPRESS} --build "$pdir" ..
}
-deploy_kernel_headers () {
+install_linux_image () {
pdir=$1
+ pname=$2
+
+ rm -rf ${pdir}
+
+ # Only some architectures with OF support have this target
+ if is_enabled CONFIG_OF_EARLY_FLATTREE && [ -d "${srctree}/arch/${SRCARCH}/boot/dts" ]; then
+ ${MAKE} -f ${srctree}/Makefile INSTALL_DTBS_PATH="${pdir}/usr/lib/linux-image-${KERNELRELEASE}" dtbs_install
+ fi
+
+ ${MAKE} -f ${srctree}/Makefile INSTALL_MOD_PATH="${pdir}" modules_install
+ rm -f "${pdir}/lib/modules/${KERNELRELEASE}/build"
+ rm -f "${pdir}/lib/modules/${KERNELRELEASE}/source"
+
+ # Install the kernel
+ if [ "${ARCH}" = um ] ; then
+ mkdir -p "${pdir}/usr/lib/uml/modules"
+ mv "${pdir}/lib/modules/${KERNELRELEASE}" "${pdir}/usr/lib/uml/modules/${KERNELRELEASE}"
+ mkdir -p "${pdir}/usr/bin" "${pdir}/usr/share/doc/${pname}"
+ cp System.map "${pdir}/usr/lib/uml/modules/${KERNELRELEASE}/System.map"
+ cp ${KCONFIG_CONFIG} "${pdir}/usr/share/doc/${pname}/config"
+ gzip "${pdir}/usr/share/doc/${pname}/config"
+ else
+ mkdir -p "${pdir}/boot"
+ cp System.map "${pdir}/boot/System.map-${KERNELRELEASE}"
+ cp ${KCONFIG_CONFIG} "${pdir}/boot/config-${KERNELRELEASE}"
+ fi
+
+ # Not all arches have the same installed path in debian
+ # XXX: have each arch Makefile export a variable of the canonical image install
+ # path instead
+ case "${SRCARCH}" in
+ um)
+ installed_image_path="usr/bin/linux-${KERNELRELEASE}";;
+ parisc|mips|powerpc)
+ installed_image_path="boot/vmlinux-${KERNELRELEASE}";;
+ *)
+ installed_image_path="boot/vmlinuz-${KERNELRELEASE}";;
+ esac
+ cp "$(${MAKE} -s -f ${srctree}/Makefile image_name)" "${pdir}/${installed_image_path}"
+
+ # Install the maintainer scripts
+ # Note: hook scripts under /etc/kernel are also executed by official Debian
+ # kernel packages, as well as kernel packages built using make-kpkg.
+ # make-kpkg sets $INITRD to indicate whether an initramfs is wanted, and
+ # so do we; recent versions of dracut and initramfs-tools will obey this.
+ debhookdir=${KDEB_HOOKDIR:-/etc/kernel}
+ for script in postinst postrm preinst prerm; do
+ mkdir -p "${pdir}${debhookdir}/${script}.d"
+
+ mkdir -p "${pdir}/DEBIAN"
+ cat <<-EOF > "${pdir}/DEBIAN/${script}"
+
+ #!/bin/sh
+
+ set -e
+
+ # Pass maintainer script parameters to hook scripts
+ export DEB_MAINT_PARAMS="\$*"
+
+ # Tell initramfs builder whether it's wanted
+ export INITRD=$(if_enabled_echo CONFIG_BLK_DEV_INITRD Yes No)
+
+ test -d ${debhookdir}/${script}.d && run-parts --arg="${KERNELRELEASE}" --arg="/${installed_image_path}" ${debhookdir}/${script}.d
+ exit 0
+ EOF
+ chmod 755 "${pdir}/DEBIAN/${script}"
+ done
+}
+
+install_linux_image_dbg () {
+ pdir=$1
+ image_pdir=$2
+
+ rm -rf ${pdir}
+
+ for module in $(find ${image_pdir}/lib/modules/ -name *.ko -printf '%P\n'); do
+ module=lib/modules/${module}
+ mkdir -p $(dirname ${pdir}/usr/lib/debug/${module})
+ # only keep debug symbols in the debug file
+ ${OBJCOPY} --only-keep-debug ${image_pdir}/${module} ${pdir}/usr/lib/debug/${module}
+ # strip original module from debug symbols
+ ${OBJCOPY} --strip-debug ${image_pdir}/${module}
+ # then add a link to those
+ ${OBJCOPY} --add-gnu-debuglink=${pdir}/usr/lib/debug/${module} ${image_pdir}/${module}
+ done
+
+ # re-sign stripped modules
+ if is_enabled CONFIG_MODULE_SIG_ALL; then
+ ${MAKE} -f ${srctree}/Makefile INSTALL_MOD_PATH="${image_pdir}" modules_sign
+ fi
+
+ # Build debug package
+ # Different tools want the image in different locations
+ # perf
+ mkdir -p ${pdir}/usr/lib/debug/lib/modules/${KERNELRELEASE}/
+ cp vmlinux ${pdir}/usr/lib/debug/lib/modules/${KERNELRELEASE}/
+ # systemtap
+ mkdir -p ${pdir}/usr/lib/debug/boot/
+ ln -s ../lib/modules/${KERNELRELEASE}/vmlinux ${pdir}/usr/lib/debug/boot/vmlinux-${KERNELRELEASE}
+ # kdump-tools
+ ln -s lib/modules/${KERNELRELEASE}/vmlinux ${pdir}/usr/lib/debug/vmlinux-${KERNELRELEASE}
+}
+
+install_kernel_headers () {
+ pdir=$1
+ version=$2
rm -rf $pdir
@@ -67,7 +171,7 @@ deploy_kernel_headers () {
) > debian/hdrsrcfiles
{
- if is_enabled CONFIG_STACK_VALIDATION; then
+ if is_enabled CONFIG_OBJTOOL; then
echo tools/objtool/objtool
fi
@@ -91,7 +195,7 @@ deploy_kernel_headers () {
ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build
}
-deploy_libc_headers () {
+install_libc_headers () {
pdir=$1
rm -rf $pdir
@@ -101,137 +205,43 @@ deploy_libc_headers () {
# move asm headers to /usr/include/<libc-machine>/asm to match the structure
# used by Debian-based distros (to support multi-arch)
- host_arch=$(dpkg-architecture -a$(cat debian/arch) -qDEB_HOST_MULTIARCH)
+ host_arch=$(dpkg-architecture -a$DEB_HOST_ARCH -qDEB_HOST_MULTIARCH)
mkdir $pdir/usr/include/$host_arch
mv $pdir/usr/include/asm $pdir/usr/include/$host_arch/
}
-version=$KERNELRELEASE
-tmpdir=debian/linux-image
-dbg_dir=debian/linux-image-dbg
-packagename=linux-image-$version
-dbg_packagename=$packagename-dbg
-
-if [ "$ARCH" = "um" ] ; then
- packagename=user-mode-linux-$version
-fi
-
-# Not all arches have the same installed path in debian
-# XXX: have each arch Makefile export a variable of the canonical image install
-# path instead
-case $ARCH in
-um)
- installed_image_path="usr/bin/linux-$version"
- ;;
-parisc|mips|powerpc)
- installed_image_path="boot/vmlinux-$version"
- ;;
-*)
- installed_image_path="boot/vmlinuz-$version"
-esac
-
-BUILD_DEBUG=$(if_enabled_echo CONFIG_DEBUG_INFO Yes)
-
-# Setup the directory structure
-rm -rf "$tmpdir" "$dbg_dir" debian/files
-mkdir -m 755 -p "$tmpdir/DEBIAN"
-mkdir -p "$tmpdir/lib" "$tmpdir/boot"
-
-# Install the kernel
-if [ "$ARCH" = "um" ] ; then
- mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin" "$tmpdir/usr/share/doc/$packagename"
- cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map"
- cp $KCONFIG_CONFIG "$tmpdir/usr/share/doc/$packagename/config"
- gzip "$tmpdir/usr/share/doc/$packagename/config"
-else
- cp System.map "$tmpdir/boot/System.map-$version"
- cp $KCONFIG_CONFIG "$tmpdir/boot/config-$version"
-fi
-cp "$($MAKE -s -f $srctree/Makefile image_name)" "$tmpdir/$installed_image_path"
-
-if is_enabled CONFIG_OF_EARLY_FLATTREE; then
- # Only some architectures with OF support have this target
- if [ -d "${srctree}/arch/$SRCARCH/boot/dts" ]; then
- $MAKE -f $srctree/Makefile INSTALL_DTBS_PATH="$tmpdir/usr/lib/$packagename" dtbs_install
- fi
-fi
-
-if is_enabled CONFIG_MODULES; then
- INSTALL_MOD_PATH="$tmpdir" $MAKE -f $srctree/Makefile modules_install
- rm -f "$tmpdir/lib/modules/$version/build"
- rm -f "$tmpdir/lib/modules/$version/source"
- if [ "$ARCH" = "um" ] ; then
- mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/"
- rmdir "$tmpdir/lib/modules/$version"
- fi
- if [ -n "$BUILD_DEBUG" ] ; then
- for module in $(find $tmpdir/lib/modules/ -name *.ko -printf '%P\n'); do
- module=lib/modules/$module
- mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module)
- # only keep debug symbols in the debug file
- $OBJCOPY --only-keep-debug $tmpdir/$module $dbg_dir/usr/lib/debug/$module
- # strip original module from debug symbols
- $OBJCOPY --strip-debug $tmpdir/$module
- # then add a link to those
- $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $tmpdir/$module
- done
-
- # resign stripped modules
- if is_enabled CONFIG_MODULE_SIG_ALL; then
- INSTALL_MOD_PATH="$tmpdir" $MAKE -f $srctree/Makefile modules_sign
- fi
- fi
-fi
-
-# Install the maintainer scripts
-# Note: hook scripts under /etc/kernel are also executed by official Debian
-# kernel packages, as well as kernel packages built using make-kpkg.
-# make-kpkg sets $INITRD to indicate whether an initramfs is wanted, and
-# so do we; recent versions of dracut and initramfs-tools will obey this.
-debhookdir=${KDEB_HOOKDIR:-/etc/kernel}
-for script in postinst postrm preinst prerm ; do
- mkdir -p "$tmpdir$debhookdir/$script.d"
- cat <<EOF > "$tmpdir/DEBIAN/$script"
-#!/bin/sh
-
-set -e
-
-# Pass maintainer script parameters to hook scripts
-export DEB_MAINT_PARAMS="\$*"
-
-# Tell initramfs builder whether it's wanted
-export INITRD=$(if_enabled_echo CONFIG_BLK_DEV_INITRD Yes No)
-
-test -d $debhookdir/$script.d && run-parts --arg="$version" --arg="/$installed_image_path" $debhookdir/$script.d
-exit 0
-EOF
- chmod 755 "$tmpdir/DEBIAN/$script"
+rm -f debian/files
+
+packages_enabled=$(dh_listpackages)
+
+for package in ${packages_enabled}
+do
+ case ${package} in
+ *-dbg)
+ # This must be done after linux-image, that is, we expect the
+ # debug package appears after linux-image in debian/control.
+ install_linux_image_dbg debian/linux-image-dbg debian/linux-image;;
+ linux-image-*|user-mode-linux-*)
+ install_linux_image debian/linux-image ${package};;
+ linux-libc-dev)
+ install_libc_headers debian/linux-libc-dev;;
+ linux-headers-*)
+ install_kernel_headers debian/linux-headers ${package#linux-headers-};;
+ esac
done
-if [ "$ARCH" != "um" ]; then
- if is_enabled CONFIG_MODULES; then
- deploy_kernel_headers debian/linux-headers
- create_package linux-headers-$version debian/linux-headers
- fi
-
- deploy_libc_headers debian/linux-libc-dev
- create_package linux-libc-dev debian/linux-libc-dev
-fi
-
-create_package "$packagename" "$tmpdir"
-
-if [ -n "$BUILD_DEBUG" ] ; then
- # Build debug package
- # Different tools want the image in different locations
- # perf
- mkdir -p $dbg_dir/usr/lib/debug/lib/modules/$version/
- cp vmlinux $dbg_dir/usr/lib/debug/lib/modules/$version/
- # systemtap
- mkdir -p $dbg_dir/usr/lib/debug/boot/
- ln -s ../lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/boot/vmlinux-$version
- # kdump-tools
- ln -s lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/vmlinux-$version
- create_package "$dbg_packagename" "$dbg_dir"
-fi
+for package in ${packages_enabled}
+do
+ case ${package} in
+ *-dbg)
+ create_package ${package} debian/linux-image-dbg;;
+ linux-image-*|user-mode-linux-*)
+ create_package ${package} debian/linux-image;;
+ linux-libc-dev)
+ create_package ${package} debian/linux-libc-dev;;
+ linux-headers-*)
+ create_package ${package} debian/linux-headers;;
+ esac
+done
exit 0
diff --git a/scripts/package/buildtar b/scripts/package/buildtar
index 936198a90477..65b4ea502962 100755
--- a/scripts/package/buildtar
+++ b/scripts/package/buildtar
@@ -16,35 +16,7 @@ set -e
#
# Some variables and settings used throughout the script
#
-tmpdir="${objtree}/tar-install"
-tarball="${objtree}/linux-${KERNELRELEASE}-${ARCH}.tar"
-
-
-#
-# Figure out how to compress, if requested at all
-#
-case "${1}" in
- dir-pkg|tar-pkg)
- opts=
- ;;
- targz-pkg)
- opts="-I ${KGZIP}"
- tarball=${tarball}.gz
- ;;
- tarbz2-pkg)
- opts="-I ${KBZIP2}"
- tarball=${tarball}.bz2
- ;;
- tarxz-pkg)
- opts="-I ${XZ}"
- tarball=${tarball}.xz
- ;;
- *)
- echo "Unknown tarball target \"${1}\" requested, please add it to ${0}." >&2
- exit 1
- ;;
-esac
-
+tmpdir=$1
#
# Clean-up and re-create the temporary directory
@@ -118,13 +90,21 @@ case "${ARCH}" in
fi
;;
arm64)
- for i in Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo ; do
+ for i in Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo vmlinuz.efi ; do
if [ -f "${objtree}/arch/arm64/boot/${i}" ] ; then
cp -v -- "${objtree}/arch/arm64/boot/${i}" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
break
fi
done
;;
+ riscv)
+ for i in Image.bz2 Image.gz Image; do
+ if [ -f "${objtree}/arch/riscv/boot/${i}" ] ; then
+ cp -v -- "${objtree}/arch/riscv/boot/${i}" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+ break
+ fi
+ done
+ ;;
*)
[ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-kbuild-${KERNELRELEASE}"
echo "" >&2
@@ -136,21 +116,3 @@ case "${ARCH}" in
sleep 5
;;
esac
-
-if [ "${1}" = dir-pkg ]; then
- echo "Kernel tree successfully created in $tmpdir"
- exit 0
-fi
-
-#
-# Create the tarball
-#
-if tar --owner=root --group=root --help >/dev/null 2>&1; then
- opts="$opts --owner=root --group=root"
-fi
-
-tar cf $tarball -C $tmpdir $opts $dirs
-
-echo "Tarball successfully created in $tarball"
-
-exit 0
diff --git a/scripts/package/deb-build-option b/scripts/package/deb-build-option
new file mode 100755
index 000000000000..7950eff01781
--- /dev/null
+++ b/scripts/package/deb-build-option
@@ -0,0 +1,14 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+
+# Set up CROSS_COMPILE if not defined yet
+if [ "${CROSS_COMPILE+set}" != "set" -a "${DEB_HOST_ARCH}" != "${DEB_BUILD_ARCH}" ]; then
+ echo CROSS_COMPILE=${DEB_HOST_GNU_TYPE}-
+fi
+
+version=$(dpkg-parsechangelog -S Version)
+debian_revision="${version##*-}"
+
+if [ "${version}" != "${debian_revision}" ]; then
+ echo KBUILD_BUILD_VERSION=${debian_revision}
+fi
diff --git a/scripts/package/gen-diff-patch b/scripts/package/gen-diff-patch
new file mode 100755
index 000000000000..8a98b7bb78a0
--- /dev/null
+++ b/scripts/package/gen-diff-patch
@@ -0,0 +1,36 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+
+diff_patch=$1
+
+mkdir -p "$(dirname "${diff_patch}")"
+
+git -C "${srctree:-.}" diff HEAD > "${diff_patch}"
+
+if [ ! -s "${diff_patch}" ] ||
+ [ -z "$(git -C "${srctree:-.}" ls-files --other --exclude-standard | head -n1)" ]; then
+ exit
+fi
+
+# The source tarball, which is generated by 'git archive', contains everything
+# you committed in the repository. If you have local diff ('git diff HEAD'),
+# it will go into ${diff_patch}. If untracked files are remaining, the resulting
+# source package may not be correct.
+#
+# Examples:
+# - You modified a source file to add #include "new-header.h"
+# but forgot to add new-header.h
+# - You modified a Makefile to add 'obj-$(CONFIG_FOO) += new-dirver.o'
+# but you forgot to add new-driver.c
+#
+# You need to commit them, or at least stage them by 'git add'.
+#
+# This script does not take care of untracked files because doing so would
+# introduce additional complexity. Instead, print a warning message here if
+# untracked files are found.
+# If all untracked files are just garbage, you can ignore this warning.
+echo >&2 "============================ WARNING ============================"
+echo >&2 "Your working tree has diff from HEAD, and also untracked file(s)."
+echo >&2 "Please make sure you did 'git add' for all new files you need in"
+echo >&2 "the source package."
+echo >&2 "================================================================="
diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian
index 60a2a63a5e90..ba2453e08d40 100755
--- a/scripts/package/mkdebian
+++ b/scripts/package/mkdebian
@@ -84,16 +84,75 @@ set_debarch() {
fi
}
+# Create debian/source/ if it is a source package build
+gen_source ()
+{
+ mkdir -p debian/source
+
+ echo "3.0 (quilt)" > debian/source/format
+
+ {
+ echo "diff-ignore"
+ echo "extend-diff-ignore = .*"
+ } > debian/source/local-options
+
+ # Add .config as a patch
+ mkdir -p debian/patches
+ {
+ echo "Subject: Add .config"
+ echo "Author: ${maintainer}"
+ echo
+ echo "--- /dev/null"
+ echo "+++ linux/.config"
+ diff -u /dev/null "${KCONFIG_CONFIG}" | tail -n +3
+ } > debian/patches/config.patch
+ echo config.patch > debian/patches/series
+
+ "${srctree}/scripts/package/gen-diff-patch" debian/patches/diff.patch
+ if [ -s debian/patches/diff.patch ]; then
+ sed -i "
+ 1iSubject: Add local diff
+ 1iAuthor: ${maintainer}
+ 1i
+ " debian/patches/diff.patch
+
+ echo diff.patch >> debian/patches/series
+ else
+ rm -f debian/patches/diff.patch
+ fi
+}
+
+rm -rf debian
+mkdir debian
+
+email=${DEBEMAIL-$EMAIL}
+
+# use email string directly if it contains <email>
+if echo "${email}" | grep -q '<.*>'; then
+ maintainer=${email}
+else
+ # or construct the maintainer string
+ user=${KBUILD_BUILD_USER-$(id -nu)}
+ name=${DEBFULLNAME-${user}}
+ if [ -z "${email}" ]; then
+ buildhost=${KBUILD_BUILD_HOST-$(hostname -f 2>/dev/null || hostname)}
+ email="${user}@${buildhost}"
+ fi
+ maintainer="${name} <${email}>"
+fi
+
+if [ "$1" = --need-source ]; then
+ gen_source
+fi
+
# Some variables and settings used throughout the script
version=$KERNELRELEASE
if [ -n "$KDEB_PKGVERSION" ]; then
packageversion=$KDEB_PKGVERSION
- revision=${packageversion##*-}
else
- revision=$(cat .version 2>/dev/null||echo 1)
- packageversion=$version-$revision
+ packageversion=$(${srctree}/scripts/setlocalversion --no-local ${srctree})-$($srctree/init/build-version)
fi
-sourcename=$KDEB_SOURCENAME
+sourcename=${KDEB_SOURCENAME:-linux-upstream}
if [ "$ARCH" = "um" ] ; then
packagename=user-mode-linux
@@ -104,22 +163,6 @@ fi
debarch=
set_debarch
-email=${DEBEMAIL-$EMAIL}
-
-# use email string directly if it contains <email>
-if echo $email | grep -q '<.*>'; then
- maintainer=$email
-else
- # or construct the maintainer string
- user=${KBUILD_BUILD_USER-$(id -nu)}
- name=${DEBFULLNAME-$user}
- if [ -z "$email" ]; then
- buildhost=${KBUILD_BUILD_HOST-$(hostname -f 2>/dev/null || hostname)}
- email="$user@$buildhost"
- fi
- maintainer="$name <$email>"
-fi
-
# Try to determine distribution
if [ -n "$KDEB_CHANGELOG_DIST" ]; then
distribution=$KDEB_CHANGELOG_DIST
@@ -132,9 +175,6 @@ else
echo >&2 "Install lsb-release or set \$KDEB_CHANGELOG_DIST explicitly"
fi
-mkdir -p debian/source/
-echo "1.0" > debian/source/format
-
echo $debarch > debian/arch
extra_build_depends=", $(if_enabled_echo CONFIG_UNWINDER_ORC libelf-dev:native)"
extra_build_depends="$extra_build_depends, $(if_enabled_echo CONFIG_SYSTEM_TRUSTED_KEYRING libssl-dev:native)"
@@ -150,7 +190,7 @@ EOF
# Generate copyright file
cat <<EOF > debian/copyright
-This is a packacked upstream version of the Linux kernel.
+This is a packaged upstream version of the Linux kernel.
The sources may be found at most Linux archive sites, including:
https://www.kernel.org/pub/linux/kernel
@@ -175,7 +215,7 @@ Section: kernel
Priority: optional
Maintainer: $maintainer
Rules-Requires-Root: no
-Build-Depends: bc, rsync, kmod, cpio, bison, flex | flex:native $extra_build_depends
+Build-Depends: bc, debhelper, rsync, kmod, cpio, bison, flex $extra_build_depends
Homepage: https://www.kernel.org/
Package: $packagename-$version
@@ -183,6 +223,10 @@ Architecture: $debarch
Description: Linux kernel, version $version
This package contains the Linux kernel, modules and corresponding other
files, version: $version.
+EOF
+
+if [ "${SRCARCH}" != um ]; then
+cat <<EOF >> debian/control
Package: linux-libc-dev
Section: devel
@@ -205,6 +249,7 @@ Description: Linux kernel headers for $version on $debarch
This is useful for people who need to build external modules
EOF
fi
+fi
if is_enabled CONFIG_DEBUG_INFO; then
cat <<EOF >> debian/control
@@ -222,22 +267,27 @@ cat <<EOF > debian/rules
#!$(command -v $MAKE) -f
srctree ?= .
+KERNELRELEASE = ${KERNELRELEASE}
+
+.PHONY: clean build build-arch build-indep binary binary-arch binary-indep
build-indep:
build-arch:
- \$(MAKE) KERNELRELEASE=${version} ARCH=${ARCH} \
- KBUILD_BUILD_VERSION=${revision} -f \$(srctree)/Makefile
+ \$(MAKE) -f \$(srctree)/Makefile ARCH=${ARCH} \
+ KERNELRELEASE=\$(KERNELRELEASE) \
+ \$(shell \$(srctree)/scripts/package/deb-build-option) \
+ olddefconfig all
build: build-arch
binary-indep:
binary-arch: build-arch
- \$(MAKE) KERNELRELEASE=${version} ARCH=${ARCH} \
- KBUILD_BUILD_VERSION=${revision} -f \$(srctree)/Makefile intdeb-pkg
+ \$(MAKE) -f \$(srctree)/Makefile ARCH=${ARCH} \
+ KERNELRELEASE=\$(KERNELRELEASE) intdeb-pkg
clean:
- rm -rf debian/*tmp debian/files
- \$(MAKE) clean
+ rm -rf debian/files debian/linux-*
+ \$(MAKE) -f \$(srctree)/Makefile ARCH=${ARCH} clean
binary: binary-arch
EOF
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
index 7c477ca7dc98..c9299f9c1f3e 100755
--- a/scripts/package/mkspec
+++ b/scripts/package/mkspec
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Output a simple RPM spec file.
-# This version assumes a minimum of RPM 4.0.3.
+# This version assumes a minimum of RPM 4.13
#
# The only gothic bit here is redefining install_post to avoid
# stripping the symbols from files in the kernel which we want
@@ -15,19 +15,19 @@ if [ "$1" = prebuilt ]; then
MAKE="$MAKE -f $srctree/Makefile"
else
S=
+
+ mkdir -p rpmbuild/SOURCES
+ cp linux.tar.gz rpmbuild/SOURCES
+ cp "${KCONFIG_CONFIG}" rpmbuild/SOURCES/config
+ "${srctree}/scripts/package/gen-diff-patch" rpmbuild/SOURCES/diff.patch
fi
-if grep -q CONFIG_MODULES=y .config; then
+if grep -q CONFIG_MODULES=y include/config/auto.conf; then
M=
else
M=DEL
fi
-if grep -q CONFIG_DRM=y .config; then
- PROVIDES=kernel-drm
-fi
-
-PROVIDES="$PROVIDES kernel-$KERNELRELEASE"
__KERNELRELEASE=$(echo $KERNELRELEASE | sed -e "s/-/_/g")
EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \
--exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation \
@@ -47,8 +47,17 @@ sed -e '/^DEL/d' -e 's/^\t*//' <<EOF
Group: System Environment/Kernel
Vendor: The Linux Community
URL: https://www.kernel.org
-$S Source: kernel-$__KERNELRELEASE.tar.gz
- Provides: $PROVIDES
+$S Source0: linux.tar.gz
+$S Source1: config
+$S Source2: diff.patch
+ Provides: kernel-$KERNELRELEASE
+$S BuildRequires: bc binutils bison dwarves
+$S BuildRequires: (elfutils-libelf-devel or libelf-devel) flex
+$S BuildRequires: gcc make openssl openssl-devel perl python3 rsync
+
+ # $UTS_MACHINE as a fallback of _arch in case
+ # /usr/lib/rpm/platform/*/macros was not included.
+ %{!?_arch: %define _arch $UTS_MACHINE}
%define __spec_install_post /usr/lib/rpm/brp-compress || :
%define debug_package %{nil}
@@ -76,26 +85,26 @@ $S$M This package provides kernel headers and makefiles sufficient to build modu
$S$M against the $__KERNELRELEASE kernel package.
$S$M
$S %prep
-$S %setup -q
+$S %setup -q -n linux
+$S cp %{SOURCE1} .config
+$S patch -p1 < %{SOURCE2}
$S
$S %build
-$S $MAKE %{?_smp_mflags} KBUILD_BUILD_VERSION=%{release}
+$S $MAKE %{?_smp_mflags} KERNELRELEASE=$KERNELRELEASE KBUILD_BUILD_VERSION=%{release}
$S
%install
mkdir -p %{buildroot}/boot
%ifarch ia64
mkdir -p %{buildroot}/boot/efi
- cp \$($MAKE image_name) %{buildroot}/boot/efi/vmlinuz-$KERNELRELEASE
+ cp \$($MAKE -s image_name) %{buildroot}/boot/efi/vmlinuz-$KERNELRELEASE
ln -s efi/vmlinuz-$KERNELRELEASE %{buildroot}/boot/
%else
- cp \$($MAKE image_name) %{buildroot}/boot/vmlinuz-$KERNELRELEASE
+ cp \$($MAKE -s image_name) %{buildroot}/boot/vmlinuz-$KERNELRELEASE
%endif
$M $MAKE %{?_smp_mflags} INSTALL_MOD_PATH=%{buildroot} modules_install
$MAKE %{?_smp_mflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install
cp System.map %{buildroot}/boot/System.map-$KERNELRELEASE
cp .config %{buildroot}/boot/config-$KERNELRELEASE
- bzip2 -9 --keep vmlinux
- mv vmlinux.bz2 %{buildroot}/boot/vmlinux-$KERNELRELEASE.bz2
$S$M rm -f %{buildroot}/lib/modules/$KERNELRELEASE/build
$S$M rm -f %{buildroot}/lib/modules/$KERNELRELEASE/source
$S$M mkdir -p %{buildroot}/usr/src/kernels/$KERNELRELEASE
diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh
new file mode 100755
index 000000000000..728d55190d97
--- /dev/null
+++ b/scripts/pahole-flags.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+extra_paholeopt=
+
+if ! [ -x "$(command -v ${PAHOLE})" ]; then
+ exit 0
+fi
+
+pahole_ver=$($(dirname $0)/pahole-version.sh ${PAHOLE})
+
+if [ "${pahole_ver}" -ge "118" ] && [ "${pahole_ver}" -le "121" ]; then
+ # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars
+ extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_vars"
+fi
+if [ "${pahole_ver}" -ge "121" ]; then
+ extra_paholeopt="${extra_paholeopt} --btf_gen_floats"
+fi
+if [ "${pahole_ver}" -ge "122" ]; then
+ extra_paholeopt="${extra_paholeopt} -j"
+fi
+if [ "${pahole_ver}" -ge "124" ]; then
+ # see PAHOLE_HAS_LANG_EXCLUDE
+ extra_paholeopt="${extra_paholeopt} --lang_exclude=rust"
+fi
+if [ "${pahole_ver}" -ge "125" ]; then
+ extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_inconsistent_proto --btf_gen_optimized"
+fi
+
+echo ${extra_paholeopt}
diff --git a/scripts/pahole-version.sh b/scripts/pahole-version.sh
new file mode 100755
index 000000000000..f8a32ab93ad1
--- /dev/null
+++ b/scripts/pahole-version.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Usage: $ ./pahole-version.sh pahole
+#
+# Prints pahole's version in a 3-digit form, such as 119 for v1.19.
+
+if [ ! -x "$(command -v "$@")" ]; then
+ echo 0
+ exit 1
+fi
+
+"$@" --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/'
diff --git a/scripts/prune-kernel b/scripts/prune-kernel
index e8aa940bc0a9..dadfd0e47f89 100755
--- a/scripts/prune-kernel
+++ b/scripts/prune-kernel
@@ -16,6 +16,10 @@ do
rm -f "/boot/initramfs-$f.img" "/boot/System.map-$f"
rm -f "/boot/vmlinuz-$f" "/boot/config-$f"
rm -rf "/lib/modules/$f"
- new-kernel-pkg --remove $f
+ if [ -x "$(command -v new-kernel-pkg)" ]; then
+ new-kernel-pkg --remove $f
+ elif [ -x "$(command -v kernel-install)" ]; then
+ kernel-install remove $f
+ fi
fi
done
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index b9c2ee7ab43f..40ae6b2c7a6d 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -38,6 +38,14 @@
#define R_AARCH64_ABS64 257
#endif
+#ifndef EM_LOONGARCH
+#define EM_LOONGARCH 258
+#define R_LARCH_32 1
+#define R_LARCH_64 2
+#define R_LARCH_MARK_LA 20
+#define R_LARCH_SOP_PUSH_PLT_PCREL 29
+#endif
+
#define R_ARM_PC24 1
#define R_ARM_THM_CALL 10
#define R_ARM_CALL 28
@@ -102,6 +110,7 @@ static ssize_t uwrite(void const *const buf, size_t const count)
{
size_t cnt = count;
off_t idx = 0;
+ void *p = NULL;
file_updated = 1;
@@ -109,7 +118,10 @@ static ssize_t uwrite(void const *const buf, size_t const count)
off_t aoffset = (file_ptr + count) - file_end;
if (aoffset > file_append_size) {
- file_append = realloc(file_append, aoffset);
+ p = realloc(file_append, aoffset);
+ if (!p)
+ free(file_append);
+ file_append = p;
file_append_size = aoffset;
}
if (!file_append) {
@@ -438,7 +450,29 @@ static int arm_is_fake_mcount(Elf32_Rel const *rp)
static int arm64_is_fake_mcount(Elf64_Rel const *rp)
{
- return ELF64_R_TYPE(w(rp->r_info)) != R_AARCH64_CALL26;
+ return ELF64_R_TYPE(w8(rp->r_info)) != R_AARCH64_CALL26;
+}
+
+static int LARCH32_is_fake_mcount(Elf32_Rel const *rp)
+{
+ switch (ELF64_R_TYPE(w(rp->r_info))) {
+ case R_LARCH_MARK_LA:
+ case R_LARCH_SOP_PUSH_PLT_PCREL:
+ return 0;
+ }
+
+ return 1;
+}
+
+static int LARCH64_is_fake_mcount(Elf64_Rel const *rp)
+{
+ switch (ELF64_R_TYPE(w(rp->r_info))) {
+ case R_LARCH_MARK_LA:
+ case R_LARCH_SOP_PUSH_PLT_PCREL:
+ return 0;
+ }
+
+ return 1;
}
/* 64-bit EM_MIPS has weird ELF64_Rela.r_info.
@@ -558,6 +592,7 @@ static int do_file(char const *const fname)
break;
case EM_IA_64: reltype = R_IA64_IMM64; break;
case EM_MIPS: /* reltype: e_class */ break;
+ case EM_LOONGARCH: /* reltype: e_class */ break;
case EM_PPC: reltype = R_PPC_ADDR32; break;
case EM_PPC64: reltype = R_PPC64_ADDR64; break;
case EM_S390: /* reltype: e_class */ break;
@@ -589,6 +624,10 @@ static int do_file(char const *const fname)
reltype = R_MIPS_32;
is_fake_mcount32 = MIPS32_is_fake_mcount;
}
+ if (w2(ehdr->e_machine) == EM_LOONGARCH) {
+ reltype = R_LARCH_32;
+ is_fake_mcount32 = LARCH32_is_fake_mcount;
+ }
if (do32(ehdr, fname, reltype) < 0)
goto out;
break;
@@ -610,6 +649,10 @@ static int do_file(char const *const fname)
Elf64_r_info = MIPS64_r_info;
is_fake_mcount64 = MIPS64_is_fake_mcount;
}
+ if (w2(ghdr->e_machine) == EM_LOONGARCH) {
+ reltype = R_LARCH_64;
+ is_fake_mcount64 = LARCH64_is_fake_mcount;
+ }
if (do64(ghdr, fname, reltype) < 0)
goto out;
break;
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index f9b19524da11..1e9baa5c4fc6 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -192,15 +192,20 @@ static unsigned int get_symindex(Elf_Sym const *sym, Elf32_Word const *symtab,
Elf32_Word const *symtab_shndx)
{
unsigned long offset;
+ unsigned short shndx = w2(sym->st_shndx);
int index;
- if (sym->st_shndx != SHN_XINDEX)
- return w2(sym->st_shndx);
+ if (shndx > SHN_UNDEF && shndx < SHN_LORESERVE)
+ return shndx;
- offset = (unsigned long)sym - (unsigned long)symtab;
- index = offset / sizeof(*sym);
+ if (shndx == SHN_XINDEX) {
+ offset = (unsigned long)sym - (unsigned long)symtab;
+ index = offset / sizeof(*sym);
- return w(symtab_shndx[index]);
+ return w(symtab_shndx[index]);
+ }
+
+ return 0;
}
static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index 867860ea57da..6a4645a57976 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -173,39 +173,6 @@ my $mcount_regex; # Find the call site to mcount (return offset)
my $mcount_adjust; # Address adjustment to mcount offset
my $alignment; # The .align value to use for $mcount_section
my $section_type; # Section header plus possible alignment command
-my $can_use_local = 0; # If we can use local function references
-
-# Shut up recordmcount if user has older objcopy
-my $quiet_recordmcount = ".tmp_quiet_recordmcount";
-my $print_warning = 1;
-$print_warning = 0 if ( -f $quiet_recordmcount);
-
-##
-# check_objcopy - whether objcopy supports --globalize-symbols
-#
-# --globalize-symbols came out in 2.17, we must test the version
-# of objcopy, and if it is less than 2.17, then we can not
-# record local functions.
-sub check_objcopy
-{
- open (IN, "$objcopy --version |") or die "error running $objcopy";
- while (<IN>) {
- if (/objcopy.*\s(\d+)\.(\d+)/) {
- $can_use_local = 1 if ($1 > 2 || ($1 == 2 && $2 >= 17));
- last;
- }
- }
- close (IN);
-
- if (!$can_use_local && $print_warning) {
- print STDERR "WARNING: could not find objcopy version or version " .
- "is less than 2.17.\n" .
- "\tLocal function references are disabled.\n";
- open (QUIET, ">$quiet_recordmcount");
- printf QUIET "Disables the warning from recordmcount.pl\n";
- close QUIET;
- }
-}
if ($arch =~ /(x86(_64)?)|(i386)/) {
if ($bits == 64) {
@@ -222,7 +189,7 @@ if ($arch =~ /(x86(_64)?)|(i386)/) {
$local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)";
$weak_regex = "^[0-9a-fA-F]+\\s+([wW])\\s+(\\S+)";
$section_regex = "Disassembly of section\\s+(\\S+):";
-$function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:";
+$function_regex = "^([0-9a-fA-F]+)\\s+<([^^]*?)>:";
$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s(mcount|__fentry__)\$";
$section_type = '@progbits';
$mcount_adjust = 0;
@@ -252,7 +219,7 @@ if ($arch eq "x86_64") {
} elsif ($arch eq "s390" && $bits == 64) {
if ($cc =~ /-DCC_USING_HOTPATCH/) {
- $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*brcl\\s*0,[0-9a-f]+ <([^\+]*)>\$";
+ $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(brcl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
$mcount_adjust = 0;
}
$alignment = 8;
@@ -266,9 +233,9 @@ if ($arch eq "x86_64") {
# force flags for this arch
$ld .= " -m shlelf_linux";
if ($endian eq "big") {
- $objcopy .= " -O elf32-shbig-linux";
+ $objcopy .= " -O elf32-shbig-linux";
} else {
- $objcopy .= " -O elf32-sh-linux";
+ $objcopy .= " -O elf32-sh-linux";
}
} elsif ($arch eq "powerpc") {
@@ -289,12 +256,12 @@ if ($arch eq "x86_64") {
$ldemulation = "lppc"
}
if ($bits == 64) {
- $type = ".quad";
- $cc .= " -m64 ";
- $ld .= " -m elf64".$ldemulation." ";
+ $type = ".quad";
+ $cc .= " -m64 ";
+ $ld .= " -m elf64".$ldemulation." ";
} else {
- $cc .= " -m32 ";
- $ld .= " -m elf32".$ldemulation." ";
+ $cc .= " -m32 ";
+ $ld .= " -m elf32".$ldemulation." ";
}
} elsif ($arch eq "arm") {
@@ -313,7 +280,7 @@ if ($arch eq "x86_64") {
$type = "data8";
if ($is_module eq "0") {
- $cc .= " -mconstant-gp";
+ $cc .= " -mconstant-gp";
}
} elsif ($arch eq "sparc64") {
# In the objdump output there are giblets like:
@@ -392,12 +359,9 @@ if ($arch eq "x86_64") {
$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
} elsif ($arch eq "riscv") {
$function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:";
- $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL\\s_mcount\$";
+ $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL(_PLT)?\\s_?mcount\$";
$type = ".quad";
$alignment = 2;
-} elsif ($arch eq "nds32") {
- $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_NDS32_HI20_RELA\\s+_mcount\$";
- $alignment = 2;
} elsif ($arch eq "csky") {
$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_CKCORE_PCREL_JSR_IMM26BY2\\s+_mcount\$";
$alignment = 2;
@@ -434,8 +398,6 @@ if ($filename =~ m,^(.*)(\.\S),) {
my $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s";
my $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o";
-check_objcopy();
-
#
# Step 1: find all the local (static functions) and weak symbols.
# 't' is local, 'w/W' is weak
@@ -473,11 +435,6 @@ sub update_funcs
# is this function static? If so, note this fact.
if (defined $locals{$ref_func}) {
-
- # only use locals if objcopy supports globalize-symbols
- if (!$can_use_local) {
- return;
- }
$convert{$ref_func} = 1;
}
@@ -497,7 +454,7 @@ sub update_funcs
#
# Step 2: find the sections and mcount call sites
#
-open(IN, "LANG=C $objdump -hdr $inputfile|") || die "error running $objdump";
+open(IN, "LC_ALL=C $objdump -hdr $inputfile|") || die "error running $objdump";
my $text;
@@ -530,10 +487,10 @@ while (<IN>) {
$read_function = defined($text_sections{$1});
if (!$read_function) {
foreach my $prefix (keys %text_section_prefixes) {
- if (substr($1, 0, length $prefix) eq $prefix) {
- $read_function = 1;
- last;
- }
+ if (substr($1, 0, length $prefix) eq $prefix) {
+ $read_function = 1;
+ last;
+ }
}
}
# print out any recorded offsets
@@ -642,3 +599,5 @@ if ($#converts >= 0) {
`$rm $mcount_o $mcount_s`;
exit(0);
+
+# vim: softtabstop=4
diff --git a/scripts/relocs_check.sh b/scripts/relocs_check.sh
new file mode 100755
index 000000000000..137c660499f3
--- /dev/null
+++ b/scripts/relocs_check.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Get a list of all the relocations, remove from it the relocations
+# that are known to be legitimate and return this list to arch specific
+# script that will look for suspicious relocations.
+
+objdump="$1"
+nm="$2"
+vmlinux="$3"
+
+# Remove from the possible bad relocations those that match an undefined
+# weak symbol which will result in an absolute relocation to 0.
+# Weak unresolved symbols are of that form in nm output:
+# " w _binary__btf_vmlinux_bin_end"
+undef_weak_symbols=$($nm "$vmlinux" | awk '$1 ~ /w/ { print $2 }')
+
+$objdump -R "$vmlinux" |
+ grep -E '\<R_' |
+ ([ "$undef_weak_symbols" ] && grep -F -w -v "$undef_weak_symbols" || cat)
diff --git a/scripts/remove-stale-files b/scripts/remove-stale-files
new file mode 100755
index 000000000000..f3659ea0335b
--- /dev/null
+++ b/scripts/remove-stale-files
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+set -e
+
+# When you move, remove or rename generated files, you probably also update
+# .gitignore and cleaning rules in the Makefile. This is the right thing
+# to do. However, people usually do 'git pull', 'git bisect', etc. without
+# running 'make clean'. Then, the stale generated files are left over, often
+# causing build issues.
+#
+# Also, 'git status' shows such stale build artifacts as untracked files.
+# What is worse, some people send a wrong patch to get them back to .gitignore
+# without checking the commit history.
+#
+# So, when you (re)move generated files, please move the cleaning rules from
+# the Makefile to this script. This is run before Kbuild starts building
+# anything, so people will not be annoyed by such garbage files.
+#
+# This script is not intended to grow endlessly. Rather, it is a temporary scrap
+# yard. Stale files stay in this file for a while (for some release cycles?),
+# then will be really dead and removed from the code base entirely.
+
+rm -f arch/powerpc/purgatory/kexec-purgatory.c
+rm -f arch/riscv/purgatory/kexec-purgatory.c
+rm -f arch/x86/purgatory/kexec-purgatory.c
+
+rm -f scripts/extract-cert
+
+rm -f scripts/kconfig/[gmnq]conf-cfg
+
+rm -f rust/target.json
+
+rm -f scripts/bin2c
+
+rm -f .scmversion
+
+rm -rf include/ksym
+
+find . -name '*.usyms' | xargs rm -f
diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh
new file mode 100755
index 000000000000..7a925d2b20fc
--- /dev/null
+++ b/scripts/rust_is_available.sh
@@ -0,0 +1,162 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Tests whether a suitable Rust toolchain is available.
+
+set -e
+
+min_tool_version=$(dirname $0)/min-tool-version.sh
+
+# Convert the version string x.y.z to a canonical up-to-7-digits form.
+#
+# Note that this function uses one more digit (compared to other
+# instances in other version scripts) to give a bit more space to
+# `rustc` since it will reach 1.100.0 in late 2026.
+get_canonical_version()
+{
+ IFS=.
+ set -- $1
+ echo $((100000 * $1 + 100 * $2 + $3))
+}
+
+# Check that the Rust compiler exists.
+if ! command -v "$RUSTC" >/dev/null; then
+ echo >&2 "***"
+ echo >&2 "*** Rust compiler '$RUSTC' could not be found."
+ echo >&2 "***"
+ exit 1
+fi
+
+# Check that the Rust bindings generator exists.
+if ! command -v "$BINDGEN" >/dev/null; then
+ echo >&2 "***"
+ echo >&2 "*** Rust bindings generator '$BINDGEN' could not be found."
+ echo >&2 "***"
+ exit 1
+fi
+
+# Check that the Rust compiler version is suitable.
+#
+# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
+rust_compiler_version=$( \
+ LC_ALL=C "$RUSTC" --version 2>/dev/null \
+ | head -n 1 \
+ | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
+)
+rust_compiler_min_version=$($min_tool_version rustc)
+rust_compiler_cversion=$(get_canonical_version $rust_compiler_version)
+rust_compiler_min_cversion=$(get_canonical_version $rust_compiler_min_version)
+if [ "$rust_compiler_cversion" -lt "$rust_compiler_min_cversion" ]; then
+ echo >&2 "***"
+ echo >&2 "*** Rust compiler '$RUSTC' is too old."
+ echo >&2 "*** Your version: $rust_compiler_version"
+ echo >&2 "*** Minimum version: $rust_compiler_min_version"
+ echo >&2 "***"
+ exit 1
+fi
+if [ "$rust_compiler_cversion" -gt "$rust_compiler_min_cversion" ]; then
+ echo >&2 "***"
+ echo >&2 "*** Rust compiler '$RUSTC' is too new. This may or may not work."
+ echo >&2 "*** Your version: $rust_compiler_version"
+ echo >&2 "*** Expected version: $rust_compiler_min_version"
+ echo >&2 "***"
+fi
+
+# Check that the Rust bindings generator is suitable.
+#
+# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
+rust_bindings_generator_version=$( \
+ LC_ALL=C "$BINDGEN" --version 2>/dev/null \
+ | head -n 1 \
+ | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' \
+)
+rust_bindings_generator_min_version=$($min_tool_version bindgen)
+rust_bindings_generator_cversion=$(get_canonical_version $rust_bindings_generator_version)
+rust_bindings_generator_min_cversion=$(get_canonical_version $rust_bindings_generator_min_version)
+if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cversion" ]; then
+ echo >&2 "***"
+ echo >&2 "*** Rust bindings generator '$BINDGEN' is too old."
+ echo >&2 "*** Your version: $rust_bindings_generator_version"
+ echo >&2 "*** Minimum version: $rust_bindings_generator_min_version"
+ echo >&2 "***"
+ exit 1
+fi
+if [ "$rust_bindings_generator_cversion" -gt "$rust_bindings_generator_min_cversion" ]; then
+ echo >&2 "***"
+ echo >&2 "*** Rust bindings generator '$BINDGEN' is too new. This may or may not work."
+ echo >&2 "*** Your version: $rust_bindings_generator_version"
+ echo >&2 "*** Expected version: $rust_bindings_generator_min_version"
+ echo >&2 "***"
+fi
+
+# Check that the `libclang` used by the Rust bindings generator is suitable.
+#
+# In order to do that, first invoke `bindgen` to get the `libclang` version
+# found by `bindgen`. This step may already fail if, for instance, `libclang`
+# is not found, thus inform the user in such a case.
+bindgen_libclang_output=$( \
+ LC_ALL=C "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang.h 2>&1 >/dev/null
+) || bindgen_libclang_code=$?
+if [ -n "$bindgen_libclang_code" ]; then
+ echo >&2 "***"
+ echo >&2 "*** Running '$BINDGEN' to check the libclang version (used by the Rust"
+ echo >&2 "*** bindings generator) failed with code $bindgen_libclang_code. This may be caused by"
+ echo >&2 "*** a failure to locate libclang. See output and docs below for details:"
+ echo >&2 "***"
+ echo >&2 "$bindgen_libclang_output"
+ echo >&2 "***"
+ exit 1
+fi
+
+# `bindgen` returned successfully, thus use the output to check that the version
+# of the `libclang` found by the Rust bindings generator is suitable.
+bindgen_libclang_version=$( \
+ echo "$bindgen_libclang_output" \
+ | sed -nE 's:.*clang version ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p'
+)
+bindgen_libclang_min_version=$($min_tool_version llvm)
+bindgen_libclang_cversion=$(get_canonical_version $bindgen_libclang_version)
+bindgen_libclang_min_cversion=$(get_canonical_version $bindgen_libclang_min_version)
+if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then
+ echo >&2 "***"
+ echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN') is too old."
+ echo >&2 "*** Your version: $bindgen_libclang_version"
+ echo >&2 "*** Minimum version: $bindgen_libclang_min_version"
+ echo >&2 "***"
+ exit 1
+fi
+
+# If the C compiler is Clang, then we can also check whether its version
+# matches the `libclang` version used by the Rust bindings generator.
+#
+# In the future, we might be able to perform a full version check, see
+# https://github.com/rust-lang/rust-bindgen/issues/2138.
+cc_name=$($(dirname $0)/cc-version.sh $CC | cut -f1 -d' ')
+if [ "$cc_name" = Clang ]; then
+ clang_version=$( \
+ LC_ALL=C $CC --version 2>/dev/null \
+ | sed -nE '1s:.*version ([0-9]+\.[0-9]+\.[0-9]+).*:\1:p'
+ )
+ if [ "$clang_version" != "$bindgen_libclang_version" ]; then
+ echo >&2 "***"
+ echo >&2 "*** libclang (used by the Rust bindings generator '$BINDGEN')"
+ echo >&2 "*** version does not match Clang's. This may be a problem."
+ echo >&2 "*** libclang version: $bindgen_libclang_version"
+ echo >&2 "*** Clang version: $clang_version"
+ echo >&2 "***"
+ fi
+fi
+
+# Check that the source code for the `core` standard library exists.
+#
+# `$KRUSTFLAGS` is passed in case the user added `--sysroot`.
+rustc_sysroot=$("$RUSTC" $KRUSTFLAGS --print sysroot)
+rustc_src=${RUST_LIB_SRC:-"$rustc_sysroot/lib/rustlib/src/rust/library"}
+rustc_src_core="$rustc_src/core/src/lib.rs"
+if [ ! -e "$rustc_src_core" ]; then
+ echo >&2 "***"
+ echo >&2 "*** Source code for the 'core' standard library could not be found"
+ echo >&2 "*** at '$rustc_src_core'."
+ echo >&2 "***"
+ exit 1
+fi
diff --git a/scripts/rust_is_available_bindgen_libclang.h b/scripts/rust_is_available_bindgen_libclang.h
new file mode 100644
index 000000000000..0ef6db10d674
--- /dev/null
+++ b/scripts/rust_is_available_bindgen_libclang.h
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#pragma message("clang version " __clang_version__)
diff --git a/scripts/selinux/genheaders/genheaders.c b/scripts/selinux/genheaders/genheaders.c
index f355b3e0e968..15520806889e 100644
--- a/scripts/selinux/genheaders/genheaders.c
+++ b/scripts/selinux/genheaders/genheaders.c
@@ -59,35 +59,27 @@ int main(int argc, char *argv[])
exit(2);
}
- for (i = 0; secclass_map[i].name; i++) {
- struct security_class_mapping *map = &secclass_map[i];
- map->name = stoupperx(map->name);
- for (j = 0; map->perms[j]; j++)
- map->perms[j] = stoupperx(map->perms[j]);
- }
-
- isids_len = sizeof(initial_sid_to_string) / sizeof (char *);
- for (i = 1; i < isids_len; i++) {
- const char *s = initial_sid_to_string[i];
-
- if (s)
- initial_sid_to_string[i] = stoupperx(s);
- }
-
fprintf(fout, "/* This file is automatically generated. Do not edit. */\n");
fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n");
for (i = 0; secclass_map[i].name; i++) {
- struct security_class_mapping *map = &secclass_map[i];
- fprintf(fout, "#define SECCLASS_%-39s %2d\n", map->name, i+1);
+ char *name = stoupperx(secclass_map[i].name);
+
+ fprintf(fout, "#define SECCLASS_%-39s %2d\n", name, i+1);
+ free(name);
}
fprintf(fout, "\n");
+ isids_len = sizeof(initial_sid_to_string) / sizeof(char *);
for (i = 1; i < isids_len; i++) {
const char *s = initial_sid_to_string[i];
- if (s)
- fprintf(fout, "#define SECINITSID_%-39s %2d\n", s, i);
+ if (s) {
+ char *sidname = stoupperx(s);
+
+ fprintf(fout, "#define SECINITSID_%-39s %2d\n", sidname, i);
+ free(sidname);
+ }
}
fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1);
fprintf(fout, "\nstatic inline bool security_is_socket_class(u16 kern_tclass)\n");
@@ -96,10 +88,14 @@ int main(int argc, char *argv[])
fprintf(fout, "\tswitch (kern_tclass) {\n");
for (i = 0; secclass_map[i].name; i++) {
static char s[] = "SOCKET";
- struct security_class_mapping *map = &secclass_map[i];
- int len = strlen(map->name), l = sizeof(s) - 1;
- if (len >= l && memcmp(map->name + len - l, s, l) == 0)
- fprintf(fout, "\tcase SECCLASS_%s:\n", map->name);
+ int len, l;
+ char *name = stoupperx(secclass_map[i].name);
+
+ len = strlen(name);
+ l = sizeof(s) - 1;
+ if (len >= l && memcmp(name + len - l, s, l) == 0)
+ fprintf(fout, "\tcase SECCLASS_%s:\n", name);
+ free(name);
}
fprintf(fout, "\t\tsock = true;\n");
fprintf(fout, "\t\tbreak;\n");
@@ -110,33 +106,52 @@ int main(int argc, char *argv[])
fprintf(fout, "}\n");
fprintf(fout, "\n#endif\n");
- fclose(fout);
+
+ if (fclose(fout) != 0) {
+ fprintf(stderr, "Could not successfully close %s: %s\n",
+ argv[1], strerror(errno));
+ exit(4);
+ }
fout = fopen(argv[2], "w");
if (!fout) {
fprintf(stderr, "Could not open %s for writing: %s\n",
argv[2], strerror(errno));
- exit(4);
+ exit(5);
}
fprintf(fout, "/* This file is automatically generated. Do not edit. */\n");
fprintf(fout, "#ifndef _SELINUX_AV_PERMISSIONS_H_\n#define _SELINUX_AV_PERMISSIONS_H_\n\n");
for (i = 0; secclass_map[i].name; i++) {
- struct security_class_mapping *map = &secclass_map[i];
- int len = strlen(map->name);
+ const struct security_class_mapping *map = &secclass_map[i];
+ int len;
+ char *name = stoupperx(map->name);
+
+ len = strlen(name);
for (j = 0; map->perms[j]; j++) {
+ char *permname;
+
if (j >= 32) {
fprintf(stderr, "Too many permissions to fit into an access vector at (%s, %s).\n",
map->name, map->perms[j]);
exit(5);
}
- fprintf(fout, "#define %s__%-*s 0x%08xU\n", map->name,
- 39-len, map->perms[j], 1U<<j);
+ permname = stoupperx(map->perms[j]);
+ fprintf(fout, "#define %s__%-*s 0x%08xU\n", name,
+ 39-len, permname, 1U<<j);
+ free(permname);
}
+ free(name);
}
fprintf(fout, "\n#endif\n");
- fclose(fout);
+
+ if (fclose(fout) != 0) {
+ fprintf(stderr, "Could not successfully close %s: %s\n",
+ argv[2], strerror(errno));
+ exit(6);
+ }
+
exit(0);
}
diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh
index 2dccf141241d..24086793b0d8 100755
--- a/scripts/selinux/install_policy.sh
+++ b/scripts/selinux/install_policy.sh
@@ -31,8 +31,7 @@ fi
if selinuxenabled; then
echo "SELinux is already enabled"
echo "This prevents safely relabeling all files."
- echo "Boot with selinux=0 on the kernel command-line or"
- echo "SELINUX=disabled in /etc/selinux/config."
+ echo "Boot with selinux=0 on the kernel command-line."
exit 1
fi
@@ -78,7 +77,7 @@ cd /etc/selinux/dummy/contexts/files
$SF -F file_contexts /
mounts=`cat /proc/$$/mounts | \
- egrep "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
+ grep -E "ext[234]|jfs|xfs|reiserfs|jffs2|gfs2|btrfs|f2fs|ocfs2" | \
awk '{ print $2 '}`
$SF -F file_contexts $mounts
diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
index 105c1c31a316..1415604c3d24 100644
--- a/scripts/selinux/mdp/mdp.c
+++ b/scripts/selinux/mdp/mdp.c
@@ -82,7 +82,7 @@ int main(int argc, char *argv[])
/* print out the class permissions */
for (i = 0; secclass_map[i].name; i++) {
- struct security_class_mapping *map = &secclass_map[i];
+ const struct security_class_mapping *map = &secclass_map[i];
fprintf(fout, "class %s\n", map->name);
fprintf(fout, "{\n");
for (j = 0; map->perms[j]; j++)
@@ -103,7 +103,7 @@ int main(int argc, char *argv[])
#define SYSTEMLOW "s0"
#define SYSTEMHIGH "s1:c0.c1"
for (i = 0; secclass_map[i].name; i++) {
- struct security_class_mapping *map = &secclass_map[i];
+ const struct security_class_mapping *map = &secclass_map[i];
fprintf(fout, "mlsconstrain %s {\n", map->name);
for (j = 0; map->perms[j]; j++)
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index bb709eda96cd..3d3babac8298 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -11,16 +11,17 @@
#
usage() {
- echo "Usage: $0 [--save-scmversion] [srctree]" >&2
+ echo "Usage: $0 [--no-local] [srctree]" >&2
exit 1
}
-scm_only=false
-srctree=.
-if test "$1" = "--save-scmversion"; then
- scm_only=true
+no_local=false
+if test "$1" = "--no-local"; then
+ no_local=true
shift
fi
+
+srctree=.
if test $# -gt 0; then
srctree=$1
shift
@@ -31,107 +32,82 @@ fi
scm_version()
{
- local short
- short=false
+ local short=false
+ local no_dirty=false
+ local tag
+
+ while [ $# -gt 0 ];
+ do
+ case "$1" in
+ --short)
+ short=true;;
+ --no-dirty)
+ no_dirty=true;;
+ esac
+ shift
+ done
cd "$srctree"
- if test -e .scmversion; then
- cat .scmversion
+
+ if test -n "$(git rev-parse --show-cdup 2>/dev/null)"; then
return
fi
- if test "$1" = "--short"; then
- short=true
- fi
-
- # Check for git and a git repo.
- if test -z "$(git rev-parse --show-cdup 2>/dev/null)" &&
- head=$(git rev-parse --verify HEAD 2>/dev/null); then
-
- # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore
- # it, because this version is defined in the top level Makefile.
- if [ -z "$(git describe --exact-match 2>/dev/null)" ]; then
-
- # If only the short version is requested, don't bother
- # running further git commands
- if $short; then
- echo "+"
- return
- fi
- # If we are past a tagged commit (like
- # "v2.6.30-rc5-302-g72357d5"), we pretty print it.
- #
- # Ensure the abbreviated sha1 has exactly 12
- # hex characters, to make the output
- # independent of git version, local
- # core.abbrev settings and/or total number of
- # objects in the current repository - passing
- # --abbrev=12 ensures a minimum of 12, and the
- # awk substr() then picks the 'g' and first 12
- # hex chars.
- if atag="$(git describe --abbrev=12 2>/dev/null)"; then
- echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),substr($(NF),0,13))}'
-
- # If we don't have a tag at all we print -g{commitish},
- # again using exactly 12 hex chars.
- else
- head="$(echo $head | cut -c1-12)"
- printf '%s%s' -g $head
- fi
- fi
- # Is this git on svn?
- if git config --get svn-remote.svn.url >/dev/null; then
- printf -- '-svn%s' "$(git svn find-rev $head)"
- fi
+ if ! head=$(git rev-parse --verify HEAD 2>/dev/null); then
+ return
+ fi
- # Check for uncommitted changes.
- # First, with git-status, but --no-optional-locks is only
- # supported in git >= 2.14, so fall back to git-diff-index if
- # it fails. Note that git-diff-index does not refresh the
- # index, so it may give misleading results. See
- # git-update-index(1), git-diff-index(1), and git-status(1).
- if {
- git --no-optional-locks status -uno --porcelain 2>/dev/null ||
- git diff-index --name-only HEAD
- } | grep -qvE '^(.. )?scripts/package'; then
- printf '%s' -dirty
- fi
+ # If a localversion*' file and the corresponding annotated tag exist,
+ # use it. This is the case in linux-next.
+ tag=${file_localversion#-}
+ tag=$(git describe --exact-match --match=$tag $tag 2>/dev/null)
- # All done with git
- return
+ # Otherwise, default to the annotated tag derived from KERNELVERSION.
+ # mainline kernel: 6.2.0-rc5 -> v6.2-rc5
+ # stable kernel: 6.1.7 -> v6.1.7
+ if [ -z "${tag}" ]; then
+ tag=v$(echo "${KERNELVERSION}" | sed -E 's/^([0-9]+\.[0-9]+)\.0(.*)$/\1\2/')
fi
- # Check for mercurial and a mercurial repo.
- if test -d .hg && hgid=$(hg id 2>/dev/null); then
- # Do we have an tagged version? If so, latesttagdistance == 1
- if [ "$(hg log -r . --template '{latesttagdistance}')" = "1" ]; then
- id=$(hg log -r . --template '{latesttag}')
- printf '%s%s' -hg "$id"
- else
- tag=$(printf '%s' "$hgid" | cut -d' ' -f2)
- if [ -z "$tag" -o "$tag" = tip ]; then
- id=$(printf '%s' "$hgid" | sed 's/[+ ].*//')
- printf '%s%s' -hg "$id"
- fi
+ # If we are at the tagged commit, we ignore it because the version is
+ # well-defined.
+ if [ -z "$(git describe --exact-match --match=$tag 2>/dev/null)" ]; then
+
+ # If only the short version is requested, don't bother
+ # running further git commands
+ if $short; then
+ echo "+"
+ return
+ fi
+ # If we are past the tagged commit, we pretty print it.
+ # (like 6.1.0-14595-g292a089d78d3)
+ if atag="$(git describe --match=$tag 2>/dev/null)"; then
+ echo "$atag" | awk -F- '{printf("-%05d", $(NF-1))}'
fi
- # Are there uncommitted changes?
- # These are represented by + after the changeset id.
- case "$hgid" in
- *+|*+\ *) printf '%s' -dirty ;;
- esac
+ # Add -g and exactly 12 hex chars.
+ printf '%s%s' -g "$(echo $head | cut -c1-12)"
+ fi
- # All done with mercurial
+ if ${no_dirty}; then
return
fi
- # Check for svn and a svn repo.
- if rev=$(LANG= LC_ALL= LC_MESSAGES=C svn info 2>/dev/null | grep '^Last Changed Rev'); then
- rev=$(echo $rev | awk '{print $NF}')
- printf -- '-svn%s' "$rev"
-
- # All done with svn
- return
+ # Check for uncommitted changes.
+ # This script must avoid any write attempt to the source tree, which
+ # might be read-only.
+ # You cannot use 'git describe --dirty' because it tries to create
+ # .git/index.lock .
+ # First, with git-status, but --no-optional-locks is only supported in
+ # git >= 2.14, so fall back to git-diff-index if it fails. Note that
+ # git-diff-index does not refresh the index, so it may give misleading
+ # results.
+ # See git-update-index(1), git-diff-index(1), and git-status(1).
+ if {
+ git --no-optional-locks status -uno --porcelain 2>/dev/null ||
+ git diff-index --name-only HEAD
+ } | read dummy; then
+ printf '%s' -dirty
fi
}
@@ -152,43 +128,43 @@ collect_files()
echo "$res"
}
-if $scm_only; then
- if test ! -e .scmversion; then
- res=$(scm_version)
- echo "$res" >.scmversion
- fi
- exit
-fi
-
-if test -e include/config/auto.conf; then
- . include/config/auto.conf
-else
- echo "Error: kernelrelease not valid - run 'make prepare' to update it" >&2
+if [ -z "${KERNELVERSION}" ]; then
+ echo "KERNELVERSION is not set" >&2
exit 1
fi
# localversion* files in the build and source directory
-res="$(collect_files localversion*)"
+file_localversion="$(collect_files localversion*)"
if test ! "$srctree" -ef .; then
- res="$res$(collect_files "$srctree"/localversion*)"
+ file_localversion="${file_localversion}$(collect_files "$srctree"/localversion*)"
fi
-# CONFIG_LOCALVERSION and LOCALVERSION (if set)
-res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"
+if ${no_local}; then
+ echo "${KERNELVERSION}$(scm_version --no-dirty)"
+ exit 0
+fi
-# scm version string if not at a tagged commit
-if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then
+if ! test -e include/config/auto.conf; then
+ echo "Error: kernelrelease not valid - run 'make prepare' to update it" >&2
+ exit 1
+fi
+
+# version string from CONFIG_LOCALVERSION
+config_localversion=$(sed -n 's/^CONFIG_LOCALVERSION=\(.*\)$/\1/p' include/config/auto.conf)
+
+# scm version string if not at the kernel version tag or at the file_localversion
+if grep -q "^CONFIG_LOCALVERSION_AUTO=y$" include/config/auto.conf; then
# full scm version string
- res="$res$(scm_version)"
-else
- # append a plus sign if the repository is not in a clean
- # annotated or signed tagged state (as git describe only
- # looks at signed or annotated tags - git tag -a/-s) and
- # LOCALVERSION= is not specified
- if test "${LOCALVERSION+set}" != "set"; then
- scm=$(scm_version --short)
- res="$res${scm:++}"
- fi
+ scm_version="$(scm_version)"
+elif [ "${LOCALVERSION+set}" != "set" ]; then
+ # If the variable LOCALVERSION is not set, append a plus
+ # sign if the repository is not in a clean annotated or
+ # signed tagged state (as git describe only looks at signed
+ # or annotated tags - git tag -a/-s).
+ #
+ # If the variable LOCALVERSION is set (including being set
+ # to an empty string), we don't want to append a plus sign.
+ scm_version="$(scm_version --short)"
fi
-echo "$res"
+echo "${KERNELVERSION}${file_localversion}${config_localversion}${LOCALVERSION}${scm_version}"
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index fbd34b8e8f57..598ef5465f82 100644
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -30,6 +30,13 @@
#include <openssl/engine.h>
/*
+ * OpenSSL 3.0 deprecates the OpenSSL's ENGINE API.
+ *
+ * Remove this if/when that API is no longer used
+ */
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+/*
* Use CMS if we have openssl-1.0.0 or newer available - otherwise we have to
* assume that it's not available and its header file is missing and that we
* should use PKCS#7 instead. Switching to the older PKCS#7 format restricts
@@ -107,7 +114,7 @@ static void drain_openssl_errors(void)
bool __cond = (cond); \
display_openssl_errors(__LINE__); \
if (__cond) { \
- err(1, fmt, ## __VA_ARGS__); \
+ errx(1, fmt, ## __VA_ARGS__); \
} \
} while(0)
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 0ef3abfc4a51..83cdb843d92f 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -30,6 +30,8 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
#include <tools/be_byteshift.h>
#include <tools/le_byteshift.h>
@@ -54,6 +56,14 @@
#define EM_ARCV2 195
#endif
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
+
+#ifndef EM_LOONGARCH
+#define EM_LOONGARCH 258
+#endif
+
static uint32_t (*r)(const uint32_t *);
static uint16_t (*r2)(const uint16_t *);
static uint64_t (*r8)(const uint64_t *);
@@ -227,7 +237,7 @@ static void sort_relative_table(char *extab_image, int image_size)
}
}
-static void x86_sort_relative_table(char *extab_image, int image_size)
+static void sort_relative_table_with_data(char *extab_image, int image_size)
{
int i = 0;
@@ -236,7 +246,7 @@ static void x86_sort_relative_table(char *extab_image, int image_size)
w(r(loc) + i, loc);
w(r(loc + 1) + i + 4, loc + 1);
- w(r(loc + 2) + i + 8, loc + 2);
+ /* Don't touch the fixup type or data */
i += sizeof(uint32_t) * 3;
}
@@ -249,51 +259,12 @@ static void x86_sort_relative_table(char *extab_image, int image_size)
w(r(loc) - i, loc);
w(r(loc + 1) - (i + 4), loc + 1);
- w(r(loc + 2) - (i + 8), loc + 2);
+ /* Don't touch the fixup type or data */
i += sizeof(uint32_t) * 3;
}
}
-static void s390_sort_relative_table(char *extab_image, int image_size)
-{
- int i;
-
- for (i = 0; i < image_size; i += 16) {
- char *loc = extab_image + i;
- uint64_t handler;
-
- w(r((uint32_t *)loc) + i, (uint32_t *)loc);
- w(r((uint32_t *)(loc + 4)) + (i + 4), (uint32_t *)(loc + 4));
- /*
- * 0 is a special self-relative handler value, which means that
- * handler should be ignored. It is safe, because it means that
- * handler field points to itself, which should never happen.
- * When creating extable-relative values, keep it as 0, since
- * this should never occur either: it would mean that handler
- * field points to the first extable entry.
- */
- handler = r8((uint64_t *)(loc + 8));
- if (handler)
- handler += i + 8;
- w8(handler, (uint64_t *)(loc + 8));
- }
-
- qsort(extab_image, image_size / 16, 16, compare_relative_table);
-
- for (i = 0; i < image_size; i += 16) {
- char *loc = extab_image + i;
- uint64_t handler;
-
- w(r((uint32_t *)loc) - i, (uint32_t *)loc);
- w(r((uint32_t *)(loc + 4)) - (i + 4), (uint32_t *)(loc + 4));
- handler = r8((uint64_t *)(loc + 8));
- if (handler)
- handler -= i + 8;
- w8(handler, (uint64_t *)(loc + 8));
- }
-}
-
static int do_file(char const *const fname, void *addr)
{
int rc = -1;
@@ -332,13 +303,13 @@ static int do_file(char const *const fname, void *addr)
switch (r2(&ehdr->e_machine)) {
case EM_386:
- case EM_X86_64:
- custom_sort = x86_sort_relative_table;
- break;
+ case EM_AARCH64:
+ case EM_LOONGARCH:
+ case EM_RISCV:
case EM_S390:
- custom_sort = s390_sort_relative_table;
+ case EM_X86_64:
+ custom_sort = sort_relative_table_with_data;
break;
- case EM_AARCH64:
case EM_PARISC:
case EM_PPC:
case EM_PPC64:
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index a2baa2fefb13..7bd0184380d3 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -19,6 +19,9 @@
#undef extable_ent_size
#undef compare_extable
+#undef get_mcount_loc
+#undef sort_mcount_loc
+#undef elf_mcount_loc
#undef do_sort
#undef Elf_Addr
#undef Elf_Ehdr
@@ -41,6 +44,9 @@
#ifdef SORTTABLE_64
# define extable_ent_size 16
# define compare_extable compare_extable_64
+# define get_mcount_loc get_mcount_loc_64
+# define sort_mcount_loc sort_mcount_loc_64
+# define elf_mcount_loc elf_mcount_loc_64
# define do_sort do_sort_64
# define Elf_Addr Elf64_Addr
# define Elf_Ehdr Elf64_Ehdr
@@ -62,6 +68,9 @@
#else
# define extable_ent_size 8
# define compare_extable compare_extable_32
+# define get_mcount_loc get_mcount_loc_32
+# define sort_mcount_loc sort_mcount_loc_32
+# define elf_mcount_loc elf_mcount_loc_32
# define do_sort do_sort_32
# define Elf_Addr Elf32_Addr
# define Elf_Ehdr Elf32_Ehdr
@@ -84,8 +93,6 @@
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
/* ORC unwinder only support X86_64 */
-#include <errno.h>
-#include <pthread.h>
#include <asm/orc_types.h>
#define ERRSTR_MAXSZ 256
@@ -121,7 +128,7 @@ static int orc_sort_cmp(const void *_a, const void *_b)
* whitelisted .o files which didn't get objtool generation.
*/
orc_a = g_orc_table + (a - g_orc_ip_table);
- return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1;
+ return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1;
}
static void *sort_orctable(void *arg)
@@ -191,7 +198,66 @@ static int compare_extable(const void *a, const void *b)
return 1;
return 0;
}
+#ifdef MCOUNT_SORT_ENABLED
+pthread_t mcount_sort_thread;
+
+struct elf_mcount_loc {
+ Elf_Ehdr *ehdr;
+ Elf_Shdr *init_data_sec;
+ uint_t start_mcount_loc;
+ uint_t stop_mcount_loc;
+};
+
+/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
+static void *sort_mcount_loc(void *arg)
+{
+ struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
+ uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->sh_addr)
+ + _r(&(emloc->init_data_sec)->sh_offset);
+ uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
+ unsigned char *start_loc = (void *)emloc->ehdr + offset;
+
+ qsort(start_loc, count/sizeof(uint_t), sizeof(uint_t), compare_extable);
+ return NULL;
+}
+
+/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
+static void get_mcount_loc(uint_t *_start, uint_t *_stop)
+{
+ FILE *file_start, *file_stop;
+ char start_buff[20];
+ char stop_buff[20];
+ int len = 0;
+
+ file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r");
+ if (!file_start) {
+ fprintf(stderr, "get start_mcount_loc error!");
+ return;
+ }
+
+ file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r");
+ if (!file_stop) {
+ fprintf(stderr, "get stop_mcount_loc error!");
+ pclose(file_start);
+ return;
+ }
+
+ while (fgets(start_buff, sizeof(start_buff), file_start) != NULL) {
+ len = strlen(start_buff);
+ start_buff[len - 1] = '\0';
+ }
+ *_start = strtoul(start_buff, NULL, 16);
+
+ while (fgets(stop_buff, sizeof(stop_buff), file_stop) != NULL) {
+ len = strlen(stop_buff);
+ stop_buff[len - 1] = '\0';
+ }
+ *_stop = strtoul(stop_buff, NULL, 16);
+ pclose(file_start);
+ pclose(file_stop);
+}
+#endif
static int do_sort(Elf_Ehdr *ehdr,
char const *const fname,
table_sort_t custom_sort)
@@ -217,6 +283,11 @@ static int do_sort(Elf_Ehdr *ehdr,
int idx;
unsigned int shnum;
unsigned int shstrndx;
+#ifdef MCOUNT_SORT_ENABLED
+ struct elf_mcount_loc mstruct = {0};
+ uint_t _start_mcount_loc = 0;
+ uint_t _stop_mcount_loc = 0;
+#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
unsigned int orc_ip_size = 0;
unsigned int orc_size = 0;
@@ -253,6 +324,17 @@ static int do_sort(Elf_Ehdr *ehdr,
symtab_shndx = (Elf32_Word *)((const char *)ehdr +
_r(&s->sh_offset));
+#ifdef MCOUNT_SORT_ENABLED
+ /* locate the .init.data section in vmlinux */
+ if (!strcmp(secstrings + idx, ".init.data")) {
+ get_mcount_loc(&_start_mcount_loc, &_stop_mcount_loc);
+ mstruct.ehdr = ehdr;
+ mstruct.init_data_sec = s;
+ mstruct.start_mcount_loc = _start_mcount_loc;
+ mstruct.stop_mcount_loc = _stop_mcount_loc;
+ }
+#endif
+
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
/* locate the ORC unwind tables */
if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
@@ -294,6 +376,23 @@ static int do_sort(Elf_Ehdr *ehdr,
goto out;
}
#endif
+
+#ifdef MCOUNT_SORT_ENABLED
+ if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) {
+ fprintf(stderr,
+ "incomplete mcount's sort in file: %s\n",
+ fname);
+ goto out;
+ }
+
+ /* create thread to sort mcount_loc concurrently */
+ if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) {
+ fprintf(stderr,
+ "pthread_create mcount_sort_thread failed '%s': %s\n",
+ strerror(errno), fname);
+ goto out;
+ }
+#endif
if (!extab_sec) {
fprintf(stderr, "no __ex_table in file: %s\n", fname);
goto out;
@@ -364,11 +463,11 @@ out:
void *retval = NULL;
/* wait for ORC tables sort done */
rc = pthread_join(orc_sort_thread, &retval);
- if (rc)
+ if (rc) {
fprintf(stderr,
"pthread_join failed '%s': %s\n",
strerror(errno), fname);
- else if (retval) {
+ } else if (retval) {
rc = -1;
fprintf(stderr,
"failed to sort ORC tables '%s': %s\n",
@@ -376,5 +475,23 @@ out:
}
}
#endif
+
+#ifdef MCOUNT_SORT_ENABLED
+ if (mcount_sort_thread) {
+ void *retval = NULL;
+ /* wait for mcount sort done */
+ rc = pthread_join(mcount_sort_thread, &retval);
+ if (rc) {
+ fprintf(stderr,
+ "pthread_join failed '%s': %s\n",
+ strerror(errno), fname);
+ } else if (retval) {
+ rc = -1;
+ fprintf(stderr,
+ "failed to sort mcount '%s': %s\n",
+ (char *)retval, fname);
+ }
+ }
+#endif
return rc;
}
diff --git a/scripts/spdxcheck-test.sh b/scripts/spdxcheck-test.sh
index cfea6a0d1cc0..9f6d1a74da6e 100644
--- a/scripts/spdxcheck-test.sh
+++ b/scripts/spdxcheck-test.sh
@@ -1,12 +1,10 @@
#!/bin/sh
-for PYTHON in python2 python3; do
- # run check on a text and a binary file
- for FILE in Makefile Documentation/logo.gif; do
- $PYTHON scripts/spdxcheck.py $FILE
- $PYTHON scripts/spdxcheck.py - < $FILE
- done
-
- # run check on complete tree to catch any other issues
- $PYTHON scripts/spdxcheck.py > /dev/null
+# run check on a text and a binary file
+for FILE in Makefile Documentation/images/logo.gif; do
+ python3 scripts/spdxcheck.py $FILE
+ python3 scripts/spdxcheck.py - < $FILE
done
+
+# run check on complete tree to catch any other issues
+python3 scripts/spdxcheck.py > /dev/null
diff --git a/scripts/spdxcheck.py b/scripts/spdxcheck.py
index cbdb5c83c08f..92a65317f972 100755
--- a/scripts/spdxcheck.py
+++ b/scripts/spdxcheck.py
@@ -6,6 +6,7 @@ from argparse import ArgumentParser
from ply import lex, yacc
import locale
import traceback
+import fnmatch
import sys
import git
import re
@@ -28,6 +29,21 @@ class SPDXdata(object):
self.licenses = [ ]
self.exceptions = { }
+class dirinfo(object):
+ def __init__(self):
+ self.missing = 0
+ self.total = 0
+ self.files = []
+
+ def update(self, fname, basedir, miss):
+ self.total += 1
+ self.missing += miss
+ if miss:
+ fname = './' + fname
+ bdir = os.path.dirname(fname)
+ if bdir == basedir.rstrip('/'):
+ self.files.append(fname)
+
# Read the spdx data from the LICENSES directory
def read_spdxdata(repo):
@@ -44,7 +60,7 @@ def read_spdxdata(repo):
continue
exception = None
- for l in open(el.path).readlines():
+ for l in open(el.path, encoding="utf-8").readlines():
if l.startswith('Valid-License-Identifier:'):
lid = l.split(':')[1].strip().upper()
if lid in spdx.licenses:
@@ -91,11 +107,25 @@ class id_parser(object):
self.parser = yacc.yacc(module = self, write_tables = False, debug = False)
self.lines_checked = 0
self.checked = 0
+ self.excluded = 0
self.spdx_valid = 0
self.spdx_errors = 0
+ self.spdx_dirs = {}
+ self.dirdepth = -1
+ self.basedir = '.'
self.curline = 0
self.deepest = 0
+ def set_dirinfo(self, basedir, dirdepth):
+ if dirdepth >= 0:
+ self.basedir = basedir
+ bdir = basedir.lstrip('./').rstrip('/')
+ if bdir != '':
+ parts = bdir.split('/')
+ else:
+ parts = []
+ self.dirdepth = dirdepth + len(parts)
+
# Validate License and Exception IDs
def validate(self, tok):
id = tok.value.upper()
@@ -167,9 +197,9 @@ class id_parser(object):
def parse_lines(self, fd, maxlines, fname):
self.checked += 1
self.curline = 0
+ fail = 1
try:
for line in fd:
- line = line.decode(locale.getpreferredencoding(False), errors='ignore')
self.curline += 1
if self.curline > maxlines:
break
@@ -192,6 +222,7 @@ class id_parser(object):
# Should we check for more SPDX ids in the same file and
# complain if there are any?
#
+ fail = 0
break
except ParserException as pe:
@@ -200,31 +231,105 @@ class id_parser(object):
tok = pe.tok.value
sys.stdout.write('%s: %d:%d %s: %s\n' %(fname, self.curline, col, pe.txt, tok))
else:
- sys.stdout.write('%s: %d:0 %s\n' %(fname, self.curline, col, pe.txt))
+ sys.stdout.write('%s: %d:0 %s\n' %(fname, self.curline, pe.txt))
self.spdx_errors += 1
-def scan_git_tree(tree):
+ if fname == '-':
+ return
+
+ base = os.path.dirname(fname)
+ if self.dirdepth > 0:
+ parts = base.split('/')
+ i = 0
+ base = '.'
+ while i < self.dirdepth and i < len(parts) and len(parts[i]):
+ base += '/' + parts[i]
+ i += 1
+ elif self.dirdepth == 0:
+ base = self.basedir
+ else:
+ base = './' + base.rstrip('/')
+ base += '/'
+
+ di = self.spdx_dirs.get(base, dirinfo())
+ di.update(fname, base, fail)
+ self.spdx_dirs[base] = di
+
+class pattern(object):
+ def __init__(self, line):
+ self.pattern = line
+ self.match = self.match_file
+ if line == '.*':
+ self.match = self.match_dot
+ elif line.endswith('/'):
+ self.pattern = line[:-1]
+ self.match = self.match_dir
+ elif line.startswith('/'):
+ self.pattern = line[1:]
+ self.match = self.match_fn
+
+ def match_dot(self, fpath):
+ return os.path.basename(fpath).startswith('.')
+
+ def match_file(self, fpath):
+ return os.path.basename(fpath) == self.pattern
+
+ def match_fn(self, fpath):
+ return fnmatch.fnmatchcase(fpath, self.pattern)
+
+ def match_dir(self, fpath):
+ if self.match_fn(os.path.dirname(fpath)):
+ return True
+ return fpath.startswith(self.pattern)
+
+def exclude_file(fpath):
+ for rule in exclude_rules:
+ if rule.match(fpath):
+ return True
+ return False
+
+def scan_git_tree(tree, basedir, dirdepth):
+ parser.set_dirinfo(basedir, dirdepth)
for el in tree.traverse():
- # Exclude stuff which would make pointless noise
- # FIXME: Put this somewhere more sensible
- if el.path.startswith("LICENSES"):
- continue
- if el.path.find("license-rules.rst") >= 0:
- continue
if not os.path.isfile(el.path):
continue
+ if exclude_file(el.path):
+ parser.excluded += 1
+ continue
with open(el.path, 'rb') as fd:
parser.parse_lines(fd, args.maxlines, el.path)
-def scan_git_subtree(tree, path):
+def scan_git_subtree(tree, path, dirdepth):
for p in path.strip('/').split('/'):
tree = tree[p]
- scan_git_tree(tree)
+ scan_git_tree(tree, path.strip('/'), dirdepth)
+
+def read_exclude_file(fname):
+ rules = []
+ if not fname:
+ return rules
+ with open(fname) as fd:
+ for line in fd:
+ line = line.strip()
+ if line.startswith('#'):
+ continue
+ if not len(line):
+ continue
+ rules.append(pattern(line))
+ return rules
if __name__ == '__main__':
ap = ArgumentParser(description='SPDX expression checker')
ap.add_argument('path', nargs='*', help='Check path or file. If not given full git tree scan. For stdin use "-"')
+ ap.add_argument('-d', '--dirs', action='store_true',
+ help='Show [sub]directory statistics.')
+ ap.add_argument('-D', '--depth', type=int, default=-1,
+ help='Directory depth for -d statistics. Default: unlimited')
+ ap.add_argument('-e', '--exclude',
+ help='File containing file patterns to exclude. Default: scripts/spdxexclude')
+ ap.add_argument('-f', '--files', action='store_true',
+ help='Show files without SPDX.')
ap.add_argument('-m', '--maxlines', type=int, default=15,
help='Maximum number of lines to scan in a file. Default 15')
ap.add_argument('-v', '--verbose', action='store_true', help='Verbose statistics output')
@@ -243,7 +348,7 @@ if __name__ == '__main__':
# Initialize SPDX data
spdx = read_spdxdata(repo)
- # Initilize the parser
+ # Initialize the parser
parser = id_parser(spdx)
except SPDXException as se:
@@ -259,6 +364,15 @@ if __name__ == '__main__':
sys.exit(1)
try:
+ fname = args.exclude
+ if not fname:
+ fname = os.path.join(os.path.dirname(__file__), 'spdxexclude')
+ exclude_rules = read_exclude_file(fname)
+ except Exception as ex:
+ sys.stderr.write('FAIL: Reading exclude file %s: %s\n' %(fname, ex))
+ sys.exit(1)
+
+ try:
if len(args.path) and args.path[0] == '-':
stdin = os.fdopen(sys.stdin.fileno(), 'rb')
parser.parse_lines(stdin, args.maxlines, '-')
@@ -268,13 +382,21 @@ if __name__ == '__main__':
if os.path.isfile(p):
parser.parse_lines(open(p, 'rb'), args.maxlines, p)
elif os.path.isdir(p):
- scan_git_subtree(repo.head.reference.commit.tree, p)
+ scan_git_subtree(repo.head.reference.commit.tree, p,
+ args.depth)
else:
sys.stderr.write('path %s does not exist\n' %p)
sys.exit(1)
else:
# Full git tree scan
- scan_git_tree(repo.head.commit.tree)
+ scan_git_tree(repo.head.commit.tree, '.', args.depth)
+
+ ndirs = len(parser.spdx_dirs)
+ dirsok = 0
+ if ndirs:
+ for di in parser.spdx_dirs.values():
+ if not di.missing:
+ dirsok += 1
if args.verbose:
sys.stderr.write('\n')
@@ -283,10 +405,38 @@ if __name__ == '__main__':
sys.stderr.write('License IDs %12d\n' %len(spdx.licenses))
sys.stderr.write('Exception IDs %12d\n' %len(spdx.exceptions))
sys.stderr.write('\n')
+ sys.stderr.write('Files excluded: %12d\n' %parser.excluded)
sys.stderr.write('Files checked: %12d\n' %parser.checked)
sys.stderr.write('Lines checked: %12d\n' %parser.lines_checked)
- sys.stderr.write('Files with SPDX: %12d\n' %parser.spdx_valid)
+ if parser.checked:
+ pc = int(100 * parser.spdx_valid / parser.checked)
+ sys.stderr.write('Files with SPDX: %12d %3d%%\n' %(parser.spdx_valid, pc))
sys.stderr.write('Files with errors: %12d\n' %parser.spdx_errors)
+ if ndirs:
+ sys.stderr.write('\n')
+ sys.stderr.write('Directories accounted: %8d\n' %ndirs)
+ pc = int(100 * dirsok / ndirs)
+ sys.stderr.write('Directories complete: %8d %3d%%\n' %(dirsok, pc))
+
+ if ndirs and ndirs != dirsok and args.dirs:
+ if args.verbose:
+ sys.stderr.write('\n')
+ sys.stderr.write('Incomplete directories: SPDX in Files\n')
+ for f in sorted(parser.spdx_dirs.keys()):
+ di = parser.spdx_dirs[f]
+ if di.missing:
+ valid = di.total - di.missing
+ pc = int(100 * valid / di.total)
+ sys.stderr.write(' %-80s: %5d of %5d %3d%%\n' %(f, valid, di.total, pc))
+
+ if ndirs and ndirs != dirsok and args.files:
+ if args.verbose or args.dirs:
+ sys.stderr.write('\n')
+ sys.stderr.write('Files without SPDX:\n')
+ for f in sorted(parser.spdx_dirs.keys()):
+ di = parser.spdx_dirs[f]
+ for f in sorted(di.files):
+ sys.stderr.write(' %s\n' %f)
sys.exit(0)
diff --git a/scripts/spdxexclude b/scripts/spdxexclude
new file mode 100644
index 000000000000..81bdb13ed789
--- /dev/null
+++ b/scripts/spdxexclude
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Patterns for excluding files and directories
+
+# Ignore the license directory and the licensing documentation which would
+# create lots of noise for no value
+LICENSES/
+license-rules.rst
+
+# Ignore config files and snippets. The majority is generated
+# by the Kconfig tools
+kernel/configs/
+arch/*/configs/
+
+# Other files without copyrightable content
+/CREDITS
+/MAINTAINERS
+/README
diff --git a/scripts/spelling.txt b/scripts/spelling.txt
index 2e3ba91a5072..855c4863124b 100644
--- a/scripts/spelling.txt
+++ b/scripts/spelling.txt
@@ -22,6 +22,8 @@ absolut||absolute
absoulte||absolute
acccess||access
acceess||access
+accelaration||acceleration
+accelearion||acceleration
acceleratoin||acceleration
accelleration||acceleration
accesing||accessing
@@ -57,11 +59,13 @@ acording||according
activete||activate
actived||activated
actualy||actually
+actvie||active
acumulating||accumulating
acumulative||accumulative
acumulator||accumulator
acutally||actually
adapater||adapter
+adderted||asserted
addional||additional
additionaly||additionally
additonal||additional
@@ -84,6 +88,7 @@ againt||against
agaist||against
aggreataon||aggregation
aggreation||aggregation
+ajust||adjust
albumns||albums
alegorical||allegorical
algined||aligned
@@ -118,6 +123,7 @@ alue||value
ambigious||ambiguous
ambigous||ambiguous
amoung||among
+amount of times||number of times
amout||amount
amplifer||amplifier
amplifyer||amplifier
@@ -149,6 +155,7 @@ aquired||acquired
aquisition||acquisition
arbitary||arbitrary
architechture||architecture
+archtecture||architecture
arguement||argument
arguements||arguments
arithmatic||arithmetic
@@ -161,10 +168,13 @@ asign||assign
asser||assert
assertation||assertion
assertting||asserting
+assgined||assigned
assiged||assigned
assigment||assignment
assigments||assignments
assistent||assistant
+assocaited||associated
+assocating||associating
assocation||association
associcated||associated
assotiated||associated
@@ -173,13 +183,17 @@ assum||assume
assumtpion||assumption
asuming||assuming
asycronous||asynchronous
+asychronous||asynchronous
asynchnous||asynchronous
+asynchronus||asynchronous
asynchromous||asynchronous
asymetric||asymmetric
asymmeric||asymmetric
+atleast||at least
atomatically||automatically
atomicly||atomically
atempt||attempt
+atrributes||attributes
attachement||attachment
attatch||attach
attched||attached
@@ -223,6 +237,7 @@ baloons||balloons
bandwith||bandwidth
banlance||balance
batery||battery
+battey||battery
beacuse||because
becasue||because
becomming||becoming
@@ -234,6 +249,7 @@ beter||better
betweeen||between
bianries||binaries
bitmast||bitmask
+bitwiedh||bitwidth
boardcast||broadcast
borad||board
boundry||boundary
@@ -242,6 +258,7 @@ brigde||bridge
broadcase||broadcast
broadcat||broadcast
bufer||buffer
+bufferred||buffered
bufufer||buffer
cacluated||calculated
caculate||calculate
@@ -258,6 +275,12 @@ calucate||calculate
calulate||calculate
cancelation||cancellation
cancle||cancel
+cant||can't
+cant'||can't
+canot||cannot
+cann't||can't
+cannnot||cannot
+capabiity||capability
capabilites||capabilities
capabilties||capabilities
capabilty||capability
@@ -268,6 +291,7 @@ capapbilities||capabilities
caputure||capture
carefuly||carefully
cariage||carriage
+casued||caused
catagory||category
cehck||check
challange||challenge
@@ -294,6 +318,7 @@ chiled||child
chked||checked
chnage||change
chnages||changes
+chnange||change
chnnel||channel
choosen||chosen
chouse||chose
@@ -315,10 +340,12 @@ comminucation||communication
commited||committed
commiting||committing
committ||commit
+commnunication||communication
commoditiy||commodity
comsume||consume
comsumer||consumer
comsuming||consuming
+comaptible||compatible
compability||compatibility
compaibility||compatibility
comparsion||comparison
@@ -339,16 +366,20 @@ compoment||component
comppatible||compatible
compres||compress
compresion||compression
+compresser||compressor
comression||compression
+comsumed||consumed
comunicate||communicate
comunication||communication
conbination||combination
conditionaly||conditionally
conditon||condition
condtion||condition
+condtional||conditional
conected||connected
conector||connector
configration||configuration
+configred||configured
configuartion||configuration
configuation||configuration
configued||configured
@@ -397,11 +428,14 @@ cotrol||control
cound||could
couter||counter
coutner||counter
+creationg||creating
cryptocraphic||cryptographic
+cummulative||cumulative
cunter||counter
curently||currently
cylic||cyclic
dafault||default
+deactive||deactivate
deafult||default
deamon||daemon
debouce||debounce
@@ -417,6 +451,8 @@ deffered||deferred
defferred||deferred
definate||definite
definately||definitely
+definiation||definition
+definiton||definition
defintion||definition
defintions||definitions
defualt||default
@@ -430,6 +466,7 @@ delare||declare
delares||declares
delaring||declaring
delemiter||delimiter
+delibrately||deliberately
delievered||delivered
demodualtor||demodulator
demension||dimension
@@ -458,7 +495,9 @@ destorys||destroys
destroied||destroyed
detabase||database
deteced||detected
+detecion||detection
detectt||detect
+detroyed||destroyed
develope||develop
developement||development
developped||developed
@@ -470,6 +509,7 @@ devided||divided
deviece||device
devision||division
diable||disable
+diabled||disabled
dicline||decline
dictionnary||dictionary
didnt||didn't
@@ -477,14 +517,20 @@ diferent||different
differrence||difference
diffrent||different
differenciate||differentiate
+diffreential||differential
diffrentiate||differentiate
difinition||definition
digial||digital
dimention||dimension
dimesions||dimensions
diconnected||disconnected
+disabed||disabled
+disasembler||disassembler
+disble||disable
disgest||digest
+disired||desired
dispalying||displaying
+dissable||disable
diplay||display
directon||direction
direcly||directly
@@ -508,6 +554,7 @@ dissconect||disconnect
distiction||distinction
divisable||divisible
divsiors||divisors
+dsiabled||disabled
docuentation||documentation
documantation||documentation
documentaion||documentation
@@ -571,13 +618,16 @@ errror||error
estbalishment||establishment
etsablishment||establishment
etsbalishment||establishment
+evalute||evaluate
+evalutes||evaluates
evalution||evaluation
-exeeds||exceeds
excecutable||executable
+excceed||exceed
exceded||exceeded
exceds||exceeds
exceeed||exceed
excellant||excellent
+exchnage||exchange
execeeded||exceeded
execeeds||exceeds
exeed||exceed
@@ -586,8 +636,11 @@ exeuction||execution
existance||existence
existant||existent
exixt||exist
+exsits||exists
exlcude||exclude
+exlcuding||excluding
exlcusive||exclusive
+exlusive||exclusive
exmaple||example
expecially||especially
experies||expires
@@ -625,17 +678,20 @@ feauture||feature
feautures||features
fetaure||feature
fetaures||features
+fetcing||fetching
fileystem||filesystem
fimrware||firmware
fimware||firmware
firmare||firmware
firmaware||firmware
+firtly||firstly
firware||firmware
firwmare||firmware
finanize||finalize
findn||find
finilizes||finalizes
finsih||finish
+fliter||filter
flusing||flushing
folloing||following
followign||following
@@ -653,6 +709,7 @@ frequence||frequency
frequncy||frequency
frequancy||frequency
frome||from
+fronend||frontend
fucntion||function
fuction||function
fuctions||functions
@@ -676,6 +733,8 @@ generiously||generously
genereate||generate
genereted||generated
genric||generic
+gerenal||general
+geting||getting
globel||global
grabing||grabbing
grahical||graphical
@@ -694,9 +753,12 @@ hanled||handled
happend||happened
hardare||hardware
harware||hardware
+hardward||hardware
havind||having
heirarchically||hierarchically
+heirarchy||hierarchy
helpfull||helpful
+hearbeat||heartbeat
heterogenous||heterogeneous
hexdecimal||hexadecimal
hybernate||hibernate
@@ -707,6 +769,7 @@ howver||however
hsould||should
hypervior||hypervisor
hypter||hyper
+idel||idle
identidier||identifier
iligal||illegal
illigal||illegal
@@ -735,6 +798,7 @@ implmentation||implementation
implmenting||implementing
incative||inactive
incomming||incoming
+incompaitiblity||incompatibility
incompatabilities||incompatibilities
incompatable||incompatible
incompatble||incompatible
@@ -792,10 +856,12 @@ integrety||integrity
integrey||integrity
intendet||intended
intented||intended
+interal||internal
interanl||internal
interchangable||interchangeable
interferring||interfering
interger||integer
+intergrated||integrated
intermittant||intermittent
internel||internal
interoprability||interoperability
@@ -808,6 +874,7 @@ interrup||interrupt
interrups||interrupts
interruptted||interrupted
interupted||interrupted
+intiailized||initialized
intial||initial
intialisation||initialisation
intialised||initialised
@@ -841,6 +908,7 @@ iteraions||iterations
iternations||iterations
itertation||iteration
itslef||itself
+ivalid||invalid
jave||java
jeffies||jiffies
jumpimng||jumping
@@ -895,9 +963,11 @@ matchs||matches
mathimatical||mathematical
mathimatic||mathematic
mathimatics||mathematics
+maxmium||maximum
maximium||maximum
maxium||maximum
mechamism||mechanism
+mechanim||mechanism
meetign||meeting
memeory||memory
memmber||member
@@ -906,6 +976,7 @@ memroy||memory
ment||meant
mergable||mergeable
mesage||message
+mesages||messages
messags||messages
messgaes||messages
messsage||message
@@ -914,9 +985,12 @@ metdata||metadata
micropone||microphone
microprocesspr||microprocessor
migrateable||migratable
+millenium||millennium
milliseonds||milliseconds
+minimim||minimum
minium||minimum
minimam||minimum
+minimun||minimum
miniumum||minimum
minumum||minimum
misalinged||misaligned
@@ -935,6 +1009,7 @@ mmnemonic||mnemonic
mnay||many
modfiy||modify
modifer||modifier
+modul||module
modulues||modules
momery||memory
memomry||memory
@@ -944,8 +1019,9 @@ monochromo||monochrome
monocrome||monochrome
mopdule||module
mroe||more
-multipler||multiplier
mulitplied||multiplied
+muliple||multiple
+multipler||multiplier
multidimensionnal||multidimensional
multipe||multiple
multple||multiple
@@ -968,14 +1044,18 @@ negotation||negotiation
nerver||never
nescessary||necessary
nessessary||necessary
+none existent||non-existent
noticable||noticeable
notication||notification
notications||notifications
notifcations||notifications
notifed||notified
notity||notify
+nubmer||number
numebr||number
+numer||number
numner||number
+nunber||number
obtaion||obtain
obusing||abusing
occassionally||occasionally
@@ -987,20 +1067,25 @@ occured||occurred
occurence||occurrence
occure||occurred
occuring||occurring
+ocurrence||occurrence
offser||offset
offet||offset
offlaod||offload
offloded||offloaded
offseting||offsetting
+oflload||offload
omited||omitted
omiting||omitting
omitt||omit
ommiting||omitting
ommitted||omitted
onself||oneself
+onthe||on the
ony||only
+openning||opening
operatione||operation
opertaions||operations
+opportunies||opportunities
optionnal||optional
optmizations||optimizations
orientatied||orientated
@@ -1013,6 +1098,9 @@ oustanding||outstanding
overaall||overall
overhread||overhead
overlaping||overlapping
+oveflow||overflow
+overflw||overflow
+overlfow||overflow
overide||override
overrided||overridden
overriden||overridden
@@ -1030,6 +1118,7 @@ pakage||package
paket||packet
pallette||palette
paln||plan
+palne||plane
paramameters||parameters
paramaters||parameters
paramater||parameter
@@ -1059,10 +1148,12 @@ perfomring||performing
periperal||peripheral
peripherial||peripheral
permissons||permissions
+permited||permitted
peroid||period
persistance||persistence
persistant||persistent
phoneticly||phonetically
+plaform||platform
plalform||platform
platfoem||platform
platfrom||platform
@@ -1091,19 +1182,27 @@ preemptable||preemptible
prefered||preferred
prefferably||preferably
prefitler||prefilter
+preform||perform
premption||preemption
prepaired||prepared
+prepate||prepare
preperation||preparation
preprare||prepare
pressre||pressure
+presuambly||presumably
+previosuly||previously
+previsously||previously
primative||primitive
princliple||principle
priorty||priority
+priting||printing
privilaged||privileged
privilage||privilege
priviledge||privilege
priviledges||privileges
+privleges||privileges
probaly||probably
+probabalistic||probabilistic
procceed||proceed
proccesors||processors
procesed||processed
@@ -1123,6 +1222,7 @@ programable||programmable
programers||programmers
programm||program
programms||programs
+progres||progress
progresss||progress
prohibitted||prohibited
prohibitting||prohibiting
@@ -1147,6 +1247,7 @@ promixity||proximity
psudo||pseudo
psuedo||pseudo
psychadelic||psychedelic
+purgable||purgeable
pwoer||power
queing||queuing
quering||querying
@@ -1160,6 +1261,7 @@ receieve||receive
recepient||recipient
recevied||received
receving||receiving
+recievd||received
recieved||received
recieve||receive
reciever||receiver
@@ -1181,6 +1283,7 @@ refering||referring
refernces||references
refernnce||reference
refrence||reference
+regiser||register
registed||registered
registerd||registered
registeration||registration
@@ -1208,6 +1311,7 @@ reponse||response
representaion||representation
reqeust||request
reqister||register
+requed||requeued
requestied||requested
requiere||require
requirment||requirement
@@ -1220,6 +1324,7 @@ reseting||resetting
reseved||reserved
reseverd||reserved
resizeable||resizable
+resotre||restore
resouce||resource
resouces||resources
resoures||resources
@@ -1252,11 +1357,14 @@ routins||routines
rquest||request
runing||running
runned||ran
+runnnig||running
runnning||running
runtine||runtime
sacrifying||sacrificing
safly||safely
safty||safety
+satify||satisfy
+satisifed||satisfied
savable||saveable
scaleing||scaling
scaned||scanned
@@ -1265,6 +1373,7 @@ scarch||search
schdule||schedule
seach||search
searchs||searches
+secion||section
secquence||sequence
secund||second
segement||segment
@@ -1293,6 +1402,7 @@ servive||service
setts||sets
settting||setting
shapshot||snapshot
+shoft||shift
shotdown||shutdown
shoud||should
shouldnt||shouldn't
@@ -1306,12 +1416,18 @@ similiar||similar
simlar||similar
simliar||similar
simpified||simplified
+simultaneusly||simultaneously
+simultanous||simultaneous
singaled||signaled
singal||signal
singed||signed
+slect||select
sleeped||slept
sliped||slipped
+softwade||software
softwares||software
+soley||solely
+souce||source
speach||speech
specfic||specific
specfield||specified
@@ -1320,7 +1436,9 @@ specifc||specific
specifed||specified
specificatin||specification
specificaton||specification
+specificed||specified
specifing||specifying
+specifiy||specify
specifiying||specifying
speficied||specified
speicify||specify
@@ -1358,6 +1476,7 @@ submited||submitted
submition||submission
succeded||succeeded
suceed||succeed
+succesfuly||successfully
succesfully||successfully
succesful||successful
successed||succeeded
@@ -1373,6 +1492,7 @@ suported||supported
suport||support
supportet||supported
suppored||supported
+supporing||supporting
supportin||supporting
suppoted||supported
suppported||supported
@@ -1399,6 +1519,8 @@ syfs||sysfs
symetric||symmetric
synax||syntax
synchonized||synchronized
+sychronization||synchronization
+sychronously||synchronously
synchronuously||synchronously
syncronize||synchronize
syncronized||synchronized
@@ -1408,15 +1530,18 @@ syste||system
sytem||system
sythesis||synthesis
taht||that
+tained||tainted
+tarffic||traffic
tansmit||transmit
targetted||targeted
targetting||targeting
taskelt||tasklet
teh||the
+temeprature||temperature
temorary||temporary
temproarily||temporarily
temperture||temperature
-thead||thread
+theads||threads
therfore||therefore
thier||their
threds||threads
@@ -1424,6 +1549,7 @@ threee||three
threshhold||threshold
thresold||threshold
throught||through
+tansition||transition
trackling||tracking
troughput||throughput
trys||tries
@@ -1436,6 +1562,8 @@ timout||timeout
tmis||this
toogle||toggle
torerable||tolerable
+torlence||tolerance
+traget||target
traking||tracking
tramsmitted||transmitted
tramsmit||transmit
@@ -1449,6 +1577,7 @@ transferd||transferred
transfered||transferred
transfering||transferring
transision||transition
+transistioned||transitioned
transmittd||transmitted
transormed||transformed
trasfer||transfer
@@ -1462,13 +1591,16 @@ tunning||tuning
ture||true
tyep||type
udpate||update
+updtes||updates
uesd||used
+unknwon||unknown
uknown||unknown
usccess||success
uncommited||uncommitted
uncompatible||incompatible
unconditionaly||unconditionally
undeflow||underflow
+undelying||underlying
underun||underrun
unecessary||unnecessary
unexecpted||unexpected
@@ -1480,10 +1612,12 @@ unexpexted||unexpected
unfortunatelly||unfortunately
unifiy||unify
uniterrupted||uninterrupted
+uninterruptable||uninterruptible
unintialized||uninitialized
unitialized||uninitialized
unkmown||unknown
unknonw||unknown
+unknouwn||unknown
unknow||unknown
unkown||unknown
unamed||unnamed
@@ -1495,13 +1629,17 @@ unneccessary||unnecessary
unnecesary||unnecessary
unneedingly||unnecessarily
unnsupported||unsupported
+unuspported||unsupported
unmached||unmatched
unprecise||imprecise
+unpriviledged||unprivileged
+unpriviliged||unprivileged
unregester||unregister
unresgister||unregister
unrgesiter||unregister
unsinged||unsigned
unstabel||unstable
+unsolicted||unsolicited
unsolicitied||unsolicited
unsuccessfull||unsuccessful
unsuported||unsupported
@@ -1511,6 +1649,8 @@ unuseful||useless
unvalid||invalid
upate||update
upsupported||unsupported
+upto||up to
+useable||usable
usefule||useful
usefull||useful
usege||usage
@@ -1532,9 +1672,11 @@ varient||variant
vaule||value
verbse||verbose
veify||verify
+verfication||verification
veriosn||version
verisons||versions
verison||version
+veritical||vertical
verson||version
vicefersa||vice-versa
virtal||virtual
@@ -1544,6 +1686,7 @@ visiters||visitors
vitual||virtual
vunerable||vulnerable
wakeus||wakeups
+was't||wasn't
wathdog||watchdog
wating||waiting
wiat||wait
@@ -1554,10 +1697,12 @@ whenver||whenever
wheter||whether
whe||when
wierd||weird
+wihout||without
wiil||will
wirte||write
withing||within
wnat||want
+wont||won't
workarould||workaround
writeing||writing
writting||writing
diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install
index b5f9fd5b2880..1fb88fdceec3 100755
--- a/scripts/sphinx-pre-install
+++ b/scripts/sphinx-pre-install
@@ -22,16 +22,19 @@ my $need = 0;
my $optional = 0;
my $need_symlink = 0;
my $need_sphinx = 0;
-my $need_venv = 0;
+my $need_pip = 0;
my $need_virtualenv = 0;
my $rec_sphinx_upgrade = 0;
+my $verbose_warn_install = 1;
my $install = "";
my $virtenv_dir = "";
my $python_cmd = "";
+my $activate_cmd;
my $min_version;
my $cur_version;
my $rec_version = "1.7.9"; # PDF won't build here
my $min_pdf_version = "2.4.4"; # Min version where pdf builds
+my $latest_avail_ver;
#
# Command line arguments
@@ -76,6 +79,7 @@ my %texlive = (
'ucs.sty' => 'texlive-ucs',
'upquote.sty' => 'texlive-upquote',
'wrapfig.sty' => 'texlive-wrapfig',
+ 'ctexhook.sty' => 'texlive-ctex',
);
#
@@ -100,10 +104,12 @@ sub check_missing(%)
next;
}
- if ($is_optional) {
- print "Warning: better to also install \"$prog\".\n";
- } else {
- print "ERROR: please install \"$prog\", otherwise, build won't work.\n";
+ if ($verbose_warn_install) {
+ if ($is_optional) {
+ print "Warning: better to also install \"$prog\".\n";
+ } else {
+ print "ERROR: please install \"$prog\", otherwise, build won't work.\n";
+ }
}
if (defined($map{$prog})) {
$install .= " " . $map{$prog};
@@ -259,7 +265,7 @@ sub get_sphinx_version($)
open IN, "$cmd --version 2>&1 |";
while (<IN>) {
- if (m/^\s*sphinx-build\s+([\d\.]+)(\+\/[\da-f]+)?$/) {
+ if (m/^\s*sphinx-build\s+([\d\.]+)((\+\/[\da-f]+)|(b\d+))?$/) {
$ver=$1;
last;
}
@@ -319,10 +325,7 @@ sub check_sphinx()
return;
}
- if ($cur_version lt $rec_version) {
- $rec_sphinx_upgrade = 1;
- return;
- }
+ return if ($cur_version lt $rec_version);
# On version check mode, just assume Sphinx has all mandatory deps
exit (0) if ($version_check);
@@ -359,7 +362,6 @@ sub give_debian_hints()
{
my %map = (
"python-sphinx" => "python3-sphinx",
- "sphinx_rtd_theme" => "python3-sphinx-rtd-theme",
"ensurepip" => "python3-venv",
"virtualenv" => "virtualenv",
"dot" => "graphviz",
@@ -370,6 +372,9 @@ sub give_debian_hints()
);
if ($pdf) {
+ check_missing_file(["/usr/share/texlive/texmf-dist/tex/latex/ctex/ctexhook.sty"],
+ "texlive-lang-chinese", 2);
+
check_missing_file(["/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"],
"fonts-dejavu", 2);
@@ -383,14 +388,14 @@ sub give_debian_hints()
check_missing(\%map);
return if (!$need && !$optional);
- printf("You should run:\n\n\tsudo apt-get install $install\n");
+ printf("You should run:\n") if ($verbose_warn_install);
+ printf("\n\tsudo apt-get install $install\n");
}
sub give_redhat_hints()
{
my %map = (
"python-sphinx" => "python3-sphinx",
- "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
"virtualenv" => "python3-virtualenv",
"dot" => "graphviz",
"convert" => "ImageMagick",
@@ -455,10 +460,12 @@ sub give_redhat_hints()
if (!$old) {
# dnf, for Fedora 18+
- printf("You should run:\n\n\tsudo dnf install -y $install\n");
+ printf("You should run:\n") if ($verbose_warn_install);
+ printf("\n\tsudo dnf install -y $install\n");
} else {
# yum, for RHEL (and clones) or Fedora version < 18
- printf("You should run:\n\n\tsudo yum install -y $install\n");
+ printf("You should run:\n") if ($verbose_warn_install);
+ printf("\n\tsudo yum install -y $install\n");
}
}
@@ -466,7 +473,6 @@ sub give_opensuse_hints()
{
my %map = (
"python-sphinx" => "python3-sphinx",
- "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
"virtualenv" => "python3-virtualenv",
"dot" => "graphviz",
"convert" => "ImageMagick",
@@ -506,14 +512,14 @@ sub give_opensuse_hints()
check_missing(\%map);
return if (!$need && !$optional);
- printf("You should run:\n\n\tsudo zypper install --no-recommends $install\n");
+ printf("You should run:\n") if ($verbose_warn_install);
+ printf("\n\tsudo zypper install --no-recommends $install\n");
}
sub give_mageia_hints()
{
my %map = (
"python-sphinx" => "python3-sphinx",
- "sphinx_rtd_theme" => "python3-sphinx_rtd_theme",
"virtualenv" => "python3-virtualenv",
"dot" => "graphviz",
"convert" => "ImageMagick",
@@ -550,13 +556,13 @@ sub give_mageia_hints()
check_missing(\%map);
return if (!$need && !$optional);
- printf("You should run:\n\n\tsudo $packager_cmd $install\n");
+ printf("You should run:\n") if ($verbose_warn_install);
+ printf("\n\tsudo $packager_cmd $install\n");
}
sub give_arch_linux_hints()
{
my %map = (
- "sphinx_rtd_theme" => "python-sphinx_rtd_theme",
"virtualenv" => "python-virtualenv",
"dot" => "graphviz",
"convert" => "imagemagick",
@@ -580,13 +586,13 @@ sub give_arch_linux_hints()
check_missing(\%map);
return if (!$need && !$optional);
- printf("You should run:\n\n\tsudo pacman -S $install\n");
+ printf("You should run:\n") if ($verbose_warn_install);
+ printf("\n\tsudo pacman -S $install\n");
}
sub give_gentoo_hints()
{
my %map = (
- "sphinx_rtd_theme" => "dev-python/sphinx_rtd_theme",
"virtualenv" => "dev-python/virtualenv",
"dot" => "media-gfx/graphviz",
"convert" => "media-gfx/imagemagick",
@@ -607,7 +613,8 @@ sub give_gentoo_hints()
return if (!$need && !$optional);
- printf("You should run:\n\n");
+ printf("You should run:\n") if ($verbose_warn_install);
+ printf("\n");
my $imagemagick = "media-gfx/imagemagick svg png";
my $cairo = "media-gfx/graphviz cairo pdf";
@@ -697,10 +704,203 @@ sub check_distros()
sub deactivate_help()
{
- printf "\nIf you want to exit the virtualenv, you can use:\n";
+ printf "\n If you want to exit the virtualenv, you can use:\n";
printf "\tdeactivate\n";
}
+sub get_virtenv()
+{
+ my $ver;
+ my $min_activate = "$ENV{'PWD'}/${virtenv_prefix}${min_version}/bin/activate";
+ my @activates = glob "$ENV{'PWD'}/${virtenv_prefix}*/bin/activate";
+
+ @activates = sort {$b cmp $a} @activates;
+
+ foreach my $f (@activates) {
+ next if ($f lt $min_activate);
+
+ my $sphinx_cmd = $f;
+ $sphinx_cmd =~ s/activate/sphinx-build/;
+ next if (! -f $sphinx_cmd);
+
+ my $ver = get_sphinx_version($sphinx_cmd);
+
+ if (!$ver) {
+ $f =~ s#/bin/activate##;
+ print("Warning: virtual environment $f is not working.\nPython version upgrade? Remove it with:\n\n\trm -rf $f\n\n");
+ }
+
+ if ($need_sphinx && ($ver ge $min_version)) {
+ return ($f, $ver);
+ } elsif ($ver gt $cur_version) {
+ return ($f, $ver);
+ }
+ }
+ return ("", "");
+}
+
+sub recommend_sphinx_upgrade()
+{
+ my $venv_ver;
+
+ # Avoid running sphinx-builds from venv if $cur_version is good
+ if ($cur_version && ($cur_version ge $rec_version)) {
+ $latest_avail_ver = $cur_version;
+ return;
+ }
+
+ # Get the highest version from sphinx_*/bin/sphinx-build and the
+ # corresponding command to activate the venv/virtenv
+ ($activate_cmd, $venv_ver) = get_virtenv();
+
+ # Store the highest version from Sphinx existing virtualenvs
+ if (($activate_cmd ne "") && ($venv_ver gt $cur_version)) {
+ $latest_avail_ver = $venv_ver;
+ } else {
+ $latest_avail_ver = $cur_version if ($cur_version);
+ }
+
+ # As we don't know package version of Sphinx, and there's no
+ # virtual environments, don't check if upgrades are needed
+ if (!$virtualenv) {
+ return if (!$latest_avail_ver);
+ }
+
+ # Either there are already a virtual env or a new one should be created
+ $need_pip = 1;
+
+ return if (!$latest_avail_ver);
+
+ # Return if the reason is due to an upgrade or not
+ if ($latest_avail_ver lt $rec_version) {
+ $rec_sphinx_upgrade = 1;
+ }
+
+ return $latest_avail_ver;
+}
+
+#
+# The logic here is complex, as it have to deal with different versions:
+# - minimal supported version;
+# - minimal PDF version;
+# - recommended version.
+# It also needs to work fine with both distro's package and venv/virtualenv
+sub recommend_sphinx_version($)
+{
+ my $virtualenv_cmd = shift;
+
+ # Version is OK. Nothing to do.
+ if ($cur_version && ($cur_version ge $rec_version)) {
+ if ($cur_version lt $min_pdf_version) {
+ print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n";
+ }
+ return;
+ };
+
+ if (!$need_sphinx) {
+ # sphinx-build is present and its version is >= $min_version
+
+ #only recommend enabling a newer virtenv version if makes sense.
+ if ($latest_avail_ver gt $cur_version) {
+ printf "\nYou may also use the newer Sphinx version $latest_avail_ver with:\n";
+ printf "\tdeactivate\n" if ($ENV{'PWD'} =~ /${virtenv_prefix}/);
+ printf "\t. $activate_cmd\n";
+ deactivate_help();
+
+ return;
+ }
+ return if ($latest_avail_ver ge $rec_version);
+ }
+
+ if (!$virtualenv) {
+ # No sphinx either via package or via virtenv. As we can't
+ # Compare the versions here, just return, recommending the
+ # user to install it from the package distro.
+ return if (!$latest_avail_ver);
+
+ # User doesn't want a virtenv recommendation, but he already
+ # installed one via virtenv with a newer version.
+ # So, print commands to enable it
+ if ($latest_avail_ver gt $cur_version) {
+ printf "\nYou may also use the Sphinx virtualenv version $latest_avail_ver with:\n";
+ printf "\tdeactivate\n" if ($ENV{'PWD'} =~ /${virtenv_prefix}/);
+ printf "\t. $activate_cmd\n";
+ deactivate_help();
+
+ return;
+ }
+ print "\n";
+ } else {
+ $need++ if ($need_sphinx);
+ }
+
+ # Suggest newer versions if current ones are too old
+ if ($latest_avail_ver && $latest_avail_ver ge $min_version) {
+ # If there's a good enough version, ask the user to enable it
+ if ($latest_avail_ver ge $rec_version) {
+ printf "\nNeed to activate Sphinx (version $latest_avail_ver) on virtualenv with:\n";
+ printf "\t. $activate_cmd\n";
+ deactivate_help();
+
+ if ($latest_avail_ver lt $min_pdf_version) {
+ print "note: If you want pdf, you need at least Sphinx $min_pdf_version.\n";
+ }
+
+ return;
+ }
+
+ # Version is above the minimal required one, but may be
+ # below the recommended one. So, print warnings/notes
+
+ if ($latest_avail_ver lt $rec_version) {
+ print "Warning: It is recommended at least Sphinx version $rec_version.\n";
+ }
+ }
+
+ # At this point, either it needs Sphinx or upgrade is recommended,
+ # both via pip
+
+ if ($rec_sphinx_upgrade) {
+ if (!$virtualenv) {
+ print "Instead of install/upgrade Python Sphinx pkg, you could use pip/pypi with:\n\n";
+ } else {
+ print "To upgrade Sphinx, use:\n\n";
+ }
+ } else {
+ print "\nSphinx needs to be installed either:\n1) via pip/pypi with:\n\n";
+ }
+
+ $python_cmd = find_python_no_venv();
+
+ printf "\t$virtualenv_cmd $virtenv_dir\n";
+
+ printf "\t. $virtenv_dir/bin/activate\n";
+ printf "\tpip install -r $requirement_file\n";
+ deactivate_help();
+
+ printf "\n2) As a package with:\n";
+
+ my $old_need = $need;
+ my $old_optional = $optional;
+ %missing = ();
+ $pdf = 0;
+ $optional = 0;
+ $install = "";
+ $verbose_warn_install = 0;
+
+ add_package("python-sphinx", 0);
+
+ check_distros();
+
+ $need = $old_need;
+ $optional = $old_optional;
+
+ printf "\n Please note that Sphinx >= 3.0 will currently produce false-positive\n";
+ printf " warning when the same name is used for more than one type (functions,\n";
+ printf " structs, enums,...). This is known Sphinx bug. For more details, see:\n";
+ printf "\thttps://github.com/sphinx-doc/sphinx/pull/8313\n";
+}
+
sub check_needs()
{
# Check if Sphinx is already accessible from current environment
@@ -722,15 +922,14 @@ sub check_needs()
if ($virtualenv) {
my $tmp = qx($python_cmd --version 2>&1);
if ($tmp =~ m/(\d+\.)(\d+\.)/) {
- if ($1 >= 3 && $2 >= 3) {
- $need_venv = 1; # python 3.3 or upper
- } else {
- $need_virtualenv = 1;
- }
if ($1 < 3) {
# Fail if it finds python2 (or worse)
die "Python 3 is required to build the kernel docs\n";
}
+ if ($1 == 3 && $2 < 3) {
+ # Need Python 3.3 or upper for venv
+ $need_virtualenv = 1;
+ }
} else {
die "Warning: couldn't identify $python_cmd version!";
}
@@ -739,14 +938,22 @@ sub check_needs()
}
}
- # Set virtualenv command line, if python < 3.3
+ my $venv_ver = recommend_sphinx_upgrade();
+
my $virtualenv_cmd;
- if ($need_virtualenv) {
- $virtualenv_cmd = findprog("virtualenv-3");
- $virtualenv_cmd = findprog("virtualenv-3.5") if (!$virtualenv_cmd);
- if (!$virtualenv_cmd) {
- check_program("virtualenv", 0);
- $virtualenv_cmd = "virtualenv";
+
+ if ($need_pip) {
+ # Set virtualenv command line, if python < 3.3
+ if ($need_virtualenv) {
+ $virtualenv_cmd = findprog("virtualenv-3");
+ $virtualenv_cmd = findprog("virtualenv-3.5") if (!$virtualenv_cmd);
+ if (!$virtualenv_cmd) {
+ check_program("virtualenv", 0);
+ $virtualenv_cmd = "virtualenv";
+ }
+ } else {
+ $virtualenv_cmd = "$python_cmd -m venv";
+ check_python_module("ensurepip", 0);
}
}
@@ -754,7 +961,6 @@ sub check_needs()
check_perl_module("Pod::Usage", 0);
check_program("make", 0);
check_program("gcc", 0);
- check_python_module("sphinx_rtd_theme", 1) if (!$virtualenv);
check_program("dot", 1);
check_program("convert", 1);
@@ -763,10 +969,6 @@ sub check_needs()
check_program("rsvg-convert", 2) if ($pdf);
check_program("latexmk", 2) if ($pdf);
- if ($need_sphinx || $rec_sphinx_upgrade) {
- check_python_module("ensurepip", 0) if ($need_venv);
- }
-
# Do distro-specific checks and output distro-install commands
check_distros();
@@ -784,67 +986,7 @@ sub check_needs()
which("sphinx-build-3");
}
- # NOTE: if the system has a too old Sphinx version installed,
- # it will recommend installing a newer version using virtualenv
-
- if ($need_sphinx || $rec_sphinx_upgrade) {
- my $min_activate = "$ENV{'PWD'}/${virtenv_prefix}${min_version}/bin/activate";
- my @activates = glob "$ENV{'PWD'}/${virtenv_prefix}*/bin/activate";
-
- if ($cur_version lt $rec_version) {
- print "Warning: It is recommended at least Sphinx version $rec_version.\n";
- print " If you want pdf, you need at least $min_pdf_version.\n";
- }
- if ($cur_version lt $min_pdf_version) {
- print "Note: It is recommended at least Sphinx version $min_pdf_version if you need PDF support.\n";
- }
- @activates = sort {$b cmp $a} @activates;
- my ($activate, $ver);
- foreach my $f (@activates) {
- next if ($f lt $min_activate);
-
- my $sphinx_cmd = $f;
- $sphinx_cmd =~ s/activate/sphinx-build/;
- next if (! -f $sphinx_cmd);
-
- $ver = get_sphinx_version($sphinx_cmd);
- if ($need_sphinx && ($ver ge $min_version)) {
- $activate = $f;
- last;
- } elsif ($ver gt $cur_version) {
- $activate = $f;
- last;
- }
- }
- if ($activate ne "") {
- if ($need_sphinx) {
- printf "\nNeed to activate Sphinx (version $ver) on virtualenv with:\n";
- printf "\t. $activate\n";
- deactivate_help();
- exit (1);
- } else {
- printf "\nYou may also use a newer Sphinx (version $ver) with:\n";
- printf "\tdeactivate && . $activate\n";
- }
- } else {
- my $rec_activate = "$virtenv_dir/bin/activate";
-
- print "To upgrade Sphinx, use:\n\n" if ($rec_sphinx_upgrade);
-
- $python_cmd = find_python_no_venv();
-
- if ($need_venv) {
- printf "\t$python_cmd -m venv $virtenv_dir\n";
- } else {
- printf "\t$virtualenv_cmd $virtenv_dir\n";
- }
- printf "\t. $rec_activate\n";
- printf "\tpip install -r $requirement_file\n";
- deactivate_help();
-
- $need++ if (!$rec_sphinx_upgrade);
- }
- }
+ recommend_sphinx_version($virtualenv_cmd);
printf "\n";
print "All optional dependencies are met.\n" if (!$optional);
diff --git a/scripts/subarch.include b/scripts/subarch.include
index 650682821126..4bd327d0ae42 100644
--- a/scripts/subarch.include
+++ b/scripts/subarch.include
@@ -7,7 +7,7 @@
SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
-e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
- -e s/s390x/s390/ -e s/parisc64/parisc/ \
+ -e s/s390x/s390/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
- -e s/riscv.*/riscv/)
+ -e s/riscv.*/riscv/ -e s/loongarch.*/loongarch/)
diff --git a/scripts/syscallhdr.sh b/scripts/syscallhdr.sh
index 848ac2735115..22e34cd46b9b 100755
--- a/scripts/syscallhdr.sh
+++ b/scripts/syscallhdr.sh
@@ -69,7 +69,7 @@ guard=_UAPI_ASM_$(basename "$outfile" |
sed -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
-e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g')
-grep -E "^[0-9A-Fa-fXx]+[[:space:]]+$abis" "$infile" | sort -n | {
+grep -E "^[0-9A-Fa-fXx]+[[:space:]]+$abis" "$infile" | {
echo "#ifndef $guard"
echo "#define $guard"
echo
diff --git a/scripts/syscallnr.sh b/scripts/syscallnr.sh
new file mode 100755
index 000000000000..3aa29e0dcc52
--- /dev/null
+++ b/scripts/syscallnr.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Generate a syscall number header.
+#
+# Each line of the syscall table should have the following format:
+#
+# NR ABI NAME [NATIVE] [COMPAT]
+#
+# NR syscall number
+# ABI ABI name
+# NAME syscall name
+# NATIVE native entry point (optional)
+# COMPAT compat entry point (optional)
+set -e
+
+usage() {
+ echo >&2 "usage: $0 [--abis ABIS] [--prefix PREFIX] INFILE OUTFILE" >&2
+ echo >&2
+ echo >&2 " INFILE input syscall table"
+ echo >&2 " OUTFILE output header file"
+ echo >&2
+ echo >&2 "options:"
+ echo >&2 " --abis ABIS ABI(s) to handle (By default, all lines are handled)"
+ echo >&2 " --prefix PREFIX The prefix to the macro like __NR_<PREFIX><NAME>"
+ exit 1
+}
+
+# default unless specified by options
+abis=
+prefix=
+
+while [ $# -gt 0 ]
+do
+ case $1 in
+ --abis)
+ abis=$(echo "($2)" | tr ',' '|')
+ shift 2;;
+ --prefix)
+ prefix=$2
+ shift 2;;
+ -*)
+ echo "$1: unknown option" >&2
+ usage;;
+ *)
+ break;;
+ esac
+done
+
+if [ $# -ne 2 ]; then
+ usage
+fi
+
+infile="$1"
+outfile="$2"
+
+guard=_ASM_$(basename "$outfile" |
+ sed -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
+ -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g')
+
+grep -E "^[0-9A-Fa-fXx]+[[:space:]]+$abis" "$infile" | sort -n | {
+ echo "#ifndef $guard"
+ echo "#define $guard"
+ echo
+
+ max=0
+ while read nr abi name native compat ; do
+ max=$nr
+ done
+
+ echo "#define __NR_${prefix}syscalls $(($max + 1))"
+ echo
+ echo "#endif /* $guard */"
+} > "$outfile"
diff --git a/scripts/syscalltbl.sh b/scripts/syscalltbl.sh
index aa6ab156301c..6abe143889ef 100755
--- a/scripts/syscalltbl.sh
+++ b/scripts/syscalltbl.sh
@@ -52,10 +52,15 @@ outfile="$2"
nxt=0
-grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | sort -n | {
+grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | {
while read nr abi name native compat ; do
+ if [ $nxt -gt $nr ]; then
+ echo "error: $infile: syscall table is not sorted or duplicates the same syscall number" >&2
+ exit 1
+ fi
+
while [ $nxt -lt $nr ]; do
echo "__SYSCALL($nxt, sys_ni_syscall)"
nxt=$((nxt + 1))
diff --git a/scripts/tags.sh b/scripts/tags.sh
index fd96734deff1..a70d43723146 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -8,7 +8,7 @@
# Uses the following environment variables:
# SUBARCH, SRCARCH, srctree
-if [ "$KBUILD_VERBOSE" = "1" ]; then
+if [[ "$KBUILD_VERBOSE" =~ 1 ]]; then
set -x
fi
@@ -17,6 +17,13 @@ ignore="$(echo "$RCS_FIND_IGNORE" | sed 's|\\||g' )"
# tags and cscope files should also ignore MODVERSION *.mod.c files
ignore="$ignore ( -name *.mod.c ) -prune -o"
+# ignore arbitrary directories
+if [ -n "${IGNORE_DIRS}" ]; then
+ for i in ${IGNORE_DIRS}; do
+ ignore="${ignore} ( -path $i ) -prune -o"
+ done
+fi
+
# Use make KBUILD_ABS_SRCTREE=1 {tags|cscope}
# to force full paths for a non-O= build
if [ "${srctree}" = "." -o -z "${srctree}" ]; then
@@ -25,11 +32,11 @@ else
tree=${srctree}/
fi
-# ignore userspace tools
-if [ -n "$COMPILED_SOURCE" ]; then
- ignore="$ignore ( -path ./tools ) -prune -o"
-else
- ignore="$ignore ( -path ${tree}tools ) -prune -o"
+# gtags(1) refuses to index any file outside of its current working dir.
+# If gtags indexing is requested and the build output directory is not
+# the kernel source tree, index all files in absolute-path form.
+if [[ "$1" == "gtags" && -n "${tree}" ]]; then
+ tree=$(realpath "$tree")/
fi
# Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH
@@ -95,10 +102,13 @@ all_sources()
all_compiled_sources()
{
- realpath -es $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) \
- include/generated/autoconf.h $(find $ignore -name "*.cmd" -exec \
- grep -Poh '(?(?=^source_.* \K).*|(?=^ \K\S).*(?= \\))' {} \+ |
- awk '!a[$0]++') | sort -u
+ {
+ echo include/generated/autoconf.h
+ find $ignore -name "*.cmd" -exec \
+ grep -Poh '(?<=^ )\S+|(?<== )\S+[^\\](?=$)' {} \+ |
+ awk '!a[$0]++'
+ } | xargs realpath -esq $([ -z "$KBUILD_ABS_SRCTREE" ] && echo --relative-to=.) |
+ sort -u
}
all_target_sources()
@@ -128,7 +138,7 @@ docscope()
dogtags()
{
- all_target_sources | gtags -i -f -
+ all_target_sources | gtags -i -C "${tree:-.}" -f - "$PWD"
}
# Basic regular expressions with an optional /kind-spec/ for ctags and
@@ -140,71 +150,71 @@ dogtags()
# - etags regular expressions have to match at the start of a line;
# a ^[^#] is prepended by setup_regex unless an anchor is already present
regex_asm=(
- '/^\(ENTRY\|_GLOBAL\)(\([[:alnum:]_\\]*\)).*/\2/'
+ '/^\(ENTRY\|_GLOBAL\)([[:space:]]*\([[:alnum:]_\\]*\)).*/\2/'
)
regex_c=(
- '/^SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/sys_\1/'
- '/^BPF_CALL_[0-9](\([[:alnum:]_]*\).*/\1/'
- '/^COMPAT_SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/compat_sys_\1/'
- '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1/'
- '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
- '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1/'
- '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
- '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/get_\1_slot/'
- '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/free_\1_slot/'
- '/^PAGEFLAG(\([[:alnum:]_]*\).*/Page\1/'
- '/^PAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/'
- '/^PAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/'
- '/^TESTSETFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/'
- '/^TESTPAGEFLAG(\([[:alnum:]_]*\).*/Page\1/'
- '/^SETPAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/'
- '/\<__SETPAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/'
- '/\<TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
- '/\<__TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
- '/\<CLEARPAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/'
- '/\<__CLEARPAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/'
- '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/'
- '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/'
- '/^PAGEFLAG_FALSE(\([[:alnum:]_]*\).*/Page\1/'
- '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/'
- '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/'
- '/\<SETPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/SetPage\1/'
- '/\<CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/ClearPage\1/'
- '/\<__CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/__ClearPage\1/'
- '/\<TESTCLEARFLAG_FALSE(\([[:alnum:]_]*\).*/TestClearPage\1/'
- '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/Page\1/'
- '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__SetPage\1/'
- '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__ClearPage\1/'
- '/^TASK_PFA_TEST([^,]*, *\([[:alnum:]_]*\))/task_\1/'
- '/^TASK_PFA_SET([^,]*, *\([[:alnum:]_]*\))/task_set_\1/'
- '/^TASK_PFA_CLEAR([^,]*, *\([[:alnum:]_]*\))/task_clear_\1/'
- '/^DEF_MMIO_\(IN\|OUT\)_[XD](\([[:alnum:]_]*\),[^)]*)/\2/'
- '/^DEBUGGER_BOILERPLATE(\([[:alnum:]_]*\))/\1/'
- '/^DEF_PCI_AC_\(\|NO\)RET(\([[:alnum:]_]*\).*/\2/'
- '/^PCI_OP_READ(\(\w*\).*[1-4])/pci_bus_read_config_\1/'
- '/^PCI_OP_WRITE(\(\w*\).*[1-4])/pci_bus_write_config_\1/'
- '/\<DEFINE_\(RT_MUTEX\|MUTEX\|SEMAPHORE\|SPINLOCK\)(\([[:alnum:]_]*\)/\2/v/'
- '/\<DEFINE_\(RAW_SPINLOCK\|RWLOCK\|SEQLOCK\)(\([[:alnum:]_]*\)/\2/v/'
- '/\<DECLARE_\(RWSEM\|COMPLETION\)(\([[:alnum:]_]\+\)/\2/v/'
- '/\<DECLARE_BITMAP(\([[:alnum:]_]*\)/\1/v/'
- '/\(^\|\s\)\(\|L\|H\)LIST_HEAD(\([[:alnum:]_]*\)/\3/v/'
- '/\(^\|\s\)RADIX_TREE(\([[:alnum:]_]*\)/\2/v/'
- '/\<DEFINE_PER_CPU([^,]*, *\([[:alnum:]_]*\)/\1/v/'
- '/\<DEFINE_PER_CPU_SHARED_ALIGNED([^,]*, *\([[:alnum:]_]*\)/\1/v/'
- '/\<DECLARE_WAIT_QUEUE_HEAD(\([[:alnum:]_]*\)/\1/v/'
- '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)(\([[:alnum:]_]*\)/\2/v/'
- '/\(^\s\)OFFSET(\([[:alnum:]_]*\)/\2/v/'
- '/\(^\s\)DEFINE(\([[:alnum:]_]*\)/\2/v/'
- '/\<\(DEFINE\|DECLARE\)_HASHTABLE(\([[:alnum:]_]*\)/\2/v/'
- '/\<DEFINE_ID\(R\|A\)(\([[:alnum:]_]\+\)/\2/'
- '/\<DEFINE_WD_CLASS(\([[:alnum:]_]\+\)/\1/'
- '/\<ATOMIC_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/'
- '/\<RAW_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/'
- '/\<DECLARE_FAULT_ATTR(\([[:alnum:]_]\+\)/\1/'
- '/\<BLOCKING_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/'
- '/\<DEVICE_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/dev_attr_\2/'
- '/\<DRIVER_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/driver_attr_\2/'
- '/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)(\([[:alnum:]_]\+\)/\4/'
+ '/^SYSCALL_DEFINE[0-9]([[:space:]]*\([[:alnum:]_]*\).*/sys_\1/'
+ '/^BPF_CALL_[0-9]([[:space:]]*\([[:alnum:]_]*\).*/\1/'
+ '/^COMPAT_SYSCALL_DEFINE[0-9]([[:space:]]*\([[:alnum:]_]*\).*/compat_sys_\1/'
+ '/^TRACE_EVENT([[:space:]]*\([[:alnum:]_]*\).*/trace_\1/'
+ '/^TRACE_EVENT([[:space:]]*\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
+ '/^DEFINE_EVENT([^,)]*,[[:space:]]*\([[:alnum:]_]*\).*/trace_\1/'
+ '/^DEFINE_EVENT([^,)]*,[[:space:]]*\([[:alnum:]_]*\).*/trace_\1_rcuidle/'
+ '/^DEFINE_INSN_CACHE_OPS([[:space:]]*\([[:alnum:]_]*\).*/get_\1_slot/'
+ '/^DEFINE_INSN_CACHE_OPS([[:space:]]*\([[:alnum:]_]*\).*/free_\1_slot/'
+ '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/Page\1/'
+ '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/SetPage\1/'
+ '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/ClearPage\1/'
+ '/^TESTSETFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestSetPage\1/'
+ '/^TESTPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/Page\1/'
+ '/^SETPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/SetPage\1/'
+ '/\<__SETPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__SetPage\1/'
+ '/\<TESTCLEARFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/'
+ '/\<__TESTCLEARFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/'
+ '/\<CLEARPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/ClearPage\1/'
+ '/\<__CLEARPAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/'
+ '/^__PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__SetPage\1/'
+ '/^__PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/'
+ '/^PAGEFLAG_FALSE([[:space:]]*\([[:alnum:]_]*\).*/Page\1/'
+ '/\<TESTSCFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestSetPage\1/'
+ '/\<TESTSCFLAG([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/'
+ '/\<SETPAGEFLAG_NOOP([[:space:]]*\([[:alnum:]_]*\).*/SetPage\1/'
+ '/\<CLEARPAGEFLAG_NOOP([[:space:]]*\([[:alnum:]_]*\).*/ClearPage\1/'
+ '/\<__CLEARPAGEFLAG_NOOP([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/'
+ '/\<TESTCLEARFLAG_FALSE([[:space:]]*\([[:alnum:]_]*\).*/TestClearPage\1/'
+ '/^PAGE_TYPE_OPS([[:space:]]*\([[:alnum:]_]*\).*/Page\1/'
+ '/^PAGE_TYPE_OPS([[:space:]]*\([[:alnum:]_]*\).*/__SetPage\1/'
+ '/^PAGE_TYPE_OPS([[:space:]]*\([[:alnum:]_]*\).*/__ClearPage\1/'
+ '/^TASK_PFA_TEST([^,]*,[[:space:]]*\([[:alnum:]_]*\))/task_\1/'
+ '/^TASK_PFA_SET([^,]*,[[:space:]]*\([[:alnum:]_]*\))/task_set_\1/'
+ '/^TASK_PFA_CLEAR([^,]*,[[:space:]]*\([[:alnum:]_]*\))/task_clear_\1/'
+ '/^DEF_MMIO_\(IN\|OUT\)_[XD]([[:space:]]*\([[:alnum:]_]*\),[^)]*)/\2/'
+ '/^DEBUGGER_BOILERPLATE([[:space:]]*\([[:alnum:]_]*\))/\1/'
+ '/^DEF_PCI_AC_\(\|NO\)RET([[:space:]]*\([[:alnum:]_]*\).*/\2/'
+ '/^PCI_OP_READ([[:space:]]*\(\w*\).*[1-4])/pci_bus_read_config_\1/'
+ '/^PCI_OP_WRITE([[:space:]]*\(\w*\).*[1-4])/pci_bus_write_config_\1/'
+ '/\<DEFINE_\(RT_MUTEX\|MUTEX\|SEMAPHORE\|SPINLOCK\)([[:space:]]*\([[:alnum:]_]*\)/\2/v/'
+ '/\<DEFINE_\(RAW_SPINLOCK\|RWLOCK\|SEQLOCK\)([[:space:]]*\([[:alnum:]_]*\)/\2/v/'
+ '/\<DECLARE_\(RWSEM\|COMPLETION\)([[:space:]]*\([[:alnum:]_]\+\)/\2/v/'
+ '/\<DECLARE_BITMAP([[:space:]]*\([[:alnum:]_]*\)/\1/v/'
+ '/\(^\|\s\)\(\|L\|H\)LIST_HEAD([[:space:]]*\([[:alnum:]_]*\)/\3/v/'
+ '/\(^\|\s\)RADIX_TREE([[:space:]]*\([[:alnum:]_]*\)/\2/v/'
+ '/\<DEFINE_PER_CPU([^,]*,[[:space:]]*\([[:alnum:]_]*\)/\1/v/'
+ '/\<DEFINE_PER_CPU_SHARED_ALIGNED([^,]*,[[:space:]]*\([[:alnum:]_]*\)/\1/v/'
+ '/\<DECLARE_WAIT_QUEUE_HEAD([[:space:]]*\([[:alnum:]_]*\)/\1/v/'
+ '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)([[:space:]]*\([[:alnum:]_]*\)/\2/v/'
+ '/\(^\s\)OFFSET([[:space:]]*\([[:alnum:]_]*\)/\2/v/'
+ '/\(^\s\)DEFINE([[:space:]]*\([[:alnum:]_]*\)/\2/v/'
+ '/\<\(DEFINE\|DECLARE\)_HASHTABLE([[:space:]]*\([[:alnum:]_]*\)/\2/v/'
+ '/\<DEFINE_ID\(R\|A\)([[:space:]]*\([[:alnum:]_]\+\)/\2/'
+ '/\<DEFINE_WD_CLASS([[:space:]]*\([[:alnum:]_]\+\)/\1/'
+ '/\<ATOMIC_NOTIFIER_HEAD([[:space:]]*\([[:alnum:]_]\+\)/\1/'
+ '/\<RAW_NOTIFIER_HEAD([[:space:]]*\([[:alnum:]_]\+\)/\1/'
+ '/\<DECLARE_FAULT_ATTR([[:space:]]*\([[:alnum:]_]\+\)/\1/'
+ '/\<BLOCKING_NOTIFIER_HEAD([[:space:]]*\([[:alnum:]_]\+\)/\1/'
+ '/\<DEVICE_ATTR_\(RW\|RO\|WO\)([[:space:]]*\([[:alnum:]_]\+\)/dev_attr_\2/'
+ '/\<DRIVER_ATTR_\(RW\|RO\|WO\)([[:space:]]*\([[:alnum:]_]\+\)/driver_attr_\2/'
+ '/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)([[:space:]]*\([[:alnum:]_]\+\)/\4/'
'/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_t/'
'/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_init/'
)
@@ -247,6 +257,10 @@ setup_regex()
exuberant()
{
+ CTAGS_EXTRA="extra"
+ if $1 --version 2>&1 | grep -iq universal; then
+ CTAGS_EXTRA="extras"
+ fi
setup_regex exuberant asm c
all_target_sources | xargs $1 -a \
-I __initdata,__exitdata,__initconst,__ro_after_init \
@@ -261,13 +275,15 @@ exuberant()
-I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL,ACPI_EXPORT_SYMBOL \
-I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \
-I static,const \
- --extra=+fq --c-kinds=+px --fields=+iaS --langmap=c:+.h \
+ --$CTAGS_EXTRA=+fq --c-kinds=+px --fields=+iaS --langmap=c:+.h \
"${regex[@]}"
- setup_regex exuberant kconfig
- all_kconfigs | xargs $1 -a \
- --langdef=kconfig --language-force=kconfig "${regex[@]}"
-
+ KCONFIG_ARGS=()
+ if ! $1 --list-languages | grep -iq kconfig; then
+ setup_regex exuberant kconfig
+ KCONFIG_ARGS=(--langdef=kconfig --language-force=kconfig "${regex[@]}")
+ fi
+ all_kconfigs | xargs $1 -a "${KCONFIG_ARGS[@]}"
}
emacs()
@@ -326,5 +342,5 @@ esac
# Remove structure forward declarations.
if [ -n "$remove_structs" ]; then
- LANG=C sed -i -e '/^\([a-zA-Z_][a-zA-Z0-9_]*\)\t.*\t\/\^struct \1;.*\$\/;"\tx$/d' $1
+ LC_ALL=C sed -i -e '/^\([a-zA-Z_][a-zA-Z0-9_]*\)\t.*\t\/\^struct \1;.*\$\/;"\tx$/d' $1
fi
diff --git a/scripts/test_dwarf5_support.sh b/scripts/test_dwarf5_support.sh
deleted file mode 100755
index c46e2456b47a..000000000000
--- a/scripts/test_dwarf5_support.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-
-# Test that the assembler doesn't need -Wa,-gdwarf-5 when presented with DWARF
-# v5 input, such as `.file 0` and `md5 0x00`. Should be fixed in GNU binutils
-# 2.35.2. https://sourceware.org/bugzilla/show_bug.cgi?id=25611
-echo '.file 0 "filename" md5 0x7a0b65214090b6693bd1dc24dd248245' | \
- $* -gdwarf-5 -Wno-unused-command-line-argument -c -x assembler -o /dev/null -
diff --git a/scripts/test_fortify.sh b/scripts/test_fortify.sh
new file mode 100644
index 000000000000..c2688ab8281d
--- /dev/null
+++ b/scripts/test_fortify.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+set -e
+
+# Argument 1: Source file to build.
+IN="$1"
+shift
+# Extract just the filename for error messages below.
+FILE="${IN##*/}"
+# Extract the function name for error messages below.
+FUNC="${FILE#*-}"
+FUNC="${FUNC%%-*}"
+FUNC="${FUNC%%.*}"
+# Extract the symbol to test for in build/symbol test below.
+WANT="__${FILE%%-*}"
+
+# Argument 2: Where to write the build log.
+OUT="$1"
+shift
+TMP="${OUT}.tmp"
+
+# Argument 3: Path to "nm" tool.
+NM="$1"
+shift
+
+# Remaining arguments are: $(CC) $(c_flags)
+
+# Clean up temporary file at exit.
+__cleanup() {
+ rm -f "$TMP"
+}
+trap __cleanup EXIT
+
+# Function names in warnings are wrapped in backticks under UTF-8 locales.
+# Run the commands with LANG=C so that grep output will not change.
+export LANG=C
+
+status=
+# Attempt to build a source that is expected to fail with a specific warning.
+if "$@" -Werror -c "$IN" -o "$OUT".o 2> "$TMP" ; then
+ # If the build succeeds, either the test has failed or the
+ # warning may only happen at link time (Clang). In that case,
+ # make sure the expected symbol is unresolved in the symbol list.
+ # If so, FORTIFY is working for this case.
+ if ! $NM -A "$OUT".o | grep -m1 "\bU ${WANT}$" >>"$TMP" ; then
+ status="warning: unsafe ${FUNC}() usage lacked '$WANT' symbol in $IN"
+ fi
+else
+ # If the build failed, check for the warning in the stderr.
+ # GCC:
+ # ./include/linux/fortify-string.h:316:25: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning]
+ # Clang 14:
+ # ./include/linux/fortify-string.h:316:4: error: call to __write_overflow_field declared with 'warning' attribute: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror,-Wattribute-warning]
+ if ! grep -Eq -m1 "error: call to .?\b${WANT}\b.?" "$TMP" ; then
+ status="warning: unsafe ${FUNC}() usage lacked '$WANT' warning in $IN"
+ fi
+fi
+
+if [ -n "$status" ]; then
+ # Report on failure results, including compilation warnings.
+ echo "$status" | tee "$OUT" >&2
+else
+ # Report on good results, and save any compilation output to log.
+ echo "ok: unsafe ${FUNC}() usage correctly detected with '$WANT' in $IN" >"$OUT"
+fi
+cat "$TMP" >>"$OUT"
diff --git a/scripts/tools-support-relr.sh b/scripts/tools-support-relr.sh
index 45e8aa360b45..4c121946e517 100755
--- a/scripts/tools-support-relr.sh
+++ b/scripts/tools-support-relr.sh
@@ -7,7 +7,12 @@ trap "rm -f $tmp_file.o $tmp_file $tmp_file.bin" EXIT
cat << "END" | $CC -c -x c - -o $tmp_file.o >/dev/null 2>&1
void *p = &p;
END
-$LD $tmp_file.o -shared -Bsymbolic --pack-dyn-relocs=relr -o $tmp_file
+
+# ld.lld before 15 did not support -z pack-relative-relocs.
+if ! $LD $tmp_file.o -shared -Bsymbolic --pack-dyn-relocs=relr -o $tmp_file 2>/dev/null; then
+ $LD $tmp_file.o -shared -Bsymbolic -z pack-relative-relocs -o $tmp_file 2>&1 |
+ grep -q pack-relative-relocs && exit 1
+fi
# Despite printing an error message, GNU nm still exits with exit code 0 if it
# sees a relr section. So we need to check that nothing is printed to stderr.
diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py
index 74f8aadfd4cb..42fa87300941 100755
--- a/scripts/tracing/draw_functrace.py
+++ b/scripts/tracing/draw_functrace.py
@@ -8,16 +8,16 @@ This script parses a trace provided by the function tracer in
kernel/trace/trace_functions.c
The resulted trace is processed into a tree to produce a more human
view of the call stack by drawing textual but hierarchical tree of
-calls. Only the functions's names and the the call time are provided.
+calls. Only the functions's names and the call time are provided.
Usage:
Be sure that you have CONFIG_FUNCTION_TRACER
- # mount -t debugfs nodev /sys/kernel/debug
- # echo function > /sys/kernel/debug/tracing/current_tracer
- $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func
+ # mount -t tracefs nodev /sys/kernel/tracing
+ # echo function > /sys/kernel/tracing/current_tracer
+ $ cat /sys/kernel/tracing/trace_pipe > ~/raw_trace_func
Wait some times but not too much, the script is a bit slow.
Break the pipe (Ctrl + Z)
- $ scripts/draw_functrace.py < raw_trace_func > draw_functrace
+ $ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace
Then you have your drawn trace in draw_functrace
"""
@@ -103,10 +103,10 @@ def parseLine(line):
line = line.strip()
if line.startswith("#"):
raise CommentLineException
- m = re.match("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line)
+ m = re.match("[^]]+?\\] +([a-z.]+) +([0-9.]+): (\\w+) <-(\\w+)", line)
if m is None:
raise BrokenLineException
- return (m.group(1), m.group(2), m.group(3))
+ return (m.group(2), m.group(3), m.group(4))
def main():
diff --git a/scripts/tracing/ftrace-bisect.sh b/scripts/tracing/ftrace-bisect.sh
index 926701162bc8..bb4f59262bbe 100755
--- a/scripts/tracing/ftrace-bisect.sh
+++ b/scripts/tracing/ftrace-bisect.sh
@@ -12,7 +12,7 @@
# (note, if this is a problem with function_graph tracing, then simply
# replace "function" with "function_graph" in the following steps).
#
-# # cd /sys/kernel/debug/tracing
+# # cd /sys/kernel/tracing
# # echo schedule > set_ftrace_filter
# # echo function > current_tracer
#
@@ -20,22 +20,40 @@
#
# # echo nop > current_tracer
#
-# # cat available_filter_functions > ~/full-file
+# Starting with v5.1 this can be done with numbers, making it much faster:
+#
+# The old (slow) way, for kernels before v5.1.
+#
+# [old-way] # cat available_filter_functions > ~/full-file
+#
+# [old-way] *** Note *** this process will take several minutes to update the
+# [old-way] filters. Setting multiple functions is an O(n^2) operation, and we
+# [old-way] are dealing with thousands of functions. So go have coffee, talk
+# [old-way] with your coworkers, read facebook. And eventually, this operation
+# [old-way] will end.
+#
+# The new way (using numbers) is an O(n) operation, and usually takes less than a second.
+#
+# seq `wc -l available_filter_functions | cut -d' ' -f1` > ~/full-file
+#
+# This will create a sequence of numbers that match the functions in
+# available_filter_functions, and when echoing in a number into the
+# set_ftrace_filter file, it will enable the corresponding function in
+# O(1) time. Making enabling all functions O(n) where n is the number of
+# functions to enable.
+#
+# For either the new or old way, the rest of the operations remain the same.
+#
# # ftrace-bisect ~/full-file ~/test-file ~/non-test-file
# # cat ~/test-file > set_ftrace_filter
#
-# *** Note *** this will take several minutes. Setting multiple functions is
-# an O(n^2) operation, and we are dealing with thousands of functions. So go
-# have coffee, talk with your coworkers, read facebook. And eventually, this
-# operation will end.
-#
# # echo function > current_tracer
#
# If it crashes, we know that ~/test-file has a bad function.
#
# Reboot back to test kernel.
#
-# # cd /sys/kernel/debug/tracing
+# # cd /sys/kernel/tracing
# # mv ~/test-file ~/full-file
#
# If it didn't crash.
diff --git a/scripts/ver_linux b/scripts/ver_linux
index a92acc703f9b..1a8ee4ff0e32 100755
--- a/scripts/ver_linux
+++ b/scripts/ver_linux
@@ -47,7 +47,6 @@ BEGIN {
printversion("Net-tools", version("ifconfig --version"))
printversion("Kbd", version("loadkeys -V"))
printversion("Console-tools", version("loadkeys -V"))
- printversion("Oprofile", version("oprofiled --version"))
printversion("Sh-utils", version("expr --v"))
printversion("Udev", version("udevadm --version"))
printversion("Wireless-tools", version("iwconfig --version"))
diff --git a/scripts/xen-hypercalls.sh b/scripts/xen-hypercalls.sh
index f18b00843df3..f18b00843df3 100644..100755
--- a/scripts/xen-hypercalls.sh
+++ b/scripts/xen-hypercalls.sh