diff options
Diffstat (limited to 'scripts')
39 files changed, 1493 insertions, 246 deletions
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index b2ab2a92a375..0f82314621f2 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -7,6 +7,7 @@ quote := " squote := ' empty := space := $(empty) $(empty) +space_escape := _-_SPACE_-_ ### # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o @@ -226,10 +227,10 @@ objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) # See Documentation/kbuild/makefiles.txt for more info ifneq ($(KBUILD_NOCMDDEP),1) -# Check if both arguments has same arguments. Result is empty string if equal. -# User may override this check using make KBUILD_NOCMDDEP=1 -arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ - $(filter-out $(cmd_$@), $(cmd_$(1))) ) +# Check if both arguments are the same including their order. Result is empty +# string if equal. User may override this check using make KBUILD_NOCMDDEP=1 +arg-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \ + $(subst $(space),$(space_escape),$(strip $(cmd_$1)))) else arg-check = $(if $(strip $(cmd_$@)),,1) endif @@ -256,10 +257,42 @@ if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ # Execute the command and also postprocess generated .d dependencies file. if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \ @set -e; \ + $(cmd_and_fixdep), @:) + +ifndef CONFIG_TRIM_UNUSED_KSYMS + +cmd_and_fixdep = \ $(echo-cmd) $(cmd_$(1)); \ scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\ rm -f $(depfile); \ - mv -f $(dot-target).tmp $(dot-target).cmd, @:) + mv -f $(dot-target).tmp $(dot-target).cmd; + +else + +# Filter out exported kernel symbol names from the preprocessor output. +# See also __KSYM_DEPS__ in include/linux/export.h. +# We disable the depfile generation here, so as not to overwrite the existing +# depfile while fixdep is parsing it. +flags_nodeps = $(filter-out -Wp$(comma)-M%, $($(1))) +ksym_dep_filter = \ + case "$(1)" in \ + cc_*_c|cpp_i_c) \ + $(CPP) $(call flags_nodeps,c_flags) -D__KSYM_DEPS__ $< ;; \ + as_*_S|cpp_s_S) \ + $(CPP) $(call flags_nodeps,a_flags) -D__KSYM_DEPS__ $< ;; \ + boot*|build*|*cpp_lds_S|dtc|host*|vdso*) : ;; \ + *) echo "Don't know how to preprocess $(1)" >&2; false ;; \ + esac | tr ";" "\n" | sed -rn 's/^.*=== __KSYM_(.*) ===.*$$/KSYM_\1/p' + +cmd_and_fixdep = \ + $(echo-cmd) $(cmd_$(1)); \ + $(ksym_dep_filter) | \ + scripts/basic/fixdep -e $(depfile) $@ '$(make-cmd)' \ + > $(dot-target).tmp; \ + rm -f $(depfile); \ + mv -f $(dot-target).tmp $(dot-target).cmd; + +endif # Usage: $(call if_changed_rule,foo) # Will check if $(cmd_foo) or any of the prerequisites changed, @@ -341,8 +374,6 @@ endif # ############################################################################### # -space_escape := %%%SPACE%%% -# define config_filename ifneq ($$(CONFIG_$(1)),"") $(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1))))))) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index e1bc1907090e..0d1ca5bf42fb 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -152,11 +152,11 @@ cmd_cc_s_c = $(CC) $(c_flags) $(DISABLE_LTO) -fverbose-asm -S -o $@ $< $(obj)/%.s: $(src)/%.c FORCE $(call if_changed_dep,cc_s_c) -quiet_cmd_cc_i_c = CPP $(quiet_modtag) $@ -cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $< +quiet_cmd_cpp_i_c = CPP $(quiet_modtag) $@ +cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $< $(obj)/%.i: $(src)/%.c FORCE - $(call if_changed_dep,cc_i_c) + $(call if_changed_dep,cpp_i_c) cmd_gensymtypes = \ $(CPP) -D__GENKSYMS__ $(c_flags) $< | \ @@ -266,26 +266,24 @@ endif # CONFIG_STACK_VALIDATION define rule_cc_o_c $(call echo-cmd,checksrc) $(cmd_checksrc) \ - $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \ + $(call cmd_and_fixdep,cc_o_c) \ $(cmd_modversions) \ - $(cmd_objtool) \ - $(call echo-cmd,record_mcount) \ - $(cmd_record_mcount) \ - scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \ - $(dot-target).tmp; \ - rm -f $(depfile); \ - mv -f $(dot-target).tmp $(dot-target).cmd + $(cmd_objtool) \ + $(call echo-cmd,record_mcount) $(cmd_record_mcount) endef define rule_as_o_S - $(call echo-cmd,as_o_S) $(cmd_as_o_S); \ - $(cmd_objtool) \ - scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,as_o_S)' > \ - $(dot-target).tmp; \ - rm -f $(depfile); \ - mv -f $(dot-target).tmp $(dot-target).cmd + $(call cmd_and_fixdep,as_o_S) \ + $(cmd_objtool) endef +# List module undefined symbols (or empty line if not enabled) +ifdef CONFIG_TRIM_UNUSED_KSYMS +cmd_undef_syms = $(NM) $@ | sed -n 's/^ \+U //p' | xargs echo +else +cmd_undef_syms = echo +endif + # Built-in and composite module parts $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_obj) FORCE $(call cmd,force_checksrc) @@ -296,7 +294,8 @@ $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_obj) FORCE $(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_obj) FORCE $(call cmd,force_checksrc) $(call if_changed_rule,cc_o_c) - @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod) + @{ echo $(@:.o=.ko); echo $@; \ + $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod) quiet_cmd_cc_lst_c = MKLST $@ cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \ @@ -314,11 +313,11 @@ modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL) $(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) $(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) -quiet_cmd_as_s_S = CPP $(quiet_modtag) $@ -cmd_as_s_S = $(CPP) $(a_flags) -o $@ $< +quiet_cmd_cpp_s_S = CPP $(quiet_modtag) $@ +cmd_cpp_s_S = $(CPP) $(a_flags) -o $@ $< $(obj)/%.s: $(src)/%.S FORCE - $(call if_changed_dep,as_s_S) + $(call if_changed_dep,cpp_s_S) quiet_cmd_as_o_S = AS $(quiet_modtag) $@ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< @@ -426,7 +425,8 @@ $(call multi_depend, $(multi-used-y), .o, -objs -y) $(multi-used-m): FORCE $(call if_changed,link_multi-m) - @{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod) + @{ echo $(@:.o=.ko); echo $(link_multi_deps); \ + $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod) $(call multi_depend, $(multi-used-m), .o, -objs -y -m) targets += $(multi-used-y) $(multi-used-m) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index f9e47a70509c..53449a6ff6aa 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -24,6 +24,7 @@ warning-1 += $(call cc-option, -Wmissing-prototypes) warning-1 += -Wold-style-definition warning-1 += $(call cc-option, -Wmissing-include-dirs) warning-1 += $(call cc-option, -Wunused-but-set-variable) +warning-1 += $(call cc-option, -Wunused-const-variable) warning-1 += $(call cc-disable-warning, missing-field-initializers) warning-1 += $(call cc-disable-warning, sign-compare) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index ddf83d0181e7..e7df0f5db7ec 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -96,10 +96,10 @@ obj-dirs := $(addprefix $(obj)/,$(obj-dirs)) # Note: Files that end up in two or more modules are compiled without the # KBUILD_MODNAME definition. The reason is that any made-up name would # differ in different configs. -name-fix = $(subst $(comma),_,$(subst -,_,$1)) -basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" +name-fix = $(squote)$(quote)$(subst $(comma),_,$(subst -,_,$1))$(quote)$(squote) +basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget)) modname_flags = $(if $(filter 1,$(words $(modname))),\ - -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") + -DKBUILD_MODNAME=$(call name-fix,$(modname))) orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \ $(ccflags-y) $(CFLAGS_$(basetarget).o) @@ -162,7 +162,7 @@ endif c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ $(__c_flags) $(modkern_cflags) \ - -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) + $(basename_flags) $(modname_flags) a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ $(__a_flags) $(modkern_aflags) @@ -277,6 +277,11 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \ # --------------------------------------------------------------------------- DTC ?= $(objtree)/scripts/dtc/dtc +# Disable noisy checks by default +ifeq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),) +DTC_FLAGS += -Wno-unit_address_vs_reg +endif + # Generate an assembly file to wrap the output of the device tree compiler quiet_cmd_dt_S_dtb= DTB $@ cmd_dt_S_dtb= \ diff --git a/scripts/adjust_autoksyms.sh b/scripts/adjust_autoksyms.sh new file mode 100755 index 000000000000..8dc1918b6783 --- /dev/null +++ b/scripts/adjust_autoksyms.sh @@ -0,0 +1,101 @@ +#!/bin/sh + +# Script to create/update include/generated/autoksyms.h and dependency files +# +# Copyright: (C) 2016 Linaro Limited +# Created by: Nicolas Pitre, January 2016 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +# Create/update the include/generated/autoksyms.h file from the list +# of all module's needed symbols as recorded on the third line of +# .tmp_versions/*.mod files. +# +# For each symbol being added or removed, the corresponding dependency +# file's timestamp is updated to force a rebuild of the affected source +# file. All arguments passed to this script are assumed to be a command +# to be exec'd to trigger a rebuild of those files. + +set -e + +cur_ksyms_file="include/generated/autoksyms.h" +new_ksyms_file="include/generated/autoksyms.h.tmpnew" + +info() { + if [ "$quiet" != "silent_" ]; then + printf " %-7s %s\n" "$1" "$2" + fi +} + +info "CHK" "$cur_ksyms_file" + +# Use "make V=1" to debug this script. +case "$KBUILD_VERBOSE" in +*1*) + set -x + ;; +esac + +# We need access to CONFIG_ symbols +case "${KCONFIG_CONFIG}" in +*/*) + . "${KCONFIG_CONFIG}" + ;; +*) + # Force using a file from the current directory + . "./${KCONFIG_CONFIG}" +esac + +# In case it doesn't exist yet... +if [ -e "$cur_ksyms_file" ]; then touch "$cur_ksyms_file"; fi + +# Generate a new ksym list file with symbols needed by the current +# set of modules. +cat > "$new_ksyms_file" << EOT +/* + * Automatically generated file; DO NOT EDIT. + */ + +EOT +sed -ns -e '3{s/ /\n/g;/^$/!p;}' "$MODVERDIR"/*.mod | sort -u | +while read sym; do + if [ -n "$CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX" ]; then + sym="${sym#_}" + fi + echo "#define __KSYM_${sym} 1" +done >> "$new_ksyms_file" + +# Special case for modversions (see modpost.c) +if [ -n "$CONFIG_MODVERSIONS" ]; then + echo "#define __KSYM_module_layout 1" >> "$new_ksyms_file" +fi + +# Extract changes between old and new list and touch corresponding +# dependency files. +changed=$( +count=0 +sort "$cur_ksyms_file" "$new_ksyms_file" | uniq -u | +sed -n 's/^#define __KSYM_\(.*\) 1/\1/p' | tr "A-Z_" "a-z/" | +while read sympath; do + if [ -z "$sympath" ]; then continue; fi + depfile="include/config/ksym/${sympath}.h" + mkdir -p "$(dirname "$depfile")" + touch "$depfile" + echo $((count += 1)) +done | tail -1 ) +changed=${changed:-0} + +if [ $changed -gt 0 ]; then + # Replace the old list with tne new one + old=$(grep -c "^#define __KSYM_" "$cur_ksyms_file" || true) + new=$(grep -c "^#define __KSYM_" "$new_ksyms_file" || true) + info "KSYMS" "symbols: before=$old, after=$new, changed=$changed" + info "UPD" "$cur_ksyms_file" + mv -f "$new_ksyms_file" "$cur_ksyms_file" + # Then trigger a rebuild of affected source files + exec $@ +else + rm -f "$new_ksyms_file" +fi diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c index e000f44e37b8..c1b7ef3e24c1 100644 --- a/scripts/asn1_compiler.c +++ b/scripts/asn1_compiler.c @@ -650,7 +650,7 @@ int main(int argc, char **argv) } hdr = fopen(headername, "w"); - if (!out) { + if (!hdr) { perror(headername); exit(1); } diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index caef815d1743..746ec1ece614 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -120,13 +120,15 @@ #define INT_NFIG ntohl(0x4e464947) #define INT_FIG_ ntohl(0x4649475f) +int insert_extra_deps; char *target; char *depfile; char *cmdline; static void usage(void) { - fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n"); + fprintf(stderr, "Usage: fixdep [-e] <depfile> <target> <cmdline>\n"); + fprintf(stderr, " -e insert extra dependencies given on stdin\n"); exit(1); } @@ -138,6 +140,40 @@ static void print_cmdline(void) printf("cmd_%s := %s\n\n", target, cmdline); } +/* + * Print out a dependency path from a symbol name + */ +static void print_config(const char *m, int slen) +{ + int c, i; + + printf(" $(wildcard include/config/"); + for (i = 0; i < slen; i++) { + c = m[i]; + if (c == '_') + c = '/'; + else + c = tolower(c); + putchar(c); + } + printf(".h) \\\n"); +} + +static void do_extra_deps(void) +{ + if (insert_extra_deps) { + char buf[80]; + while(fgets(buf, sizeof(buf), stdin)) { + int len = strlen(buf); + if (len < 2 || buf[len-1] != '\n') { + fprintf(stderr, "fixdep: bad data on stdin\n"); + exit(1); + } + print_config(buf, len-1); + } + } +} + struct item { struct item *next; unsigned int len; @@ -197,23 +233,12 @@ static void define_config(const char *name, int len, unsigned int hash) static void use_config(const char *m, int slen) { unsigned int hash = strhash(m, slen); - int c, i; if (is_defined_config(m, slen, hash)) return; define_config(m, slen, hash); - - printf(" $(wildcard include/config/"); - for (i = 0; i < slen; i++) { - c = m[i]; - if (c == '_') - c = '/'; - else - c = tolower(c); - putchar(c); - } - printf(".h) \\\n"); + print_config(m, slen); } static void parse_config_file(const char *map, size_t len) @@ -250,7 +275,7 @@ static void parse_config_file(const char *map, size_t len) } } -/* test is s ends in sub */ +/* test if s ends in sub */ static int strrcmp(const char *s, const char *sub) { int slen = strlen(s); @@ -333,6 +358,7 @@ static void parse_dep_file(void *map, size_t len) /* Ignore certain dependencies */ if (strrcmp(s, "include/generated/autoconf.h") && + strrcmp(s, "include/generated/autoksyms.h") && strrcmp(s, "arch/um/include/uml-config.h") && strrcmp(s, "include/linux/kconfig.h") && strrcmp(s, ".ver")) { @@ -378,6 +404,8 @@ static void parse_dep_file(void *map, size_t len) exit(1); } + do_extra_deps(); + printf("\n%s: $(deps_%s)\n\n", target, target); printf("$(deps_%s):\n", target); } @@ -434,7 +462,10 @@ int main(int argc, char *argv[]) { traps(); - if (argc != 4) + if (argc == 5 && !strcmp(argv[1], "-e")) { + insert_extra_deps = 1; + argv++; + } else if (argc != 4) usage(); depfile = argv[1]; diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter index 38b64f487315..0254f3ba0dba 100755 --- a/scripts/bloat-o-meter +++ b/scripts/bloat-o-meter @@ -32,18 +32,21 @@ old = getsizes(sys.argv[1]) new = getsizes(sys.argv[2]) grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0 delta, common = [], {} +otot, ntot = 0, 0 for a in old: if a in new: common[a] = 1 for name in old: + otot += old[name] if name not in common: remove += 1 down += old[name] delta.append((-old[name], name)) for name in new: + ntot += new[name] if name not in common: add += 1 up += new[name] @@ -63,3 +66,6 @@ print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \ print("%-40s %7s %7s %+7s" % ("function", "old", "new", "delta")) for d, n in delta: if d: print("%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d)) + +print("Total: Before=%d, After=%d, chg %f%%" % \ + (otot, ntot, (ntot - otot)*100/otot)) diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py index d8f6c094cce5..df643f60bb41 100755 --- a/scripts/checkkconfigsymbols.py +++ b/scripts/checkkconfigsymbols.py @@ -89,7 +89,7 @@ def parse_options(): if opts.diff and not re.match(r"^[\w\-\.]+\.\.[\w\-\.]+$", opts.diff): sys.exit("Please specify valid input in the following format: " - "\'commmit1..commit2\'") + "\'commit1..commit2\'") if opts.commit or opts.diff: if not opts.force and tree_is_dirty(): diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d574d13ba963..6750595bd7b8 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -27,12 +27,15 @@ my $emacs = 0; my $terse = 0; my $showfile = 0; my $file = 0; +my $git = 0; +my %git_commits = (); my $check = 0; my $check_orig = 0; my $summary = 1; my $mailback = 0; my $summary_file = 0; my $show_types = 0; +my $list_types = 0; my $fix = 0; my $fix_inplace = 0; my $root; @@ -68,13 +71,24 @@ Options: --emacs emacs compile window format --terse one line per report --showfile emit diffed file position, not input file position + -g, --git treat FILE as a single commit or git revision range + single git commit with: + <rev> + <rev>^ + <rev>~n + multiple git commits with: + <rev1>..<rev2> + <rev1>...<rev2> + <rev>-<count> + git merges are ignored -f, --file treat FILE as regular source file --subjective, --strict enable more subjective tests + --list-types list the possible message types --types TYPE(,TYPE2...) show only these comma separated message types --ignore TYPE(,TYPE2...) ignore various comma separated message types + --show-types show the specific message type in the output --max-line-length=n set the maximum line length, if exceeded, warn --min-conf-desc-length=n set the min description length, if shorter, warn - --show-types show the message "types" in the output --root=PATH PATH to the kernel tree root --no-summary suppress the per-file summary --mailback only produce a report in case of warnings/errors @@ -106,6 +120,37 @@ EOM exit($exitcode); } +sub uniq { + my %seen; + return grep { !$seen{$_}++ } @_; +} + +sub list_types { + my ($exitcode) = @_; + + my $count = 0; + + local $/ = undef; + + open(my $script, '<', abs_path($P)) or + die "$P: Can't read '$P' $!\n"; + + my $text = <$script>; + close($script); + + my @types = (); + for ($text =~ /\b(?:(?:CHK|WARN|ERROR)\s*\(\s*"([^"]+)")/g) { + push (@types, $_); + } + @types = sort(uniq(@types)); + print("#\tMessage type\n\n"); + foreach my $type (@types) { + print(++$count . "\t" . $type . "\n"); + } + + exit($exitcode); +} + my $conf = which_conf($configuration_file); if (-f $conf) { my @conf_args; @@ -141,11 +186,13 @@ GetOptions( 'terse!' => \$terse, 'showfile!' => \$showfile, 'f|file!' => \$file, + 'g|git!' => \$git, 'subjective!' => \$check, 'strict!' => \$check, 'ignore=s' => \@ignore, 'types=s' => \@use, 'show-types!' => \$show_types, + 'list-types!' => \$list_types, 'max-line-length=i' => \$max_line_length, 'min-conf-desc-length=i' => \$min_conf_desc_length, 'root=s' => \$root, @@ -166,6 +213,8 @@ GetOptions( help(0) if ($help); +list_types(0) if ($list_types); + $fix = 1 if ($fix_inplace); $check_orig = $check; @@ -752,10 +801,42 @@ my @fixed_inserted = (); my @fixed_deleted = (); my $fixlinenr = -1; +# If input is git commits, extract all commits from the commit expressions. +# For example, HEAD-3 means we need check 'HEAD, HEAD~1, HEAD~2'. +die "$P: No git repository found\n" if ($git && !-e ".git"); + +if ($git) { + my @commits = (); + foreach my $commit_expr (@ARGV) { + my $git_range; + if ($commit_expr =~ m/^(.*)-(\d+)$/) { + $git_range = "-$2 $1"; + } elsif ($commit_expr =~ m/\.\./) { + $git_range = "$commit_expr"; + } else { + $git_range = "-1 $commit_expr"; + } + my $lines = `git log --no-color --no-merges --pretty=format:'%H %s' $git_range`; + foreach my $line (split(/\n/, $lines)) { + $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/; + next if (!defined($1) || !defined($2)); + my $sha1 = $1; + my $subject = $2; + unshift(@commits, $sha1); + $git_commits{$sha1} = $subject; + } + } + die "$P: no git commits after extraction!\n" if (@commits == 0); + @ARGV = @commits; +} + my $vname; for my $filename (@ARGV) { my $FILE; - if ($file) { + if ($git) { + open($FILE, '-|', "git format-patch -M --stdout -1 $filename") || + die "$P: $filename: git format-patch failed - $!\n"; + } elsif ($file) { open($FILE, '-|', "diff -u /dev/null $filename") || die "$P: $filename: diff failed - $!\n"; } elsif ($filename eq '-') { @@ -766,6 +847,8 @@ for my $filename (@ARGV) { } if ($filename eq '-') { $vname = 'Your patch'; + } elsif ($git) { + $vname = "Commit " . substr($filename, 0, 12) . ' ("' . $git_commits{$filename} . '")'; } else { $vname = $filename; } @@ -2755,6 +2838,19 @@ sub process { "Logical continuations should be on the previous line\n" . $hereprev); } +# check indentation starts on a tab stop + if ($^V && $^V ge 5.10.0 && + $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$))/) { + my $indent = length($1); + if ($indent % 8) { + if (WARN("TABSTOP", + "Statements should start on a tabstop\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/8)@e; + } + } + } + # check multi-line statement indentation matches previous line if ($^V && $^V ge 5.10.0 && $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|$Ident\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) { @@ -4291,7 +4387,7 @@ sub process { my $comp = $3; my $to = $4; my $newcomp = $comp; - if ($lead !~ /$Operators\s*$/ && + if ($lead !~ /(?:$Operators|\.)\s*$/ && $to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ && WARN("CONSTANT_COMPARISON", "Comparisons should place the constant on the right side of the test\n" . $herecurr) && @@ -5637,6 +5733,16 @@ sub process { } } +# check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE + if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(CONFIG_[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) { + my $config = $1; + if (WARN("PREFER_IS_ENABLED", + "Prefer IS_ENABLED(<FOO>) to CONFIG_<FOO> || CONFIG_<FOO>_MODULE\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = "\+#if IS_ENABLED($config)"; + } + } + # check for case / default statements not preceded by break/fallthrough/switch if ($line =~ /^.\s*(?:case\s+(?:$Ident|$Constant)\s*|default):/) { my $has_break = 0; @@ -5827,6 +5933,28 @@ sub process { } } +# whine about ACCESS_ONCE + if ($^V && $^V ge 5.10.0 && + $line =~ /\bACCESS_ONCE\s*$balanced_parens\s*(=(?!=))?\s*($FuncArg)?/) { + my $par = $1; + my $eq = $2; + my $fun = $3; + $par =~ s/^\(\s*(.*)\s*\)$/$1/; + if (defined($eq)) { + if (WARN("PREFER_WRITE_ONCE", + "Prefer WRITE_ONCE(<FOO>, <BAR>) over ACCESS_ONCE(<FOO>) = <BAR>\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)\s*$eq\s*\Q$fun\E/WRITE_ONCE($par, $fun)/; + } + } else { + if (WARN("PREFER_READ_ONCE", + "Prefer READ_ONCE(<FOO>) over ACCESS_ONCE(<FOO>)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)/READ_ONCE($par)/; + } + } + } + # check for lockdep_set_novalidate_class if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ || $line =~ /__lockdep_no_validate__\s*\)/ ) { @@ -5930,6 +6058,14 @@ sub process { } if ($quiet == 0) { + # If there were any defects found and not already fixing them + if (!$clean and !$fix) { + print << "EOM" + +NOTE: For some of the reported defects, checkpatch may be able to + mechanically convert to the typical style using --fix or --fix-inplace. +EOM + } # If there were whitespace errors which cleanpatch can fix # then suggest that. if ($rpt_cleaners) { diff --git a/scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci b/scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci new file mode 100644 index 000000000000..85cf5408d378 --- /dev/null +++ b/scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci @@ -0,0 +1,67 @@ +/// Use DEFINE_DEBUGFS_ATTRIBUTE rather than DEFINE_SIMPLE_ATTRIBUTE +/// for debugfs files. +/// +//# Rationale: DEFINE_SIMPLE_ATTRIBUTE + debugfs_create_file() +//# imposes some significant overhead as compared to +//# DEFINE_DEBUGFS_ATTRIBUTE + debugfs_create_file_unsafe(). +// +// Copyright (C): 2016 Nicolai Stange +// Options: --no-includes +// + +virtual context +virtual patch +virtual org +virtual report + +@dsa@ +declarer name DEFINE_SIMPLE_ATTRIBUTE; +identifier dsa_fops; +expression dsa_get, dsa_set, dsa_fmt; +position p; +@@ +DEFINE_SIMPLE_ATTRIBUTE@p(dsa_fops, dsa_get, dsa_set, dsa_fmt); + +@dcf@ +expression name, mode, parent, data; +identifier dsa.dsa_fops; +@@ +debugfs_create_file(name, mode, parent, data, &dsa_fops) + + +@context_dsa depends on context && dcf@ +declarer name DEFINE_DEBUGFS_ATTRIBUTE; +identifier dsa.dsa_fops; +expression dsa.dsa_get, dsa.dsa_set, dsa.dsa_fmt; +@@ +* DEFINE_SIMPLE_ATTRIBUTE(dsa_fops, dsa_get, dsa_set, dsa_fmt); + + +@patch_dcf depends on patch expression@ +expression name, mode, parent, data; +identifier dsa.dsa_fops; +@@ +- debugfs_create_file(name, mode, parent, data, &dsa_fops) ++ debugfs_create_file_unsafe(name, mode, parent, data, &dsa_fops) + +@patch_dsa depends on patch_dcf && patch@ +identifier dsa.dsa_fops; +expression dsa.dsa_get, dsa.dsa_set, dsa.dsa_fmt; +@@ +- DEFINE_SIMPLE_ATTRIBUTE(dsa_fops, dsa_get, dsa_set, dsa_fmt); ++ DEFINE_DEBUGFS_ATTRIBUTE(dsa_fops, dsa_get, dsa_set, dsa_fmt); + + +@script:python depends on org && dcf@ +fops << dsa.dsa_fops; +p << dsa.p; +@@ +msg="%s should be defined with DEFINE_DEBUGFS_ATTRIBUTE" % (fops) +coccilib.org.print_todo(p[0], msg) + +@script:python depends on report && dcf@ +fops << dsa.dsa_fops; +p << dsa.p; +@@ +msg="WARNING: %s should be defined with DEFINE_DEBUGFS_ATTRIBUTE" % (fops) +coccilib.report.print_report(p[0], msg) diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 00d6d53c2681..c332684e1b5a 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -2,15 +2,17 @@ # (c) 2014, Sasha Levin <sasha.levin@oracle.com> #set -x -if [[ $# != 2 ]]; then +if [[ $# < 2 ]]; then echo "Usage:" - echo " $0 [vmlinux] [base path]" + echo " $0 [vmlinux] [base path] [modules path]" exit 1 fi vmlinux=$1 basepath=$2 +modpath=$3 declare -A cache +declare -A modcache parse_symbol() { # The structure of symbol at this point is: @@ -19,6 +21,17 @@ parse_symbol() { # For example: # do_basic_setup+0x9c/0xbf + if [[ $module == "" ]] ; then + local objfile=$vmlinux + elif [[ "${modcache[$module]+isset}" == "isset" ]]; then + local objfile=${modcache[$module]} + else + [[ $modpath == "" ]] && return + local objfile=$(find "$modpath" -name $module.ko -print -quit) + [[ $objfile == "" ]] && return + modcache[$module]=$objfile + fi + # Remove the englobing parenthesis symbol=${symbol#\(} symbol=${symbol%\)} @@ -29,11 +42,11 @@ parse_symbol() { # Use 'nm vmlinux' to figure out the base address of said symbol. # It's actually faster to call it every time than to load it # all into bash. - if [[ "${cache[$name]+isset}" == "isset" ]]; then - local base_addr=${cache[$name]} + if [[ "${cache[$module,$name]+isset}" == "isset" ]]; then + local base_addr=${cache[$module,$name]} else - local base_addr=$(nm "$vmlinux" | grep -i ' t ' | awk "/ $name\$/ {print \$1}" | head -n1) - cache["$name"]="$base_addr" + local base_addr=$(nm "$objfile" | grep -i ' t ' | awk "/ $name\$/ {print \$1}" | head -n1) + cache[$module,$name]="$base_addr" fi # Let's start doing the math to get the exact address into the # symbol. First, strip out the symbol total length. @@ -48,12 +61,12 @@ parse_symbol() { local address=$(printf "%x\n" "$expr") # Pass it to addr2line to get filename and line number - # Could get more than one result - if [[ "${cache[$address]+isset}" == "isset" ]]; then - local code=${cache[$address]} + # Could get more than one result + if [[ "${cache[$module,$address]+isset}" == "isset" ]]; then + local code=${cache[$module,$address]} else - local code=$(addr2line -i -e "$vmlinux" "$address") - cache[$address]=$code + local code=$(addr2line -i -e "$objfile" "$address") + cache[$module,$address]=$code fi # addr2line doesn't return a proper error code if it fails, so @@ -105,13 +118,23 @@ handle_line() { fi done - # The symbol is the last element, process it - symbol=${words[$last]} + if [[ ${words[$last]} =~ \[([^]]+)\] ]]; then + module=${words[$last]} + module=${module#\[} + module=${module%\]} + symbol=${words[$last-1]} + unset words[$last-1] + else + # The symbol is the last element, process it + symbol=${words[$last]} + module= + fi + unset words[$last] parse_symbol # modifies $symbol # Add up the line number to the symbol - echo "${words[@]}" "$symbol" + echo "${words[@]}" "$symbol $module" } while read line; do @@ -121,8 +144,8 @@ while read line; do handle_line "$line" # Is it a code line? elif [[ $line == *Code:* ]]; then - decode_code "$line" - else + decode_code "$line" + else # Nothing special in this line, show it as is echo "$line" fi diff --git a/scripts/docproc.c b/scripts/docproc.c index e267e621431a..0a12593b9041 100644 --- a/scripts/docproc.c +++ b/scripts/docproc.c @@ -42,8 +42,10 @@ #include <unistd.h> #include <limits.h> #include <errno.h> +#include <getopt.h> #include <sys/types.h> #include <sys/wait.h> +#include <time.h> /* exitstatus is used to keep track of any failing calls to kernel-doc, * but execution continues. */ @@ -68,12 +70,23 @@ FILELINE * docsection; #define KERNELDOCPATH "scripts/" #define KERNELDOC "kernel-doc" #define DOCBOOK "-docbook" +#define RST "-rst" #define LIST "-list" #define FUNCTION "-function" #define NOFUNCTION "-nofunction" #define NODOCSECTIONS "-no-doc-sections" #define SHOWNOTFOUND "-show-not-found" +enum file_format { + FORMAT_AUTO, + FORMAT_DOCBOOK, + FORMAT_RST, +}; + +static enum file_format file_format = FORMAT_AUTO; + +#define KERNELDOC_FORMAT (file_format == FORMAT_RST ? RST : DOCBOOK) + static char *srctree, *kernsrctree; static char **all_list = NULL; @@ -95,7 +108,7 @@ static void consume_symbol(const char *sym) static void usage (void) { - fprintf(stderr, "Usage: docproc {doc|depend} file\n"); + fprintf(stderr, "Usage: docproc [{--docbook|--rst}] {doc|depend} file\n"); fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n"); fprintf(stderr, "doc: frontend when generating kernel documentation\n"); fprintf(stderr, "depend: generate list of files referenced within file\n"); @@ -242,7 +255,7 @@ static void find_export_symbols(char * filename) /* * Document all external or internal functions in a file. * Call kernel-doc with following parameters: - * kernel-doc -docbook -nofunction function_name1 filename + * kernel-doc [-docbook|-rst] -nofunction function_name1 filename * Function names are obtained from all the src files * by find_export_symbols. * intfunc uses -nofunction @@ -263,7 +276,7 @@ static void docfunctions(char * filename, char * type) exit(1); } vec[idx++] = KERNELDOC; - vec[idx++] = DOCBOOK; + vec[idx++] = KERNELDOC_FORMAT; vec[idx++] = NODOCSECTIONS; for (i=0; i < symfilecnt; i++) { struct symfile * sym = &symfilelist[i]; @@ -275,7 +288,10 @@ static void docfunctions(char * filename, char * type) } vec[idx++] = filename; vec[idx] = NULL; - printf("<!-- %s -->\n", filename); + if (file_format == FORMAT_RST) + printf(".. %s\n", filename); + else + printf("<!-- %s -->\n", filename); exec_kernel_doc(vec); fflush(stdout); free(vec); @@ -294,7 +310,7 @@ static void singfunc(char * filename, char * line) int i, idx = 0; int startofsym = 1; vec[idx++] = KERNELDOC; - vec[idx++] = DOCBOOK; + vec[idx++] = KERNELDOC_FORMAT; vec[idx++] = SHOWNOTFOUND; /* Split line up in individual parameters preceded by FUNCTION */ @@ -343,7 +359,7 @@ static void docsect(char *filename, char *line) free(s); vec[0] = KERNELDOC; - vec[1] = DOCBOOK; + vec[1] = KERNELDOC_FORMAT; vec[2] = SHOWNOTFOUND; vec[3] = FUNCTION; vec[4] = line; @@ -431,6 +447,32 @@ static void find_all_symbols(char *filename) } /* + * Terminate s at first space, if any. If there was a space, return pointer to + * the character after that. Otherwise, return pointer to the terminating NUL. + */ +static char *chomp(char *s) +{ + while (*s && !isspace(*s)) + s++; + + if (*s) + *s++ = '\0'; + + return s; +} + +/* Return pointer to directive content, or NULL if not a directive. */ +static char *is_directive(char *line) +{ + if (file_format == FORMAT_DOCBOOK && line[0] == '!') + return line + 1; + else if (file_format == FORMAT_RST && !strncmp(line, ".. !", 4)) + return line + 4; + + return NULL; +} + +/* * Parse file, calling action specific functions for: * 1) Lines containing !E * 2) Lines containing !I @@ -443,63 +485,75 @@ static void find_all_symbols(char *filename) static void parse_file(FILE *infile) { char line[MAXLINESZ]; - char * s; + char *p, *s; while (fgets(line, MAXLINESZ, infile)) { - if (line[0] == '!') { - s = line + 2; - switch (line[1]) { - case 'E': - while (*s && !isspace(*s)) s++; - *s = '\0'; - externalfunctions(line+2); - break; - case 'I': - while (*s && !isspace(*s)) s++; - *s = '\0'; - internalfunctions(line+2); - break; - case 'D': - while (*s && !isspace(*s)) s++; - *s = '\0'; - symbolsonly(line+2); - break; - case 'F': - /* filename */ - while (*s && !isspace(*s)) s++; - *s++ = '\0'; - /* function names */ - while (isspace(*s)) - s++; - singlefunctions(line +2, s); - break; - case 'P': - /* filename */ - while (*s && !isspace(*s)) s++; - *s++ = '\0'; - /* DOC: section name */ - while (isspace(*s)) - s++; - docsection(line + 2, s); - break; - case 'C': - while (*s && !isspace(*s)) s++; - *s = '\0'; - if (findall) - findall(line+2); - break; - default: - defaultline(line); - } - } else { + p = is_directive(line); + if (!p) { + defaultline(line); + continue; + } + + switch (*p++) { + case 'E': + chomp(p); + externalfunctions(p); + break; + case 'I': + chomp(p); + internalfunctions(p); + break; + case 'D': + chomp(p); + symbolsonly(p); + break; + case 'F': + /* filename */ + s = chomp(p); + /* function names */ + while (isspace(*s)) + s++; + singlefunctions(p, s); + break; + case 'P': + /* filename */ + s = chomp(p); + /* DOC: section name */ + while (isspace(*s)) + s++; + docsection(p, s); + break; + case 'C': + chomp(p); + if (findall) + findall(p); + break; + default: defaultline(line); } } fflush(stdout); } +/* + * Is this a RestructuredText template? Answer the question by seeing if its + * name ends in ".rst". + */ +static int is_rst(const char *file) +{ + char *dot = strrchr(file, '.'); + + return dot && !strcmp(dot + 1, "rst"); +} + +enum opts { + OPT_DOCBOOK, + OPT_RST, + OPT_HELP, +}; int main(int argc, char *argv[]) { + const char *subcommand, *filename; FILE * infile; int i; @@ -509,19 +563,66 @@ int main(int argc, char *argv[]) kernsrctree = getenv("KBUILD_SRC"); if (!kernsrctree || !*kernsrctree) kernsrctree = srctree; - if (argc != 3) { + + for (;;) { + int c; + struct option opts[] = { + { "docbook", no_argument, NULL, OPT_DOCBOOK }, + { "rst", no_argument, NULL, OPT_RST }, + { "help", no_argument, NULL, OPT_HELP }, + {} + }; + + c = getopt_long_only(argc, argv, "", opts, NULL); + if (c == -1) + break; + + switch (c) { + case OPT_DOCBOOK: + file_format = FORMAT_DOCBOOK; + break; + case OPT_RST: + file_format = FORMAT_RST; + break; + case OPT_HELP: + usage(); + return 0; + default: + case '?': + usage(); + return 1; + } + } + + argc -= optind; + argv += optind; + + if (argc != 2) { usage(); exit(1); } + + subcommand = argv[0]; + filename = argv[1]; + + if (file_format == FORMAT_AUTO) + file_format = is_rst(filename) ? FORMAT_RST : FORMAT_DOCBOOK; + /* Open file, exit on error */ - infile = fopen(argv[2], "r"); + infile = fopen(filename, "r"); if (infile == NULL) { fprintf(stderr, "docproc: "); - perror(argv[2]); + perror(filename); exit(2); } - if (strcmp("doc", argv[1]) == 0) { + if (strcmp("doc", subcommand) == 0) { + if (file_format == FORMAT_RST) { + time_t t = time(NULL); + printf(".. generated from %s by docproc %s\n", + filename, ctime(&t)); + } + /* Need to do this in two passes. * First pass is used to collect all symbols exported * in the various files; @@ -557,10 +658,10 @@ int main(int argc, char *argv[]) fprintf(stderr, "Warning: didn't use docs for %s\n", all_list[i]); } - } else if (strcmp("depend", argv[1]) == 0) { + } else if (strcmp("depend", subcommand) == 0) { /* Create first part of dependency chain * file.tmpl */ - printf("%s\t", argv[2]); + printf("%s\t", filename); defaultline = noaction; internalfunctions = adddep; externalfunctions = adddep; @@ -571,7 +672,7 @@ int main(int argc, char *argv[]) parse_file(infile); printf("\n"); } else { - fprintf(stderr, "Unknown option: %s\n", argv[1]); + fprintf(stderr, "Unknown option: %s\n", subcommand); exit(1); } fclose(infile); diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index 0c03ac9159c1..386f9563313f 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -294,6 +294,30 @@ static void check_node_name_format(struct check *c, struct node *dt, } NODE_ERROR(node_name_format, NULL, &node_name_chars); +static void check_unit_address_vs_reg(struct check *c, struct node *dt, + struct node *node) +{ + const char *unitname = get_unitname(node); + struct property *prop = get_property(node, "reg"); + + if (!prop) { + prop = get_property(node, "ranges"); + if (prop && !prop->val.len) + prop = NULL; + } + + if (prop) { + if (!unitname[0]) + FAIL(c, "Node %s has a reg or ranges property, but no unit name", + node->fullpath); + } else { + if (unitname[0]) + FAIL(c, "Node %s has a unit name, but no reg property", + node->fullpath); + } +} +NODE_WARNING(unit_address_vs_reg, NULL); + static void check_property_name_chars(struct check *c, struct node *dt, struct node *node, struct property *prop) { @@ -667,6 +691,8 @@ static struct check *check_table[] = { &addr_size_cells, ®_format, &ranges_format, + &unit_address_vs_reg, + &avoid_default_addr_size, &obsolete_chosen_interrupt_controller, diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index bd99fa2d33b8..ec14954f5810 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -889,7 +889,7 @@ struct boot_info *dt_from_blob(const char *fname) if (version >= 3) { uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings); - if (off_str+size_str > totalsize) + if ((off_str+size_str < off_str) || (off_str+size_str > totalsize)) die("String table extends past total size\n"); inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str); } else { @@ -898,7 +898,7 @@ struct boot_info *dt_from_blob(const char *fname) if (version >= 17) { size_dt = fdt32_to_cpu(fdt->size_dt_struct); - if (off_dt+size_dt > totalsize) + if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize)) die("Structure block extends past total size\n"); } diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index e5b313682007..50cce864283c 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -647,10 +647,8 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; - if (fdt_stringlist_contains(prop, len, compatible)) - return 0; - else - return 1; + + return !fdt_stringlist_contains(prop, len, compatible); } int fdt_node_offset_by_compatible(const void *fdt, int startoffset, diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index 11d93e6d8220..ad9b05ae698b 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.4.1-gb06e55c8" +#define DTC_VERSION "DTC 1.4.1-g53bf130b" diff --git a/scripts/gdb/linux/Makefile b/scripts/gdb/linux/Makefile index 6cf1ecf61057..cd129e65d1ff 100644 --- a/scripts/gdb/linux/Makefile +++ b/scripts/gdb/linux/Makefile @@ -8,4 +8,14 @@ ifneq ($(KBUILD_SRC),) endif @: -clean-files := *.pyc *.pyo $(if $(KBUILD_SRC),*.py) +quiet_cmd_gen_constants_py = GEN $@ + cmd_gen_constants_py = \ + $(CPP) -E -x c -P $(c_flags) $< > $@ ;\ + sed -i '1,/<!-- end-c-headers -->/d;' $@ + +$(obj)/constants.py: $(SRCTREE)/$(obj)/constants.py.in + $(call if_changed,gen_constants_py) + +build_constants_py: $(obj)/constants.py + +clean-files := *.pyc *.pyo $(if $(KBUILD_SRC),*.py) $(obj)/constants.py diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in new file mode 100644 index 000000000000..07e6c2befe36 --- /dev/null +++ b/scripts/gdb/linux/constants.py.in @@ -0,0 +1,59 @@ +/* + * gdb helper commands and functions for Linux kernel debugging + * + * Kernel constants derived from include files. + * + * Copyright (c) 2016 Linaro Ltd + * + * Authors: + * Kieran Bingham <kieran.bingham@linaro.org> + * + * This work is licensed under the terms of the GNU GPL version 2. + * + */ + +#include <linux/fs.h> +#include <linux/mount.h> +#include <linux/radix-tree.h> + +/* We need to stringify expanded macros so that they can be parsed */ + +#define STRING(x) #x +#define XSTRING(x) STRING(x) + +#define LX_VALUE(x) LX_##x = x +#define LX_GDBPARSED(x) LX_##x = gdb.parse_and_eval(XSTRING(x)) + +/* + * IS_ENABLED generates (a || b) which is not compatible with python + * We can only switch on configuration items we know are available + * Therefore - IS_BUILTIN() is more appropriate + */ +#define LX_CONFIG(x) LX_##x = IS_BUILTIN(x) + +/* The build system will take care of deleting everything above this marker */ +<!-- end-c-headers --> + +import gdb + +/* linux/fs.h */ +LX_VALUE(MS_RDONLY) +LX_VALUE(MS_SYNCHRONOUS) +LX_VALUE(MS_MANDLOCK) +LX_VALUE(MS_DIRSYNC) +LX_VALUE(MS_NOATIME) +LX_VALUE(MS_NODIRATIME) + +/* linux/mount.h */ +LX_VALUE(MNT_NOSUID) +LX_VALUE(MNT_NODEV) +LX_VALUE(MNT_NOEXEC) +LX_VALUE(MNT_NOATIME) +LX_VALUE(MNT_NODIRATIME) +LX_VALUE(MNT_RELATIME) + +/* linux/radix-tree.h */ +LX_VALUE(RADIX_TREE_INDIRECT_PTR) +LX_GDBPARSED(RADIX_TREE_HEIGHT_MASK) +LX_GDBPARSED(RADIX_TREE_MAP_SHIFT) +LX_GDBPARSED(RADIX_TREE_MAP_MASK) diff --git a/scripts/gdb/linux/cpus.py b/scripts/gdb/linux/cpus.py index 4297b83fedef..ca11e8df31b6 100644 --- a/scripts/gdb/linux/cpus.py +++ b/scripts/gdb/linux/cpus.py @@ -97,9 +97,47 @@ def cpu_list(mask_name): bits >>= 1 bit += 1 + yield int(cpu) + + +def each_online_cpu(): + for cpu in cpu_list("__cpu_online_mask"): + yield cpu + + +def each_present_cpu(): + for cpu in cpu_list("__cpu_present_mask"): + yield cpu + + +def each_possible_cpu(): + for cpu in cpu_list("__cpu_possible_mask"): + yield cpu + + +def each_active_cpu(): + for cpu in cpu_list("__cpu_active_mask"): yield cpu +class LxCpus(gdb.Command): + """List CPU status arrays + +Displays the known state of each CPU based on the kernel masks +and can help identify the state of hotplugged CPUs""" + + def __init__(self): + super(LxCpus, self).__init__("lx-cpus", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + gdb.write("Possible CPUs : {}\n".format(list(each_possible_cpu()))) + gdb.write("Present CPUs : {}\n".format(list(each_present_cpu()))) + gdb.write("Online CPUs : {}\n".format(list(each_online_cpu()))) + gdb.write("Active CPUs : {}\n".format(list(each_active_cpu()))) + +LxCpus() + + class PerCpu(gdb.Function): """Return per-cpu variable. diff --git a/scripts/gdb/linux/dmesg.py b/scripts/gdb/linux/dmesg.py index 927d0d2a3145..f9b92ece7834 100644 --- a/scripts/gdb/linux/dmesg.py +++ b/scripts/gdb/linux/dmesg.py @@ -33,11 +33,12 @@ class LxDmesg(gdb.Command): if log_first_idx < log_next_idx: log_buf_2nd_half = -1 length = log_next_idx - log_first_idx - log_buf = inf.read_memory(start, length) + log_buf = utils.read_memoryview(inf, start, length).tobytes() else: log_buf_2nd_half = log_buf_len - log_first_idx - log_buf = inf.read_memory(start, log_buf_2nd_half) + \ - inf.read_memory(log_buf_addr, log_next_idx) + a = utils.read_memoryview(inf, start, log_buf_2nd_half) + b = utils.read_memoryview(inf, log_buf_addr, log_next_idx) + log_buf = a.tobytes() + b.tobytes() pos = 0 while pos < log_buf.__len__(): @@ -50,10 +51,10 @@ class LxDmesg(gdb.Command): continue text_len = utils.read_u16(log_buf[pos + 10:pos + 12]) - text = log_buf[pos + 16:pos + 16 + text_len] + text = log_buf[pos + 16:pos + 16 + text_len].decode() time_stamp = utils.read_u64(log_buf[pos:pos + 8]) - for line in memoryview(text).tobytes().splitlines(): + for line in text.splitlines(): gdb.write("[{time:12.6f}] {line}\n".format( time=time_stamp / 1000000000.0, line=line)) diff --git a/scripts/gdb/linux/lists.py b/scripts/gdb/linux/lists.py index 3a3775bc162b..2f335fbd86fd 100644 --- a/scripts/gdb/linux/lists.py +++ b/scripts/gdb/linux/lists.py @@ -18,6 +18,27 @@ from linux import utils list_head = utils.CachedType("struct list_head") +def list_for_each(head): + if head.type == list_head.get_type().pointer(): + head = head.dereference() + elif head.type != list_head.get_type(): + raise gdb.GdbError("Must be struct list_head not {}" + .format(head.type)) + + node = head['next'].dereference() + while node.address != head.address: + yield node.address + node = node['next'].dereference() + + +def list_for_each_entry(head, gdbtype, member): + for node in list_for_each(head): + if node.type != list_head.get_type().pointer(): + raise TypeError("Type {} found. Expected struct list_head *." + .format(node.type)) + yield utils.container_of(node, gdbtype, member) + + def list_check(head): nb = 0 if (head.type == list_head.get_type().pointer()): diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py index 0a35d6dbfb80..441b23239896 100644 --- a/scripts/gdb/linux/modules.py +++ b/scripts/gdb/linux/modules.py @@ -13,7 +13,7 @@ import gdb -from linux import cpus, utils +from linux import cpus, utils, lists module_type = utils.CachedType("struct module") @@ -21,14 +21,14 @@ module_type = utils.CachedType("struct module") def module_list(): global module_type + modules = utils.gdb_eval_or_none("modules") + if modules is None: + return + module_ptr_type = module_type.get_type().pointer() - modules = gdb.parse_and_eval("modules") - entry = modules['next'] - end_of_list = modules.address - while entry != end_of_list: - yield utils.container_of(entry, module_ptr_type, "list") - entry = entry['next'] + for module in lists.list_for_each_entry(modules, module_ptr_type, "list"): + yield module def find_module_by_name(name): @@ -78,19 +78,17 @@ class LxLsmod(gdb.Command): address=str(layout['base']).split()[0], name=module['name'].string(), size=str(layout['size']), - ref=str(module['refcnt']['counter']))) + ref=str(module['refcnt']['counter'] - 1))) - source_list = module['source_list'] t = self._module_use_type.get_type().pointer() - entry = source_list['next'] first = True - while entry != source_list.address: - use = utils.container_of(entry, t, "source_list") + sources = module['source_list'] + for use in lists.list_for_each_entry(sources, t, "source_list"): gdb.write("{separator}{name}".format( separator=" " if first else ",", name=use['source']['name'].string())) first = False - entry = entry['next'] + gdb.write("\n") diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py index 6e6709c1830c..38b1f09d1cd9 100644 --- a/scripts/gdb/linux/proc.py +++ b/scripts/gdb/linux/proc.py @@ -12,6 +12,10 @@ # import gdb +from linux import constants +from linux import utils +from linux import tasks +from linux import lists class LxCmdLine(gdb.Command): @@ -39,3 +43,155 @@ class LxVersion(gdb.Command): gdb.write(gdb.parse_and_eval("linux_banner").string()) LxVersion() + + +# Resource Structure Printers +# /proc/iomem +# /proc/ioports + +def get_resources(resource, depth): + while resource: + yield resource, depth + + child = resource['child'] + if child: + for res, deep in get_resources(child, depth + 1): + yield res, deep + + resource = resource['sibling'] + + +def show_lx_resources(resource_str): + resource = gdb.parse_and_eval(resource_str) + width = 4 if resource['end'] < 0x10000 else 8 + # Iterate straight to the first child + for res, depth in get_resources(resource['child'], 0): + start = int(res['start']) + end = int(res['end']) + gdb.write(" " * depth * 2 + + "{0:0{1}x}-".format(start, width) + + "{0:0{1}x} : ".format(end, width) + + res['name'].string() + "\n") + + +class LxIOMem(gdb.Command): + """Identify the IO memory resource locations defined by the kernel + +Equivalent to cat /proc/iomem on a running target""" + + def __init__(self): + super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + return show_lx_resources("iomem_resource") + +LxIOMem() + + +class LxIOPorts(gdb.Command): + """Identify the IO port resource locations defined by the kernel + +Equivalent to cat /proc/ioports on a running target""" + + def __init__(self): + super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + return show_lx_resources("ioport_resource") + +LxIOPorts() + + +# Mount namespace viewer +# /proc/mounts + +def info_opts(lst, opt): + opts = "" + for key, string in lst.items(): + if opt & key: + opts += string + return opts + + +FS_INFO = {constants.LX_MS_SYNCHRONOUS: ",sync", + constants.LX_MS_MANDLOCK: ",mand", + constants.LX_MS_DIRSYNC: ",dirsync", + constants.LX_MS_NOATIME: ",noatime", + constants.LX_MS_NODIRATIME: ",nodiratime"} + +MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid", + constants.LX_MNT_NODEV: ",nodev", + constants.LX_MNT_NOEXEC: ",noexec", + constants.LX_MNT_NOATIME: ",noatime", + constants.LX_MNT_NODIRATIME: ",nodiratime", + constants.LX_MNT_RELATIME: ",relatime"} + +mount_type = utils.CachedType("struct mount") +mount_ptr_type = mount_type.get_type().pointer() + + +class LxMounts(gdb.Command): + """Report the VFS mounts of the current process namespace. + +Equivalent to cat /proc/mounts on a running target +An integer value can be supplied to display the mount +values of that process namespace""" + + def __init__(self): + super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA) + + # Equivalent to proc_namespace.c:show_vfsmnt + # However, that has the ability to call into s_op functions + # whereas we cannot and must make do with the information we can obtain. + def invoke(self, arg, from_tty): + argv = gdb.string_to_argv(arg) + if len(argv) >= 1: + try: + pid = int(argv[0]) + except: + raise gdb.GdbError("Provide a PID as integer value") + else: + pid = 1 + + task = tasks.get_task_by_pid(pid) + if not task: + raise gdb.GdbError("Couldn't find a process with PID {}" + .format(pid)) + + namespace = task['nsproxy']['mnt_ns'] + if not namespace: + raise gdb.GdbError("No namespace for current process") + + for vfs in lists.list_for_each_entry(namespace['list'], + mount_ptr_type, "mnt_list"): + devname = vfs['mnt_devname'].string() + devname = devname if devname else "none" + + pathname = "" + parent = vfs + while True: + mntpoint = parent['mnt_mountpoint'] + pathname = utils.dentry_name(mntpoint) + pathname + if (parent == parent['mnt_parent']): + break + parent = parent['mnt_parent'] + + if (pathname == ""): + pathname = "/" + + superblock = vfs['mnt']['mnt_sb'] + fstype = superblock['s_type']['name'].string() + s_flags = int(superblock['s_flags']) + m_flags = int(vfs['mnt']['mnt_flags']) + rd = "ro" if (s_flags & constants.LX_MS_RDONLY) else "rw" + + gdb.write( + "{} {} {} {}{}{} 0 0\n" + .format(devname, + pathname, + fstype, + rd, + info_opts(FS_INFO, s_flags), + info_opts(MNT_INFO, m_flags))) + +LxMounts() diff --git a/scripts/gdb/linux/radixtree.py b/scripts/gdb/linux/radixtree.py new file mode 100644 index 000000000000..0fdef4e2971a --- /dev/null +++ b/scripts/gdb/linux/radixtree.py @@ -0,0 +1,97 @@ +# +# gdb helper commands and functions for Linux kernel debugging +# +# Radix Tree Parser +# +# Copyright (c) 2016 Linaro Ltd +# +# Authors: +# Kieran Bingham <kieran.bingham@linaro.org> +# +# This work is licensed under the terms of the GNU GPL version 2. +# + +import gdb + +from linux import utils +from linux import constants + +radix_tree_root_type = utils.CachedType("struct radix_tree_root") +radix_tree_node_type = utils.CachedType("struct radix_tree_node") + + +def is_indirect_ptr(node): + long_type = utils.get_long_type() + return (node.cast(long_type) & constants.LX_RADIX_TREE_INDIRECT_PTR) + + +def indirect_to_ptr(node): + long_type = utils.get_long_type() + node_type = node.type + indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INDIRECT_PTR + return indirect_ptr.cast(node_type) + + +def maxindex(height): + height = height & constants.LX_RADIX_TREE_HEIGHT_MASK + return gdb.parse_and_eval("height_to_maxindex["+str(height)+"]") + + +def lookup(root, index): + if root.type == radix_tree_root_type.get_type().pointer(): + root = root.dereference() + elif root.type != radix_tree_root_type.get_type(): + raise gdb.GdbError("Must be struct radix_tree_root not {}" + .format(root.type)) + + node = root['rnode'] + if node is 0: + return None + + if not (is_indirect_ptr(node)): + if (index > 0): + return None + return node + + node = indirect_to_ptr(node) + + height = node['path'] & constants.LX_RADIX_TREE_HEIGHT_MASK + if (index > maxindex(height)): + return None + + shift = (height-1) * constants.LX_RADIX_TREE_MAP_SHIFT + + while True: + new_index = (index >> shift) & constants.LX_RADIX_TREE_MAP_MASK + slot = node['slots'][new_index] + + node = slot.cast(node.type.pointer()).dereference() + if node is 0: + return None + + shift -= constants.LX_RADIX_TREE_MAP_SHIFT + height -= 1 + + if (height <= 0): + break + + return node + + +class LxRadixTree(gdb.Function): + """ Lookup and return a node from a RadixTree. + +$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index. +If index is omitted, the root node is dereferenced and returned.""" + + def __init__(self): + super(LxRadixTree, self).__init__("lx_radix_tree_lookup") + + def invoke(self, root, index=0): + result = lookup(root, index) + if result is None: + raise gdb.GdbError("No entry in tree at index {}".format(index)) + + return result + +LxRadixTree() diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py index 862a4ae24d49..1bf949c43b76 100644 --- a/scripts/gdb/linux/tasks.py +++ b/scripts/gdb/linux/tasks.py @@ -114,3 +114,22 @@ variable.""" LxThreadInfoFunc() + + +class LxThreadInfoByPidFunc (gdb.Function): + """Calculate Linux thread_info from task variable found by pid + +$lx_thread_info_by_pid(PID): Given PID, return the corresponding thread_info +variable.""" + + def __init__(self): + super(LxThreadInfoByPidFunc, self).__init__("lx_thread_info_by_pid") + + def invoke(self, pid): + task = get_task_by_pid(pid) + if task: + return get_thread_info(task.dereference()) + else: + raise gdb.GdbError("No task of PID " + str(pid)) + +LxThreadInfoByPidFunc() diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py index 0893b326a28b..50805874cfc3 100644 --- a/scripts/gdb/linux/utils.py +++ b/scripts/gdb/linux/utils.py @@ -87,11 +87,24 @@ def get_target_endianness(): return target_endianness +def read_memoryview(inf, start, length): + return memoryview(inf.read_memory(start, length)) + + def read_u16(buffer): + value = [0, 0] + + if type(buffer[0]) is str: + value[0] = ord(buffer[0]) + value[1] = ord(buffer[1]) + else: + value[0] = buffer[0] + value[1] = buffer[1] + if get_target_endianness() == LITTLE_ENDIAN: - return ord(buffer[0]) + (ord(buffer[1]) << 8) + return value[0] + (value[1] << 8) else: - return ord(buffer[1]) + (ord(buffer[0]) << 8) + return value[1] + (value[0] << 8) def read_u32(buffer): @@ -154,3 +167,18 @@ def get_gdbserver_type(): if gdbserver_type is not None and hasattr(gdb, 'events'): gdb.events.exited.connect(exit_handler) return gdbserver_type + + +def gdb_eval_or_none(expresssion): + try: + return gdb.parse_and_eval(expresssion) + except: + return None + + +def dentry_name(d): + parent = d['d_parent'] + if parent == d or parent == 0: + return "" + p = dentry_name(d['d_parent']) + "/" + return p + d['d_iname'].string() diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py index d5943eca19cd..3a80ad6eecad 100644 --- a/scripts/gdb/vmlinux-gdb.py +++ b/scripts/gdb/vmlinux-gdb.py @@ -30,3 +30,5 @@ else: import linux.cpus import linux.lists import linux.proc + import linux.constants + import linux.radixtree diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index dafaf96e0a34..06121ce524a7 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -873,5 +873,8 @@ int main(int argc, char **argv) (double)nsyms / (double)HASH_BUCKETS); } + if (dumpfile) + fclose(dumpfile); + return errors != 0; } diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl index 62320f93e903..8b2da054cdc3 100755 --- a/scripts/headers_check.pl +++ b/scripts/headers_check.pl @@ -69,6 +69,10 @@ sub check_declarations if ($line =~ m/^void seqbuf_dump\(void\);/) { return; } + # drm headers are being C++ friendly + if ($line =~ m/^extern "C"/) { + return; + } if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) { printf STDERR "$filename:$lineno: " . "userspace cannot reference function or " . diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 638b143ee60f..1f22a186c18c 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -63,7 +63,6 @@ static unsigned int table_size, table_cnt; static int all_symbols = 0; static int absolute_percpu = 0; static char symbol_prefix_char = '\0'; -static unsigned long long kernel_start_addr = 0; static int base_relative = 0; int token_profit[0x10000]; @@ -223,15 +222,13 @@ static int symbol_valid(struct sym_entry *s) static char *special_suffixes[] = { "_veneer", /* arm */ + "_from_arm", /* arm */ + "_from_thumb", /* arm */ NULL }; int i; char *sym_name = (char *)s->sym + 1; - - if (s->addr < kernel_start_addr) - return 0; - /* skip prefix char */ if (symbol_prefix_char && *sym_name == symbol_prefix_char) sym_name++; @@ -765,9 +762,6 @@ int main(int argc, char **argv) if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\'')) p++; symbol_prefix_char = *p; - } else if (strncmp(argv[i], "--page-offset=", 14) == 0) { - const char *p = &argv[i][14]; - kernel_start_addr = strtoull(p, NULL, 16); } else if (strcmp(argv[i], "--base-relative") == 0) base_relative = 1; else diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index dd243d2abd87..297b079ae4d9 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -375,7 +375,9 @@ load: continue; } else { if (line[0] != '\r' && line[0] != '\n') - conf_warning("unexpected data"); + conf_warning("unexpected data: %.*s", + (int)strcspn(line, "\r\n"), line); + continue; } setsym: diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index f3d3fb42b873..b8c7b29affc5 100755 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -188,7 +188,7 @@ sub read_kconfig { $cont = 0; # collect any Kconfig sources - if (/^source\s*"(.*)"/) { + if (/^source\s+"?([^"]+)/) { my $kconfig = $1; # prevent reading twice. if (!defined($read_kconfigs{$kconfig})) { @@ -237,7 +237,7 @@ sub read_kconfig { } # configs without prompts must be selected - } elsif ($state ne "NONE" && /^\s*tristate\s\S/) { + } elsif ($state ne "NONE" && /^\s*(tristate\s+\S|prompt\b)/) { # note if the config has a prompt $prompts{$config} = 1; @@ -256,8 +256,8 @@ sub read_kconfig { $iflevel-- if ($iflevel); - # stop on "help" - } elsif (/^\s*help\s*$/) { + # stop on "help" and keywords that end a menu entry + } elsif (/^\s*(---)?help(---)?\s*$/ || /^(comment|choice|menu)\b/) { $state = "NONE"; } } @@ -454,7 +454,7 @@ sub parse_config_depends $p =~ s/^[^$valid]*[$valid]+//; # We only need to process if the depend config is a module - if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") { + if (!defined($orig_configs{$conf}) || $orig_configs{$conf} eq "y") { next; } @@ -610,6 +610,40 @@ foreach my $line (@config_file) { next; } + if (/CONFIG_MODULE_SIG_KEY="(.+)"/) { + my $orig_cert = $1; + my $default_cert = "certs/signing_key.pem"; + + # Check that the logic in this script still matches the one in Kconfig + if (!defined($depends{"MODULE_SIG_KEY"}) || + $depends{"MODULE_SIG_KEY"} !~ /"\Q$default_cert\E"/) { + print STDERR "WARNING: MODULE_SIG_KEY assertion failure, ", + "update needed to ", __FILE__, " line ", __LINE__, "\n"; + print; + } elsif ($orig_cert ne $default_cert && ! -f $orig_cert) { + print STDERR "Module signature verification enabled but ", + "module signing key \"$orig_cert\" not found. Resetting ", + "signing key to default value.\n"; + print "CONFIG_MODULE_SIG_KEY=\"$default_cert\"\n"; + } else { + print; + } + next; + } + + if (/CONFIG_SYSTEM_TRUSTED_KEYS="(.+)"/) { + my $orig_keys = $1; + + if (! -f $orig_keys) { + print STDERR "System keyring enabled but keys \"$orig_keys\" ", + "not found. Resetting keys to default value.\n"; + print "CONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n"; + } else { + print; + } + next; + } + if (/^(CONFIG.*)=(m|y)/) { if (defined($configs{$1})) { if ($localyesconfig) { diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 25cf0c2c0c79..2432298487fb 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -209,12 +209,26 @@ static void sym_set_all_changed(void) static void sym_calc_visibility(struct symbol *sym) { struct property *prop; + struct symbol *choice_sym = NULL; tristate tri; /* any prompt visible? */ tri = no; + + if (sym_is_choice_value(sym)) + choice_sym = prop_get_symbol(sym_get_choice_prop(sym)); + for_all_prompts(sym, prop) { prop->visible.tri = expr_calc_value(prop->visible.expr); + /* + * Tristate choice_values with visibility 'mod' are + * not visible if the corresponding choice's value is + * 'yes'. + */ + if (choice_sym && sym->type == S_TRISTATE && + prop->visible.tri == mod && choice_sym->curr.tri == yes) + prop->visible.tri = no; + tri = EXPR_OR(tri, prop->visible.tri); } if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index c37255bb620d..2fc8fad5195e 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -39,41 +39,44 @@ use strict; # 25/07/2012 - Added support for HTML5 # -- Dan Luedtke <mail@danrl.de> -# -# This will read a 'c' file and scan for embedded comments in the -# style of gnome comments (+minor extensions - see below). -# - -# Note: This only supports 'c'. - -# usage: -# kernel-doc [ -docbook | -html | -html5 | -text | -man | -list ] -# [ -no-doc-sections ] -# [ -function funcname [ -function funcname ...] ] -# c file(s)s > outputfile -# or -# [ -nofunction funcname [ -function funcname ...] ] -# c file(s)s > outputfile -# -# Set output format using one of -docbook -html -html5 -text or -man. -# Default is man. -# The -list format is for internal use by docproc. -# -# -no-doc-sections -# Do not output DOC: sections -# -# -function funcname -# If set, then only generate documentation for the given function(s) or -# DOC: section titles. All other functions and DOC: sections are ignored. -# -# -nofunction funcname -# If set, then only generate documentation for the other function(s)/DOC: -# sections. Cannot be used together with -function (yes, that's a bug -- -# perl hackers can fix it 8)) -# -# c files - list of 'c' files to process -# -# All output goes to stdout, with errors to stderr. +sub usage { + my $message = <<"EOF"; +Usage: $0 [OPTION ...] FILE ... + +Read C language source or header FILEs, extract embedded documentation comments, +and print formatted documentation to standard output. + +The documentation comments are identified by "/**" opening comment mark. See +Documentation/kernel-doc-nano-HOWTO.txt for the documentation comment syntax. + +Output format selection (mutually exclusive): + -docbook Output DocBook format. + -html Output HTML format. + -html5 Output HTML5 format. + -list Output symbol list format. This is for use by docproc. + -man Output troff manual page format. This is the default. + -rst Output reStructuredText format. + -text Output plain text format. + +Output selection (mutually exclusive): + -function NAME Only output documentation for the given function(s) + or DOC: section title(s). All other functions and DOC: + sections are ignored. May be specified multiple times. + -nofunction NAME Do NOT output documentation for the given function(s); + only output documentation for the other functions and + DOC: sections. May be specified multiple times. + +Output selection modifiers: + -no-doc-sections Do not output DOC: sections. + +Other parameters: + -v Verbose output, more warnings and other information. + -h Print this help. + +EOF + print $message; + exit 1; +} # # format of comments. @@ -201,6 +204,8 @@ my $type_param = '\@(\w+)'; my $type_struct = '\&((struct\s*)*[_\w]+)'; my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; my $type_env = '(\$\w+)'; +my $type_enum_full = '\&(enum)\s*([_\w]+)'; +my $type_struct_full = '\&(struct)\s*([_\w]+)'; # Output conversion substitutions. # One for each output format @@ -266,6 +271,17 @@ my @highlights_text = ( ); my $blankline_text = ""; +# rst-mode +my @highlights_rst = ( + [$type_constant, "``\$1``"], + [$type_func, "\\:c\\:func\\:`\$1`"], + [$type_struct_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], + [$type_enum_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], + [$type_struct, "\\:c\\:type\\:`struct \$1 <\$1>`"], + [$type_param, "**\$1**"] + ); +my $blankline_rst = "\n"; + # list mode my @highlights_list = ( [$type_constant, "\$1"], @@ -402,6 +418,10 @@ while ($ARGV[0] =~ m/^-(.*)/) { $output_mode = "text"; @highlights = @highlights_text; $blankline = $blankline_text; + } elsif ($cmd eq "-rst") { + $output_mode = "rst"; + @highlights = @highlights_rst; + $blankline = $blankline_rst; } elsif ($cmd eq "-docbook") { $output_mode = "xml"; @highlights = @highlights_xml; @@ -437,17 +457,6 @@ while ($ARGV[0] =~ m/^-(.*)/) { # continue execution near EOF; -sub usage { - print "Usage: $0 [ -docbook | -html | -html5 | -text | -man | -list ]\n"; - print " [ -no-doc-sections ]\n"; - print " [ -function funcname [ -function funcname ...] ]\n"; - print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; - print " [ -v ]\n"; - print " c source file(s) > outputfile\n"; - print " -v : verbose output, more warnings & other info listed\n"; - exit 1; -} - # get kernel version from env sub get_kernel_version() { my $version = 'unknown kernel version'; @@ -1713,6 +1722,208 @@ sub output_blockhead_text(%) { } } +## +# output in restructured text +# + +# +# This could use some work; it's used to output the DOC: sections, and +# starts by putting out the name of the doc section itself, but that tends +# to duplicate a header already in the template file. +# +sub output_blockhead_rst(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + + foreach $section (@{$args{'sectionlist'}}) { + print "**$section**\n\n"; + output_highlight_rst($args{'sections'}{$section}); + print "\n"; + } +} + +sub output_highlight_rst { + my $contents = join "\n",@_; + my $line; + + # undo the evil effects of xml_escape() earlier + $contents = xml_unescape($contents); + + eval $dohighlight; + die $@ if $@; + + foreach $line (split "\n", $contents) { + if ($line eq "") { + print $lineprefix, $blankline; + } else { + $line =~ s/\\\\\\/\&/g; + print $lineprefix, $line; + } + print "\n"; + } +} + +sub output_function_rst(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + my $start; + + print ".. c:function:: "; + if ($args{'functiontype'} ne "") { + $start = $args{'functiontype'} . " " . $args{'function'} . " ("; + } else { + $start = $args{'function'} . " ("; + } + print $start; + + my $count = 0; + foreach my $parameter (@{$args{'parameterlist'}}) { + if ($count ne 0) { + print ", "; + } + $count++; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print $1 . $parameter . ") (" . $2; + } else { + print $type . " " . $parameter; + } + } + print ")\n\n " . $args{'purpose'} . "\n\n"; + + print ":Parameters:\n\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + my $parameter_name = $parameter; + #$parameter_name =~ s/\[.*//; + $type = $args{'parametertypes'}{$parameter}; + + if ($type ne "") { + print " ``$type $parameter``\n"; + } else { + print " ``$parameter``\n"; + } + if ($args{'parameterdescs'}{$parameter_name} ne $undescribed) { + my $oldprefix = $lineprefix; + $lineprefix = " "; + output_highlight_rst($args{'parameterdescs'}{$parameter_name}); + $lineprefix = $oldprefix; + } else { + print "\n _undescribed_\n"; + } + print "\n"; + } + output_section_rst(@_); +} + +sub output_section_rst(%) { + my %args = %{$_[0]}; + my $section; + my $oldprefix = $lineprefix; + $lineprefix = " "; + + foreach $section (@{$args{'sectionlist'}}) { + print ":$section:\n\n"; + output_highlight_rst($args{'sections'}{$section}); + print "\n"; + } + print "\n"; + $lineprefix = $oldprefix; +} + +sub output_enum_rst(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + my $name = "enum " . $args{'enum'}; + + print "\n\n.. c:type:: " . $name . "\n\n"; + print " " . $args{'purpose'} . "\n\n"; + + print "..\n\n:Constants:\n\n"; + my $oldprefix = $lineprefix; + $lineprefix = " "; + foreach $parameter (@{$args{'parameterlist'}}) { + print " `$parameter`\n"; + if ($args{'parameterdescs'}{$parameter} ne $undescribed) { + output_highlight_rst($args{'parameterdescs'}{$parameter}); + } else { + print " undescribed\n"; + } + print "\n"; + } + $lineprefix = $oldprefix; + output_section_rst(@_); +} + +sub output_typedef_rst(%) { + my %args = %{$_[0]}; + my ($parameter); + my $count; + my $name = "typedef " . $args{'typedef'}; + + ### FIXME: should the name below contain "typedef" or not? + print "\n\n.. c:type:: " . $name . "\n\n"; + print " " . $args{'purpose'} . "\n\n"; + + output_section_rst(@_); +} + +sub output_struct_rst(%) { + my %args = %{$_[0]}; + my ($parameter); + my $name = $args{'type'} . " " . $args{'struct'}; + + print "\n\n.. c:type:: " . $name . "\n\n"; + print " " . $args{'purpose'} . "\n\n"; + + print ":Definition:\n\n"; + print " ::\n\n"; + print " " . $args{'type'} . " " . $args{'struct'} . " {\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + if ($parameter =~ /^#/) { + print " " . "$parameter\n"; + next; + } + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { + # pointer-to-function + print " $1 $parameter) ($2);\n"; + } elsif ($type =~ m/^(.*?)\s*(:.*)/) { + # bitfield + print " $1 $parameter$2;\n"; + } else { + print " " . $type . " " . $parameter . ";\n"; + } + } + print " };\n\n"; + + print ":Members:\n\n"; + foreach $parameter (@{$args{'parameterlist'}}) { + ($parameter =~ /^#/) && next; + + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; + print " `$type $parameter`" . "\n"; + my $oldprefix = $lineprefix; + $lineprefix = " "; + output_highlight_rst($args{'parameterdescs'}{$parameter_name}); + $lineprefix = $oldprefix; + print "\n"; + } + print "\n"; + output_section_rst(@_); +} + + ## list mode output functions sub output_function_list(%) { @@ -2414,6 +2625,18 @@ sub xml_escape($) { return $text; } +# xml_unescape: reverse the effects of xml_escape +sub xml_unescape($) { + my $text = shift; + if (($output_mode eq "text") || ($output_mode eq "man")) { + return $text; + } + $text =~ s/\\\\\\amp;/\&/g; + $text =~ s/\\\\\\lt;/</g; + $text =~ s/\\\\\\gt;/>/g; + return $text; +} + # convert local escape strings to html # local escape strings look like: '\\\\menmonic:' (that's 4 backslashes) sub local_unescape($) { diff --git a/scripts/ld-version.sh b/scripts/ld-version.sh index 7bfe9fa1c8dc..d135882e2c40 100755 --- a/scripts/ld-version.sh +++ b/scripts/ld-version.sh @@ -5,6 +5,6 @@ gsub(".*version ", ""); gsub("-.*", ""); split($1,a, "."); - print a[1]*100000000 + a[2]*1000000 + a[3]*10000 + a[4]*100 + a[5]; + print a[1]*100000000 + a[2]*1000000 + a[3]*10000; exit } diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 49d61ade9425..f0f6d9d75435 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -82,10 +82,6 @@ kallsyms() kallsymopt="${kallsymopt} --all-symbols" fi - if [ -n "${CONFIG_ARM}" ] && [ -z "${CONFIG_XIP_KERNEL}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then - kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET" - fi - if [ -n "${CONFIG_KALLSYMS_ABSOLUTE_PERCPU}" ]; then kallsymopt="${kallsymopt} --absolute-percpu" fi diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 161dd0d67da8..a9155077feef 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -371,6 +371,49 @@ static void do_usb_table(void *symval, unsigned long size, do_usb_entry_multi(symval + i, mod); } +static void do_of_entry_multi(void *symval, struct module *mod) +{ + char alias[500]; + int len; + char *tmp; + + DEF_FIELD_ADDR(symval, of_device_id, name); + DEF_FIELD_ADDR(symval, of_device_id, type); + DEF_FIELD_ADDR(symval, of_device_id, compatible); + + len = sprintf(alias, "of:N%sT%s", (*name)[0] ? *name : "*", + (*type)[0] ? *type : "*"); + + if (compatible[0]) + sprintf(&alias[len], "%sC%s", (*type)[0] ? "*" : "", + *compatible); + + /* Replace all whitespace with underscores */ + for (tmp = alias; tmp && *tmp; tmp++) + if (isspace(*tmp)) + *tmp = '_'; + + buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias); + strcat(alias, "C"); + add_wildcard(alias); + buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias); +} + +static void do_of_table(void *symval, unsigned long size, + struct module *mod) +{ + unsigned int i; + const unsigned long id_size = SIZE_of_device_id; + + device_id_check(mod->name, "of", size, id_size, symval); + + /* Leave last one: it's the terminator. */ + size -= id_size; + + for (i = 0; i < size; i += id_size) + do_of_entry_multi(symval + i, mod); +} + /* Looks like: hid:bNvNpN */ static int do_hid_entry(const char *filename, void *symval, char *alias) @@ -684,30 +727,6 @@ static int do_pcmcia_entry(const char *filename, } ADD_TO_DEVTABLE("pcmcia", pcmcia_device_id, do_pcmcia_entry); -static int do_of_entry (const char *filename, void *symval, char *alias) -{ - int len; - char *tmp; - DEF_FIELD_ADDR(symval, of_device_id, name); - DEF_FIELD_ADDR(symval, of_device_id, type); - DEF_FIELD_ADDR(symval, of_device_id, compatible); - - len = sprintf(alias, "of:N%sT%s", (*name)[0] ? *name : "*", - (*type)[0] ? *type : "*"); - - if (compatible[0]) - sprintf(&alias[len], "%sC%s", (*type)[0] ? "*" : "", - *compatible); - - /* Replace all whitespace with underscores */ - for (tmp = alias; tmp && *tmp; tmp++) - if (isspace (*tmp)) - *tmp = '_'; - - return 1; -} -ADD_TO_DEVTABLE("of", of_device_id, do_of_entry); - static int do_vio_entry(const char *filename, void *symval, char *alias) { @@ -1348,6 +1367,8 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, /* First handle the "special" cases */ if (sym_is(name, namelen, "usb")) do_usb_table(symval, sym->st_size, mod); + if (sym_is(name, namelen, "of")) + do_of_table(symval, sym->st_size, mod); else if (sym_is(name, namelen, "pnp")) do_pnp_device_entry(symval, sym->st_size, mod); else if (sym_is(name, namelen, "pnp_card")) diff --git a/scripts/spelling.txt b/scripts/spelling.txt index 946caf3bd694..fa79c6d2a5b8 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -428,6 +428,7 @@ feautures||features fetaure||feature fetaures||features fileystem||filesystem +fimware||firmware finanize||finalize findn||find finilizes||finalizes |