| 1 |
#!/usr/bin/python
|
| 2 |
#
|
| 3 |
# kabitool - Red Hat kABI extraction tool
|
| 4 |
#
|
| 5 |
# We use this script to generate collections (groups) of kABI symbols and also
|
| 6 |
# optionally output kABI dependencies for use by the RPM.
|
| 7 |
#
|
| 8 |
# Author: Jon Masters <jcm@redhat.com>
|
| 9 |
# Copyright (C) 2006 Red Hat, Inc.
|
| 10 |
#
|
| 11 |
# This software may be freely redistributed under the terms of the GNU
|
| 12 |
# General Public License (GPL).
|
| 13 |
|
| 14 |
__author__ = "Jon Masters <jcm@redhat.com>"
|
| 15 |
__version__ = "$Revisions: 1.2 $"
|
| 16 |
__date__ = "$Date: 2006/07/25 14:34:58 $"
|
| 17 |
__copyright__ = "Copyright (C) 2006 Red Hat, Inc"
|
| 18 |
__license__ = "GPL"
|
| 19 |
|
| 20 |
import getopt
|
| 21 |
import os
|
| 22 |
import re
|
| 23 |
import sha
|
| 24 |
import string
|
| 25 |
import sys
|
| 26 |
|
| 27 |
true = 1
|
| 28 |
false = 0
|
| 29 |
|
| 30 |
def load_kabilist(symsets,filename):
|
| 31 |
"""Load a list of kABI symbols to generate symsets for from a file."""
|
| 32 |
|
| 33 |
kabi_file = open(filename,"r")
|
| 34 |
|
| 35 |
while true:
|
| 36 |
in_line = kabi_file.readline()
|
| 37 |
if in_line == "":
|
| 38 |
break
|
| 39 |
if in_line == "\n":
|
| 40 |
continue
|
| 41 |
string.split(in_line)
|
| 42 |
if in_line[0] == '[':
|
| 43 |
group=in_line[1:-2]
|
| 44 |
continue
|
| 45 |
symbol=in_line[1:-1]
|
| 46 |
|
| 47 |
if symsets.has_key(group):
|
| 48 |
symsets[group].append({"symbol":symbol})
|
| 49 |
else:
|
| 50 |
symsets[group] = [{"symbol":symbol}]
|
| 51 |
|
| 52 |
kabi_file.close()
|
| 53 |
|
| 54 |
def load_symvers(symsets,filename):
|
| 55 |
"""Load the kernel exported symbols from Module.symvers."""
|
| 56 |
|
| 57 |
ksyms_file = open(filename,"r")
|
| 58 |
|
| 59 |
while true:
|
| 60 |
in_line = ksyms_file.readline()
|
| 61 |
if in_line == "":
|
| 62 |
break;
|
| 63 |
if in_line == "\n":
|
| 64 |
continue
|
| 65 |
checksum,symbol,source,export_type = string.split(in_line)
|
| 66 |
|
| 67 |
for i in symsets:
|
| 68 |
for j in range(0,len(symsets[i])):
|
| 69 |
if symsets[i][j]["symbol"] == symbol:
|
| 70 |
symsets[i][j]["checksum"] = checksum
|
| 71 |
symsets[i][j]["source"] = source
|
| 72 |
symsets[i][j]["export_type"] = export_type
|
| 73 |
|
| 74 |
def make_hashes(symsets,symhashes):
|
| 75 |
|
| 76 |
for i in symsets:
|
| 77 |
hash_tmp = sha.new()
|
| 78 |
for j in range(0,len(symsets[i])):
|
| 79 |
hash_tmp.update(symsets[i][j]["checksum"])
|
| 80 |
symhashes[i] = hash_tmp.hexdigest()
|
| 81 |
|
| 82 |
def save_hashes(symsets,symhashes,kernel,bootdir):
|
| 83 |
|
| 84 |
symdir = "symsets-"+kernel
|
| 85 |
|
| 86 |
if not os.path.isdir(symdir):
|
| 87 |
os.mkdir(symdir)
|
| 88 |
else:
|
| 89 |
print "symsets already exist for this kernel!"
|
| 90 |
sys.exit(1)
|
| 91 |
|
| 92 |
for i in symhashes:
|
| 93 |
sym_file = open(symdir+"/"+i+"."+symhashes[i], "w")
|
| 94 |
for j in range(0,len(symsets[i])):
|
| 95 |
tmp = symsets[i][j]["checksum"] + "\t" + \
|
| 96 |
symsets[i][j]["symbol"] + "\t" + \
|
| 97 |
symsets[i][j]["source"] + "\n"
|
| 98 |
sym_file.write(tmp)
|
| 99 |
sym_file.close()
|
| 100 |
os.system("tar cfz " + bootdir + "/symsets-" + kernel + ".tar.gz " + \
|
| 101 |
"symsets-" + kernel)
|
| 102 |
|
| 103 |
def find_builtin(symsets):
|
| 104 |
|
| 105 |
pbuiltins = os.popen("find -name built-in.o -printf '%P\n'")
|
| 106 |
while true:
|
| 107 |
file = pbuiltins.readline()
|
| 108 |
if file == "":
|
| 109 |
break
|
| 110 |
file = file[:-1]
|
| 111 |
|
| 112 |
pnm = os.popen("nm --extern-only --defined-only " + file)
|
| 113 |
while true:
|
| 114 |
in_line = pnm.readline()
|
| 115 |
if in_line == "":
|
| 116 |
break
|
| 117 |
in_line[:-1]
|
| 118 |
|
| 119 |
address, type, symbol = string.split(in_line)
|
| 120 |
for i in symsets:
|
| 121 |
for j in range(0,len(symsets[i])):
|
| 122 |
if symsets[i][j]["symbol"] == symbol:
|
| 123 |
symsets[i][j]["source"] = file
|
| 124 |
|
| 125 |
pnm.close()
|
| 126 |
|
| 127 |
pbuiltins.close()
|
| 128 |
|
| 129 |
def output_deps(symhashes,depsfile):
|
| 130 |
|
| 131 |
deps_file = open(depsfile,"w")
|
| 132 |
|
| 133 |
for i in symhashes:
|
| 134 |
deps_file.write("kernel("+i+") = " + symhashes[i] + "\n")
|
| 135 |
|
| 136 |
def make_kabilist(product,update,filename_modulesymvers,filename_kabilist):
|
| 137 |
"""Make a kabilist stub file for the current kernel source tree"""
|
| 138 |
|
| 139 |
ksyms_file = open(filename_modulesymvers,"r")
|
| 140 |
kabi_file = open(filename_kabilist,"w")
|
| 141 |
kabisyms = {}
|
| 142 |
|
| 143 |
while true:
|
| 144 |
in_line = ksyms_file.readline()
|
| 145 |
if in_line == "":
|
| 146 |
break;
|
| 147 |
if in_line == "\n":
|
| 148 |
continue
|
| 149 |
checksum,symbol,source,export_type = string.split(in_line)
|
| 150 |
|
| 151 |
kabisyms[symbol] = {}
|
| 152 |
kabisyms[symbol]["checksum"] = checksum
|
| 153 |
kabisyms[symbol]["source"] = source
|
| 154 |
kabisyms[symbol]["export_type"] = export_type
|
| 155 |
|
| 156 |
pbuiltins = os.popen("find -name built-in.o -printf '%P\n'")
|
| 157 |
while true:
|
| 158 |
file = pbuiltins.readline()
|
| 159 |
if file == "":
|
| 160 |
break
|
| 161 |
file = file[:-1]
|
| 162 |
|
| 163 |
pnm = os.popen("nm --extern-only --defined-only " + file)
|
| 164 |
while true:
|
| 165 |
in_line = pnm.readline()
|
| 166 |
if in_line == "":
|
| 167 |
break
|
| 168 |
in_line[:-1]
|
| 169 |
|
| 170 |
address, type, symbol = string.split(in_line)
|
| 171 |
if kabisyms.has_key(symbol):
|
| 172 |
kabisyms[symbol]["source"] = file
|
| 173 |
|
| 174 |
pnm.close()
|
| 175 |
|
| 176 |
pbuiltins.close()
|
| 177 |
|
| 178 |
symsets = {}
|
| 179 |
for i in kabisyms:
|
| 180 |
group_name = re.sub("/[^/]*$","",kabisyms[i]["source"])
|
| 181 |
group_name = re.sub("/","_",group_name)
|
| 182 |
group_name = re.sub("-","_",group_name)
|
| 183 |
group_name = re.sub("_built-in.o","",group_name)
|
| 184 |
|
| 185 |
if symsets.has_key(group_name):
|
| 186 |
symsets[group_name].append({"symbol":i, \
|
| 187 |
"checksum":kabisyms[i]["checksum"], \
|
| 188 |
"source":kabisyms[i]["source"], \
|
| 189 |
"export_type":kabisyms[i]["export_type"]})
|
| 190 |
else:
|
| 191 |
symsets[group_name] = [{"symbol":i, \
|
| 192 |
"checksum":kabisyms[i]["checksum"], \
|
| 193 |
"source":kabisyms[i]["source"], \
|
| 194 |
"export_type":kabisyms[i]["export_type"]}]
|
| 195 |
|
| 196 |
for i in symsets:
|
| 197 |
|
| 198 |
if product == "":
|
| 199 |
kabi_file.write("["+i+"]\n")
|
| 200 |
elif update == "":
|
| 201 |
kabi_file.write("["+product+"_"+i+"]\n")
|
| 202 |
else:
|
| 203 |
kabi_file.write("["+product+"_"+i+"_"+update+"]\n")
|
| 204 |
|
| 205 |
for j in range(0,len(symsets[i])):
|
| 206 |
kabi_file.write("\t" + symsets[i][j]["symbol"] + "\n")
|
| 207 |
kabi_file.write("\n")
|
| 208 |
|
| 209 |
|
| 210 |
def debug_output(symsets):
|
| 211 |
|
| 212 |
for i in symsets:
|
| 213 |
for j in range(0,len(symsets[i])):
|
| 214 |
print "======================"
|
| 215 |
print "group: " + i
|
| 216 |
print "checksum: " + symsets[i][j]["checksum"]
|
| 217 |
print "symbol: " + symsets[i][j]["symbol"]
|
| 218 |
print "source: " + symsets[i][j]["source"]
|
| 219 |
print "export: " + symsets[i][j]["export_type"]
|
| 220 |
print "======================"
|
| 221 |
|
| 222 |
def usage():
|
| 223 |
print """
|
| 224 |
kabitool: process Module.symvers into useful exported kABI dependencies
|
| 225 |
|
| 226 |
kabitool [-b bootdir] [-d] [-k kernel] [-l] [-p product] [-u update]
|
| 227 |
|
| 228 |
-b Boot dir to use for output files
|
| 229 |
|
| 230 |
-d Output RPM style kernel dependencies
|
| 231 |
|
| 232 |
-k The kernel to generate symbol sets against
|
| 233 |
|
| 234 |
-l Make a list of kernel kABI symbols
|
| 235 |
|
| 236 |
-p Product name (FC/RHEL)
|
| 237 |
|
| 238 |
-u Update Number
|
| 239 |
|
| 240 |
-w Whitelist
|
| 241 |
|
| 242 |
"""
|
| 243 |
|
| 244 |
if __name__ == "__main__":
|
| 245 |
|
| 246 |
kernel = ""
|
| 247 |
deps = ""
|
| 248 |
list = ""
|
| 249 |
product = ""
|
| 250 |
update = ""
|
| 251 |
bootdir = "."
|
| 252 |
whitelist = ""
|
| 253 |
|
| 254 |
opts, args = getopt.getopt(sys.argv[1:], 'b:d:hk:l:p:u:w:')
|
| 255 |
|
| 256 |
for o, v in opts:
|
| 257 |
if o == "-k":
|
| 258 |
kernel = v
|
| 259 |
if o == "-d":
|
| 260 |
deps = v
|
| 261 |
if o == "-l":
|
| 262 |
list = v
|
| 263 |
if o == "-p":
|
| 264 |
product = v
|
| 265 |
if o == "-u":
|
| 266 |
update = v
|
| 267 |
if o == "-h":
|
| 268 |
usage()
|
| 269 |
sys.exit(0)
|
| 270 |
if o == "-b":
|
| 271 |
bootdir = v
|
| 272 |
if o == "-w":
|
| 273 |
whitelist = v
|
| 274 |
|
| 275 |
if (kernel == "") and (list == ""):
|
| 276 |
usage()
|
| 277 |
sys.exit(1)
|
| 278 |
|
| 279 |
if (whitelist == ""):
|
| 280 |
whitelist = "kabilist"
|
| 281 |
|
| 282 |
symsets={}
|
| 283 |
symhashes={}
|
| 284 |
|
| 285 |
if not (list == ""):
|
| 286 |
make_kabilist(product,update,"Module.symvers",list)
|
| 287 |
sys.exit(0)
|
| 288 |
|
| 289 |
if not (os.path.isfile(whitelist)):
|
| 290 |
make_kabilist(product,update,"Module.symvers",whitelist)
|
| 291 |
|
| 292 |
load_kabilist(symsets,whitelist)
|
| 293 |
load_symvers(symsets,"Module.symvers")
|
| 294 |
find_builtin(symsets)
|
| 295 |
make_hashes(symsets,symhashes)
|
| 296 |
save_hashes(symsets,symhashes,kernel,bootdir)
|
| 297 |
|
| 298 |
#os.system("gzip -c9 < Module.symvers > " + bootdir +
|
| 299 |
#"/symvers-" + kernel + ".tar.gz")
|
| 300 |
|
| 301 |
if not deps == "":
|
| 302 |
output_deps(symhashes,deps)
|