mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 01:35:30 +00:00 
			
		
		
		
	 3b7a53b683
			
		
	
	
		3b7a53b683
		
	
	
	
	
		
			
			git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2177 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			218 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env python
 | |
| 
 | |
| # Copyright (c) 2007, Intel Corporation
 | |
| # All rights reserved. This program and the accompanying materials
 | |
| # are licensed and made available under the terms and conditions of the BSD License
 | |
| # which accompanies this distribution.  The full text of the license may be found at
 | |
| # http://opensource.org/licenses/bsd-license.php
 | |
| # 
 | |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| """Calculate the dependencies a given module has by looking through the source
 | |
| code to see what guids and functions are referenced to see which Packages and
 | |
| Library Classes need to be referenced. """
 | |
| 
 | |
| import os, sys, re, getopt, string, glob, xml.dom.minidom, pprint
 | |
| from XmlRoutines import *
 | |
| 
 | |
| # Map each function name back to the lib class that declares it.
 | |
| function_table = {}
 | |
| 
 | |
| # Map each guid name to a package name.
 | |
| cname_table = {}
 | |
| 
 | |
| def inWorkspace(rel_path):
 | |
|   """Treat the given path as relative to the workspace."""
 | |
| 
 | |
|   # Make sure the user has set the workspace variable:
 | |
|   try:
 | |
|     return os.path.join(os.environ["WORKSPACE"], rel_path )
 | |
|   except:
 | |
|     print "Oops! You must set the WORKSPACE environment variable to run this script."
 | |
|     sys.exit()
 | |
| 
 | |
| def getIdentifiers(infiles):
 | |
| 
 | |
|   """Build a set of all the identifiers in this file."""
 | |
| 
 | |
|   # Start with an empty set.
 | |
|   ids = set()
 | |
| 
 | |
|   for infile in infiles:
 | |
| 
 | |
|     # Open the file
 | |
|     f = open(infile)
 | |
| 
 | |
|     # Create some lexical categories that we will use to filter out
 | |
|     strings=re.compile('L?"[^"]*"')
 | |
|     chars=re.compile("'[^']*'")
 | |
|     hex=re.compile("0[Xx][0-9a-fA-F]*")
 | |
|     keywords = re.compile('for|do|while|if|else|break|int|unsigned|switch|volatile|goto|case|char|long|struct|return|extern')
 | |
|     common = re.compile('VOID|UINTN|UINT32|UINT8|UINT64')
 | |
| 
 | |
|     # Compile a Regular expression to grab all the identifers from the input.
 | |
|     identifier = re.compile('[_a-zA-Z][0-9_a-zA-Z]{3,}')
 | |
| 
 | |
|     for line in f.readlines():
 | |
| 
 | |
|       # Filter some lexical categories out.
 | |
|       # for filter in [strings, chars, hex, keywords, common]:
 | |
|       for filter in [strings, chars, hex]:
 | |
|         line = re.sub(filter, '', line)
 | |
|       
 | |
|       # Add all the identifiers that we found on this line.
 | |
|       ids = ids.union(set(identifier.findall(line)))
 | |
| 
 | |
|     # Close the file
 | |
|     f.close()    
 | |
| 
 | |
|   # Return the set of identifiers.
 | |
|   return ids
 | |
| 
 | |
| 
 | |
| def search_classes(ids):
 | |
| 
 | |
|   """ Search the set of classes for functions."""
 | |
| 
 | |
|   # Start with an empty set.
 | |
|   classes = set()
 | |
| 
 | |
|   for id in ids:
 | |
|     try:
 | |
|       # If it is not a "hit" in the table add it to the set.
 | |
|       classes.add(function_table[id])
 | |
|     except:
 | |
|       # If it is not a "hit" in the table, ignore it.
 | |
|       pass
 | |
| 
 | |
|   return classes
 | |
| 
 | |
| def search_cnames(ids):
 | |
| 
 | |
|   """Search all the Packages to see if this code uses a Guid from one of them.
 | |
|   Return a set of matching packages."""
 | |
| 
 | |
|   packages = set()
 | |
| 
 | |
|   for id in ids:
 | |
|     try:
 | |
|       # If it is not a "hit" in the table add it to the set.
 | |
|       packages.add(cname_table[id])
 | |
|     except:
 | |
|       # If it is not a "hit" in the table, ignore it.
 | |
|       pass
 | |
| 
 | |
|   return packages
 | |
| 
 | |
| def getSpds():
 | |
| 
 | |
|   """Open the database and get all the spd files out."""
 | |
| 
 | |
|   # Open the database
 | |
|   database = xml.dom.minidom.parse(inWorkspace("Tools/Conf/FrameworkDatabase.db"))
 | |
| 
 | |
|   # Get a list of all the packages
 | |
|   for filename in XmlList(database, "/FrameworkDatabase/PackageList/Filename"):
 | |
|     spdFile = XmlElementData(filename)
 | |
| 
 | |
|     # Now open the spd file and build the database of guids.
 | |
