blob: 9e9c4bf39451984e28c88510ca4d23285f221af3 [file] [log] [blame]
#! /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