#! /bin/sh # SPDX-License-Identifier: Apache-2.0 # # (c) 2019, Google progname="${0##*/}" # Add instrumentation to module_init and probe functions. USAGE="USAGE: ${progname} [dir|file] Add debug instrumentation to module_init and probe functions." if [ X"--help" = X"${1}" -o X"{-h}" = X"${1}" ]; then echo "${USAGE}" >&2 exit fi DIR=. if [ 1 = ${#} ]; then DIR=${1} shift fi if [ 0 != ${#} ]; then echo "Unexpected Argument: ${*}" >&2 echo >&2 echo "${USAGE}" >&2 exit 1 fi # A _real_ embedded tab character TAB="`echo | tr '\n' '\t'`" # A _real_ embedded escape character ESCAPE="`echo | tr '\n' '\033'`" # Colours RED="${ESCAPE}[38;5;196m" ORANGE="${ESCAPE}[38;5;255:165:0m" BLUE="${ESCAPE}[35m" NORMAL="${ESCAPE}[0m" TMP=`mktemp -d` # ${file} ${call} and ${symbol} input SYMBOLS=" " add_debug_printk() { message="printk(KERN_WARNING \"${file##*/}:" if [ -z "${call#select}" ]; then # We need uniqueness for discovery, so instead of truth of __func__ to # cover any of our mistakes(!), we select the expectation. message+="${symbol}: ENTER\\\\n\");" else message+="%s:${call}: ENTER\\\\n\", __func__);" fi if grep "${TAB}${message%%\\*}" ${file} >/dev/null; then if [ "${SYMBOLS}" == "${SYMBOLS#* ${symbol}:${call#select}}" ]; then echo INFO: already ${file} instrumented ${call#select} ${symbol} >&2 SYMBOLS="${SYMBOLS}${symbol}:${call} " fi return fi if [ "device_initcall" = "${call}" -o "module_init" = "${call}" -o "module_exit" = "${call}" ] && grep "${TAB}printk(KERN_WARNING \"${file##*/}:%s:\(builtin\|module\)_[a-z]*_driver: ENTER" ${file} >/dev/null; then if [ "${SYMBOLS}" == "${SYMBOLS#* ${symbol}:${call#select}}" ]; then echo INFO: maybe already ${file} instrumented ${call#select} ${symbol} >&2 fi return fi sed "/^\(static \)\{0,1\}.* ${symbol}(/ { N s/^\(static \)\{0,1\}\(.* ${symbol}(\)\(void\)\{0,1\}) {[ ${TAB}]*}\(\n\)/\1\2\3)\4{\4${TAB}${message}\4}\4/ t exit N /\/[*][^*]*\$/ { : comment_loop N /\/[*].*[*]\// b comment_done b comment_loop : comment_done /\/[*].*[*]\/\$/ N } /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(\n${TAB}\)\(kfree(\|DBG(\|return[ ${TAB}]\|if (\|platform_driver_\|class_destroy(\|pr_info(\|[a-z_0-9]*_register\(_drivers\|_simple\)\{0,1\}(\|[a-z_0-9]*_\(un\|de\)register\(_drivers\|_simple\)\{0,1\}(\|[a-z+_0-9]*_driver(\)/\1${message}&/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(\n${TAB}\)\(DBG(\|return[ ${TAB}]\|if (\|platform_driver_\|pr_info(\|[a-z_0-9]*_register\(_drivers\|_simple\)\{0,1\}(\|[a-z_0-9]*_\(un\|de\)register\(_drivers\|_simple\)\{0,1\}(\)/\1${message}&/ t exit s/\(static void .*\)\(\n${TAB}\)\([a-z].*\)\2}\$/\1\2${message}\2\3\2}/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ t exit N /printk(KERN_WARNING \"${file##*/}:/ b exit s/\(.*\)\(\n${TAB}\)\(.*\n\)\2/&${message}\2/ : exit } s/^builtin_\([a-z]*\)_driver(\(${symbol}\));\$/static int __init \2_init(void)\n{\n${TAB}${message}\n${TAB}return \1_driver_register(\&\2);\n}\ndevice_initcall(\2_init);/ s/^module_\([a-z]*\)_driver(\(${symbol}\));\$/static int __init \2_init(void)\n{\n${TAB}${message}\n${TAB}return \1_driver_register(\&\2);\n}\nmodule_init(\2_init);\n\nstatic void __exit \2_exit(void)\n{\n${TAB}${message}\n${TAB}\1_driver_unregister(\&\2);\n}\nmodule_exit(\2_exit);/ " ${file} > ${TMP}/${file##*/} && ! cmp -s ${file} ${TMP}/${file##*/} && cp ${TMP}/${file##*/} ${file} && ( echo INFO: modified ${file} to instrument ${call#select} ${symbol} >&2 echo ${symbol} ) || ( files=`grep -lr "^\(static \)\{0,1\}[^ ${TAB}][ %{TAB}_a-zA-Z0-9]* ${symbol}(" ${DIR} | sed -e '/[.]h$/d' -e 's@^[.]/@@'` if [ X"${file}" != X"${files}" ]; then echo "${ORANGE}WARNING${NORMAL}: ${symbol} is in ${files}" >&2 if [ 1 -eq `echo ${files} | wc -w` ]; then file=${files} add_debug_printk exit fi fi if [ "${SYMBOLS}" == "${SYMBOLS#* ${symbol}:${call#select}}" ]; then echo "${RED}ERROR${NORMAL}: failed to modify ${file} to instrument" ${call#select} ${symbol} >&2 fi false ) ret=${?} rm -f ${TMP}/${file##*/} if [ 0 -eq ${ret} ]; then SYMBOLS="${SYMBOLS}${symbol}:${call} " fi return ${ret} } # module_init, module_exit, late_initcall ... ( grep -Hr '^\(builtin_[a-z]*_driver\|module_[a-z]*_driver\|module_\(init\|exit\)\|[a-z]*_initcall\)(' ${DIR} | sed -n 's@^[.]/@@ s/^\([^:]*\):\(builtin_[a-z]*_driver\|module_[a-z]*_driver\|module_init\|module_exit\|[a-z]*_initcall\)(\([^)]*\));$/\1 \2 \3/p' | sort -u find ${DIR} -name '*.c' | while read file; do sed -n "/.* [a-z_0-9]*(void)\$/ { : loop N /^[^\n]* [a-z_0-9]*(void)\n.*\n}\$/ { /.*platform_\(driver\|device\)_\(un\)\{0,1\}register([&][^)]*).*/ { s@^[^\n]* \([a-z_0-9]*\)(void)\n.*@${file} select \1@p b exit } /.*[ ${TAB}]_[a-z]_\(un\)\{0,1\}register_driver([&][^, ${TAB})]*).*/ { s@^[^\n]* \([a-z_0-9]*\)(void)\n.*@${file} select \1@p b exit } /.*i2c_\(add\|del\)_driver([&][^)]*).*/ { s@^[^\n]* \([a-z_0-9]*\)(void)\n.*@${file} select \1@p } b exit } b loop } : exit" ${file} done | sort -u ) | while read file call symbol; do if ! add_debug_printk && [ "${SYMBOLS}" == "${SYMBOLS#* ${symbol}:${call#select}}" ]; then echo FAILED fi if [ "${call}" != "${call#builtin_*_driver}" -o "${call}" != "${call#module_*_driver}" ]; then symbol=${symbol}_init fi call=probe sed -n "/\(static \)\{0,1\}.* ${symbol}(/,/^}/ { s/.*platform_\(driver\|device\)_register([&]\([^)]*\)).*/struct platform_\1 \2/p s/.*[ ${TAB}]\(_[a-z]\)_register_driver([&]\([^, ${TAB})]*\)).*/struct \1_driver \2/p s/.*i2c_add_driver([&]\([^)]*\)).*/struct i2c_driver \1/p } s/\(builtin\|module\)_\([a-z]*_driver\)(\([^)]*\));/struct \2 \3/p" ${file} | sort -u | while read struct; do sed -n "/\(static \)\{0,1\}${struct} = {/,/^};/ { s/^[ ${TAB}]*[.]probe[ ${TAB}]*=[ ${TAB}]*\([^ ${TAB}]*\),\$/\1/p }" ${file} | sort -u | while read symbol; do if ! add_debug_printk && [ "${SYMBOLS}" == "${SYMBOLS#* ${symbol}:${call} }" ]; then echo FAILED fi done done done | sort -u | tee ${TMP}/list | grep '^FAILED' >/dev/null ret=${?} SYMBOLS=`grep -v '^FAILED$' ${TMP}/list` rm -rf ${TMP} if [ 0 -ne ${ret} ]; then echo "DONE" >&2 AUTHOR_NAME="`git config user.name`" AUTHOR_EMAIL="`git config user.email`" if [ -z "${AUTHOR_EMAIL}" ]; then AUTHOR_EMAIL="`${USER}@google.com`" fi if [ -z "${AUTHOR_NAME}" ]; then convert_ldap_to_name() { echo "${1##*/}" | sed "s@[-_]@ @g s@ *@ @g" | sed 's@\(^\| \)a@\1A@g s@\(^\| \)b@\1B@g s@\(^\| \)c@\1C@g s@\(^\| \)d@\1D@g s@\(^\| \)e@\1E@g s@\(^\| \)f@\1F@g s@\(^\| \)g@\1G@g s@\(^\| \)h@\1H@g s@\(^\| \)i@\1I@g s@\(^\| \)j@\1J@g s@\(^\| \)k@\1K@g s@\(^\| \)l@\1L@g s@\(^\| \)m@\1M@g s@\(^\| \)n@\1N@g s@\(^\| \)o@\1O@g s@\(^\| \)p@\1P@g s@\(^\| \)q@\1Q@g s@\(^\| \)r@\1R@g s@\(^\| \)s@\1S@g s@\(^\| \)t@\1T@g s@\(^\| \)u@\1U@g s@\(^\| \|Mc\)v@\1V@g s@\(^\| \)w@\1W@g s@\(^\| \)x@\1X@g s@\(^\| \)y@\1Y@g s@\(^\| \)z@\1Z@g' } AUTHOR_NAME="`convert_ldap_to_name ${USER}`" fi git commit -a -m "GKI: DEBUG: add instrumentation to init and probe functions Automatically generated by ${0} The following symbols are instrumented: `echo \"${SYMBOLS}\" | sed 's/^/ - /'` Signed-off-by: ${AUTHOR_NAME} <${AUTHOR_EMAIL}> Test: compile" || echo "${RED}ERROR${NORMAL}: failed to commit changes to git" >&2 exit fi echo "${RED}FAILED${NORMAL}: could not complete task" >&2 exit 1