summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2020-11-07 12:50:48 +0100
committerIngo Molnar <mingo@kernel.org>2020-11-07 13:20:17 +0100
commit666fab4a3ea143315a9c059fad9f3a0f1365d54b (patch)
treee9e4be3b0eeac79346d52a86183326617d0c9999 /scripts
parent0a986ea81e1aa8ac17e82cda53cc95158217956e (diff)
parent659caaf65dc9c7150aa3e80225ec6e66b25ab3ce (diff)
downloadlinux-666fab4a3ea143315a9c059fad9f3a0f1365d54b.tar.bz2
Merge branch 'linus' into perf/kprobes
Conflicts: include/asm-generic/atomic-instrumented.h kernel/kprobes.c Use the upstream atomic-instrumented.h checksum, and pick the kprobes version of kernel/kprobes.c, which effectively reverts this upstream workaround: 645f224e7ba2: ("kprobes: Tell lockdep about kprobe nesting") Since the new code *should* be fine without nesting. Knock on wood ... Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Kbuild.include2
-rw-r--r--scripts/Makefile3
-rw-r--r--scripts/Makefile.build2
-rw-r--r--scripts/Makefile.kasan4
-rw-r--r--scripts/Makefile.kcsan4
-rw-r--r--scripts/Makefile.lib2
-rw-r--r--scripts/Makefile.modfinal5
-rw-r--r--scripts/Makefile.ubsan13
-rwxr-xr-xscripts/atomic/check-atomics.sh1
-rwxr-xr-xscripts/atomic/gen-atomic-instrumented.sh21
-rwxr-xr-xscripts/bpf_helpers_doc.py5
-rwxr-xr-xscripts/checkpatch.pl250
-rwxr-xr-xscripts/clang-tools/gen_compile_commands.py236
-rwxr-xr-xscripts/clang-tools/run-clang-tools.py74
-rwxr-xr-xscripts/coccicheck17
-rw-r--r--scripts/coccinelle/api/alloc/zalloc-simple.cocci16
-rw-r--r--scripts/coccinelle/api/device_attr_show.cocci2
-rw-r--r--scripts/coccinelle/api/kfree_mismatch.cocci228
-rw-r--r--scripts/coccinelle/api/kfree_sensitive.cocci (renamed from scripts/coccinelle/api/kzfree.cocci)35
-rw-r--r--scripts/coccinelle/api/kobj_to_dev.cocci45
-rw-r--r--scripts/coccinelle/api/kvmalloc.cocci256
-rw-r--r--scripts/coccinelle/free/ifnullfree.cocci11
-rw-r--r--scripts/coccinelle/iterators/for_each_child.cocci358
-rw-r--r--scripts/coccinelle/misc/excluded_middle.cocci39
-rw-r--r--scripts/coccinelle/misc/flexible_array.cocci88
-rw-r--r--scripts/coccinelle/misc/uninitialized_var.cocci51
-rw-r--r--scripts/const_structs.checkpatch3
-rwxr-xr-xscripts/decodecode29
-rwxr-xr-xscripts/dev-needs.sh315
-rw-r--r--scripts/dtc/Makefile2
-rw-r--r--scripts/dtc/checks.c4
-rw-r--r--scripts/dtc/dtc-parser.y4
-rwxr-xr-xscripts/dtc/dtx_diff3
-rw-r--r--scripts/dtc/libfdt/fdt.c31
-rw-r--r--scripts/dtc/libfdt/fdt_overlay.c3
-rw-r--r--scripts/dtc/libfdt/fdt_ro.c20
-rw-r--r--scripts/dtc/libfdt/fdt_rw.c2
-rw-r--r--scripts/dtc/libfdt/fdt_strerror.c4
-rw-r--r--scripts/dtc/libfdt/fdt_sw.c27
-rw-r--r--scripts/dtc/libfdt/fdt_wip.c2
-rw-r--r--scripts/dtc/util.h1
-rw-r--r--scripts/dtc/version_gen.h2
-rw-r--r--scripts/gdb/linux/dmesg.py147
-rw-r--r--scripts/gdb/linux/proc.py15
-rw-r--r--scripts/gdb/linux/tasks.py9
-rw-r--r--scripts/gdb/linux/utils.py7
-rwxr-xr-xscripts/gen_compile_commands.py151
-rwxr-xr-xscripts/get_abi.pl365
-rwxr-xr-xscripts/get_maintainer.pl9
-rw-r--r--scripts/kallsyms.c16
-rw-r--r--scripts/kconfig/Makefile16
-rw-r--r--scripts/kconfig/lkc.h47
-rw-r--r--scripts/kconfig/lkc_proto.h14
-rw-r--r--scripts/kconfig/qconf.cc381
-rw-r--r--scripts/kconfig/qconf.h77
-rwxr-xr-xscripts/kernel-doc327
-rwxr-xr-xscripts/link-vmlinux.sh26
-rwxr-xr-xscripts/mkcompile_h2
-rw-r--r--scripts/mod/modpost.c4
-rw-r--r--scripts/module.lds.S (renamed from scripts/module-common.lds)3
-rwxr-xr-xscripts/namespace.pl473
-rwxr-xr-xscripts/package/builddeb19
-rwxr-xr-xscripts/package/mkdebian44
-rw-r--r--scripts/selinux/mdp/mdp.c7
-rwxr-xr-xscripts/setlocalversion21
-rwxr-xr-xscripts/spdxcheck.py3
-rw-r--r--scripts/spelling.txt10
-rwxr-xr-xscripts/tags.sh2
69 files changed, 3011 insertions, 1405 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 0d1c8e217cd7..a6c11316c969 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -8,3 +8,4 @@ asn1_compiler
extract-cert
sign-file
insert-sys-cert
+/module.lds
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 83a1637417e5..08e011175b4c 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -56,8 +56,6 @@ kecho := $($(quiet)kecho)
# - If no file exist it is created
# - If the content differ the new file is used
# - If they are equal no change, and no timestamp update
-# - stdin is piped in from the first prerequisite ($<) so one has
-# to specify a valid file as first prerequisite (often the kbuild file)
define filechk
$(Q)set -e; \
mkdir -p $(dir $@); \
diff --git a/scripts/Makefile b/scripts/Makefile
index bc018e4b733e..b5418ec587fb 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -29,6 +29,9 @@ endif
# The following programs are only built on demand
hostprogs += unifdef
+# The module linker script is preprocessed on demand
+targets += module.lds
+
subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
subdir-$(CONFIG_MODVERSIONS) += genksyms
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index a467b9323442..ae647379b579 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -111,7 +111,7 @@ endif
# ---------------------------------------------------------------------------
quiet_cmd_cc_s_c = CC $(quiet_modtag) $@
- cmd_cc_s_c = $(CC) $(filter-out $(DEBUG_CFLAGS), $(c_flags)) $(DISABLE_LTO) -fverbose-asm -S -o $@ $<
+ cmd_cc_s_c = $(CC) $(filter-out $(DEBUG_CFLAGS), $(c_flags)) -fverbose-asm -S -o $@ $<
$(obj)/%.s: $(src)/%.c FORCE
$(call if_changed_dep,cc_s_c)
diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan
index f4beee1b0013..1e000cc2e7b4 100644
--- a/scripts/Makefile.kasan
+++ b/scripts/Makefile.kasan
@@ -1,8 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-ifdef CONFIG_KASAN
CFLAGS_KASAN_NOSANITIZE := -fno-builtin
KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET)
-endif
ifdef CONFIG_KASAN_GENERIC
@@ -49,3 +47,5 @@ CFLAGS_KASAN := -fsanitize=kernel-hwaddress \
$(instrumentation_flags)
endif # CONFIG_KASAN_SW_TAGS
+
+export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE
diff --git a/scripts/Makefile.kcsan b/scripts/Makefile.kcsan
index c50f27b3ac56..37cb504c77e1 100644
--- a/scripts/Makefile.kcsan
+++ b/scripts/Makefile.kcsan
@@ -9,7 +9,7 @@ endif
# Keep most options here optional, to allow enabling more compilers if absence
# of some options does not break KCSAN nor causes false positive reports.
-CFLAGS_KCSAN := -fsanitize=thread \
+export CFLAGS_KCSAN := -fsanitize=thread \
$(call cc-option,$(call cc-param,tsan-instrument-func-entry-exit=0) -fno-optimize-sibling-calls) \
- $(call cc-option,$(call cc-param,tsan-instrument-read-before-write=1)) \
+ $(call cc-option,$(call cc-param,tsan-compound-read-before-write=1),$(call cc-option,$(call cc-param,tsan-instrument-read-before-write=1))) \
$(call cc-param,tsan-distinguish-volatile=1)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 3d599716940c..94133708889d 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -328,7 +328,7 @@ $(obj)/%.dtb: $(src)/%.dts $(DTC) FORCE
DT_CHECKER ?= dt-validate
DT_BINDING_DIR := Documentation/devicetree/bindings
# DT_TMP_SCHEMA may be overridden from Documentation/devicetree/bindings/Makefile
-DT_TMP_SCHEMA ?= $(objtree)/$(DT_BINDING_DIR)/processed-schema.yaml
+DT_TMP_SCHEMA ?= $(objtree)/$(DT_BINDING_DIR)/processed-schema.json
quiet_cmd_dtb_check = CHECK $@
cmd_dtb_check = $(DT_CHECKER) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index 411c1e600e7d..ae01baf96f4e 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -33,11 +33,10 @@ quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o = \
$(LD) -r $(KBUILD_LDFLAGS) \
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
- $(addprefix -T , $(KBUILD_LDS_MODULE)) \
- -o $@ $(filter %.o, $^); \
+ -T scripts/module.lds -o $@ $(filter %.o, $^); \
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
-$(modules): %.ko: %.o %.mod.o $(KBUILD_LDS_MODULE) FORCE
+$(modules): %.ko: %.o %.mod.o scripts/module.lds FORCE
+$(call if_changed,ld_ko_o)
targets += $(modules) $(modules:.ko=.mod.o)
diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan
index 27348029b2b8..9716dab06bc7 100644
--- a/scripts/Makefile.ubsan
+++ b/scripts/Makefile.ubsan
@@ -1,10 +1,21 @@
# SPDX-License-Identifier: GPL-2.0
+
+export CFLAGS_UBSAN :=
+
ifdef CONFIG_UBSAN_ALIGNMENT
CFLAGS_UBSAN += $(call cc-option, -fsanitize=alignment)
endif
ifdef CONFIG_UBSAN_BOUNDS
- CFLAGS_UBSAN += $(call cc-option, -fsanitize=bounds)
+ ifdef CONFIG_CC_IS_CLANG
+ CFLAGS_UBSAN += -fsanitize=array-bounds
+ else
+ CFLAGS_UBSAN += $(call cc-option, -fsanitize=bounds)
+ endif
+endif
+
+ifdef CONFIG_UBSAN_LOCAL_BOUNDS
+ CFLAGS_UBSAN += -fsanitize=local-bounds
endif
ifdef CONFIG_UBSAN_MISC
diff --git a/scripts/atomic/check-atomics.sh b/scripts/atomic/check-atomics.sh
index 8378c63a1e09..82748d42ecc5 100755
--- a/scripts/atomic/check-atomics.sh
+++ b/scripts/atomic/check-atomics.sh
@@ -16,6 +16,7 @@ fi
cat <<EOF |
asm-generic/atomic-instrumented.h
asm-generic/atomic-long.h
+linux/atomic-arch-fallback.h
linux/atomic-fallback.h
EOF
while read header; do
diff --git a/scripts/atomic/gen-atomic-instrumented.sh b/scripts/atomic/gen-atomic-instrumented.sh
index 85dc25685c0d..5766ffcec7c5 100755
--- a/scripts/atomic/gen-atomic-instrumented.sh
+++ b/scripts/atomic/gen-atomic-instrumented.sh
@@ -5,9 +5,10 @@ ATOMICDIR=$(dirname $0)
. ${ATOMICDIR}/atomic-tbl.sh
-#gen_param_check(arg)
+#gen_param_check(meta, arg)
gen_param_check()
{
+ local meta="$1"; shift
local arg="$1"; shift
local type="${arg%%:*}"
local name="$(gen_param_name "${arg}")"
@@ -17,17 +18,25 @@ gen_param_check()
i) return;;
esac
- # We don't write to constant parameters
- [ ${type#c} != ${type} ] && rw="read"
+ if [ ${type#c} != ${type} ]; then
+ # We don't write to constant parameters.
+ rw="read"
+ elif [ "${meta}" != "s" ]; then
+ # An atomic RMW: if this parameter is not a constant, and this atomic is
+ # not just a 's'tore, this parameter is both read from and written to.
+ rw="read_write"
+ fi
printf "\tinstrument_atomic_${rw}(${name}, sizeof(*${name}));\n"
}
-#gen_param_check(arg...)
+#gen_params_checks(meta, arg...)
gen_params_checks()
{
+ local meta="$1"; shift
+
while [ "$#" -gt 0 ]; do
- gen_param_check "$1"
+ gen_param_check "$meta" "$1"
shift;
done
}
@@ -77,7 +86,7 @@ gen_proto_order_variant()
local ret="$(gen_ret_type "${meta}" "${int}")"
local params="$(gen_params "${int}" "${atomic}" "$@")"
- local checks="$(gen_params_checks "$@")"
+ local checks="$(gen_params_checks "${meta}" "$@")"
local args="$(gen_args "$@")"
local retstmt="$(gen_ret_stmt "${meta}")"
diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py
index 5bfa448b4704..6769caae142f 100755
--- a/scripts/bpf_helpers_doc.py
+++ b/scripts/bpf_helpers_doc.py
@@ -432,6 +432,8 @@ class PrinterHelpers(Printer):
'struct __sk_buff',
'struct sk_msg_md',
'struct xdp_md',
+ 'struct path',
+ 'struct btf_ptr',
]
known_types = {
'...',
@@ -451,6 +453,7 @@ class PrinterHelpers(Printer):
'struct bpf_perf_event_data',
'struct bpf_perf_event_value',
'struct bpf_pidns_info',
+ 'struct bpf_redir_neigh',
'struct bpf_sk_lookup',
'struct bpf_sock',
'struct bpf_sock_addr',
@@ -472,6 +475,8 @@ class PrinterHelpers(Printer):
'struct tcp_request_sock',
'struct udp6_sock',
'struct task_struct',
+ 'struct path',
+ 'struct btf_ptr',
}
mapped_types = {
'u8': '__u8',
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 504d2e431c60..fab38b493cef 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -43,6 +43,8 @@ my $list_types = 0;
my $fix = 0;
my $fix_inplace = 0;
my $root;
+my $gitroot = $ENV{'GIT_DIR'};
+$gitroot = ".git" if !defined($gitroot);
my %debug;
my %camelcase = ();
my %use_type = ();
@@ -65,6 +67,7 @@ my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANC
# git output parsing needs US English output, so first set backtick child process LANGUAGE
my $git_command ='export LANGUAGE=en_US.UTF-8; git';
my $tabsize = 8;
+my ${CONFIG_} = "CONFIG_";
sub help {
my ($exitcode) = @_;
@@ -127,6 +130,8 @@ Options:
--typedefsfile Read additional types from this file
--color[=WHEN] Use colors 'always', 'never', or only when output
is a terminal ('auto'). Default is 'auto'.
+ --kconfig-prefix=WORD use WORD as a prefix for Kconfig symbols (default
+ ${CONFIG_})
-h, --help, --version display this help and exit
When FILE is - read standard input.
@@ -235,6 +240,7 @@ GetOptions(
'color=s' => \$color,
'no-color' => \$color, #keep old behaviors of -nocolor
'nocolor' => \$color, #keep old behaviors of -nocolor
+ 'kconfig-prefix=s' => \${CONFIG_},
'h|help' => \$help,
'version' => \$help
) or help(1);
@@ -904,7 +910,7 @@ sub is_maintained_obsolete {
sub is_SPDX_License_valid {
my ($license) = @_;
- return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git"));
+ return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$gitroot"));
my $root_path = abs_path($root);
my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`;
@@ -922,7 +928,7 @@ sub seed_camelcase_includes {
$camelcase_seeded = 1;
- if (-e ".git") {
+ if (-e "$gitroot") {
my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`;
chomp $git_last_include_commit;
$camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit";
@@ -950,7 +956,7 @@ sub seed_camelcase_includes {
return;
}
- if (-e ".git") {
+ if (-e "$gitroot") {
$files = `${git_command} ls-files "include/*.h"`;
@include_files = split('\n', $files);
}
@@ -970,10 +976,20 @@ sub seed_camelcase_includes {
}
}
+sub git_is_single_file {
+ my ($filename) = @_;
+
+ return 0 if ((which("git") eq "") || !(-e "$gitroot"));
+
+ my $output = `${git_command} ls-files -- $filename 2>/dev/null`;
+ my $count = $output =~ tr/\n//;
+ return $count eq 1 && $output =~ m{^${filename}$};
+}
+
sub git_commit_info {
my ($commit, $id, $desc) = @_;
- return ($id, $desc) if ((which("git") eq "") || !(-e ".git"));
+ return ($id, $desc) if ((which("git") eq "") || !(-e "$gitroot"));
my $output = `${git_command} log --no-color --format='%H %s' -1 $commit 2>&1`;
$output =~ s/^\s*//gm;
@@ -1012,7 +1028,7 @@ 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");
+die "$P: No git repository found\n" if ($git && !-e "$gitroot");
if ($git) {
my @commits = ();
@@ -1043,6 +1059,9 @@ my $vname;
$allow_c99_comments = !defined $ignore_type{"C99_COMMENT_TOLERANCE"};
for my $filename (@ARGV) {
my $FILE;
+ my $is_git_file = git_is_single_file($filename);
+ my $oldfile = $file;
+ $file = 1 if ($is_git_file);
if ($git) {
open($FILE, '-|', "git format-patch -M --stdout -1 $filename") ||
die "$P: $filename: git format-patch failed - $!\n";
@@ -1087,6 +1106,7 @@ for my $filename (@ARGV) {
@modifierListFile = ();
@typeListFile = ();
build_types();
+ $file = $oldfile if ($is_git_file);
}
if (!$quiet) {
@@ -1163,10 +1183,10 @@ sub parse_email {
}
}
+ $comment = trim($comment);
$name = trim($name);
$name =~ s/^\"|\"$//g;
- $name =~ s/(\s*\([^\)]+\))\s*//;
- if (defined($1)) {
+ if ($name =~ s/(\s*\([^\)]+\))\s*//) {
$name_comment = trim($1);
}
$address = trim($address);
@@ -1181,10 +1201,12 @@ sub parse_email {
}
sub format_email {
- my ($name, $address) = @_;
+ my ($name, $name_comment, $address, $comment) = @_;
my $formatted_email;
+ $name_comment = trim($name_comment);
+ $comment = trim($comment);
$name = trim($name);
$name =~ s/^\"|\"$//g;
$address = trim($address);
@@ -1197,9 +1219,9 @@ sub format_email {
if ("$name" eq "") {
$formatted_email = "$address";
} else {
- $formatted_email = "$name <$address>";
+ $formatted_email = "$name$name_comment <$address>";
}
-
+ $formatted_email .= "$comment";
return $formatted_email;
}
@@ -1207,17 +1229,23 @@ sub reformat_email {
my ($email) = @_;
my ($email_name, $name_comment, $email_address, $comment) = parse_email($email);
- return format_email($email_name, $email_address);
+ return format_email($email_name, $name_comment, $email_address, $comment);
}
sub same_email_addresses {
- my ($email1, $email2) = @_;
+ my ($email1, $email2, $match_comment) = @_;
my ($email1_name, $name1_comment, $email1_address, $comment1) = parse_email($email1);
my ($email2_name, $name2_comment, $email2_address, $comment2) = parse_email($email2);
+ if ($match_comment != 1) {
+ return $email1_name eq $email2_name &&
+ $email1_address eq $email2_address;
+ }
return $email1_name eq $email2_name &&
- $email1_address eq $email2_address;
+ $email1_address eq $email2_address &&
+ $name1_comment eq $name2_comment &&
+ $comment1 eq $comment2;
}
sub which {
@@ -2347,6 +2375,7 @@ sub process {
my $signoff = 0;
my $author = '';
my $authorsignoff = 0;
+ my $author_sob = '';
my $is_patch = 0;
my $is_binding_patch = -1;
my $in_header_lines = $file ? 0 : 1;
@@ -2661,6 +2690,10 @@ sub process {
# Check the patch for a From:
if (decode("MIME-Header", $line) =~ /^From:\s*(.*)/) {
$author = $1;
+ my $curline = $linenr;
+ while(defined($rawlines[$curline]) && ($rawlines[$curline++] =~ /^[ \t]\s*(.*)/)) {
+ $author .= $1;
+ }
$author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i);
$author =~ s/"//g;
$author = reformat_email($author);
@@ -2670,9 +2703,37 @@ sub process {
if ($line =~ /^\s*signed-off-by:\s*(.*)/i) {
$signoff++;
$in_commit_log = 0;
- if ($author ne '') {
- if (same_email_addresses($1, $author)) {
+ if ($author ne '' && $authorsignoff != 1) {
+ if (same_email_addresses($1, $author, 1)) {
$authorsignoff = 1;
+ } else {
+ my $ctx = $1;
+ my ($email_name, $email_comment, $email_address, $comment1) = parse_email($ctx);
+ my ($author_name, $author_comment, $author_address, $comment2) = parse_email($author);
+
+ if ($email_address eq $author_address && $email_name eq $author_name) {
+ $author_sob = $ctx;
+ $authorsignoff = 2;
+ } elsif ($email_address eq $author_address) {
+ $author_sob = $ctx;
+ $authorsignoff = 3;
+ } elsif ($email_name eq $author_name) {
+ $author_sob = $ctx;
+ $authorsignoff = 4;
+
+ my $address1 = $email_address;
+ my $address2 = $author_address;
+
+ if ($address1 =~ /(\S+)\+\S+(\@.*)/) {
+ $address1 = "$1$2";
+ }
+ if ($address2 =~ /(\S+)\+\S+(\@.*)/) {
+ $address2 = "$1$2";
+ }
+ if ($address1 eq $address2) {
+ $authorsignoff = 5;
+ }
+ }
}
}
}
@@ -2729,7 +2790,7 @@ sub process {
}
my ($email_name, $name_comment, $email_address, $comment) = parse_email($email);
- my $suggested_email = format_email(($email_name, $email_address));
+ my $suggested_email = format_email(($email_name, $name_comment, $email_address, $comment));
if ($suggested_email eq "") {
ERROR("BAD_SIGN_OFF",
"Unrecognized email address: '$email'\n" . $herecurr);
@@ -2739,9 +2800,9 @@ sub process {
$dequoted =~ s/" </ </;
# Don't force email to have quotes
# Allow just an angle bracketed address
- if (!same_email_addresses($email, $suggested_email)) {
+ if (!same_email_addresses($email, $suggested_email, 0)) {
WARN("BAD_SIGN_OFF",
- "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr);
+ "email address '$email' might be better as '$suggested_email'\n" . $herecurr);
}
}
@@ -2987,6 +3048,42 @@ sub process {
}
}
+# check for repeated words separated by a single space
+ if ($rawline =~ /^\+/ || $in_commit_log) {
+ while ($rawline =~ /\b($word_pattern) (?=($word_pattern))/g) {
+
+ my $first = $1;
+ my $second = $2;
+
+ if ($first =~ /(?:struct|union|enum)/) {
+ pos($rawline) += length($first) + length($second) + 1;
+ next;
+ }
+
+ next if ($first ne $second);
+ next if ($first eq 'long');
+
+ if (WARN("REPEATED_WORD",
+ "Possible repeated word: '$first'\n" . $herecurr) &&
+ $fix) {
+ $fixed[$fixlinenr] =~ s/\b$first $second\b/$first/;
+ }
+ }
+
+ # if it's a repeated word on consecutive lines in a comment block
+ if ($prevline =~ /$;+\s*$/ &&
+ $prevrawline =~ /($word_pattern)\s*$/) {
+ my $last_word = $1;
+ if ($rawline =~ /^\+\s*\*\s*$last_word /) {
+ if (WARN("REPEATED_WORD",
+ "Possible repeated word: '$last_word'\n" . $hereprev) &&
+ $fix) {
+ $fixed[$fixlinenr] =~ s/(\+\s*\*\s*)$last_word /$1/;
+ }
+ }
+ }
+ }
+
# ignore non-hunk lines and lines being removed
next if (!$hunk_line || $line =~ /^-/);
@@ -3213,6 +3310,12 @@ sub process {
}
}
+# check for embedded filenames
+ if ($rawline =~ /^\+.*\Q$realfile\E/) {
+ WARN("EMBEDDED_FILENAME",
+ "It's generally not useful to have the filename in the file\n" . $herecurr);
+ }
+
# check we are in a valid source file if not then ignore this hunk
next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/);
@@ -3310,42 +3413,6 @@ sub process {
}
}
-# check for repeated words separated by a single space
- if ($rawline =~ /^\+/) {
- while ($rawline =~ /\b($word_pattern) (?=($word_pattern))/g) {
-
- my $first = $1;
- my $second = $2;
-
- if ($first =~ /(?:struct|union|enum)/) {
- pos($rawline) += length($first) + length($second) + 1;
- next;
- }
-
- next if ($first ne $second);
- next if ($first eq 'long');
-
- if (WARN("REPEATED_WORD",
- "Possible repeated word: '$first'\n" . $herecurr) &&
- $fix) {
- $fixed[$fixlinenr] =~ s/\b$first $second\b/$first/;
- }
- }
-
- # if it's a repeated word on consecutive lines in a comment block
- if ($prevline =~ /$;+\s*$/ &&
- $prevrawline =~ /($word_pattern)\s*$/) {
- my $last_word = $1;
- if ($rawline =~ /^\+\s*\*\s*$last_word /) {
- if (WARN("REPEATED_WORD",
- "Possible repeated word: '$last_word'\n" . $hereprev) &&
- $fix) {
- $fixed[$fixlinenr] =~ s/(\+\s*\*\s*)$last_word /$1/;
- }
- }
- }
- }
-
# check for space before tabs.
if ($rawline =~ /^\+/ && $rawline =~ / \t/) {
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
@@ -3436,7 +3503,7 @@ sub process {
if ($realfile =~ m@^(drivers/net/|net/)@ &&
$prevrawline =~ /^\+[ \t]*\/\*[ \t]*$/ &&
$rawline =~ /^\+[ \t]*\*/ &&
- $realline > 2) {
+ $realline > 3) { # Do not warn about the initial copyright comment block after SPDX-License-Identifier
WARN("NETWORKING_BLOCK_COMMENT_STYLE",
"networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev);
}
@@ -3895,6 +3962,17 @@ sub process {
#ignore lines not being added
next if ($line =~ /^[^\+]/);
+# check for self assignments used to avoid compiler warnings
+# e.g.: int foo = foo, *bar = NULL;
+# struct foo bar = *(&(bar));
+ if ($line =~ /^\+\s*(?:$Declare)?([A-Za-z_][A-Za-z\d_]*)\s*=/) {
+ my $var = $1;
+ if ($line =~ /^\+\s*(?:$Declare)?$var\s*=\s*(?:$var|\*\s*\(?\s*&\s*\(?\s*$var\s*\)?\s*\)?)\s*[;,]/) {
+ WARN("SELF_ASSIGNMENT",
+ "Do not use self-assignments to avoid compiler warnings\n" . $herecurr);
+ }
+ }
+
# check for dereferences that span multiple lines
if ($prevline =~ /^\+.*$Lval\s*(?:\.|->)\s*$/ &&
$line =~ /^\+\s*(?!\#\s*(?!define\s+|if))\s*$Lval/) {
@@ -4270,6 +4348,12 @@ sub process {
"Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr);
}
+# trace_printk should not be used in production code.
+ if ($line =~ /\b(trace_printk|trace_puts|ftrace_vprintk)\s*\(/) {
+ WARN("TRACE_PRINTK",
+ "Do not use $1() in production code (this can be ignored if built only with a debug config option)\n" . $herecurr);
+ }
+
# ENOSYS means "bad syscall nr" and nothing else. This will have a small
# number of false positives, but assembly files are not checked, so at
# least the arch entry code will not trigger this warning.
@@ -4936,6 +5020,17 @@ sub process {
}
}
+# check if a statement with a comma should be two statements like:
+# foo = bar(), /* comma should be semicolon */
+# bar = baz();
+ if (defined($stat) &&
+ $stat =~ /^\+\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*,\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*;\s*$/) {
+ my $cnt = statement_rawlines($stat);
+ my $herectx = get_stat_here($linenr, $cnt, $here);
+ WARN("SUSPECT_COMMA_SEMICOLON",
+ "Possible comma where semicolon could be used\n" . $herectx);
+ }
+
# return is not a function
if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) {
my $spacing = $1;
@@ -5295,9 +5390,9 @@ sub process {
$dstat =~ s/\s*$//s;
# Flatten any parentheses and braces
- while ($dstat =~ s/\([^\(\)]*\)/1/ ||
- $dstat =~ s/\{[^\{\}]*\}/1/ ||
- $dstat =~ s/.\[[^\[\]]*\]/1/)
+ while ($dstat =~ s/\([^\(\)]*\)/1u/ ||
+ $dstat =~ s/\{[^\{\}]*\}/1u/ ||
+ $dstat =~ s/.\[[^\[\]]*\]/1u/)
{
}
@@ -5338,6 +5433,7 @@ sub process {
$dstat !~ /^\.$Ident\s*=/ && # .foo =
$dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo
$dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...)
+ $dstat !~ /^while\s*$Constant\s*$Constant\s*$/ && # while (...) {...}
$dstat !~ /^for\s*$Constant$/ && # for (...)
$dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar()
$dstat !~ /^do\s*{/ && # do {...
@@ -6524,16 +6620,16 @@ sub process {
}
# check for IS_ENABLED() without CONFIG_<FOO> ($rawline for comments too)
- if ($rawline =~ /\bIS_ENABLED\s*\(\s*(\w+)\s*\)/ && $1 !~ /^CONFIG_/) {
+ if ($rawline =~ /\bIS_ENABLED\s*\(\s*(\w+)\s*\)/ && $1 !~ /^${CONFIG_}/) {
WARN("IS_ENABLED_CONFIG",
- "IS_ENABLED($1) is normally used as IS_ENABLED(CONFIG_$1)\n" . $herecurr);
+ "IS_ENABLED($1) is normally used as IS_ENABLED(${CONFIG_}$1)\n" . $herecurr);
}
# 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*$/) {
+ 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) &&
+ "Prefer IS_ENABLED(<FOO>) to ${CONFIG_}<FOO> || ${CONFIG_}<FOO>_MODULE\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] = "\+#if IS_ENABLED($config)";
}
@@ -6886,9 +6982,33 @@ sub process {
if ($signoff == 0) {
ERROR("MISSING_SIGN_OFF",
"Missing Signed-off-by: line(s)\n");
- } elsif (!$authorsignoff) {
- WARN("NO_AUTHOR_SIGN_OFF",
- "Missing Signed-off-by: line by nominal patch author '$author'\n");
+ } elsif ($authorsignoff != 1) {
+ # authorsignoff values:
+ # 0 -> missing sign off
+ # 1 -> sign off identical
+ # 2 -> names and addresses match, comments mismatch
+ # 3 -> addresses match, names different
+ # 4 -> names match, addresses different
+ # 5 -> names match, addresses excluding subaddress details (refer RFC 5233) match
+
+ my $sob_msg = "'From: $author' != 'Signed-off-by: $author_sob'";
+
+ if ($authorsignoff == 0) {
+ ERROR("NO_AUTHOR_SIGN_OFF",
+ "Missing Signed-off-by: line by nominal patch author '$author'\n");
+ } elsif ($authorsignoff == 2) {
+ CHK("FROM_SIGN_OFF_MISMATCH",
+ "From:/Signed-off-by: email comments mismatch: $sob_msg\n");
+ } elsif ($authorsignoff == 3) {
+ WARN("FROM_SIGN_OFF_MISMATCH",
+ "From:/Signed-off-by: email name mismatch: $sob_msg\n");
+ } elsif ($authorsignoff == 4) {
+ WARN("FROM_SIGN_OFF_MISMATCH",
+ "From:/Signed-off-by: email address mismatch: $sob_msg\n");
+ } elsif ($authorsignoff == 5) {
+ WARN("FROM_SIGN_OFF_MISMATCH",
+ "From:/Signed-off-by: email subaddress mismatch: $sob_msg\n");
+ }
}
}
diff --git a/scripts/clang-tools/gen_compile_commands.py b/scripts/clang-tools/gen_compile_commands.py
new file mode 100755
index 000000000000..19963708bcf8
--- /dev/null
+++ b/scripts/clang-tools/gen_compile_commands.py
@@ -0,0 +1,236 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) Google LLC, 2018
+#
+# Author: Tom Roeder <tmroeder@google.com>
+#
+"""A tool for generating compile_commands.json in the Linux kernel."""
+
+import argparse
+import json
+import logging
+import os
+import re
+import subprocess
+
+_DEFAULT_OUTPUT = 'compile_commands.json'
+_DEFAULT_LOG_LEVEL = 'WARNING'
+
+_FILENAME_PATTERN = r'^\..*\.cmd$'
+_LINE_PATTERN = r'^cmd_[^ ]*\.o := (.* )([^ ]*\.c)$'
+_VALID_LOG_LEVELS = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
+
+
+def parse_arguments():
+ """Sets up and parses command-line arguments.
+
+ Returns:
+ log_level: A logging level to filter log output.
+ directory: The work directory where the objects were built.
+ ar: Command used for parsing .a archives.
+ output: Where to write the compile-commands JSON file.
+ paths: The list of files/directories to handle to find .cmd files.
+ """
+ usage = 'Creates a compile_commands.json database from kernel .cmd files'
+ parser = argparse.ArgumentParser(description=usage)
+
+ directory_help = ('specify the output directory used for the kernel build '
+ '(defaults to the working directory)')
+ parser.add_argument('-d', '--directory', type=str, default='.',
+ help=directory_help)
+
+ output_help = ('path to the output command database (defaults to ' +
+ _DEFAULT_OUTPUT + ')')
+ parser.add_argument('-o', '--output', type=str, default=_DEFAULT_OUTPUT,
+ help=output_help)
+
+ log_level_help = ('the level of log messages to produce (defaults to ' +
+ _DEFAULT_LOG_LEVEL + ')')
+ parser.add_argument('--log_level', choices=_VALID_LOG_LEVELS,
+ default=_DEFAULT_LOG_LEVEL, help=log_level_help)
+
+ ar_help = 'command used for parsing .a archives'
+ parser.add_argument('-a', '--ar', type=str, default='llvm-ar', help=ar_help)
+
+ paths_help = ('directories to search or files to parse '
+ '(files should be *.o, *.a, or modules.order). '
+ 'If nothing is specified, the current directory is searched')
+ parser.add_argument('paths', type=str, nargs='*', help=paths_help)
+
+ args = parser.parse_args()
+
+ return (args.log_level,
+ os.path.abspath(args.directory),
+ args.output,
+ args.ar,
+ args.paths if len(args.paths) > 0 else [args.directory])
+
+
+def cmdfiles_in_dir(directory):
+ """Generate the iterator of .cmd files found under the directory.
+
+ Walk under the given directory, and yield every .cmd file found.
+
+ Args:
+ directory: The directory to search for .cmd files.
+
+ Yields:
+ The path to a .cmd file.
+ """
+
+ filename_matcher = re.compile(_FILENAME_PATTERN)
+
+ for dirpath, _, filenames in os.walk(directory):
+ for filename in filenames:
+ if filename_matcher.match(filename):
+ yield os.path.join(dirpath, filename)
+
+
+def to_cmdfile(path):
+ """Return the path of .cmd file used for the given build artifact
+
+ Args:
+ Path: file path
+
+ Returns:
+ The path to .cmd file
+ """
+ dir, base = os.path.split(path)
+ return os.path.join(dir, '.' + base + '.cmd')
+
+
+def cmdfiles_for_o(obj):
+ """Generate the iterator of .cmd files associated with the object
+
+ Yield the .cmd file used to build the given object
+
+ Args:
+ obj: The object path
+
+ Yields:
+ The path to .cmd file
+ """
+ yield to_cmdfile(obj)
+
+
+def cmdfiles_for_a(archive, ar):
+ """Generate the iterator of .cmd files associated with the archive.
+
+ Parse the given archive, and yield every .cmd file used to build it.
+
+ Args:
+ archive: The archive to parse
+
+ Yields:
+ The path to every .cmd file found
+ """
+ for obj in subprocess.check_output([ar, '-t', archive]).decode().split():
+ yield to_cmdfile(obj)
+
+
+def cmdfiles_for_modorder(modorder):
+ """Generate the iterator of .cmd files associated with the modules.order.
+
+ Parse the given modules.order, and yield every .cmd file used to build the
+ contained modules.
+
+ Args:
+ modorder: The modules.order file to parse
+
+ Yields:
+ The path to every .cmd file found
+ """
+ with open(modorder) as f:
+ for line in f:
+ ko = line.rstrip()
+ base, ext = os.path.splitext(ko)
+ if ext != '.ko':
+ sys.exit('{}: module path must end with .ko'.format(ko))
+ mod = base + '.mod'
+ # The first line of *.mod lists the objects that compose the module.
+ with open(mod) as m:
+ for obj in m.readline().split():
+ yield to_cmdfile(obj)
+
+
+def process_line(root_directory, command_prefix, file_path):
+ """Extracts information from a .cmd line and creates an entry from it.
+
+ Args:
+ root_directory: The directory that was searched for .cmd files. Usually
+ used directly in the "directory" entry in compile_commands.json.
+ command_prefix: The extracted command line, up to the last element.
+ file_path: The .c file from the end of the extracted command.
+ Usually relative to root_directory, but sometimes absolute.
+
+ Returns:
+ An entry to append to compile_commands.
+
+ Raises:
+ ValueError: Could not find the extracted file based on file_path and
+ root_directory or file_directory.
+ """
+ # The .cmd files are intended to be included directly by Make, so they
+ # escape the pound sign '#', either as '\#' or '$(pound)' (depending on the
+ # kernel version). The compile_commands.json file is not interepreted
+ # by Make, so this code replaces the escaped version with '#'.
+ prefix = command_prefix.replace('\#', '#').replace('$(pound)', '#')
+
+ # Use os.path.abspath() to normalize the path resolving '.' and '..' .
+ abs_path = os.path.abspath(os.path.join(root_directory, file_path))
+ if not os.path.exists(abs_path):
+ raise ValueError('File %s not found' % abs_path)
+ return {
+ 'directory': root_directory,
+ 'file': abs_path,
+ 'command': prefix + file_path,
+ }
+
+
+def main():
+ """Walks through the directory and finds and parses .cmd files."""
+ log_level, directory, output, ar, paths = parse_arguments()
+
+ level = getattr(logging, log_level)
+ logging.basicConfig(format='%(levelname)s: %(message)s', level=level)
+
+ line_matcher = re.compile(_LINE_PATTERN)
+
+ compile_commands = []
+
+ for path in paths:
+ # If 'path' is a directory, handle all .cmd files under it.
+ # Otherwise, handle .cmd files associated with the file.
+ # Most of built-in objects are linked via archives (built-in.a or lib.a)
+ # but some objects are linked to vmlinux directly.
+ # Modules are listed in modules.order.
+ if os.path.isdir(path):
+ cmdfiles = cmdfiles_in_dir(path)
+ elif path.endswith('.o'):
+ cmdfiles = cmdfiles_for_o(path)
+ elif path.endswith('.a'):
+ cmdfiles = cmdfiles_for_a(path, ar)
+ elif path.endswith('modules.order'):
+ cmdfiles = cmdfiles_for_modorder(path)
+ else:
+ sys.exit('{}: unknown file type'.format(path))
+
+ for cmdfile in cmdfiles:
+ with open(cmdfile, 'rt') as f:
+ result = line_matcher.match(f.readline())
+ if result:
+ try:
+ entry = process_line(directory, result.group(1),
+ result.group(2))
+ compile_commands.append(entry)
+ except ValueError as err:
+ logging.info('Could not add line from %s: %s',
+ cmdfile, err)
+
+ with open(output, 'wt') as f:
+ json.dump(compile_commands, f, indent=2, sort_keys=True)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/clang-tools/run-clang-tools.py b/scripts/clang-tools/run-clang-tools.py
new file mode 100755
index 000000000000..fa7655c7cec0
--- /dev/null
+++ b/scripts/clang-tools/run-clang-tools.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) Google LLC, 2020
+#
+# Author: Nathan Huckleberry <nhuck@google.com>
+#
+"""A helper routine run clang-tidy and the clang static-analyzer on
+compile_commands.json.
+"""
+
+import argparse
+import json
+import multiprocessing
+import os
+import subprocess
+import sys
+
+
+def parse_arguments():
+ """Set up and parses command-line arguments.
+ Returns:
+ args: Dict of parsed args
+ Has keys: [path, type]
+ """
+ usage = """Run clang-tidy or the clang static-analyzer on a
+ compilation database."""
+ parser = argparse.ArgumentParser(description=usage)
+
+ type_help = "Type of analysis to be performed"
+ parser.add_argument("type",
+ choices=["clang-tidy", "clang-analyzer"],
+ help=type_help)
+ path_help = "Path to the compilation database to parse"
+ parser.add_argument("path", type=str, help=path_help)
+
+ return parser.parse_args()
+
+
+def init(l, a):
+ global lock
+ global args
+ lock = l
+ args = a
+
+
+def run_analysis(entry):
+ # Disable all checks, then re-enable the ones we want
+ checks = "-checks=-*,"
+ if args.type == "clang-tidy":
+ checks += "linuxkernel-*"
+ else:
+ checks += "clang-analyzer-*"
+ p = subprocess.run(["clang-tidy", "-p", args.path, checks, entry["file"]],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ cwd=entry["directory"])
+ with lock:
+ sys.stderr.buffer.write(p.stdout)
+
+
+def main():
+ args = parse_arguments()
+
+ lock = multiprocessing.Lock()
+ pool = multiprocessing.Pool(initializer=init, initargs=(lock, args))
+ # Read JSON data into the datastore variable
+ with open(args.path, "r") as f:
+ datastore = json.load(f)
+ pool.map(run_analysis, datastore)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/coccicheck b/scripts/coccicheck
index e04d328210ac..209bb0427b43 100755
--- a/scripts/coccicheck
+++ b/scripts/coccicheck
@@ -75,8 +75,13 @@ else
OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
fi
+ # Use only one thread per core by default if hyperthreading is enabled
+ THREADS_PER_CORE=$(lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]")
if [ -z "$J" ]; then
NPROC=$(getconf _NPROCESSORS_ONLN)
+ if [ $THREADS_PER_CORE -gt 1 -a $NPROC -gt 4 ] ; then
+ NPROC=$((NPROC/2))
+ fi
else
NPROC="$J"
fi
@@ -99,7 +104,7 @@ fi
if [ "$MODE" = "" ] ; then
if [ "$ONLINE" = "0" ] ; then
echo 'You have not explicitly specified the mode to use. Using default "report" mode.'
- echo 'Available modes are the following: patch, report, context, org'
+ echo 'Available modes are the following: patch, report, context, org, chain'
echo 'You can specify the mode with "make coccicheck MODE=<mode>"'
echo 'Note however that some modes are not implemented by some semantic patches.'
fi
@@ -126,8 +131,14 @@ run_cmd_parmap() {
if [ $VERBOSE -ne 0 ] ; then
echo "Running ($NPROC in parallel): $@"
fi
- echo $@ >>$DEBUG_FILE
- $@ 2>>$DEBUG_FILE
+ if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
+ echo $@>>$DEBUG_FILE
+ $@ 2>>$DEBUG_FILE
+ else
+ echo $@
+ $@ 2>&1
+ fi
+
err=$?
if [[ $err -ne 0 ]]; then
echo "coccicheck failed"
diff --git a/scripts/coccinelle/api/alloc/zalloc-simple.cocci b/scripts/coccinelle/api/alloc/zalloc-simple.cocci
index 26cda3f48f01..b3d0c3c230c1 100644
--- a/scripts/coccinelle/api/alloc/zalloc-simple.cocci
+++ b/scripts/coccinelle/api/alloc/zalloc-simple.cocci
@@ -127,6 +127,16 @@ statement S;
if ((x==NULL) || ...) S
- memset((T2)x,0,E1);
+@depends on patch@
+type T, T2;
+expression x;
+expression E1,E2,E3,E4;
+statement S;
+@@
+ x = (T)dma_alloc_coherent(E1, E2, E3, E4);
+ if ((x==NULL) || ...) S
+- memset((T2)x, 0, E2);
+
//----------------------------------------------------------
// For org mode
//----------------------------------------------------------
@@ -199,9 +209,9 @@ statement S;
position p;
@@
- x = (T)dma_alloc_coherent@p(E2,E1,E3,E4);
+ x = (T)dma_alloc_coherent@p(E1,E2,E3,E4);
if ((x==NULL) || ...) S
- memset((T2)x,0,E1);
+ memset((T2)x,0,E2);
@script:python depends on org@
p << r2.p;
@@ -217,7 +227,7 @@ p << r2.p;
x << r2.x;
@@
-msg="WARNING: dma_alloc_coherent use in %s already zeroes out memory, so memset is not needed" % (x)
+msg="WARNING: dma_alloc_coherent used in %s already zeroes out memory, so memset is not needed" % (x)
coccilib.report.print_report(p[0], msg)
//-----------------------------------------------------------------
diff --git a/scripts/coccinelle/api/device_attr_show.cocci b/scripts/coccinelle/api/device_attr_show.cocci
index d8ec4bb8ac41..a28dc061653a 100644
--- a/scripts/coccinelle/api/device_attr_show.cocci
+++ b/scripts/coccinelle/api/device_attr_show.cocci
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
///
-/// From Documentation/filesystems/sysfs.txt:
+/// From Documentation/filesystems/sysfs.rst:
/// show() must not use snprintf() when formatting the value to be
/// returned to user space. If you can guarantee that an overflow
/// will never happen you can use sprintf() otherwise you must use
diff --git a/scripts/coccinelle/api/kfree_mismatch.cocci b/scripts/coccinelle/api/kfree_mismatch.cocci
new file mode 100644
index 000000000000..d46a9b3eb7b3
--- /dev/null
+++ b/scripts/coccinelle/api/kfree_mismatch.cocci
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check that kvmalloc'ed memory is freed by kfree functions,
+/// vmalloc'ed by vfree functions and kvmalloc'ed by kvfree
+/// functions.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@alloc@
+expression E, E1;
+position kok, vok;
+@@
+
+(
+ if (...) {
+ ...
+ E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|
+ kmalloc_node\|kzalloc_node\|kmalloc_array\|
+ kmalloc_array_node\|kcalloc_node\)(...)@kok
+ ...
+ } else {
+ ...
+ E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+ vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+ vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+ __vmalloc_node\)(...)@vok
+ ...
+ }
+|
+ E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+ kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(...)@kok
+ ... when != E = E1
+ when any
+ if (E == NULL) {
+ ...
+ E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+ vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+ vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+ __vmalloc_node\)(...)@vok
+ ...
+ }
+)
+
+@free@
+expression E;
+position fok;
+@@
+
+ E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+ kvmalloc_array\)(...)
+ ...
+ kvfree(E)@fok
+
+@vfree depends on !patch@
+expression E;
+position a != alloc.kok;
+position f != free.fok;
+@@
+
+* E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+* kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+* kcalloc_node\)(...)@a
+ ... when != if (...) { ... E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...); ... }
+ when != is_vmalloc_addr(E)
+ when any
+* \(vfree\|vfree_atomic\|kvfree\)(E)@f
+
+@depends on patch exists@
+expression E;
+position a != alloc.kok;
+position f != free.fok;
+@@
+
+ E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+ kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+ kcalloc_node\)(...)@a
+ ... when != if (...) { ... E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...); ... }
+ when != is_vmalloc_addr(E)
+ when any
+- \(vfree\|vfree_atomic\|kvfree\)(E)@f
++ kfree(E)
+
+@kfree depends on !patch@
+expression E;
+position a != alloc.vok;
+position f != free.fok;
+@@
+
+* E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+* vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+* __vmalloc_node_range\|__vmalloc_node\)(...)@a
+ ... when != is_vmalloc_addr(E)
+ when any
+* \(kfree\|kfree_sensitive\|kvfree\)(E)@f
+
+@depends on patch exists@
+expression E;
+position a != alloc.vok;
+position f != free.fok;
+@@
+
+ E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+ vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+ __vmalloc_node_range\|__vmalloc_node\)(...)@a
+ ... when != is_vmalloc_addr(E)
+ when any
+- \(kfree\|kvfree\)(E)@f
++ vfree(E)
+
+@kvfree depends on !patch@
+expression E;
+position a, f;
+@@
+
+* E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+* kvmalloc_array\)(...)@a
+ ... when != is_vmalloc_addr(E)
+ when any
+* \(kfree\|kfree_sensitive\|vfree\|vfree_atomic\)(E)@f
+
+@depends on patch exists@
+expression E;
+@@
+
+ E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+ kvmalloc_array\)(...)
+ ... when != is_vmalloc_addr(E)
+ when any
+- \(kfree\|vfree\)(E)
++ kvfree(E)
+
+@kvfree_switch depends on !patch@
+expression alloc.E;
+position f;
+@@
+
+ ... when != is_vmalloc_addr(E)
+ when any
+* \(kfree\|kfree_sensitive\|vfree\|vfree_atomic\)(E)@f
+
+@depends on patch exists@
+expression alloc.E;
+position f;
+@@
+
+ ... when != is_vmalloc_addr(E)
+ when any
+(
+- \(kfree\|vfree\)(E)@f
++ kvfree(E)
+|
+- kfree_sensitive(E)@f
++ kvfree_sensitive(E)
+)
+
+@script: python depends on report@
+a << vfree.a;
+f << vfree.f;
+@@
+
+msg = "WARNING kmalloc is used to allocate this memory at line %s" % (a[0].line)
+coccilib.report.print_report(f[0], msg)
+
+@script: python depends on org@
+a << vfree.a;
+f << vfree.f;
+@@
+
+msg = "WARNING kmalloc is used to allocate this memory at line %s" % (a[0].line)
+coccilib.org.print_todo(f[0], msg)
+
+@script: python depends on report@
+a << kfree.a;
+f << kfree.f;
+@@
+
+msg = "WARNING vmalloc is used to allocate this memory at line %s" % (a[0].line)
+coccilib.report.print_report(f[0], msg)
+
+@script: python depends on org@
+a << kfree.a;
+f << kfree.f;
+@@
+
+msg = "WARNING vmalloc is used to allocate this memory at line %s" % (a[0].line)
+coccilib.org.print_todo(f[0], msg)
+
+@script: python depends on report@
+a << kvfree.a;
+f << kvfree.f;
+@@
+
+msg = "WARNING kvmalloc is used to allocate this memory at line %s" % (a[0].line)
+coccilib.report.print_report(f[0], msg)
+
+@script: python depends on org@
+a << kvfree.a;
+f << kvfree.f;
+@@
+
+msg = "WARNING kvmalloc is used to allocate this memory at line %s" % (a[0].line)
+coccilib.org.print_todo(f[0], msg)
+
+@script: python depends on report@
+ka << alloc.kok;
+va << alloc.vok;
+f << kvfree_switch.f;
+@@
+
+msg = "WARNING kmalloc (line %s) && vmalloc (line %s) are used to allocate this memory" % (ka[0].line, va[0].line)
+coccilib.report.print_report(f[0], msg)
+
+@script: python depends on org@
+ka << alloc.kok;
+va << alloc.vok;
+f << kvfree_switch.f;
+@@
+
+msg = "WARNING kmalloc (line %s) && vmalloc (line %s) are used to allocate this memory" % (ka[0].line, va[0].line)
+coccilib.org.print_todo(f[0], msg)
diff --git a/scripts/coccinelle/api/kzfree.cocci b/scripts/coccinelle/api/kfree_sensitive.cocci
index 33625bd7cec9..8d980ebf3223 100644
--- a/scripts/coccinelle/api/kzfree.cocci
+++ b/scripts/coccinelle/api/kfree_sensitive.cocci
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
///
-/// Use kzfree, kvfree_sensitive rather than memset or
-/// memzero_explicit followed by kfree
+/// Use kfree_sensitive, kvfree_sensitive rather than memset or
+/// memzero_explicit followed by kfree.
///
// Confidence: High
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers
//
-// Keywords: kzfree, kvfree_sensitive
+// Keywords: kfree_sensitive, kvfree_sensitive
//
virtual context
@@ -18,7 +18,8 @@ virtual report
@initialize:python@
@@
# kmalloc_oob_in_memset uses memset to explicitly trigger out-of-bounds access
-filter = frozenset(['kmalloc_oob_in_memset', 'kzfree', 'kvfree_sensitive'])
+filter = frozenset(['kmalloc_oob_in_memset',
+ 'kfree_sensitive', 'kvfree_sensitive'])
def relevant(p):
return not (filter & {el.current_element for el in p})
@@ -56,17 +57,13 @@ type T;
- memzero_explicit@m((T)E, size);
... when != E
when strict
-// TODO: uncomment when kfree_sensitive will be merged.
-// Only this case is commented out because developers
-// may not like patches like this since kzfree uses memset
-// internally (not memzero_explicit).
-//(
-//- kfree(E)@p;
-//+ kfree_sensitive(E);
-//|
+(
+- kfree(E)@p;
++ kfree_sensitive(E);
+|
- \(vfree\|kvfree\)(E)@p;
+ kvfree_sensitive(E, size);
-//)
+)
@rp_memset depends on patch@
expression E, size;
@@ -80,7 +77,7 @@ type T;
when strict
(
- kfree(E)@p;
-+ kzfree(E);
++ kfree_sensitive(E);
|
- \(vfree\|kvfree\)(E)@p;
+ kvfree_sensitive(E, size);
@@ -88,14 +85,16 @@ type T;
@script:python depends on report@
p << r.p;
+m << r.m;
@@
-coccilib.report.print_report(p[0],
- "WARNING: opportunity for kzfree/kvfree_sensitive")
+msg = "WARNING opportunity for kfree_sensitive/kvfree_sensitive (memset at line %s)"
+coccilib.report.print_report(p[0], msg % (m[0].line))
@script:python depends on org@
p << r.p;
+m << r.m;
@@
-coccilib.org.print_todo(p[0],
- "WARNING: opportunity for kzfree/kvfree_sensitive")
+msg = "WARNING opportunity for kfree_sensitive/kvfree_sensitive (memset at line %s)"
+coccilib.org.print_todo(p[0], msg % (m[0].line))
diff --git a/scripts/coccinelle/api/kobj_to_dev.cocci b/scripts/coccinelle/api/kobj_to_dev.cocci
new file mode 100644
index 000000000000..cd5d31c6fe76
--- /dev/null
+++ b/scripts/coccinelle/api/kobj_to_dev.cocci
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Use kobj_to_dev() instead of container_of()
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: kobj_to_dev, container_of
+//
+
+virtual context
+virtual report
+virtual org
+virtual patch
+
+
+@r depends on !patch@
+expression ptr;
+symbol kobj;
+position p;
+@@
+
+* container_of(ptr, struct device, kobj)@p
+
+
+@depends on patch@
+expression ptr;
+@@
+
+- container_of(ptr, struct device, kobj)
++ kobj_to_dev(ptr)
+
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for kobj_to_dev()")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for kobj_to_dev()")
diff --git a/scripts/coccinelle/api/kvmalloc.cocci b/scripts/coccinelle/api/kvmalloc.cocci
new file mode 100644
index 000000000000..c30dab718a49
--- /dev/null
+++ b/scripts/coccinelle/api/kvmalloc.cocci
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Find if/else condition with kmalloc/vmalloc calls.
+/// Suggest to use kvmalloc instead. Same for kvfree.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@initialize:python@
+@@
+filter = frozenset(['kvfree'])
+
+def relevant(p):
+ return not (filter & {el.current_element for el in p})
+
+@kvmalloc depends on !patch@
+expression E, E1, size;
+identifier flags;
+binary operator cmp = {<=, <, ==, >, >=};
+identifier x;
+type T;
+position p;
+@@
+
+(
+* if (size cmp E1 || ...)@p {
+ ...
+* E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+* kmalloc_array\|kmalloc_array_node\|kcalloc_node\)
+* (..., size, \(flags\|GFP_KERNEL\|\(GFP_KERNEL\|flags\)|__GFP_NOWARN\), ...)
+ ...
+ } else {
+ ...
+* E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+ ...
+ }
+|
+* E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+* kmalloc_array\|kmalloc_array_node\|kcalloc_node\)
+* (..., size, \(flags\|GFP_KERNEL\|\(GFP_KERNEL\|flags\)|__GFP_NOWARN\), ...)
+ ... when != E = E1
+ when != size = E1
+ when any
+* if (E == NULL)@p {
+ ...
+* E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+ ...
+ }
+|
+* T x = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+* kmalloc_array\|kmalloc_array_node\|kcalloc_node\)
+* (..., size, \(flags\|GFP_KERNEL\|\(GFP_KERNEL\|flags\)|__GFP_NOWARN\), ...);
+ ... when != x = E1
+ when != size = E1
+ when any
+* if (x == NULL)@p {
+ ...
+* x = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+ ...
+ }
+)
+
+@kvfree depends on !patch@
+expression E;
+position p : script:python() { relevant(p) };
+@@
+
+* if (is_vmalloc_addr(E))@p {
+ ...
+* vfree(E)
+ ...
+ } else {
+ ... when != krealloc(E, ...)
+ when any
+* \(kfree\|kzfree\)(E)
+ ...
+ }
+
+@depends on patch@
+expression E, E1, size, node;
+binary operator cmp = {<=, <, ==, >, >=};
+identifier flags, x;
+type T;
+@@
+
+(
+- if (size cmp E1)
+- E = kmalloc(size, flags);
+- else
+- E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- if (size cmp E1)
+- E = kmalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- else
+- E = vmalloc(size);
++ E = kvmalloc(size, GFP_KERNEL);
+|
+- E = kmalloc(size, flags | __GFP_NOWARN);
+- if (E == NULL)
+- E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- E = kmalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- if (E == NULL)
+- E = vmalloc(size);
++ E = kvmalloc(size, GFP_KERNEL);
+|
+- T x = kmalloc(size, flags | __GFP_NOWARN);
+- if (x == NULL)
+- x = vmalloc(size);
++ T x = kvmalloc(size, flags);
+|
+- T x = kmalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- if (x == NULL)
+- x = vmalloc(size);
++ T x = kvmalloc(size, GFP_KERNEL);
+|
+- if (size cmp E1)
+- E = kzalloc(size, flags);
+- else
+- E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- if (size cmp E1)
+- E = kzalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- else
+- E = vzalloc(size);
++ E = kvzalloc(size, GFP_KERNEL);
+|
+- E = kzalloc(size, flags | __GFP_NOWARN);
+- if (E == NULL)
+- E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- E = kzalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- if (E == NULL)
+- E = vzalloc(size);
++ E = kvzalloc(size, GFP_KERNEL);
+|
+- T x = kzalloc(size, flags | __GFP_NOWARN);
+- if (x == NULL)
+- x = vzalloc(size);
++ T x = kvzalloc(size, flags);
+|
+- T x = kzalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- if (x == NULL)
+- x = vzalloc(size);
++ T x = kvzalloc(size, GFP_KERNEL);
+|
+- if (size cmp E1)
+- E = kmalloc_node(size, flags, node);
+- else
+- E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, flags, node);
+|
+- if (size cmp E1)
+- E = kmalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
+- else
+- E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, GFP_KERNEL, node);
+|
+- E = kmalloc_node(size, flags | __GFP_NOWARN, node);
+- if (E == NULL)
+- E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, flags, node);
+|
+- E = kmalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
+- if (E == NULL)
+- E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, GFP_KERNEL, node);
+|
+- T x = kmalloc_node(size, flags | __GFP_NOWARN, node);
+- if (x == NULL)
+- x = vmalloc_node(size, node);
++ T x = kvmalloc_node(size, flags, node);
+|
+- T x = kmalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
+- if (x == NULL)
+- x = vmalloc_node(size, node);
++ T x = kvmalloc_node(size, GFP_KERNEL, node);
+|
+- if (size cmp E1)
+- E = kvzalloc_node(size, flags, node);
+- else
+- E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, flags, node);
+|
+- if (size cmp E1)
+- E = kvzalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
+- else
+- E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, GFP_KERNEL, node);
+|
+- E = kvzalloc_node(size, flags | __GFP_NOWARN, node);
+- if (E == NULL)
+- E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, flags, node);
+|
+- E = kvzalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
+- if (E == NULL)
+- E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, GFP_KERNEL, node);
+|
+- T x = kvzalloc_node(size, flags | __GFP_NOWARN, node);
+- if (x == NULL)
+- x = vzalloc_node(size, node);
++ T x = kvzalloc_node(size, flags, node);
+|
+- T x = kvzalloc_node(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\), node);
+- if (x == NULL)
+- x = vzalloc_node(size, node);
++ T x = kvzalloc_node(size, GFP_KERNEL, node);
+)
+
+@depends on patch@
+expression E;
+position p : script:python() { relevant(p) };
+@@
+
+- if (is_vmalloc_addr(E))@p
+- vfree(E);
+- else
+- kfree(E);
++ kvfree(E);
+
+@script: python depends on report@
+p << kvmalloc.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for kvmalloc")
+
+@script: python depends on org@
+p << kvmalloc.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for kvmalloc")
+
+@script: python depends on report@
+p << kvfree.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for kvfree")
+
+@script: python depends on org@
+p << kvfree.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for kvfree")
diff --git a/scripts/coccinelle/free/ifnullfree.cocci b/scripts/coccinelle/free/ifnullfree.cocci
index 2045391e36a0..285b92d5c665 100644
--- a/scripts/coccinelle/free/ifnullfree.cocci
+++ b/scripts/coccinelle/free/ifnullfree.cocci
@@ -21,8 +21,14 @@ expression E;
(
kfree(E);
|
+ kvfree(E);
+|
kfree_sensitive(E);
|
+ kvfree_sensitive(E, ...);
+|
+ vfree(E);
+|
debugfs_remove(E);
|
debugfs_remove_recursive(E);
@@ -42,9 +48,10 @@ position p;
@@
* if (E != NULL)
-* \(kfree@p\|kfree_sensitive@p\|debugfs_remove@p\|debugfs_remove_recursive@p\|
+* \(kfree@p\|kvfree@p\|kfree_sensitive@p\|kvfree_sensitive@p\|vfree@p\|
+* debugfs_remove@p\|debugfs_remove_recursive@p\|
* usb_free_urb@p\|kmem_cache_destroy@p\|mempool_destroy@p\|
-* dma_pool_destroy@p\)(E);
+* dma_pool_destroy@p\)(E, ...);
@script:python depends on org@
p << r.p;
diff --git a/scripts/coccinelle/iterators/for_each_child.cocci b/scripts/coccinelle/iterators/for_each_child.cocci
new file mode 100644
index 000000000000..bc394615948e
--- /dev/null
+++ b/scripts/coccinelle/iterators/for_each_child.cocci
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Adds missing of_node_put() before return/break/goto statement within a for_each iterator for child nodes.
+//# False positives can be due to function calls within the for_each
+//# loop that may encapsulate an of_node_put.
+///
+// Confidence: High
+// Copyright: (C) 2020 Sumera Priyadarsini
+// URL: http://coccinelle.lip6.fr
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@r@
+local idexpression n;
+expression e1,e2;
+iterator name for_each_node_by_name, for_each_node_by_type,
+for_each_compatible_node, for_each_matching_node,
+for_each_matching_node_and_match, for_each_child_of_node,
+for_each_available_child_of_node, for_each_node_with_property;
+iterator i;
+statement S;
+expression list [n1] es;
+@@
+
+(
+(
+for_each_node_by_name(n,e1) S
+|
+for_each_node_by_type(n,e1) S
+|
+for_each_compatible_node(n,e1,e2) S
+|
+for_each_matching_node(n,e1) S
+|
+for_each_matching_node_and_match(n,e1,e2) S
+|
+for_each_child_of_node(e1,n) S
+|
+for_each_available_child_of_node(e1,n) S
+|
+for_each_node_with_property(n,e1) S
+)
+&
+i(es,n,...) S
+)
+
+@ruleone depends on patch && !context && !org && !report@
+
+local idexpression r.n;
+iterator r.i,i1;
+expression e;
+expression list [r.n1] es;
+statement S;
+@@
+
+ i(es,n,...) {
+ ...
+(
+ of_node_put(n);
+|
+ e = n
+|
+ return n;
+|
+ i1(...,n,...) S
+|
+- return of_node_get(n);
++ return n;
+|
++ of_node_put(n);
+? return ...;
+)
+ ... when any
+ }
+
+@ruletwo depends on patch && !context && !org && !report@
+
+local idexpression r.n;
+iterator r.i,i1,i2;
+expression e,e1;
+expression list [r.n1] es;
+statement S,S2;
+@@
+
+ i(es,n,...) {
+ ...
+(
+ of_node_put(n);
+|
+ e = n
+|
+ i1(...,n,...) S
+|
++ of_node_put(n);
+? break;
+)
+ ... when any
+ }
+... when != n
+ when strict
+ when forall
+(
+ n = e1;
+|
+?i2(...,n,...) S2
+)
+
+@rulethree depends on patch && !context && !org && !report exists@
+
+local idexpression r.n;
+iterator r.i,i1,i2;
+expression e,e1;
+identifier l;
+expression list [r.n1] es;
+statement S,S2;
+@@
+
+ i(es,n,...) {
+ ...
+(
+ of_node_put(n);
+|
+ e = n
+|
+ i1(...,n,...) S
+|
++ of_node_put(n);
+? goto l;
+)
+ ... when any
+ }
+... when exists
+l: ... when != n
+ when strict
+ when forall
+(
+ n = e1;
+|
+?i2(...,n,...) S2
+)
+
+// ----------------------------------------------------------------------------
+
+@ruleone_context depends on !patch && (context || org || report) exists@
+statement S;
+expression e;
+expression list[r.n1] es;
+iterator r.i, i1;
+local idexpression r.n;
+position j0, j1;
+@@
+
+ i@j0(es,n,...) {
+ ...
+(
+ of_node_put(n);
+|
+ e = n
+|
+ return n;
+|
+ i1(...,n,...) S
+|
+ return @j1 ...;
+)
+ ... when any
+ }
+
+@ruleone_disj depends on !patch && (context || org || report)@
+expression list[r.n1] es;
+iterator r.i;
+local idexpression r.n;
+position ruleone_context.j0, ruleone_context.j1;
+@@
+
+* i@j0(es,n,...) {
+ ...
+*return @j1...;
+ ... when any
+ }
+
+@ruletwo_context depends on !patch && (context || org || report) exists@
+statement S, S2;
+expression e, e1;
+expression list[r.n1] es;
+iterator r.i, i1, i2;
+local idexpression r.n;
+position j0, j2;
+@@
+
+ i@j0(es,n,...) {
+ ...
+(
+ of_node_put(n);
+|
+ e = n
+|
+ i1(...,n,...) S
+|
+ break@j2;
+)
+ ... when any
+ }
+... when != n
+ when strict
+ when forall
+(
+ n = e1;
+|
+?i2(...,n,...) S2
+)
+
+@ruletwo_disj depends on !patch && (context || org || report)@
+statement S2;
+expression e1;
+expression list[r.n1] es;
+iterator r.i, i2;
+local idexpression r.n;
+position ruletwo_context.j0, ruletwo_context.j2;
+@@
+
+* i@j0(es,n,...) {
+ ...
+*break @j2;
+ ... when any
+ }
+... when != n
+ when strict
+ when forall
+(
+ n = e1;
+|
+?i2(...,n,...) S2
+)
+
+@rulethree_context depends on !patch && (context || org || report) exists@
+identifier l;
+statement S,S2;
+expression e, e1;
+expression list[r.n1] es;
+iterator r.i, i1, i2;
+local idexpression r.n;
+position j0, j3;
+@@
+
+ i@j0(es,n,...) {
+ ...
+(
+ of_node_put(n);
+|
+ e = n
+|
+ i1(...,n,...) S
+|
+ goto l@j3;
+)
+ ... when any
+ }
+... when exists
+l:
+... when != n
+ when strict
+ when forall
+(
+ n = e1;
+|
+?i2(...,n,...) S2
+)
+
+@rulethree_disj depends on !patch && (context || org || report) exists@
+identifier l;
+statement S2;
+expression e1;
+expression list[r.n1] es;
+iterator r.i, i2;
+local idexpression r.n;
+position rulethree_context.j0, rulethree_context.j3;
+@@
+
+* i@j0(es,n,...) {
+ ...
+*goto l@j3;
+ ... when any
+ }
+... when exists
+ l:
+ ... when != n
+ when strict
+ when forall
+(
+ n = e1;
+|
+?i2(...,n,...) S2
+)
+
+// ----------------------------------------------------------------------------
+
+@script:python ruleone_org depends on org@
+i << r.i;
+j0 << ruleone_context.j0;
+j1 << ruleone_context. j1;
+@@
+
+msg = "WARNING: Function \"%s\" should have of_node_put() before return " % (i)
+coccilib.org.print_safe_todo(j0[0], msg)
+coccilib.org.print_link(j1[0], "")
+
+@script:python ruletwo_org depends on org@
+i << r.i;
+j0 << ruletwo_context.j0;
+j2 << ruletwo_context.j2;
+@@
+
+msg = "WARNING: Function \"%s\" should have of_node_put() before break " % (i)
+coccilib.org.print_safe_todo(j0[0], msg)
+coccilib.org.print_link(j2[0], "")
+
+@script:python rulethree_org depends on org@
+i << r.i;
+j0 << rulethree_context.j0;
+j3 << rulethree_context.j3;
+@@
+
+msg = "WARNING: Function \"%s\" should have of_node_put() before goto " % (i)
+coccilib.org.print_safe_todo(j0[0], msg)
+coccilib.org.print_link(j3[0], "")
+
+// ----------------------------------------------------------------------------
+
+@script:python ruleone_report depends on report@
+i << r.i;
+j0 << ruleone_context.j0;
+j1 << ruleone_context.j1;
+@@
+
+msg = "WARNING: Function \"%s\" should have of_node_put() before return around line %s." % (i, j1[0].line)
+coccilib.report.print_report(j0[0], msg)
+
+@script:python ruletwo_report depends on report@
+i << r.i;
+j0 << ruletwo_context.j0;
+j2 << ruletwo_context.j2;
+@@
+
+msg = "WARNING: Function \"%s\" should have of_node_put() before break around line %s." % (i,j2[0].line)
+coccilib.report.print_report(j0[0], msg)
+
+@script:python rulethree_report depends on report@
+i << r.i;
+j0 << rulethree_context.j0;
+j3 << rulethree_context.j3;
+@@
+
+msg = "WARNING: Function \"%s\" should have of_node_put() before goto around lines %s." % (i,j3[0].line)
+coccilib.report.print_report(j0[0], msg)
diff --git a/scripts/coccinelle/misc/excluded_middle.cocci b/scripts/coccinelle/misc/excluded_middle.cocci
new file mode 100644
index 000000000000..ab28393e4843
--- /dev/null
+++ b/scripts/coccinelle/misc/excluded_middle.cocci
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Condition !A || A && B is equivalent to !A || B.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@r depends on !patch@
+expression A, B;
+position p;
+@@
+
+* !A || (A &&@p B)
+
+@depends on patch@
+expression A, B;
+@@
+
+ !A ||
+- (A && B)
++ B
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING !A || A && B is equivalent to !A || B")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING !A || A && B is equivalent to !A || B")
diff --git a/scripts/coccinelle/misc/flexible_array.cocci b/scripts/coccinelle/misc/flexible_array.cocci
new file mode 100644
index 000000000000..947fbaff82a9
--- /dev/null
+++ b/scripts/coccinelle/misc/flexible_array.cocci
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Zero-length and one-element arrays are deprecated, see
+/// Documentation/process/deprecated.rst
+/// Flexible-array members should be used instead.
+///
+//
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS.
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual report
+virtual org
+virtual patch
+
+@initialize:python@
+@@
+def relevant(positions):
+ for p in positions:
+ if "uapi" in p.file:
+ return False
+ return True
+
+@r depends on !patch@
+identifier name, array;
+type T;
+position p : script:python() { relevant(p) };
+@@
+
+(
+ struct name {
+ ...
+* T array@p[\(0\|1\)];
+ };
+|
+ struct {
+ ...
+* T array@p[\(0\|1\)];
+ };
+|
+ union name {
+ ...
+* T array@p[\(0\|1\)];
+ };
+|
+ union {
+ ...
+* T array@p[\(0\|1\)];
+ };
+)
+
+@depends on patch@
+identifier name, array;
+type T;
+position p : script:python() { relevant(p) };
+@@
+
+(
+ struct name {
+ ...
+ T array@p[
+- 0
+ ];
+ };
+|
+ struct {
+ ...
+ T array@p[
+- 0
+ ];
+ };
+)
+
+@script: python depends on report@
+p << r.p;
+@@
+
+msg = "WARNING use flexible-array member instead (https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays)"
+coccilib.report.print_report(p[0], msg)
+
+@script: python depends on org@
+p << r.p;
+@@
+
+msg = "WARNING use flexible-array member instead (https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays)"
+coccilib.org.print_todo(p[0], msg)
diff --git a/scripts/coccinelle/misc/uninitialized_var.cocci b/scripts/coccinelle/misc/uninitialized_var.cocci
new file mode 100644
index 000000000000..8fa845cefe11
--- /dev/null
+++ b/scripts/coccinelle/misc/uninitialized_var.cocci
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Please, don't reintroduce uninitialized_var().
+/// From Documentation/process/deprecated.rst:
+/// For any compiler warnings about uninitialized variables, just add
+/// an initializer. Using warning-silencing tricks is dangerous as it
+/// papers over real bugs (or can in the future), and suppresses unrelated
+/// compiler warnings (e.g. "unused variable"). If the compiler thinks it
+/// is uninitialized, either simply initialize the variable or make compiler
+/// changes. Keep in mind that in most cases, if an initialization is
+/// obviously redundant, the compiler's dead-store elimination pass will make
+/// sure there are no needless variable writes.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual context
+virtual report
+virtual org
+
+@r@
+identifier var;
+type T;
+position p;
+@@
+
+(
+* T var =@p var;
+|
+* T var =@p *(&(var));
+|
+* var =@p var
+|
+* var =@p *(&(var))
+)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0],
+ "WARNING this kind of initialization is deprecated (https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0],
+ "WARNING this kind of initialization is deprecated (https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch
index e9df9cc28a85..1aae4f4fdacc 100644
--- a/scripts/const_structs.checkpatch
+++ b/scripts/const_structs.checkpatch
@@ -39,6 +39,9 @@ nlmsvc_binding
nvkm_device_chip
of_device_id
pci_raw_ops
+phy_ops
+pinctrl_ops
+pinmux_ops
pipe_buf_operations
platform_hibernation_ops
platform_suspend_ops
diff --git a/scripts/decodecode b/scripts/decodecode
index fbdb325cdf4f..31d884e35f2f 100755
--- a/scripts/decodecode
+++ b/scripts/decodecode
@@ -6,6 +6,7 @@
# options: set env. variable AFLAGS=options to pass options to "as";
# e.g., to decode an i386 oops on an x86_64 system, use:
# AFLAGS=--32 decodecode < 386.oops
+# PC=hex - the PC (program counter) the oops points to
cleanup() {
rm -f $T $T.s $T.o $T.oo $T.aa $T.dis
@@ -67,15 +68,19 @@ if [ -z "$ARCH" ]; then
esac
fi
+# Params: (tmp_file, pc_sub)
disas() {
- ${CROSS_COMPILE}as $AFLAGS -o $1.o $1.s > /dev/null 2>&1
+ t=$1
+ pc_sub=$2
+
+ ${CROSS_COMPILE}as $AFLAGS -o $t.o $t.s > /dev/null 2>&1
if [ "$ARCH" = "arm" ]; then
if [ $width -eq 2 ]; then
OBJDUMPFLAGS="-M force-thumb"
fi
- ${CROSS_COMPILE}strip $1.o
+ ${CROSS_COMPILE}strip $t.o
fi
if [ "$ARCH" = "arm64" ]; then
@@ -83,11 +88,18 @@ disas() {
type=inst
fi
- ${CROSS_COMPILE}strip $1.o
+ ${CROSS_COMPILE}strip $t.o
fi
- ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $1.o | \
- grep -v "/tmp\|Disassembly\|\.text\|^$" > $1.dis 2>&1
+ if [ $pc_sub -ne 0 ]; then
+ if [ $PC ]; then
+ adj_vma=$(( $PC - $pc_sub ))
+ OBJDUMPFLAGS="$OBJDUMPFLAGS --adjust-vma=$adj_vma"
+ fi
+ fi
+
+ ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $t.o | \
+ grep -v "/tmp\|Disassembly\|\.text\|^$" > $t.dis 2>&1
}
marker=`expr index "$code" "\<"`
@@ -95,14 +107,17 @@ if [ $marker -eq 0 ]; then
marker=`expr index "$code" "\("`
fi
+
touch $T.oo
if [ $marker -ne 0 ]; then
+ # 2 opcode bytes and a single space
+ pc_sub=$(( $marker / 3 ))
echo All code >> $T.oo
echo ======== >> $T.oo
beforemark=`echo "$code"`
echo -n " .$type 0x" > $T.s
echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s
- disas $T
+ disas $T $pc_sub
cat $T.dis >> $T.oo
rm -f $T.o $T.s $T.dis
@@ -114,7 +129,7 @@ echo =========================================== >> $T.aa
code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`
echo -n " .$type 0x" > $T.s
echo $code >> $T.s
-disas $T
+disas $T 0
cat $T.dis >> $T.aa
# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3,
diff --git a/scripts/dev-needs.sh b/scripts/dev-needs.sh
new file mode 100755
index 000000000000..454cc304fb44
--- /dev/null
+++ b/scripts/dev-needs.sh
@@ -0,0 +1,315 @@
+#! /bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020, Google LLC. All rights reserved.
+# Author: Saravana Kannan <saravanak@google.com>
+
+function help() {
+ cat << EOF
+Usage: $(basename $0) [-c|-d|-m|-f] [filter options] <list of devices>
+
+This script needs to be run on the target device once it has booted to a
+shell.
+
+The script takes as input a list of one or more device directories under
+/sys/devices and then lists the probe dependency chain (suppliers and
+parents) of these devices. It does a breadth first search of the dependency
+chain, so the last entry in the output is close to the root of the
+dependency chain.
+
+By default it lists the full path to the devices under /sys/devices.
+
+It also takes an optional modifier flag as the first parameter to change
+what information is listed in the output. If the requested information is
+not available, the device name is printed.
+
+ -c lists the compatible string of the dependencies
+ -d lists the driver name of the dependencies that have probed
+ -m lists the module name of the dependencies that have a module
+ -f list the firmware node path of the dependencies
+ -g list the dependencies as edges and nodes for graphviz
+ -t list the dependencies as edges for tsort
+
+The filter options provide a way to filter out some dependencies:
+ --allow-no-driver By default dependencies that don't have a driver
+ attached are ignored. This is to avoid following
+ device links to "class" devices that are created
+ when the consumer probes (as in, not a probe
+ dependency). If you want to follow these links
+ anyway, use this flag.
+
+ --exclude-devlinks Don't follow device links when tracking probe
+ dependencies.
+
+ --exclude-parents Don't follow parent devices when tracking probe
+ dependencies.
+
+EOF
+}
+
+function dev_to_detail() {
+ local i=0
+ while [ $i -lt ${#OUT_LIST[@]} ]
+ do
+ local C=${OUT_LIST[i]}
+ local S=${OUT_LIST[i+1]}
+ local D="'$(detail_chosen $C $S)'"
+ if [ ! -z "$D" ]
+ then
+ # This weirdness is needed to work with toybox when
+ # using the -t option.
+ printf '%05u\t%s\n' ${i} "$D" | tr -d \'
+ fi
+ i=$((i+2))
+ done
+}
+
+function already_seen() {
+ local i=0
+ while [ $i -lt ${#OUT_LIST[@]} ]
+ do
+ if [ "$1" = "${OUT_LIST[$i]}" ]
+ then
+ # if-statement treats 0 (no-error) as true
+ return 0
+ fi
+ i=$(($i+2))
+ done
+
+ # if-statement treats 1 (error) as false
+ return 1
+}
+
+# Return 0 (no-error/true) if parent was added
+function add_parent() {
+
+ if [ ${ALLOW_PARENTS} -eq 0 ]
+ then
+ return 1
+ fi
+
+ local CON=$1
+ # $CON could be a symlink path. So, we need to find the real path and
+ # then go up one level to find the real parent.
+ local PARENT=$(realpath $CON/..)
+
+ while [ ! -e ${PARENT}/driver ]
+ do
+ if [ "$PARENT" = "/sys/devices" ]
+ then
+ return 1
+ fi
+ PARENT=$(realpath $PARENT/..)
+ done
+
+ CONSUMERS+=($PARENT)
+ OUT_LIST+=(${CON} ${PARENT})
+ return 0
+}
+
+# Return 0 (no-error/true) if one or more suppliers were added
+function add_suppliers() {
+ local CON=$1
+ local RET=1
+
+ if [ ${ALLOW_DEVLINKS} -eq 0 ]
+ then
+ return 1
+ fi
+
+ SUPPLIER_LINKS=$(ls -1d $CON/supplier:* 2>/dev/null)
+ for SL in $SUPPLIER_LINKS;
+ do
+ SYNC_STATE=$(cat $SL/sync_state_only)
+
+ # sync_state_only links are proxy dependencies.
+ # They can also have cycles. So, don't follow them.
+ if [ "$SYNC_STATE" != '0' ]
+ then
+ continue
+ fi
+
+ SUPPLIER=$(realpath $SL/supplier)
+
+ if [ ! -e $SUPPLIER/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
+ then
+ continue
+ fi
+
+ CONSUMERS+=($SUPPLIER)
+ OUT_LIST+=(${CON} ${SUPPLIER})
+ RET=0
+ done
+
+ return $RET
+}
+
+function detail_compat() {
+ f=$1/of_node/compatible
+ if [ -e $f ]
+ then
+ echo -n $(cat $f)
+ else
+ echo -n $1
+ fi
+}
+
+function detail_module() {
+ f=$1/driver/module
+ if [ -e $f ]
+ then
+ echo -n $(basename $(realpath $f))
+ else
+ echo -n $1
+ fi
+}
+
+function detail_driver() {
+ f=$1/driver
+ if [ -e $f ]
+ then
+ echo -n $(basename $(realpath $f))
+ else
+ echo -n $1
+ fi
+}
+
+function detail_fwnode() {
+ f=$1/firmware_node
+ if [ ! -e $f ]
+ then
+ f=$1/of_node
+ fi
+
+ if [ -e $f ]
+ then
+ echo -n $(realpath $f)
+ else
+ echo -n $1
+ fi
+}
+
+function detail_graphviz() {
+ if [ "$2" != "ROOT" ]
+ then
+ echo -n "\"$(basename $2)\"->\"$(basename $1)\""
+ else
+ echo -n "\"$(basename $1)\""
+ fi
+}
+
+function detail_tsort() {
+ echo -n "\"$2\" \"$1\""
+}
+
+function detail_device() { echo -n $1; }
+
+alias detail=detail_device
+ALLOW_NO_DRIVER=0
+ALLOW_DEVLINKS=1
+ALLOW_PARENTS=1
+
+while [ $# -gt 0 ]
+do
+ ARG=$1
+ case $ARG in
+ --help)
+ help
+ exit 0
+ ;;
+ -c)
+ alias detail=detail_compat
+ ;;
+ -m)
+ alias detail=detail_module
+ ;;
+ -d)
+ alias detail=detail_driver
+ ;;
+ -f)
+ alias detail=detail_fwnode
+ ;;
+ -g)
+ alias detail=detail_graphviz
+ ;;
+ -t)
+ alias detail=detail_tsort
+ ;;
+ --allow-no-driver)
+ ALLOW_NO_DRIVER=1
+ ;;
+ --exclude-devlinks)
+ ALLOW_DEVLINKS=0
+ ;;
+ --exclude-parents)
+ ALLOW_PARENTS=0
+ ;;
+ *)
+ # Stop at the first argument that's not an option.
+ break
+ ;;
+ esac
+ shift
+done
+
+function detail_chosen() {
+ detail $1 $2
+}
+
+if [ $# -eq 0 ]
+then
+ help
+ exit 1
+fi
+
+CONSUMERS=($@)
+OUT_LIST=()
+
+# Do a breadth first, non-recursive tracking of suppliers. The parent is also
+# considered a "supplier" as a device can't probe without its parent.
+i=0
+while [ $i -lt ${#CONSUMERS[@]} ]
+do
+ CONSUMER=$(realpath ${CONSUMERS[$i]})
+ i=$(($i+1))
+
+ if already_seen ${CONSUMER}
+ then
+ continue
+ fi
+
+ # If this is not a device with a driver, we don't care about its
+ # suppliers.
+ if [ ! -e ${CONSUMER}/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
+ then
+ continue
+ fi
+
+ ROOT=1
+
+ # Add suppliers to CONSUMERS list and output the consumer details.
+ #
+ # We don't need to worry about a cycle in the dependency chain causing
+ # infinite loops. That's because the kernel doesn't allow cycles in
+ # device links unless it's a sync_state_only device link. And we ignore
+ # sync_state_only device links inside add_suppliers.
+ if add_suppliers ${CONSUMER}
+ then
+ ROOT=0
+ fi
+
+ if add_parent ${CONSUMER}
+ then
+ ROOT=0
+ fi
+
+ if [ $ROOT -eq 1 ]
+ then
+ OUT_LIST+=(${CONSUMER} "ROOT")
+ fi
+done
+
+# Can NOT combine sort and uniq using sort -suk2 because stable sort in toybox
+# isn't really stable.
+dev_to_detail | sort -k2 -k1 | uniq -f 1 | sort | cut -f2-
+
+exit 0
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile
index a698ece43fff..4852bf44e913 100644
--- a/scripts/dtc/Makefile
+++ b/scripts/dtc/Makefile
@@ -9,7 +9,7 @@ dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
# Source files need to get at the userspace version of libfdt_env.h to compile
-HOST_EXTRACFLAGS := -I $(srctree)/$(src)/libfdt
+HOST_EXTRACFLAGS += -I $(srctree)/$(src)/libfdt
ifeq ($(shell pkg-config --exists yaml-0.1 2>/dev/null && echo yes),)
ifneq ($(CHECK_DT_BINDING)$(CHECK_DTBS),)
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
index b7955dbd71ca..17cb6890d45a 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -891,10 +891,8 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no
return;
prop = get_property(node, "reg");
- if (!prop) {
- FAIL(c, dti, node, "missing PCI reg property");
+ if (!prop)
return;
- }
cells = (cell_t *)prop->val.val;
if (cells[1] || cells[2])
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
index 40dcf4f149da..a0316a3cc309 100644
--- a/scripts/dtc/dtc-parser.y
+++ b/scripts/dtc/dtc-parser.y
@@ -476,8 +476,8 @@ integer_rela:
;
integer_shift:
- integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
- | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
+ integer_shift DT_LSHIFT integer_add { $$ = ($3 < 64) ? ($1 << $3) : 0; }
+ | integer_shift DT_RSHIFT integer_add { $$ = ($3 < 64) ? ($1 >> $3) : 0; }
| integer_add
;
diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff
index 541c432e7d19..d3422ee15e30 100755
--- a/scripts/dtc/dtx_diff
+++ b/scripts/dtc/dtx_diff
@@ -29,7 +29,8 @@ Usage:
-s SRCTREE linux kernel source tree is at path SRCTREE
(default is current directory)
-S linux kernel source tree is at root of current git repo
- -T Annotate output .dts with input source file and line (-T -T for more details)
+ -T annotate output .dts with input source file and line
+ (-T -T for more details)
-u unsorted, do not sort DTx
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index c28fcc115771..6cf2fa03b037 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -134,16 +134,20 @@ int fdt_check_header(const void *fdt)
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
- unsigned absoffset = offset + fdt_off_dt_struct(fdt);
+ unsigned int uoffset = offset;
+ unsigned int absoffset = offset + fdt_off_dt_struct(fdt);
+
+ if (offset < 0)
+ return NULL;
if (!can_assume(VALID_INPUT))
- if ((absoffset < offset)
+ if ((absoffset < uoffset)
|| ((absoffset + len) < absoffset)
|| (absoffset + len) > fdt_totalsize(fdt))
return NULL;
if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
- if (((offset + len) < offset)
+ if (((uoffset + len) < uoffset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
@@ -206,10 +210,11 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
int fdt_check_node_offset_(const void *fdt, int offset)
{
- if (can_assume(VALID_INPUT))
- return offset;
- if ((offset < 0) || (offset % FDT_TAGSIZE)
- || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+ if (!can_assume(VALID_INPUT)
+ && ((offset < 0) || (offset % FDT_TAGSIZE)))
+ return -FDT_ERR_BADOFFSET;
+
+ if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
return offset;
@@ -217,8 +222,11 @@ int fdt_check_node_offset_(const void *fdt, int offset)
int fdt_check_prop_offset_(const void *fdt, int offset)
{
- if ((offset < 0) || (offset % FDT_TAGSIZE)
- || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
+ if (!can_assume(VALID_INPUT)
+ && ((offset < 0) || (offset % FDT_TAGSIZE)))
+ return -FDT_ERR_BADOFFSET;
+
+ if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)
return -FDT_ERR_BADOFFSET;
return offset;
@@ -306,9 +314,12 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
int fdt_move(const void *fdt, void *buf, int bufsize)
{
+ if (!can_assume(VALID_INPUT) && bufsize < 0)
+ return -FDT_ERR_NOSPACE;
+
FDT_RO_PROBE(fdt);
- if (fdt_totalsize(fdt) > bufsize)
+ if (fdt_totalsize(fdt) > (unsigned int)bufsize)
return -FDT_ERR_NOSPACE;
memmove(buf, fdt, fdt_totalsize(fdt));
diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c
index b310e49a698e..d217e79b6722 100644
--- a/scripts/dtc/libfdt/fdt_overlay.c
+++ b/scripts/dtc/libfdt/fdt_overlay.c
@@ -241,6 +241,7 @@ static int overlay_update_local_node_references(void *fdto,
if (fixup_len % sizeof(uint32_t))
return -FDT_ERR_BADOVERLAY;
+ fixup_len /= sizeof(uint32_t);
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
if (!tree_val) {
@@ -250,7 +251,7 @@ static int overlay_update_local_node_references(void *fdto,
return tree_len;
}
- for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
+ for (i = 0; i < fixup_len; i++) {
fdt32_t adj_val;
uint32_t poffset;
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index e03570a56eb5..91cc6fefe374 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -53,7 +53,7 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
err = -FDT_ERR_BADOFFSET;
absoffset = stroffset + fdt_off_dt_strings(fdt);
- if (absoffset >= totalsize)
+ if (absoffset >= (unsigned)totalsize)
goto fail;
len = totalsize - absoffset;
@@ -61,17 +61,19 @@ const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
if (stroffset < 0)
goto fail;
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
- if (stroffset >= fdt_size_dt_strings(fdt))
+ if ((unsigned)stroffset >= fdt_size_dt_strings(fdt))
goto fail;
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
len = fdt_size_dt_strings(fdt) - stroffset;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
- if ((stroffset >= 0)
- || (stroffset < -fdt_size_dt_strings(fdt)))
+ unsigned int sw_stroffset = -stroffset;
+
+ if ((stroffset >= 0) ||
+ (sw_stroffset > fdt_size_dt_strings(fdt)))
goto fail;
- if ((-stroffset) < len)
- len = -stroffset;
+ if (sw_stroffset < len)
+ len = sw_stroffset;
} else {
err = -FDT_ERR_INTERNAL;
goto fail;
@@ -157,8 +159,8 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
{
- int offset = n * sizeof(struct fdt_reserve_entry);
- int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
+ unsigned int offset = n * sizeof(struct fdt_reserve_entry);
+ unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
if (!can_assume(VALID_INPUT)) {
if (absoffset < fdt_off_mem_rsvmap(fdt))
@@ -680,7 +682,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
{
int offset;
- if ((phandle == 0) || (phandle == -1))
+ if ((phandle == 0) || (phandle == ~0U))
return -FDT_ERR_BADPHANDLE;
FDT_RO_PROBE(fdt);
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
index 93e4a2b56348..68887b969a45 100644
--- a/scripts/dtc/libfdt/fdt_rw.c
+++ b/scripts/dtc/libfdt/fdt_rw.c
@@ -59,7 +59,7 @@ static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
return -FDT_ERR_BADOFFSET;
- if ((p < (char *)fdt) || (dsize + newlen < oldlen))
+ if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen))
return -FDT_ERR_BADOFFSET;
if (dsize - oldlen + newlen > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE;
diff --git a/scripts/dtc/libfdt/fdt_strerror.c b/scripts/dtc/libfdt/fdt_strerror.c
index 768db66eada5..b4356931b06d 100644
--- a/scripts/dtc/libfdt/fdt_strerror.c
+++ b/scripts/dtc/libfdt/fdt_strerror.c
@@ -40,7 +40,7 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
};
-#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])))
const char *fdt_strerror(int errval)
{
@@ -48,7 +48,7 @@ const char *fdt_strerror(int errval)
return "<valid offset/length>";
else if (errval == 0)
return "<no error>";
- else if (errval > -FDT_ERRTABSIZE) {
+ else if (-errval < FDT_ERRTABSIZE) {
const char *s = fdt_errtable[-errval].str;
if (s)
diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c
index 94ce4bb91a00..68b543c4dfa2 100644
--- a/scripts/dtc/libfdt/fdt_sw.c
+++ b/scripts/dtc/libfdt/fdt_sw.c
@@ -93,8 +93,8 @@ static inline uint32_t sw_flags(void *fdt)
static void *fdt_grab_space_(void *fdt, size_t len)
{
- int offset = fdt_size_dt_struct(fdt);
- int spaceleft;
+ unsigned int offset = fdt_size_dt_struct(fdt);
+ unsigned int spaceleft;
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
- fdt_size_dt_strings(fdt);
@@ -108,8 +108,8 @@ static void *fdt_grab_space_(void *fdt, size_t len)
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
{
- const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
- sizeof(struct fdt_reserve_entry));
+ const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry));
void *fdt = buf;
if (bufsize < hdrsize)
@@ -152,6 +152,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
FDT_SW_PROBE(fdt);
+ if (bufsize < 0)
+ return -FDT_ERR_NOSPACE;
+
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt);
@@ -159,7 +162,7 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
headsize + tailsize > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;
- if ((headsize + tailsize) > bufsize)
+ if ((headsize + tailsize) > (unsigned)bufsize)
return -FDT_ERR_NOSPACE;
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
@@ -247,18 +250,18 @@ int fdt_end_node(void *fdt)
static int fdt_add_string_(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
- int strtabsize = fdt_size_dt_strings(fdt);
- int len = strlen(s) + 1;
- int struct_top, offset;
+ unsigned int strtabsize = fdt_size_dt_strings(fdt);
+ unsigned int len = strlen(s) + 1;
+ unsigned int struct_top, offset;
- offset = -strtabsize - len;
+ offset = strtabsize + len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
- if (fdt_totalsize(fdt) + offset < struct_top)
+ if (fdt_totalsize(fdt) - offset < struct_top)
return 0; /* no more room :( */
- memcpy(strtab + offset, s, len);
+ memcpy(strtab - offset, s, len);
fdt_set_size_dt_strings(fdt, strtabsize + len);
- return offset;
+ return -offset;
}
/* Must only be used to roll back in case of error */
diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c
index f64139e0b3dc..c2d7566a67dc 100644
--- a/scripts/dtc/libfdt/fdt_wip.c
+++ b/scripts/dtc/libfdt/fdt_wip.c
@@ -23,7 +23,7 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
if (!propval)
return proplen;
- if (proplen < (len + idx))
+ if ((unsigned)proplen < (len + idx))
return -FDT_ERR_NOSPACE;
memcpy((char *)propval + idx, val, len);
diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h
index 5a4172dd0f84..a771b4654c76 100644
--- a/scripts/dtc/util.h
+++ b/scripts/dtc/util.h
@@ -2,6 +2,7 @@
#ifndef UTIL_H
#define UTIL_H
+#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <getopt.h>
diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
index 0714799446f8..054cdd0fdbe8 100644
--- a/scripts/dtc/version_gen.h
+++ b/scripts/dtc/version_gen.h
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.6.0-g9d7888cb"
+#define DTC_VERSION "DTC 1.6.0-gcbca977e"
diff --git a/scripts/gdb/linux/dmesg.py b/scripts/gdb/linux/dmesg.py
index 2fa7bb83885f..a92c55bd8de5 100644
--- a/scripts/gdb/linux/dmesg.py
+++ b/scripts/gdb/linux/dmesg.py
@@ -16,8 +16,13 @@ import sys
from linux import utils
-printk_log_type = utils.CachedType("struct printk_log")
-
+printk_info_type = utils.CachedType("struct printk_info")
+prb_data_blk_lpos_type = utils.CachedType("struct prb_data_blk_lpos")
+prb_desc_type = utils.CachedType("struct prb_desc")
+prb_desc_ring_type = utils.CachedType("struct prb_desc_ring")
+prb_data_ring_type = utils.CachedType("struct prb_data_ring")
+printk_ringbuffer_type = utils.CachedType("struct printk_ringbuffer")
+atomic_long_type = utils.CachedType("atomic_long_t")
class LxDmesg(gdb.Command):
"""Print Linux kernel log buffer."""
@@ -26,44 +31,110 @@ class LxDmesg(gdb.Command):
super(LxDmesg, self).__init__("lx-dmesg", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
- log_buf_addr = int(str(gdb.parse_and_eval(
- "(void *)'printk.c'::log_buf")).split()[0], 16)
- log_first_idx = int(gdb.parse_and_eval("'printk.c'::log_first_idx"))
- log_next_idx = int(gdb.parse_and_eval("'printk.c'::log_next_idx"))
- log_buf_len = int(gdb.parse_and_eval("'printk.c'::log_buf_len"))
-
inf = gdb.inferiors()[0]
- start = log_buf_addr + log_first_idx
- if log_first_idx < log_next_idx:
- log_buf_2nd_half = -1
- length = log_next_idx - log_first_idx
- log_buf = utils.read_memoryview(inf, start, length).tobytes()
- else:
- log_buf_2nd_half = log_buf_len - log_first_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()
-
- length_offset = printk_log_type.get_type()['len'].bitpos // 8
- text_len_offset = printk_log_type.get_type()['text_len'].bitpos // 8
- time_stamp_offset = printk_log_type.get_type()['ts_nsec'].bitpos // 8
- text_offset = printk_log_type.get_type().sizeof
-
- pos = 0
- while pos < log_buf.__len__():
- length = utils.read_u16(log_buf, pos + length_offset)
- if length == 0:
- if log_buf_2nd_half == -1:
- gdb.write("Corrupted log buffer!\n")
+
+ # read in prb structure
+ prb_addr = int(str(gdb.parse_and_eval("(void *)'printk.c'::prb")).split()[0], 16)
+ sz = printk_ringbuffer_type.get_type().sizeof
+ prb = utils.read_memoryview(inf, prb_addr, sz).tobytes()
+
+ # read in descriptor ring structure
+ off = printk_ringbuffer_type.get_type()['desc_ring'].bitpos // 8
+ addr = prb_addr + off
+ sz = prb_desc_ring_type.get_type().sizeof
+ desc_ring = utils.read_memoryview(inf, addr, sz).tobytes()
+
+ # read in descriptor array
+ off = prb_desc_ring_type.get_type()['count_bits'].bitpos // 8
+ desc_ring_count = 1 << utils.read_u32(desc_ring, off)
+ desc_sz = prb_desc_type.get_type().sizeof
+ off = prb_desc_ring_type.get_type()['descs'].bitpos // 8
+ addr = utils.read_ulong(desc_ring, off)
+ descs = utils.read_memoryview(inf, addr, desc_sz * desc_ring_count).tobytes()
+
+ # read in info array
+ info_sz = printk_info_type.get_type().sizeof
+ off = prb_desc_ring_type.get_type()['infos'].bitpos // 8
+ addr = utils.read_ulong(desc_ring, off)
+ infos = utils.read_memoryview(inf, addr, info_sz * desc_ring_count).tobytes()
+
+ # read in text data ring structure
+ off = printk_ringbuffer_type.get_type()['text_data_ring'].bitpos // 8
+ addr = prb_addr + off
+ sz = prb_data_ring_type.get_type().sizeof
+ text_data_ring = utils.read_memoryview(inf, addr, sz).tobytes()
+
+ # read in text data
+ off = prb_data_ring_type.get_type()['size_bits'].bitpos // 8
+ text_data_sz = 1 << utils.read_u32(text_data_ring, off)
+ off = prb_data_ring_type.get_type()['data'].bitpos // 8
+ addr = utils.read_ulong(text_data_ring, off)
+ text_data = utils.read_memoryview(inf, addr, text_data_sz).tobytes()
+
+ counter_off = atomic_long_type.get_type()['counter'].bitpos // 8
+
+ sv_off = prb_desc_type.get_type()['state_var'].bitpos // 8
+
+ off = prb_desc_type.get_type()['text_blk_lpos'].bitpos // 8
+ begin_off = off + (prb_data_blk_lpos_type.get_type()['begin'].bitpos // 8)
+ next_off = off + (prb_data_blk_lpos_type.get_type()['next'].bitpos // 8)
+
+ ts_off = printk_info_type.get_type()['ts_nsec'].bitpos // 8
+ len_off = printk_info_type.get_type()['text_len'].bitpos // 8
+
+ # definitions from kernel/printk/printk_ringbuffer.h
+ desc_committed = 1
+ desc_finalized = 2
+ desc_sv_bits = utils.get_long_type().sizeof * 8
+ desc_flags_shift = desc_sv_bits - 2
+ desc_flags_mask = 3 << desc_flags_shift
+ desc_id_mask = ~desc_flags_mask
+
+ # read in tail and head descriptor ids
+ off = prb_desc_ring_type.get_type()['tail_id'].bitpos // 8
+ tail_id = utils.read_u64(desc_ring, off + counter_off)
+ off = prb_desc_ring_type.get_type()['head_id'].bitpos // 8
+ head_id = utils.read_u64(desc_ring, off + counter_off)
+
+ did = tail_id
+ while True:
+ ind = did % desc_ring_count
+ desc_off = desc_sz * ind
+ info_off = info_sz * ind
+
+ # skip non-committed record
+ state = 3 & (utils.read_u64(descs, desc_off + sv_off +
+ counter_off) >> desc_flags_shift)
+ if state != desc_committed and state != desc_finalized:
+ if did == head_id:
break
- pos = log_buf_2nd_half
+ did = (did + 1) & desc_id_mask
continue
- text_len = utils.read_u16(log_buf, pos + text_len_offset)
- text_start = pos + text_offset
- text = log_buf[text_start:text_start + text_len].decode(
- encoding='utf8', errors='replace')
- time_stamp = utils.read_u64(log_buf, pos + time_stamp_offset)
+ begin = utils.read_ulong(descs, desc_off + begin_off) % text_data_sz
+ end = utils.read_ulong(descs, desc_off + next_off) % text_data_sz
+
+ # handle data-less record
+ if begin & 1 == 1:
+ text = ""
+ else:
+ # handle wrapping data block
+ if begin > end:
+ begin = 0
+
+ # skip over descriptor id
+ text_start = begin + utils.get_long_type().sizeof
+
+ text_len = utils.read_u16(infos, info_off + len_off)
+
+ # handle truncated message
+ if end - text_start < text_len:
+ text_len = end - text_start
+
+ text = text_data[text_start:text_start + text_len].decode(
+ encoding='utf8', errors='replace')
+
+ time_stamp = utils.read_u64(infos, info_off + ts_off)
for line in text.splitlines():
msg = u"[{time:12.6f}] {line}\n".format(
@@ -75,7 +146,9 @@ class LxDmesg(gdb.Command):
msg = msg.encode(encoding='utf8', errors='replace')
gdb.write(msg)
- pos += length
+ if did == head_id:
+ break
+ did = (did + 1) & desc_id_mask
LxDmesg()
diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
index 6a56bba233a9..09cd871925a5 100644
--- a/scripts/gdb/linux/proc.py
+++ b/scripts/gdb/linux/proc.py
@@ -167,6 +167,9 @@ values of that process namespace"""
if not namespace:
raise gdb.GdbError("No namespace for current process")
+ gdb.write("{:^18} {:^15} {:>9} {} {} options\n".format(
+ "mount", "super_block", "devname", "pathname", "fstype"))
+
for vfs in lists.list_for_each_entry(namespace['list'],
mount_ptr_type, "mnt_list"):
devname = vfs['mnt_devname'].string()
@@ -190,14 +193,10 @@ values of that process namespace"""
m_flags = int(vfs['mnt']['mnt_flags'])
rd = "ro" if (s_flags & constants.LX_SB_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)))
+ gdb.write("{} {} {} {} {} {}{}{} 0 0\n".format(
+ vfs.format_string(), superblock.format_string(), devname,
+ pathname, fstype, rd, info_opts(FS_INFO, s_flags),
+ info_opts(MNT_INFO, m_flags)))
LxMounts()
diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py
index 0301dc1e0138..17ec19e9b5bf 100644
--- a/scripts/gdb/linux/tasks.py
+++ b/scripts/gdb/linux/tasks.py
@@ -73,11 +73,12 @@ class LxPs(gdb.Command):
super(LxPs, self).__init__("lx-ps", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
+ gdb.write("{:>10} {:>12} {:>7}\n".format("TASK", "PID", "COMM"))
for task in task_lists():
- gdb.write("{address} {pid} {comm}\n".format(
- address=task,
- pid=task["pid"],
- comm=task["comm"].string()))
+ gdb.write("{} {:^5} {}\n".format(
+ task.format_string().split()[0],
+ task["pid"].format_string(),
+ task["comm"].string()))
LxPs()
diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py
index ea94221dbd39..ff7c1799d588 100644
--- a/scripts/gdb/linux/utils.py
+++ b/scripts/gdb/linux/utils.py
@@ -123,6 +123,13 @@ def read_u64(buffer, offset):
return read_u32(buffer, offset + 4) + (read_u32(buffer, offset) << 32)
+def read_ulong(buffer, offset):
+ if get_long_type().sizeof == 8:
+ return read_u64(buffer, offset)
+ else:
+ return read_u32(buffer, offset)
+
+
target_arch = None
diff --git a/scripts/gen_compile_commands.py b/scripts/gen_compile_commands.py
deleted file mode 100755
index c458696ef3a7..000000000000
--- a/scripts/gen_compile_commands.py
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0
-#
-# Copyright (C) Google LLC, 2018
-#
-# Author: Tom Roeder <tmroeder@google.com>
-#
-"""A tool for generating compile_commands.json in the Linux kernel."""
-
-import argparse
-import json
-import logging
-import os
-import re
-
-_DEFAULT_OUTPUT = 'compile_commands.json'
-_DEFAULT_LOG_LEVEL = 'WARNING'
-
-_FILENAME_PATTERN = r'^\..*\.cmd$'
-_LINE_PATTERN = r'^cmd_[^ ]*\.o := (.* )([^ ]*\.c)$'
-_VALID_LOG_LEVELS = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
-
-# A kernel build generally has over 2000 entries in its compile_commands.json
-# database. If this code finds 300 or fewer, then warn the user that they might
-# not have all the .cmd files, and they might need to compile the kernel.
-_LOW_COUNT_THRESHOLD = 300
-
-
-def parse_arguments():
- """Sets up and parses command-line arguments.
-
- Returns:
- log_level: A logging level to filter log output.
- directory: The directory to search for .cmd files.
- output: Where to write the compile-commands JSON file.
- """
- usage = 'Creates a compile_commands.json database from kernel .cmd files'
- parser = argparse.ArgumentParser(description=usage)
-
- directory_help = ('Path to the kernel source directory to search '
- '(defaults to the working directory)')
- parser.add_argument('-d', '--directory', type=str, help=directory_help)
-
- output_help = ('The location to write compile_commands.json (defaults to '
- 'compile_commands.json in the search directory)')
- parser.add_argument('-o', '--output', type=str, help=output_help)
-
- log_level_help = ('The level of log messages to produce (one of ' +
- ', '.join(_VALID_LOG_LEVELS) + '; defaults to ' +
- _DEFAULT_LOG_LEVEL + ')')
- parser.add_argument(
- '--log_level', type=str, default=_DEFAULT_LOG_LEVEL,
- help=log_level_help)
-
- args = parser.parse_args()
-
- log_level = args.log_level
- if log_level not in _VALID_LOG_LEVELS:
- raise ValueError('%s is not a valid log level' % log_level)
-
- directory = args.directory or os.getcwd()
- output = args.output or os.path.join(directory, _DEFAULT_OUTPUT)
- directory = os.path.abspath(directory)
-
- return log_level, directory, output
-
-
-def process_line(root_directory, file_directory, command_prefix, relative_path):
- """Extracts information from a .cmd line and creates an entry from it.
-
- Args:
- root_directory: The directory that was searched for .cmd files. Usually
- used directly in the "directory" entry in compile_commands.json.
- file_directory: The path to the directory the .cmd file was found in.
- command_prefix: The extracted command line, up to the last element.
- relative_path: The .c file from the end of the extracted command.
- Usually relative to root_directory, but sometimes relative to
- file_directory and sometimes neither.
-
- Returns:
- An entry to append to compile_commands.
-
- Raises:
- ValueError: Could not find the extracted file based on relative_path and
- root_directory or file_directory.
- """
- # The .cmd files are intended to be included directly by Make, so they
- # escape the pound sign '#', either as '\#' or '$(pound)' (depending on the
- # kernel version). The compile_commands.json file is not interepreted
- # by Make, so this code replaces the escaped version with '#'.
- prefix = command_prefix.replace('\#', '#').replace('$(pound)', '#')
-
- cur_dir = root_directory
- expected_path = os.path.join(cur_dir, relative_path)
- if not os.path.exists(expected_path):
- # Try using file_directory instead. Some of the tools have a different
- # style of .cmd file than the kernel.
- cur_dir = file_directory
- expected_path = os.path.join(cur_dir, relative_path)
- if not os.path.exists(expected_path):
- raise ValueError('File %s not in %s or %s' %
- (relative_path, root_directory, file_directory))
- return {
- 'directory': cur_dir,
- 'file': relative_path,
- 'command': prefix + relative_path,
- }
-
-
-def main():
- """Walks through the directory and finds and parses .cmd files."""
- log_level, directory, output = parse_arguments()
-
- level = getattr(logging, log_level)
- logging.basicConfig(format='%(levelname)s: %(message)s', level=level)
-
- filename_matcher = re.compile(_FILENAME_PATTERN)
- line_matcher = re.compile(_LINE_PATTERN)
-
- compile_commands = []
- for dirpath, _, filenames in os.walk(directory):
- for filename in filenames:
- if not filename_matcher.match(filename):
- continue
- filepath = os.path.join(dirpath, filename)
-
- with open(filepath, 'rt') as f:
- for line in f:
- result = line_matcher.match(line)
- if not result:
- continue
-
- try:
- entry = process_line(directory, dirpath,
- result.group(1), result.group(2))
- compile_commands.append(entry)
- except ValueError as err:
- logging.info('Could not add line from %s: %s',
- filepath, err)
-
- with open(output, 'wt') as f:
- json.dump(compile_commands, f, indent=2, sort_keys=True)
-
- count = len(compile_commands)
- if count < _LOW_COUNT_THRESHOLD:
- logging.warning(
- 'Found %s entries. Have you compiled the kernel?', count)
-
-
-if __name__ == '__main__':
- main()
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
index c738cb795514..2cb592f8eba4 100755
--- a/scripts/get_abi.pl
+++ b/scripts/get_abi.pl
@@ -2,18 +2,28 @@
# SPDX-License-Identifier: GPL-2.0
use strict;
+use warnings;
+use utf8;
use Pod::Usage;
use Getopt::Long;
use File::Find;
use Fcntl ':mode';
-my $help;
-my $man;
-my $debug;
+my $help = 0;
+my $man = 0;
+my $debug = 0;
+my $enable_lineno = 0;
my $prefix="Documentation/ABI";
+#
+# If true, assumes that the description is formatted with ReST
+#
+my $description_is_rst = 1;
+
GetOptions(
"debug|d+" => \$debug,
+ "enable-lineno" => \$enable_lineno,
+ "rst-source!" => \$description_is_rst,
"dir=s" => \$prefix,
'help|?' => \$help,
man => \$man
@@ -32,6 +42,7 @@ pod2usage(2) if ($cmd eq "search" && !$arg);
require Data::Dumper if ($debug);
my %data;
+my %symbols;
#
# Displays an error message, printing file name and line
@@ -39,7 +50,15 @@ my %data;
sub parse_error($$$$) {
my ($file, $ln, $msg, $data) = @_;
- print STDERR "file $file#$ln: $msg at\n\t$data";
+ $data =~ s/\s+$/\n/;
+
+ print STDERR "Warning: file $file#$ln:\n\t$msg";
+
+ if ($data ne "") {
+ print STDERR ". Line\n\t\t$data";
+ } else {
+ print STDERR "\n";
+ }
}
#
@@ -55,24 +74,28 @@ sub parse_abi {
my $name = $file;
$name =~ s,.*/,,;
- my $nametag = "File $name";
+ my $fn = $file;
+ $fn =~ s,Documentation/ABI/,,;
+
+ my $nametag = "File $fn";
$data{$nametag}->{what} = "File $name";
$data{$nametag}->{type} = "File";
$data{$nametag}->{file} = $name;
$data{$nametag}->{filepath} = $file;
$data{$nametag}->{is_file} = 1;
+ $data{$nametag}->{line_no} = 1;
my $type = $file;
$type =~ s,.*/(.*)/.*,$1,;
my $what;
my $new_what;
- my $tag;
+ my $tag = "";
my $ln;
my $xrefs;
my $space;
my @labels;
- my $label;
+ my $label = "";
print STDERR "Opening $file\n" if ($debug > 1);
open IN, $file;
@@ -95,16 +118,26 @@ sub parse_abi {
# Invalid, but it is a common mistake
if ($new_tag eq "where") {
- parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", $_);
+ parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", "");
$new_tag = "what";
}
if ($new_tag =~ m/what/) {
$space = "";
+ $content =~ s/[,.;]$//;
+
+ push @{$symbols{$content}->{file}}, " $file:" . ($ln - 1);
+
if ($tag =~ m/what/) {
$what .= ", " . $content;
} else {
- parse_error($file, $ln, "What '$what' doesn't have a description", "") if ($what && !$data{$what}->{description});
+ if ($what) {
+ parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
+
+ foreach my $w(split /, /, $what) {
+ $symbols{$w}->{xref} = $what;
+ };
+ }
$what = $content;
$label = $content;
@@ -113,7 +146,7 @@ sub parse_abi {
push @labels, [($content, $label)];
$tag = $new_tag;
- push @{$data{$nametag}->{xrefs}}, [($content, $label)] if ($data{$nametag}->{what});
+ push @{$data{$nametag}->{symbols}}, $content if ($data{$nametag}->{what});
next;
}
@@ -121,30 +154,44 @@ sub parse_abi {
$tag = $new_tag;
if ($new_what) {
- @{$data{$what}->{label}} = @labels if ($data{$nametag}->{what});
+ @{$data{$what}->{label_list}} = @labels if ($data{$nametag}->{what});
@labels = ();
$label = "";
$new_what = 0;
$data{$what}->{type} = $type;
- $data{$what}->{file} = $name;
- $data{$what}->{filepath} = $file;
+ if (!defined($data{$what}->{file})) {
+ $data{$what}->{file} = $name;
+ $data{$what}->{filepath} = $file;
+ } else {
+ if ($name ne $data{$what}->{file}) {
+ $data{$what}->{file} .= " " . $name;
+ $data{$what}->{filepath} .= " " . $file;
+ }
+ }
print STDERR "\twhat: $what\n" if ($debug > 1);
+ $data{$what}->{line_no} = $ln;
+ } else {
+ $data{$what}->{line_no} = $ln if (!defined($data{$what}->{line_no}));
}
if (!$what) {
parse_error($file, $ln, "'What:' should come first:", $_);
next;
}
- if ($tag eq "description") {
- next if ($content =~ m/^\s*$/);
- if ($content =~ m/^(\s*)(.*)/) {
- my $new_content = $2;
- $space = $new_tag . $sep . $1;
- while ($space =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
- $space =~ s/./ /g;
- $data{$what}->{$tag} .= "$new_content\n";
+ if ($new_tag eq "description") {
+ $sep =~ s,:, ,;
+ $content = ' ' x length($new_tag) . $sep . $content;
+ while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
+ if ($content =~ m/^(\s*)(\S.*)$/) {
+ # Preserve initial spaces for the first line
+ $space = $1;
+ $content = "$2\n";
+ $data{$what}->{$tag} .= $content;
+ } else {
+ undef($space);
}
+
} else {
$data{$what}->{$tag} = $content;
}
@@ -159,29 +206,24 @@ sub parse_abi {
}
if ($tag eq "description") {
- if (!$data{$what}->{description}) {
- next if (m/^\s*\n/);
- if (m/^(\s*)(.*)/) {
+ my $content = $_;
+ while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
+ if (m/^\s*\n/) {
+ $data{$what}->{$tag} .= "\n";
+ next;
+ }
+
+ if (!defined($space)) {
+ # Preserve initial spaces for the first line
+ if ($content =~ m/^(\s*)(\S.*)$/) {
$space = $1;
- while ($space =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
- $data{$what}->{$tag} .= "$2\n";
+ $content = "$2\n";
}
} else {
- my $content = $_;
- if (m/^\s*\n/) {
- $data{$what}->{$tag} .= $content;
- next;
- }
-
- while ($content =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}
$space = "" if (!($content =~ s/^($space)//));
-
- # Compress spaces with tabs
- $content =~ s<^ {8}> <\t>;
- $content =~ s<^ {1,7}\t> <\t>;
- $content =~ s< {1,7}\t> <\t>;
- $data{$what}->{$tag} .= $content;
}
+ $data{$what}->{$tag} .= $content;
+
next;
}
if (m/^\s*(.*)/) {
@@ -191,32 +233,26 @@ sub parse_abi {
}
# Everything else is error
- parse_error($file, $ln, "Unexpected line:", $_);
+ parse_error($file, $ln, "Unexpected content", $_);
+ }
+ $data{$nametag}->{description} =~ s/^\n+// if ($data{$nametag}->{description});
+ if ($what) {
+ parse_error($file, $ln, "What '$what' doesn't have a description", "") if (!$data{$what}->{description});
+
+ foreach my $w(split /, /,$what) {
+ $symbols{$w}->{xref} = $what;
+ };
}
- $data{$nametag}->{description} =~ s/^\n+//;
close IN;
}
-#
-# Outputs the book on ReST format
-#
-
-my %labels;
-
-sub output_rest {
- foreach my $what (sort {
- ($data{$a}->{type} eq "File") cmp ($data{$b}->{type} eq "File") ||
- $a cmp $b
- } keys %data) {
- my $type = $data{$what}->{type};
- my $file = $data{$what}->{file};
- my $filepath = $data{$what}->{filepath};
-
- my $w = $what;
- $w =~ s/([\(\)\_\-\*\=\^\~\\])/\\$1/g;
+sub create_labels {
+ my %labels;
+ foreach my $what (keys %data) {
+ next if ($data{$what}->{file} eq "File");
- foreach my $p (@{$data{$what}->{label}}) {
+ foreach my $p (@{$data{$what}->{label_list}}) {
my ($content, $label) = @{$p};
$label = "abi_" . $label . " ";
$label =~ tr/A-Z/a-z/;
@@ -233,81 +269,144 @@ sub output_rest {
}
$labels{$label} = 1;
- $data{$what}->{label} .= $label;
-
- printf ".. _%s:\n\n", $label;
+ $data{$what}->{label} = $label;
# only one label is enough
last;
}
+ }
+}
+#
+# Outputs the book on ReST format
+#
- $filepath =~ s,.*/(.*/.*),\1,;;
- $filepath =~ s,[/\-],_,g;;
- my $fileref = "abi_file_".$filepath;
+# \b doesn't work well with paths. So, we need to define something else
+my $bondary = qr { (?<![\w\/\`\{])(?=[\w\/\`\{])|(?<=[\w\/\`\{])(?![\w\/\`\{]) }x;
- if ($type eq "File") {
- my $bar = $w;
- $bar =~ s/./-/g;
+sub output_rest {
+ create_labels();
- print ".. _$fileref:\n\n";
- print "$w\n$bar\n\n";
- } else {
- my @names = split /\s*,\s*/,$w;
+ foreach my $what (sort {
+ ($data{$a}->{type} eq "File") cmp ($data{$b}->{type} eq "File") ||
+ $a cmp $b
+ } keys %data) {
+ my $type = $data{$what}->{type};
+
+ my @file = split / /, $data{$what}->{file};
+ my @filepath = split / /, $data{$what}->{filepath};
+
+ if ($enable_lineno) {
+ printf "#define LINENO %s%s#%s\n\n",
+ $prefix, $file[0],
+ $data{$what}->{line_no};
+ }
+ my $w = $what;
+ $w =~ s/([\(\)\_\-\*\=\^\~\\])/\\$1/g;
+
+ if ($type ne "File") {
+ printf ".. _%s:\n\n", $data{$what}->{label};
+
+ my @names = split /, /,$w;
my $len = 0;
foreach my $name (@names) {
+ $name = "**$name**";
$len = length($name) if (length($name) > $len);
}
- print "What:\n\n";
-
print "+-" . "-" x $len . "-+\n";
foreach my $name (@names) {
printf "| %s", $name . " " x ($len - length($name)) . " |\n";
print "+-" . "-" x $len . "-+\n";
}
+
print "\n";
}
- print "Defined on file :ref:`$file <$fileref>`\n\n" if ($type ne "File");
+ for (my $i = 0; $i < scalar(@filepath); $i++) {
+ my $path = $filepath[$i];
+ my $f = $file[$i];
- my $desc = $data{$what}->{description};
- $desc =~ s/^\s+//;
+ $path =~ s,.*/(.*/.*),$1,;;
+ $path =~ s,[/\-],_,g;;
+ my $fileref = "abi_file_".$path;
- # Remove title markups from the description, as they won't work
- $desc =~ s/\n[\-\*\=\^\~]+\n/\n/g;
+ if ($type eq "File") {
+ print ".. _$fileref:\n\n";
+ } else {
+ print "Defined on file :ref:`$f <$fileref>`\n\n";
+ }
+ }
+
+ if ($type eq "File") {
+ my $bar = $w;
+ $bar =~ s/./-/g;
+ print "$w\n$bar\n\n";
+ }
+
+ my $desc = "";
+ $desc = $data{$what}->{description} if (defined($data{$what}->{description}));
+ $desc =~ s/\s+$/\n/;
if (!($desc =~ /^\s*$/)) {
- if ($desc =~ m/\:\n/ || $desc =~ m/\n[\t ]+/ || $desc =~ m/[\x00-\x08\x0b-\x1f\x7b-\xff]/) {
- # put everything inside a code block
- $desc =~ s/\n/\n /g;
+ if ($description_is_rst) {
+ # Enrich text by creating cross-references
+
+ $desc =~ s,Documentation/(?!devicetree)(\S+)\.rst,:doc:`/$1`,g;
+
+ my @matches = $desc =~ m,Documentation/ABI/([\w\/\-]+),;
+ foreach my $f (@matches) {
+ my $xref = $f;
+ my $path = $f;
+ $path =~ s,.*/(.*/.*),$1,;;
+ $path =~ s,[/\-],_,g;;
+ $xref .= " <abi_file_" . $path . ">";
+ $desc =~ s,\bDocumentation/ABI/$f\b,:ref:`$xref`,g;
+ }
- print "::\n\n";
- print " $desc\n\n";
- } else {
- # Escape any special chars from description
- $desc =~s/([\x00-\x08\x0b-\x1f\x21-\x2a\x2d\x2f\x3c-\x40\x5c\x5e-\x60\x7b-\xff])/\\$1/g;
+ @matches = $desc =~ m,$bondary(/sys/[^\s\.\,\;\:\*\s\`\'\(\)]+)$bondary,;
+
+ foreach my $s (@matches) {
+ if (defined($data{$s}) && defined($data{$s}->{label})) {
+ my $xref = $s;
+
+ $xref =~ s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g;
+ $xref = ":ref:`$xref <" . $data{$s}->{label} . ">`";
+
+ $desc =~ s,$bondary$s$bondary,$xref,g;
+ }
+ }
print "$desc\n\n";
+ } else {
+ $desc =~ s/^\s+//;
+
+ # Remove title markups from the description, as they won't work
+ $desc =~ s/\n[\-\*\=\^\~]+\n/\n\n/g;
+
+ if ($desc =~ m/\:\n/ || $desc =~ m/\n[\t ]+/ || $desc =~ m/[\x00-\x08\x0b-\x1f\x7b-\xff]/) {
+ # put everything inside a code block
+ $desc =~ s/\n/\n /g;
+
+ print "::\n\n";
+ print " $desc\n\n";
+ } else {
+ # Escape any special chars from description
+ $desc =~s/([\x00-\x08\x0b-\x1f\x21-\x2a\x2d\x2f\x3c-\x40\x5c\x5e-\x60\x7b-\xff])/\\$1/g;
+ print "$desc\n\n";
+ }
}
} else {
print "DESCRIPTION MISSING for $what\n\n" if (!$data{$what}->{is_file});
}
- if ($data{$what}->{xrefs}) {
+ if ($data{$what}->{symbols}) {
printf "Has the following ABI:\n\n";
- foreach my $p(@{$data{$what}->{xrefs}}) {
- my ($content, $label) = @{$p};
- $label = "abi_" . $label . " ";
- $label =~ tr/A-Z/a-z/;
-
- # Convert special chars to "_"
- $label =~s/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff])/_/g;
- $label =~ s,_+,_,g;
- $label =~ s,_$,,;
+ foreach my $content(@{$data{$what}->{symbols}}) {
+ my $label = $data{$symbols{$content}->{xref}}->{label};
# Escape special chars from content
$content =~s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g;
@@ -315,6 +414,14 @@ sub output_rest {
print "- :ref:`$content <$label>`\n\n";
}
}
+
+ if (defined($data{$what}->{users})) {
+ my $users = $data{$what}->{users};
+
+ $users =~ s/\n/\n\t/g;
+ printf "Users:\n\t%s\n\n", $users if ($users ne "");
+ }
+
}
}
@@ -335,27 +442,34 @@ sub search_symbols {
print "\n$what\n$bar\n\n";
- my $kernelversion = $data{$what}->{kernelversion};
- my $contact = $data{$what}->{contact};
- my $users = $data{$what}->{users};
- my $date = $data{$what}->{date};
- my $desc = $data{$what}->{description};
- $kernelversion =~ s/^\s+//;
- $contact =~ s/^\s+//;
- $users =~ s/^\s+//;
- $users =~ s/\n//g;
- $date =~ s/^\s+//;
- $desc =~ s/^\s+//;
+ my $kernelversion = $data{$what}->{kernelversion} if (defined($data{$what}->{kernelversion}));
+ my $contact = $data{$what}->{contact} if (defined($data{$what}->{contact}));
+ my $users = $data{$what}->{users} if (defined($data{$what}->{users}));
+ my $date = $data{$what}->{date} if (defined($data{$what}->{date}));
+ my $desc = $data{$what}->{description} if (defined($data{$what}->{description}));
+
+ $kernelversion =~ s/^\s+// if ($kernelversion);
+ $contact =~ s/^\s+// if ($contact);
+ if ($users) {
+ $users =~ s/^\s+//;
+ $users =~ s/\n//g;
+ }
+ $date =~ s/^\s+// if ($date);
+ $desc =~ s/^\s+// if ($desc);
printf "Kernel version:\t\t%s\n", $kernelversion if ($kernelversion);
printf "Date:\t\t\t%s\n", $date if ($date);
printf "Contact:\t\t%s\n", $contact if ($contact);
printf "Users:\t\t\t%s\n", $users if ($users);
- print "Defined on file:\t$file\n\n";
+ print "Defined on file(s):\t$file\n\n";
print "Description:\n\n$desc";
}
}
+# Ensure that the prefix will always end with a slash
+# While this is not needed for find, it makes the patch nicer
+# with --enable-lineno
+$prefix =~ s,/?$,/,;
#
# Parses all ABI files located at $prefix dir
@@ -367,12 +481,23 @@ print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
#
# Handles the command
#
-if ($cmd eq "rest") {
- output_rest;
-} elsif ($cmd eq "search") {
+if ($cmd eq "search") {
search_symbols;
-}
+} else {
+ if ($cmd eq "rest") {
+ output_rest;
+ }
+
+ # Warn about duplicated ABI entries
+ foreach my $what(sort keys %symbols) {
+ my @files = @{$symbols{$what}->{file}};
+ next if (scalar(@files) == 1);
+
+ printf STDERR "Warning: $what is defined %d times: @files\n",
+ scalar(@files);
+ }
+}
__END__
@@ -382,7 +507,8 @@ abi_book.pl - parse the Linux ABI files and produce a ReST book.
=head1 SYNOPSIS
-B<abi_book.pl> [--debug] [--man] [--help] [--dir=<dir>] <COMAND> [<ARGUMENT>]
+B<abi_book.pl> [--debug] [--enable-lineno] [--man] [--help]
+ [--(no-)rst-source] [--dir=<dir>] <COMAND> [<ARGUMENT>]
Where <COMMAND> can be:
@@ -405,6 +531,17 @@ B<validate> - validate the ABI contents
Changes the location of the ABI search. By default, it uses
the Documentation/ABI directory.
+=item B<--rst-source> and B<--no-rst-source>
+
+The input file may be using ReST syntax or not. Those two options allow
+selecting between a rst-compliant source ABI (--rst-source), or a
+plain text that may be violating ReST spec, so it requres some escaping
+logic (--no-rst-source).
+
+=item B<--enable-lineno>
+
+Enable output of #define LINENO lines.
+
=item B<--debug>
Put the script in verbose mode, useful for debugging. Can be called multiple
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index 484d2fbf5921..2075db0c08b8 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -541,6 +541,9 @@ foreach my $file (@ARGV) {
die "$P: file '${file}' not found\n";
}
}
+ if ($from_filename && (vcs_exists() && !vcs_file_exists($file))) {
+ warn "$P: file '$file' not found in version control $!\n";
+ }
if ($from_filename || ($file ne "&STDIN" && vcs_file_exists($file))) {
$file =~ s/^\Q${cur_path}\E//; #strip any absolute path
$file =~ s/^\Q${lk_path}\E//; #or the path to the lk tree
@@ -954,8 +957,10 @@ sub get_maintainers {
foreach my $file (@files) {
if ($email &&
- ($email_git || ($email_git_fallback &&
- !$exact_pattern_match_hash{$file}))) {
+ ($email_git ||
+ ($email_git_fallback &&
+ $file !~ /MAINTAINERS$/ &&
+ !$exact_pattern_match_hash{$file}))) {
vcs_file_signoffs($file);
}
if ($email && $email_git_blame) {
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 0096cd965332..7ecd2ccba531 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -82,6 +82,7 @@ static char *sym_name(const struct sym_entry *s)
static bool is_ignored_symbol(const char *name, char type)
{
+ /* Symbol names that exactly match to the following are ignored.*/
static const char * const ignored_symbols[] = {
/*
* Symbols which vary between passes. Passes 1 and 2 must have
@@ -104,6 +105,7 @@ static bool is_ignored_symbol(const char *name, char type)
NULL
};
+ /* Symbol names that begin with the following are ignored.*/
static const char * const ignored_prefixes[] = {
"$", /* local symbols for ARM, MIPS, etc. */
".LASANPC", /* s390 kasan local symbols */
@@ -113,6 +115,7 @@ static bool is_ignored_symbol(const char *name, char type)
NULL
};
+ /* Symbol names that end with the following are ignored.*/
static const char * const ignored_suffixes[] = {
"_from_arm", /* arm */
"_from_thumb", /* arm */
@@ -120,9 +123,15 @@ static bool is_ignored_symbol(const char *name, char type)
NULL
};
+ /* Symbol names that contain the following are ignored.*/
+ static const char * const ignored_matches[] = {
+ ".long_branch.", /* ppc stub */
+ ".plt_branch.", /* ppc stub */
+ NULL
+ };
+
const char * const *p;
- /* Exclude symbols which vary between passes. */
for (p = ignored_symbols; *p; p++)
if (!strcmp(name, *p))
return true;
@@ -138,6 +147,11 @@ static bool is_ignored_symbol(const char *name, char type)
return true;
}
+ for (p = ignored_matches; *p; p++) {
+ if (strstr(name, *p))
+ return true;
+ }
+
if (type == 'U' || type == 'u')
return true;
/* exclude debugging symbols */
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 52b59bf9efe4..e46df0a2d4f9 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -20,19 +20,19 @@ endif
unexport CONFIG_
xconfig: $(obj)/qconf
- $< $(silent) $(Kconfig)
+ $(Q)$< $(silent) $(Kconfig)
gconfig: $(obj)/gconf
- $< $(silent) $(Kconfig)
+ $(Q)$< $(silent) $(Kconfig)
menuconfig: $(obj)/mconf
- $< $(silent) $(Kconfig)
+ $(Q)$< $(silent) $(Kconfig)
config: $(obj)/conf
- $< $(silent) --oldaskconfig $(Kconfig)
+ $(Q)$< $(silent) --oldaskconfig $(Kconfig)
nconfig: $(obj)/nconf
- $< $(silent) $(Kconfig)
+ $(Q)$< $(silent) $(Kconfig)
build_menuconfig: $(obj)/mconf
@@ -68,12 +68,12 @@ simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \
PHONY += $(simple-targets)
$(simple-targets): $(obj)/conf
- $< $(silent) --$@ $(Kconfig)
+ $(Q)$< $(silent) --$@ $(Kconfig)
PHONY += savedefconfig defconfig
savedefconfig: $(obj)/conf
- $< $(silent) --$@=defconfig $(Kconfig)
+ $(Q)$< $(silent) --$@=defconfig $(Kconfig)
defconfig: $(obj)/conf
ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
@@ -111,7 +111,7 @@ tinyconfig:
# CHECK: -o cache_dir=<path> working?
PHONY += testconfig
testconfig: $(obj)/conf
- $(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \
+ $(Q)$(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \
-o cache_dir=$(abspath $(obj)/tests/.cache) \
$(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no)
clean-files += tests/.cache
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index d4ca8297364f..8454649b17bd 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -66,23 +66,6 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
fprintf(stderr, "Error in writing or end of file.\n");
}
-/* menu.c */
-void _menu_init(void);
-void menu_warn(struct menu *menu, const char *fmt, ...);
-struct menu *menu_add_menu(void);
-void menu_end_menu(void);
-void menu_add_entry(struct symbol *sym);
-void menu_add_dep(struct expr *dep);
-void menu_add_visibility(struct expr *dep);
-struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
-void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
-void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
-void menu_add_option_modules(void);
-void menu_add_option_defconfig_list(void);
-void menu_add_option_allnoconfig_y(void);
-void menu_finalize(struct menu *parent);
-void menu_set_type(int type);
-
/* util.c */
struct file *file_lookup(const char *name);
void *xmalloc(size_t size);
@@ -109,6 +92,36 @@ void str_append(struct gstr *gs, const char *s);
void str_printf(struct gstr *gs, const char *fmt, ...);
const char *str_get(struct gstr *gs);
+/* menu.c */
+void _menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option_modules(void);
+void menu_add_option_defconfig_list(void);
+void menu_add_option_allnoconfig_y(void);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+extern struct menu rootmenu;
+
+bool menu_is_empty(struct menu *menu);
+bool menu_is_visible(struct menu *menu);
+bool menu_has_prompt(struct menu *menu);
+const char *menu_get_prompt(struct menu *menu);
+struct menu *menu_get_root_menu(struct menu *menu);
+struct menu *menu_get_parent_menu(struct menu *menu);
+bool menu_has_help(struct menu *menu);
+const char *menu_get_help(struct menu *menu);
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
+void menu_get_ext_help(struct menu *menu, struct gstr *help);
+
/* symbol.c */
void sym_clear_all_valid(void);
struct symbol *sym_choice_default(struct symbol *sym);
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index f9ab98238aef..9e81be33c40f 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -12,20 +12,6 @@ bool conf_get_changed(void);
void conf_set_changed_callback(void (*fn)(void));
void conf_set_message_callback(void (*fn)(const char *s));
-/* menu.c */
-extern struct menu rootmenu;
-
-bool menu_is_empty(struct menu *menu);
-bool menu_is_visible(struct menu *menu);
-bool menu_has_prompt(struct menu *menu);
-const char * menu_get_prompt(struct menu *menu);
-struct menu * menu_get_root_menu(struct menu *menu);
-struct menu * menu_get_parent_menu(struct menu *menu);
-bool menu_has_help(struct menu *menu);
-const char * menu_get_help(struct menu *menu);
-struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
-void menu_get_ext_help(struct menu *menu, struct gstr *help);
-
/* symbol.c */
extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 8638785328a7..f7eb093614f2 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -83,14 +83,6 @@ QIcon ConfigItem::menuIcon;
QIcon ConfigItem::menubackIcon;
/*
- * set the new data
- * TODO check the value
- */
-void ConfigItem::okRename(int col)
-{
-}
-
-/*
* update the displayed of a menu entry
*/
void ConfigItem::updateMenu(void)
@@ -147,9 +139,6 @@ void ConfigItem::updateMenu(void)
if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
setIcon(promptColIdx, QIcon());
- setText(noColIdx, QString());
- setText(modColIdx, QString());
- setText(yesColIdx, QString());
break;
}
expr = sym_get_tristate_value(sym);
@@ -159,12 +148,10 @@ void ConfigItem::updateMenu(void)
setIcon(promptColIdx, choiceYesIcon);
else
setIcon(promptColIdx, symbolYesIcon);
- setText(yesColIdx, "Y");
ch = 'Y';
break;
case mod:
setIcon(promptColIdx, symbolModIcon);
- setText(modColIdx, "M");
ch = 'M';
break;
default:
@@ -172,31 +159,16 @@ void ConfigItem::updateMenu(void)
setIcon(promptColIdx, choiceNoIcon);
else
setIcon(promptColIdx, symbolNoIcon);
- setText(noColIdx, "N");
ch = 'N';
break;
}
- if (expr != no)
- setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
- if (expr != mod)
- setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
- if (expr != yes)
- setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
setText(dataColIdx, QChar(ch));
break;
case S_INT:
case S_HEX:
case S_STRING:
- const char* data;
-
- data = sym_get_string_value(sym);
-
- setText(dataColIdx, data);
- if (type == S_STRING)
- prompt = QString("%1: %2").arg(prompt).arg(data);
- else
- prompt = QString("(%2) %1").arg(prompt).arg(data);
+ setText(dataColIdx, sym_get_string_value(sym));
break;
}
if (!sym_has_value(sym) && visible)
@@ -237,6 +209,17 @@ void ConfigItem::init(void)
if (list->mode != fullMode)
setExpanded(true);
sym_calc_value(menu->sym);
+
+ if (menu->sym) {
+ enum symbol_type type = menu->sym->type;
+
+ // Allow to edit "int", "hex", and "string" in-place in
+ // the data column. Unfortunately, you cannot specify
+ // the flags per column. Set ItemIsEditable for all
+ // columns here, and check the column in createEditor().
+ if (type == S_INT || type == S_HEX || type == S_STRING)
+ setFlags(flags() | Qt::ItemIsEditable);
+ }
}
updateMenu();
}
@@ -257,46 +240,65 @@ ConfigItem::~ConfigItem(void)
}
}
-ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
- : Parent(parent)
+QWidget *ConfigItemDelegate::createEditor(QWidget *parent,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
{
- connect(this, SIGNAL(editingFinished()), SLOT(hide()));
-}
+ ConfigItem *item;
-void ConfigLineEdit::show(ConfigItem* i)
-{
- item = i;
- if (sym_get_string_value(item->menu->sym))
- setText(sym_get_string_value(item->menu->sym));
- else
- setText(QString());
- Parent::show();
- setFocus();
+ // Only the data column is editable
+ if (index.column() != dataColIdx)
+ return nullptr;
+
+ // You cannot edit invisible menus
+ item = static_cast<ConfigItem *>(index.internalPointer());
+ if (!item || !item->menu || !menu_is_visible(item->menu))
+ return nullptr;
+
+ return QStyledItemDelegate::createEditor(parent, option, index);
}
-void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
+void ConfigItemDelegate::setModelData(QWidget *editor,
+ QAbstractItemModel *model,
+ const QModelIndex &index) const
{
- switch (e->key()) {
- case Qt::Key_Escape:
- break;
- case Qt::Key_Return:
- case Qt::Key_Enter:
- sym_set_string_value(item->menu->sym, text().toLatin1());
- parent()->updateList();
- break;
- default:
- Parent::keyPressEvent(e);
- return;
+ QLineEdit *lineEdit;
+ ConfigItem *item;
+ struct symbol *sym;
+ bool success;
+
+ lineEdit = qobject_cast<QLineEdit *>(editor);
+ // If this is not a QLineEdit, use the parent's default.
+ // (does this happen?)
+ if (!lineEdit)
+ goto parent;
+
+ item = static_cast<ConfigItem *>(index.internalPointer());
+ if (!item || !item->menu)
+ goto parent;
+
+ sym = item->menu->sym;
+ if (!sym)
+ goto parent;
+
+ success = sym_set_string_value(sym, lineEdit->text().toUtf8().data());
+ if (success) {
+ ConfigList::updateListForAll();
+ } else {
+ QMessageBox::information(editor, "qconf",
+ "Cannot set the data (maybe due to out of range).\n"
+ "Setting the old value.");
+ lineEdit->setText(sym_get_string_value(sym));
}
- e->accept();
- parent()->list->setFocus();
- hide();
+
+parent:
+ QStyledItemDelegate::setModelData(editor, model, index);
}
-ConfigList::ConfigList(ConfigView* p, const char *name)
- : Parent(p),
+ConfigList::ConfigList(QWidget *parent, const char *name)
+ : QTreeWidget(parent),
updateAll(false),
- showName(false), showRange(false), showData(false), mode(singleMode), optMode(normalOpt),
+ showName(false), mode(singleMode), optMode(normalOpt),
rootEntry(0), headerPopup(0)
{
setObjectName(name);
@@ -306,7 +308,7 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
setVerticalScrollMode(ScrollPerPixel);
setHorizontalScrollMode(ScrollPerPixel);
- setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
+ setHeaderLabels(QStringList() << "Option" << "Name" << "Value");
connect(this, SIGNAL(itemSelectionChanged(void)),
SLOT(updateSelection(void)));
@@ -314,8 +316,6 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
if (name) {
configSettings->beginGroup(name);
showName = configSettings->value("/showName", false).toBool();
- showRange = configSettings->value("/showRange", false).toBool();
- showData = configSettings->value("/showData", false).toBool();
optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
configSettings->endGroup();
connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
@@ -323,9 +323,18 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
showColumn(promptColIdx);
+ setItemDelegate(new ConfigItemDelegate(this));
+
+ allLists.append(this);
+
reinit();
}
+ConfigList::~ConfigList()
+{
+ allLists.removeOne(this);
+}
+
bool ConfigList::menuSkip(struct menu *menu)
{
if (optMode == normalOpt && menu_is_visible(menu))
@@ -339,21 +348,10 @@ bool ConfigList::menuSkip(struct menu *menu)
void ConfigList::reinit(void)
{
- hideColumn(dataColIdx);
- hideColumn(yesColIdx);
- hideColumn(modColIdx);
- hideColumn(noColIdx);
hideColumn(nameColIdx);
if (showName)
showColumn(nameColIdx);
- if (showRange) {
- showColumn(noColIdx);
- showColumn(modColIdx);
- showColumn(yesColIdx);
- }
- if (showData)
- showColumn(dataColIdx);
updateListAll();
}
@@ -375,8 +373,6 @@ void ConfigList::saveSettings(void)
if (!objectName().isEmpty()) {
configSettings->beginGroup(objectName());
configSettings->setValue("/showName", showName);
- configSettings->setValue("/showRange", showRange);
- configSettings->setValue("/showData", showData);
configSettings->setValue("/optionMode", (int)optMode);
configSettings->endGroup();
}
@@ -462,6 +458,28 @@ update:
resizeColumnToContents(0);
}
+void ConfigList::updateListForAll()
+{
+ QListIterator<ConfigList *> it(allLists);
+
+ while (it.hasNext()) {
+ ConfigList *list = it.next();
+
+ list->updateList();
+ }
+}
+
+void ConfigList::updateListAllForAll()
+{
+ QListIterator<ConfigList *> it(allLists);
+
+ while (it.hasNext()) {
+ ConfigList *list = it.next();
+
+ list->updateList();
+ }
+}
+
void ConfigList::setValue(ConfigItem* item, tristate val)
{
struct symbol* sym;
@@ -482,7 +500,7 @@ void ConfigList::setValue(ConfigItem* item, tristate val)
return;
if (oldval == no && item->menu->list)
item->setExpanded(true);
- parent()->updateList();
+ ConfigList::updateListForAll();
break;
}
}
@@ -516,12 +534,9 @@ void ConfigList::changeValue(ConfigItem* item)
item->setExpanded(true);
}
if (oldexpr != newexpr)
- parent()->updateList();
+ ConfigList::updateListForAll();
break;
- case S_INT:
- case S_HEX:
- case S_STRING:
- parent()->lineEdit->show(item);
+ default:
break;
}
}
@@ -804,15 +819,6 @@ void ConfigList::mouseReleaseEvent(QMouseEvent* e)
}
}
break;
- case noColIdx:
- setValue(item, no);
- break;
- case modColIdx:
- setValue(item, mod);
- break;
- case yesColIdx:
- setValue(item, yes);
- break;
case dataColIdx:
changeValue(item);
break;
@@ -883,95 +889,31 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
action = new QAction("Show Name", this);
action->setCheckable(true);
connect(action, SIGNAL(toggled(bool)),
- parent(), SLOT(setShowName(bool)));
- connect(parent(), SIGNAL(showNameChanged(bool)),
+ SLOT(setShowName(bool)));
+ connect(this, SIGNAL(showNameChanged(bool)),
action, SLOT(setChecked(bool)));
action->setChecked(showName);
headerPopup->addAction(action);
-
- action = new QAction("Show Range", this);
- action->setCheckable(true);
- connect(action, SIGNAL(toggled(bool)),
- parent(), SLOT(setShowRange(bool)));
- connect(parent(), SIGNAL(showRangeChanged(bool)),
- action, SLOT(setChecked(bool)));
- action->setChecked(showRange);
- headerPopup->addAction(action);
-
- action = new QAction("Show Data", this);
- action->setCheckable(true);
- connect(action, SIGNAL(toggled(bool)),
- parent(), SLOT(setShowData(bool)));
- connect(parent(), SIGNAL(showDataChanged(bool)),
- action, SLOT(setChecked(bool)));
- action->setChecked(showData);
- headerPopup->addAction(action);
}
headerPopup->exec(e->globalPos());
e->accept();
}
-ConfigView*ConfigView::viewList;
-QAction *ConfigList::showNormalAction;
-QAction *ConfigList::showAllAction;
-QAction *ConfigList::showPromptAction;
-
-ConfigView::ConfigView(QWidget* parent, const char *name)
- : Parent(parent)
-{
- setObjectName(name);
- QVBoxLayout *verticalLayout = new QVBoxLayout(this);
- verticalLayout->setContentsMargins(0, 0, 0, 0);
-
- list = new ConfigList(this);
- verticalLayout->addWidget(list);
- lineEdit = new ConfigLineEdit(this);
- lineEdit->hide();
- verticalLayout->addWidget(lineEdit);
-
- this->nextView = viewList;
- viewList = this;
-}
-
-ConfigView::~ConfigView(void)
-{
- ConfigView** vp;
-
- for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
- if (*vp == this) {
- *vp = nextView;
- break;
- }
- }
-}
-
-void ConfigView::setShowName(bool b)
+void ConfigList::setShowName(bool on)
{
- if (list->showName != b) {
- list->showName = b;
- list->reinit();
- emit showNameChanged(b);
- }
-}
+ if (showName == on)
+ return;
-void ConfigView::setShowRange(bool b)
-{
- if (list->showRange != b) {
- list->showRange = b;
- list->reinit();
- emit showRangeChanged(b);
- }
+ showName = on;
+ reinit();
+ emit showNameChanged(on);
}
-void ConfigView::setShowData(bool b)
-{
- if (list->showData != b) {
- list->showData = b;
- list->reinit();
- emit showDataChanged(b);
- }
-}
+QList<ConfigList *> ConfigList::allLists;
+QAction *ConfigList::showNormalAction;
+QAction *ConfigList::showAllAction;
+QAction *ConfigList::showPromptAction;
void ConfigList::setAllOpen(bool open)
{
@@ -984,22 +926,6 @@ void ConfigList::setAllOpen(bool open)
}
}
-void ConfigView::updateList()
-{
- ConfigView* v;
-
- for (v = viewList; v; v = v->nextView)
- v->list->updateList();
-}
-
-void ConfigView::updateListAll(void)
-{
- ConfigView* v;
-
- for (v = viewList; v; v = v->nextView)
- v->list->updateListAll();
-}
-
ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
: Parent(parent), sym(0), _menu(0)
{
@@ -1108,6 +1034,11 @@ void ConfigInfoView::menuInfo(void)
if (showDebug())
stream << debug_info(sym);
+ struct gstr help_gstr = str_new();
+
+ menu_get_ext_help(_menu, &help_gstr);
+ stream << print_filter(str_get(&help_gstr));
+ str_free(&help_gstr);
} else if (_menu->prompt) {
stream << "<big><b>";
stream << print_filter(_menu->prompt->text);
@@ -1119,11 +1050,11 @@ void ConfigInfoView::menuInfo(void)
expr_print_help, &stream, E_NONE);
stream << "<br><br>";
}
+
+ stream << "defined at " << _menu->file->name << ":"
+ << _menu->lineno << "<br><br>";
}
}
- if (showDebug())
- stream << "defined at " << _menu->file->name << ":"
- << _menu->lineno << "<br><br>";
setText(info);
}
@@ -1276,7 +1207,7 @@ void ConfigInfoView::clicked(const QUrl &url)
}
free(result);
- delete data;
+ delete[] data;
}
void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
@@ -1310,12 +1241,12 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
split = new QSplitter(this);
split->setOrientation(Qt::Vertical);
- list = new ConfigView(split, "search");
- list->list->mode = listMode;
+ list = new ConfigList(split, "search");
+ list->mode = listMode;
info = new ConfigInfoView(split, "search");
- connect(list->list, SIGNAL(menuChanged(struct menu *)),
+ connect(list, SIGNAL(menuChanged(struct menu *)),
info, SLOT(setInfo(struct menu *)));
- connect(list->list, SIGNAL(menuChanged(struct menu *)),
+ connect(list, SIGNAL(menuChanged(struct menu *)),
parent, SLOT(setMenuLink(struct menu *)));
layout1->addWidget(split);
@@ -1359,7 +1290,7 @@ void ConfigSearchWindow::search(void)
ConfigItem *lastItem = NULL;
free(result);
- list->list->clear();
+ list->clear();
info->clear();
result = sym_re_search(editField->text().toLatin1());
@@ -1367,7 +1298,7 @@ void ConfigSearchWindow::search(void)
return;
for (p = result; *p; p++) {
for_all_prompts((*p), prop)
- lastItem = new ConfigItem(list->list, lastItem, prop->menu,
+ lastItem = new ConfigItem(list, lastItem, prop->menu,
menu_is_visible(prop->menu));
}
}
@@ -1415,23 +1346,21 @@ ConfigMainWindow::ConfigMainWindow(void)
split1->setOrientation(Qt::Horizontal);
split1->setChildrenCollapsible(false);
- menuView = new ConfigView(widget, "menu");
- menuList = menuView->list;
+ menuList = new ConfigList(widget, "menu");
split2 = new QSplitter(widget);
split2->setChildrenCollapsible(false);
split2->setOrientation(Qt::Vertical);
// create config tree
- configView = new ConfigView(widget, "config");
- configList = configView->list;
+ configList = new ConfigList(widget, "config");
helpText = new ConfigInfoView(widget, "help");
layout->addWidget(split2);
split2->addWidget(split1);
- split1->addWidget(configView);
- split1->addWidget(menuView);
+ split1->addWidget(configList);
+ split1->addWidget(menuList);
split2->addWidget(helpText);
setTabOrder(configList, helpText);
@@ -1475,14 +1404,8 @@ ConfigMainWindow::ConfigMainWindow(void)
QAction *showNameAction = new QAction("Show Name", this);
showNameAction->setCheckable(true);
- connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
- showNameAction->setChecked(configView->showName());
- QAction *showRangeAction = new QAction("Show Range", this);
- showRangeAction->setCheckable(true);
- connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
- QAction *showDataAction = new QAction("Show Data", this);
- showDataAction->setCheckable(true);
- connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
+ connect(showNameAction, SIGNAL(toggled(bool)), configList, SLOT(setShowName(bool)));
+ showNameAction->setChecked(configList->showName);
QActionGroup *optGroup = new QActionGroup(this);
optGroup->setExclusive(true);
@@ -1534,8 +1457,6 @@ ConfigMainWindow::ConfigMainWindow(void)
// create options menu
menu = menuBar()->addMenu("&Option");
menu->addAction(showNameAction);
- menu->addAction(showRangeAction);
- menu->addAction(showDataAction);
menu->addSeparator();
menu->addActions(optGroup->actions());
menu->addSeparator();
@@ -1608,7 +1529,7 @@ void ConfigMainWindow::loadConfig(void)
free(configname);
configname = xstrdup(name);
- ConfigView::updateListAll();
+ ConfigList::updateListAllForAll();
}
bool ConfigMainWindow::saveConfig(void)
@@ -1743,7 +1664,7 @@ void ConfigMainWindow::showSingleView(void)
backAction->setEnabled(true);
- menuView->hide();
+ menuList->hide();
menuList->setRootMenu(0);
configList->mode = singleMode;
if (configList->rootEntry == &rootmenu)
@@ -1774,7 +1695,7 @@ void ConfigMainWindow::showSplitView(void)
menuList->mode = symbolMode;
menuList->setRootMenu(&rootmenu);
menuList->setAllOpen(true);
- menuView->show();
+ menuList->show();
menuList->setFocus();
}
@@ -1789,7 +1710,7 @@ void ConfigMainWindow::showFullView(void)
backAction->setEnabled(false);
- menuView->hide();
+ menuList->hide();
menuList->setRootMenu(0);
configList->mode = fullMode;
if (configList->rootEntry == &rootmenu)
@@ -1831,17 +1752,26 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
void ConfigMainWindow::showIntro(void)
{
- static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
- "For each option, a blank box indicates the feature is disabled, a check\n"
- "indicates it is enabled, and a dot indicates that it is to be compiled\n"
- "as a module. Clicking on the box will cycle through the three states.\n\n"
- "If you do not see an option (e.g., a device driver) that you believe\n"
- "should be present, try turning on Show All Options under the Options menu.\n"
- "Although there is no cross reference yet to help you figure out what other\n"
- "options must be enabled to support the option you are interested in, you can\n"
- "still view the help of a grayed-out option.\n\n"
- "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
- "which you can then match by examining other options.\n\n";
+ static const QString str =
+ "Welcome to the qconf graphical configuration tool.\n"
+ "\n"
+ "For bool and tristate options, a blank box indicates the "
+ "feature is disabled, a check indicates it is enabled, and a "
+ "dot indicates that it is to be compiled as a module. Clicking "
+ "on the box will cycle through the three states. For int, hex, "
+ "and string options, double-clicking or pressing F2 on the "
+ "Value cell will allow you to edit the value.\n"
+ "\n"
+ "If you do not see an option (e.g., a device driver) that you "
+ "believe should be present, try turning on Show All Options "
+ "under the Options menu. Enabling Show Debug Info will help you"
+ "figure out what other options must be enabled to support the "
+ "option you are interested in, and hyperlinks will navigate to "
+ "them.\n"
+ "\n"
+ "Toggling Show Debug Info under the Options menu will show the "
+ "dependencies, which you can then match by examining other "
+ "options.\n";
QMessageBox::information(this, "qconf", str);
}
@@ -1921,7 +1851,6 @@ int main(int ac, char** av)
const char *name;
progname = av[0];
- configApp = new QApplication(ac, av);
if (ac > 1 && av[1][0] == '-') {
switch (av[1][1]) {
case 's':
@@ -1942,6 +1871,8 @@ int main(int ac, char** av)
conf_read(NULL);
//zconfdump(stdout);
+ configApp = new QApplication(ac, av);
+
configSettings = new ConfigSettings();
configSettings->beginGroup("/kconfig/qconf");
v = new ConfigMainWindow();
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index f97376a8123f..78b0a1dfcd53 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -11,15 +11,14 @@
#include <QPushButton>
#include <QSettings>
#include <QSplitter>
+#include <QStyledItemDelegate>
#include <QTextBrowser>
#include <QTreeWidget>
#include "expr.h"
-class ConfigView;
class ConfigList;
class ConfigItem;
-class ConfigLineEdit;
class ConfigMainWindow;
class ConfigSettings : public QSettings {
@@ -30,7 +29,7 @@ public:
};
enum colIdx {
- promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx
+ promptColIdx, nameColIdx, dataColIdx
};
enum listMode {
singleMode, menuMode, symbolMode, fullMode, listMode
@@ -43,13 +42,10 @@ class ConfigList : public QTreeWidget {
Q_OBJECT
typedef class QTreeWidget Parent;
public:
- ConfigList(ConfigView* p, const char *name = 0);
+ ConfigList(QWidget *parent, const char *name = 0);
+ ~ConfigList();
void reinit(void);
ConfigItem* findConfigItem(struct menu *);
- ConfigView* parent(void) const
- {
- return (ConfigView*)Parent::parent();
- }
void setSelected(QTreeWidgetItem *item, bool enable) {
for (int i = 0; i < selectedItems().size(); i++)
selectedItems().at(i)->setSelected(false);
@@ -75,6 +71,7 @@ public slots:
void updateSelection(void);
void saveSettings(void);
void setOptionMode(QAction *action);
+ void setShowName(bool on);
signals:
void menuChanged(struct menu *menu);
@@ -82,6 +79,7 @@ signals:
void itemSelected(struct menu *menu);
void parentSelected(void);
void gotFocus(struct menu *);
+ void showNameChanged(bool on);
public:
void updateListAll(void)
@@ -100,7 +98,7 @@ public:
bool updateAll;
- bool showName, showRange, showData;
+ bool showName;
enum listMode mode;
enum optionMode optMode;
struct menu *rootEntry;
@@ -108,6 +106,10 @@ public:
QPalette inactivedColorGroup;
QMenu* headerPopup;
+ static QList<ConfigList *> allLists;
+ static void updateListForAll();
+ static void updateListAllForAll();
+
static QAction *showNormalAction, *showAllAction, *showPromptAction;
};
@@ -131,7 +133,6 @@ public:
}
~ConfigItem(void);
void init(void);
- void okRename(int col);
void updateMenu(void);
void testUpdateMenu(bool v);
ConfigList* listView() const
@@ -168,48 +169,18 @@ public:
static QIcon menuIcon, menubackIcon;
};
-class ConfigLineEdit : public QLineEdit {
- Q_OBJECT
- typedef class QLineEdit Parent;
-public:
- ConfigLineEdit(ConfigView* parent);
- ConfigView* parent(void) const
- {
- return (ConfigView*)Parent::parent();
- }
- void show(ConfigItem *i);
- void keyPressEvent(QKeyEvent *e);
-
-public:
- ConfigItem *item;
-};
-
-class ConfigView : public QWidget {
- Q_OBJECT
- typedef class QWidget Parent;
-public:
- ConfigView(QWidget* parent, const char *name = 0);
- ~ConfigView(void);
- static void updateList();
- static void updateListAll(void);
-
- bool showName(void) const { return list->showName; }
- bool showRange(void) const { return list->showRange; }
- bool showData(void) const { return list->showData; }
-public slots:
- void setShowName(bool);
- void setShowRange(bool);
- void setShowData(bool);
-signals:
- void showNameChanged(bool);
- void showRangeChanged(bool);
- void showDataChanged(bool);
+class ConfigItemDelegate : public QStyledItemDelegate
+{
+private:
+ struct menu *menu;
public:
- ConfigList* list;
- ConfigLineEdit* lineEdit;
-
- static ConfigView* viewList;
- ConfigView* nextView;
+ ConfigItemDelegate(QObject *parent = nullptr)
+ : QStyledItemDelegate(parent) {}
+ QWidget *createEditor(QWidget *parent,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+ void setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const override;
};
class ConfigInfoView : public QTextBrowser {
@@ -257,7 +228,7 @@ protected:
QLineEdit* editField;
QPushButton* searchButton;
QSplitter* split;
- ConfigView* list;
+ ConfigList *list;
ConfigInfoView* info;
struct symbol **result;
@@ -292,9 +263,7 @@ protected:
void closeEvent(QCloseEvent *e);
ConfigSearchWindow *searchWindow;
- ConfigView *menuView;
ConfigList *menuList;
- ConfigView *configView;
ConfigList *configList;
ConfigInfoView *helpText;
QAction *backAction;
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index d1b445665ad6..f699cf05d409 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -56,6 +56,13 @@ Output format selection (mutually exclusive):
-rst Output reStructuredText format.
-none Do not output documentation, only warnings.
+Output format selection modifier (affects only ReST output):
+
+ -sphinx-version Use the ReST C domain dialect compatible with an
+ specific Sphinx Version.
+ If not specified, kernel-doc will auto-detect using
+ the sphinx-build version found on PATH.
+
Output selection (mutually exclusive):
-export Only output documentation for symbols that have been
exported using EXPORT_SYMBOL() or EXPORT_SYMBOL_GPL()
@@ -66,9 +73,8 @@ 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.
+ -nosymbol NAME Exclude the specified symbols from the output
+ documentation. May be specified multiple times.
Output selection modifiers:
-no-doc-sections Do not output DOC: sections.
@@ -271,6 +277,8 @@ if ($#ARGV == -1) {
}
my $kernelversion;
+my ($sphinx_major, $sphinx_minor, $sphinx_patch);
+
my $dohighlight = "";
my $verbose = 0;
@@ -286,9 +294,8 @@ my $modulename = "Kernel API";
use constant {
OUTPUT_ALL => 0, # output all symbols and doc sections
OUTPUT_INCLUDE => 1, # output only specified symbols
- OUTPUT_EXCLUDE => 2, # output everything except specified symbols
- OUTPUT_EXPORTED => 3, # output exported symbols
- OUTPUT_INTERNAL => 4, # output non-exported symbols
+ OUTPUT_EXPORTED => 2, # output exported symbols
+ OUTPUT_INTERNAL => 3, # output non-exported symbols
};
my $output_selection = OUTPUT_ALL;
my $show_not_found = 0; # No longer used
@@ -313,6 +320,7 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June',
# CAVEAT EMPTOR! Some of the others I localised may not want to be, which
# could cause "use of undefined value" or other bugs.
my ($function, %function_table, %parametertypes, $declaration_purpose);
+my %nosymbol_table = ();
my $declaration_start_line;
my ($type, $declaration_name, $return_type);
my ($newsection, $newcontents, $prototype, $brcount, %source_map);
@@ -432,10 +440,9 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
$output_selection = OUTPUT_INCLUDE;
$function = shift @ARGV;
$function_table{$function} = 1;
- } elsif ($cmd eq "nofunction") { # output all except specific functions
- $output_selection = OUTPUT_EXCLUDE;
- $function = shift @ARGV;
- $function_table{$function} = 1;
+ } elsif ($cmd eq "nosymbol") { # Exclude specific symbols
+ my $symbol = shift @ARGV;
+ $nosymbol_table{$symbol} = 1;
} elsif ($cmd eq "export") { # only exported symbols
$output_selection = OUTPUT_EXPORTED;
%function_table = ();
@@ -457,6 +464,23 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
$enable_lineno = 1;
} elsif ($cmd eq 'show-not-found') {
$show_not_found = 1; # A no-op but don't fail
+ } elsif ($cmd eq "sphinx-version") {
+ my $ver_string = shift @ARGV;
+ if ($ver_string =~ m/^(\d+)(\.\d+)?(\.\d+)?/) {
+ $sphinx_major = $1;
+ if (defined($2)) {
+ $sphinx_minor = substr($2,1);
+ } else {
+ $sphinx_minor = 0;
+ }
+ if (defined($3)) {
+ $sphinx_patch = substr($3,1)
+ } else {
+ $sphinx_patch = 0;
+ }
+ } else {
+ die "Sphinx version should either major.minor or major.minor.patch format\n";
+ }
} else {
# Unknown argument
usage();
@@ -465,6 +489,51 @@ while ($ARGV[0] =~ m/^--?(.*)/) {
# continue execution near EOF;
+# The C domain dialect changed on Sphinx 3. So, we need to check the
+# version in order to produce the right tags.
+sub findprog($)
+{
+ foreach(split(/:/, $ENV{PATH})) {
+ return "$_/$_[0]" if(-x "$_/$_[0]");
+ }
+}
+
+sub get_sphinx_version()
+{
+ my $ver;
+
+ my $cmd = "sphinx-build";
+ if (!findprog($cmd)) {
+ my $cmd = "sphinx-build3";
+ if (!findprog($cmd)) {
+ $sphinx_major = 1;
+ $sphinx_minor = 2;
+ $sphinx_patch = 0;
+ printf STDERR "Warning: Sphinx version not found. Using default (Sphinx version %d.%d.%d)\n",
+ $sphinx_major, $sphinx_minor, $sphinx_patch;
+ return;
+ }
+ }
+
+ open IN, "$cmd --version 2>&1 |";
+ while (<IN>) {
+ if (m/^\s*sphinx-build\s+([\d]+)\.([\d\.]+)(\+\/[\da-f]+)?$/) {
+ $sphinx_major = $1;
+ $sphinx_minor = $2;
+ $sphinx_patch = $3;
+ last;
+ }
+ # Sphinx 1.2.x uses a different format
+ if (m/^\s*Sphinx.*\s+([\d]+)\.([\d\.]+)$/) {
+ $sphinx_major = $1;
+ $sphinx_minor = $2;
+ $sphinx_patch = $3;
+ last;
+ }
+ }
+ close IN;
+}
+
# get kernel version from env
sub get_kernel_version() {
my $version = 'unknown kernel version';
@@ -531,11 +600,11 @@ sub dump_doc_section {
return;
}
+ return if (defined($nosymbol_table{$name}));
+
if (($output_selection == OUTPUT_ALL) ||
- ($output_selection == OUTPUT_INCLUDE &&
- defined($function_table{$name})) ||
- ($output_selection == OUTPUT_EXCLUDE &&
- !defined($function_table{$name})))
+ (($output_selection == OUTPUT_INCLUDE) &&
+ defined($function_table{$name})))
{
dump_section($file, $name, $contents);
output_blockhead({'sectionlist' => \@sectionlist,
@@ -618,10 +687,10 @@ sub output_function_man(%) {
$type = $args{'parametertypes'}{$parameter};
if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
# pointer-to-function
- print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n";
+ print ".BI \"" . $parenth . $1 . "\" " . " \") (" . $2 . ")" . $post . "\"\n";
} else {
$type =~ s/([^\*])$/$1 /;
- print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n";
+ print ".BI \"" . $parenth . $type . "\" " . " \"" . $post . "\"\n";
}
$count++;
$parenth = "";
@@ -761,6 +830,8 @@ sub output_blockhead_rst(%) {
my ($parameter, $section);
foreach $section (@{$args{'sectionlist'}}) {
+ next if (defined($nosymbol_table{$section}));
+
if ($output_selection != OUTPUT_INCLUDE) {
print "**$section**\n\n";
}
@@ -846,16 +917,37 @@ sub output_function_rst(%) {
my ($parameter, $section);
my $oldprefix = $lineprefix;
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 ``";
+ my $is_macro = 0;
+
+ if ($sphinx_major < 3) {
+ 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 ``";
+ $is_macro = 1;
+ } else {
+ print ".. c:function:: ";
+ }
} else {
- print ".. c:function:: ";
+ if ($args{'typedef'} || $args{'functiontype'} eq "") {
+ $is_macro = 1;
+ print ".. c:macro:: ". $args{'function'} . "\n\n";
+ } else {
+ print ".. c:function:: ";
+ }
+
+ if ($args{'typedef'}) {
+ print_lineno($declaration_start_line);
+ print " **Typedef**: ";
+ $lineprefix = "";
+ output_highlight_rst($args{'purpose'});
+ $start = "\n\n**Syntax**\n\n ``";
+ } else {
+ print "``" if ($is_macro);
+ }
}
if ($args{'functiontype'} ne "") {
$start .= $args{'functiontype'} . " " . $args{'function'} . " (";
@@ -876,13 +968,15 @@ sub output_function_rst(%) {
# pointer-to-function
print $1 . $parameter . ") (" . $2 . ")";
} else {
- print $type . " " . $parameter;
+ print $type;
}
}
- if ($args{'typedef'}) {
- print ");``\n\n";
+ if ($is_macro) {
+ print ")``\n\n";
} else {
print ")\n\n";
+ }
+ if (!$args{'typedef'}) {
print_lineno($declaration_start_line);
$lineprefix = " ";
output_highlight_rst($args{'purpose'});
@@ -897,7 +991,7 @@ sub output_function_rst(%) {
$type = $args{'parametertypes'}{$parameter};
if ($type ne "") {
- print "``$type $parameter``\n";
+ print "``$type``\n";
} else {
print "``$parameter``\n";
}
@@ -938,9 +1032,14 @@ sub output_enum_rst(%) {
my ($parameter);
my $oldprefix = $lineprefix;
my $count;
- my $name = "enum " . $args{'enum'};
- print "\n\n.. c:type:: " . $name . "\n\n";
+ if ($sphinx_major < 3) {
+ my $name = "enum " . $args{'enum'};
+ print "\n\n.. c:type:: " . $name . "\n\n";
+ } else {
+ my $name = $args{'enum'};
+ print "\n\n.. c:enum:: " . $name . "\n\n";
+ }
print_lineno($declaration_start_line);
$lineprefix = " ";
output_highlight_rst($args{'purpose'});
@@ -966,8 +1065,13 @@ sub output_typedef_rst(%) {
my %args = %{$_[0]};
my ($parameter);
my $oldprefix = $lineprefix;
- my $name = "typedef " . $args{'typedef'};
+ my $name;
+ if ($sphinx_major < 3) {
+ $name = "typedef " . $args{'typedef'};
+ } else {
+ $name = $args{'typedef'};
+ }
print "\n\n.. c:type:: " . $name . "\n\n";
print_lineno($declaration_start_line);
$lineprefix = " ";
@@ -982,9 +1086,18 @@ sub output_struct_rst(%) {
my %args = %{$_[0]};
my ($parameter);
my $oldprefix = $lineprefix;
- my $name = $args{'type'} . " " . $args{'struct'};
- print "\n\n.. c:type:: " . $name . "\n\n";
+ if ($sphinx_major < 3) {
+ my $name = $args{'type'} . " " . $args{'struct'};
+ print "\n\n.. c:type:: " . $name . "\n\n";
+ } else {
+ my $name = $args{'struct'};
+ if ($args{'type'} eq 'union') {
+ print "\n\n.. c:union:: " . $name . "\n\n";
+ } else {
+ print "\n\n.. c:struct:: " . $name . "\n\n";
+ }
+ }
print_lineno($declaration_start_line);
$lineprefix = " ";
output_highlight_rst($args{'purpose'});
@@ -1043,12 +1156,14 @@ sub output_declaration {
my $name = shift;
my $functype = shift;
my $func = "output_${functype}_$output_mode";
+
+ return if (defined($nosymbol_table{$name}));
+
if (($output_selection == OUTPUT_ALL) ||
(($output_selection == OUTPUT_INCLUDE ||
$output_selection == OUTPUT_EXPORTED) &&
defined($function_table{$name})) ||
- (($output_selection == OUTPUT_EXCLUDE ||
- $output_selection == OUTPUT_INTERNAL) &&
+ ($output_selection == OUTPUT_INTERNAL &&
!($functype eq "function" && defined($function_table{$name}))))
{
&$func(@_);
@@ -1083,7 +1198,7 @@ sub dump_struct($$) {
my $x = shift;
my $file = shift;
- if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
+ if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|____cacheline_aligned_in_smp|____cacheline_aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
my $decl_type = $1;
$declaration_name = $2;
my $members = $3;
@@ -1099,6 +1214,7 @@ sub dump_struct($$) {
$members =~ s/\s*__packed\s*/ /gos;
$members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos;
$members =~ s/\s*____cacheline_aligned_in_smp/ /gos;
+ $members =~ s/\s*____cacheline_aligned/ /gos;
# replace DECLARE_BITMAP
$members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos;
@@ -1228,6 +1344,8 @@ sub show_warnings($$) {
my $functype = shift;
my $name = shift;
+ return 0 if (defined($nosymbol_table{$name}));
+
return 1 if ($output_selection == OUTPUT_ALL);
if ($output_selection == OUTPUT_EXPORTED) {
@@ -1251,27 +1369,28 @@ sub show_warnings($$) {
return 0;
}
}
- if ($output_selection == OUTPUT_EXCLUDE) {
- if (!defined($function_table{$name})) {
- return 1;
- } else {
- return 0;
- }
- }
die("Please add the new output type at show_warnings()");
}
sub dump_enum($$) {
my $x = shift;
my $file = shift;
+ my $members;
+
$x =~ s@/\*.*?\*/@@gos; # strip comments.
# strip #define macros inside enums
$x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
- if ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) {
+ if ($x =~ /typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;/) {
+ $declaration_name = $2;
+ $members = $1;
+ } elsif ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) {
$declaration_name = $1;
- my $members = $2;
+ $members = $2;
+ }
+
+ if ($declaration_name) {
my %_members;
$members =~ s/\s+$//;
@@ -1306,27 +1425,31 @@ sub dump_enum($$) {
'sections' => \%sections,
'purpose' => $declaration_purpose
});
- }
- else {
+ } else {
print STDERR "${file}:$.: error: Cannot parse enum!\n";
++$errors;
}
}
+my $typedef_type = qr { ((?:\s+[\w\*]+){1,8})\s* }x;
+my $typedef_ident = qr { \*?\s*(\w\S+)\s* }x;
+my $typedef_args = qr { \s*\((.*)\); }x;
+
+my $typedef1 = qr { typedef$typedef_type\($typedef_ident\)$typedef_args }x;
+my $typedef2 = qr { typedef$typedef_type$typedef_ident$typedef_args }x;
+
sub dump_typedef($$) {
my $x = shift;
my $file = shift;
$x =~ s@/\*.*?\*/@@gos; # strip comments.
- # Parse function prototypes
- if ($x =~ /typedef\s+(\w+)\s*\(\*\s*(\w\S+)\s*\)\s*\((.*)\);/ ||
- $x =~ /typedef\s+(\w+)\s*(\w\S+)\s*\s*\((.*)\);/) {
-
- # Function typedefs
+ # Parse function typedef prototypes
+ if ($x =~ $typedef1 || $x =~ $typedef2) {
$return_type = $1;
$declaration_name = $2;
my $args = $3;
+ $return_type =~ s/^\s+//;
create_parameterlist($args, ',', $file, $declaration_name);
@@ -1402,7 +1525,7 @@ sub create_parameterlist($$$$) {
# Treat preprocessor directive as a typeless variable just to fill
# corresponding data structures "correctly". Catch it later in
# output_* subs.
- push_parameter($arg, "", $file);
+ push_parameter($arg, "", "", $file);
} elsif ($arg =~ m/\(.+\)\s*\(/) {
# pointer-to-function
$arg =~ tr/#/,/;
@@ -1411,7 +1534,7 @@ sub create_parameterlist($$$$) {
$type = $arg;
$type =~ s/([^\(]+\(\*?)\s*$param/$1/;
save_struct_actual($param);
- push_parameter($param, $type, $file, $declaration_name);
+ push_parameter($param, $type, $arg, $file, $declaration_name);
} elsif ($arg) {
$arg =~ s/\s*:\s*/:/g;
$arg =~ s/\s*\[/\[/g;
@@ -1436,26 +1559,28 @@ sub create_parameterlist($$$$) {
foreach $param (@args) {
if ($param =~ m/^(\*+)\s*(.*)/) {
save_struct_actual($2);
- push_parameter($2, "$type $1", $file, $declaration_name);
+
+ push_parameter($2, "$type $1", $arg, $file, $declaration_name);
}
elsif ($param =~ m/(.*?):(\d+)/) {
if ($type ne "") { # skip unnamed bit-fields
save_struct_actual($1);
- push_parameter($1, "$type:$2", $file, $declaration_name)
+ push_parameter($1, "$type:$2", $arg, $file, $declaration_name)
}
}
else {
save_struct_actual($param);
- push_parameter($param, $type, $file, $declaration_name);
+ push_parameter($param, $type, $arg, $file, $declaration_name);
}
}
}
}
}
-sub push_parameter($$$$) {
+sub push_parameter($$$$$) {
my $param = shift;
my $type = shift;
+ my $org_arg = shift;
my $file = shift;
my $declaration_name = shift;
@@ -1519,8 +1644,8 @@ sub push_parameter($$$$) {
# "[blah" in a parameter string;
###$param =~ s/\s*//g;
push @parameterlist, $param;
- $type =~ s/\s\s+/ /g;
- $parametertypes{$param} = $type;
+ $org_arg =~ s/\s\s+/ /g;
+ $parametertypes{$param} = $org_arg;
}
sub check_sections($$$$$) {
@@ -1594,6 +1719,8 @@ sub dump_function($$) {
my $file = shift;
my $noret = 0;
+ print_lineno($new_start_line);
+
$prototype =~ s/^static +//;
$prototype =~ s/^extern +//;
$prototype =~ s/^asmlinkage +//;
@@ -1669,30 +1796,48 @@ sub dump_function($$) {
return;
}
- my $prms = join " ", @parameterlist;
- check_sections($file, $declaration_name, "function", $sectcheck, $prms);
+ my $prms = join " ", @parameterlist;
+ check_sections($file, $declaration_name, "function", $sectcheck, $prms);
- # This check emits a lot of warnings at the moment, because many
- # functions don't have a 'Return' doc section. So until the number
- # of warnings goes sufficiently down, the check is only performed in
- # verbose mode.
- # TODO: always perform the check.
- if ($verbose && !$noret) {
- check_return_section($file, $declaration_name, $return_type);
- }
+ # This check emits a lot of warnings at the moment, because many
+ # functions don't have a 'Return' doc section. So until the number
+ # of warnings goes sufficiently down, the check is only performed in
+ # verbose mode.
+ # TODO: always perform the check.
+ if ($verbose && !$noret) {
+ check_return_section($file, $declaration_name, $return_type);
+ }
- output_declaration($declaration_name,
- 'function',
- {'function' => $declaration_name,
- 'module' => $modulename,
- 'functiontype' => $return_type,
- 'parameterlist' => \@parameterlist,
- 'parameterdescs' => \%parameterdescs,
- 'parametertypes' => \%parametertypes,
- 'sectionlist' => \@sectionlist,
- 'sections' => \%sections,
- 'purpose' => $declaration_purpose
- });
+ # The function parser can be called with a typedef parameter.
+ # Handle it.
+ if ($return_type =~ /typedef/) {
+ output_declaration($declaration_name,
+ 'function',
+ {'function' => $declaration_name,
+ 'typedef' => 1,
+ 'module' => $modulename,
+ 'functiontype' => $return_type,
+ 'parameterlist' => \@parameterlist,
+ 'parameterdescs' => \%parameterdescs,
+ 'parametertypes' => \%parametertypes,
+ 'sectionlist' => \@sectionlist,
+ 'sections' => \%sections,
+ 'purpose' => $declaration_purpose
+ });
+ } else {
+ output_declaration($declaration_name,
+ 'function',
+ {'function' => $declaration_name,
+ 'module' => $modulename,
+ 'functiontype' => $return_type,
+ 'parameterlist' => \@parameterlist,
+ 'parameterdescs' => \%parameterdescs,
+ 'parametertypes' => \%parametertypes,
+ 'sectionlist' => \@sectionlist,
+ 'sections' => \%sections,
+ 'purpose' => $declaration_purpose
+ });
+ }
}
sub reset_state {
@@ -1870,6 +2015,7 @@ sub process_export_file($) {
while (<IN>) {
if (/$export_symbol/) {
+ next if (defined($nosymbol_table{$2}));
$function_table{$2} = 1;
}
}
@@ -1901,7 +2047,7 @@ sub process_name($$) {
if (/$doc_block/o) {
$state = STATE_DOCBLOCK;
$contents = "";
- $new_start_line = $. + 1;
+ $new_start_line = $.;
if ( $1 eq "" ) {
$section = $section_intro;
@@ -1984,6 +2130,7 @@ sub process_body($$) {
if ($state == STATE_BODY_WITH_BLANK_LINE && /^\s*\*\s?\S/) {
dump_section($file, $section, $contents);
$section = $section_default;
+ $new_start_line = $.;
$contents = "";
}
@@ -2039,6 +2186,7 @@ sub process_body($$) {
$prototype = "";
$state = STATE_PROTO;
$brcount = 0;
+ $new_start_line = $. + 1;
} elsif (/$doc_content/) {
if ($1 eq "") {
if ($section eq $section_context) {
@@ -2186,7 +2334,7 @@ sub process_file($) {
$file = map_filename($orig_file);
- if (!open(IN,"<$file")) {
+ if (!open(IN_FILE,"<$file")) {
print STDERR "Error: Cannot open file $file\n";
++$errors;
return;
@@ -2195,9 +2343,9 @@ sub process_file($) {
$. = 1;
$section_counter = 0;
- while (<IN>) {
+ while (<IN_FILE>) {
while (s/\\\s*$//) {
- $_ .= <IN>;
+ $_ .= <IN_FILE>;
}
# Replace tabs by spaces
while ($_ =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {};
@@ -2229,9 +2377,14 @@ sub process_file($) {
print STDERR "${file}:1: warning: no structured comments found\n";
}
}
+ close IN_FILE;
}
+if ($output_mode eq "rst") {
+ get_sphinx_version() if (!$sphinx_major);
+}
+
$kernelversion = get_kernel_version();
# generate a sequence of code that will splice in highlighting information
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index e6e2d9e5ff48..6eded325c837 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -169,10 +169,9 @@ gen_btf()
printf '\1' | dd of=${2} conv=notrunc bs=1 seek=16 status=none
}
-# Create ${2} .o file with all symbols from the ${1} object file
+# Create ${2} .S file with all symbols from the ${1} object file
kallsyms()
{
- info KSYM ${2}
local kallsymopt;
if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then
@@ -187,13 +186,8 @@ kallsyms()
kallsymopt="${kallsymopt} --base-relative"
fi
- local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
- ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
-
- local afile="`basename ${2} .o`.S"
-
- ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${afile}
- ${CC} ${aflags} -c -o ${2} ${afile}
+ info KSYMS ${2}
+ ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2}
}
# Perform one step in kallsyms generation, including temporary linking of
@@ -203,9 +197,15 @@ kallsyms_step()
kallsymso_prev=${kallsymso}
kallsyms_vmlinux=.tmp_vmlinux.kallsyms${1}
kallsymso=${kallsyms_vmlinux}.o
+ kallsyms_S=${kallsyms_vmlinux}.S
vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o}
- kallsyms ${kallsyms_vmlinux} ${kallsymso}
+ kallsyms ${kallsyms_vmlinux} ${kallsyms_S}
+
+ info AS ${kallsyms_S}
+ ${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \
+ ${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
+ -c -o ${kallsymso} ${kallsyms_S}
}
# Create map file with all symbols from ${1}
@@ -341,9 +341,9 @@ fi
vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o}
# fill in BTF IDs
-if [ -n "${CONFIG_DEBUG_INFO_BTF}" ]; then
-info BTFIDS vmlinux
-${RESOLVE_BTFIDS} vmlinux
+if [ -n "${CONFIG_DEBUG_INFO_BTF}" -a -n "${CONFIG_BPF}" ]; then
+ info BTFIDS vmlinux
+ ${RESOLVE_BTFIDS} vmlinux
fi
if [ -n "${CONFIG_BUILDTIME_TABLE_SORT}" ]; then
diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
index baf3ab8d9d49..4ae735039daf 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -35,7 +35,7 @@ else
LINUX_COMPILE_BY=$KBUILD_BUILD_USER
fi
if test -z "$KBUILD_BUILD_HOST"; then
- LINUX_COMPILE_HOST=`hostname`
+ LINUX_COMPILE_HOST=`uname -n`
else
LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST
fi
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 69341b36f271..f882ce0d9327 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -2254,7 +2254,7 @@ static void add_header(struct buffer *b, struct module *mod)
buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
buf_printf(b, "\n");
buf_printf(b, "__visible struct module __this_module\n");
- buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
+ buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
if (mod->has_init)
buf_printf(b, "\t.init = init_module,\n");
@@ -2308,7 +2308,7 @@ static int add_versions(struct buffer *b, struct module *mod)
buf_printf(b, "\n");
buf_printf(b, "static const struct modversion_info ____versions[]\n");
- buf_printf(b, "__used __section(__versions) = {\n");
+ buf_printf(b, "__used __section(\"__versions\") = {\n");
for (s = mod->unres; s; s = s->next) {
if (!s->module)
diff --git a/scripts/module-common.lds b/scripts/module.lds.S
index d61b9e8678e8..69b9b71a6a47 100644
--- a/scripts/module-common.lds
+++ b/scripts/module.lds.S
@@ -24,3 +24,6 @@ SECTIONS {
__jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) }
}
+
+/* bring in arch-specific sections */
+#include <asm/module.lds.h>
diff --git a/scripts/namespace.pl b/scripts/namespace.pl
deleted file mode 100755
index 1da7bca201a4..000000000000
--- a/scripts/namespace.pl
+++ /dev/null
@@ -1,473 +0,0 @@
-#!/usr/bin/env perl
-#
-# namespace.pl. Mon Aug 30 2004
-#
-# Perform a name space analysis on the linux kernel.
-#
-# Copyright Keith Owens <kaos@ocs.com.au>. GPL.
-#
-# Invoke by changing directory to the top of the kernel object
-# tree then namespace.pl, no parameters.
-#
-# Tuned for 2.1.x kernels with the new module handling, it will
-# work with 2.0 kernels as well.
-#
-# Last change 2.6.9-rc1, adding support for separate source and object
-# trees.
-#
-# The source must be compiled/assembled first, the object files
-# are the primary input to this script. Incomplete or missing
-# objects will result in a flawed analysis. Compile both vmlinux
-# and modules.
-#
-# Even with complete objects, treat the result of the analysis
-# with caution. Some external references are only used by
-# certain architectures, others with certain combinations of
-# configuration parameters. Ideally the source should include
-# something like
-#
-# #ifndef CONFIG_...
-# static
-# #endif
-# symbol_definition;
-#
-# so the symbols are defined as static unless a particular
-# CONFIG_... requires it to be external.
-#
-# A symbol that is suffixed with '(export only)' has these properties
-#
-# * It is global.
-# * It is marked EXPORT_SYMBOL or EXPORT_SYMBOL_GPL, either in the same
-# source file or a different source file.
-# * Given the current .config, nothing uses the symbol.
-#
-# The symbol is a candidate for conversion to static, plus removal of the
-# export. But be careful that a different .config might use the symbol.
-#
-#
-# Name space analysis and cleanup is an iterative process. You cannot
-# expect to find all the problems in a single pass.
-#
-# * Identify possibly unnecessary global declarations, verify that they
-# really are unnecessary and change them to static.
-# * Compile and fix up gcc warnings about static, removing dead symbols
-# as necessary.
-# * make clean and rebuild with different configs (especially
-# CONFIG_MODULES=n) to see which symbols are being defined when the
-# config does not require them. These symbols bloat the kernel object
-# for no good reason, which is frustrating for embedded systems.
-# * Wrap config sensitive symbols in #ifdef CONFIG_foo, as long as the
-# code does not get too ugly.
-# * Repeat the name space analysis until you can live with with the
-# result.
-#
-
-use warnings;
-use strict;
-use File::Find;
-use File::Spec;
-
-my $nm = ($ENV{'NM'} || "nm") . " -p";
-my $objdump = ($ENV{'OBJDUMP'} || "objdump") . " -s -j .comment";
-my $srctree = File::Spec->curdir();
-my $objtree = File::Spec->curdir();
-$srctree = File::Spec->rel2abs($ENV{'srctree'}) if (exists($ENV{'srctree'}));
-$objtree = File::Spec->rel2abs($ENV{'objtree'}) if (exists($ENV{'objtree'}));
-
-if ($#ARGV != -1) {
- print STDERR "usage: $0 takes no parameters\n";
- die("giving up\n");
-}
-
-my %nmdata = (); # nm data for each object
-my %def = (); # all definitions for each name
-my %ksymtab = (); # names that appear in __ksymtab_
-my %ref = (); # $ref{$name} exists if there is a true external reference to $name
-my %export = (); # $export{$name} exists if there is an EXPORT_... of $name
-
-my %nmexception = (
- 'fs/ext3/bitmap' => 1,
- 'fs/ext4/bitmap' => 1,
- 'arch/x86/lib/thunk_32' => 1,
- 'arch/x86/lib/cmpxchg' => 1,
- 'arch/x86/vdso/vdso32/note' => 1,
- 'lib/irq_regs' => 1,
- 'usr/initramfs_data' => 1,
- 'drivers/scsi/aic94xx/aic94xx_dump' => 1,
- 'drivers/scsi/libsas/sas_dump' => 1,
- 'lib/dec_and_lock' => 1,
- 'drivers/ide/ide-probe-mini' => 1,
- 'usr/initramfs_data' => 1,
- 'drivers/acpi/acpia/exdump' => 1,
- 'drivers/acpi/acpia/rsdump' => 1,
- 'drivers/acpi/acpia/nsdumpdv' => 1,
- 'drivers/acpi/acpia/nsdump' => 1,
- 'arch/ia64/sn/kernel/sn2/io' => 1,
- 'arch/ia64/kernel/gate-data' => 1,
- 'security/capability' => 1,
- 'fs/ntfs/sysctl' => 1,
- 'fs/jfs/jfs_debug' => 1,
-);
-
-my %nameexception = (
- 'mod_use_count_' => 1,
- '__initramfs_end' => 1,
- '__initramfs_start' => 1,
- '_einittext' => 1,
- '_sinittext' => 1,
- 'kallsyms_names' => 1,
- 'kallsyms_num_syms' => 1,
- 'kallsyms_addresses'=> 1,
- 'kallsyms_offsets' => 1,
- 'kallsyms_relative_base'=> 1,
- '__this_module' => 1,
- '_etext' => 1,
- '_edata' => 1,
- '_end' => 1,
- '__bss_start' => 1,
- '_text' => 1,
- '_stext' => 1,
- '__gp' => 1,
- 'ia64_unw_start' => 1,
- 'ia64_unw_end' => 1,
- '__init_begin' => 1,
- '__init_end' => 1,
- '__bss_stop' => 1,
- '__nosave_begin' => 1,
- '__nosave_end' => 1,
- 'pg0' => 1,
- 'vdso_enabled' => 1,
- '__stack_chk_fail' => 1,
- 'VDSO32_PRELINK' => 1,
- 'VDSO32_vsyscall' => 1,
- 'VDSO32_rt_sigreturn'=>1,
- 'VDSO32_sigreturn' => 1,
-);
-
-
-&find(\&linux_objects, '.'); # find the objects and do_nm on them
-&list_multiply_defined();
-&resolve_external_references();
-&list_extra_externals();
-
-exit(0);
-
-sub linux_objects
-{
- # Select objects, ignoring objects which are only created by
- # merging other objects. Also ignore all of modules, scripts
- # and compressed. Most conglomerate objects are handled by do_nm,
- # this list only contains the special cases. These include objects
- # that are linked from just one other object and objects for which
- # there is really no permanent source file.
- my $basename = $_;
- $_ = $File::Find::name;
- s:^\./::;
- if (/.*\.o$/ &&
- ! (
- m:/built-in.a$:
- || m:arch/x86/vdso/:
- || m:arch/x86/boot/:
- || m:arch/ia64/ia32/ia32.o$:
- || m:arch/ia64/kernel/gate-syms.o$:
- || m:arch/ia64/lib/__divdi3.o$:
- || m:arch/ia64/lib/__divsi3.o$:
- || m:arch/ia64/lib/__moddi3.o$:
- || m:arch/ia64/lib/__modsi3.o$:
- || m:arch/ia64/lib/__udivdi3.o$:
- || m:arch/ia64/lib/__udivsi3.o$:
- || m:arch/ia64/lib/__umoddi3.o$:
- || m:arch/ia64/lib/__umodsi3.o$:
- || m:arch/ia64/scripts/check_gas_for_hint.o$:
- || m:arch/ia64/sn/kernel/xp.o$:
- || m:boot/bbootsect.o$:
- || m:boot/bsetup.o$:
- || m:/bootsect.o$:
- || m:/boot/setup.o$:
- || m:/compressed/:
- || m:drivers/cdrom/driver.o$:
- || m:drivers/char/drm/tdfx_drv.o$:
- || m:drivers/ide/ide-detect.o$:
- || m:drivers/ide/pci/idedriver-pci.o$:
- || m:drivers/media/media.o$:
- || m:drivers/scsi/sd_mod.o$:
- || m:drivers/video/video.o$:
- || m:fs/devpts/devpts.o$:
- || m:fs/exportfs/exportfs.o$:
- || m:fs/hugetlbfs/hugetlbfs.o$:
- || m:fs/msdos/msdos.o$:
- || m:fs/nls/nls.o$:
- || m:fs/ramfs/ramfs.o$:
- || m:fs/romfs/romfs.o$:
- || m:fs/vfat/vfat.o$:
- || m:init/mounts.o$:
- || m:^modules/:
- || m:net/netlink/netlink.o$:
- || m:net/sched/sched.o$:
- || m:/piggy.o$:
- || m:^scripts/:
- || m:sound/.*/snd-:
- || m:^.*/\.tmp_:
- || m:^\.tmp_:
- || m:/vmlinux-obj.o$:
- || m:^tools/:
- )
- ) {
- do_nm($basename, $_);
- }
- $_ = $basename; # File::Find expects $_ untouched (undocumented)
-}
-
-sub do_nm
-{
- my ($basename, $fullname) = @_;
- my ($source, $type, $name);
- if (! -e $basename) {
- printf STDERR "$basename does not exist\n";
- return;
- }
- if ($fullname !~ /\.o$/) {
- printf STDERR "$fullname is not an object file\n";
- return;
- }
- ($source = $basename) =~ s/\.o$//;
- if (-e "$source.c" || -e "$source.S") {
- $source = File::Spec->catfile($objtree, $File::Find::dir, $source)
- } else {
- $source = File::Spec->catfile($srctree, $File::Find::dir, $source)
- }
- if (! -e "$source.c" && ! -e "$source.S") {
- # No obvious source, exclude the object if it is conglomerate
- open(my $objdumpdata, "$objdump $basename|")
- or die "$objdump $fullname failed $!\n";
-
- my $comment;
- while (<$objdumpdata>) {
- chomp();
- if (/^In archive/) {
- # Archives are always conglomerate
- $comment = "GCC:GCC:";
- last;
- }
- next if (! /^[ 0-9a-f]{5,} /);
- $comment .= substr($_, 43);
- }
- close($objdumpdata);
-
- if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) {
- printf STDERR "No source file found for $fullname\n";
- }
- return;
- }
- open (my $nmdata, "$nm $basename|")
- or die "$nm $fullname failed $!\n";
-
- my @nmdata;
- while (<$nmdata>) {
- chop;
- ($type, $name) = (split(/ +/, $_, 3))[1..2];
- # Expected types
- # A absolute symbol
- # B weak external reference to data that has been resolved
- # C global variable, uninitialised
- # D global variable, initialised
- # G global variable, initialised, small data section
- # R global array, initialised
- # S global variable, uninitialised, small bss
- # T global label/procedure
- # U external reference
- # W weak external reference to text that has been resolved
- # V similar to W, but the value of the weak symbol becomes zero with no error.
- # a assembler equate
- # b static variable, uninitialised
- # d static variable, initialised
- # g static variable, initialised, small data section
- # r static array, initialised
- # s static variable, uninitialised, small bss
- # t static label/procedures
- # w weak external reference to text that has not been resolved
- # v similar to w
- # ? undefined type, used a lot by modules
- if ($type !~ /^[ABCDGRSTUWVabdgrstwv?]$/) {
- printf STDERR "nm output for $fullname contains unknown type '$_'\n";
- }
- elsif ($name =~ /\./) {
- # name with '.' is local static
- }
- else {
- $type = 'R' if ($type eq '?'); # binutils replaced ? with R at one point
- # binutils keeps changing the type for exported symbols, force it to R
- $type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
- $name =~ s/_R[a-f0-9]{8}$//; # module versions adds this
- if ($type =~ /[ABCDGRSTWV]/ &&
- $name ne 'init_module' &&
- $name ne 'cleanup_module' &&
- $name ne 'Using_Versions' &&
- $name !~ /^Version_[0-9]+$/ &&
- $name !~ /^__parm_/ &&
- $name !~ /^__kstrtab/ &&
- $name !~ /^__ksymtab/ &&
- $name !~ /^__kcrctab_/ &&
- $name !~ /^__exitcall_/ &&
- $name !~ /^__initcall_/ &&
- $name !~ /^__kdb_initcall_/ &&
- $name !~ /^__kdb_exitcall_/ &&
- $name !~ /^__module_/ &&
- $name !~ /^__mod_/ &&
- $name !~ /^__crc_/ &&
- $name ne '__this_module' &&
- $name ne 'kernel_version') {
- if (!exists($def{$name})) {
- $def{$name} = [];
- }
- push(@{$def{$name}}, $fullname);
- }
- push(@nmdata, "$type $name");
- if ($name =~ /^__ksymtab_/) {
- $name = substr($name, 10);
- if (!exists($ksymtab{$name})) {
- $ksymtab{$name} = [];
- }
- push(@{$ksymtab{$name}}, $fullname);
- }
- }
- }
- close($nmdata);
-
- if ($#nmdata < 0) {
- printf "No nm data for $fullname\n"
- unless $nmexception{$fullname};
- return;
- }
- $nmdata{$fullname} = \@nmdata;
-}
-
-sub drop_def
-{
- my ($object, $name) = @_;
- my $nmdata = $nmdata{$object};
- my ($i, $j);
- for ($i = 0; $i <= $#{$nmdata}; ++$i) {
- if ($name eq (split(' ', $nmdata->[$i], 2))[1]) {
- splice(@{$nmdata{$object}}, $i, 1);
- my $def = $def{$name};
- for ($j = 0; $j < $#{$def{$name}}; ++$j) {
- if ($def{$name}[$j] eq $object) {
- splice(@{$def{$name}}, $j, 1);
- }
- }
- last;
- }
- }
-}
-
-sub list_multiply_defined
-{
- foreach my $name (keys(%def)) {
- if ($#{$def{$name}} > 0) {
- # Special case for cond_syscall
- if ($#{$def{$name}} == 1 &&
- ($name =~ /^sys_/ || $name =~ /^compat_sys_/ ||
- $name =~ /^sys32_/)) {
- if($def{$name}[0] eq "kernel/sys_ni.o" ||
- $def{$name}[1] eq "kernel/sys_ni.o") {
- &drop_def("kernel/sys_ni.o", $name);
- next;
- }
- }
-
- printf "$name is multiply defined in :-\n";
- foreach my $module (@{$def{$name}}) {
- printf "\t$module\n";
- }
- }
- }
-}
-
-sub resolve_external_references
-{
- my ($kstrtab, $ksymtab, $export);
-
- printf "\n";
- foreach my $object (keys(%nmdata)) {
- my $nmdata = $nmdata{$object};
- for (my $i = 0; $i <= $#{$nmdata}; ++$i) {
- my ($type, $name) = split(' ', $nmdata->[$i], 2);
- if ($type eq "U" || $type eq "w") {
- if (exists($def{$name}) || exists($ksymtab{$name})) {
- # add the owning object to the nmdata
- $nmdata->[$i] = "$type $name $object";
- # only count as a reference if it is not EXPORT_...
- $kstrtab = "R __kstrtab_$name";
- $ksymtab = "R __ksymtab_$name";
- $export = 0;
- for (my $j = 0; $j <= $#{$nmdata}; ++$j) {
- if ($nmdata->[$j] eq $kstrtab ||
- $nmdata->[$j] eq $ksymtab) {
- $export = 1;
- last;
- }
- }
- if ($export) {
- $export{$name} = "";
- }
- else {
- $ref{$name} = ""
- }
- }
- elsif ( ! $nameexception{$name}
- && $name !~ /^__sched_text_/
- && $name !~ /^__start_/
- && $name !~ /^__end_/
- && $name !~ /^__stop_/
- && $name !~ /^__scheduling_functions_.*_here/
- && $name !~ /^__.*initcall_/
- && $name !~ /^__.*per_cpu_start/
- && $name !~ /^__.*per_cpu_end/
- && $name !~ /^__alt_instructions/
- && $name !~ /^__setup_/
- && $name !~ /^__mod_timer/
- && $name !~ /^__mod_page_state/
- && $name !~ /^init_module/
- && $name !~ /^cleanup_module/
- ) {
- printf "Cannot resolve ";
- printf "weak " if ($type eq "w");
- printf "reference to $name from $object\n";
- }
- }
- }
- }
-}
-
-sub list_extra_externals
-{
- my %noref = ();
-
- foreach my $name (keys(%def)) {
- if (! exists($ref{$name})) {
- my @module = @{$def{$name}};
- foreach my $module (@module) {
- if (! exists($noref{$module})) {
- $noref{$module} = [];
- }
- push(@{$noref{$module}}, $name);
- }
- }
- }
- if (%noref) {
- printf "\nExternally defined symbols with no external references\n";
- foreach my $module (sort(keys(%noref))) {
- printf " $module\n";
- foreach (sort(@{$noref{$module}})) {
- my $export;
- if (exists($export{$_})) {
- $export = " (export only)";
- } else {
- $export = "";
- }
- printf " $_$export\n";
- }
- }
- }
-}
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 6df3c9f8b2da..1b11f8993629 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -26,24 +26,29 @@ if_enabled_echo() {
create_package() {
local pname="$1" pdir="$2"
+ local dpkg_deb_opts
mkdir -m 755 -p "$pdir/DEBIAN"
mkdir -p "$pdir/usr/share/doc/$pname"
cp debian/copyright "$pdir/usr/share/doc/$pname/"
cp debian/changelog "$pdir/usr/share/doc/$pname/changelog.Debian"
- gzip -9 "$pdir/usr/share/doc/$pname/changelog.Debian"
+ gzip -n -9 "$pdir/usr/share/doc/$pname/changelog.Debian"
sh -c "cd '$pdir'; find . -type f ! -path './DEBIAN/*' -printf '%P\0' \
| xargs -r0 md5sum > DEBIAN/md5sums"
# Fix ownership and permissions
- chown -R root:root "$pdir"
+ if [ "$DEB_RULES_REQUIRES_ROOT" = "no" ]; then
+ dpkg_deb_opts="--root-owner-group"
+ else
+ chown -R root:root "$pdir"
+ fi
chmod -R go-w "$pdir"
# in case we are in a restrictive umask environment like 0077
chmod -R a+rX "$pdir"
# Create the package
dpkg-gencontrol -p$pname -P"$pdir"
- dpkg-deb ${KDEB_COMPRESS:+-Z$KDEB_COMPRESS} --build "$pdir" ..
+ dpkg-deb $dpkg_deb_opts ${KDEB_COMPRESS:+-Z$KDEB_COMPRESS} --build "$pdir" ..
}
deploy_kernel_headers () {
@@ -55,7 +60,7 @@ deploy_kernel_headers () {
cd $srctree
find . arch/$SRCARCH -maxdepth 1 -name Makefile\*
find include scripts -type f -o -type l
- find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform
+ find arch/$SRCARCH -name Kbuild.platforms -o -name Platform
find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f
) > debian/hdrsrcfiles
@@ -202,8 +207,10 @@ EOF
done
if [ "$ARCH" != "um" ]; then
- deploy_kernel_headers debian/linux-headers
- create_package linux-headers-$version debian/linux-headers
+ if is_enabled CONFIG_MODULES; then
+ deploy_kernel_headers debian/linux-headers
+ create_package linux-headers-$version debian/linux-headers
+ fi
deploy_libc_headers debian/linux-libc-dev
create_package linux-libc-dev debian/linux-libc-dev
diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian
index 48fbd3d0284a..60a2a63a5e90 100755
--- a/scripts/package/mkdebian
+++ b/scripts/package/mkdebian
@@ -94,16 +94,16 @@ else
packageversion=$version-$revision
fi
sourcename=$KDEB_SOURCENAME
-packagename=linux-image-$version
-kernel_headers_packagename=linux-headers-$version
-dbg_packagename=$packagename-dbg
-debarch=
-set_debarch
if [ "$ARCH" = "um" ] ; then
- packagename=user-mode-linux-$version
+ packagename=user-mode-linux
+else
+ packagename=linux-image
fi
+debarch=
+set_debarch
+
email=${DEBEMAIL-$EMAIL}
# use email string directly if it contains <email>
@@ -174,22 +174,16 @@ Source: $sourcename
Section: kernel
Priority: optional
Maintainer: $maintainer
+Rules-Requires-Root: no
Build-Depends: bc, rsync, kmod, cpio, bison, flex | flex:native $extra_build_depends
Homepage: https://www.kernel.org/
-Package: $packagename
+Package: $packagename-$version
Architecture: $debarch
Description: Linux kernel, version $version
This package contains the Linux kernel, modules and corresponding other
files, version: $version.
-Package: $kernel_headers_packagename
-Architecture: $debarch
-Description: Linux kernel headers for $version on $debarch
- This package provides kernel header files for $version on $debarch
- .
- This is useful for people who need to build external modules
-
Package: linux-libc-dev
Section: devel
Provides: linux-kernel-headers
@@ -200,10 +194,22 @@ Description: Linux support headers for userspace development
Multi-Arch: same
EOF
+if is_enabled CONFIG_MODULES; then
+cat <<EOF >> debian/control
+
+Package: linux-headers-$version
+Architecture: $debarch
+Description: Linux kernel headers for $version on $debarch
+ This package provides kernel header files for $version on $debarch
+ .
+ This is useful for people who need to build external modules
+EOF
+fi
+
if is_enabled CONFIG_DEBUG_INFO; then
cat <<EOF >> debian/control
-Package: $dbg_packagename
+Package: linux-image-$version-dbg
Section: debug
Architecture: $debarch
Description: Linux kernel debugging symbols for $version
@@ -217,11 +223,15 @@ cat <<EOF > debian/rules
srctree ?= .
-build:
+build-indep:
+build-arch:
\$(MAKE) KERNELRELEASE=${version} ARCH=${ARCH} \
KBUILD_BUILD_VERSION=${revision} -f \$(srctree)/Makefile
-binary-arch:
+build: build-arch
+
+binary-indep:
+binary-arch: build-arch
\$(MAKE) KERNELRELEASE=${version} ARCH=${ARCH} \
KBUILD_BUILD_VERSION=${revision} -f \$(srctree)/Makefile intdeb-pkg
diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
index 6ceb88eb9b59..105c1c31a316 100644
--- a/scripts/selinux/mdp/mdp.c
+++ b/scripts/selinux/mdp/mdp.c
@@ -35,6 +35,9 @@ struct security_class_mapping {
#include "classmap.h"
#include "initial_sid_to_string.h"
+#include "policycap_names.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
int main(int argc, char *argv[])
{
@@ -115,6 +118,10 @@ int main(int argc, char *argv[])
}
}
+ /* enable all policy capabilities */
+ for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
+ fprintf(fout, "policycap %s;\n", selinux_policycap_names[i]);
+
/* types, roles, and allows */
fprintf(fout, "type base_t;\n");
fprintf(fout, "role base_r;\n");
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 20f2efd57b11..bb709eda96cd 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -45,7 +45,7 @@ scm_version()
# Check for git and a git repo.
if test -z "$(git rev-parse --show-cdup 2>/dev/null)" &&
- head=$(git rev-parse --verify --short HEAD 2>/dev/null); then
+ head=$(git rev-parse --verify HEAD 2>/dev/null); then
# If we are at a tagged commit (like "v2.6.30-rc6"), we ignore
# it, because this version is defined in the top level Makefile.
@@ -59,11 +59,22 @@ scm_version()
fi
# If we are past a tagged commit (like
# "v2.6.30-rc5-302-g72357d5"), we pretty print it.
- if atag="$(git describe 2>/dev/null)"; then
- echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
-
- # If we don't have a tag at all we print -g{commitish}.
+ #
+ # Ensure the abbreviated sha1 has exactly 12
+ # hex characters, to make the output
+ # independent of git version, local
+ # core.abbrev settings and/or total number of
+ # objects in the current repository - passing
+ # --abbrev=12 ensures a minimum of 12, and the
+ # awk substr() then picks the 'g' and first 12
+ # hex chars.
+ if atag="$(git describe --abbrev=12 2>/dev/null)"; then
+ echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),substr($(NF),0,13))}'
+
+ # If we don't have a tag at all we print -g{commitish},
+ # again using exactly 12 hex chars.
else
+ head="$(echo $head | cut -c1-12)"
printf '%s%s' -g $head
fi
fi
diff --git a/scripts/spdxcheck.py b/scripts/spdxcheck.py
index 6374e078a5f2..bc87200f9c7c 100755
--- a/scripts/spdxcheck.py
+++ b/scripts/spdxcheck.py
@@ -180,6 +180,9 @@ class id_parser(object):
# Remove trailing comment closure
if line.strip().endswith('*/'):
expr = expr.rstrip('*/').strip()
+ # Remove trailing xml comment closure
+ if line.strip().endswith('-->'):
+ expr = expr.rstrip('-->').strip()
# Special case for SH magic boot code files
if line.startswith('LIST \"'):
expr = expr.rstrip('\"').strip()
diff --git a/scripts/spelling.txt b/scripts/spelling.txt
index f253681e7e2a..953f4a2de1e5 100644
--- a/scripts/spelling.txt
+++ b/scripts/spelling.txt
@@ -9,6 +9,7 @@
#
abandonning||abandoning
abigious||ambiguous
+abitrary||arbitrary
abitrate||arbitrate
abnornally||abnormally
abnrormal||abnormal
@@ -482,6 +483,7 @@ disgest||digest
dispalying||displaying
diplay||display
directon||direction
+direcly||directly
direectly||directly
diregard||disregard
disassocation||disassociation
@@ -589,14 +591,13 @@ explictly||explicitly
expresion||expression
exprimental||experimental
extened||extended
-exteneded||extended||extended
+exteneded||extended
extensability||extensibility
extention||extension
extenstion||extension
extracter||extractor
faied||failed
faield||failed
-falied||failed
faild||failed
failded||failed
failer||failure
@@ -793,7 +794,6 @@ interrup||interrupt
interrups||interrupts
interruptted||interrupted
interupted||interrupted
-interupt||interrupt
intial||initial
intialisation||initialisation
intialised||initialised
@@ -871,6 +871,7 @@ malplace||misplace
managable||manageable
managment||management
mangement||management
+manger||manager
manoeuvering||maneuvering
manufaucturing||manufacturing
mappping||mapping
@@ -968,7 +969,6 @@ occurd||occurred
occured||occurred
occurence||occurrence
occure||occurred
-occured||occurred
occuring||occurring
offser||offset
offet||offset
@@ -1437,7 +1437,6 @@ udpate||update
uesd||used
uknown||unknown
usccess||success
-usupported||unsupported
uncommited||uncommitted
uncompatible||incompatible
unconditionaly||unconditionally
@@ -1478,6 +1477,7 @@ unsolicitied||unsolicited
unsuccessfull||unsuccessful
unsuported||unsupported
untill||until
+ununsed||unused
unuseful||useless
unvalid||invalid
upate||update
diff --git a/scripts/tags.sh b/scripts/tags.sh
index 850f4ccb6afc..fd96734deff1 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -205,6 +205,8 @@ regex_c=(
'/\<DEVICE_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/dev_attr_\2/'
'/\<DRIVER_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/driver_attr_\2/'
'/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)(\([[:alnum:]_]\+\)/\4/'
+ '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_t/'
+ '/^SEQCOUNT_LOCKTYPE(\([^,]*\),[[:space:]]*\([^,]*\),[^)]*)/seqcount_\2_init/'
)
regex_kconfig=(
'/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/'