Fixed up lddot a bit.
[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" = "$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 "\"$1\" -> \"$lib\";"
57             continue
58         fi
59         lib="$lib2"
60         unset lib2
61         if excluded "$lib"; then continue; fi
62         echo "\"$1\" -> \"$lib\";"
63         if has "$lib"; then continue; fi
64         found=("${found[@]}" "$lib")
65         examine "$lib"
66     done <"$tfile"
67     rm -f "$tfile"
68     return 0
69 }
70
71 found=()
72 exclude=()
73 programs=()
74
75 while [ $# -gt 0 ]; do
76     arg="$1"
77     shift
78     case "$arg" in
79         -x)
80             exclude=("${exclude[@]}" "$1")
81             shift
82             ;;
83         *)
84             programs=("${programs[@]}" "$arg")
85     esac
86 done
87
88 if [ ${#programs[@]} -lt 1 ]; then
89     echo "usage: lddot [-x EXCLUDED] PROGRAM..." >&2
90     exit 1
91 fi
92
93 echo "digraph {"
94 rv=0
95 for bin in "${programs[@]}"; do
96     if [[ "$bin" != */* ]]; then
97         if ! bin2="$(findbin "$bin")"; then
98             echo "lddot: $bin: not found" >&2
99             rv=1
100             continue
101         fi
102         bin="$bin2"
103         unset bin2
104     fi
105     if [ ! -r "$bin" ]; then
106         echo "lddot: $bin: not readable" >&2
107         rv=1
108         continue
109     fi
110     if ! examine "$bin"; then rv=1; fi
111 done
112 echo "}"
113
114 exit $rv