diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/Makefile.build | 43 | ||||
-rw-r--r-- | scripts/Makefile.modpost | 14 | ||||
-rw-r--r-- | scripts/Makefile.ubsan | 5 | ||||
-rw-r--r-- | scripts/basic/fixdep.c | 86 | ||||
-rwxr-xr-x | scripts/checkkconfigsymbols.py | 338 | ||||
-rwxr-xr-x | scripts/checkpatch.pl | 338 | ||||
-rwxr-xr-x | scripts/coccicheck | 2 | ||||
-rw-r--r-- | scripts/coccinelle/api/memdup_user.cocci | 8 | ||||
-rw-r--r-- | scripts/coccinelle/api/pm_runtime.cocci | 18 | ||||
-rw-r--r-- | scripts/coccinelle/misc/cond_no_effect.cocci | 64 | ||||
-rw-r--r-- | scripts/const_structs.checkpatch | 64 | ||||
-rwxr-xr-x | scripts/gen_initramfs_list.sh | 5 | ||||
-rw-r--r-- | scripts/genksyms/lex.l | 35 | ||||
-rw-r--r-- | scripts/genksyms/lex.lex.c_shipped | 35 | ||||
-rwxr-xr-x | scripts/kernel-doc | 48 | ||||
-rwxr-xr-x | scripts/link-vmlinux.sh | 71 | ||||
-rw-r--r-- | scripts/mod/modpost.c | 2 | ||||
-rw-r--r-- | scripts/recordmcount.c | 1 | ||||
-rwxr-xr-x | scripts/recordmcount.pl | 1 | ||||
-rw-r--r-- | scripts/spelling.txt | 1 | ||||
-rwxr-xr-x | scripts/tags.sh | 3 | ||||
-rwxr-xr-x | scripts/tracing/ftrace-bisect.sh | 115 | ||||
-rwxr-xr-x | scripts/ver_linux | 260 |
23 files changed, 971 insertions, 586 deletions
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 11602e5efb3b..de46ab03f063 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -81,6 +81,7 @@ endif ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),) lib-target := $(obj)/lib.a +obj-y += $(obj)/lib-ksyms.o endif ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),) @@ -358,12 +359,22 @@ $(sort $(subdir-obj-y)): $(subdir-ym) ; # Rule to compile a set of .o files into one .o file # ifdef builtin-target -quiet_cmd_link_o_target = LD $@ + +ifdef CONFIG_THIN_ARCHIVES + cmd_make_builtin = rm -f $@; $(AR) rcST$(KBUILD_ARFLAGS) + cmd_make_empty_builtin = rm -f $@; $(AR) rcST$(KBUILD_ARFLAGS) + quiet_cmd_link_o_target = AR $@ +else + cmd_make_builtin = $(LD) $(ld_flags) -r -o + cmd_make_empty_builtin = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) + quiet_cmd_link_o_target = LD $@ +endif + # If the list of objects to link is empty, just create an empty built-in.o cmd_link_o_target = $(if $(strip $(obj-y)),\ - $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \ + $(cmd_make_builtin) $@ $(filter $(obj-y), $^) \ $(cmd_secanalysis),\ - rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@) + $(cmd_make_empty_builtin) $@) $(builtin-target): $(obj-y) FORCE $(call if_changed,link_o_target) @@ -389,12 +400,36 @@ $(modorder-target): $(subdir-ym) FORCE # ifdef lib-target quiet_cmd_link_l_target = AR $@ -cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y) + +ifdef CONFIG_THIN_ARCHIVES + cmd_link_l_target = rm -f $@; $(AR) rcsT$(KBUILD_ARFLAGS) $@ $(lib-y) +else + cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y) +endif $(lib-target): $(lib-y) FORCE $(call if_changed,link_l_target) targets += $(lib-target) + +dummy-object = $(obj)/.lib_exports.o +ksyms-lds = $(dot-target).lds +ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX +ref_prefix = EXTERN(_ +else +ref_prefix = EXTERN( +endif + +quiet_cmd_export_list = EXPORTS $@ +cmd_export_list = $(OBJDUMP) -h $< | \ + sed -ne '/___ksymtab/{s/.*+/$(ref_prefix)/;s/ .*/)/;p}' >$(ksyms-lds);\ + rm -f $(dummy-object);\ + $(AR) rcs$(KBUILD_ARFLAGS) $(dummy-object);\ + $(LD) $(ld_flags) -r -o $@ -T $(ksyms-lds) $(dummy-object);\ + rm $(dummy-object) $(ksyms-lds) + +$(obj)/lib-ksyms.o: $(lib-target) FORCE + $(call if_changed,export_list) endif # diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 1366a94b6c39..16923ba4b5b1 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -115,14 +115,18 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE targets += $(modules:.ko=.mod.o) -# Step 6), final link of the modules +ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) + +# Step 6), final link of the modules with optional arch pass after final link quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ - $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ - -o $@ $(filter-out FORCE,$^) + cmd_ld_ko_o = \ + $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ + -o $@ $(filter-out FORCE,$^) ; \ + $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) $(modules): %.ko :%.o %.mod.o FORCE - $(call if_changed,ld_ko_o) + +$(call if_changed,ld_ko_o) targets += $(modules) diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan index 8ab68679cfb5..dd779c40c8e6 100644 --- a/scripts/Makefile.ubsan +++ b/scripts/Makefile.ubsan @@ -3,7 +3,6 @@ ifdef CONFIG_UBSAN CFLAGS_UBSAN += $(call cc-option, -fsanitize=integer-divide-by-zero) CFLAGS_UBSAN += $(call cc-option, -fsanitize=unreachable) CFLAGS_UBSAN += $(call cc-option, -fsanitize=vla-bound) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=null) CFLAGS_UBSAN += $(call cc-option, -fsanitize=signed-integer-overflow) CFLAGS_UBSAN += $(call cc-option, -fsanitize=bounds) CFLAGS_UBSAN += $(call cc-option, -fsanitize=object-size) @@ -14,4 +13,8 @@ ifdef CONFIG_UBSAN ifdef CONFIG_UBSAN_ALIGNMENT CFLAGS_UBSAN += $(call cc-option, -fsanitize=alignment) endif + +ifdef CONFIG_UBSAN_NULL + CFLAGS_UBSAN += $(call cc-option, -fsanitize=null) +endif endif diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 746ec1ece614..fff818b92acb 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -82,8 +82,7 @@ * to date before even starting the recursive build, so it's too late * at this point anyway. * - * The algorithm to grep for "CONFIG_..." is bit unusual, but should - * be fast ;-) We don't even try to really parse the header files, but + * We don't even try to really parse the header files, but * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will * be picked up as well. It's not a problem with respect to * correctness, since that can only give too many dependencies, thus @@ -115,11 +114,6 @@ #include <ctype.h> #include <arpa/inet.h> -#define INT_CONF ntohl(0x434f4e46) -#define INT_ONFI ntohl(0x4f4e4649) -#define INT_NFIG ntohl(0x4e464947) -#define INT_FIG_ ntohl(0x4649475f) - int insert_extra_deps; char *target; char *depfile; @@ -241,37 +235,22 @@ static void use_config(const char *m, int slen) print_config(m, slen); } -static void parse_config_file(const char *map, size_t len) +static void parse_config_file(const char *p) { - const int *end = (const int *) (map + len); - /* start at +1, so that p can never be < map */ - const int *m = (const int *) map + 1; - const char *p, *q; - - for (; m < end; m++) { - if (*m == INT_CONF) { p = (char *) m ; goto conf; } - if (*m == INT_ONFI) { p = (char *) m-1; goto conf; } - if (*m == INT_NFIG) { p = (char *) m-2; goto conf; } - if (*m == INT_FIG_) { p = (char *) m-3; goto conf; } - continue; - conf: - if (p > map + len - 7) - continue; - if (memcmp(p, "CONFIG_", 7)) - continue; + const char *q, *r; + + while ((p = strstr(p, "CONFIG_"))) { p += 7; - for (q = p; q < map + len; q++) { - if (!(isalnum(*q) || *q == '_')) - goto found; - } - continue; - - found: - if (!memcmp(q - 7, "_MODULE", 7)) - q -= 7; - if (q - p < 0) - continue; - use_config(p, q - p); + q = p; + while (*q && (isalnum(*q) || *q == '_')) + q++; + if (memcmp(q - 7, "_MODULE", 7) == 0) + r = q - 7; + else + r = q; + if (r > p) + use_config(p, r - p); + p = q; } } @@ -291,7 +270,7 @@ static void do_config_file(const char *filename) { struct stat st; int fd; - void *map; + char *map; fd = open(filename, O_RDONLY); if (fd < 0) { @@ -308,18 +287,23 @@ static void do_config_file(const char *filename) close(fd); return; } - map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if ((long) map == -1) { - perror("fixdep: mmap"); + map = malloc(st.st_size + 1); + if (!map) { + perror("fixdep: malloc"); close(fd); return; } + if (read(fd, map, st.st_size) != st.st_size) { + perror("fixdep: read"); + close(fd); + return; + } + map[st.st_size] = '\0'; + close(fd); - parse_config_file(map, st.st_size); - - munmap(map, st.st_size); + parse_config_file(map); - close(fd); + free(map); } /* @@ -446,22 +430,8 @@ static void print_deps(void) close(fd); } -static void traps(void) -{ - static char test[] __attribute__((aligned(sizeof(int)))) = "CONF"; - int *p = (int *)test; - - if (*p != INT_CONF) { - fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianness? %#x\n", - *p); - exit(2); - } -} - int main(int argc, char *argv[]) { - traps(); - if (argc == 5 && !strcmp(argv[1], "-e")) { insert_extra_deps = 1; argv++; diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py index df643f60bb41..a32e4da4c117 100755 --- a/scripts/checkkconfigsymbols.py +++ b/scripts/checkkconfigsymbols.py @@ -1,98 +1,99 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """Find Kconfig symbols that are referenced but not defined.""" -# (c) 2014-2015 Valentin Rothberg <valentinrothberg@gmail.com> +# (c) 2014-2016 Valentin Rothberg <valentinrothberg@gmail.com> # (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de> # # Licensed under the terms of the GNU GPL License version 2 +import argparse import difflib import os import re import signal +import subprocess import sys from multiprocessing import Pool, cpu_count -from optparse import OptionParser -from subprocess import Popen, PIPE, STDOUT # regex expressions OPERATORS = r"&|\(|\)|\||\!" -FEATURE = r"(?:\w*[A-Z0-9]\w*){2,}" -DEF = r"^\s*(?:menu){,1}config\s+(" + FEATURE + r")\s*" -EXPR = r"(?:" + OPERATORS + r"|\s|" + FEATURE + r")+" +SYMBOL = r"(?:\w*[A-Z0-9]\w*){2,}" +DEF = r"^\s*(?:menu){,1}config\s+(" + SYMBOL + r")\s*" +EXPR = r"(?:" + OPERATORS + r"|\s|" + SYMBOL + r")+" DEFAULT = r"default\s+.*?(?:if\s.+){,1}" STMT = r"^\s*(?:if|select|depends\s+on|(?:" + DEFAULT + r"))\s+" + EXPR -SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")" +SOURCE_SYMBOL = r"(?:\W|\b)+[D]{,1}CONFIG_(" + SYMBOL + r")" # regex objects REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$") -REGEX_FEATURE = re.compile(r'(?!\B)' + FEATURE + r'(?!\B)') -REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE) +REGEX_SYMBOL = re.compile(r'(?!\B)' + SYMBOL + r'(?!\B)') +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|---help---)\s*$") -REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$") +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("(\"(.*?)\")") def parse_options(): """The user interface of this module.""" - usage = "%prog [options]\n\n" \ - "Run this tool to detect Kconfig symbols that are referenced but " \ - "not defined in\nKconfig. The output of this tool has the " \ - "format \'Undefined symbol\\tFile list\'\n\n" \ - "If no option is specified, %prog will default to check your\n" \ - "current tree. Please note that specifying commits will " \ - "\'git reset --hard\'\nyour current tree! You may save " \ - "uncommitted changes to avoid losing data." - - parser = OptionParser(usage=usage) - - parser.add_option('-c', '--commit', dest='commit', action='store', - default="", - help="Check if the specified commit (hash) introduces " - "undefined Kconfig symbols.") - - parser.add_option('-d', '--diff', dest='diff', action='store', - default="", - help="Diff undefined symbols between two commits. The " - "input format bases on Git log's " - "\'commmit1..commit2\'.") - - parser.add_option('-f', '--find', dest='find', action='store_true', - default=False, - help="Find and show commits that may cause symbols to be " - "missing. Required to run with --diff.") - - parser.add_option('-i', '--ignore', dest='ignore', action='store', - default="", - help="Ignore files matching this pattern. Note that " - "the pattern needs to be a Python regex. To " - "ignore defconfigs, specify -i '.*defconfig'.") - - parser.add_option('-s', '--sim', dest='sim', action='store', default="", - help="Print a list of maximum 10 string-similar symbols.") - - parser.add_option('', '--force', dest='force', action='store_true', - default=False, - help="Reset current Git tree even when it's dirty.") - - (opts, _) = parser.parse_args() - - if opts.commit and opts.diff: + usage = "Run this tool to detect Kconfig symbols that are referenced but " \ + "not defined in Kconfig. If no option is specified, " \ + "checkkconfigsymbols defaults to check your current tree. " \ + "Please note that specifying commits will 'git reset --hard\' " \ + "your current tree! You may save uncommitted changes to avoid " \ + "losing data." + + parser = argparse.ArgumentParser(description=usage) + + parser.add_argument('-c', '--commit', dest='commit', action='store', + default="", + help="check if the specified commit (hash) introduces " + "undefined Kconfig symbols") + + parser.add_argument('-d', '--diff', dest='diff', action='store', + default="", + help="diff undefined symbols between two commits " + "(e.g., -d commmit1..commit2)") + + parser.add_argument('-f', '--find', dest='find', action='store_true', + default=False, + help="find and show commits that may cause symbols to be " + "missing (required to run with --diff)") + + parser.add_argument('-i', '--ignore', dest='ignore', action='store', + default="", + help="ignore files matching this Python regex " + "(e.g., -i '.*defconfig')") + + parser.add_argument('-s', '--sim', dest='sim', action='store', default="", + help="print a list of max. 10 string-similar symbols") + + parser.add_argument('--force', dest='force', action='store_true', + default=False, + help="reset current Git tree even when it's dirty") + + parser.add_argument('--no-color', dest='color', action='store_false', + default=True, + help="don't print colored output (default when not " + "outputting to a terminal)") + + args = parser.parse_args() + + if args.commit and args.diff: sys.exit("Please specify only one option at once.") - if opts.diff and not re.match(r"^[\w\-\.]+\.\.[\w\-\.]+$", opts.diff): + if args.diff and not re.match(r"^[\w\-\.]+\.\.[\w\-\.]+$", args.diff): sys.exit("Please specify valid input in the following format: " "\'commit1..commit2\'") - if opts.commit or opts.diff: - if not opts.force and tree_is_dirty(): + if args.commit or args.diff: + if not args.force and tree_is_dirty(): sys.exit("The current Git tree is dirty (see 'git status'). " "Running this script may\ndelete important data since it " "calls 'git reset --hard' for some performance\nreasons. " @@ -100,138 +101,148 @@ def parse_options(): "'--force' if you\nwant to ignore this warning and " "continue.") - if opts.commit: - opts.find = False + if args.commit: + args.find = False - if opts.ignore: + if args.ignore: try: - re.match(opts.ignore, "this/is/just/a/test.c") + re.match(args.ignore, "this/is/just/a/test.c") except: sys.exit("Please specify a valid Python regex.") - return opts + return args def main(): """Main function of this module.""" - opts = parse_options() + args = parse_options() - if opts.sim and not opts.commit and not opts.diff: - sims = find_sims(opts.sim, opts.ignore) + global COLOR + COLOR = args.color and sys.stdout.isatty() + + if args.sim and not args.commit and not args.diff: + sims = find_sims(args.sim, args.ignore) if sims: - print "%s: %s" % (yel("Similar symbols"), ', '.join(sims)) + print("%s: %s" % (yel("Similar symbols"), ', '.join(sims))) else: - print "%s: no similar symbols found" % yel("Similar symbols") + print("%s: no similar symbols found" % yel("Similar symbols")) sys.exit(0) # dictionary of (un)defined symbols defined = {} undefined = {} - if opts.commit or opts.diff: + if args.commit or args.diff: head = get_head() # get commit range commit_a = None commit_b = None - if opts.commit: - commit_a = opts.commit + "~" - commit_b = opts.commit - elif opts.diff: - split = opts.diff.split("..") + if args.commit: + commit_a = args.commit + "~" + commit_b = args.commit + elif args.diff: + split = args.diff.split("..") commit_a = split[0] commit_b = split[1] undefined_a = {} undefined_b = {} # get undefined items before the commit - execute("git reset --hard %s" % commit_a) - undefined_a, _ = check_symbols(opts.ignore) + reset(commit_a) + undefined_a, _ = check_symbols(args.ignore) # get undefined items for the commit - execute("git reset --hard %s" % commit_b) - undefined_b, defined = check_symbols(opts.ignore) + reset(commit_b) + undefined_b, defined = check_symbols(args.ignore) # report cases that are present for the commit but not before - for feature in sorted(undefined_b): - # feature has not been undefined before - if not feature in undefined_a: - files = sorted(undefined_b.get(feature)) - undefined[feature] = files - # check if there are new files that reference the undefined feature + for symbol in sorted(undefined_b): + # symbol has not been undefined before + if symbol not in undefined_a: + files = sorted(undefined_b.get(symbol)) + undefined[symbol] = files + # check if there are new files that reference the undefined symbol else: - files = sorted(undefined_b.get(feature) - - undefined_a.get(feature)) + files = sorted(undefined_b.get(symbol) - + undefined_a.get(symbol)) if files: - undefined[feature] = files + undefined[symbol] = files # reset to head - execute("git reset --hard %s" % head) + reset(head) # default to check the entire tree else: - undefined, defined = check_symbols(opts.ignore) + undefined, defined = check_symbols(args.ignore) # now print the output - for feature in sorted(undefined): - print red(feature) + for symbol in sorted(undefined): + print(red(symbol)) - files = sorted(undefined.get(feature)) - print "%s: %s" % (yel("Referencing files"), ", ".join(files)) + files = sorted(undefined.get(symbol)) + print("%s: %s" % (yel("Referencing files"), ", ".join(files))) - sims = find_sims(feature, opts.ignore, defined) + sims = find_sims(symbol, args.ignore, defined) sims_out = yel("Similar symbols") if sims: - print "%s: %s" % (sims_out, ', '.join(sims)) + print("%s: %s" % (sims_out, ', '.join(sims))) else: - print "%s: %s" % (sims_out, "no similar symbols found") + print("%s: %s" % (sims_out, "no similar symbols found")) - if opts.find: - print "%s:" % yel("Commits changing symbol") - commits = find_commits(feature, opts.diff) + if args.find: + print("%s:" % yel("Commits changing symbol")) + commits = find_commits(symbol, args.diff) if commits: for commit in commits: commit = commit.split(" ", 1) - print "\t- %s (\"%s\")" % (yel(commit[0]), commit[1]) + print("\t- %s (\"%s\")" % (yel(commit[0]), commit[1])) else: - print "\t- no commit found" - print # new line + print("\t- no commit found") + print() # new line + + +def reset(commit): + """Reset current git tree to %commit.""" + execute(["git", "reset", "--hard", commit]) def yel(string): """ Color %string yellow. """ - return "\033[33m%s\033[0m" % string + return "\033[33m%s\033[0m" % string if COLOR else string def red(string): """ Color %string red. """ - return "\033[31m%s\033[0m" % string + return "\033[31m%s\033[0m" % string if COLOR else string def execute(cmd): """Execute %cmd and return stdout. Exit in case of error.""" - pop = Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True) - (stdout, _) = pop.communicate() # wait until finished - if pop.returncode != 0: - sys.exit(stdout) + try: + stdout = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=False) + stdout = stdout.decode(errors='replace') + except subprocess.CalledProcessError as fail: + exit(fail) return stdout def find_commits(symbol, diff): """Find commits changing %symbol in the given range of %diff.""" - commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s" - % (symbol, diff)) + commits = execute(["git", "log", "--pretty=oneline", + "--abbrev-commit", "-G", + symbol, diff]) return [x for x in commits.split("\n") if x] def tree_is_dirty(): """Return true if the current working tree is dirty (i.e., if any file has been added, deleted, modified, renamed or copied but not committed).""" - stdout = execute("git status --porcelain") + stdout = execute(["git", "status", "--porcelain"]) for line in stdout: if re.findall(r"[URMADC]{1}", line[:2]): return True @@ -240,13 +251,13 @@ def tree_is_dirty(): def get_head(): """Return commit hash of current HEAD.""" - stdout = execute("git rev-parse HEAD") + stdout = execute(["git", "rev-parse", "HEAD"]) return stdout.strip('\n') def partition(lst, size): """Partition list @lst into eveni-sized lists of size @size.""" - return [lst[i::size] for i in xrange(size)] + return [lst[i::size] for i in range(size)] def init_worker(): @@ -254,7 +265,7 @@ def init_worker(): signal.signal(signal.SIGINT, signal.SIG_IGN) -def find_sims(symbol, ignore, defined = []): +def find_sims(symbol, ignore, defined=[]): """Return a list of max. ten Kconfig symbols that are string-similar to @symbol.""" if defined: @@ -279,7 +290,7 @@ def find_sims(symbol, ignore, defined = []): def get_files(): """Return a list of all files in the current git directory.""" # use 'git ls-files' to get the worklist - stdout = execute("git ls-files") + stdout = execute(["git", "ls-files"]) if len(stdout) > 0 and stdout[-1] == "\n": stdout = stdout[:-1] @@ -311,8 +322,8 @@ def check_symbols_helper(pool, ignore): check_symbols() in order to properly terminate running worker processes.""" source_files = [] kconfig_files = [] - defined_features = [] - referenced_features = dict() # {file: [features]} + defined_symbols = [] + referenced_symbols = dict() # {file: [symbols]} for gitfile in get_files(): if REGEX_FILE_KCONFIG.match(gitfile): @@ -326,76 +337,75 @@ def check_symbols_helper(pool, ignore): # parse source files arglist = partition(source_files, cpu_count()) for res in pool.map(parse_source_files, arglist): - referenced_features.update(res) - + referenced_symbols.update(res) # parse kconfig files arglist = [] for part in partition(kconfig_files, cpu_count()): arglist.append((part, ignore)) for res in pool.map(parse_kconfig_files, arglist): - defined_features.extend(res[0]) - referenced_features.update(res[1]) - defined_features = set(defined_features) + defined_symbols.extend(res[0]) + referenced_symbols.update(res[1]) + defined_symbols = set(defined_symbols) - # inverse mapping of referenced_features to dict(feature: [files]) + # inverse mapping of referenced_symbols to dict(symbol: [files]) inv_map = dict() - for _file, features in referenced_features.iteritems(): - for feature in features: - inv_map[feature] = inv_map.get(feature, set()) - inv_map[feature].add(_file) - referenced_features = inv_map - - undefined = {} # {feature: [files]} - for feature in sorted(referenced_features): + for _file, symbols in referenced_symbols.items(): + for symbol in symbols: + inv_map[symbol] = inv_map.get(symbol, set()) + inv_map[symbol].add(_file) + referenced_symbols = inv_map + + undefined = {} # {symbol: [files]} + for symbol in sorted(referenced_symbols): # filter some false positives - if feature == "FOO" or feature == "BAR" or \ - feature == "FOO_BAR" or feature == "XXX": + if symbol == "FOO" or symbol == "BAR" or \ + symbol == "FOO_BAR" or symbol == "XXX": continue - if feature not in defined_features: - if feature.endswith("_MODULE"): + if symbol not in defined_symbols: + if symbol.endswith("_MODULE"): # avoid false positives for kernel modules - if feature[:-len("_MODULE")] in defined_features: + if symbol[:-len("_MODULE")] in defined_symbols: continue - undefined[feature] = referenced_features.get(feature) - return undefined, defined_features + undefined[symbol] = referenced_symbols.get(symbol) + return undefined, defined_symbols def parse_source_files(source_files): """Parse each source file in @source_files and return dictionary with source files as keys and lists of references Kconfig symbols as values.""" - referenced_features = dict() + referenced_symbols = dict() for sfile in source_files: - referenced_features[sfile] = parse_source_file(sfile) - return referenced_features + referenced_symbols[sfile] = parse_source_file(sfile) + return referenced_symbols def parse_source_file(sfile): - """Parse @sfile and return a list of referenced Kconfig features.""" + """Parse @sfile and return a list of referenced Kconfig symbols.""" lines = [] references = [] if not os.path.exists(sfile): return references - with open(sfile, "r") as stream: + with open(sfile, "r", encoding='utf-8', errors='replace') as stream: lines = stream.readlines() for line in lines: - if not "CONFIG_" in line: + if "CONFIG_" not in line: continue - features = REGEX_SOURCE_FEATURE.findall(line) - for feature in features: - if not REGEX_FILTER_FEATURES.search(feature): + symbols = REGEX_SOURCE_SYMBOL.findall(line) + for symbol in symbols: + if not REGEX_FILTER_SYMBOLS.search(symbol): continue - references.append(feature) + references.append(symbol) return references -def get_features_in_line(line): - """Return mentioned Kconfig features in @line.""" - return REGEX_FEATURE.findall(line) +def get_symbols_in_line(line): + """Return mentioned Kconfig symbols in @line.""" + return REGEX_SYMBOL.findall(line) def parse_kconfig_files(args): @@ -404,21 +414,21 @@ def parse_kconfig_files(args): pattern.""" kconfig_files = args[0] ignore = args[1] - defined_features = [] - referenced_features = dict() + defined_symbols = [] + referenced_symbols = dict() for kfile in kconfig_files: defined, references = parse_kconfig_file(kfile) - defined_features.extend(defined) + defined_symbols.extend(defined) if ignore and re.match(ignore, kfile): # do not collect references for files that match the ignore pattern continue - referenced_features[kfile] = references - return (defined_features, referenced_features) + referenced_symbols[kfile] = references + return (defined_symbols, referenced_symbols) def parse_kconfig_file(kfile): - """Parse @kfile and update feature definitions and references.""" + """Parse @kfile and update symbol definitions and references.""" lines = [] defined = [] references = [] @@ -427,7 +437,7 @@ def parse_kconfig_file(kfile): if not os.path.exists(kfile): return defined, references - with open(kfile, "r") as stream: + with open(kfile, "r", encoding='utf-8', errors='replace') as stream: lines = stream.readlines() for i in range(len(lines)): @@ -436,8 +446,8 @@ def parse_kconfig_file(kfile): line = line.split("#")[0] # ignore comments if REGEX_KCONFIG_DEF.match(line): - feature_def = REGEX_KCONFIG_DEF.findall(line) - defined.append(feature_def[0]) + symbol_def = REGEX_KCONFIG_DEF.findall(line) + defined.append(symbol_def[0]) skip = False elif REGEX_KCONFIG_HELP.match(line): skip = True @@ -446,18 +456,18 @@ def parse_kconfig_file(kfile): pass elif REGEX_KCONFIG_STMT.match(line): line = REGEX_QUOTES.sub("", line) - features = get_features_in_line(line) + symbols = get_symbols_in_line(line) # multi-line statements while line.endswith("\\"): i += 1 line = lines[i] line = line.strip('\n') - features.extend(get_features_in_line(line)) - for feature in set(features): - if REGEX_NUMERIC.match(feature): + symbols.extend(get_symbols_in_line(line)) + for symbol in set(symbols): + if REGEX_NUMERIC.match(symbol): # ignore numeric values continue - references.append(feature) + references.append(symbol) return defined, references diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 206a6b346a8d..a8368d1c4348 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -54,6 +54,7 @@ my $min_conf_desc_length = 4; my $spelling_file = "$D/spelling.txt"; my $codespell = 0; my $codespellfile = "/usr/share/codespell/dictionary.txt"; +my $conststructsfile = "$D/const_structs.checkpatch"; my $color = 1; my $allow_c99_comments = 1; @@ -523,7 +524,11 @@ our @mode_permission_funcs = ( ["module_param_array_named", 5], ["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2], ["proc_create(?:_data|)", 2], - ["(?:CLASS|DEVICE|SENSOR)_ATTR", 2], + ["(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR", 2], + ["IIO_DEV_ATTR_[A-Z_]+", 1], + ["SENSOR_(?:DEVICE_|)ATTR_2", 2], + ["SENSOR_TEMPLATE(?:_2|)", 3], + ["__ATTR", 2], ); #Create a search pattern for all these functions to speed up a loop below @@ -541,6 +546,32 @@ our $mode_perms_world_writable = qr{ 0[0-7][0-7][2367] }x; +our %mode_permission_string_types = ( + "S_IRWXU" => 0700, + "S_IRUSR" => 0400, + "S_IWUSR" => 0200, + "S_IXUSR" => 0100, + "S_IRWXG" => 0070, + "S_IRGRP" => 0040, + "S_IWGRP" => 0020, + "S_IXGRP" => 0010, + "S_IRWXO" => 0007, + "S_IROTH" => 0004, + "S_IWOTH" => 0002, + "S_IXOTH" => 0001, + "S_IRWXUGO" => 0777, + "S_IRUGO" => 0444, + "S_IWUGO" => 0222, + "S_IXUGO" => 0111, +); + +#Create a search pattern for all these strings to speed up a loop below +our $mode_perms_string_search = ""; +foreach my $entry (keys %mode_permission_string_types) { + $mode_perms_string_search .= '|' if ($mode_perms_string_search ne ""); + $mode_perms_string_search .= $entry; +} + our $allowed_asm_includes = qr{(?x: irq| memory| @@ -598,6 +629,29 @@ if ($codespell) { $misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix; +my $const_structs = ""; +if (open(my $conststructs, '<', $conststructsfile)) { + while (<$conststructs>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + if ($line =~ /\s/) { + print("$conststructsfile: '$line' invalid - ignored\n"); + next; + } + + $const_structs .= '|' if ($const_structs ne ""); + $const_structs .= $line; + } + close($conststructsfile); +} else { + warn "No structs that should be const will be found - file '$conststructsfile': $!\n"; +} + sub build_types { my $mods = "(?x: \n" . join("|\n ", (@modifierList, @modifierListFile)) . "\n)"; my $all = "(?x: \n" . join("|\n ", (@typeList, @typeListFile)) . "\n)"; @@ -704,6 +758,16 @@ sub seed_camelcase_file { } } +sub is_maintained_obsolete { + my ($filename) = @_; + + return 0 if (!(-e "$root/scripts/get_maintainer.pl")); + + my $status = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`; + + return $status =~ /obsolete/i; +} + my $camelcase_seeded = 0; sub seed_camelcase_includes { return if ($camelcase_seeded); @@ -2289,6 +2353,10 @@ sub process { } if ($found_file) { + if (is_maintained_obsolete($realfile)) { + WARN("OBSOLETE", + "$realfile is marked as 'obsolete' in the MAINTAINERS hierarchy. No unnecessary modifications please.\n"); + } if ($realfile =~ m@^(?:drivers/net/|net/|drivers/staging/)@) { $check = 1; } else { @@ -2939,6 +3007,30 @@ sub process { "Block comments use a trailing */ on a separate line\n" . $herecurr); } +# Block comment * alignment + if ($prevline =~ /$;[ \t]*$/ && #ends in comment + $line =~ /^\+[ \t]*$;/ && #leading comment + $rawline =~ /^\+[ \t]*\*/ && #leading * + (($prevrawline =~ /^\+.*?\/\*/ && #leading /* + $prevrawline !~ /\*\/[ \t]*$/) || #no trailing */ + $prevrawline =~ /^\+[ \t]*\*/)) { #leading * + my $oldindent; + $prevrawline =~ m@^\+([ \t]*/?)\*@; + if (defined($1)) { + $oldindent = expand_tabs($1); + } else { + $prevrawline =~ m@^\+(.*/?)\*@; + $oldindent = expand_tabs($1); + } + $rawline =~ m@^\+([ \t]*)\*@; + my $newindent = $1; + $newindent = expand_tabs($newindent); + if (length($oldindent) ne length($newindent)) { + WARN("BLOCK_COMMENT_STYLE", + "Block comments should align the * on each line\n" . $hereprev); + } + } + # check for missing blank lines after struct/union declarations # with exceptions for various attributes and macros if ($prevline =~ /^[\+ ]};?\s*$/ && @@ -4665,7 +4757,17 @@ sub process { $has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/); $has_arg_concat = 1 if ($ctx =~ /\#\#/ && $ctx !~ /\#\#\s*(?:__VA_ARGS__|args)\b/); - $dstat =~ s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*//; + $dstat =~ s/^.\s*\#\s*define\s+$Ident(\([^\)]*\))?\s*//; + my $define_args = $1; + my $define_stmt = $dstat; + my @def_args = (); + + if (defined $define_args && $define_args ne "") { + $define_args = substr($define_args, 1, length($define_args) - 2); + $define_args =~ s/\s*//g; + @def_args = split(",", $define_args); + } + $dstat =~ s/$;//g; $dstat =~ s/\\\n.//g; $dstat =~ s/^\s*//s; @@ -4701,6 +4803,15 @@ sub process { ^\[ }x; #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; + + $ctx =~ s/\n*$//; + my $herectx = $here . "\n"; + my $stmt_cnt = statement_rawlines($ctx); + + for (my $n = 0; $n < $stmt_cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + if ($dstat ne '' && $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(), $dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo(); @@ -4716,13 +4827,6 @@ sub process { $dstat !~ /^\(\{/ && # ({... $ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/) { - $ctx =~ s/\n*$//; - my $herectx = $here . "\n"; - my $cnt = statement_rawlines($ctx); - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } if ($dstat =~ /;/) { ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", @@ -4731,6 +4835,46 @@ sub process { ERROR("COMPLEX_MACRO", "Macros with complex values should be enclosed in parentheses\n" . "$herectx"); } + + } + + # Make $define_stmt single line, comment-free, etc + my @stmt_array = split('\n', $define_stmt); + my $first = 1; + $define_stmt = ""; + foreach my $l (@stmt_array) { + $l =~ s/\\$//; + if ($first) { + $define_stmt = $l; + $first = 0; + } elsif ($l =~ /^[\+ ]/) { + $define_stmt .= substr($l, 1); + } + } + $define_stmt =~ s/$;//g; + $define_stmt =~ s/\s+/ /g; + $define_stmt = trim($define_stmt); + +# check if any macro arguments are reused (ignore '...' and 'type') + foreach my $arg (@def_args) { + next if ($arg =~ /\.\.\./); + next if ($arg =~ /^type$/i); + my $tmp = $define_stmt; + $tmp =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; + $tmp =~ s/\#+\s*$arg\b//g; + $tmp =~ s/\b$arg\s*\#\#//g; + my $use_cnt = $tmp =~ s/\b$arg\b//g; + if ($use_cnt > 1) { + CHK("MACRO_ARG_REUSE", + "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx"); + } +# check if any macro arguments may have other precedence issues + if ($define_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m && + ((defined($1) && $1 ne ',') || + (defined($2) && $2 ne ','))) { + CHK("MACRO_ARG_PRECEDENCE", + "Macro argument '$arg' may be better as '($arg)' to avoid precedence issues\n" . "$herectx"); + } } # check for macros with flow control, but without ## concatenation @@ -5495,46 +5639,46 @@ sub process { } # Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar) - if ($^V && $^V ge 5.10.0 && - defined $stat && - $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { - if (WARN("PREFER_ETHER_ADDR_COPY", - "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") && - $fix) { - $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/; - } - } +# if ($^V && $^V ge 5.10.0 && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# if (WARN("PREFER_ETHER_ADDR_COPY", +# "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/; +# } +# } # Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar) - if ($^V && $^V ge 5.10.0 && - defined $stat && - $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { - WARN("PREFER_ETHER_ADDR_EQUAL", - "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n") - } +# if ($^V && $^V ge 5.10.0 && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# WARN("PREFER_ETHER_ADDR_EQUAL", +# "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n") +# } # check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr # check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr - if ($^V && $^V ge 5.10.0 && - defined $stat && - $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { - - my $ms_val = $7; - - if ($ms_val =~ /^(?:0x|)0+$/i) { - if (WARN("PREFER_ETH_ZERO_ADDR", - "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") && - $fix) { - $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/; - } - } elsif ($ms_val =~ /^(?:0xff|255)$/i) { - if (WARN("PREFER_ETH_BROADCAST_ADDR", - "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") && - $fix) { - $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/; - } - } - } +# if ($^V && $^V ge 5.10.0 && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# +# my $ms_val = $7; +# +# if ($ms_val =~ /^(?:0x|)0+$/i) { +# if (WARN("PREFER_ETH_ZERO_ADDR", +# "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/; +# } +# } elsif ($ms_val =~ /^(?:0xff|255)$/i) { +# if (WARN("PREFER_ETH_BROADCAST_ADDR", +# "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/; +# } +# } +# } # typecasts on min/max could be min_t/max_t if ($^V && $^V ge 5.10.0 && @@ -5654,6 +5798,19 @@ sub process { "externs should be avoided in .c files\n" . $herecurr); } + if ($realfile =~ /\.[ch]$/ && defined $stat && + $stat =~ /^.\s*(?:extern\s+)?$Type\s*$Ident\s*\(\s*([^{]+)\s*\)\s*;/s && + $1 ne "void") { + my $args = trim($1); + while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) { + my $arg = trim($1); + if ($arg =~ /^$Type$/ && $arg !~ /enum\s+$Ident$/) { + WARN("FUNCTION_ARGUMENTS", + "function definition argument '$arg' should also have an identifier name\n" . $herecurr); + } + } + } + # checks for new __setup's if ($rawline =~ /\b__setup\("([^"]*)"/) { my $name = $1; @@ -5853,46 +6010,6 @@ sub process { } # check for various structs that are normally const (ops, kgdb, device_tree) - my $const_structs = qr{ - acpi_dock_ops| - address_space_operations| - backlight_ops| - block_device_operations| - dentry_operations| - dev_pm_ops| - dma_map_ops| - extent_io_ops| - file_lock_operations| - file_operations| - hv_ops| - ide_dma_ops| - intel_dvo_dev_ops| - item_operations| - iwl_ops| - kgdb_arch| - kgdb_io| - kset_uevent_ops| - lock_manager_operations| - microcode_ops| - mtrr_ops| - neigh_ops| - nlmsvc_binding| - of_device_id| - pci_raw_ops| - pipe_buf_operations| - platform_hibernation_ops| - platform_suspend_ops| - proto_ops| - rpc_pipe_ops| - seq_operations| - snd_ac97_build_ops| - soc_pcmcia_socket_ops| - stacktrace_ops| - sysfs_ops| - tty_operations| - uart_ops| - usb_mon_operations| - wd_ops}x; if ($line !~ /\bconst\b/ && $line =~ /\bstruct\s+($const_structs)\b/) { WARN("CONST_STRUCT", @@ -5979,34 +6096,69 @@ sub process { # Mode permission misuses where it seems decimal should be octal # This uses a shortcut match to avoid unnecessary uses of a slow foreach loop if ($^V && $^V ge 5.10.0 && + defined $stat && $line =~ /$mode_perms_search/) { foreach my $entry (@mode_permission_funcs) { my $func = $entry->[0]; my $arg_pos = $entry->[1]; + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + my $skip_args = ""; if ($arg_pos > 1) { $arg_pos--; $skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}"; } - my $test = "\\b$func\\s*\\(${skip_args}([\\d]+)\\s*[,\\)]"; - if ($line =~ /$test/) { + my $test = "\\b$func\\s*\\(${skip_args}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]"; + if ($stat =~ /$test/) { my $val = $1; $val = $6 if ($skip_args ne ""); - - if ($val !~ /^0$/ && - (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || - length($val) ne 4)) { + if (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || + ($val =~ /^$Octal$/ && length($val) ne 4)) { ERROR("NON_OCTAL_PERMISSIONS", - "Use 4 digit octal (0777) not decimal permissions\n" . $herecurr); - } elsif ($val =~ /^$Octal$/ && (oct($val) & 02)) { + "Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real); + } + if ($val =~ /^$Octal$/ && (oct($val) & 02)) { ERROR("EXPORTED_WORLD_WRITABLE", - "Exporting writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); + "Exporting writable files is usually an error. Consider more restrictive permissions.\n" . "$here\n" . $stat_real); } } } } +# check for uses of S_<PERMS> that could be octal for readability + if ($line =~ /\b$mode_perms_string_search\b/) { + my $val = ""; + my $oval = ""; + my $to = 0; + my $curpos = 0; + my $lastpos = 0; + while ($line =~ /\b(($mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) { + $curpos = pos($line); + my $match = $2; + my $omatch = $1; + last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos)); + $lastpos = $curpos; + $to |= $mode_permission_string_types{$match}; + $val .= '\s*\|\s*' if ($val ne ""); + $val .= $match; + $oval .= $omatch; + } + $oval =~ s/^\s*\|\s*//; + $oval =~ s/\s*\|\s*$//; + my $octal = sprintf("%04o", $to); + if (WARN("SYMBOLIC_PERMS", + "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/$val/$octal/; + } + } + # validate content of MODULE_LICENSE against list from include/linux/module.h if ($line =~ /\bMODULE_LICENSE\s*\(\s*($String)\s*\)/) { my $extracted_string = get_quoted_string($line, $rawline); diff --git a/scripts/coccicheck b/scripts/coccicheck index c92c1528a54d..ec487b8e7051 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -1,7 +1,7 @@ #!/bin/bash # Linux kernel coccicheck # -# Read Documentation/coccinelle.txt +# Read Documentation/dev-tools/coccinelle.rst # # This script requires at least spatch # version 1.0.0-rc11. diff --git a/scripts/coccinelle/api/memdup_user.cocci b/scripts/coccinelle/api/memdup_user.cocci index c606231b0e46..2a5aea8e8487 100644 --- a/scripts/coccinelle/api/memdup_user.cocci +++ b/scripts/coccinelle/api/memdup_user.cocci @@ -15,11 +15,11 @@ virtual org virtual report @depends on patch@ -expression from,to,size,flag; +expression from,to,size; identifier l1,l2; @@ -- to = \(kmalloc\|kzalloc\)(size,flag); +- to = \(kmalloc\|kzalloc\)(size,GFP_KERNEL); + to = memdup_user(from,size); if ( - to==NULL @@ -37,12 +37,12 @@ identifier l1,l2; - } @r depends on !patch@ -expression from,to,size,flag; +expression from,to,size; position p; statement S1,S2; @@ -* to = \(kmalloc@p\|kzalloc@p\)(size,flag); +* to = \(kmalloc@p\|kzalloc@p\)(size,GFP_KERNEL); if (to==NULL || ...) S1 if (copy_from_user(to, from, size) != 0) S2 diff --git a/scripts/coccinelle/api/pm_runtime.cocci b/scripts/coccinelle/api/pm_runtime.cocci index 89b98a2f7a6f..d67ccf5f8227 100644 --- a/scripts/coccinelle/api/pm_runtime.cocci +++ b/scripts/coccinelle/api/pm_runtime.cocci @@ -17,9 +17,10 @@ virtual report @runtime_bad_err_handle exists@ expression ret; +position p; @@ ( -ret = \(pm_runtime_idle\| +ret@p = \(pm_runtime_idle\| pm_runtime_suspend\| pm_runtime_autosuspend\| pm_runtime_resume\| @@ -47,12 +48,13 @@ IS_ERR_VALUE(ret) // For context mode //---------------------------------------------------------- -@depends on runtime_bad_err_handle && context@ +@depends on context@ identifier pm_runtime_api; expression ret; +position runtime_bad_err_handle.p; @@ ( -ret = pm_runtime_api(...); +ret@p = pm_runtime_api(...); ... * IS_ERR_VALUE(ret) ... @@ -62,12 +64,13 @@ ret = pm_runtime_api(...); // For patch mode //---------------------------------------------------------- -@depends on runtime_bad_err_handle && patch@ +@depends on patch@ identifier pm_runtime_api; expression ret; +position runtime_bad_err_handle.p; @@ ( -ret = pm_runtime_api(...); +ret@p = pm_runtime_api(...); ... - IS_ERR_VALUE(ret) + ret < 0 @@ -78,13 +81,14 @@ ret = pm_runtime_api(...); // For org and report mode //---------------------------------------------------------- -@r depends on runtime_bad_err_handle && (org || report) exists@ +@r depends on (org || report) exists@ position p1, p2; identifier pm_runtime_api; expression ret; +position runtime_bad_err_handle.p; @@ ( -ret = pm_runtime_api@p1(...); +ret@p = pm_runtime_api@p1(...); ... IS_ERR_VALUE@p2(ret) ... diff --git a/scripts/coccinelle/misc/cond_no_effect.cocci b/scripts/coccinelle/misc/cond_no_effect.cocci new file mode 100644 index 000000000000..8467dbd1c465 --- /dev/null +++ b/scripts/coccinelle/misc/cond_no_effect.cocci @@ -0,0 +1,64 @@ +///Find conditions where if and else branch are functionally +// identical. +// +// There can be false positives in cases where the positional +// information is used (as with lockdep) or where the identity +// is a placeholder for not yet handled cases. +// Unfortunately there also seems to be a tendency to use +// the last if else/else as a "default behavior" - which some +// might consider a legitimate coding pattern. From discussion +// on kernelnewbies though it seems that this is not really an +// accepted pattern and if at all it would need to be commented +// +// In the Linux kernel it does not seem to actually report +// false positives except for those that were documented as +// being intentional. +// the two known cases are: +// arch/sh/kernel/traps_64.c:read_opcode() +// } else if ((pc & 1) == 0) { +// /* SHcompact */ +// /* TODO : provide handling for this. We don't really support +// user-mode SHcompact yet, and for a kernel fault, this would +// have to come from a module built for SHcompact. */ +// return -EFAULT; +// } else { +// /* misaligned */ +// return -EFAULT; +// } +// fs/kernfs/file.c:kernfs_fop_open() +// * Both paths of the branch look the same. They're supposed to +// * look that way and give @of->mutex different static lockdep keys. +// */ +// if (has_mmap) +// mutex_init(&of->mutex); +// else +// mutex_init(&of->mutex); +// +// All other cases look like bugs or at least lack of documentation +// +// Confidence: Moderate +// Copyright: (C) 2016 Nicholas Mc Guire, OSADL. GPLv2. +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report + +@cond@ +statement S1; +position p; +@@ + +* if@p (...) S1 else S1 + +@script:python depends on org@ +p << cond.p; +@@ + +cocci.print_main("WARNING: possible condition with no effect (if == else)",p) + +@script:python depends on report@ +p << cond.p; +@@ + +coccilib.report.print_report(p[0],"WARNING: possible condition with no effect (if == else)") diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch new file mode 100644 index 000000000000..ac5f1267151d --- /dev/null +++ b/scripts/const_structs.checkpatch @@ -0,0 +1,64 @@ +acpi_dock_ops +address_space_operations +backlight_ops +block_device_operations +clk_ops +comedi_lrange +component_ops +dentry_operations +dev_pm_ops +dma_map_ops +driver_info +drm_connector_funcs +drm_encoder_funcs +drm_encoder_helper_funcs +ethtool_ops +extent_io_ops +file_lock_operations +file_operations +hv_ops +ide_dma_ops +ide_port_ops +inode_operations +intel_dvo_dev_ops +irq_domain_ops +item_operations +iwl_cfg +iwl_ops +kgdb_arch +kgdb_io +kset_uevent_ops +lock_manager_operations +machine_desc +microcode_ops +mlxsw_reg_info +mtrr_ops +neigh_ops +net_device_ops +nlmsvc_binding +nvkm_device_chip +of_device_id +pci_raw_ops +pipe_buf_operations +platform_hibernation_ops +platform_suspend_ops +proto_ops +regmap_access_table +rpc_pipe_ops +rtc_class_ops +sd_desc +seq_operations +sirfsoc_padmux +snd_ac97_build_ops +snd_soc_component_driver +soc_pcmcia_socket_ops +stacktrace_ops +sysfs_ops +tty_operations +uart_ops +usb_mon_operations +v4l2_ctrl_ops +v4l2_ioctl_ops +vm_operations_struct +wacom_features +wd_ops diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index 17fa901418ae..0055b07b03b6 100755 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -97,7 +97,10 @@ print_mtime() { } list_parse() { - [ ! -L "$1" ] && echo "$1 \\" || : + if [ -L "$1" ]; then + return + fi + echo "$1" | sed 's/:/\\:/g; s/$/ \\/' } # for each file print a line in following format diff --git a/scripts/genksyms/lex.l b/scripts/genksyms/lex.l index e583565f2011..5235aa507ba5 100644 --- a/scripts/genksyms/lex.l +++ b/scripts/genksyms/lex.l @@ -289,6 +289,23 @@ repeat: } break; + case ST_TYPEOF_1: + if (token == IDENT) + { + if (is_reserved_word(yytext, yyleng) + || find_symbol(yytext, SYM_TYPEDEF, 1)) + { + yyless(0); + unput('('); + lexstate = ST_NORMAL; + token = TYPEOF_KEYW; + break; + } + _APP("(", 1); + } + lexstate = ST_TYPEOF; + /* FALLTHRU */ + case ST_TYPEOF: switch (token) { @@ -313,24 +330,6 @@ repeat: } break; - case ST_TYPEOF_1: - if (token == IDENT) - { - if (is_reserved_word(yytext, yyleng) - || find_symbol(yytext, SYM_TYPEDEF, 1)) - { - yyless(0); - unput('('); - lexstate = ST_NORMAL; - token = TYPEOF_KEYW; - break; - } - _APP("(", 1); - } - APP; - lexstate = ST_TYPEOF; - goto repeat; - case ST_BRACKET: APP; switch (token) diff --git a/scripts/genksyms/lex.lex.c_shipped b/scripts/genksyms/lex.lex.c_shipped index f82740a69b85..985c5541aae4 100644 --- a/scripts/genksyms/lex.lex.c_shipped +++ b/scripts/genksyms/lex.lex.c_shipped @@ -2098,6 +2098,23 @@ repeat: } break; + case ST_TYPEOF_1: + if (token == IDENT) + { + if (is_reserved_word(yytext, yyleng) + || find_symbol(yytext, SYM_TYPEDEF, 1)) + { + yyless(0); + unput('('); + lexstate = ST_NORMAL; + token = TYPEOF_KEYW; + break; + } + _APP("(", 1); + } + lexstate = ST_TYPEOF; + /* FALLTHRU */ + case ST_TYPEOF: switch (token) { @@ -2122,24 +2139,6 @@ repeat: } break; - case ST_TYPEOF_1: - if (token == IDENT) - { - if (is_reserved_word(yytext, yyleng) - || find_symbol(yytext, SYM_TYPEDEF, 1)) - { - yyless(0); - unput('('); - lexstate = ST_NORMAL; - token = TYPEOF_KEYW; - break; - } - _APP("(", 1); - } - APP; - lexstate = ST_TYPEOF; - goto repeat; - case ST_BRACKET: APP; switch (token) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 4f2e9049e8fa..93721f3c91bf 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -212,6 +212,7 @@ my $anon_struct_union = 0; my $type_constant = '\%([-_\w]+)'; my $type_func = '(\w+)\(\)'; my $type_param = '\@(\w+)'; +my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params my $type_struct = '\&((struct\s*)*[_\w]+)'; my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; my $type_env = '(\$\w+)'; @@ -292,6 +293,7 @@ my @highlights_rst = ( # Note: need to escape () to avoid func matching later [$type_member_func, "\\:c\\:type\\:`\$1\$2\\\\(\\\\) <\$1>`"], [$type_member, "\\:c\\:type\\:`\$1\$2 <\$1>`"], + [$type_fp_param, "**\$1\\\\(\\\\)**"], [$type_func, "\\:c\\:func\\:`\$1()`"], [$type_struct_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], [$type_enum_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], @@ -412,7 +414,7 @@ my $doc_com_body = '\s*\* ?'; my $doc_decl = $doc_com . '(\w+)'; # @params and a strictly limited set of supported section names 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*$'; @@ -1831,13 +1833,22 @@ sub output_function_rst(%) { my %args = %{$_[0]}; my ($parameter, $section); my $oldprefix = $lineprefix; - my $start; - - print ".. c:function:: "; + my $start = ""; + + if ($args{'typedef'}) { + print ".. c:type:: ". $args{'function'} . "\n\n"; + print_lineno($declaration_start_line); + print " **Typedef**: "; + $lineprefix = ""; + output_highlight_rst($args{'purpose'}); + $start = "\n\n**Syntax**\n\n ``"; + } else { + print ".. c:function:: "; + } if ($args{'functiontype'} ne "") { - $start = $args{'functiontype'} . " " . $args{'function'} . " ("; + $start .= $args{'functiontype'} . " " . $args{'function'} . " ("; } else { - $start = $args{'function'} . " ("; + $start .= $args{'function'} . " ("; } print $start; @@ -1849,9 +1860,6 @@ sub output_function_rst(%) { $count++; $type = $args{'parametertypes'}{$parameter}; - # RST doesn't like address_space tags at function prototypes - $type =~ s/__(user|kernel|iomem|percpu|pmem|rcu)\s*//; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print $1 . $parameter . ") (" . $2; @@ -1859,11 +1867,15 @@ sub output_function_rst(%) { print $type . " " . $parameter; } } - print ")\n\n"; - print_lineno($declaration_start_line); - $lineprefix = " "; - output_highlight_rst($args{'purpose'}); - print "\n"; + if ($args{'typedef'}) { + print ");``\n\n"; + } else { + print ")\n\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; + } print "**Parameters**\n\n"; $lineprefix = " "; @@ -2003,7 +2015,7 @@ sub output_struct_rst(%) { ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; print_lineno($parameterdesc_start_lines{$parameter_name}); - print "``$type $parameter``\n"; + print "``" . $parameter . "``\n"; output_highlight_rst($args{'parameterdescs'}{$parameter_name}); print "\n"; } @@ -2193,7 +2205,9 @@ sub dump_typedef($$) { $x =~ s@/\*.*?\*/@@gos; # strip comments. # Parse function prototypes - if ($x =~ /typedef\s+(\w+)\s*\(\*\s*(\w\S+)\s*\)\s*\((.*)\);/) { + if ($x =~ /typedef\s+(\w+)\s*\(\*\s*(\w\S+)\s*\)\s*\((.*)\);/ || + $x =~ /typedef\s+(\w+)\s*(\w\S+)\s*\s*\((.*)\);/) { + # Function typedefs $return_type = $1; $declaration_name = $2; @@ -2204,6 +2218,7 @@ sub dump_typedef($$) { output_declaration($declaration_name, 'function', {'function' => $declaration_name, + 'typedef' => 1, 'module' => $modulename, 'functiontype' => $return_type, 'parameterlist' => \@parameterlist, @@ -2338,6 +2353,7 @@ sub push_parameter($$$) { if ($type eq "" && $param =~ /\.\.\.$/) { + $param = "..."; if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { $parameterdescs{$param} = "variable arguments"; } diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 4f727eb5ec43..f742c65108b9 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -37,12 +37,40 @@ info() fi } +# Thin archive build here makes a final archive with +# symbol table and indexes from vmlinux objects, which can be +# used as input to linker. +# +# Traditional incremental style of link does not require this step +# +# built-in.o output file +# +archive_builtin() +{ + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + info AR built-in.o + rm -f built-in.o; + ${AR} rcsT${KBUILD_ARFLAGS} built-in.o \ + ${KBUILD_VMLINUX_INIT} \ + ${KBUILD_VMLINUX_MAIN} + fi +} + # Link of vmlinux.o used for section mismatch analysis # ${1} output file modpost_link() { - ${LD} ${LDFLAGS} -r -o ${1} ${KBUILD_VMLINUX_INIT} \ - --start-group ${KBUILD_VMLINUX_MAIN} --end-group + local objects + + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + objects="--whole-archive built-in.o" + else + objects="${KBUILD_VMLINUX_INIT} \ + --start-group \ + ${KBUILD_VMLINUX_MAIN} \ + --end-group" + fi + ${LD} ${LDFLAGS} -r -o ${1} ${objects} } # Link of vmlinux @@ -51,18 +79,36 @@ modpost_link() vmlinux_link() { local lds="${objtree}/${KBUILD_LDS}" + local objects if [ "${SRCARCH}" != "um" ]; then - ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ - -T ${lds} ${KBUILD_VMLINUX_INIT} \ - --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1} + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + objects="--whole-archive built-in.o ${1}" + else + objects="${KBUILD_VMLINUX_INIT} \ + --start-group \ + ${KBUILD_VMLINUX_MAIN} \ + --end-group \ + ${1}" + fi + + ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ + -T ${lds} ${objects} else - ${CC} ${CFLAGS_vmlinux} -o ${2} \ - -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT} \ - -Wl,--start-group \ - ${KBUILD_VMLINUX_MAIN} \ - -Wl,--end-group \ - -lutil -lrt -lpthread ${1} + if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + objects="-Wl,--whole-archive built-in.o ${1}" + else + objects="${KBUILD_VMLINUX_INIT} \ + -Wl,--start-group \ + ${KBUILD_VMLINUX_MAIN} \ + -Wl,--end-group \ + ${1}" + fi + + ${CC} ${CFLAGS_vmlinux} -o ${2} \ + -Wl,-T,${lds} \ + ${objects} \ + -lutil -lrt -lpthread rm -f linux fi } @@ -119,6 +165,7 @@ cleanup() rm -f .tmp_kallsyms* rm -f .tmp_version rm -f .tmp_vmlinux* + rm -f built-in.o rm -f System.map rm -f vmlinux rm -f vmlinux.o @@ -162,6 +209,8 @@ case "${KCONFIG_CONFIG}" in . "./${KCONFIG_CONFIG}" esac +archive_builtin + #link vmlinux.o info LD vmlinux.o modpost_link vmlinux.o diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 48958d3cec9e..bd8349759095 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -888,7 +888,7 @@ static void check_section(const char *modname, struct elf_info *elf, #define DATA_SECTIONS ".data", ".data.rel" #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ - ".kprobes.text" + ".kprobes.text", ".cpuidle.text" #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ ".fixup", ".entry.text", ".exception.text", ".text.*", \ ".coldtext" diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index a68f03133df9..5423a58d1b06 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -365,6 +365,7 @@ is_mcounted_section_name(char const *const txtname) strcmp(".irqentry.text", txtname) == 0 || strcmp(".softirqentry.text", txtname) == 0 || strcmp(".kprobes.text", txtname) == 0 || + strcmp(".cpuidle.text", txtname) == 0 || strcmp(".text.unlikely", txtname) == 0; } diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 2d48011bc362..faac4b10d8ea 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -136,6 +136,7 @@ my %text_sections = ( ".irqentry.text" => 1, ".softirqentry.text" => 1, ".kprobes.text" => 1, + ".cpuidle.text" => 1, ".text.unlikely" => 1, ); diff --git a/scripts/spelling.txt b/scripts/spelling.txt index fa79c6d2a5b8..163c720d3f2b 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -629,7 +629,6 @@ mispelt||misspelt miximum||maximum mmnemonic||mnemonic mnay||many -modeled||modelled modulues||modules monochorome||monochrome monochromo||monochrome diff --git a/scripts/tags.sh b/scripts/tags.sh index b3775a9604ea..a2ff3388e5ea 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -263,7 +263,8 @@ exuberant() -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL,ACPI_EXPORT_SYMBOL \ -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ -I static,const \ - --extra=+f --c-kinds=+px --langmap=c:+.h "${regex[@]}" + --extra=+fq --c-kinds=+px --fields=+iaS --langmap=c:+.h \ + "${regex[@]}" setup_regex exuberant kconfig all_kconfigs | xargs $1 -a \ diff --git a/scripts/tracing/ftrace-bisect.sh b/scripts/tracing/ftrace-bisect.sh new file mode 100755 index 000000000000..9ff8ac5fc53c --- /dev/null +++ b/scripts/tracing/ftrace-bisect.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# +# Here's how to use this: +# +# This script is used to help find functions that are being traced by function +# tracer or function graph tracing that causes the machine to reboot, hang, or +# crash. Here's the steps to take. +# +# First, determine if function tracing is working with a single function: +# +# (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 +# # echo schedule > set_ftrace_filter +# # echo function > current_tracer +# +# If this works, then we know that something is being traced that shouldn't be. +# +# # echo nop > current_tracer +# +# # cat available_filter_functions > ~/full-file +# # 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 +# # mv ~/test-file ~/full-file +# +# If it didn't crash. +# +# # echo nop > current_tracer +# # mv ~/non-test-file ~/full-file +# +# Get rid of the other test file from previous run (or save them off somewhere). +# # rm -f ~/test-file ~/non-test-file +# +# And start again: +# +# # ftrace-bisect ~/full-file ~/test-file ~/non-test-file +# +# The good thing is, because this cuts the number of functions in ~/test-file +# by half, the cat of it into set_ftrace_filter takes half as long each +# iteration, so don't talk so much at the water cooler the second time. +# +# Eventually, if you did this correctly, you will get down to the problem +# function, and all we need to do is to notrace it. +# +# The way to figure out if the problem function is bad, just do: +# +# # echo <problem-function> > set_ftrace_notrace +# # echo > set_ftrace_filter +# # echo function > current_tracer +# +# And if it doesn't crash, we are done. +# +# If it does crash, do this again (there's more than one problem function) +# but you need to echo the problem function(s) into set_ftrace_notrace before +# enabling function tracing in the above steps. Or if you can compile the +# kernel, annotate the problem functions with "notrace" and start again. +# + + +if [ $# -ne 3 ]; then + echo 'usage: ftrace-bisect full-file test-file non-test-file' + exit +fi + +full=$1 +test=$2 +nontest=$3 + +x=`cat $full | wc -l` +if [ $x -eq 1 ]; then + echo "There's only one function left, must be the bad one" + cat $full + exit 0 +fi + +let x=$x/2 +let y=$x+1 + +if [ ! -f $full ]; then + echo "$full does not exist" + exit 1 +fi + +if [ -f $test ]; then + echo -n "$test exists, delete it? [y/N]" + read a + if [ "$a" != "y" -a "$a" != "Y" ]; then + exit 1 + fi +fi + +if [ -f $nontest ]; then + echo -n "$nontest exists, delete it? [y/N]" + read a + if [ "$a" != "y" -a "$a" != "Y" ]; then + exit 1 + fi +fi + +sed -ne "1,${x}p" $full > $test +sed -ne "$y,\$p" $full > $nontest diff --git a/scripts/ver_linux b/scripts/ver_linux index 0d8bd29b1bd6..430b201f3e25 100755 --- a/scripts/ver_linux +++ b/scripts/ver_linux @@ -1,193 +1,89 @@ -#!/bin/sh +#!/bin/awk -f # Before running this script please ensure that your PATH is # typical as you use for compilation/installation. I use # /bin /sbin /usr/bin /usr/sbin /usr/local/bin, but it may # differ on your system. -# -echo 'If some fields are empty or look unusual you may have an old version.' -echo 'Compare to the current minimal requirements in Documentation/Changes.' -echo ' ' -uname -a -echo ' ' - -gcc -dumpversion 2>&1 | -awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("GNU C\t\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -make --version 2>&1 | -awk '/GNU Make/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("GNU Make\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -ld -v 2>&1 | -awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Binutils\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -mount --version 2>&1 | -awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - $0 = substr($0,RSTART,RLENGTH) - printf("Util-linux\t\t%s\nMount\t\t\t%s\n",$0,$0) -}' - -depmod -V 2>&1 | -awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Module-init-tools\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -tune2fs 2>&1 | -awk '/^tune2fs/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("E2fsprogs\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -fsck.jfs -V 2>&1 | -awk '/version/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Jfsutils\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -reiserfsck -V 2>&1 | -awk '/^reiserfsck/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Reiserfsprogs\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -fsck.reiser4 -V 2>&1 | grep ^fsck.reiser4 | awk \ -'NR==1{print "reiser4progs ", $2}' - -xfs_db -V 2>&1 | -awk '/version/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Xfsprogs\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -pccardctl -V 2>&1 | -awk '/pcmciautils/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Pcmciautils\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -cardmgr -V 2>&1| grep version | awk \ -'NR==1{print "pcmcia-cs ", $3}' - -quota -V 2>&1 | -awk '/version/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Quota-tools\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -pppd --version 2>&1 | -awk '/version/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("PPP\t\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -isdnctrl 2>&1 | grep version | awk \ -'NR==1{print "isdn4k-utils ", $NF}' - -showmount --version 2>&1 | grep nfs-utils | awk \ -'NR==1{print "nfs-utils ", $NF}' - -test -r /proc/self/maps && -sed ' - /.*libc-\(.*\)\.so$/!d - s//Linux C Library\t\t\1/ - q -' /proc/self/maps - -ldd --version 2>&1 | -awk '/^ldd/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Dynamic linker (ldd)\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -libcpp=`ldconfig -p 2>/dev/null | - awk '/(libg|stdc)[+]+\.so/ { - print $NF - exit +BEGIN { + usage = "If some fields are empty or look unusual you may have an old version.\n" + usage = usage "Compare to the current minimal requirements in Documentation/Changes.\n" + print usage + + system("uname -a") + printf("\n") + + printversion("GNU C", version("gcc -dumpversion 2>&1")) + printversion("GNU Make", version("make --version 2>&1")) + printversion("Binutils", version("ld -v 2>&1")) + printversion("Util-linux", version("mount --version 2>&1")) + printversion("Mount", version("mount --version 2>&1")) + printversion("Module-init-tools", version("depmod -V 2>&1")) + printversion("E2fsprogs", version("tune2fs 2>&1")) + printversion("Jfsutils", version("fsck.jfs -V 2>&1")) + printversion("Reiserfsprogs", version("reiserfsck -V 2>&1")) + printversion("Reiser4fsprogs", version("fsck.reiser4 -V 2>&1")) + printversion("Xfsprogs", version("xfs_db -V 2>&1")) + printversion("Pcmciautils", version("pccardctl -V 2>&1")) + printversion("Pcmcia-cs", version("cardmgr -V 2>&1")) + printversion("Quota-tools", version("quota -V 2>&1")) + printversion("PPP", version("pppd --version 2>&1")) + printversion("Isdn4k-utils", version("isdnctrl 2>&1")) + printversion("Nfs-utils", version("showmount --version 2>&1")) + + if (system("test -r /proc/self/maps") == 0) { + while (getline <"/proc/self/maps" > 0) { + n = split($0, procmaps, "/") + if (/libc.*so$/ && match(procmaps[n], /[0-9]+([.]?[0-9]+)+/)) { + ver = substr(procmaps[n], RSTART, RLENGTH) + printversion("Linux C Library", ver) + break + } + } } -'` -test -r "$libcpp" && -ls -l $libcpp | -sed ' - s!.*so\.!! - s!^!Linux C++ Library\t! -' -ps --version 2>&1 | -awk '/version/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Procps\t\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -ifconfig --version 2>&1 | -awk '/tools/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Net-tools\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -loadkeys -V 2>&1 | -awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - $0 = substr($0,RSTART,RLENGTH) - printf("Kbd\t\t\t%s\nConsole-tools\t\t%s\n",$0,$0) -}' -oprofiled --version 2>&1 | awk \ -'(NR==1 && ($2 == "oprofile")) {print "oprofile ", $3}' + printversion("Dynamic linker (ldd)", version("ldd --version 2>&1")) -expr --v 2>&1 | -awk '/^expr/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Sh-utils\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' - -udevadm --version 2>&1 | -awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Udev\t\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' + while ("ldconfig -p 2>/dev/null" | getline > 0) { + if (/(libg|stdc)[+]+\.so/) { + libcpp = $NF + break + } + } + if (system("test -r " libcpp) == 0) + printversion("Linux C++ Library", version("readlink " libcpp)) + + printversion("Procps", version("ps --version 2>&1")) + printversion("Net-tools", version("ifconfig --version 2>&1")) + printversion("Kbd", version("loadkeys -V 2>&1")) + printversion("Console-tools", version("loadkeys -V 2>&1")) + printversion("Oprofile", version("oprofiled --version 2>&1")) + printversion("Sh-utils", version("expr --v 2>&1")) + printversion("Udev", version("udevadm --version 2>&1")) + printversion("Wireless-tools", version("iwconfig --version 2>&1")) + + if (system("test -r /proc/modules") == 0) { + while ("sort /proc/modules" | getline > 0) { + mods = mods sep $1 + sep = " " + } + printversion("Modules Loaded", mods) + } +} -iwconfig --version 2>&1 | -awk '/version/{ - match($0, /[0-9]+([.]?[0-9]+)+/) - printf("Wireless-tools\t\t%s\n", - substr($0,RSTART,RLENGTH)) -}' +function version(cmd, ver) { + while (cmd | getline > 0) { + if (!/ver_linux/ && match($0, /[0-9]+([.]?[0-9]+)+/)) { + ver = substr($0, RSTART, RLENGTH) + break + } + } + close(cmd) + return ver +} -test -e /proc/modules && -sort /proc/modules | -sed ' - s/ .*// - H -${ - g - s/^\n/Modules Loaded\t\t/ - y/\n/ / - q +function printversion(name, value, ofmt) { + if (value != "") { + ofmt = "%-20s\t%s\n" + printf(ofmt, name, value) + } } - d -' |