2 # Generate symbal for memory profile info.
4 # This tool depends on DIA2Dump.exe (VS) or nm (gcc) to parse debug entry.
6 # Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
7 # This program and the accompanying materials are licensed and made available under
8 # the terms and conditions of the BSD License that accompanies this distribution.
9 # The full text of the license may be found at
10 # http://opensource.org/licenses/bsd-license.php.
12 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 from optparse
import OptionParser
23 __copyright__
= "Copyright (c) 2016, Intel Corporation. All rights reserved."
27 self
.listLineAddress
= []
30 self
.functionName
= ""
35 def getSymbol (self
, rva
):
39 while index
+ 1 < self
.lineCount
:
40 if self
.listLineAddress
[index
][0] <= rva
and self
.listLineAddress
[index
+ 1][0] > rva
:
41 offset
= rva
- self
.listLineAddress
[index
][0]
42 functionName
= self
.listLineAddress
[index
][1]
43 lineName
= self
.listLineAddress
[index
][2]
44 sourceName
= self
.listLineAddress
[index
][3]
46 return " (" + self
.listLineAddress
[index
][1] + "() - " + ")"
48 return " (" + self
.listLineAddress
[index
][1] + "() - " + sourceName
+ ":" + str(lineName
) + ")"
53 def parse_debug_file(self
, driverName
, pdbName
):
54 if cmp (pdbName
, "") == 0 :
56 self
.pdbName
= pdbName
;
61 print "parsing (debug) - " + pdbName
62 os
.system ('%s %s %s > nmDump.line.log' % (nmCommand
, nmLineOption
, pdbName
))
64 print 'ERROR: nm command not available. Please verify PATH'
70 linefile
= open("nmDump.line.log")
71 reportLines
= linefile
.readlines()
74 # 000113ca T AllocatePool c:\home\edk-ii\MdePkg\Library\UefiMemoryAllocationLib\MemoryAllocationLib.c:399
75 patchLineFileMatchString
= "([0-9a-fA-F]*)\s+[T|D|t|d]\s+(\w+)\s*((?:[a-zA-Z]:)?[\w+\-./_a-zA-Z0-9\\\\]*):?([0-9]*)"
77 for reportLine
in reportLines
:
78 #print "check - " + reportLine
79 match
= re
.match(patchLineFileMatchString
, reportLine
)
81 #print "match - " + reportLine[:-1]
82 #print "0 - " + match.group(0)
83 #print "1 - " + match.group(1)
84 #print "2 - " + match.group(2)
85 #print "3 - " + match.group(3)
86 #print "4 - " + match.group(4)
88 rva
= int (match
.group(1), 16)
89 functionName
= match
.group(2)
90 sourceName
= match
.group(3)
91 if cmp (match
.group(4), "") != 0 :
92 lineName
= int (match
.group(4))
95 self
.listLineAddress
.append ([rva
, functionName
, lineName
, sourceName
])
97 self
.lineCount
= len (self
.listLineAddress
)
99 self
.listLineAddress
= sorted(self
.listLineAddress
, key
=lambda symbolAddress
:symbolAddress
[0])
101 #for key in self.listLineAddress :
102 #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]
104 def parse_pdb_file(self
, driverName
, pdbName
):
105 if cmp (pdbName
, "") == 0 :
107 self
.pdbName
= pdbName
;
110 #DIA2DumpCommand = "\"C:\\Program Files (x86)\Microsoft Visual Studio 14.0\\DIA SDK\\Samples\\DIA2Dump\\x64\\Debug\\Dia2Dump.exe\""
111 DIA2DumpCommand
= "Dia2Dump.exe"
112 #DIA2SymbolOption = "-p"
113 DIA2LinesOption
= "-l"
114 print "parsing (pdb) - " + pdbName
115 #os.system ('%s %s %s > DIA2Dump.symbol.log' % (DIA2DumpCommand, DIA2SymbolOption, pdbName))
116 os
.system ('%s %s %s > DIA2Dump.line.log' % (DIA2DumpCommand
, DIA2LinesOption
, pdbName
))
118 print 'ERROR: DIA2Dump command not available. Please verify PATH'
124 linefile
= open("DIA2Dump.line.log")
125 reportLines
= linefile
.readlines()
128 # ** GetDebugPrintErrorLevel
129 # line 32 at [0000C790][0001:0000B790], len = 0x3 c:\home\edk-ii\mdepkg\library\basedebugprinterrorlevellib\basedebugprinterrorlevellib.c (MD5: 687C0AE564079D35D56ED5D84A6164CC)
130 # line 36 at [0000C793][0001:0000B793], len = 0x5
131 # line 37 at [0000C798][0001:0000B798], len = 0x2
133 patchLineFileMatchString
= "\s+line ([0-9]+) at \[([0-9a-fA-F]{8})\]\[[0-9a-fA-F]{4}\:[0-9a-fA-F]{8}\], len = 0x[0-9a-fA-F]+\s*([\w+\-\:./_a-zA-Z0-9\\\\]*)\s*"
134 patchLineFileMatchStringFunc
= "\*\*\s+(\w+)\s*"
136 for reportLine
in reportLines
:
137 #print "check line - " + reportLine
138 match
= re
.match(patchLineFileMatchString
, reportLine
)
139 if match
is not None:
140 #print "match - " + reportLine[:-1]
141 #print "0 - " + match.group(0)
142 #print "1 - " + match.group(1)
143 #print "2 - " + match.group(2)
144 if cmp (match
.group(3), "") != 0 :
145 self
.sourceName
= match
.group(3)
146 sourceName
= self
.sourceName
147 functionName
= self
.functionName
149 rva
= int (match
.group(2), 16)
150 lineName
= int (match
.group(1))
151 self
.listLineAddress
.append ([rva
, functionName
, lineName
, sourceName
])
153 match
= re
.match(patchLineFileMatchStringFunc
, reportLine
)
154 if match
is not None:
155 self
.functionName
= match
.group(1)
157 self
.lineCount
= len (self
.listLineAddress
)
158 self
.listLineAddress
= sorted(self
.listLineAddress
, key
=lambda symbolAddress
:symbolAddress
[0])
160 #for key in self.listLineAddress :
161 #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]
165 self
.symbolsTable
= {}
173 def getSymbolName(driverName
, rva
):
176 #print "driverName - " + driverName
179 symbolList
= symbolsFile
.symbolsTable
[driverName
]
180 if symbolList
is not None:
181 return symbolList
.getSymbol (rva
)
187 def processLine(newline
):
191 driverPrefixLen
= len("Driver - ")
193 if cmp(newline
[0:driverPrefixLen
],"Driver - ") == 0 :
194 driverlineList
= newline
.split(" ")
195 driverName
= driverlineList
[2]
196 #print "Checking : ", driverName
198 # EDKII application output
199 pdbMatchString
= "Driver - \w* \(Usage - 0x[0-9a-fA-F]+\) \(Pdb - ([:\-.\w\\\\/]*)\)\s*"
201 match
= re
.match(pdbMatchString
, newline
)
202 if match
is not None:
203 #print "match - " + newline
204 #print "0 - " + match.group(0)
205 #print "1 - " + match.group(1)
206 pdbName
= match
.group(1)
207 #print "PDB - " + pdbName
209 symbolsFile
.symbolsTable
[driverName
] = Symbols()
211 if cmp (pdbName
[-3:], "pdb") == 0 :
212 symbolsFile
.symbolsTable
[driverName
].parse_pdb_file (driverName
, pdbName
)
214 symbolsFile
.symbolsTable
[driverName
].parse_debug_file (driverName
, pdbName
)
216 elif cmp(newline
,"") == 0 :
220 if newline
.find ("<==") != -1 :
221 entry_list
= newline
.split(" ")
222 rvaName
= entry_list
[4]
223 #print "rva : ", rvaName
224 symbolName
= getSymbolName (driverName
, int(rvaName
, 16))
229 if cmp(rvaName
,"") == 0 :
232 return newline
+ symbolName
234 def myOptionParser():
235 usage
= "%prog [--version] [-h] [--help] [-i inputfile [-o outputfile]]"
236 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
237 Parser
.add_option("-i", "--inputfile", dest
="inputfilename", type="string", help="The input memory profile info file output from MemoryProfileInfo application in MdeModulePkg")
238 Parser
.add_option("-o", "--outputfile", dest
="outputfilename", type="string", help="The output memory profile info file with symbol, MemoryProfileInfoSymbol.txt will be used if it is not specified")
240 (Options
, args
) = Parser
.parse_args()
241 if Options
.inputfilename
is None:
242 Parser
.error("no input file specified")
243 if Options
.outputfilename
is None:
244 Options
.outputfilename
= "MemoryProfileInfoSymbol.txt"
250 Options
= myOptionParser()
252 symbolsFile
= SymbolsFile()
255 file = open(Options
.inputfilename
)
257 print "fail to open " + Options
.inputfilename
260 newfile
= open(Options
.outputfilename
, "w")
262 print "fail to open " + Options
.outputfilename
267 line
= file.readline()
272 newline
= processLine(newline
)
274 newfile
.write(newline
)
280 if __name__
== '__main__':