|     getCNames(inWorkspace(spdFile))
 | |
|     getLibClasses(inWorkspace(spdFile))
 | |
| 
 | |
| def getCNames(spdFile):
 | |
| 
 | |
|   """Extract all the C_Names from an spd file."""
 | |
| 
 | |
|   # Begin to parse the XML of the .spd
 | |
|   spd = xml.dom.minidom.parse(spdFile)
 | |
| 
 | |
|   # Get the name of the package
 | |
|   packageName = XmlElement(spd, "PackageSurfaceArea/SpdHeader/PackageName")
 | |
|   packageVersion = XmlElement(spd, "PackageSurfaceArea/SpdHeader/Version")
 | |
|   packageGuid = XmlElement(spd, "PackageSurfaceArea/SpdHeader/GuidValue")
 | |
| 
 | |
|   # Find the C_Name
 | |
|   for cname in XmlList(spd, "/PackageSurfaceArea/GuidDeclarations/Entry/C_Name") + \
 | |
|                XmlList(spd, "/PackageSurfaceArea/PcdDeclarations/PcdEntry/C_Name") + \
 | |
|                XmlList(spd, "/PackageSurfaceArea/PpiDeclarations/Entry/C_Name") + \
 | |
|                XmlList(spd, "/PackageSurfaceArea/ProtocolDeclarations/Entry/C_Name"):
 | |
| 
 | |
|     # Get the text of the <C_Name> tag.
 | |
|     cname_text = XmlElementData(cname)
 | |
| 
 | |
|     # Map the <C_Name> to the <PackageName>. We will use this to lookup every 
 | |
|     # identifier in the Input Code.
 | |
|     cname_table[cname_text] = {"name": packageName, "version": packageVersion, "guid": packageGuid}
 | |
| 
 | |
| 
 | |
|   return
 | |
| 
 | |
| def getLibClasses(spdFile):
 | |
| 
 | |
|   """Extract all the Lib Classes from an spd file."""
 | |
| 
 | |
|   # Begin to parse the XML of the .spd
 | |
|   spd = xml.dom.minidom.parse(spdFile)
 | |
| 
 | |
|   # Get the guid of the package
 | |
|   packageGuid = XmlElement(spd, "/PackageSurfaceArea/SpdHeader/GuidValue")
 | |
| 
 | |
|   for libClass in XmlList(spd, "/PackageSurfaceArea/LibraryClassDeclarations/LibraryClass"):
 | |
|     className = XmlAttribute(libClass, "Name")
 | |
|     headerfile = XmlElementData(libClass.getElementsByTagName("IncludeHeader")[0])
 | |
| 
 | |
|     packageRoot=os.path.dirname(spdFile)
 | |
| 
 | |
|     headerfile = os.path.join(packageRoot, headerfile)
 | |
| 
 | |
|     f = open(headerfile)
 | |
| 
 | |
|     # This pattern can pick out function names if the EFI coding
 | |
|     # standard is followed. We could also use dumpbin on library
 | |
|     # instances to get a list of symbols.
 | |
|     functionPattern = re.compile("([_a-zA-Z][_a-zA-Z0-9]*) *\( *");
 | |
| 
 | |
|     for line in f.readlines():
 | |
|       m = functionPattern.match(line)
 | |
|       if m:
 | |
|         functionName = m.group(1)
 | |
|         # Map it!
 | |
|         function_table[functionName] = (className, packageGuid)
 | |
| 
 | |
|     f.close()
 | |
| 
 | |
| def guid(strVal):
 | |
|   """Make a guid number out of a guid hex string."""
 | |
|   return long(strVal.replace('-',''), 16)
 | |
| 
 | |
| # This acts like the main() function for the script, unless it is 'import'ed into another
 | |
| # script.
 | |
| if __name__ == '__main__':
 | |
| 
 | |
|   # Create a pretty printer for dumping data structures in a readable form.
 | |
|   pp = pprint.PrettyPrinter(indent=2)
 | |
| 
 | |
|   # Process the command line args.
 | |
|   optlist, args = getopt.getopt(sys.argv[1:], 'h', [ 'example-long-arg=', 'testing'])
 | |
| 
 | |
|   """You should pass a file name as a paramter. It should be preprocessed text
 | |
| of all the .c and .h files in your module, which is cat'ed together into one
 | |
| large file."""
 | |
| 
 | |
|   # Scrape out all the things that look like identifiers.
 | |
|   ids = getIdentifiers(args)
 | |
| 
 | |
|   # Read in the spds from the workspace to find the Guids.
 | |
|   getSpds()
 | |
| 
 | |
|   # Debug stuff.
 | |
|   print "Function Table = "
 | |
|   pp.pprint(function_table)
 | |
|   print "CName Table = "
 | |
|   pp.pprint(cname_table)
 | |
|   print "Classes = "
 | |
|   pp.pprint(list(search_classes(ids)))
 | |
|   print "C_Names = "
 | |
|   pp.pprint(list(search_cnames(ids)))
 |