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 - 2018, 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.
17 from __future__
import print_function
21 from optparse
import OptionParser
24 __copyright__
= "Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved."
28 self
.listLineAddress
= []
31 self
.functionName
= ""
36 def getSymbol (self
, rva
):
40 while index
+ 1 < self
.lineCount
:
41 if self
.listLineAddress
[index
][0] <= rva
and self
.listLineAddress
[index
+ 1][0] > rva
:
42 offset
= rva
- self
.listLineAddress
[index
][0]
43 functionName
= self
.listLineAddress
[index
][1]
44 lineName
= self
.listLineAddress
[index
][2]
45 sourceName
= self
.listLineAddress
[index
][3]
47 return " (" + self
.listLineAddress
[index
][1] + "() - " + ")"
49 return " (" + self
.listLineAddress
[index
][1] + "() - " + sourceName
+ ":" + str(lineName
) + ")"
54 def parse_debug_file(self
, driverName
, pdbName
):
55 if cmp (pdbName
, "") == 0 :
57 self
.pdbName
= pdbName
;
62 print("parsing (debug) - " + pdbName
)
63 os
.system ('%s %s %s > nmDump.line.log' % (nmCommand
, nmLineOption
, pdbName
))
65 print('ERROR: nm command not available. Please verify PATH')
71 linefile
= open("nmDump.line.log")
72 reportLines
= linefile
.readlines()
75 # 000113ca T AllocatePool c:\home\edk-ii\MdePkg\Library\UefiMemoryAllocationLib\MemoryAllocationLib.c:399
76 patchLineFileMatchString
= "([0-9a-fA-F]*)\s+[T|D|t|d]\s+(\w+)\s*((?:[a-zA-Z]:)?[\w+\-./_a-zA-Z0-9\\\\]*):?([0-9]*)"
78 for reportLine
in reportLines
:
79 #print "check - " + reportLine
80 match
= re
.match(patchLineFileMatchString
, reportLine
)
82 #print "match - " + reportLine[:-1]
83 #print "0 - " + match.group(0)
84 #print "1 - " + match.group(1)
85 #print "2 - " + match.group(2)
86 #print "3 - " + match.group(3)
87 #print "4 - " + match.group(4)
89 rva
= int (match
.group(1), 16)
90 functionName
= match
.group(2)
91 sourceName
= match
.group(3)
92 if cmp (match
.group(4), "") != 0 :
93 lineName
= int (match
.group(4))
96 self
.listLineAddress
.append ([rva
, functionName
, lineName
, sourceName
])
98 self
.lineCount
= len (self
.listLineAddress
)
100 self
.listLineAddress
= sorted(self
.listLineAddress
, key
=lambda symbolAddress
:symbolAddress
[0])
102 #for key in self.listLineAddress :
103 #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]
105 def parse_pdb_file(self
, driverName
, pdbName
):
106 if cmp (pdbName
, "") == 0 :
108 self
.pdbName
= pdbName
;
111 #DIA2DumpCommand = "\"C:\\Program Files (x86)\Microsoft Visual Studio 14.0\\DIA SDK\\Samples\\DIA2Dump\\x64\\Debug\\Dia2Dump.exe\""
112 DIA2DumpCommand
= "Dia2Dump.exe"
113 #DIA2SymbolOption = "-p"
114 DIA2LinesOption
= "-l"
115 print("parsing (pdb) - " + pdbName
)
116 #os.system ('%s %s %s > DIA2Dump.symbol.log' % (DIA2DumpCommand, DIA2SymbolOption, pdbName))
117 os
.system ('%s %s %s > DIA2Dump.line.log' % (DIA2DumpCommand
, DIA2LinesOption
, pdbName
))
119 print('ERROR: DIA2Dump command not available. Please verify PATH')
125 linefile
= open("DIA2Dump.line.log")
126 reportLines
= linefile
.readlines()
129 # ** GetDebugPrintErrorLevel
130 # line 32 at [0000C790][0001:0000B790], len = 0x3 c:\home\edk-ii\mdepkg\library\basedebugprinterrorlevellib\basedebugprinterrorlevellib.c (MD5: 687C0AE564079D35D56ED5D84A6164CC)
131 # line 36 at [0000C793][0001:0000B793], len = 0x5
132 # line 37 at [0000C798][0001:0000B798], len = 0x2
134 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*"
135 patchLineFileMatchStringFunc
= "\*\*\s+(\w+)\s*"
137 for reportLine
in reportLines
:
138 #print "check line - " + reportLine
139 match
= re
.match(patchLineFileMatchString
, reportLine
)
140 if match
is not None:
141 #print "match - " + reportLine[:-1]
142 #print "0 - " + match.group(0)
143 #print "1 - " + match.group(1)
144 #print "2 - " + match.group(2)
145 if cmp (match
.group(3), "") != 0 :
146 self
.sourceName
= match
.group(3)
147 sourceName
= self
.sourceName
148 functionName
= self
.functionName
150 rva
= int (match
.group(2), 16)
151 lineName
= int (match
.group(1))
152 self
.listLineAddress
.append ([rva
, functionName
, lineName
, sourceName
])
154 match
= re
.match(patchLineFileMatchStringFunc
, reportLine
)
155 if match
is not None:
156 self
.functionName
= match
.group(1)
158 self
.lineCount
= len (self
.listLineAddress
)
159 self
.listLineAddress
= sorted(self
.listLineAddress
, key
=lambda symbolAddress
:symbolAddress
[0])
161 #for key in self.listLineAddress :
162 #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]
166 self
.symbolsTable
= {}
174 def getSymbolName(driverName
, rva
):
177 #print "driverName - " + driverName
180 symbolList
= symbolsFile
.symbolsTable
[driverName
]
181 if symbolList
is not None:
182 return symbolList
.getSymbol (rva
)
188 def processLine(newline
):
192 driverPrefixLen
= len("Driver - ")
194 if cmp(newline
[0:driverPrefixLen
], "Driver - ") == 0 :
195 driverlineList
= newline
.split(" ")
196 driverName
= driverlineList
[2]
197 #print "Checking : ", driverName
199 # EDKII application output
200 pdbMatchString
= "Driver - \w* \(Usage - 0x[0-9a-fA-F]+\) \(Pdb - ([:\-.\w\\\\/]*)\)\s*"
202 match
= re
.match(pdbMatchString
, newline
)
203 if match
is not None:
204 #print "match - " + newline
205 #print "0 - " + match.group(0)
206 #print "1 - " + match.group(1)
207 pdbName
= match
.group(1)
208 #print "PDB - " + pdbName
210 symbolsFile
.symbolsTable
[driverName
] = Symbols()
212 if cmp (pdbName
[-3:], "pdb") == 0 :
213 symbolsFile
.symbolsTable
[driverName
].parse_pdb_file (driverName
, pdbName
)
215 symbolsFile
.symbolsTable
[driverName
].parse_debug_file (driverName
, pdbName
)
217 elif cmp(newline
, "") == 0 :
221 if newline
.find ("<==") != -1 :
222 entry_list
= newline
.split(" ")
223 rvaName
= entry_list
[4]
224 #print "rva : ", rvaName
225 symbolName
= getSymbolName (driverName
, int(rvaName
, 16))
230 if cmp(rvaName
, "") == 0 :
233 return newline
+ symbolName
235 def myOptionParser():
236 usage
= "%prog [--version] [-h] [--help] [-i inputfile [-o outputfile]]"
237 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
238 Parser
.add_option("-i", "--inputfile", dest
="inputfilename", type="string", help="The input memory profile info file output from MemoryProfileInfo application in MdeModulePkg")
239 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")
241 (Options
, args
) = Parser
.parse_args()
242 if Options
.inputfilename
is None:
243 Parser
.error("no input file specified")
244 if Options
.outputfilename
is None:
245 Options
.outputfilename
= "MemoryProfileInfoSymbol.txt"
251 Options
= myOptionParser()
253 symbolsFile
= SymbolsFile()
256 file = open(Options
.inputfilename
)
258 print("fail to open " + Options
.inputfilename
)
261 newfile
= open(Options
.outputfilename
, "w")
263 print("fail to open " + Options
.outputfilename
)
268 line
= file.readline()
273 newline
= processLine(newline
)
275 newfile
.write(newline
)
281 if __name__
== '__main__':