Home Home > GIT Browse
summaryrefslogtreecommitdiff
blob: 975e5acc29044cec73b8800f87c8e876e99561b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/bin/bash
# collect_ksyms
# 
# Arguments: Kernel version (for installed kernel) or kernel.rpm
# 
# Shell script that extracts lists of exported and used symbols
# from the 2.6 kernel and it's modules.
# The symbols and it's versions are categorized and sorted and displayed.
# 
# (c) Kurt Garloff <garloff@suse.de>, 2004-05-15
# License: GNU GPL.

unset LANG
export LC_ALL=POSIX

crcs=""
needed=""

# Arguments: list of symbols to match
filter()
{
	awk '
		BEGIN   { invert = 0
		  for (i=1; i<ARGC; i++) {
		    sym[ARGV[i]] = 1;
		  }
		  split("", ARGV)
		}
		($1 in sym) { print }
	' "$@"
}
# Arguments: list of symbols to match
filter_out()
{
	awk '
		BEGIN   { invert = 0
		  for (i=1; i<ARGC; i++) {
		    sym[ARGV[i]] = 1;
		  }
		  split("", ARGV)
		}
		!($1 in sym) { print }
	' "$@"
}

# Arguments: filename
# Fills the variables crcs and needed with the symbols it collects
# from the module named $1
collect_sym_file()
{
	test ! -r $1 && return
	#echo "Module $1"
	#name=$1; name=${name##*/}; name=${name%.ko}
	name=$1; name=${name##*modules/}; name=${name#*/}; name=${name%.ko}
	syms="$(nm $1)"
	crc=$(echo "$syms" | grep __crc_ | sed "s%^\(00000000\|\)\([0-9a-f]*\) . __crc_\(.*\)$%\3\t\2\t${name}%")
	#need=$(echo "$syms" | grep '^ *[uU]' | sed "s/^ *[uU] \(.*\)$/\1\t${name}/")
	need=$(echo "$syms" | grep '^ *[uU]' | sed "s%^ *[uU] \(.*\)$%\1%")
	if test ! -z "$crc"; then
		#crcs=$(echo -e "$crcs\n$crc")
		crcs="$crcs\n$crc"
	fi
	if test ! -z "$need"; then
		#needed=$(echo -e "$needed\n$need")
		needed="$needed\n$need"
	fi
}

# Arguments: kversion
# Collects the symbols from all modules in the module directory
# for kernel version $1
collect_sym_modules()
{
	dir=$PREFIX/lib/modules/$1
	if test ! -d $dir; then
		echo "$dir does not exist"
		exit 1
	fi
	modules=$(find $dir -name "*.ko")
	for name in $modules; do
		collect_sym_file $name
	done
	echo Modules scanned: $(echo "$modules" | wc -l)
}

# Arguments: kversion
# Collects the symbols from the kernel image (System.map) 
# for kernel version $1
collect_sym_image()
{
	if test -e $PREFIX/boot/vmlinux-$1; then
		collect_sym_file $PREFIX/boot/vmlinux-$1
	elif test -e $PREFIX/boot/System.map-$1; then
#		provided="$(cat $PREFIX/boot/System.map-$1 | grep __kstrtab_ | sed 's/^[0-9a-f]* . __kstrtab_//')"
		crcs="$(cat $PREFIX/boot/System.map-$1 | grep __crc_ | sed 's/^\(00000000\|\)\([0-9a-f]*\) . __crc_\(.*\)$/\3\t\2\tvmlinux/')"
	else
		echo "Cannot find kernel image symbols for $1 (prefix $PREFIX)"
		exit 1
	fi
}	

# main
if test -z "$1" -o "$1" = "-h"; then
	echo "Usage: collect_syms VERSION"
	echo "VERSION is the output of uname -r"
	exit 1
fi
# Determine whether we are in RPM mode and collect needed and 
# provided symbols
name=$1
name=${name%.rpm}
if test "$name" = $1; then
	collect_sym_image $1
	collect_sym_modules $1
else
	DIR=$PWD
	VERSION="${name##*kernel-}"
	# SAFE tmp dir creation!
	PREFIX=$(mktemp -d /tmp/kernel-$VERSION.XXXXXX)
	cd $PREFIX
	if test "${name#/}" = "${name}"; then
		unrpm $DIR/$1 >/dev/null 2>&1
	else
		unrpm $1 >/dev/null 2>&1
	fi
	#VERSION=${VERSION%.*}
	#VERSION=$(echo $VERSION | sed 's/^\([^-]*\)-\(.*\)$/\2-\1/')
	VERSION=`ls boot/System.map-*`
	VERSION=${VERSION#boot/System.map-}
	#echo $VERSION
	collect_sym_image $VERSION
	collect_sym_modules $VERSION
	cd $DIR
	rm -rf $PREFIX
fi

# Consolidate
needed=$(echo -e "$needed" | sort -k1 -u | sed '/^$/d')
crcs=$(echo -e "$crcs" | sort -u | sed '/^$/d')
echo Needed symbols: $(echo "$needed" | wc -l)
#echo "$needed"
echo Provided symbols with CRC: $(echo "$crcs" | wc -l)
#echo "$crcs"

# And filter ...
#needfilt=$(echo "$needed" | sed 's/	.*$//')
needfilt="$needed"
#echo "Filter: $needfilt"
#echo "$crcs" > crcs
#echo $needfilt > needfilt
used=$(echo "$crcs" | filter $needfilt)
echo Used symbols:"   "$(echo "$used" | wc -l)
echo "$used" | sed 's/\([^	]*\)	\([0-9a-f]*\)/0x\2	\1/'
unused=$(echo "$crcs" | filter_out $needfilt)
echo Unused symbols: $(echo "$unused" | wc -l)
echo "$unused" | sed 's/\([^	]*\)	\([0-9a-f]*\)/0x\2	\1/'
provfilt=$(echo "$crcs" | sed 's/	.*$//')
#echo "Filter: $provfilt"
unresolved=$(echo "$needed" | filter_out $provfilt)
echo Unresolved symbols: $(echo "$unresolved" | sed '/^$/d' | wc -l)
echo "$unresolved"