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 - 2016, 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 return _parseGeneral(lines
, efifilepath
)
63 def _parseForGCC(lines
, efifilepath
):
64 """ Parse map file generated by GCC linker """
69 for index
, line
in enumerate(lines
):
71 # status machine transection
72 if status
== 0 and line
== "Memory Configuration":
75 elif status
== 1 and line
== 'Linker script and memory map':
78 elif status
==2 and line
== 'START GROUP':
84 m
= re
.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line
)
86 sections
.append(m
.groups(0))
88 m
= re
.match('^.data._gPcd_BinaryPatch_([\w_\d]+)$', line
)
91 PcdName
= m
.groups(0)[0]
92 m
= re
.match('^([\da-fA-Fx]+) +([\da-fA-Fx]+)', lines
[index
+ 1].strip())
94 bpcds
.append((PcdName
, int(m
.groups(0)[0], 16) , int(sections
[-1][1], 16), sections
[-1][0]))
96 # get section information from efi file
97 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
98 if efisecs
== None or len(efisecs
) == 0:
102 for efisec
in efisecs
:
103 for section
in sections
:
104 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
105 redirection
= int(section
[1], 16) - efisec
[1]
108 for efisec
in efisecs
:
109 if pcd
[1] >= efisec
[1] and pcd
[1] < efisec
[1]+efisec
[3]:
110 #assert efisec[0].strip() == pcd[3].strip() and efisec[1] + redirection == pcd[2], "There are some differences between map file and efi file"
111 pcds
.append([pcd
[0], efisec
[2] + pcd
[1] - efisec
[1] - redirection
, efisec
[0]])
114 def _parseGeneral(lines
, efifilepath
):
115 """ For MSFT, ICC, EBC
116 @param lines line array for map file
118 @return a list which element hold (PcdName, Offset, SectionName)
120 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
121 secs
= [] # key = section name
127 if re
.match("^Start[' ']+Length[' ']+Name[' ']+Class", line
):
130 if re
.match("^Address[' ']+Publics by Value[' ']+Rva\+Base", line
):
133 if re
.match("^entry point at", line
):
136 if status
== 1 and len(line
) != 0:
137 m
= secRe
.match(line
)
138 assert m
!= None, "Fail to parse the section in map file , line is %s" % line
139 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
140 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
141 if status
== 2 and len(line
) != 0:
142 m
= symRe
.match(line
)
143 assert m
!= None, "Fail to parse the symbol in map file, line is %s" % line
144 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
145 sec_no
= int(sec_no
, 16)
146 sym_offset
= int(sym_offset
, 16)
147 vir_addr
= int(vir_addr
, 16)
148 m2
= re
.match('^[_]+gPcd_BinaryPatch_([\w]+)', sym_name
)
150 # fond a binary pcd entry in map file
152 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
153 bPcds
.append([m2
.groups(0)[0], sec
[3], sym_offset
, vir_addr
, sec_no
])
155 if len(bPcds
) == 0: return None
157 # get section information from efi file
158 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
159 if efisecs
== None or len(efisecs
) == 0:
165 for efisec
in efisecs
:
167 if pcd
[1].strip() == efisec
[0].strip():
168 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
169 elif pcd
[4] == index
:
170 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
173 def generatePcdTable(list, pcdpath
):
175 f
= open(pcdpath
, 'w')
179 f
.write('PCD Name Offset Section Name\r\n')
182 f
.write('%-30s 0x%-08X %-6s\r\n' % (pcditem
[0], pcditem
[1], pcditem
[2]))
185 #print 'Success to generate Binary Patch PCD table at %s!' % pcdpath
187 if __name__
== '__main__':
188 UsageString
= "%prog -m <MapFile> -e <EfiFile> -o <OutFile>"
189 AdditionalNotes
= "\nPCD table is generated in file name with .BinaryPcdTable.txt postfix"
190 parser
= optparse
.OptionParser(description
=__copyright__
, version
=__version__
, usage
=UsageString
)
191 parser
.add_option('-m', '--mapfile', action
='store', dest
='mapfile',
192 help='Absolute path of module map file.')
193 parser
.add_option('-e', '--efifile', action
='store', dest
='efifile',
194 help='Absolute path of EFI binary file.')
195 parser
.add_option('-o', '--outputfile', action
='store', dest
='outfile',
196 help='Absolute path of output file to store the got patchable PCD table.')
198 (options
, args
) = parser
.parse_args()
200 if options
.mapfile
== None or options
.efifile
== None:
201 print parser
.get_usage()
202 elif os
.path
.exists(options
.mapfile
) and os
.path
.exists(options
.efifile
):
203 list = parsePcdInfoFromMapFile(options
.mapfile
, options
.efifile
)
205 if options
.outfile
!= None:
206 generatePcdTable(list, options
.outfile
)
208 generatePcdTable(list, options
.mapfile
.replace('.map', '.BinaryPcdTable.txt'))
210 print 'Fail to generate Patch PCD Table based on map file and efi file'
212 print 'Fail to generate Patch PCD Table for fail to find map file or efi file!'