diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/Makefile.build | 9 | ||||
-rw-r--r-- | scripts/Makefile.compiler | 2 | ||||
-rw-r--r-- | scripts/Makefile.gcc-plugins | 16 | ||||
-rw-r--r-- | scripts/Makefile.kcov | 9 | ||||
-rw-r--r-- | scripts/Makefile.lib | 3 | ||||
-rwxr-xr-x | scripts/checkpatch.pl | 35 | ||||
-rw-r--r-- | scripts/gcc-plugins/Kconfig | 10 | ||||
-rw-r--r-- | scripts/gcc-plugins/gcc-common.h | 77 | ||||
-rw-r--r-- | scripts/gcc-plugins/randomize_layout_plugin.c | 22 | ||||
-rw-r--r-- | scripts/gcc-plugins/sancov_plugin.c | 134 | ||||
-rw-r--r-- | scripts/gcc-plugins/structleak_plugin.c | 257 | ||||
-rw-r--r-- | scripts/gdb/linux/cpus.py | 4 | ||||
-rw-r--r-- | scripts/gdb/linux/symbols.py | 38 | ||||
-rw-r--r-- | scripts/gdb/linux/utils.py | 22 | ||||
-rwxr-xr-x | scripts/generate_rust_analyzer.py | 13 | ||||
-rw-r--r-- | scripts/generate_rust_target.rs | 4 | ||||
-rwxr-xr-x | scripts/git-resolve.sh | 201 | ||||
-rwxr-xr-x | scripts/min-tool-version.sh | 6 | ||||
-rw-r--r-- | scripts/rustdoc_test_builder.rs | 8 | ||||
-rw-r--r-- | scripts/rustdoc_test_gen.rs | 16 | ||||
-rw-r--r-- | scripts/spelling.txt | 2 |
21 files changed, 364 insertions, 524 deletions
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 884dc86ce04e..557e725ab932 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -222,6 +222,15 @@ $(obj)/%.lst: $(obj)/%.c FORCE # Compile Rust sources (.rs) # --------------------------------------------------------------------------- +# The features in this list are the ones allowed for non-`rust/` code. +# +# - Stable since Rust 1.81.0: `feature(lint_reasons)`. +# - Stable since Rust 1.82.0: `feature(asm_const)`, `feature(raw_ref_op)`. +# - Stable since Rust 1.87.0: `feature(asm_goto)`. +# - Expected to become stable: `feature(arbitrary_self_types)`. +# +# Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on +# the unstable features in use. rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,raw_ref_op # `--out-dir` is required to avoid temporaries being created by `rustc` in the diff --git a/scripts/Makefile.compiler b/scripts/Makefile.compiler index 65cfa72e376b..ef91910de265 100644 --- a/scripts/Makefile.compiler +++ b/scripts/Makefile.compiler @@ -60,7 +60,7 @@ cc-option-yn = $(if $(call cc-option,$1),y,n) cc-disable-warning = $(call cc-option,-Wno-$(strip $1)) # gcc-min-version -# Usage: cflags-$(call gcc-min-version, 70100) += -foo +# Usage: cflags-$(call gcc-min-version, 110100) += -foo gcc-min-version = $(call test-ge, $(CONFIG_GCC_VERSION), $1) # clang-min-version diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index e50dc931be49..435ab3f0ec44 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -8,20 +8,6 @@ ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY endif export DISABLE_LATENT_ENTROPY_PLUGIN -gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so -gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) \ - += -fplugin-arg-structleak_plugin-verbose -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_STACKLEAK) += stackleak_plugin.so gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ += -DSTACKLEAK_PLUGIN @@ -46,8 +32,6 @@ KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) # 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 diff --git a/scripts/Makefile.kcov b/scripts/Makefile.kcov index 67e8cfe3474b..78305a84ba9d 100644 --- a/scripts/Makefile.kcov +++ b/scripts/Makefile.kcov @@ -1,6 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only -kcov-flags-$(CONFIG_CC_HAS_SANCOV_TRACE_PC) += -fsanitize-coverage=trace-pc +kcov-flags-y += -fsanitize-coverage=trace-pc kcov-flags-$(CONFIG_KCOV_ENABLE_COMPARISONS) += -fsanitize-coverage=trace-cmp -kcov-flags-$(CONFIG_GCC_PLUGIN_SANCOV) += -fplugin=$(objtree)/scripts/gcc-plugins/sancov_plugin.so + +kcov-rflags-y += -Cpasses=sancov-module +kcov-rflags-y += -Cllvm-args=-sanitizer-coverage-level=3 +kcov-rflags-y += -Cllvm-args=-sanitizer-coverage-trace-pc +kcov-rflags-$(CONFIG_KCOV_ENABLE_COMPARISONS) += -Cllvm-args=-sanitizer-coverage-trace-compares export CFLAGS_KCOV := $(kcov-flags-y) +export RUSTFLAGS_KCOV := $(kcov-rflags-y) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 6fc2a82ee3bb..2b332645e0c2 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -169,6 +169,9 @@ ifeq ($(CONFIG_KCOV),y) _c_flags += $(if $(patsubst n%,, \ $(KCOV_INSTRUMENT_$(target-stem).o)$(KCOV_INSTRUMENT)$(if $(is-kernel-object),$(CONFIG_KCOV_INSTRUMENT_ALL))), \ $(CFLAGS_KCOV)) +_rust_flags += $(if $(patsubst n%,, \ + $(KCOV_INSTRUMENT_$(target-stem).o)$(KCOV_INSTRUMENT)$(if $(is-kernel-object),$(CONFIG_KCOV_INSTRUMENT_ALL))), \ + $(RUSTFLAGS_KCOV)) endif # diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 966813c2573c..664f7b7a622c 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -151,6 +151,24 @@ EOM exit($exitcode); } +my $DO_WHILE_0_ADVICE = q{ + do {} while (0) advice is over-stated in a few situations: + + The more obvious case is macros, like MODULE_PARM_DESC, invoked at + file-scope, where C disallows code (it must be in functions). See + $exceptions if you have one to add by name. + + More troublesome is declarative macros used at top of new scope, + like DECLARE_PER_CPU. These might just compile with a do-while-0 + wrapper, but would be incorrect. Most of these are handled by + detecting struct,union,etc declaration primitives in $exceptions. + + Theres also macros called inside an if (block), which "return" an + expression. These cannot do-while, and need a ({}) wrapper. + + Enjoy this qualification while we work to improve our heuristics. +}; + sub uniq { my %seen; return grep { !$seen{$_}++ } @_; @@ -5885,9 +5903,9 @@ sub process { } } -# multi-statement macros should be enclosed in a do while loop, grab the -# first statement and ensure its the whole macro if its not enclosed -# in a known good container +# Usually multi-statement macros should be enclosed in a do {} while +# (0) loop. Grab the first statement and ensure its the whole macro +# if its not enclosed in a known good container if ($realfile !~ m@/vmlinux.lds.h$@ && $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { my $ln = $linenr; @@ -5940,10 +5958,13 @@ sub process { my $exceptions = qr{ $Declare| + # named exceptions module_param_named| MODULE_PARM_DESC| DECLARE_PER_CPU| DEFINE_PER_CPU| + static_assert| + # declaration primitives __typeof__\(| union| struct| @@ -5978,11 +5999,11 @@ sub process { ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", "Macros starting with if should be enclosed by a do - while loop to avoid possible if/else logic defects\n" . "$herectx"); } elsif ($dstat =~ /;/) { - ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", - "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx"); + WARN("MULTISTATEMENT_MACRO_USE_DO_WHILE", + "Non-declarative macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx\nBUT SEE:\n$DO_WHILE_0_ADVICE"); } else { ERROR("COMPLEX_MACRO", - "Macros with complex values should be enclosed in parentheses\n" . "$herectx"); + "Macros with complex values should be enclosed in parentheses\n" . "$herectx\nBUT SEE:\n$DO_WHILE_0_ADVICE"); } } @@ -6026,7 +6047,7 @@ sub process { } # check if this is an unused argument - if ($define_stmt !~ /\b$arg\b/) { + if ($define_stmt !~ /\b$arg\b/ && $define_stmt) { WARN("MACRO_ARG_UNUSED", "Argument '$arg' is not used in function-like macro\n" . "$herectx"); } diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig index 231f4a20d617..6b34ba19358d 100644 --- a/scripts/gcc-plugins/Kconfig +++ b/scripts/gcc-plugins/Kconfig @@ -19,16 +19,6 @@ menuconfig GCC_PLUGINS if GCC_PLUGINS -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 - gcc-4.5 on). It is based on the commit "Add fuzzing coverage support" - by Dmitry Vyukov <dvyukov@google.com>. - config GCC_PLUGIN_LATENT_ENTROPY bool "Generate some entropy during boot and runtime" help diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h index 3222c1070444..6cb6d1051815 100644 --- a/scripts/gcc-plugins/gcc-common.h +++ b/scripts/gcc-plugins/gcc-common.h @@ -3,11 +3,7 @@ #define GCC_COMMON_H_INCLUDED #include "bversion.h" -#if BUILDING_GCC_VERSION >= 6000 #include "gcc-plugin.h" -#else -#include "plugin.h" -#endif #include "plugin-version.h" #include "config.h" #include "system.h" @@ -39,9 +35,7 @@ #include "hash-map.h" -#if BUILDING_GCC_VERSION >= 7000 #include "memmodel.h" -#endif #include "emit-rtl.h" #include "debug.h" #include "target.h" @@ -74,9 +68,7 @@ #include "context.h" #include "tree-ssa-alias.h" #include "tree-ssa.h" -#if BUILDING_GCC_VERSION >= 7000 #include "tree-vrp.h" -#endif #include "tree-ssanames.h" #include "print-tree.h" #include "tree-eh.h" @@ -123,6 +115,38 @@ static inline tree build_const_char_string(int len, const char *str) return cstr; } +static inline void __add_type_attr(tree type, const char *attr, tree args) +{ + tree oldattr; + + if (type == NULL_TREE) + return; + oldattr = lookup_attribute(attr, TYPE_ATTRIBUTES(type)); + if (oldattr != NULL_TREE) { + gcc_assert(TREE_VALUE(oldattr) == args || TREE_VALUE(TREE_VALUE(oldattr)) == TREE_VALUE(args)); + return; + } + + TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type)); + TYPE_ATTRIBUTES(type) = tree_cons(get_identifier(attr), args, TYPE_ATTRIBUTES(type)); +} + +static inline void add_type_attr(tree type, const char *attr, tree args) +{ + tree main_variant = TYPE_MAIN_VARIANT(type); + + __add_type_attr(TYPE_CANONICAL(type), attr, args); + __add_type_attr(TYPE_CANONICAL(main_variant), attr, args); + __add_type_attr(main_variant, attr, args); + + for (type = TYPE_NEXT_VARIANT(main_variant); type; type = TYPE_NEXT_VARIANT(type)) { + if (!lookup_attribute(attr, TYPE_ATTRIBUTES(type))) + TYPE_ATTRIBUTES(type) = TYPE_ATTRIBUTES(main_variant); + + __add_type_attr(TYPE_CANONICAL(type), attr, args); + } +} + #define PASS_INFO(NAME, REF, ID, POS) \ struct register_pass_info NAME##_pass_info = { \ .pass = make_##NAME##_pass(), \ @@ -149,16 +173,6 @@ static inline opt_pass *get_pass_for_id(int id) return g->get_passes()->get_pass_for_id(id); } -#if BUILDING_GCC_VERSION < 6000 -/* gimple related */ -template <> -template <> -inline bool is_a_helper<const gassign *>::test(const_gimple gs) -{ - return gs->code == GIMPLE_ASSIGN; -} -#endif - #define TODO_verify_ssa TODO_verify_il #define TODO_verify_flow TODO_verify_il #define TODO_verify_stmts TODO_verify_il @@ -181,7 +195,6 @@ static inline const char *get_decl_section_name(const_tree decl) #define varpool_get_node(decl) varpool_node::get(decl) #define dump_varpool_node(file, node) (node)->dump(file) -#if BUILDING_GCC_VERSION >= 8000 #define cgraph_create_edge(caller, callee, call_stmt, count, freq) \ (caller)->create_edge((callee), (call_stmt), (count)) @@ -189,15 +202,6 @@ static inline const char *get_decl_section_name(const_tree decl) old_call_stmt, call_stmt, count, freq, reason) \ (caller)->create_edge_including_clones((callee), \ (old_call_stmt), (call_stmt), (count), (reason)) -#else -#define cgraph_create_edge(caller, callee, call_stmt, count, freq) \ - (caller)->create_edge((callee), (call_stmt), (count), (freq)) - -#define cgraph_create_edge_including_clones(caller, callee, \ - old_call_stmt, call_stmt, count, freq, reason) \ - (caller)->create_edge_including_clones((callee), \ - (old_call_stmt), (call_stmt), (count), (freq), (reason)) -#endif typedef struct cgraph_node *cgraph_node_ptr; typedef struct cgraph_edge *cgraph_edge_p; @@ -293,14 +297,12 @@ static inline void cgraph_call_edge_duplication_hooks(cgraph_edge *cs1, cgraph_e symtab->call_edge_duplication_hooks(cs1, cs2); } -#if BUILDING_GCC_VERSION >= 6000 typedef gimple *gimple_ptr; typedef const gimple *const_gimple_ptr; #define gimple gimple_ptr #define const_gimple const_gimple_ptr #undef CONST_CAST_GIMPLE #define CONST_CAST_GIMPLE(X) CONST_CAST(gimple, (X)) -#endif /* gimple related */ static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree lhs, tree op1, tree op2 MEM_STAT_DECL) @@ -400,15 +402,7 @@ static inline void ipa_remove_stmt_references(symtab_node *referring_node, gimpl referring_node->remove_stmt_references(stmt); } -#if BUILDING_GCC_VERSION < 6000 -#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \ - get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, pvolatilep, keep_aligning) -#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET(VOIDmode, (ARG0), (ARG1)) -#endif - -#if BUILDING_GCC_VERSION >= 6000 #define gen_rtx_set(ARG0, ARG1) gen_rtx_SET((ARG0), (ARG1)) -#endif #ifdef __cplusplus static inline void debug_tree(const_tree t) @@ -425,15 +419,8 @@ static inline void debug_gimple_stmt(const_gimple s) #define debug_gimple_stmt(s) debug_gimple_stmt(CONST_CAST_GIMPLE(s)) #endif -#if BUILDING_GCC_VERSION >= 7000 #define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \ get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep) -#endif - -#if BUILDING_GCC_VERSION < 7000 -#define SET_DECL_ALIGN(decl, align) DECL_ALIGN(decl) = (align) -#define SET_DECL_MODE(decl, mode) DECL_MODE(decl) = (mode) -#endif #if BUILDING_GCC_VERSION >= 14000 #define last_stmt(x) last_nondebug_stmt(x) diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c index 971a1908a8cc..ff65a4f87f24 100644 --- a/scripts/gcc-plugins/randomize_layout_plugin.c +++ b/scripts/gcc-plugins/randomize_layout_plugin.c @@ -73,6 +73,9 @@ static tree handle_randomize_layout_attr(tree *node, tree name, tree args, int f if (TYPE_P(*node)) { type = *node; + } else if (TREE_CODE(*node) == FIELD_DECL) { + *no_add_attrs = false; + return NULL_TREE; } else { gcc_assert(TREE_CODE(*node) == TYPE_DECL); type = TREE_TYPE(*node); @@ -348,15 +351,14 @@ static int relayout_struct(tree type) TREE_CHAIN(newtree[i]) = newtree[i+1]; TREE_CHAIN(newtree[num_fields - 1]) = NULL_TREE; + add_type_attr(type, "randomize_performed", NULL_TREE); + add_type_attr(type, "designated_init", NULL_TREE); + if (has_flexarray) + add_type_attr(type, "has_flexarray", NULL_TREE); + main_variant = TYPE_MAIN_VARIANT(type); - for (variant = main_variant; variant; variant = TYPE_NEXT_VARIANT(variant)) { + for (variant = main_variant; variant; variant = TYPE_NEXT_VARIANT(variant)) TYPE_FIELDS(variant) = newtree[0]; - TYPE_ATTRIBUTES(variant) = copy_list(TYPE_ATTRIBUTES(variant)); - TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("randomize_performed"), NULL_TREE, TYPE_ATTRIBUTES(variant)); - TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("designated_init"), NULL_TREE, TYPE_ATTRIBUTES(variant)); - if (has_flexarray) - TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("has_flexarray"), NULL_TREE, TYPE_ATTRIBUTES(type)); - } /* * force a re-layout of the main variant @@ -424,10 +426,8 @@ static void randomize_type(tree type) if (lookup_attribute("randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type))) || is_pure_ops_struct(type)) relayout_struct(type); - for (variant = TYPE_MAIN_VARIANT(type); variant; variant = TYPE_NEXT_VARIANT(variant)) { - TYPE_ATTRIBUTES(type) = copy_list(TYPE_ATTRIBUTES(type)); - TYPE_ATTRIBUTES(type) = tree_cons(get_identifier("randomize_considered"), NULL_TREE, TYPE_ATTRIBUTES(type)); - } + add_type_attr(type, "randomize_considered", NULL_TREE); + #ifdef __DEBUG_PLUGIN fprintf(stderr, "Marking randomize_considered on struct %s\n", ORIG_TYPE_NAME(type)); #ifdef __DEBUG_VERBOSE diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c deleted file mode 100644 index b76cb9c42cec..000000000000 --- a/scripts/gcc-plugins/sancov_plugin.c +++ /dev/null @@ -1,134 +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/sancov - * - * This plugin inserts a __sanitizer_cov_trace_pc() call at the start of basic blocks. - * It supports all gcc versions with plugin support (from gcc-4.5 on). - * It is based on the commit "Add fuzzing coverage support" by Dmitry Vyukov <dvyukov@google.com>. - * - * You can read about it more here: - * https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296 - * https://lwn.net/Articles/674854/ - * https://github.com/google/syzkaller - * https://lwn.net/Articles/677764/ - * - * Usage: - * make run - */ - -#include "gcc-common.h" - -__visible int plugin_is_GPL_compatible; - -tree sancov_fndecl; - -static struct plugin_info sancov_plugin_info = { - .version = PLUGIN_VERSION, - .help = "sancov plugin\n", -}; - -static unsigned int sancov_execute(void) -{ - basic_block bb; - - /* Remove this line when this plugin and kcov will be in the kernel. - if (!strcmp(DECL_NAME_POINTER(current_function_decl), DECL_NAME_POINTER(sancov_fndecl))) - return 0; - */ - - FOR_EACH_BB_FN(bb, cfun) { - const_gimple stmt; - gcall *gcall; - gimple_stmt_iterator gsi = gsi_after_labels(bb); - - if (gsi_end_p(gsi)) - continue; - - stmt = gsi_stmt(gsi); - gcall = as_a_gcall(gimple_build_call(sancov_fndecl, 0)); - gimple_set_location(gcall, gimple_location(stmt)); - gsi_insert_before(&gsi, gcall, GSI_SAME_STMT); - } - return 0; -} - -#define PASS_NAME sancov - -#define NO_GATE -#define TODO_FLAGS_FINISH TODO_dump_func | TODO_verify_stmts | TODO_update_ssa_no_phi | TODO_verify_flow - -#include "gcc-generate-gimple-pass.h" - -static void sancov_start_unit(void __unused *gcc_data, void __unused *user_data) -{ - tree leaf_attr, nothrow_attr; - tree BT_FN_VOID = build_function_type_list(void_type_node, NULL_TREE); - - sancov_fndecl = build_fn_decl("__sanitizer_cov_trace_pc", BT_FN_VOID); - - DECL_ASSEMBLER_NAME(sancov_fndecl); - TREE_PUBLIC(sancov_fndecl) = 1; - DECL_EXTERNAL(sancov_fndecl) = 1; - DECL_ARTIFICIAL(sancov_fndecl) = 1; - DECL_PRESERVE_P(sancov_fndecl) = 1; - DECL_UNINLINABLE(sancov_fndecl) = 1; - TREE_USED(sancov_fndecl) = 1; - - nothrow_attr = tree_cons(get_identifier("nothrow"), NULL, NULL); - decl_attributes(&sancov_fndecl, nothrow_attr, 0); - gcc_assert(TREE_NOTHROW(sancov_fndecl)); - leaf_attr = tree_cons(get_identifier("leaf"), NULL, NULL); - decl_attributes(&sancov_fndecl, leaf_attr, 0); -} - -__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) -{ - int i; - const char * const plugin_name = plugin_info->base_name; - const int argc = plugin_info->argc; - const struct plugin_argument * const argv = plugin_info->argv; - bool enable = true; - - static const struct ggc_root_tab gt_ggc_r_gt_sancov[] = { - { - .base = &sancov_fndecl, - .nelt = 1, - .stride = sizeof(sancov_fndecl), - .cb = >_ggc_mx_tree_node, - .pchw = >_pch_nx_tree_node - }, - LAST_GGC_ROOT_TAB - }; - - /* BBs can be split afterwards?? */ - PASS_INFO(sancov, "asan", 0, PASS_POS_INSERT_BEFORE); - - if (!plugin_default_version_check(version, &gcc_version)) { - error(G_("incompatible gcc/plugin versions")); - return 1; - } - - for (i = 0; i < argc; ++i) { - if (!strcmp(argv[i].key, "no-sancov")) { - enable = false; - continue; - } - error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); - } - - register_callback(plugin_name, PLUGIN_INFO, NULL, &sancov_plugin_info); - - if (!enable) - return 0; - -#if BUILDING_GCC_VERSION < 6000 - register_callback(plugin_name, PLUGIN_START_UNIT, &sancov_start_unit, NULL); - register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_sancov); - register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &sancov_pass_info); -#endif - - return 0; -} diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c deleted file mode 100644 index d8c744233832..000000000000 --- a/scripts/gcc-plugins/structleak_plugin.c +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright 2013-2017 by PaX Team <pageexec@freemail.hu> - * - * 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, - * but for the kernel it doesn't matter since it doesn't link against - * any of the gcc libraries - * - * gcc plugin to forcibly initialize certain local variables that could - * otherwise leak kernel stack to userland if they aren't properly initialized - * by later code - * - * Homepage: https://pax.grsecurity.net/ - * - * Options: - * -fplugin-arg-structleak_plugin-disable - * -fplugin-arg-structleak_plugin-verbose - * -fplugin-arg-structleak_plugin-byref - * -fplugin-arg-structleak_plugin-byref-all - * - * Usage: - * $ # for 4.5/4.6/C based 4.7 - * $ gcc -I`gcc -print-file-name=plugin`/include -I`gcc -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c - * $ # for C++ based 4.7/4.8+ - * $ g++ -I`g++ -print-file-name=plugin`/include -I`g++ -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c - * $ gcc -fplugin=./structleak_plugin.so test.c -O2 - * - * TODO: eliminate redundant initializers - */ - -#include "gcc-common.h" - -/* unused C type flag in all versions 4.5-6 */ -#define TYPE_USERSPACE(TYPE) TYPE_LANG_FLAG_5(TYPE) - -__visible int plugin_is_GPL_compatible; - -static struct plugin_info structleak_plugin_info = { - .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" - "verbose\tprint all initialized variables\n", -}; - -#define BYREF_STRUCT 1 -#define BYREF_ALL 2 - -static bool verbose; -static int byref; - -static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) -{ - *no_add_attrs = true; - - /* check for types? for now accept everything linux has to offer */ - if (TREE_CODE(*node) != FIELD_DECL) - return NULL_TREE; - - *no_add_attrs = false; - return NULL_TREE; -} - -static struct attribute_spec user_attr = { }; - -static void register_attributes(void *event_data, void *data) -{ - user_attr.name = "user"; - user_attr.handler = handle_user_attribute; - user_attr.affects_type_identity = true; - - register_attribute(&user_attr); -} - -static tree get_field_type(tree field) -{ - return strip_array_types(TREE_TYPE(field)); -} - -static bool is_userspace_type(tree type) -{ - tree field; - - for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) { - tree fieldtype = get_field_type(field); - enum tree_code code = TREE_CODE(fieldtype); - - if (code == RECORD_TYPE || code == UNION_TYPE) - if (is_userspace_type(fieldtype)) - return true; - - if (lookup_attribute("user", DECL_ATTRIBUTES(field))) - return true; - } - return false; -} - -static void finish_type(void *event_data, void *data) -{ - tree type = (tree)event_data; - - if (type == NULL_TREE || type == error_mark_node) - return; - - if (TREE_CODE(type) == ENUMERAL_TYPE) - return; - - if (TYPE_USERSPACE(type)) - return; - - if (is_userspace_type(type)) - TYPE_USERSPACE(type) = 1; -} - -static void initialize(tree var) -{ - basic_block bb; - gimple_stmt_iterator gsi; - tree initializer; - gimple init_stmt; - tree type; - - /* this is the original entry bb before the forced split */ - bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); - - /* first check if variable is already initialized, warn otherwise */ - for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { - gimple stmt = gsi_stmt(gsi); - tree rhs1; - - /* we're looking for an assignment of a single rhs... */ - if (!gimple_assign_single_p(stmt)) - continue; - rhs1 = gimple_assign_rhs1(stmt); - /* ... of a non-clobbering expression... */ - if (TREE_CLOBBER_P(rhs1)) - continue; - /* ... to our variable... */ - if (gimple_get_lhs(stmt) != var) - continue; - /* if it's an initializer then we're good */ - if (TREE_CODE(rhs1) == CONSTRUCTOR) - return; - } - - /* these aren't the 0days you're looking for */ - if (verbose) - inform(DECL_SOURCE_LOCATION(var), - "%s variable will be forcibly initialized", - (byref && TREE_ADDRESSABLE(var)) ? "byref" - : "userspace"); - - /* build the initializer expression */ - type = TREE_TYPE(var); - if (AGGREGATE_TYPE_P(type)) - initializer = build_constructor(type, NULL); - else - initializer = fold_convert(type, integer_zero_node); - - /* build the initializer stmt */ - init_stmt = gimple_build_assign(var, initializer); - gsi = gsi_after_labels(single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun))); - gsi_insert_before(&gsi, init_stmt, GSI_NEW_STMT); - update_stmt(init_stmt); -} - -static unsigned int structleak_execute(void) -{ - basic_block bb; - tree var; - unsigned int i; - - /* split the first bb where we can put the forced initializers */ - gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); - bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); - if (!single_pred_p(bb)) { - split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); - gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); - } - - /* enumerate all local variables and forcibly initialize our targets */ - FOR_EACH_LOCAL_DECL(cfun, i, var) { - tree type = TREE_TYPE(var); - - gcc_assert(DECL_P(var)); - if (!auto_var_in_fn_p(var, current_function_decl)) - continue; - - /* only care about structure types unless byref-all */ - if (byref != BYREF_ALL && TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) - continue; - - /* if the type is of interest, examine the variable */ - if (TYPE_USERSPACE(type) || - (byref && TREE_ADDRESSABLE(var))) - initialize(var); - } - - return 0; -} - -#define PASS_NAME structleak -#define NO_GATE -#define PROPERTIES_REQUIRED PROP_cfg -#define TODO_FLAGS_FINISH TODO_verify_il | TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_remove_unused_locals | TODO_update_ssa | TODO_ggc_collect | TODO_verify_flow -#include "gcc-generate-gimple-pass.h" - -__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) -{ - int i; - const char * const plugin_name = plugin_info->base_name; - const int argc = plugin_info->argc; - const struct plugin_argument * const argv = plugin_info->argv; - bool enable = true; - - PASS_INFO(structleak, "early_optimizations", 1, PASS_POS_INSERT_BEFORE); - - if (!plugin_default_version_check(version, &gcc_version)) { - error(G_("incompatible gcc/plugin versions")); - return 1; - } - - if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) { - inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name); - enable = false; - } - - for (i = 0; i < argc; ++i) { - if (!strcmp(argv[i].key, "disable")) { - enable = false; - continue; - } - if (!strcmp(argv[i].key, "verbose")) { - verbose = true; - continue; - } - if (!strcmp(argv[i].key, "byref")) { - byref = BYREF_STRUCT; - continue; - } - if (!strcmp(argv[i].key, "byref-all")) { - byref = BYREF_ALL; - continue; - } - error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); - } - - register_callback(plugin_name, PLUGIN_INFO, NULL, &structleak_plugin_info); - if (enable) { - register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &structleak_pass_info); - register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL); - } - register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); - - return 0; -} diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py index f506965ea759..6edf4ef61636 100644 --- a/scripts/gdb/linux/cpus.py +++ b/scripts/gdb/linux/cpus.py @@ -141,7 +141,7 @@ LxCpus() class PerCpu(gdb.Function): """Return per-cpu variable. -$lx_per_cpu("VAR"[, CPU]): Return the per-cpu variable called VAR for the +$lx_per_cpu(VAR[, CPU]): Return the per-cpu variable called VAR for the given CPU number. If CPU is omitted, the CPU of the current context is used. Note that VAR has to be quoted as string.""" @@ -158,7 +158,7 @@ PerCpu() class PerCpuPtr(gdb.Function): """Return per-cpu pointer. -$lx_per_cpu_ptr("VAR"[, CPU]): Return the per-cpu pointer called VAR for the +$lx_per_cpu_ptr(VAR[, CPU]): Return the per-cpu pointer called VAR for the given CPU number. If CPU is omitted, the CPU of the current context is used. Note that VAR has to be quoted as string.""" diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py index b255177301e9..2332bd8eddf1 100644 --- a/scripts/gdb/linux/symbols.py +++ b/scripts/gdb/linux/symbols.py @@ -38,19 +38,13 @@ if hasattr(gdb, 'Breakpoint'): # Disable pagination while reporting symbol (re-)loading. # The console input is blocked in this context so that we would # get stuck waiting for the user to acknowledge paged output. - show_pagination = gdb.execute("show pagination", to_string=True) - pagination = show_pagination.endswith("on.\n") - gdb.execute("set pagination off") - - if module_name in cmd.loaded_modules: - gdb.write("refreshing all symbols to reload module " - "'{0}'\n".format(module_name)) - cmd.load_all_symbols() - else: - cmd.load_module_symbols(module) - - # restore pagination state - gdb.execute("set pagination %s" % ("on" if pagination else "off")) + with utils.pagination_off(): + if module_name in cmd.loaded_modules: + gdb.write("refreshing all symbols to reload module " + "'{0}'\n".format(module_name)) + cmd.load_all_symbols() + else: + cmd.load_module_symbols(module) return False @@ -60,6 +54,18 @@ def get_vmcore_s390(): vmcore_info = 0x0e0c paddr_vmcoreinfo_note = gdb.parse_and_eval("*(unsigned long long *)" + hex(vmcore_info)) + if paddr_vmcoreinfo_note == 0 or paddr_vmcoreinfo_note & 1: + # In the early boot case, extract vm_layout.kaslr_offset from the + # vmlinux image in physical memory. + if paddr_vmcoreinfo_note == 0: + kaslr_offset_phys = 0 + else: + kaslr_offset_phys = paddr_vmcoreinfo_note - 1 + with utils.pagination_off(): + gdb.execute("symbol-file {0} -o {1}".format( + utils.get_vmlinux(), hex(kaslr_offset_phys))) + kaslr_offset = gdb.parse_and_eval("vm_layout.kaslr_offset") + return "KERNELOFFSET=" + hex(kaslr_offset)[2:] inferior = gdb.selected_inferior() elf_note = inferior.read_memory(paddr_vmcoreinfo_note, 12) n_namesz, n_descsz, n_type = struct.unpack(">III", elf_note) @@ -178,11 +184,7 @@ lx-symbols command.""" saved_states.append({'breakpoint': bp, 'enabled': bp.enabled}) # drop all current symbols and reload vmlinux - orig_vmlinux = 'vmlinux' - for obj in gdb.objfiles(): - if (obj.filename.endswith('vmlinux') or - obj.filename.endswith('vmlinux.debug')): - orig_vmlinux = obj.filename + orig_vmlinux = utils.get_vmlinux() gdb.execute("symbol-file", to_string=True) kerneloffset = get_kerneloffset() if kerneloffset is None: diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py index 03ebdccf5f69..e11f6f67961a 100644 --- a/scripts/gdb/linux/utils.py +++ b/scripts/gdb/linux/utils.py @@ -200,7 +200,7 @@ def get_gdbserver_type(): def probe_kgdb(): try: - thread_info = gdb.execute("info thread 2", to_string=True) + thread_info = gdb.execute("info thread 1", to_string=True) return "shadowCPU" in thread_info except gdb.error: return False @@ -251,3 +251,23 @@ def parse_vmcore(s): else: kerneloffset = int(match.group(1), 16) return VmCore(kerneloffset=kerneloffset) + + +def get_vmlinux(): + vmlinux = 'vmlinux' + for obj in gdb.objfiles(): + if (obj.filename.endswith('vmlinux') or + obj.filename.endswith('vmlinux.debug')): + vmlinux = obj.filename + return vmlinux + + +@contextlib.contextmanager +def pagination_off(): + show_pagination = gdb.execute("show pagination", to_string=True) + pagination = show_pagination.endswith("on.\n") + gdb.execute("set pagination off") + try: + yield + finally: + gdb.execute("set pagination %s" % ("on" if pagination else "off")) diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index fe663dd0c43b..7c3ea2b55041 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -19,7 +19,7 @@ def args_crates_cfgs(cfgs): return crates_cfgs -def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): +def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edition): # Generate the configuration list. cfg = [] with open(objtree / "include" / "generated" / "rustc_cfg") as fd: @@ -35,7 +35,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): crates_indexes = {} crates_cfgs = args_crates_cfgs(cfgs) - def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False): + def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False, edition="2021"): crate = { "display_name": display_name, "root_module": str(root_module), @@ -43,7 +43,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): "is_proc_macro": is_proc_macro, "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps], "cfg": cfg, - "edition": "2021", + "edition": edition, "env": { "RUST_MODFILE": "This is only for rust-analyzer" } @@ -61,6 +61,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): display_name, deps, cfg=[], + edition="2021", ): append_crate( display_name, @@ -68,12 +69,13 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): deps, cfg, is_workspace_member=False, + edition=edition, ) # NB: sysroot crates reexport items from one another so setting up our transitive dependencies # here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth # for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`. - append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", [])) + append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", []), edition=core_edition) append_sysroot_crate("alloc", ["core"]) append_sysroot_crate("std", ["alloc", "core"]) append_sysroot_crate("proc_macro", ["core", "std"]) @@ -177,6 +179,7 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true') parser.add_argument('--cfgs', action='append', default=[]) + parser.add_argument("core_edition") parser.add_argument("srctree", type=pathlib.Path) parser.add_argument("objtree", type=pathlib.Path) parser.add_argument("sysroot", type=pathlib.Path) @@ -193,7 +196,7 @@ def main(): assert args.sysroot in args.sysroot_src.parents rust_project = { - "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs), + "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs, args.core_edition), "sysroot": str(args.sysroot), } diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs index 8667d0ae3c82..39c82908ff3a 100644 --- a/scripts/generate_rust_target.rs +++ b/scripts/generate_rust_target.rs @@ -209,7 +209,7 @@ fn main() { // target feature of the same name plus the other two target features in // `clang/lib/Driver/ToolChains/Arch/X86.cpp`. These should be eventually enabled via // `-Ctarget-feature` when `rustc` starts recognizing them (or via a new dedicated - // flag); see https://github.com/rust-lang/rust/issues/116852. + // flag); see <https://github.com/rust-lang/rust/issues/116852>. features += ",+retpoline-external-thunk"; features += ",+retpoline-indirect-branches"; features += ",+retpoline-indirect-calls"; @@ -218,7 +218,7 @@ fn main() { // The kernel uses `-mharden-sls=all`, which Clang maps to both these target features in // `clang/lib/Driver/ToolChains/Arch/X86.cpp`. These should be eventually enabled via // `-Ctarget-feature` when `rustc` starts recognizing them (or via a new dedicated - // flag); see https://github.com/rust-lang/rust/issues/116851. + // flag); see <https://github.com/rust-lang/rust/issues/116851>. features += ",+harden-sls-ijmp"; features += ",+harden-sls-ret"; } diff --git a/scripts/git-resolve.sh b/scripts/git-resolve.sh new file mode 100755 index 000000000000..e9b5940c0f28 --- /dev/null +++ b/scripts/git-resolve.sh @@ -0,0 +1,201 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# (c) 2025, Sasha Levin <sashal@kernel.org> + +usage() { + echo "Usage: $(basename "$0") [--selftest] [--force] <commit-id> [commit-subject]" + echo "Resolves a short git commit ID to its full SHA-1 hash, particularly useful for fixing references in commit messages." + echo "" + echo "Arguments:" + echo " --selftest Run self-tests" + echo " --force Try to find commit by subject if ID lookup fails" + echo " commit-id Short git commit ID to resolve" + echo " commit-subject Optional commit subject to help resolve between multiple matches" + exit 1 +} + +# Convert subject with ellipsis to grep pattern +convert_to_grep_pattern() { + local subject="$1" + # First escape ALL regex special characters + local escaped_subject + escaped_subject=$(printf '%s\n' "$subject" | sed 's/[[\.*^$()+?{}|]/\\&/g') + # Also escape colons, parentheses, and hyphens as they are special in our context + escaped_subject=$(echo "$escaped_subject" | sed 's/[:-]/\\&/g') + # Then convert escaped ... sequence to .*? + escaped_subject=$(echo "$escaped_subject" | sed 's/\\\.\\\.\\\./.*?/g') + echo "^${escaped_subject}$" +} + +git_resolve_commit() { + local force=0 + if [ "$1" = "--force" ]; then + force=1 + shift + fi + + # Split input into commit ID and subject + local input="$*" + local commit_id="${input%% *}" + local subject="" + + # Extract subject if present (everything after the first space) + if [[ "$input" == *" "* ]]; then + subject="${input#* }" + # Strip the ("...") quotes if present + subject="${subject#*(\"}" + subject="${subject%\")*}" + fi + + # Get all possible matching commit IDs + local matches + readarray -t matches < <(git rev-parse --disambiguate="$commit_id" 2>/dev/null) + + # Return immediately if we have exactly one match + if [ ${#matches[@]} -eq 1 ]; then + echo "${matches[0]}" + return 0 + fi + + # If no matches and not in force mode, return failure + if [ ${#matches[@]} -eq 0 ] && [ $force -eq 0 ]; then + return 1 + fi + + # If we have a subject, try to find a match with that subject + if [ -n "$subject" ]; then + # Convert subject with possible ellipsis to grep pattern + local grep_pattern + grep_pattern=$(convert_to_grep_pattern "$subject") + + # In force mode with no ID matches, use git log --grep directly + if [ ${#matches[@]} -eq 0 ] && [ $force -eq 1 ]; then + # Use git log to search, but filter to ensure subject matches exactly + local match + match=$(git log --format="%H %s" --grep="$grep_pattern" --perl-regexp -10 | \ + while read -r hash subject; do + if echo "$subject" | grep -qP "$grep_pattern"; then + echo "$hash" + break + fi + done) + if [ -n "$match" ]; then + echo "$match" + return 0 + fi + else + # Normal subject matching for existing matches + for match in "${matches[@]}"; do + if git log -1 --format="%s" "$match" | grep -qP "$grep_pattern"; then + echo "$match" + return 0 + fi + done + fi + fi + + # No match found + return 1 +} + +run_selftest() { + local test_cases=( + '00250b5 ("MAINTAINERS: add new Rockchip SoC list")' + '0037727 ("KVM: selftests: Convert xen_shinfo_test away from VCPU_ID")' + 'ffef737 ("net/tls: Fix skb memory leak when running kTLS traffic")' + 'd3d7 ("cifs: Improve guard for excluding $LXDEV xattr")' + 'dbef ("Rename .data.once to .data..once to fix resetting WARN*_ONCE")' + '12345678' # Non-existent commit + '12345 ("I'\''m a dummy commit")' # Valid prefix but wrong subject + '--force 99999999 ("net/tls: Fix skb memory leak when running kTLS traffic")' # Force mode with non-existent ID but valid subject + '83be ("firmware: ... auto-update: fix poll_complete() ... errors")' # Wildcard test + '--force 999999999999 ("firmware: ... auto-update: fix poll_complete() ... errors")' # Force mode wildcard test + ) + + local expected=( + "00250b529313d6262bb0ebbd6bdf0a88c809f6f0" + "0037727b3989c3fe1929c89a9a1dfe289ad86f58" + "ffef737fd0372ca462b5be3e7a592a8929a82752" + "d3d797e326533794c3f707ce1761da7a8895458c" + "dbefa1f31a91670c9e7dac9b559625336206466f" + "" # Expect empty output for non-existent commit + "" # Expect empty output for wrong subject + "ffef737fd0372ca462b5be3e7a592a8929a82752" # Should find commit by subject in force mode + "83beece5aff75879bdfc6df8ba84ea88fd93050e" # Wildcard test + "83beece5aff75879bdfc6df8ba84ea88fd93050e" # Force mode wildcard test + ) + + local expected_exit_codes=( + 0 + 0 + 0 + 0 + 0 + 1 # Expect failure for non-existent commit + 1 # Expect failure for wrong subject + 0 # Should succeed in force mode + 0 # Should succeed with wildcard + 0 # Should succeed with force mode and wildcard + ) + + local failed=0 + + echo "Running self-tests..." + for i in "${!test_cases[@]}"; do + # Capture both output and exit code + local result + result=$(git_resolve_commit ${test_cases[$i]}) # Removed quotes to allow --force to be parsed + local exit_code=$? + + # Check both output and exit code + if [ "$result" != "${expected[$i]}" ] || [ $exit_code != ${expected_exit_codes[$i]} ]; then + echo "Test case $((i+1)) FAILED" + echo "Input: ${test_cases[$i]}" + echo "Expected output: '${expected[$i]}'" + echo "Got output: '$result'" + echo "Expected exit code: ${expected_exit_codes[$i]}" + echo "Got exit code: $exit_code" + failed=1 + else + echo "Test case $((i+1)) PASSED" + fi + done + + if [ $failed -eq 0 ]; then + echo "All tests passed!" + exit 0 + else + echo "Some tests failed!" + exit 1 + fi +} + +# Check for selftest +if [ "$1" = "--selftest" ]; then + run_selftest + exit $? +fi + +# Handle --force flag +force="" +if [ "$1" = "--force" ]; then + force="--force" + shift +fi + +# Verify arguments +if [ $# -eq 0 ]; then + usage +fi + +# Skip validation in force mode +if [ -z "$force" ]; then + # Validate that the first argument matches at least one git commit + if [ "$(git rev-parse --disambiguate="$1" 2>/dev/null | wc -l)" -eq 0 ]; then + echo "Error: '$1' does not match any git commit" + exit 1 + fi +fi + +git_resolve_commit $force "$@" +exit $? diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index 787868183b84..0d223b4a9445 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -14,15 +14,13 @@ fi case "$1" in binutils) - echo 2.25.0 + echo 2.30.0 ;; gcc) if [ "$ARCH" = parisc64 ]; then echo 12.0.0 - elif [ "$SRCARCH" = x86 ]; then - echo 8.1.0 else - echo 5.1.0 + echo 8.1.0 fi ;; llvm) diff --git a/scripts/rustdoc_test_builder.rs b/scripts/rustdoc_test_builder.rs index e5894652f12c..f7540bcf595a 100644 --- a/scripts/rustdoc_test_builder.rs +++ b/scripts/rustdoc_test_builder.rs @@ -28,7 +28,7 @@ fn main() { // // ``` // fn main() { #[allow(non_snake_case)] fn _doctest_main_rust_kernel_file_rs_28_0() { - // fn main() { #[allow(non_snake_case)] fn _doctest_main_rust_kernel_file_rs_37_0() -> Result<(), impl core::fmt::Debug> { + // fn main() { #[allow(non_snake_case)] fn _doctest_main_rust_kernel_file_rs_37_0() -> Result<(), impl ::core::fmt::Debug> { // ``` // // It should be unlikely that doctest code matches such lines (when code is formatted properly). @@ -49,8 +49,10 @@ fn main() { // Qualify `Result` to avoid the collision with our own `Result` coming from the prelude. let body = body.replace( - &format!("{rustdoc_function_name}() -> Result<(), impl core::fmt::Debug> {{"), - &format!("{rustdoc_function_name}() -> core::result::Result<(), impl core::fmt::Debug> {{"), + &format!("{rustdoc_function_name}() -> Result<(), impl ::core::fmt::Debug> {{"), + &format!( + "{rustdoc_function_name}() -> ::core::result::Result<(), impl ::core::fmt::Debug> {{" + ), ); // For tests that get generated with `Result`, like above, `rustdoc` generates an `unwrap()` on diff --git a/scripts/rustdoc_test_gen.rs b/scripts/rustdoc_test_gen.rs index ec8d70ac888b..1ca253594d38 100644 --- a/scripts/rustdoc_test_gen.rs +++ b/scripts/rustdoc_test_gen.rs @@ -167,12 +167,14 @@ fn main() { rust_tests, r#"/// Generated `{name}` KUnit test case from a Rust documentation test. #[no_mangle] -pub extern "C" fn {kunit_name}(__kunit_test: *mut kernel::bindings::kunit) {{ +pub extern "C" fn {kunit_name}(__kunit_test: *mut ::kernel::bindings::kunit) {{ /// Overrides the usual [`assert!`] macro with one that calls KUnit instead. #[allow(unused)] macro_rules! assert {{ ($cond:expr $(,)?) => {{{{ - kernel::kunit_assert!("{kunit_name}", "{real_path}", __DOCTEST_ANCHOR - {line}, $cond); + ::kernel::kunit_assert!( + "{kunit_name}", "{real_path}", __DOCTEST_ANCHOR - {line}, $cond + ); }}}} }} @@ -180,13 +182,15 @@ pub extern "C" fn {kunit_name}(__kunit_test: *mut kernel::bindings::kunit) {{ #[allow(unused)] macro_rules! assert_eq {{ ($left:expr, $right:expr $(,)?) => {{{{ - kernel::kunit_assert_eq!("{kunit_name}", "{real_path}", __DOCTEST_ANCHOR - {line}, $left, $right); + ::kernel::kunit_assert_eq!( + "{kunit_name}", "{real_path}", __DOCTEST_ANCHOR - {line}, $left, $right + ); }}}} }} // Many tests need the prelude, so provide it by default. #[allow(unused)] - use kernel::prelude::*; + use ::kernel::prelude::*; // Unconditionally print the location of the original doctest (i.e. rather than the location in // the generated file) so that developers can easily map the test back to the source code. @@ -197,11 +201,11 @@ pub extern "C" fn {kunit_name}(__kunit_test: *mut kernel::bindings::kunit) {{ // This follows the syntax for declaring test metadata in the proposed KTAP v2 spec, which may // be used for the proposed KUnit test attributes API. Thus hopefully this will make migration // easier later on. - kernel::kunit::info(format_args!(" # {kunit_name}.location: {real_path}:{line}\n")); + ::kernel::kunit::info(format_args!(" # {kunit_name}.location: {real_path}:{line}\n")); /// The anchor where the test code body starts. #[allow(unused)] - static __DOCTEST_ANCHOR: i32 = core::line!() as i32 + {body_offset} + 1; + static __DOCTEST_ANCHOR: i32 = ::core::line!() as i32 + {body_offset} + 1; {{ {body} main(); diff --git a/scripts/spelling.txt b/scripts/spelling.txt index a290db720b0f..ac94fa1c2415 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -1240,6 +1240,8 @@ prefered||preferred prefferably||preferably prefitler||prefilter preform||perform +previleged||privileged +previlege||privilege premption||preemption prepaired||prepared prepate||prepare |