]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenPatchPcdTable/GenPatchPcdTable.py
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 # SPDX-License-Identifier: BSD-2-Clause-Patent
13 #====================================== External Libraries ========================================
14 from __future__
import print_function
16 import Common
.LongFilePathOs
as os
20 from Common
.BuildToolError
import *
21 import Common
.EdkLogger
as EdkLogger
22 from Common
.Misc
import PeImageClass
, startPatternGeneral
, addressPatternGeneral
, valuePatternGcc
, pcdPatternGcc
, secReGeneral
23 from Common
.BuildVersion
import gBUILD_VERSION
24 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
26 # Version and Copyright
27 __version_number__
= ("0.10" + " " + gBUILD_VERSION
)
28 __version__
= "%prog Version " + __version_number__
29 __copyright__
= "Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved."
31 #====================================== Internal Libraries ========================================
33 #============================================== Code ===============================================
34 symRe
= re
.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.\-:\\\\\w\?@\$<>]+) +([\da-fA-F]+)', re
.UNICODE
)
36 def parsePcdInfoFromMapFile(mapfilepath
, efifilepath
):
37 """ Parse map file to get binary patch pcd information
38 @param path Map file absolution path
40 @return a list which element hold (PcdName, Offset, SectionName)
44 f
= open(mapfilepath
, 'r')
50 if len(lines
) == 0: return None
51 firstline
= lines
[0].strip()
52 if re
.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', firstline
):
53 return _parseForXcodeAndClang9(lines
, efifilepath
)
54 if (firstline
.startswith("Archive member included ") and
55 firstline
.endswith(" file (symbol)")):
56 return _parseForGCC(lines
, efifilepath
)
57 if firstline
.startswith("# Path:"):
58 return _parseForXcodeAndClang9(lines
, efifilepath
)
59 return _parseGeneral(lines
, efifilepath
)
61 def _parseForXcodeAndClang9(lines
, efifilepath
):
62 valuePattern
= re
.compile('^([\da-fA-FxX]+)([\s\S]*)([_]*_gPcd_BinaryPatch_([\w]+))')
67 if status
== 0 and (re
.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', line
) \
68 or line
== "# Symbols:"):
71 if status
== 1 and len(line
) != 0:
72 if '_gPcd_BinaryPatch_' in line
:
73 m
= valuePattern
.match(line
)
75 pcds
.append((m
.groups(0)[3], int(m
.groups(0)[0], 16)))
78 def _parseForGCC(lines
, efifilepath
):
79 """ Parse map file generated by GCC linker """
80 dataPattern
= re
.compile('^.data._gPcd_BinaryPatch_([\w_\d]+)$')
85 for index
, line
in enumerate(lines
):
87 # status machine transection
88 if status
== 0 and line
== "Memory Configuration":
91 elif status
== 1 and line
== 'Linker script and memory map':
94 elif status
==2 and line
== 'START GROUP':
100 m
= valuePatternGcc
.match(line
)
102 sections
.append(m
.groups(0))
104 m
= dataPattern
.match(line
)
107 PcdName
= m
.groups(0)[0]
108 m
= pcdPatternGcc
.match(lines
[index
+ 1].strip())
110 bpcds
.append((PcdName
, int(m
.groups(0)[0], 16), int(sections
[-1][1], 16), sections
[-1][0]))
112 # get section information from efi file
113 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
114 if efisecs
is None or len(efisecs
) == 0:
118 for efisec
in efisecs
:
119 for section
in sections
:
120 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
121 redirection
= int(section
[1], 16) - efisec
[1]
124 for efisec
in efisecs
:
125 if pcd
[1] >= efisec
[1] and pcd
[1] < efisec
[1]+efisec
[3]:
126 #assert efisec[0].strip() == pcd[3].strip() and efisec[1] + redirection == pcd[2], "There are some differences between map file and efi file"
127 pcds
.append([pcd
[0], efisec
[2] + pcd
[1] - efisec
[1] - redirection
, efisec
[0]])
130 def _parseGeneral(lines
, efifilepath
):
131 """ For MSFT, ICC, EBC
132 @param lines line array for map file
134 @return a list which element hold (PcdName, Offset, SectionName)
136 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
137 secs
= [] # key = section name
139 symPattern
= re
.compile('^[_]+gPcd_BinaryPatch_([\w]+)')
143 if startPatternGeneral
.match(line
):
146 if addressPatternGeneral
.match(line
):
149 if line
.startswith("entry point at"):
152 if status
== 1 and len(line
) != 0:
153 m
= secReGeneral
.match(line
)
154 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
155 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
156 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
157 if status
== 2 and len(line
) != 0:
158 m
= symRe
.match(line
)
159 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
160 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
161 sec_no
= int(sec_no
, 16)
162 sym_offset
= int(sym_offset
, 16)
163 vir_addr
= int(vir_addr
, 16)
164 m2
= symPattern
.match(sym_name
)
166 # fond a binary pcd entry in map file
168 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
169 bPcds
.append([m2
.groups(0)[0], sec
[3], sym_offset
, vir_addr
, sec_no
])
171 if len(bPcds
) == 0: return None
173 # get section information from efi file
174 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
175 if efisecs
is None or len(efisecs
) == 0:
181 for efisec
in efisecs
:
183 if pcd
[1].strip() == efisec
[0].strip():
184 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
185 elif pcd
[4] == index
:
186 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
189 def generatePcdTable(list, pcdpath
):
191 f
= open(pcdpath
, 'w')
195 f
.write('PCD Name Offset Section Name\r\n')
198 f
.write('%-30s 0x%-08X %-6s\r\n' % (pcditem
[0], pcditem
[1], pcditem
[2]))
201 #print 'Success to generate Binary Patch PCD table at %s!' % pcdpath
203 if __name__
== '__main__':
204 UsageString
= "%prog -m <MapFile> -e <EfiFile> -o <OutFile>"
205 AdditionalNotes
= "\nPCD table is generated in file name with .BinaryPcdTable.txt postfix"
206 parser
= optparse
.OptionParser(description
=__copyright__
, version
=__version__
, usage
=UsageString
)
207 parser
.add_option('-m', '--mapfile', action
='store', dest
='mapfile',
208 help='Absolute path of module map file.')
209 parser
.add_option('-e', '--efifile', action
='store', dest
='efifile',
210 help='Absolute path of EFI binary file.')
211 parser
.add_option('-o', '--outputfile', action
='store', dest
='outfile',
212 help='Absolute path of output file to store the got patchable PCD table.')
214 (options
, args
) = parser
.parse_args()
216 if options
.mapfile
is None or options
.efifile
is None:
217 print(parser
.get_usage())
218 elif os
.path
.exists(options
.mapfile
) and os
.path
.exists(options
.efifile
):
219 list = parsePcdInfoFromMapFile(options
.mapfile
, options
.efifile
)
221 if options
.outfile
is not None:
222 generatePcdTable(list, options
.outfile
)
224 generatePcdTable(list, options
.mapfile
.replace('.map', '.BinaryPcdTable.txt'))
226 print('Fail to generate Patch PCD Table based on map file and efi file')
228 print('Fail to generate Patch PCD Table for fail to find map file or efi file!')