3 progname="${progname%.sh}"
6 echo "Host side filter pipeline tool to convert kernel /proc/lockdep_chains via"
7 echo "graphviz into dependency chart for visualization. Watch out for any up-arrows"
8 echo "as they signify a circular dependency."
10 echo "Usage: ${progname} [flags...] [regex...] < input-file > output-file"
13 echo " --format={png|ps|svg|fig|imap|cmapx} | -T<format>"
14 echo " Output format, default png"
16 echo " Leave intermediate files /tmp/${progname}.*"
17 echo " --verbose | -v"
18 echo " Do not strip address from lockname"
20 echo " Show only primary references for regex matches"
22 echo " Cluster the primary references for regex matches"
23 echo " --serial=<serial> | -s <serial>"
24 echo " Input from 'adb -s <serial> shell su 0 cat /proc/lockdep_chains'"
25 echo " --input=<filename> | -i <filename>"
26 echo " Input lockdeps from filename, otherwise from standard in"
27 echo " --output=<filename> | -o <filename>"
28 echo " Output formatted graph to filename, otherwise to standard out"
30 echo "Chart is best viewed in portrait. ps or pdf formats tend to pixelate. png tends"
31 echo "to hit a bug in cairo rendering at scale. Not having a set of regex matches for"
32 echo "locknames will probably give you what you deserve ..."
34 echo "Kernel Prerequisite to get /proc/lockdep_chains:"
35 echo " CONFIG_PROVE_LOCKING=y"
36 echo " CONFIG_LOCK_STAT=y"
37 echo " CONFIG_DEBUG_LOCKDEP=y"
40 rm -f /tmp/${progname}.*
42 # Indent rules and strip out address (may be overridden below)
45 s/"[[][0-9a-f]*[]] /"/g'
57 while [ ${#} -gt 0 ]; do
70 dot_format="-T${1#--format=}"
78 # indent, but do _not_ strip out addresses
84 --focus | -f | --primary) # reserving --primary
88 --secondary) # reserving --secondary
92 --cluster) # reserve -c for dot (configure plugins)
97 if [ "${input}" != "cat -" ]; then
99 echo "ERROR: --input or --serial can only be specified once" >&2
102 input="adb -s ${2} shell su 0 cat /proc/lockdep_chains"
107 input="adb -s ${1#--serial=} shell su 0 cat /proc/lockdep_chains"
111 if [ "${input}" != "cat -" ]; then
113 echo "ERROR: --input or --serial can only be specified once" >&2
121 if [ "${input}" != "cat -" ]; then
123 echo "ERROR: --input or --serial can only be specified once" >&2
126 input="cat ${1#--input=}"
130 if [ "${output}" != "cat -" ]; then
132 echo "ERROR: --output can only be specified once" >&2
135 output="cat - > ${2}" # run through eval
140 if [ "${output}" != "cat -" ]; then
142 echo "ERROR: --output can only be specified once" >&2
145 output="cat - > ${1#--output=}" # run through eval
154 # Everything else is a filter, which will also hide bad option flags,
155 # which is an as-designed price we pay to allow "->rwlock" for instance.
156 if [ X"${1}" = X"${1#* }" ]; then
157 if [ -z "${filter}" ]; then
160 filter="${filter}|${1}"
163 if [ -z "${filter}" ]; then
166 filter="${filter}| ${1}"
175 if [ -z "${filter}" ]; then
176 echo "WARNING: no regex specified will give you what you deserve!" >&2
178 if [ -n "${focus}" -a -z "${filter}" ]; then
179 echo "WARNING: --focus without regex, ignored" >&2
181 if [ -n "${cluster}" -a -z "${filter}" ]; then
182 echo "WARNING: --cluster without regex, ignored" >&2
184 if [ -n "${cluster}" -a -n "${focus}" -a -n "${filter}" ]; then
185 echo "WARNING: orthogonal options --cluster & --focus, ignoring --cluster" >&2
189 # convert to dot digraph series
191 sed '/^all lock chains:$/d
192 / [&]__lockdep_no_validate__$/d
194 s/irq_context: [1-9]/irq_context/
202 b loop' > /tmp/${progname}.formed
204 if [ ! -s /tmp/${progname}.formed ]; then
205 echo "ERROR: no input" >&2
206 if [ -z "${debug}" ]; then
207 rm -f /tmp/${progname}.*
212 if [ -n "${filter}" ]; then
213 grep "${filter}" /tmp/${progname}.formed |
217 sort -u > /tmp/${progname}.symbols
223 echo 'remincross="true";'
224 echo 'concentrate="true";'
227 if [ -s /tmp/${progname}.symbols ]; then
228 if [ -n "${cluster}" ]; then
229 echo 'subgraph cluster_symbols {'
231 grep "${filter}" /tmp/${progname}.symbols |
232 sed 's/.*/& [shape=box] ;/'
233 grep -v "${filter}" /tmp/${progname}.symbols |
234 sed 's/.*/& [shape=diamond] ;/'
238 grep "${filter}" /tmp/${progname}.symbols |
239 sed 's/.*/& [shape=box] ;/'
240 grep -v "${filter}" /tmp/${progname}.symbols |
241 sed 's/.*/& [shape=diamond] ;/'
248 if [ -s /tmp/${progname}.symbols ]; then
249 if [ -z "${focus}" ]; then
250 # Secondary relationships
251 fgrep -f /tmp/${progname}.symbols /tmp/${progname}.formed
253 # Focus only on primary relationships
254 grep "${filter}" /tmp/${progname}.formed
257 cat /tmp/${progname}.formed
259 # optimize int A -> B ; single references
260 sed 's/\("[^"]*"\) -> \("[^"]*"\) ->/\1 -> \2 ;|\2 ->/g' |
261 sed 's/\("[^"]*"\) -> \("[^"]*"\) ->/\1 -> \2 ;|\2 ->/g' |
266 if [ -s /tmp/${progname}.symbols ]; then
267 beautify < /tmp/${progname}.symbols |
268 sed 's/^ */ /' > /tmp/${progname}.short
269 tee /tmp/${progname}.split |
270 fgrep -f /tmp/${progname}.short |
271 sed 's/ ;$/ [color=red] ;/'
272 fgrep -v -f /tmp/${progname}.short /tmp/${progname}.split
273 rm -f /tmp/${progname}.short /tmp/${progname}.split
280 tee /tmp/${progname}.input |
281 if dot ${dot_format} && [ -z "${debug}" ]; then
282 rm -f /tmp/${progname}.*