1#! /bin/sh 2# SPDX-License-Identifier: GPL-2.0 3# 4# (c) 2019, Google 5progname="${0##*/}" 6 7# Change to EXPORT_SYMBOL, EXPORT_SYMBOL_GPL or other namespace variant default 8EXPORT_SYMBOL=${EXPORT_SYMBOL_GPL:-${progname#add_}} 9 10USAGE="USAGE: ${progname} [--no-skip-arch] < kernel_build_error_log 11 ${progname} [--no-skip-arch] kernel_build_error_log 12 grep /<module>[.]ko build_error_log | ${progname} [--no-skip-arch] 13 ${EDITOR:-vi} \`${progname} [--no-skip-arch] < kernel_build_error_log\` 14 15To acquire the kernel_build_error_log eg: 16\$ ./build_sm8250.sh -j50 2>&1 | tee kernel_build_error_log 17 18To only create commit related to symbols needed for cam_spec.ko module: 19\$ grep /cam_spec[.]ko kernel_build_error_log | ${progname} 20 21The script will only affect the current directory level and downward, 22this allows one to segregate the adjusted content. Any symbols that 23are needed outside the range of that directory will result in errors 24and the git commit phase will not be performed. 25 26Add ${EXPORT_SYMBOL} for any noted missing symbols, output the list of files 27modified to stdout (so it can be passed to an editor command line should you 28need to check or adjust the results). Automatically commit the list of files 29into git. 30 31Deals as simply as it can to handle __trace_<symbols>, sorting the result. 32 33Keep in mind exports can change, be added or subtracted, and that preliminary 34work may expose or remove required symbols to resolve during later work. As 35such this script only adds, so you may need to revert the results and try 36again to get the most up to date set. By making this part automated it can 37deal with the tens or thousands of exports that need to be discovered or 38added. If you need to adjust a subsystem, run this script in the subsystem 39directory, and it will only adjust from that point downwards leaving other 40higher up trees alone." 41 42if [ X"--help" = X"${1}" -o X"{-h}" = X"${1}" ]; then 43 echo "${USAGE}" >&2 44 exit 45fi 46skip_arch=true 47if [ X"--no-skip-arch" = X"${1}" ]; then 48 skip_arch=false 49 shift 50fi 51INPUT= 52if [ 1 = ${#} ]; then 53 INPUT=${1} 54 shift 55fi 56if [ 0 != ${#} ]; then 57 echo "Unexpected Argument: ${*}" >&2 58 echo >&2 59 echo "${USAGE}" >&2 60 exit 1 61fi 62 63# A _real_ embedded tab character 64TAB="`echo | tr '\n' '\t'`" 65# A _real_ embedded escape character 66ESCAPE="`echo | tr '\n' '\033'`" 67# Colours 68RED="${ESCAPE}[38;5;196m" 69BLUE="${ESCAPE}[35m" 70NORMAL="${ESCAPE}[0m" 71 72# Common grep/sed regex expressions 73STRUCT_TYPE="struct[ ${TAB}][^ ${TAB}]\{1,\}" 74VAR_TYPE="\(${STRUCT_TYPE}\|bool\|char\|int\|long\|long long\|u\{0,1\}int[0-9]*t\)[ ${TAB}]\{1,\}[*]\{0,1\}" 75STRUCT_TYPE="${STRUCT_TYPE}[ ${TAB}]\{1,\}[*]\{0,1\}" 76 77# Files that exports should never exist, or need to be carefully considered 78skip_arch_files() { 79 if ${skip_arch}; then 80 grep -v '\(^\|^[^:]*/\)arch/[^a][^r][^m][^:]*:' 81 else 82 cat - 83 fi 84} 85 86# Following sucks in all the data from stdin or ${INPUT} 87# Check for depmod output (undefined!) or built-in kernel complaints (undefined 88# references). The later is not advised because it means the kernel may be 89# dependent on a module, we collect it to provide a signal for future work. 90echo "Reading symbols" >&2 91MODULES="` 92 sed -n \ 93 -e 's/^ERROR: "\([^"]*\)" [[]\(.*[.]ko\)[]] undefined!$/\1 \2/p' \ 94 -e 's/^[^:]*:[0-9]*: undefined reference to \`\([^'\'']*\)'\''$/\1/p' \ 95 ${INPUT} | 96 sort -u`" 97SYMBOLS="`echo \"${MODULES}\" | sed 's/ .*$//' | sort -u`" 98if [ -z "${SYMBOLS}" ]; then 99 echo "${BLUE}WARNING${NORMAL}: no symbols found" >&2 100 exit 101fi 102 103SYMBOLS_PLUS_TRACE="${SYMBOLS}" 104TRACE_MODULES="`echo \"${MODULES}\" | 105 sed -n 's/__tracepoint_.* //p' | 106 sort -u`" 107TRACE_MODULES_2= 108c=`echo "${TRACE_MODULES}" | wc -l` 109if [ 1 -eq ${c} ];then 110 TRACE_MODULES="${TRACE_MODULES%/*.ko}" 111 if [ -z "${INPUT}" ]; then 112 TRACE_MODULES_2=* 113 else 114 TRACE_MODULES_2=${INPUT} 115 fi 116elif [ -z "${INPUT}" ]; then 117 TRACE_MODULES=* 118else 119 TRACE_MODULES=${INPUT} 120fi 121TRACE_FILE="`grep -rl '^#define CREATE_TRACE_POINTS' ${TRACE_MODULES}`" 122if [ -z "${TRACE_FILE}" -a -n "${TRACE_MODULES_2}" ]; then 123 TRACE_FILE="`grep -rl '^#define CREATE_TRACE_POINTS' ${TRACE_MODULES_2}`" 124fi 125c=0 126if [ -n "${TRACE_FILE}" ]; then 127 c=`echo "${TRACE_FILE}" | wc -l` 128fi 129if [ 1 -eq ${c} ]; then 130 SYMBOLS_PLUS_TRACE="${SYMBOLS} 131`echo \"${SYMBOLS}\" | 132 sed -n 's/^__tracepoint_\(.*\)/EXPORT_TRACEPOINT_SYMBOL_GPL(\1);/p'`" 133else 134 TRACE_FILE= 135fi 136 137echo "Finding symbols in the current tree" >&2 138DATA="`grep -Fr \"${SYMBOLS_PLUS_TRACE}\" * | 139 grep \"^[^:]*[.][cS]:[^ ${TAB}]\" | 140 skip_arch_files`" 141echo "Editing the files that contain the symbols" >&2 142TMP=`mktemp -d` 143 144[ 'USAGE: report_strip_of_tag tag 145 146Report if a problematic function segment tag is stripped from the file 147 148expects ${F}, ${TMP}, ${TAB}, ${RED} and ${NORMAL} to be defined' ] 149report_strip_of_tag() { 150 if diff --side-by-side --suppress-common-lines ${F} ${TMP}/${F##*/} | 151 sed -n "s/\(.*[ ${TAB}]\)\(__${1}\)\([^a-zA-Z0-9_].*[^ ${TAB}]\)[ ${TAB}]\{1,\}|[ ${TAB}]\{1,\}/\1${BLUE}\2${NORMAL}\3 -> /p" | 152 grep __${1} >&2; then 153 echo "${RED}ERROR${NORMAL}: scrubbing __${1} from function in ${F}" >&2 154 echo " Compile check, possibly edit ${F} and friends." >&2 155 echo " Then re-run ${progname} to complete." >&2 156 echo FAILED 157 fi 158} 159 160for s in ${SYMBOLS}; do 161 # Already there? 162 if echo "${DATA}" | 163 grep "EXPORT_\(TRACEPOINT_SYMBOL_GPL*(${s#__tracepoint_}\|SYMBOL\(_GPL\)*(${s}\))" >/dev/null; then 164 echo INFO: ${s} found and already exported >&2 165 continue 166 fi 167 m="`echo \"${DATA}\" | grep \"^[^:]*:\([^ ${TAB}].*[ *]\|\)${s}(\"`" 168 c=0 169 if [ -n "${m}" ]; then 170 c=`echo "${m}" | wc -l` 171 fi 172 if [ 0 -eq ${c} ]; then 173 m="`echo \"${DATA}\" | grep \"^[^:]*:\(const[ ${TAB}]\{1,\}\|\)${STRUCT_TYPE}${s}\([[][]]\|\) = {\"`" 174 c=0 175 if [ -n "${m}" ]; then 176 c=`echo "${m}" | wc -l` 177 fi 178 if [ 0 -eq ${c} ]; then 179 m="`echo \"${DATA}\" | grep \"^[^:]*:\(const[ ${TAB}]\{1,\}\|\)${VAR_TYPE}${s}[\[ ${TAB};=]\"`" 180 c=0 181 if [ -n "${m}" ]; then 182 c=`echo "${m}" | wc -l` 183 fi 184 if [ 0 -eq ${c} ]; then 185 if [ -z "${TRACE_FILE}" -o "${s}" = "${s#__tracepoint_}" ]; then 186 echo "${RED}ERROR${NORMAL}: ${s} not found" >&2 187 if [ "${s}" != "${s#__tracepoint_}" -o "${s}" = "${s#__}" ]; then 188 echo FAILED 189 else 190 echo "${RED}WARNING${NORMAL}: ${s} might be a linker variable? skipping marking as failure" >&2 191 fi 192 else 193 echo ${TRACE_FILE} ${s} 194 fi 195 elif [ 1 -eq ${c} ]; then 196 echo "${DATA}" | 197 sed -n "s/^\([^:]*\):\(const[ $TAB]\{1,\}\|\)${VAR_TYPE}${s}.*/\1 ${s}/p" 198 else 199 echo "${RED}ERROR${NORMAL}: ${c} matches: `echo \"${m}\" | 200 tr '\n' '&' | 201 sed -e 's/&$//' \ 202 -e 's/&/ & /g'`" >&2 203 echo FAILED 204 fi 205 elif [ 1 -eq ${c} ]; then 206 echo "${DATA}" | 207 sed -n "s/^\([^:]*\):\(const[ $TAB]\{1,\}\|\)${STRUCT_TYPE}\(${s}\)\([[][]]\|\) = {.*/\1 \3/p" 208 else 209 echo "${RED}ERROR${NORMAL}: ${c} matches: `echo \"${m}\" | 210 tr '\n' '&' | 211 sed -e 's/&$//' \ 212 -e 's/&/ & /g'`" >&2 213 echo FAILED 214 fi 215 elif [ 1 -eq ${c} ]; then 216 echo "${DATA}" | 217 sed -n "s/^\([^:]*\):\([^ ${TAB}].*[ *]\|\)\(${s}\)(.*/\1 \3/p" 218 else 219 echo "${RED}ERROR${NORMAL}: ${c} matches: `echo \"${m}\" | 220 tr '\n' '&' | 221 sed -e 's/&$//' \ 222 -e 's/&/ & /g'`" >&2 223 echo FAILED 224 fi 225done | 226 sort -u | 227 while read F s; do 228 if [ "FAILED" = "${F}" ]; then 229 echo FAILED 230 continue 231 fi 232 if [ "${s}" != "${s#__tracepoint_}" ]; then 233 sed "\$ { 234 /^[^E]/ { 235 a \ 236 237 } 238 a \ 239 newEXPORT_TRACEPOINT_SYMBOL_GPL(${s#__tracepoint_}); 240 }" ${F} 241 else 242 cat ${F} 243 fi | 244 sed "/^\([^ ${TAB}].*[ *]\|\)${s}(/ { 245 : loop1 246 N 247 /\(\n}\);*$/ { 248 s//\1/ 249 s/^\([^\n]*[^\n ${TAB}]\|\)[ ${TAB}]\{1,\}__\(init\|exit\)[ ${TAB}]\{1,\}\([^\n]*(\)/\1 \3/ 250 s/^\([^\n]*[^\n ${TAB}]\|\)[ ${TAB}]\{1,\}__\(init\|exit\)\([^ ${TAB}a-zA-Z0-9_][^\n]*(\)/\1 \3/ 251 s/^__\(init\|exit\)[ ${TAB}]\{1,\}\([^\n]*(\)/\2/ 252 s/^__\(init\|exit\)\([^ ${TAB}a-zA-Z0-9_][^\n]*(\)/\2/ 253 a \ 254 new${EXPORT_SYMBOL}(${s}); 255 b next1 256 } 257 b loop1 258 : next1 259 } 260 /^\(const[ ${TAB}]\{1,\}\|\)${STRUCT_TYPE}${s}\([[][]]\|\)[ ${TAB}]*=[ ${TAB}]*{/ { 261 : loop2 262 N 263 /\n};$/ { 264 a \ 265 new${EXPORT_SYMBOL}(${s}); 266 b next2 267 } 268 b loop2 269 : next2 270 } 271 /^\(const[ ${TAB}]\{1,\}\|\)${VAR_TYPE}${s}\(\([[][]]\|\)[ ${TAB}]*=.*\|\);/ { 272 a \ 273 new${EXPORT_SYMBOL}(${s}); 274 } 275 /^\(const[ ${TAB}]\{1,\}\|\)${VAR_TYPE}${s}\([[][]]\|\)[ ${TAB}]*=[ ${TAB}]*{\{0,1\}\$/ { 276 : loop3 277 N 278 /;$/ { 279 a \ 280 new${EXPORT_SYMBOL}(${s}); 281 b next3 282 } 283 b loop3 284 : next3 285 }" | 286 sed '/^newEXPORT/ { 287 s//EXPORT/ 288 N 289 : loop 290 N 291 s/\(\n\)\n$/\1/ 292 t loop 293 }' >${TMP}/${F##*/} && 294 ! cmp -s ${F} ${TMP}/${F##*/} && 295 [ -s ${TMP}/${F##*/} ] && 296 report_strip_of_tag init && 297 report_strip_of_tag exit && 298 cp ${TMP}/${F##*/} ${F} && 299 echo INFO: export ${s} in ${F} >&2 || 300 ( 301 echo "${RED}ERROR${NORMAL}: export ${s} in ${F}" >&2 302 echo FAILED 303 ) 304 echo ${F} 305 rm ${TMP}/${F##*/} 306 done >${TMP}/${progname}.out 307FILES="`grep -v '^FAILED$' ${TMP}/${progname}.out | sort -u`" 308echo "${FILES}" 309grep '^FAILED$' ${TMP}/${progname}.out >/dev/null 310ret=${?} 311rm -rf ${TMP} 312if [ 0 -ne ${ret} ]; then 313 echo "DONE" >&2 314 GIT_FILES="`git diff | 315 sed -n 's@^diff --git a/\(.*\) b/\1$@\1@p' | 316 sort -u`" 317 if [ -z "${GIT_FILES}" ]; then 318 echo "${BLUE}WARNING${NORMAL}: no changes to commit" >&2 319 if [ -n "${FILES}" ]; then 320 echo " but we altered files!" >&2 321 fi 322 exit 323 fi 324 SEMI="" 325 if [ X"${GIT_FILES}" != X"`echo ${FILES} | tr ' ' '\n' | sort -u`" ]; then 326 SEMI="Semi-" 327 FILES=`echo ${FILES} ${GIT_FILES} | 328 tr ' ' '\n' | 329 sort -u` 330 echo "${BLUE}WARNING${NORMAL}: list of files in git different from files we expected to edit, continuation?" >&2 331 fi 332 333 AUTHOR_NAME="`git config user.name`" 334 AUTHOR_EMAIL="`git config user.email`" 335 if [ -z "${AUTHOR_EMAIL}" ]; then 336 AUTHOR_EMAIL="`${USER}@google.com`" 337 fi 338 if [ -z "${AUTHOR_NAME}" ]; then 339 convert_ldap_to_name() { 340 echo "${1##*/}" | 341 sed "s@[-_]@ @g 342 s@ *@ @g" | 343 sed 's@\(^\| \)a@\1A@g 344 s@\(^\| \)b@\1B@g 345 s@\(^\| \)c@\1C@g 346 s@\(^\| \)d@\1D@g 347 s@\(^\| \)e@\1E@g 348 s@\(^\| \)f@\1F@g 349 s@\(^\| \)g@\1G@g 350 s@\(^\| \)h@\1H@g 351 s@\(^\| \)i@\1I@g 352 s@\(^\| \)j@\1J@g 353 s@\(^\| \)k@\1K@g 354 s@\(^\| \)l@\1L@g 355 s@\(^\| \)m@\1M@g 356 s@\(^\| \)n@\1N@g 357 s@\(^\| \)o@\1O@g 358 s@\(^\| \)p@\1P@g 359 s@\(^\| \)q@\1Q@g 360 s@\(^\| \)r@\1R@g 361 s@\(^\| \)s@\1S@g 362 s@\(^\| \)t@\1T@g 363 s@\(^\| \)u@\1U@g 364 s@\(^\| \|Mc\)v@\1V@g 365 s@\(^\| \)w@\1W@g 366 s@\(^\| \)x@\1X@g 367 s@\(^\| \)y@\1Y@g 368 s@\(^\| \)z@\1Z@g' 369 } 370 AUTHOR_NAME="`convert_ldap_to_name ${USER}`" 371 fi 372 373 git commit ${FILES} -m "GKI: add missing exports for <config>=m for <compatible> 374 375<edit> 376 377${SEMI}Automatically generated by ${0##*/} 378 379The following symbols are exported: 380`echo \"${SYMBOLS}\" | 381 sed 's/^/ - /'` 382 383Signed-off-by: ${AUTHOR_NAME} <${AUTHOR_EMAIL}> 384Test: compile" || 385 echo "${RED}ERROR${NORMAL}: failed to commit changes to git" >&2 386 exit 387fi 388echo "${RED}FAILED${NORMAL}: could not complete task" >&2 389exit 1 390