File indexing completed on 2024-10-06 08:10:26
0001 #!/bin/bash 0002 0003 # Copyright 2013 Dominik Seichter <domseichter@googlemail.com> 0004 # 0005 # This program is free software; you can redistribute it and/or 0006 # modify it under the terms of the GNU General Public License as 0007 # published by the Free Software Foundation; either version 2 of 0008 # the License, or (at your option) any later version. 0009 # 0010 # This program is distributed in the hope that it will be useful, 0011 # but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 # GNU General Public License for more details. 0014 # 0015 # You should have received a copy of the GNU General Public License 0016 # along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 0018 # This is the maximum depth to which dependencies are resolved 0019 MAXDEPTH=14 0020 0021 TMPFILE= 0022 READELFTMPFILE= 0023 LDDTMPFILE= 0024 0025 cleanup() { 0026 for _v in TMPFILE READELFTMPFILE LDDTMPFILE; do 0027 [ -n "${!_v}" ] && rm -f -- "${!_v}" 0028 done 0029 } 0030 0031 trap cleanup EXIT 0032 0033 # analyze a given file on its 0034 # dependecies using ldd and write 0035 # the results to a given temporary file 0036 # 0037 # Usage: analyze [OUTPUTFILE] [INPUTFILE] 0038 analyze() 0039 { 0040 local OUT="$1" 0041 local IN="$2" 0042 local NAME=$(basename "$IN") 0043 0044 for i in $LIST 0045 do 0046 if [ X"$i" == X"$NAME" ]; 0047 then 0048 # This file was already parsed 0049 return 0050 fi 0051 done 0052 # Put the file in the list of all files 0053 LIST="$LIST $NAME" 0054 0055 DEPTH=$(($DEPTH + 1)) 0056 if [ $DEPTH -ge $MAXDEPTH ]; 0057 then 0058 echo "MAXDEPTH of $MAXDEPTH reached at file $IN." 0059 echo "Continuing with next file..." 0060 DEPTH=$(($DEPTH - 1)) 0061 return 0062 fi 0063 0064 echo "Parsing file: $IN" 0065 0066 $READELF "$IN" > "$READELFTMPFILE" 2>&1 0067 ELFRET=$? 0068 0069 if [ $ELFRET != 0 ]; 0070 then 0071 echo "ERROR: ELF reader returned error code $RET" 0072 echo "ERROR:" 0073 cat -v -- "$TMPFILE" 0074 echo "Aborting..." 0075 exit 1 0076 fi 0077 0078 DEPENDENCIES=$(cat "$READELFTMPFILE" | grep NEEDED | awk '{if (substr($NF,1,1) == "[") print substr($NF, 2, length($NF) - 2); else print $NF}') 0079 0080 for DEP in $DEPENDENCIES; 0081 do 0082 if [ -n "$DEP" ]; 0083 then 0084 0085 # XXX Change ldd to something more secure? 0086 ldd "$IN" > "$LDDTMPFILE" 2>&1 0087 LDDRET=$? 0088 0089 if [ $LDDRET != 0 ]; 0090 then 0091 echo "ERROR: ldd returned error code $RET" 0092 echo "ERROR:" 0093 cat -v -- "$TMPFILE" 0094 echo "Aborting..." 0095 exit 1 0096 fi 0097 0098 DEPPATH=$(grep -- "$DEP" "$LDDTMPFILE" | awk '{print $3}') 0099 if [ -n "$DEPPATH" ]; 0100 then 0101 echo " \"$NAME\" -> \"$DEP\";" >> $OUT 0102 analyze "$OUT" "$DEPPATH" 0103 fi 0104 fi 0105 done 0106 0107 DEPTH=$(($DEPTH - 1)) 0108 } 0109 0110 ######################################## 0111 # main # 0112 ######################################## 0113 0114 if [ $# != 2 ]; 0115 then 0116 echo "Usage:" 0117 echo " $0 [filename] [outputimage]" 0118 echo "" 0119 echo "This tools analyses a shared library or an executable" 0120 echo "and generates a dependency graph as an image." 0121 echo "" 0122 echo "GraphViz must be installed for this tool to work." 0123 echo "" 0124 exit 1 0125 fi 0126 0127 DEPTH=0 0128 INPUT="$1" 0129 OUTPUT="$2" 0130 TMPFILE="$(mktemp -t)" 0131 LDDTMPFILE="$(mktemp -t)" 0132 READELFTMPFILE="$(mktemp -t)" 0133 LIST="" 0134 0135 if [ ! -e "$INPUT" ]; 0136 then 0137 echo "ERROR: File not found: $INPUT" 0138 echo "Aborting..." 0139 exit 2 0140 fi 0141 0142 # Use either readelf or dump 0143 # Linux has readelf, Solaris has dump 0144 READELF=$(type readelf 2> /dev/null) 0145 if [ $? != 0 ]; then 0146 READELF=$(type dump 2> /dev/null) 0147 if [ $? != 0 ]; then 0148 echo Unable to find ELF reader 0149 exit 1 0150 fi 0151 READELF="dump -Lv" 0152 else 0153 READELF="readelf -d" 0154 fi 0155 0156 0157 0158 echo "Analyzing dependencies of: $INPUT" 0159 echo "Creating output as: $OUTPUT" 0160 echo "" 0161 0162 echo "digraph DependencyTree {" > "$TMPFILE" 0163 echo " \"$(basename $INPUT)\" [shape=box];" >> "$TMPFILE" 0164 analyze "$TMPFILE" "$INPUT" 0165 echo "}" >> "$TMPFILE" 0166 0167 #cat $TMPFILE # output generated dotfile for debugging purposses 0168 dot -Tpng "$TMPFILE" "-o$OUTPUT" 0169 0170 exit 0