diff options
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/checksyscalls.sh | 4 | ||||
-rwxr-xr-x | scripts/coccicheck | 2 | ||||
-rw-r--r-- | scripts/coccinelle/api/kobj_to_dev.cocci | 45 | ||||
-rw-r--r-- | scripts/coccinelle/free/kfree.cocci | 12 | ||||
-rw-r--r-- | scripts/coccinelle/misc/flexible_array.cocci | 23 | ||||
-rw-r--r-- | scripts/coccinelle/misc/irqf_oneshot.cocci | 4 | ||||
-rw-r--r-- | scripts/coccinelle/misc/minmax.cocci | 222 | ||||
-rw-r--r-- | scripts/coccinelle/misc/swap.cocci | 122 | ||||
-rw-r--r-- | scripts/coccinelle/misc/uninitialized_var.cocci | 15 | ||||
-rwxr-xr-x | scripts/decode_stacktrace.sh | 89 |
10 files changed, 462 insertions, 76 deletions
diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index a18b47695f55..b7609958ee36 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -40,6 +40,10 @@ cat << EOF #define __IGNORE_setrlimit /* setrlimit */ #endif +#ifndef __ARCH_WANT_MEMFD_SECRET +#define __IGNORE_memfd_secret +#endif + /* Missing flags argument */ #define __IGNORE_renameat /* renameat2 */ diff --git a/scripts/coccicheck b/scripts/coccicheck index 65fee63aeadb..caba0bff6da7 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -87,7 +87,7 @@ else fi # Use only one thread per core by default if hyperthreading is enabled - THREADS_PER_CORE=$(lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]") + THREADS_PER_CORE=$(LANG=C lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]") if [ -z "$J" ]; then NPROC=$(getconf _NPROCESSORS_ONLN) if [ $THREADS_PER_CORE -gt 1 -a $NPROC -gt 4 ] ; then diff --git a/scripts/coccinelle/api/kobj_to_dev.cocci b/scripts/coccinelle/api/kobj_to_dev.cocci deleted file mode 100644 index cd5d31c6fe76..000000000000 --- a/scripts/coccinelle/api/kobj_to_dev.cocci +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/// -/// Use kobj_to_dev() instead of container_of() -/// -// Confidence: High -// Copyright: (C) 2020 Denis Efremov ISPRAS -// Options: --no-includes --include-headers -// -// Keywords: kobj_to_dev, container_of -// - -virtual context -virtual report -virtual org -virtual patch - - -@r depends on !patch@ -expression ptr; -symbol kobj; -position p; -@@ - -* container_of(ptr, struct device, kobj)@p - - -@depends on patch@ -expression ptr; -@@ - -- container_of(ptr, struct device, kobj) -+ kobj_to_dev(ptr) - - -@script:python depends on report@ -p << r.p; -@@ - -coccilib.report.print_report(p[0], "WARNING opportunity for kobj_to_dev()") - -@script:python depends on org@ -p << r.p; -@@ - -coccilib.org.print_todo(p[0], "WARNING opportunity for kobj_to_dev()") diff --git a/scripts/coccinelle/free/kfree.cocci b/scripts/coccinelle/free/kfree.cocci index 168568386034..9b6e2037c2a9 100644 --- a/scripts/coccinelle/free/kfree.cocci +++ b/scripts/coccinelle/free/kfree.cocci @@ -22,9 +22,9 @@ position p1; @@ ( -* kfree@p1(E) + kfree@p1(E) | -* kfree_sensitive@p1(E) + kfree_sensitive@p1(E) ) @print expression@ @@ -66,9 +66,9 @@ position ok; while (1) { ... ( -* kfree@ok(E) + kfree@ok(E) | -* kfree_sensitive@ok(E) + kfree_sensitive@ok(E) ) ... when != break; when != goto l; @@ -84,9 +84,9 @@ position free.p1!=loop.ok,p2!={print.p,sz.p}; @@ ( -* kfree@p1(E,...) + kfree@p1(E,...) | -* kfree_sensitive@p1(E,...) + kfree_sensitive@p1(E,...) ) ... ( diff --git a/scripts/coccinelle/misc/flexible_array.cocci b/scripts/coccinelle/misc/flexible_array.cocci index 947fbaff82a9..f427fd68ed2d 100644 --- a/scripts/coccinelle/misc/flexible_array.cocci +++ b/scripts/coccinelle/misc/flexible_array.cocci @@ -51,21 +51,40 @@ position p : script:python() { relevant(p) }; }; ) +@only_field depends on patch@ +identifier name, array; +type T; +position q; +@@ + +( + struct name {@q + T array[0]; + }; +| + struct {@q + T array[0]; + }; +) + @depends on patch@ identifier name, array; type T; position p : script:python() { relevant(p) }; +// position @q with rule "only_field" simplifies +// handling of bitfields, arrays, etc. +position q != only_field.q; @@ ( - struct name { + struct name {@q ... T array@p[ - 0 ]; }; | - struct { + struct {@q ... T array@p[ - 0 diff --git a/scripts/coccinelle/misc/irqf_oneshot.cocci b/scripts/coccinelle/misc/irqf_oneshot.cocci index 7b48287b3dc1..9b6f404d07f2 100644 --- a/scripts/coccinelle/misc/irqf_oneshot.cocci +++ b/scripts/coccinelle/misc/irqf_oneshot.cocci @@ -103,11 +103,11 @@ devm_request_threaded_irq@p(dev, irq, NULL, ...) @script:python depends on org@ p << match.p; @@ -msg = "ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT" +msg = "WARNING: Threaded IRQ with no primary handler requested without IRQF_ONESHOT (unless it is nested IRQ)" coccilib.org.print_todo(p[0],msg) @script:python depends on report@ p << match.p; @@ -msg = "ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT" +msg = "WARNING: Threaded IRQ with no primary handler requested without IRQF_ONESHOT (unless it is nested IRQ)" coccilib.report.print_report(p[0],msg) diff --git a/scripts/coccinelle/misc/minmax.cocci b/scripts/coccinelle/misc/minmax.cocci new file mode 100644 index 000000000000..fcf908b34f27 --- /dev/null +++ b/scripts/coccinelle/misc/minmax.cocci @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// +/// Check for opencoded min(), max() implementations. +/// Generated patches sometimes require adding a cast to fix compile warning. +/// Warnings/patches scope intentionally limited to a function body. +/// +// Confidence: Medium +// Copyright: (C) 2021 Denis Efremov ISPRAS +// Options: --no-includes --include-headers +// +// Keywords: min, max +// + + +virtual report +virtual org +virtual context +virtual patch + +@rmax depends on !patch@ +identifier func; +expression x, y; +binary operator cmp = {>, >=}; +position p; +@@ + +func(...) +{ + <... +* ((x) cmp@p (y) ? (x) : (y)) + ...> +} + +@rmaxif depends on !patch@ +identifier func; +expression x, y; +expression max_val; +binary operator cmp = {>, >=}; +position p; +@@ + +func(...) +{ + <... +* if ((x) cmp@p (y)) { +* max_val = (x); +* } else { +* max_val = (y); +* } + ...> +} + +@rmin depends on !patch@ +identifier func; +expression x, y; +binary operator cmp = {<, <=}; +position p; +@@ + +func(...) +{ + <... +* ((x) cmp@p (y) ? (x) : (y)) + ...> +} + +@rminif depends on !patch@ +identifier func; +expression x, y; +expression min_val; +binary operator cmp = {<, <=}; +position p; +@@ + +func(...) +{ + <... +* if ((x) cmp@p (y)) { +* min_val = (x); +* } else { +* min_val = (y); +* } + ...> +} + +@pmax depends on patch@ +identifier func; +expression x, y; +binary operator cmp = {>=, >}; +@@ + +func(...) +{ + <... +- ((x) cmp (y) ? (x) : (y)) ++ max(x, y) + ...> +} + +@pmaxif depends on patch@ +identifier func; +expression x, y; +expression max_val; +binary operator cmp = {>=, >}; +@@ + +func(...) +{ + <... +- if ((x) cmp (y)) { +- max_val = x; +- } else { +- max_val = y; +- } ++ max_val = max(x, y); + ...> +} + +// Don't generate patches for errcode returns. +@errcode depends on patch@ +position p; +identifier func; +expression x; +binary operator cmp = {<, <=}; +@@ + +func(...) +{ + <... + return ((x) cmp@p 0 ? (x) : 0); + ...> +} + +@pmin depends on patch@ +identifier func; +expression x, y; +binary operator cmp = {<=, <}; +position p != errcode.p; +@@ + +func(...) +{ + <... +- ((x) cmp@p (y) ? (x) : (y)) ++ min(x, y) + ...> +} + +@pminif depends on patch@ +identifier func; +expression x, y; +expression min_val; +binary operator cmp = {<=, <}; +@@ + +func(...) +{ + <... +- if ((x) cmp (y)) { +- min_val = x; +- } else { +- min_val = y; +- } ++ min_val = min(x, y); + ...> +} + +@script:python depends on report@ +p << rmax.p; +@@ + +for p0 in p: + coccilib.report.print_report(p0, "WARNING opportunity for max()") + +@script:python depends on org@ +p << rmax.p; +@@ + +for p0 in p: + coccilib.org.print_todo(p0, "WARNING opportunity for max()") + +@script:python depends on report@ +p << rmaxif.p; +@@ + +for p0 in p: + coccilib.report.print_report(p0, "WARNING opportunity for max()") + +@script:python depends on org@ +p << rmaxif.p; +@@ + +for p0 in p: + coccilib.org.print_todo(p0, "WARNING opportunity for max()") + +@script:python depends on report@ +p << rmin.p; +@@ + +for p0 in p: + coccilib.report.print_report(p0, "WARNING opportunity for min()") + +@script:python depends on org@ +p << rmin.p; +@@ + +for p0 in p: + coccilib.org.print_todo(p0, "WARNING opportunity for min()") + +@script:python depends on report@ +p << rminif.p; +@@ + +for p0 in p: + coccilib.report.print_report(p0, "WARNING opportunity for min()") + +@script:python depends on org@ +p << rminif.p; +@@ + +for p0 in p: + coccilib.org.print_todo(p0, "WARNING opportunity for min()") diff --git a/scripts/coccinelle/misc/swap.cocci b/scripts/coccinelle/misc/swap.cocci new file mode 100644 index 000000000000..c5e71b7ef7f5 --- /dev/null +++ b/scripts/coccinelle/misc/swap.cocci @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// +/// Check for opencoded swap() implementation. +/// +// Confidence: High +// Copyright: (C) 2021 Denis Efremov ISPRAS +// Options: --no-includes --include-headers +// +// Keywords: swap +// + +virtual patch +virtual org +virtual report +virtual context + +@rvar depends on !patch@ +identifier tmp; +expression a, b; +type T; +position p; +@@ + +( +* T tmp; +| +* T tmp = 0; +| +* T *tmp = NULL; +) +... when != tmp +* tmp = a; +* a = b;@p +* b = tmp; +... when != tmp + +@r depends on !patch@ +identifier tmp; +expression a, b; +position p != rvar.p; +@@ + +* tmp = a; +* a = b;@p +* b = tmp; + +@rpvar depends on patch@ +identifier tmp; +expression a, b; +type T; +@@ + +( +- T tmp; +| +- T tmp = 0; +| +- T *tmp = NULL; +) +... when != tmp +- tmp = a; +- a = b; +- b = tmp ++ swap(a, b) + ; +... when != tmp + +@rp depends on patch@ +identifier tmp; +expression a, b; +@@ + +- tmp = a; +- a = b; +- b = tmp ++ swap(a, b) + ; + +@depends on patch && (rpvar || rp)@ +@@ + +( + for (...;...;...) +- { + swap(...); +- } +| + while (...) +- { + swap(...); +- } +| + if (...) +- { + swap(...); +- } +) + + +@script:python depends on report@ +p << r.p; +@@ + +coccilib.report.print_report(p[0], "WARNING opportunity for swap()") + +@script:python depends on org@ +p << r.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING opportunity for swap()") + +@script:python depends on report@ +p << rvar.p; +@@ + +coccilib.report.print_report(p[0], "WARNING opportunity for swap()") + +@script:python depends on org@ +p << rvar.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING opportunity for swap()") diff --git a/scripts/coccinelle/misc/uninitialized_var.cocci b/scripts/coccinelle/misc/uninitialized_var.cocci index 8fa845cefe11..69bbaae47e73 100644 --- a/scripts/coccinelle/misc/uninitialized_var.cocci +++ b/scripts/coccinelle/misc/uninitialized_var.cocci @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /// /// Please, don't reintroduce uninitialized_var(). -/// From Documentation/process/deprecated.rst: +/// +/// From Documentation/process/deprecated.rst, +/// commit 4b19bec97c88 ("docs: deprecated.rst: Add uninitialized_var()"): /// For any compiler warnings about uninitialized variables, just add /// an initializer. Using warning-silencing tricks is dangerous as it /// papers over real bugs (or can in the future), and suppresses unrelated @@ -11,6 +13,11 @@ /// obviously redundant, the compiler's dead-store elimination pass will make /// sure there are no needless variable writes. /// +/// Later, commit 3942ea7a10c9 ("deprecated.rst: Remove now removed +/// uninitialized_var") removed this section because all initializations of +/// this kind were cleaned-up from the kernel. This cocci rule checks that +/// the macro is not explicitly or implicitly reintroduced. +/// // Confidence: High // Copyright: (C) 2020 Denis Efremov ISPRAS // Options: --no-includes --include-headers @@ -40,12 +47,10 @@ position p; p << r.p; @@ -coccilib.report.print_report(p[0], - "WARNING this kind of initialization is deprecated (https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)") +coccilib.report.print_report(p[0], "WARNING this kind of initialization is deprecated") @script:python depends on org@ p << r.p; @@ -coccilib.org.print_todo(p[0], - "WARNING this kind of initialization is deprecated (https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)") +coccilib.org.print_todo(p[0], "WARNING this kind of initialization is deprecated") diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 90398347e366..5fbad61fe490 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -3,11 +3,10 @@ # (c) 2014, Sasha Levin <sasha.levin@oracle.com> #set -x -if [[ $# < 1 ]]; then +usage() { echo "Usage:" - echo " $0 -r <release> | <vmlinux> [base path] [modules path]" - exit 1 -fi + echo " $0 -r <release> | <vmlinux> [<base path>|auto] [<modules path>]" +} if [[ $1 == "-r" ]] ; then vmlinux="" @@ -24,6 +23,7 @@ if [[ $1 == "-r" ]] ; then if [[ $vmlinux == "" ]] ; then echo "ERROR! vmlinux image for release $release is not found" >&2 + usage exit 2 fi else @@ -31,12 +31,35 @@ else basepath=${2-auto} modpath=$3 release="" + debuginfod= + + # Can we use debuginfod-find? + if type debuginfod-find >/dev/null 2>&1 ; then + debuginfod=${1-only} + fi + + if [[ $vmlinux == "" && -z $debuginfod ]] ; then + echo "ERROR! vmlinux image must be specified" >&2 + usage + exit 1 + fi fi declare -A cache declare -A modcache find_module() { + if [[ -n $debuginfod ]] ; then + if [[ -n $modbuildid ]] ; then + debuginfod-find debuginfo $modbuildid && return + fi + + # Only using debuginfod so don't try to find vmlinux module path + if [[ $debuginfod == "only" ]] ; then + return + fi + fi + if [[ "$modpath" != "" ]] ; then for fn in $(find "$modpath" -name "${module//_/[-_]}.ko*") ; do if readelf -WS "$fn" | grep -qwF .debug_line ; then @@ -51,7 +74,7 @@ find_module() { find_module && return if [[ $release == "" ]] ; then - release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" | sed -n 's/\$1 = "\(.*\)".*/\1/p') + release=$(gdb -ex 'print init_uts_ns.name.release' -ex 'quit' -quiet -batch "$vmlinux" 2>/dev/null | sed -n 's/\$1 = "\(.*\)".*/\1/p') fi for dn in {/usr/lib/debug,}/lib/modules/$release ; do @@ -105,7 +128,7 @@ parse_symbol() { if [[ "${cache[$module,$name]+isset}" == "isset" ]]; then local base_addr=${cache[$module,$name]} else - local base_addr=$(nm "$objfile" | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}') + local base_addr=$(nm "$objfile" 2>/dev/null | awk '$3 == "'$name'" && ($2 == "t" || $2 == "T") {print $1; exit}') if [[ $base_addr == "" ]] ; then # address not found return @@ -129,7 +152,7 @@ parse_symbol() { if [[ "${cache[$module,$address]+isset}" == "isset" ]]; then local code=${cache[$module,$address]} else - local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address") + local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address" 2>/dev/null) cache[$module,$address]=$code fi @@ -150,6 +173,27 @@ parse_symbol() { symbol="$segment$name ($code)" } +debuginfod_get_vmlinux() { + local vmlinux_buildid=${1##* } + + if [[ $vmlinux != "" ]]; then + return + fi + + if [[ $vmlinux_buildid =~ ^[0-9a-f]+ ]]; then + vmlinux=$(debuginfod-find debuginfo $vmlinux_buildid) + if [[ $? -ne 0 ]] ; then + echo "ERROR! vmlinux image not found via debuginfod-find" >&2 + usage + exit 2 + fi + return + fi + echo "ERROR! Build ID for vmlinux not found. Try passing -r or specifying vmlinux" >&2 + usage + exit 2 +} + decode_code() { local scripts=`dirname "${BASH_SOURCE[0]}"` @@ -157,6 +201,14 @@ decode_code() { } handle_line() { + if [[ $basepath == "auto" && $vmlinux != "" ]] ; then + module="" + symbol="kernel_init+0x0/0x0" + parse_symbol + basepath=${symbol#kernel_init (} + basepath=${basepath%/init/main.c:*)} + fi + local words # Tokenize @@ -182,16 +234,28 @@ handle_line() { fi done + if [[ ${words[$last]} =~ ^[0-9a-f]+\] ]]; then + words[$last-1]="${words[$last-1]} ${words[$last]}" + unset words[$last] + last=$(( $last - 1 )) + fi + if [[ ${words[$last]} =~ \[([^]]+)\] ]]; then module=${words[$last]} module=${module#\[} module=${module%\]} + modbuildid=${module#* } + module=${module% *} + if [[ $modbuildid == $module ]]; then + modbuildid= + fi symbol=${words[$last-1]} unset words[$last-1] else # The symbol is the last element, process it symbol=${words[$last]} module= + modbuildid= fi unset words[$last] @@ -201,14 +265,6 @@ handle_line() { echo "${words[@]}" "$symbol $module" } -if [[ $basepath == "auto" ]] ; then - module="" - symbol="kernel_init+0x0/0x0" - parse_symbol - basepath=${symbol#kernel_init (} - basepath=${basepath%/init/main.c:*)} -fi - while read line; do # Let's see if we have an address in the line if [[ $line =~ \[\<([^]]+)\>\] ]] || @@ -218,6 +274,9 @@ while read line; do # Is it a code line? elif [[ $line == *Code:* ]]; then decode_code "$line" + # Is it a version line? + elif [[ -n $debuginfod && $line =~ PID:\ [0-9]+\ Comm: ]]; then + debuginfod_get_vmlinux "$line" else # Nothing special in this line, show it as is echo "$line" |