X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=BaseTools%2FSource%2FPython%2FCommon%2FMisc.py;h=79073e2fef7b7e7cdb0065a48e8318da3cc399a4;hp=e9e41de02e8e1a322c6be1876dfe22c750a486b9;hb=82a6a9605c35f814bd6187979980258ed1b75abd;hpb=1be2ed90a20618d71ddf34b8a07d038da0b36854
diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py
index e9e41de02e..79073e2fef 100644
--- a/BaseTools/Source/Python/Common/Misc.py
+++ b/BaseTools/Source/Python/Common/Misc.py
@@ -1,7 +1,7 @@
## @file
# Common routines used by all tools
#
-# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2015, 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
@@ -23,6 +23,7 @@ import time
import re
import cPickle
import array
+import shutil
from UserDict import IterableUserDict
from UserList import UserList
@@ -43,6 +44,218 @@ gFileTimeStampCache = {} # {file path : file time stamp}
## Dictionary used to store dependencies of files
gDependencyDatabase = {} # arch : {file path : [dependent files list]}
+def GetVariableOffset(mapfilepath, efifilepath, varnames):
+ """ Parse map file to get variable offset in current EFI file
+ @param mapfilepath Map file absolution path
+ @param efifilepath: EFI binary file full path
+ @param varnames iteratable container whose elements are variable names to be searched
+
+ @return List whos elements are tuple with variable name and raw offset
+ """
+ lines = []
+ try:
+ f = open(mapfilepath, 'r')
+ lines = f.readlines()
+ f.close()
+ except:
+ return None
+
+ if len(lines) == 0: return None
+ firstline = lines[0].strip()
+ if (firstline.startswith("Archive member included ") and
+ firstline.endswith(" file (symbol)")):
+ return _parseForGCC(lines, efifilepath, varnames)
+ return _parseGeneral(lines, efifilepath, varnames)
+
+def _parseForGCC(lines, efifilepath, varnames):
+ """ Parse map file generated by GCC linker """
+ status = 0
+ sections = []
+ varoffset = []
+ for line in lines:
+ line = line.strip()
+ # status machine transection
+ if status == 0 and line == "Memory Configuration":
+ status = 1
+ continue
+ elif status == 1 and line == 'Linker script and memory map':
+ status = 2
+ continue
+ elif status ==2 and line == 'START GROUP':
+ status = 3
+ continue
+
+ # status handler
+ if status == 2:
+ m = re.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line)
+ if m != None:
+ sections.append(m.groups(0))
+ for varname in varnames:
+ m = re.match("^([\da-fA-Fx]+) +[_]*(%s)$" % varname, line)
+ if m != None:
+ varoffset.append((varname, int(m.groups(0)[0], 16) , int(sections[-1][1], 16), sections[-1][0]))
+
+ if not varoffset:
+ return []
+ # get section information from efi file
+ efisecs = PeImageClass(efifilepath).SectionHeaderList
+ if efisecs == None or len(efisecs) == 0:
+ return []
+ #redirection
+ redirection = 0
+ for efisec in efisecs:
+ for section in sections:
+ if section[0].strip() == efisec[0].strip() and section[0].strip() == '.text':
+ redirection = int(section[1], 16) - efisec[1]
+
+ ret = []
+ for var in varoffset:
+ for efisec in efisecs:
+ if var[1] >= efisec[1] and var[1] < efisec[1]+efisec[3]:
+ ret.append((var[0], hex(efisec[2] + var[1] - efisec[1] - redirection)))
+ return ret
+
+def _parseGeneral(lines, efifilepath, varnames):
+ status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
+ secs = [] # key = section name
+ varoffset = []
+ secRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE)
+ symRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re.UNICODE)
+
+ for line in lines:
+ line = line.strip()
+ if re.match("^Start[' ']+Length[' ']+Name[' ']+Class", line):
+ status = 1
+ continue
+ if re.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line):
+ status = 2
+ continue
+ if re.match("^entry point at", line):
+ status = 3
+ continue
+ if status == 1 and len(line) != 0:
+ m = secRe.match(line)
+ assert m != None, "Fail to parse the section in map file , line is %s" % line
+ sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0)
+ secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class])
+ if status == 2 and len(line) != 0:
+ for varname in varnames:
+ m = symRe.match(line)
+ assert m != None, "Fail to parse the symbol in map file, line is %s" % line
+ sec_no, sym_offset, sym_name, vir_addr = m.groups(0)
+ sec_no = int(sec_no, 16)
+ sym_offset = int(sym_offset, 16)
+ vir_addr = int(vir_addr, 16)
+ m2 = re.match('^[_]*(%s)' % varname, sym_name)
+ if m2 != None:
+ # fond a binary pcd entry in map file
+ for sec in secs:
+ if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]):
+ varoffset.append([varname, sec[3], sym_offset, vir_addr, sec_no])
+
+ if not varoffset: return []
+
+ # get section information from efi file
+ efisecs = PeImageClass(efifilepath).SectionHeaderList
+ if efisecs == None or len(efisecs) == 0:
+ return []
+
+ ret = []
+ for var in varoffset:
+ index = 0
+ for efisec in efisecs:
+ index = index + 1
+ if var[1].strip() == efisec[0].strip():
+ ret.append((var[0], hex(efisec[2] + var[2])))
+ elif var[4] == index:
+ ret.append((var[0], hex(efisec[2] + var[2])))
+
+ return ret
+
+## Routine to process duplicated INF
+#
+# This function is called by following two cases:
+# Case 1 in DSC:
+# [components.arch]
+# Pkg/module/module.inf
+# Pkg/module/module.inf {
+#
+# FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
+# }
+# Case 2 in FDF:
+# INF Pkg/module/module.inf
+# INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
+#
+# This function copies Pkg/module/module.inf to
+# Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
+#
+# @param Path Original PathClass object
+# @param BaseName New file base name
+#
+# @retval return the new PathClass object
+#
+def ProcessDuplicatedInf(Path, BaseName, Workspace):
+ Filename = os.path.split(Path.File)[1]
+ if '.' in Filename:
+ Filename = BaseName + Path.BaseName + Filename[Filename.rfind('.'):]
+ else:
+ Filename = BaseName + Path.BaseName
+
+ #
+ # If -N is specified on command line, cache is disabled
+ # The directory has to be created
+ #
+ DbDir = os.path.split(GlobalData.gDatabasePath)[0]
+ if not os.path.exists(DbDir):
+ os.makedirs(DbDir)
+ #
+ # A temporary INF is copied to database path which must have write permission
+ # The temporary will be removed at the end of build
+ # In case of name conflict, the file name is
+ # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
+ #
+ TempFullPath = os.path.join(DbDir,
+ Filename)
+ RtPath = PathClass(Path.File, Workspace)
+ #
+ # Modify the full path to temporary path, keep other unchanged
+ #
+ # To build same module more than once, the module path with FILE_GUID overridden has
+ # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
+ # in DSC which is used as relative path by C files and other files in INF.
+ # A trick was used: all module paths are PathClass instances, after the initialization
+ # of PathClass, the PathClass.Path is overridden by the temporary INF path.
+ #
+ # The reason for creating a temporary INF is:
+ # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
+ # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
+ # A different key for the same module is needed to create different output directory,
+ # retrieve overridden PCDs, library instances.
+ #
+ # The BaseName is the FILE_GUID which is also the output directory name.
+ #
+ #
+ RtPath.Path = TempFullPath
+ RtPath.BaseName = BaseName
+ #
+ # If file exists, compare contents
+ #
+ if os.path.exists(TempFullPath):
+ with open(str(Path), 'rb') as f1: Src = f1.read()
+ with open(TempFullPath, 'rb') as f2: Dst = f2.read()
+ if Src == Dst:
+ return RtPath
+ GlobalData.gTempInfs.append(TempFullPath)
+ shutil.copy2(str(Path), TempFullPath)
+ return RtPath
+
+## Remove temporary created INFs whose paths were saved in gTempInfs
+#
+def ClearDuplicatedInf():
+ for File in GlobalData.gTempInfs:
+ if os.path.exists(File):
+ os.remove(File)
+
## callback routine for processing variable option
#
# This function can be used to process variable number of option values. The
@@ -441,6 +654,7 @@ def RealPath(File, Dir='', OverrideDir=''):
return NewFile
def RealPath2(File, Dir='', OverrideDir=''):
+ NewFile = None
if OverrideDir:
NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
if NewFile:
@@ -450,8 +664,10 @@ def RealPath2(File, Dir='', OverrideDir=''):
return NewFile[len(OverrideDir)+1:], NewFile[0:len(OverrideDir)]
if GlobalData.gAllFiles:
NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]
- else:
+ if not NewFile:
NewFile = os.path.normpath(os.path.join(Dir, File))
+ if not os.path.exists(NewFile):
+ return None, None
if NewFile:
if Dir:
if Dir[-1] == os.path.sep:
@@ -1292,15 +1508,17 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''):
return [VpdOffset, Size, Value], IsValid, 2
elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):
HiiString = FieldList[0]
- Guid = Offset = Value = ''
+ Guid = Offset = Value = Attribute = ''
if len(FieldList) > 1:
Guid = FieldList[1]
if len(FieldList) > 2:
Offset = FieldList[2]
if len(FieldList) > 3:
Value = FieldList[3]
- IsValid = (3 <= len(FieldList) <= 4)
- return [HiiString, Guid, Offset, Value], IsValid, 3
+ if len(FieldList) > 4:
+ Attribute = FieldList[4]
+ IsValid = (3 <= len(FieldList) <= 5)
+ return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3
return [], False, 0
## AnalyzePcdData
@@ -1456,6 +1674,45 @@ def CommonPath(PathList):
return os.path.sep.join(P1[:Index])
return os.path.sep.join(P1)
+#
+# Convert string to C format array
+#
+def ConvertStringToByteArray(Value):
+ Value = Value.strip()
+ if not Value:
+ return None
+ if Value[0] == '{':
+ if not Value.endswith('}'):
+ return None
+ Value = Value.replace(' ', '').replace('{', '').replace('}', '')
+ ValFields = Value.split(',')
+ try:
+ for Index in range(len(ValFields)):
+ ValFields[Index] = str(int(ValFields[Index], 0))
+ except ValueError:
+ return None
+ Value = '{' + ','.join(ValFields) + '}'
+ return Value
+
+ Unicode = False
+ if Value.startswith('L"'):
+ if not Value.endswith('"'):
+ return None
+ Value = Value[1:]
+ Unicode = True
+ elif not Value.startswith('"') or not Value.endswith('"'):
+ return None
+
+ Value = eval(Value) # translate escape character
+ NewValue = '{'
+ for Index in range(0,len(Value)):
+ if Unicode:
+ NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ','
+ else:
+ NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ','
+ Value = NewValue + '0}'
+ return Value
+
class PathClass(object):
def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,
Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):