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 ========================================
20 from __future__
import print_function
22 import Common
.LongFilePathOs
as os
26 from Common
.BuildToolError
import *
27 import Common
.EdkLogger
as EdkLogger
28 from Common
.Misc
import PeImageClass
, startPatternGeneral
, addressPatternGeneral
, valuePatternGcc
, pcdPatternGcc
, secReGeneral
29 from Common
.BuildVersion
import gBUILD_VERSION
30 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
32 # Version and Copyright
33 __version_number__
= ("0.10" + " " + gBUILD_VERSION
)
34 __version__
= "%prog Version " + __version_number__
35 __copyright__
= "Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved."
37 #====================================== Internal Libraries ========================================
39 #============================================== Code ===============================================
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 dataPattern
= re
.compile('^.data._gPcd_BinaryPatch_([\w_\d]+)$')
88 for index
, line
in enumerate(lines
):
90 # status machine transection
91 if status
== 0 and line
== "Memory Configuration":
94 elif status
== 1 and line
== 'Linker script and memory map':
97 elif status
==2 and line
== 'START GROUP':
103 m
= valuePatternGcc
.match(line
)
105 sections
.append(m
.groups(0))
107 m
= dataPattern
.match(line
)
110 PcdName
= m
.groups(0)[0]
111 m
= pcdPatternGcc
.match(lines
[index
+ 1].strip())
113 bpcds
.append((PcdName
, int(m
.groups(0)[0], 16), int(sections
[-1][1], 16), sections
[-1][0]))
115 # get section information from efi file
116 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
117 if efisecs
is None or len(efisecs
) == 0:
121 for efisec
in efisecs
:
122 for section
in sections
:
123 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
124 redirection
= int(section
[1], 16) - efisec
[1]
127 for efisec
in efisecs
:
128 if pcd
[1] >= efisec
[1] and pcd
[1] < efisec
[1]+efisec
[3]:
129 #assert efisec[0].strip() == pcd[3].strip() and efisec[1] + redirection == pcd[2], "There are some differences between map file and efi file"
130 pcds
.append([pcd
[0], efisec
[2] + pcd
[1] - efisec
[1] - redirection
, efisec
[0]])
133 def _parseGeneral(lines
, efifilepath
):
134 """ For MSFT, ICC, EBC
135 @param lines line array for map file
137 @return a list which element hold (PcdName, Offset, SectionName)
139 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
140 secs
= [] # key = section name
142 symPattern
= re
.compile('^[_]+gPcd_BinaryPatch_([\w]+)')
146 if startPatternGeneral
.match(line
):
149 if addressPatternGeneral
.match(line
):
152 if line
.startswith("entry point at"):
155 if status
== 1 and len(line
) != 0:
156 m
= secReGeneral
.match(line
)
157 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
158 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
159 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
160 if status
== 2 and len(line
) != 0:
161 m
= symRe
.match(line
)
162 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
163 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
164 sec_no
= int(sec_no
, 16)
165 sym_offset
= int(sym_offset
, 16)
166 vir_addr
= int(vir_addr
, 16)
167 m2
= symPattern
.match(sym_name
)
169 # fond a binary pcd entry in map file
171 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
172 bPcds
.append([m2
.groups(0)[0], sec
[3], sym_offset
, vir_addr
, sec_no
])
174 if len(bPcds
) == 0: return None
176 # get section information from efi file
177 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
178 if efisecs
is None or len(efisecs
) == 0:
184 for efisec
in efisecs
:
186 if pcd
[1].strip() == efisec
[0].strip():
187 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
188 elif pcd
[4] == index
:
189 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
192 def generatePcdTable(list, pcdpath
):
194 f
= open(pcdpath
, 'w')
198 f
.write('PCD Name Offset Section Name\r\n')
201 f
.write('%-30s 0x%-08X %-6s\r\n' % (pcditem
[0], pcditem
[1], pcditem
[2]))
204 #print 'Success to generate Binary Patch PCD table at %s!' % pcdpath
206 if __name__
== '__main__':
207 UsageString
= "%prog -m <MapFile> -e <EfiFile> -o <OutFile>"
208 AdditionalNotes
= "\nPCD table is generated in file name with .BinaryPcdTable.txt postfix"
209 parser
= optparse
.OptionParser(description
=__copyright__
, version
=__version__
, usage
=UsageString
)
210 parser
.add_option('-m', '--mapfile', action
='store', dest
='mapfile',
211 help='Absolute path of module map file.')
212 parser
.add_option('-e', '--efifile', action
='store', dest
='efifile',
213 help='Absolute path of EFI binary file.')
214 parser
.add_option('-o', '--outputfile', action
='store', dest
='outfile',
215 help='Absolute path of output file to store the got patchable PCD table.')
217 (options
, args
) = parser
.parse_args()
219 if options
.mapfile
is None or options
.efifile
is None:
220 print(parser
.get_usage())
221 elif os
.path
.exists(options
.mapfile
) and os
.path
.exists(options
.efifile
):
222 list = parsePcdInfoFromMapFile(options
.mapfile
, options
.efifile
)
224 if options
.outfile
is not None:
225 generatePcdTable(list, options
.outfile
)
227 generatePcdTable(list, options
.mapfile
.replace('.map', '.BinaryPcdTable.txt'))
229 print('Fail to generate Patch PCD Table based on map file and efi file')
231 print('Fail to generate Patch PCD Table for fail to find map file or efi file!')