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