blob: 47845d9adc913785f6672c6e20afa2f3c82807c7 [file] [log] [blame]
#! /bin/sh
# SPDX-License-Identifier: Apache-2.0
#
# (c) 2019, Google
progname="${0##*/}"
# Change to EXPORT_SYMBOL, EXPORT_SYMBOL_GPL or other namespace variant default
EXPORT_SYMBOL=${EXPORT_SYMBOL_GPL:-${progname#add_}}
USAGE="USAGE: ${progname} [--no-skip-arch] < kernel_build_error_log
${progname} [--no-skip-arch] kernel_build_error_log
grep /<module>[.]ko build_error_log | ${progname} [--no-skip-arch]
${EDITOR:-vi} \`${progname} [--no-skip-arch] < kernel_build_error_log\`
To acquire the kernel_build_error_log eg:
\$ ./build_sm8250.sh -j50 2>&1 | tee kernel_build_error_log
To only create commit related to symbols needed for cam_spec.ko module:
\$ grep /cam_spec[.]ko kernel_build_error_log | ${progname}
To only create commit related to a specific list of symbols, there is
the option to land just the symbols, no spaces, one per line, into a
manufactured or edited kernel_build_error_log and feed that to the script.
The script will only affect the current directory level and downward,
this allows one to segregate the adjusted content. Any symbols that
are needed outside the range of that directory will result in errors
and the git commit phase will not be performed.
Add ${EXPORT_SYMBOL} for any noted missing symbols, output the list of files
modified to stdout (so it can be passed to an editor command line should you
need to check or adjust the results). Automatically commit the list of files
into git.
Deals as simply as it can to handle __trace_<symbols>, sorting the result.
Keep in mind exports can change, be added or subtracted, and that preliminary
work may expose or remove required symbols to resolve during later work. As
such this script only adds, so you may need to revert the results and try
again to get the most up to date set. By making this part automated it can
deal with the tens or thousands of exports that need to be discovered or
added. If you need to adjust a subsystem, run this script in the subsystem
directory, and it will only adjust from that point downwards leaving other
higher up trees alone."
if [ X"--help" = X"${1}" -o X"{-h}" = X"${1}" ]; then
echo "${USAGE}" >&2
exit
fi
skip_arch=true
if [ X"--no-skip-arch" = X"${1}" ]; then
skip_arch=false
shift
fi
INPUT=
if [ 1 = ${#} ]; then
INPUT=${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'`"
# A _real_ embedded carriage return character
CR="`echo | tr '\n' '\r'`"
# Colours
RED="${ESCAPE}[38;5;196m"
BLUE="${ESCAPE}[35m"
NORMAL="${ESCAPE}[0m"
# Common grep/sed regex expressions
STRUCT_TYPE="struct[ ${TAB}][^ ${TAB}]\{1,\}"
VAR_TYPE="\(${STRUCT_TYPE}\|bool\|char\|int\|long\|long long\|u\{0,1\}int[0-9]*t\)[ ${TAB}]\{1,\}[*]\{0,1\}"
STRUCT_TYPE="${STRUCT_TYPE}[ ${TAB}]\{1,\}[*]\{0,1\}"
# Files that exports should never exist, or need to be carefully considered
skip_arch_files() {
if ${skip_arch}; then
grep -v '\(^\|^[^:]*/\)arch/[^a][^r][^m][^:]*:'
else
cat -
fi
}
# Following sucks in all the data from stdin or ${INPUT}
# Check for depmod output (undefined!) or built-in kernel complaints (undefined
# references). The later is not advised because it means the kernel may be
# dependent on a module, we collect it to provide a signal for future work.
echo "Reading symbols" >&2
MODULES="`
cat ${INPUT:--} |
tr -d \"${CR}\" |
sed -n \
-e '/^abi_gki_.*_whitelist$/d' \
-e 's/^[_a-zA-Z][_a-zA-Z0-9]\{6,\}$/&/p' \
-e 's/^ERROR: "\([^"]*\)" [[]\(.*[.]ko\)[]] undefined!$/\1 \2/p' \
-e 's/^[^:]*:[0-9]*: undefined reference to \`\([^'\'']*\)'\''$/\1/p' |
sort -u`"
SYMBOLS="`echo \"${MODULES}\" | sed 's/ .*$//' | sort -u`"
if [ -z "${SYMBOLS}" ]; then
echo "${BLUE}WARNING${NORMAL}: no symbols found" >&2
exit
fi
SYMBOLS_PLUS_TRACE="${SYMBOLS}"
TRACE_MODULES="`echo \"${MODULES}\" |
sed -n 's/__tracepoint_.* //p' |
sort -u`"
TRACE_MODULES_2=
c=`echo "${TRACE_MODULES}" | wc -l`
if [ 1 -eq ${c} ];then
TRACE_MODULES="${TRACE_MODULES%/*.ko}"
if [ -z "${INPUT}" ]; then
TRACE_MODULES_2=*
else
TRACE_MODULES_2=${INPUT}
fi
elif [ -z "${INPUT}" ]; then
TRACE_MODULES=*
else
TRACE_MODULES=${INPUT}
fi
TRACE_FILE="`grep -rl '^#define CREATE_TRACE_POINTS' ${TRACE_MODULES}`"
if [ -z "${TRACE_FILE}" -a -n "${TRACE_MODULES_2}" ]; then
TRACE_FILE="`grep -rl '^#define CREATE_TRACE_POINTS' ${TRACE_MODULES_2}`"
fi
c=0
if [ -n "${TRACE_FILE}" ]; then
c=`echo "${TRACE_FILE}" | wc -l`
fi
if [ 1 -eq ${c} ]; then
SYMBOLS_PLUS_TRACE="${SYMBOLS}
`echo \"${SYMBOLS}\" |
sed -n 's/^__tracepoint_\(.*\)/EXPORT_TRACEPOINT_SYMBOL_GPL(\1);/p'`"
else
TRACE_FILE=
fi
echo "Finding symbols in the current tree" >&2
DATA="`grep -Fr \"${SYMBOLS_PLUS_TRACE}\" * |
grep \"^[^:]*[.][cS]:[^ ${TAB}]\" |
skip_arch_files`"
echo "Editing the files that contain the symbols" >&2
TMP=`mktemp -d`
[ 'USAGE: report_strip_of_tag tag
Report if a problematic function segment tag is stripped from the file
expects ${F}, ${TMP}, ${TAB}, ${RED} and ${NORMAL} to be defined' ]
report_strip_of_tag() {
if diff --side-by-side --suppress-common-lines ${F} ${TMP}/${F##*/} |
sed -n "s/\(.*[ ${TAB}]\)\(__${1}\)\([^a-zA-Z0-9_].*[^ ${TAB}]\)[ ${TAB}]\{1,\}|[ ${TAB}]\{1,\}/\1${BLUE}\2${NORMAL}\3 -> /p" |
grep __${1} >&2; then
echo "${RED}ERROR${NORMAL}: scrubbing __${1} from function in ${F}" >&2
echo " Compile check, possibly edit ${F} and friends." >&2
echo " Then re-run ${progname} to complete." >&2
echo FAILED
fi
}
for s in ${SYMBOLS}; do
# Already there?
if echo "${DATA}" |
grep "EXPORT_\(TRACEPOINT_SYMBOL_GPL*(${s#__tracepoint_}\|SYMBOL\(_GPL\)*(${s}\))" >/dev/null; then
echo INFO: ${s} found and already exported >&2
continue
fi
m="`echo \"${DATA}\" | grep \"^[^:]*:\([^ ${TAB}].*[ *]\|\)${s}(\"`"
c=0
if [ -n "${m}" ]; then
c=`echo "${m}" | wc -l`
fi
if [ 0 -eq ${c} ]; then
m="`echo \"${DATA}\" | grep \"^[^:]*:\(const[ ${TAB}]\{1,\}\|\)${STRUCT_TYPE}${s}\([[][]]\|\) = {\"`"
c=0
if [ -n "${m}" ]; then
c=`echo "${m}" | wc -l`
fi
if [ 0 -eq ${c} ]; then
m="`echo \"${DATA}\" | grep \"^[^:]*:\(const[ ${TAB}]\{1,\}\|\)${VAR_TYPE}${s}[\[ ${TAB};=]\"`"
c=0
if [ -n "${m}" ]; then
c=`echo "${m}" | wc -l`
fi
if [ 0 -eq ${c} ]; then
if [ -z "${TRACE_FILE}" -o "${s}" = "${s#__tracepoint_}" ]; then
echo "${RED}ERROR${NORMAL}: ${s} not found" >&2
if [ "${s}" != "${s#__tracepoint_}" -o "${s}" = "${s#__}" ]; then
echo FAILED
else
echo "${RED}WARNING${NORMAL}: ${s} might be a linker variable? skipping marking as failure" >&2
fi
else
echo ${TRACE_FILE} ${s}
fi
elif [ 1 -eq ${c} ]; then
echo "${DATA}" |
sed -n "s/^\([^:]*\):\(const[ $TAB]\{1,\}\|\)${VAR_TYPE}${s}.*/\1 ${s}/p"
else
echo "${RED}ERROR${NORMAL}: ${c} matches: `echo \"${m}\" |
tr '\n' '&' |
sed -e 's/&$//' \
-e 's/&/ & /g'`" >&2
echo FAILED
fi
elif [ 1 -eq ${c} ]; then
echo "${DATA}" |
sed -n "s/^\([^:]*\):\(const[ $TAB]\{1,\}\|\)${STRUCT_TYPE}\(${s}\)\([[][]]\|\) = {.*/\1 \3/p"
else
echo "${RED}ERROR${NORMAL}: ${c} matches: `echo \"${m}\" |
tr '\n' '&' |
sed -e 's/&$//' \
-e 's/&/ & /g'`" >&2
echo FAILED
fi
elif [ 1 -eq ${c} ]; then
echo "${DATA}" |
sed -n "s/^\([^:]*\):\([^ ${TAB}].*[ *]\|\)\(${s}\)(.*/\1 \3/p"
else
echo "${RED}ERROR${NORMAL}: ${c} matches: `echo \"${m}\" |
tr '\n' '&' |
sed -e 's/&$//' \
-e 's/&/ & /g'`" >&2
echo FAILED
fi
done |
sort -u |
while read F s; do
if [ "FAILED" = "${F}" ]; then
echo FAILED
continue
fi
if [ "${s}" != "${s#__tracepoint_}" ]; then
sed "\$ {
/^[^E]/ {
a \
}
a \
newEXPORT_TRACEPOINT_SYMBOL_GPL(${s#__tracepoint_});
}" ${F}
else
cat ${F}
fi |
sed "/^\([^ ${TAB}].*[ *]\|\)${s}(/ {
: loop1
N
/\(\n}\);*$/ {
s//\1/
s/^\([^\n]*[^\n ${TAB}]\|\)[ ${TAB}]\{1,\}__\(init\|exit\)[ ${TAB}]\{1,\}\([^\n]*(\)/\1 \3/
s/^\([^\n]*[^\n ${TAB}]\|\)[ ${TAB}]\{1,\}__\(init\|exit\)\([^ ${TAB}a-zA-Z0-9_][^\n]*(\)/\1 \3/
s/^__\(init\|exit\)[ ${TAB}]\{1,\}\([^\n]*(\)/\2/
s/^__\(init\|exit\)\([^ ${TAB}a-zA-Z0-9_][^\n]*(\)/\2/
a \
new${EXPORT_SYMBOL}(${s});
b next1
}
b loop1
: next1
}
/^\(const[ ${TAB}]\{1,\}\|\)${STRUCT_TYPE}${s}\([[][]]\|\)[ ${TAB}]*=[ ${TAB}]*{/ {
: loop2
N
/\n};$/ {
a \
new${EXPORT_SYMBOL}(${s});
b next2
}
b loop2
: next2
}
/^\(const[ ${TAB}]\{1,\}\|\)${VAR_TYPE}${s}\(\([[][]]\|\)[ ${TAB}]*=.*\|\);/ {
a \
new${EXPORT_SYMBOL}(${s});
}
/^\(const[ ${TAB}]\{1,\}\|\)${VAR_TYPE}${s}\([[][]]\|\)[ ${TAB}]*=[ ${TAB}]*{\{0,1\}\$/ {
: loop3
N
/;$/ {
a \
new${EXPORT_SYMBOL}(${s});
b next3
}
b loop3
: next3
}" |
sed '/^newEXPORT/ {
s//EXPORT/
N
: loop
N
s/\(\n\)\n$/\1/
t loop
}' >${TMP}/${F##*/} &&
! cmp -s ${F} ${TMP}/${F##*/} &&
[ -s ${TMP}/${F##*/} ] &&
report_strip_of_tag init &&
report_strip_of_tag exit &&
cp ${TMP}/${F##*/} ${F} &&
echo INFO: export ${s} in ${F} >&2 ||
(
echo "${RED}ERROR${NORMAL}: export ${s} in ${F}" >&2
echo FAILED
)
echo ${F}
rm ${TMP}/${F##*/}
done >${TMP}/${progname}.out
FILES="`grep -v '^FAILED$' ${TMP}/${progname}.out | sort -u`"
echo "${FILES}"
grep '^FAILED$' ${TMP}/${progname}.out >/dev/null
ret=${?}
rm -rf ${TMP}
if [ 0 -ne ${ret} ]; then
echo "DONE" >&2
GIT_FILES="`git diff |
sed -n 's@^diff --git a/\(.*\) b/\1$@\1@p' |
sort -u`"
if [ -z "${GIT_FILES}" ]; then
echo "${BLUE}WARNING${NORMAL}: no changes to commit" >&2
if [ -n "${FILES}" ]; then
echo " but we altered files!" >&2
fi
exit
fi
SEMI=""
if [ X"${GIT_FILES}" != X"`echo ${FILES} | tr ' ' '\n' | sort -u`" ]; then
SEMI="Semi-"
FILES=`echo ${FILES} ${GIT_FILES} |
tr ' ' '\n' |
sort -u`
echo "${BLUE}WARNING${NORMAL}: list of files in git different from files we expected to edit, continuation?" >&2
fi
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 ${FILES} -m "GKI: add missing exports for <config>=m for <compatible>
<edit>
${SEMI}Automatically generated by ${0##*/}
The following symbols are exported:
`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