]>
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 (firstline
.startswith("Archive member included ") and
53 firstline
.endswith(" file (symbol)")):
54 return _parseForGCC(lines
, efifilepath
)
55 if firstline
.startswith("# Path:"):
56 return _parseForXcode(lines
, efifilepath
)
57 return _parseGeneral(lines
, efifilepath
)
59 def _parseForXcode(lines
, efifilepath
):
60 valuePattern
= re
.compile('^([\da-fA-FxX]+)([\s\S]*)([_]*_gPcd_BinaryPatch_([\w]+))')
65 if status
== 0 and line
== "# Symbols:":
68 if status
== 1 and len(line
) != 0:
69 if '_gPcd_BinaryPatch_' in line
:
70 m
= valuePattern
.match(line
)
72 pcds
.append((m
.groups(0)[3], int(m
.groups(0)[0], 16)))
75 def _parseForGCC(lines
, efifilepath
):
76 """ Parse map file generated by GCC linker """
77 dataPattern
= re
.compile('^.data._gPcd_BinaryPatch_([\w_\d]+)$')
82 for index
, line
in enumerate(lines
):
84 # status machine transection
85 if status
== 0 and line
== "Memory Configuration":
88 elif status
== 1 and line
== 'Linker script and memory map':
91 elif status
==2 and line
== 'START GROUP':
97 m
= valuePatternGcc
.match(line
)
99 sections
.append(m
.groups(0))
101 m
= dataPattern
.match(line
)
104 PcdName
= m
.groups(0)[0]
105 m
= pcdPatternGcc
.match(lines
[index
+ 1].strip())
107 bpcds
.append((PcdName
, int(m
.groups(0)[0], 16), int(sections
[-1][1], 16), sections
[-1][0]))
109 # get section information from efi file
110 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
111 if efisecs
is None or len(efisecs
) == 0:
115 for efisec
in efisecs
:
116 for section
in sections
:
117 if section
[0].strip() == efisec
[0].strip() and section
[0].strip() == '.text':
118 redirection
= int(section
[1], 16) - efisec
[1]
121 for efisec
in efisecs
:
122 if pcd
[1] >= efisec
[1] and pcd
[1] < efisec
[1]+efisec
[3]:
123 #assert efisec[0].strip() == pcd[3].strip() and efisec[1] + redirection == pcd[2], "There are some differences between map file and efi file"
124 pcds
.append([pcd
[0], efisec
[2] + pcd
[1] - efisec
[1] - redirection
, efisec
[0]])
127 def _parseGeneral(lines
, efifilepath
):
128 """ For MSFT, ICC, EBC
129 @param lines line array for map file
131 @return a list which element hold (PcdName, Offset, SectionName)
133 status
= 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
134 secs
= [] # key = section name
136 symPattern
= re
.compile('^[_]+gPcd_BinaryPatch_([\w]+)')
140 if startPatternGeneral
.match(line
):
143 if addressPatternGeneral
.match(line
):
146 if line
.startswith("entry point at"):
149 if status
== 1 and len(line
) != 0:
150 m
= secReGeneral
.match(line
)
151 assert m
is not None, "Fail to parse the section in map file , line is %s" % line
152 sec_no
, sec_start
, sec_length
, sec_name
, sec_class
= m
.groups(0)
153 secs
.append([int(sec_no
, 16), int(sec_start
, 16), int(sec_length
, 16), sec_name
, sec_class
])
154 if status
== 2 and len(line
) != 0:
155 m
= symRe
.match(line
)
156 assert m
is not None, "Fail to parse the symbol in map file, line is %s" % line
157 sec_no
, sym_offset
, sym_name
, vir_addr
= m
.groups(0)
158 sec_no
= int(sec_no
, 16)
159 sym_offset
= int(sym_offset
, 16)
160 vir_addr
= int(vir_addr
, 16)
161 m2
= symPattern
.match(sym_name
)
163 # fond a binary pcd entry in map file
165 if sec
[0] == sec_no
and (sym_offset
>= sec
[1] and sym_offset
< sec
[1] + sec
[2]):
166 bPcds
.append([m2
.groups(0)[0], sec
[3], sym_offset
, vir_addr
, sec_no
])
168 if len(bPcds
) == 0: return None
170 # get section information from efi file
171 efisecs
= PeImageClass(efifilepath
).SectionHeaderList
172 if efisecs
is None or len(efisecs
) == 0:
178 for efisec
in efisecs
:
180 if pcd
[1].strip() == efisec
[0].strip():
181 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
182 elif pcd
[4] == index
:
183 pcds
.append([pcd
[0], efisec
[2] + pcd
[2], efisec
[0]])
186 def generatePcdTable(list, pcdpath
):
188 f
= open(pcdpath
, 'w')
192 f
.write('PCD Name Offset Section Name\r\n')
195 f
.write('%-30s 0x%-08X %-6s\r\n' % (pcditem
[0], pcditem
[1], pcditem
[2]))
198 #print 'Success to generate Binary Patch PCD table at %s!' % pcdpath
200 if __name__
== '__main__':
201 UsageString
= "%prog -m <MapFile> -e <EfiFile> -o <OutFile>"
202 AdditionalNotes
= "\nPCD table is generated in file name with .BinaryPcdTable.txt postfix"
203 parser
= optparse
.OptionParser(description
=__copyright__
, version
=__version__
, usage
=UsageString
)
204 parser
.add_option('-m', '--mapfile', action
='store', dest
='mapfile',
205 help='Absolute path of module map file.')
206 parser
.add_option('-e', '--efifile', action
='store', dest
='efifile',
207 help='Absolute path of EFI binary file.')
208 parser
.add_option('-o', '--outputfile', action
='store', dest
='outfile',
209 help='Absolute path of output file to store the got patchable PCD table.')
211 (options
, args
) = parser
.parse_args()
213 if options
.mapfile
is None or options
.efifile
is None:
214 print(parser
.get_usage())
215 elif os
.path
.exists(options
.mapfile
) and os
.path
.exists(options
.efifile
):
216 list = parsePcdInfoFromMapFile(options
.mapfile
, options
.efifile
)
218 if options
.outfile
is not None:
219 generatePcdTable(list, options
.outfile
)
221 generatePcdTable(list, options
.mapfile
.replace('.map', '.BinaryPcdTable.txt'))
223 print('Fail to generate Patch PCD Table based on map file and efi file')
225 print('Fail to generate Patch PCD Table for fail to find map file or efi file!')