]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py
59748763a553d2711470f4b06879767a95055330
2 # Generate PCD table for 'Patchable In Module' type PCD with given .map file.
3 # The Patch PCD table like:
5 # PCD Name Offset in binary
6 # ======== ================
8 # Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
9 # This program and the accompanying materials
10 # are licensed and made available under the terms and conditions of the BSD License
11 # which accompanies this distribution. The full text of the license may be found at
12 # http://opensource.org/licenses/bsd-license.php
14 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #====================================== External Libraries ========================================
21 import Common
.LongFilePathOs
as os
25 from Common
.BuildToolError
import *
26 import Common
.EdkLogger
as EdkLogger
27 from Common
.Misc
import PeImageClass
28 from Common
.BuildVersion
import gBUILD_VERSION
29 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
31 # Version and Copyright
32 __version_number__
= ("0.10" + " " + gBUILD_VERSION
)
33 __version__
= "%prog Version " + __version_number__
34 __copyright__
= "Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved."
36 #====================================== Internal Libraries ========================================
38 #============================================== Code ===============================================
39 secRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re
.UNICODE
)
40 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.\-:\\\\\w\?@\$<>]+) +([\da-fA-F]+)', re
.UNICODE
)
42 def parsePcdInfoFromMapFile(mapfilepath
, efifilepath
):
43 """ Parse map file to get binary patch pcd information
44 @param path Map file absolution path
46 @return a list which element hold (PcdName, Offset, SectionName)
50 f
= open(mapfilepath
, 'r')
56 if len(lines
) == 0: return None
57 firstline
= lines
[0].strip()
58 if (firstline
.startswith("Archive member included ") and
59 firstline
.endswith(" file (symbol)")):
60 return _parseForGCC(lines
, efifilepath
)
61 if firstline
.startswith("# Path:"):
62 return _parseForXcode(lines
, efifilepath
)
63 return _parseGeneral(lines
, efifilepath
)
65 def _parseForXcode(lines
, efifilepath
):
66 valuePattern
= re
.compile('^([\da-fA-FxX]+)([\s\S]*)([_]*_gPcd_BinaryPatch_([\w]+))')
71 if status
== 0 and line
== "# Symbols:":
74 if status
== 1 and len(line
) != 0:
75 if '_gPcd_BinaryPatch_' in line
:
76 m
= valuePattern
.match(line
)
78 pcds
.append((m
.groups(0)[3], int(m
.groups(0)[0], 16)))
81 def _parseForGCC(lines
, efifilepath
):
82 """ Parse map file generated by GCC linker """
83 valuePattern
= re
.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')
84 dataPattern
= re
.compile('^.data._gPcd_BinaryPatch_([\w_\d]+)$')
85 pcdPattern
= re
.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')
90 for index
, line
in enumerate(lines
):
92 # status machine transection
93 if status
== 0 and line
== "Memory Configuration":
96 elif status
== 1 and line
== 'Linker script and memory map':
99 elif status
==2 and line
== 'START GROUP':
105 m
= valuePattern
.match(line
)
107 sections
.append(m
.groups(0))
109 m
= dataPattern
.match(line
)
112 PcdName
= m
.groups(0)[0]
113 m
= pcdPattern
.match(lines
[index
+ 1].strip())
115 bpcds
.append((PcdName
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
117 # get section information from efi file
118 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
119 if efisecs
is None or len(efisecs
) == 0:
123 for efisec
in efisecs
:
124 for section
in sections
:
125 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
126 redirection
= int(section
[1], 16) - efisec
[1]
129 for efisec
in efisecs
:
130 if pcd
[1] >= efisec
[1] and pcd
[1] < efisec
[1]+efisec
[3]:
131 #assert efisec[0].strip() == pcd[3].strip() and efisec[1] + redirection == pcd[2], "There are some differences between map file and efi file"
132 pcds
.append([pcd
[0], efisec
[2] + pcd
[1] - efisec
[1] - redirection
, efisec
[0]])
135 def _parseGeneral(lines
, efifilepath
):
136 """ For MSFT, ICC, EBC
137 @param lines line array for map file
139 @return a list which element hold (PcdName, Offset, SectionName)
141 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
142 secs
= [] # key = section name
144 startPattern
= re
.compile("^Start[' ']+Length[' ']+Name[' ']+Class")
145 addressPattern
= re
.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")
146 symPattern
= re
.compile('^[_]+gPcd_BinaryPatch_([\w]+)')
150 if startPattern
.match(line
):
153 if addressPattern
.match(line
):
156 if line
.startswith("entry point at"):
159 if status
== 1 and len(line
) != 0:
160 m
= secRe
.match(line
)
161 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
162 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
163 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
164 if status
== 2 and len(line
) != 0:
165 m
= symRe
.match(line
)
166 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
167 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
168 sec_no
= int(sec_no
, 16)
169 sym_offset
= int(sym_offset
, 16)
170 vir_addr
= int(vir_addr
, 16)
171 m2
= symPattern
.match(sym_name
)
173 # fond a binary pcd entry in map file
175 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
176 bPcds
.append([m2
.groups(0)[0], sec
[3], sym_offset
, vir_addr
, sec_no
])
178 if len(bPcds
) == 0: return None
180 # get section information from efi file
181 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
182 if efisecs
is None or len(efisecs
) == 0:
188 for efisec
in efisecs
:
190 if pcd
[1].strip() == efisec
[0].strip():
191 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
192 elif pcd
[4] == index
:
193 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
196 def generatePcdTable(list, pcdpath
):
198 f
= open(pcdpath
, 'w')
202 f
.write('PCD Name Offset Section Name\r\n')
205 f
.write('%-30s 0x%-08X %-6s\r\n' % (pcditem
[0], pcditem
[1], pcditem
[2]))
208 #print 'Success to generate Binary Patch PCD table at %s!' % pcdpath
210 if __name__
== '__main__':
211 UsageString
= "%prog -m <MapFile> -e <EfiFile> -o <OutFile>"
212 AdditionalNotes
= "\nPCD table is generated in file name with .BinaryPcdTable.txt postfix"
213 parser
= optparse
.OptionParser(description
=__copyright__
, version
=__version__
, usage
=UsageString
)
214 parser
.add_option('-m', '--mapfile', action
='store', dest
='mapfile',
215 help='Absolute path of module map file.')
216 parser
.add_option('-e', '--efifile', action
='store', dest
='efifile',
217 help='Absolute path of EFI binary file.')
218 parser
.add_option('-o', '--outputfile', action
='store', dest
='outfile',
219 help='Absolute path of output file to store the got patchable PCD table.')
221 (options
, args
) = parser
.parse_args()
223 if options
.mapfile
is None or options
.efifile
is None:
224 print parser
.get_usage()
225 elif os
.path
.exists(options
.mapfile
) and os
.path
.exists(options
.efifile
):
226 list = parsePcdInfoFromMapFile(options
.mapfile
, options
.efifile
)
228 if options
.outfile
is not None:
229 generatePcdTable(list, options
.outfile
)
231 generatePcdTable(list, options
.mapfile
.replace('.map', '.BinaryPcdTable.txt'))
233 print 'Fail to generate Patch PCD Table based on map file and efi file'
235 print 'Fail to generate Patch PCD Table for fail to find map file or efi file!'