acmecert: Rationalized invocation.
[utils.git] / lddot
1 #!/bin/bash
2
3 IFS=: ldpath=($LD_LIBRARY_PATH)
4 while read dir; do
5     if [ "${dir:0:1}" == "#" ]; then
6         continue
7     elif [ -d "$dir" ]; then
8         ldpath=("${ldpath[@]}" "$dir")
9     fi
10 done </etc/ld.so.conf
11 ldpath=("${ldpath[@]}" /usr/lib /lib)
12 IFS=: apath=($PATH)
13
14 findlib() {
15     for d in "${ldpath[@]}"; do
16         if [ -r "$d/$1" ]; then
17             echo "$d/$1"
18             return 0
19         fi
20     done
21     return 1
22 }
23
24 findbin() {
25     for d in "${apath[@]}"; do
26         if [ -r "$d/$1" ]; then
27             echo "$d/$1"
28             return 0
29         fi
30     done
31     return 1
32 }
33
34 has() {
35     for obj in "${found[@]}"; do
36         if [ "$obj" = "$1" ]; then return 0; fi
37     done
38     return 1
39 }
40
41 excluded() {
42     for obj in "${exclude[@]}"; do
43         if [ -d "$obj" ] && [[ "$1" == "$obj"* ]]; then return 0; fi
44         if [ "$1" -ef "$obj" ]; then return 0; fi
45     done
46     return 1
47 }
48
49 examine() {
50     local tfile lib lib2
51     tfile="$(mktemp /tmp/lddotXXXXXX)"
52     objdump -p "$1" | sed -n 's/^.*NEEDED \+\(lib.*\)/\1/p' >"$tfile"
53     while read lib; do
54         if ! lib2="$(findlib "$lib")"; then
55             echo "\"$lib\" [ color=red ];"
56             echo "lddot: $lib: not found" >&2
57             echo "\"$1\" -> \"$lib\";"
58             continue
59         fi
60         lib="$lib2"
61         unset lib2
62         if excluded "$lib"; then continue; fi
63         echo "\"$1\" -> \"$lib\";"
64         if has "$lib"; then continue; fi
65         found=("${found[@]}" "$lib")
66         examine "$lib"
67     done <"$tfile"
68     rm -f "$tfile"
69     return 0
70 }
71
72 found=()
73 exclude=()
74 programs=()
75
76 while [ $# -gt 0 ]; do
77     arg="$1"
78     shift
79     case "$arg" in
80         -x)
81             exclude=("${exclude[@]}" "$1")
82             shift
83             ;;
84         *)
85             programs=("${programs[@]}" "$arg")
86     esac
87 done
88
89 if [ ${#programs[@]} -lt 1 ]; then
90     echo "usage: lddot [-x EXCLUDED] PROGRAM..." >&2
91     exit 1
92 fi
93
94 echo "digraph {"
95 rv=0
96 for bin in "${programs[@]}"; do
97     if [[ "$bin" != */* ]]; then
98         if ! bin2="$(findbin "$bin")"; then
99             echo "lddot: $bin: not found" >&2
100             rv=1
101             continue
102         fi
103         bin="$bin2"
104         unset bin2
105     fi
106     if [ ! -r "$bin" ]; then
107         echo "lddot: $bin: not readable" >&2
108         rv=1
109         continue
110     fi
111     echo "\"$bin\" [ shape=box ];"
112     if ! examine "$bin"; then rv=1; fi
113 done
114 echo "}"
115
116 exit $rv