#!/usr/bin/python # # kabitool - Red Hat kABI extraction tool # # We use this script to generate collections (groups) of kABI symbols and also # optionally output kABI dependencies for use by the RPM. # # Author: Jon Masters <jcm@redhat.com> # Copyright (C) 2006 Red Hat, Inc. # # This software may be freely redistributed under the terms of the GNU # General Public License (GPL). # Changelog: # # 2006/12/11 - Add better error handling to catch unresolved symbols. __author__ = "Jon Masters <jcm@redhat.com>" __version__ = "$Revisions: 1.3 $" __date__ = "$Date: 2007/11/26 18:21:15 $" __copyright__ = "Copyright (C) 2006 Red Hat, Inc" __license__ = "GPL" import getopt import os import re import sha import string import sys true = 1 false = 0 def load_kabilist(symsets,filename): """Load a list of kABI symbols to generate symsets for from a file.""" kabi_file = open(filename,"r") while true: in_line = kabi_file.readline() if in_line == "": break if in_line == "\n": continue string.split(in_line) if in_line[0] == '[': group=in_line[1:-2] continue symbol=in_line[1:-1] if symsets.has_key(group): symsets[group].append({"symbol":symbol}) else: symsets[group] = [{"symbol":symbol}] kabi_file.close() def load_symvers(symsets,filename): """Load the kernel exported symbols from Module.symvers.""" ksyms_file = open(filename,"r") while true: in_line = ksyms_file.readline() if in_line == "": break; if in_line == "\n": continue checksum,symbol,source,export_type = string.split(in_line) for i in symsets: for j in range(0,len(symsets[i])): if symsets[i][j]["symbol"] == symbol: symsets[i][j]["checksum"] = checksum symsets[i][j]["source"] = source symsets[i][j]["export_type"] = export_type def make_hashes(symsets,symhashes): for i in symsets: hash_tmp = sha.new() for j in range(0,len(symsets[i])): if symsets[i][j].has_key("checksum"): hash_tmp.update(symsets[i][j]["checksum"]) else: print "kabitool: cannot find checksum for symbol",symsets[i][j]["symbol"],"in group",i sys.exit(1) symhashes[i] = hash_tmp.hexdigest() def save_hashes(symsets,symhashes,kernel,bootdir): symdir = "symsets-"+kernel if not os.path.isdir(symdir): os.mkdir(symdir) else: print "symsets already exist for this kernel!" sys.exit(1) for i in symhashes: sym_file = open(symdir+"/"+i+"."+symhashes[i], "w") for j in range(0,len(symsets[i])): if symsets[i][j].has_key("checksum"): tmp = symsets[i][j]["checksum"] + "\t" + \ symsets[i][j]["symbol"] + "\t" + \ symsets[i][j]["source"] + "\n" sym_file.write(tmp) else: print "kabitool: cannot find checksum for symbol",symsets[i][j]["symbol"],"in group",i sys.exit(1) sym_file.close() os.system("tar cfz " + bootdir + "/symsets-" + kernel + ".tar.gz " + \ "symsets-" + kernel) def find_builtin(symsets): pbuiltins = os.popen("find -name built-in.o -printf '%P\n'") while true: file = pbuiltins.readline() if file == "": break file = file[:-1] pnm = os.popen("nm --extern-only --defined-only " + file) while true: in_line = pnm.readline() if in_line == "": break in_line[:-1] address, type, symbol = string.split(in_line) for i in symsets: for j in range(0,len(symsets[i])): if symsets[i][j]["symbol"] == symbol: symsets[i][j]["source"] = file pnm.close() pbuiltins.close() def output_deps(symhashes,depsfile): deps_file = open(depsfile,"w") for i in symhashes: deps_file.write("kernel("+i+") = " + symhashes[i] + "\n") def make_kabilist(product,update,filename_modulesymvers,filename_kabilist): """Make a kabilist stub file for the current kernel source tree""" ksyms_file = open(filename_modulesymvers,"r") kabi_file = open(filename_kabilist,"w") kabisyms = {} while true: in_line = ksyms_file.readline() if in_line == "": break; if in_line == "\n": continue checksum,symbol,source,export_type = string.split(in_line) kabisyms[symbol] = {} kabisyms[symbol]["checksum"] = checksum kabisyms[symbol]["source"] = source kabisyms[symbol]["export_type"] = export_type pbuiltins = os.popen("find -name built-in.o -printf '%P\n'") while true: file = pbuiltins.readline() if file == "": break file = file[:-1] pnm = os.popen("nm --extern-only --defined-only " + file) while true: in_line = pnm.readline() if in_line == "": break in_line[:-1] address, type, symbol = string.split(in_line) if kabisyms.has_key(symbol): kabisyms[symbol]["source"] = file pnm.close() pbuiltins.close() symsets = {} for i in kabisyms: group_name = re.sub("/[^/]*$","",kabisyms[i]["source"]) group_name = re.sub("/","_",group_name) group_name = re.sub("-","_",group_name) group_name = re.sub("_built-in.o","",group_name) if symsets.has_key(group_name): symsets[group_name].append({"symbol":i, \ "checksum":kabisyms[i]["checksum"], \ "source":kabisyms[i]["source"], \ "export_type":kabisyms[i]["export_type"]}) else: symsets[group_name] = [{"symbol":i, \ "checksum":kabisyms[i]["checksum"], \ "source":kabisyms[i]["source"], \ "export_type":kabisyms[i]["export_type"]}] for i in symsets: if product == "": kabi_file.write("["+i+"]\n") elif update == "": kabi_file.write("["+product+"_"+i+"]\n") else: kabi_file.write("["+product+"_"+i+"_"+update+"]\n") for j in range(0,len(symsets[i])): kabi_file.write("\t" + symsets[i][j]["symbol"] + "\n") kabi_file.write("\n") def debug_output(symsets): for i in symsets: for j in range(0,len(symsets[i])): print "======================" print "group: " + i print "checksum: " + symsets[i][j]["checksum"] print "symbol: " + symsets[i][j]["symbol"] print "source: " + symsets[i][j]["source"] print "export: " + symsets[i][j]["export_type"] print "======================" def usage(): print """ kabitool: process Module.symvers into useful exported kABI dependencies kabitool [-b bootdir] [-d] [-k kernel] [-l] [-p product] [-u update] -b Boot dir to use for output files -d Output RPM style kernel dependencies -k The kernel to generate symbol sets against -l Make a list of kernel kABI symbols -p Product name (FC/RHEL) -u Update Number -w Whitelist """ if __name__ == "__main__": kernel = "" deps = "" list = "" product = "" update = "" bootdir = "." whitelist = "" opts, args = getopt.getopt(sys.argv[1:], 'b:d:hk:l:p:u:w:') for o, v in opts: if o == "-k": kernel = v if o == "-d": deps = v if o == "-l": list = v if o == "-p": product = v if o == "-u": update = v if o == "-h": usage() sys.exit(0) if o == "-b": bootdir = v if o == "-w": whitelist = v if (kernel == "") and (list == ""): usage() sys.exit(1) if (whitelist == ""): whitelist = "kabilist" symsets={} symhashes={} if not (list == ""): make_kabilist(product,update,"Module.symvers",list) sys.exit(0) if not (os.path.isfile(whitelist)): make_kabilist(product,update,"Module.symvers",whitelist) load_kabilist(symsets,whitelist) load_symvers(symsets,"Module.symvers") find_builtin(symsets) make_hashes(symsets,symhashes) save_hashes(symsets,symhashes,kernel,bootdir) #os.system("gzip -c9 < Module.symvers > " + bootdir + #"/symvers-" + kernel + ".tar.gz") if not deps == "": output_deps(symhashes,deps)