#format wiki #language nl == Roel Kluin == Email: <> ... ---- CategoryHomepage '''''This is my old page, see [[roelkluin|updated personal page]] for more recent scripts and snippets.''''' all code is (c) Roel kluin, 2007 GNU GPL V.2. == Examples == These may require the script 'vars' below sourced, and should be called in a git tree. I simply paste them into my console (bash). Match Unlikely(x) ?= y {{{ git-grep -n "\(un\)\?likely$s([^()]*\(([^()]*)[^()]*\)*)$s.=" }}} These can be replaced with strchr: {{{ E="\([^\"\\\\]\|\\\\[\\\\tnr\?'\"0bafv]\|\\\\[0-7]\{1,3\}\|\\\\[a-f0-9]\{1,2\}\|\\\\[A-F0-9]\{1,2\}\)" git-grep -n "strstr$s($s$W$s,$s\"$E\"$s)" }}} Show module initializing functions, not using {{{__init}}} or similarly exit: {{{ git-grep -n "\(void\|int\)${s}[[:alnum:]_]*module_[ei][xn]it(void)" | grep -v "__[ie][xn]it" }}} Matches if(function) BUG(): {{{ q="${s}if$s(\($ccode$Q\)\?$L$s($ccode)$s$ccode$s)" git-grep -n -B1 "^\($q\)\?${s}BUG($s)$s;$cendl" | grep "$q$cendl" | grep -v "\(sizeof\|unlikely\|likely\)($ccode)" | less }}} A sed script to audit ioremap/iounmap balancing (can be adapted for others): {{{ git-grep -l '[^[:alnum:]]ioremap' | while read -r g; do echo "--------------------------[ $g ]--------------------------" sed -n "/[^[:alnum:]]ioremap.*(\(.*\))/,/^[}{]$/{ s/\(.*return.*\)/\1\t\t-------return/ tp s/\(.*goto.*\)/\1\t\t------goto/ tp s/\(.*iounmap.*\)/\1\t\t<----/ tp s/\(.*ioremap.*\)/\1\t\t---->/ Tp = :p p }" $g done | less }}} Make sure no-one is freeing skbs with kfree instead of kfree_skb: {{{ for f in $(git-grep -l "struct${s}sk_buff"); do sed -n "s/^.*struct${S}sk_buff${s}\*${s}\(${V}\)$Q.*$/\1/p" $f | sort | uniq | while read -r n; do sed -n "/struct${s}sk_buff${s}\*${s}${n}/,/^[{}].*$/{ /kfree(${s}${n}${s})/= }" $f | while read -r q; do echo -e "kfreeing sk_buff $n at line $q in $f\n$q"; sed -n "/struct${s}sk_buff${s}\*${s}${n}/,/^[{}].*$/p" $f; done done done 2>&1 | less }}} matches a comparison as the last argument of a function. This may be correct but it is sometimes a misplaced check (and should be placed after the parenthesis instead). Use getcalls and/or getfunc to determine whether a boolean as the last argument is correct: {{{ h="\(([^()]*)\)\+"; git-grep -n -A9 ",[^);,]*=" | sed -n "s/^\([^\.]*\.[chsS]-[0-9]*-\|\([^\.]*\.[chsS]:[0-9]*:\)$s\)\(.*\)$/\2\3/p" | tr "\n" "@" | grep -o "@[^@]*$W$s(\(\([^,()]*\|$h\)*,\)\+\([^,()]*\|$h\)*[^\"]=${s}[^\",()]*)${s}[)&|]" | tr "@\t" " " | tr -s " " | less }}} Find values used as a boolean instead of the more common bitwise usage: {{{ f1="\($W${s}[&|]\|[0-9]\+${s}[&|]\|)${s}[&|]\)" # adds 2 h="\(([^()]*\(([^()]*\(([^()]*)[^()]*\)*[^()]*)[^()]*\)*)\)\?" git-grep "\($f1$s$V$s$h$s\(&&\|||\|)\|?\)\|\(&&\|||\|(\)$s$V$s$h${s}[&|]$s\([0-9]*\($W\|[^0]\)[0-9]*\)\)" | sed -n "s/^.*\($f1$s\($V\)$s\(([^()]*)\)\?$s\(&&\|||\|)\)\|\(&&\|||\|(\)$s\($V\)$s\(([^()]*)\)\?${s}[&|]$s\([0-9]*\($W\|[^0]\)[0-9]*\)\).*$/\4\8/p" | while read -r n; do echo "$n"; done | sort | uniq -c | sort -rn | while read -r n a; do b=$(git-grep -n "\(\(\(if\|while\)$s(\|&&\|||\|\!\)$s$a$s\(&&\|||\|\|)?\|(\)\|\(&&\|||\|(\)$s$a$s\(&&\|||\|(\|?\)\)" | grep -v "Kconfig") [ -z "$b" ] && continue; c=`echo "$b" | wc -l` let d=$(($n/$c)) echo "----[ a=\"$a\" # used $n times as bitwise, $c times as boolean, div $d ]----" [ $c -gt 20 ] && continue; [ $d -lt 5 ] && continue; echo "$b" done | less }}} catch tests below 0 on unsigned {{{ # define what to search for left_operator="\([;,|^?:(]\|[\!+*/%&|~^-]=\|>>=\|<<=\|\[\|&&\|$an_$s&\)" right_operator="\([;,&|^?:)]\|[\!+*/%&|~^<>-]=\|>>=\|<<=\|>[^>]\|<[^<]\|\]\)" variable="$s\(\(++\|--\)$w\|$w\(++\|--\)\|$w\)$s" comparison="\(\(>=\|<\)${s}0\|\([><\!=]=\|[<>]\)$s-$s$D\)$s" query="$left_operator$variable$comparison$right_operator" arr="\(\[[^\]]*\]$s\)*" attr="__attribute__$s(([^;]*))" # for each unsigned typedefs for ut in "unsigned" "unsigned long" $( git-grep "^${s}typedef${S}unsigned$S\($V$S\)*\($V$s$arr\|$attr$S$V$s$arr\|$V$s$arr$S$attr\)$s;$cendl" | sed -n "s/^[^.]*\.[hc]:${s}typedef${S}unsigned$S\($V$S\)*\(\($V\)$s$arr\|$attr$S\($V\)$s$arr\|\($V\)$s$arr$S$attr\)$s;$cendl/\3\5\7/p" | sort | uniq); do # create the spatch cat > ../spatches/negative_unsigned.cocci << EOF @@ constant C; $ut i; @@ ( * i < 0 | * i < -C | * i > -C | * i <= -C | * i >= -C ) EOF # find for f in $(git-grep -l "\(^\|$Q\)$ut\($Q\|$\)" | grep "[^.]*\.[ch]" | xargs grep -l "$query"); do spatch -quiet -all_includes -I ./include -sp_file ../spatches/negative_unsigned $f; done done > ../spatch.log }}} to display the results of the previous patch as 'vi file +line' commands: {{{ sed -n "s/^\(.\)\(-- \([^[:space:]]*\)[[:space:]]\|@ -\([0-9]*\),\|\).*$/\1 \3\4/p" ../spatch.log| while read a b; do if [ "$a" = "-" ]; then if [ -f "$b" ]; then f="$b" elif [ -z "$b" ]; then echo "vi $f +$i"; i=$(($i+1)); fi elif [ "$a" = "@" ]; then i=$b; else i=$(($i+1)); fi done }}} == Scripts == I called it vars, it contains some functions for kernel hacking. usage: "source path/to/vars" N.B. do not source this in a shell that you plan to use to compile a kernel ($Q is used in Makefiles as well, which will give some problems) {{{ #!/bin/bash # (c) Roel kluin, 2008 GNU GPL V.2 alias gg="git-grep -n" # Usage: v /path/to/sourcefile.c[:- ]linenr or # (as pasted from git-grep -n) v() { f="$1" [ $# -eq 2 ] && l=$2 if [ ! -f "$f" ]; then l=${f##*[:-]}; f="${f%[:-]*}"; fi [ -f "$f" -a $l -gt 0 ] && vi "$f" +"$l"; } export int="[0-9]" export hex="[a-f0-9]" export hEx="[A-Fa-f0-9]" export HEX="[A-F0-9]" export upp="[A-Z]" export up_="[A-Z_]" export low="[a-z0-9]" export lo_="[a-z0-9_]" export alp="[A-Za-z]" export al_="[A-Za-z_]" export ALN="[A-Z0-9]" export AN_="[A-Z0-9_]" export aln="[A-Za-z0-9]" export an_="[A-Za-z0-9_]" # to match something like 1ul, floats or hexes as well: export D="$int*\.\?$int\+x\?$hex*[uUlL]\{0,3\}[fF]\?" # more strict and catches it (costs one backreference for (git-)grep) export d="\($int\+[uUlLfF]\?\|$int\+[uU]\?[lL][lL]\?\|0x$hex\+\|0x$HEX\+\|$i\+[lL][lL][uU]\|$i*\.$i\+[fF]\?\)" # capital: can be used to catch a definition or config option export K="$UP_\+$AN_*"; # can be used for a variable/function name: export V="$al_\+$an_*" # works the same as above, but also for members and arrays: one backreference # is more strict export W="$V\(\[$s$V$s\]\|\[$s$D$s\]\|\.$V\|->$V\)*" # catches it at once (less strict) export w="\($V\|${V}\[$s$an_*${s}\]\|$V\.\|$V->\)\+" # seperators: export s="[[:space:]]*"; export S="[[:space:]]\+" # useful to delimit a variable name: export Q="[^[:alnum:]_]" # match the end of the line, including comments: one backreference (but at eol) export cendl="$s\(\/[*\/].*\)\?$" # match something that is not comment, string or character: 2 backreferences export ccode="\([^\/\"']*\|\/[^*\/]\|\/\*\([^*]*\|\**[^*\/]\)*\*\+\/\|'[^']*'\|\"[^\"]*\"\)*" # resp function open and end (only works when indentation is correct. export fo="^[\{]$cendl" export fe="^[\}]$cendl" # to match nested parentheses export nps="[^()]*" export nstdps="\(($nps\(($nps\(($nps\(($nps\(($nps)$nps\)*)$nps\)*)$nps\)*)$nps\)*)$nps\)*" # works similar to git-grep -n "$query" | tr ":" " " # except that :'s in the line are preserved ggrep2fnl() { git-grep -n "$1" | while read -r fnl; do f="$(echo "$fnl"| cut -d":" -f1)"; e="$(echo "$f" | rev | cut --complement -c3- | rev)"; [ "$e" != ".h" -a "$e" != ".c" ] && continue; echo "$f $(echo "$fnl"| cut -d":" -f2) $(echo "$fnl"| cut -d":" -f3-)"; done } #print function declaration at file "$1", line "$2" # also works for /path/to/filename.c:nr getfuncat() { [ $# -ne 1 ] && return 1; f="${1%[:-]*}" [ ! -f "$f" ] && return 2; l="${1##*[:-]}" Z="[@[:space:]]" func="\($V$Z\+\)*${V}[*@[:space:]]\+$V$s($nps$nstdps)" eol="$Z*\($Z\|\/\/[^@]*@\|\/\*\([^*]*\|\**[^\/*]\)*\*\+\/\)*@{" head -n$l "$f" | tr "\n" "@" | sed -n "s/.*@\($func\)$eol.*/\1@/p" | tail -n1 | tr "@" "\n" } #print function declaration(s) getfunc() { q="^\(${V}[*&[:space:]]\+\)*$1$s(${ccode}[^;]$cendl"; ggrep2fnl "$q" | while read -r f n l; do [ -z "`echo $l | grep "{$cendl"`" -a \ -n "`sed -n "$n,/{$cendl/{/;/p}" "$f"`" ] && continue echo "//---[ vi $f +$n ]---" [ -n "`echo $l | grep "^$s$1"`" ] && let "n--" sed -n "$n,/$fe/p" "$f" done } getstruct() { q="^$s\($V$S\)*struct\(${S}__$V\($s($nps$nstdps)\)\?\)*$S$1\(${S}__$V\($s($nps$nstdps)\)\?\)*${s}[{]\?$cendl"; ggrep2fnl "$q" | while read -r f n l; do [ -z "`echo $l | grep "{$cendl"`" -a \ -n "`sed -n "$n,/{$cendl/{/;/p}" "$f"`" ] && continue echo "//---[ vi $f +$n ]---" [ -n "`echo $l | grep "^$s$1"`" ] && let "n--" sed -n "$n,/$se/p" "$f" done } getdef() { del="[[:space:](]" sed_print=":a; /\\\\\\\\$/{N;ba}; p}" while getopts dmho Options; do case $Options in h) echo "getdef [options] DEFINITION_NAME(s) print definition(s) / macro(s) options -d print only definitions -m print only macros -o print as a single line (squeezes spaces)" return ;; d) del="[[:space:]]" ;; m) del="(" ;; o) sed_print=":a; /\\\\\\\\$/{N;ba}; s/\(\/\(\/.*\|\*\([^*]*\|\**[^\/]\)*\*\/$s\)\?\(\\\\\\\\\n\|$\)\|$S\)\+/ /g; s/^$S//g; p}" ;; esac done while [ $OPTIND -gt 1 ]; do shift; OPTIND=$(($OPTIND-1)); done def="^$s#${s}define$S$1$del" for f in $(git-grep -l -I "$def"); do sed -n "/$def/,/[^\\\\]$/{/$def/=; $sed_print" "$f" | sed "/^[0-9]*$/s/^\([0-9]*\)$/\/\/---[ vi ${f//\//\\/} +\1 ]---/" done } # rparse [source.c]: prints contents with comments removed and extended lines joined. rparse() { sed " :a s:\($S$S\|$s\n$s\): : ta /^$ccode\?\/\*/{ /^$ccode\?\/\*\([^*]*\|\**[^\/*]\)*\**$/N s:^$ccode\?\/\*\([^*]*\|\**[^\/*]\)*\*\+\/$ccode\?:\1 \4: ba } /^$ccode\?\/\//s:^$ccode\?\/\/.*$:\1: s: $:: s:^ :: /\\\\$s$/{ N s:$s\\\\$s\n$s: : ba } /^\([^#].*[^;{}]\)\?$/{ N ba } " "$1" } # echoes "function name" at file "$1" line "$2" det_func() { q="^\(${V}[*&[:space:]]\+\)*\($V\)$s(${ccode}[^;]$cendl" head "$1" -n"$2" | tac | sed -n "/$q/{s/$q/\2/p;q}" } getcalls() { git-grep -n "\(^\|^$ccode$Q\)$1$s(\($ccode\()$s;\|[^)]\|)$ccode)$ccode\)\)\?$cendl" } # get filename in git-diff with match $1 (matches from start of line) # in after (default, $2 == "+") or before ($2 == "-") changes were made gdfwm() { dil="+"; [ $# -eq 2 ] && dil="$2"; echo "$dil" git-diff | grep "^\($dil\{3\}\|$dil$1$\)" | grep -B1 "^${dil}[^$dil]" | sed -n "s/^$dil\{3\} [^\/]*\/\([^\n]*\)$/\1/p"; } # get filename and line in git-diff with match $1 (matches from start to end of line) gdflwm() { git-diff | sed -n "s/^\(.\)\(++ [^\/]*\/\(.*\)\|@ -[0-9]*,[0-9]* +\([0-9]*\),.*\|\($1\)\|.*\)$/\1 \3\4\5/p" | while read a b; do if [ "$a" = "+" ]; then if [ -f "$b" ]; then f="$b" elif [ -n "$b" ]; then echo "$f $i"; i=$(($i+1)); fi elif [ "$a" = "@" ]; then i=$b; elif [ "$a" != "-" ]; then i=$(($i+1)) fi done } }}} To translate a module name (as listed in modprobe -l or modinfo -n ''module'') into a kernel .config option: {{{ #!/bin/bash mod="${1%.ko}"; dir="${1%/*}"; sed -e :a -e '/\\$/N; s/\\\n//; ta' "${dir#*/kernel/}/Makefile" | \ sed -n "s/^obj-\$(CONFIG_\([A-Z0-9_]*\))\W*+=\W*"${mod##*/}"\.o$/\1/p"; }}} Based on Linus' script to get the email address of a maintainer, I wrote this script to get the address of a list rather than a maintainers address for mailing. {{{ git log --since="1 year ago" "$@" | sed -n "s/^ .[-a-z]*by: \(.*\) <.*$/\1/p" | sort | uniq | sort -n -r | while read -r name; do sed -n "/^P:[ \t]*.*$name/,/^$/{ s/^L:[ \t]*\(.*\)$/\1/p }" ./MAINTAINERS done | sort | uniq -c | sort -n -r | while read -r nr list; do tot=`grep -c "^L:\W*.*$list.*" ./MAINTAINERS` echo "`expr $nr / \( $tot + 1 \)` $nr $tot $list" done | sort -r | cut -d " " -f2- | while read -r nr tot list; do echo -e "$nr/$tot Acks were commited by maintainers of list $list" done }}}