| #! /bin/bash |
| # SPDX-License-Identifier: Apache-2.0 |
| # |
| # (c) 2019, Google |
| progname="${0##*/}" |
| |
| USAGE="USAGE: ${progname} [dir] |
| |
| Call this when depmod breaks down, or when one needs a list of the symbols |
| implicated in the circular dependency. |
| |
| Search current or dir directory for all kernel modules. Itemize what they |
| export, and what they import. Discover links and report who fulfills them. |
| Report any first order circular relationships and the symbols that got us |
| into the situation. |
| |
| Standard output is of the form: |
| |
| module1.ko(symbols) -> module2.ko(symbols) -> module1.ko |
| |
| Leaves an annotated modules.dep file in the specified directory. |
| |
| TBA: higher order circular dependencies" |
| |
| 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'`" |
| |
| # |
| # Start Work |
| # |
| |
| # Construct our version (symbols annoted as comments) of the modules.dep file. |
| |
| TMP=`mktemp -d` |
| |
| # Acquire a list of files that are modules |
| find ${DIR%/} -name '*.ko' >${TMP}/modules |
| |
| # Fill symbols with file type symbol |
| # type is > for requires symbol |
| # type is < for supplies symbol |
| # type is pre for requires module (in symbol field) |
| # type is post for supplies module (in file field) |
| |
| # Mine for symbols |
| xargs nm -o <${TMP}/modules | |
| sed "s@^${DIR%/}/@@" | |
| sed -n \ |
| -e 's/^\([^:]*\):.* U \(.*\)/\1 > \2/p' \ |
| -e 's/^\([^:]*\):.* [TD] \(.*\)/\1 < \2/p' >${TMP}/symbols |
| if [ ! -s ${TMP}/symbols ]; then |
| rm -rf ${TMP} |
| echo ERROR: failed to find any .ko module files in the specified directory ${DIR%/} |
| exit 1 |
| fi |
| |
| # Mine for softdep pre |
| while read file; do |
| strings ${file} | |
| sed -n 's/^softdep=pre: \(.*\)/\1/p' | |
| tr ' ' '\n' | |
| sed "s@.*@${file#${DIR%/}/} pre &@" |
| done < ${TMP}/modules | |
| sort -u >>${TMP}/symbols |
| |
| # Mine for softdep post |
| while read file; do |
| strings ${file} | |
| sed -n 's/^softdep=post: \(.*\)/\1/p' | |
| tr ' ' '\n' | |
| sed "s@.*@$& post {file#${DIR%/}/}@" |
| done < ${TMP}/modules | |
| sort -u >>${TMP}/symbols |
| |
| # Translate symbols to annotated modules.dep |
| ( |
| sed -n 's/ > / /p' ${TMP}/symbols | |
| while read file symbol ; do |
| sed -n "s@^\(.*\) < ${symbol}\$@${file}: \1 # ${symbol}@p" ${TMP}/symbols |
| done |
| sed -n 's/ pre / /p' ${TMP}/symbols | |
| while read file softdep ; do |
| grep "/${softdep}[.]ko\$" ${TMP}/modules | |
| sed "s@^${DIR%/}/@@" | |
| while read source; do |
| echo "${file}: ${source} # pre:${softdep}" |
| done |
| done |
| sed -n 's/ post / /p' ${TMP}/symbols | |
| while read softdep source ; do |
| grep "/${softdep}[.]ko\$" ${TMP}/modules | |
| sed "s@^${DIR%/}/@@" | |
| while read file; do |
| echo "${file}: ${source} # post:${softdep}" |
| done |
| done |
| ) | |
| sort -u >${DIR%/}/modules.dep |
| |
| # Cleanup (already!) |
| rm -rf ${TMP} |
| |
| # Evaluate first order dependencies from our annotated ${DIR}/modules.dep file. |
| |
| # squash adjacent lines with match for first symbols, merge second |
| merge_second_symbols() { |
| sed ': loop |
| N |
| s/^\(.*(.*) -> .*(\)\(.*\)\().*\)\n\1\(.*\)\3/\1\2,\4\3/ |
| t loop |
| h |
| s/\n.*//p |
| g |
| s/^[^\n]*\n// |
| t loop' |
| } |
| |
| # squash adjacent lines with match for second symbols, merge first |
| merge_first_symbols() { |
| sed ': loop |
| N |
| s/^\(.*(\)\(.*\)\() -> .*(.*).*\)\n\1\(.*\)\3/\1\2,\4\3/ |
| t loop |
| h |
| s/\n.*//p |
| g |
| s/^[^\n]*\n// |
| t loop' |
| } |
| |
| # squash adjacent lines with identical, but shifted one, circular dependencies |
| merge_duplicates() { |
| sed ': loop |
| N |
| s/^\(.*\)\((.*)\) -> \(.*\)\((.*)\) -> \1\n\3\4 -> \1\2 -> \3$/\1\2 -> \3\4 -> \1/ |
| t end |
| s/\n.*//p |
| g |
| s/^[^\n]*\n// |
| t loop |
| : end' |
| } |
| |
| # Report the first order circular dependencies |
| sed 's/://' ${DIR%/}/modules.dep | |
| while read file source comment symbol; do |
| sed -n "s@^${source}: ${file} # \(.*\)@${file}(${symbol}) -> ${source}(\1) -> ${file}@p" ${DIR%/}/modules.dep |
| done | |
| merge_second_symbols | |
| merge_first_symbols | |
| merge_duplicates | |
| sort -u |
| |
| # TBA: second order dependencies |