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 # SPDX-License-Identifier: BSD-2-Clause-Patent
11 from __future__
import print_function
15 from optparse
import OptionParser
18 __copyright__
= "Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved."
22 self
.listLineAddress
= []
25 self
.functionName
= ""
30 def getSymbol (self
, rva
):
34 while index
+ 1 < self
.lineCount
:
35 if self
.listLineAddress
[index
][0] <= rva
and self
.listLineAddress
[index
+ 1][0] > rva
:
36 offset
= rva
- self
.listLineAddress
[index
][0]
37 functionName
= self
.listLineAddress
[index
][1]
38 lineName
= self
.listLineAddress
[index
][2]
39 sourceName
= self
.listLineAddress
[index
][3]
41 return " (" + self
.listLineAddress
[index
][1] + "() - " + ")"
43 return " (" + self
.listLineAddress
[index
][1] + "() - " + sourceName
+ ":" + str(lineName
) + ")"
48 def parse_debug_file(self
, driverName
, pdbName
):
49 if cmp (pdbName
, "") == 0 :
51 self
.pdbName
= pdbName
;
56 print("parsing (debug) - " + pdbName
)
57 os
.system ('%s %s %s > nmDump.line.log' % (nmCommand
, nmLineOption
, pdbName
))
59 print('ERROR: nm command not available. Please verify PATH')
65 linefile
= open("nmDump.line.log")
66 reportLines
= linefile
.readlines()
69 # 000113ca T AllocatePool c:\home\edk-ii\MdePkg\Library\UefiMemoryAllocationLib\MemoryAllocationLib.c:399
70 patchLineFileMatchString
= "([0-9a-fA-F]*)\s+[T|D|t|d]\s+(\w+)\s*((?:[a-zA-Z]:)?[\w+\-./_a-zA-Z0-9\\\\]*):?([0-9]*)"
72 for reportLine
in reportLines
:
73 #print "check - " + reportLine
74 match
= re
.match(patchLineFileMatchString
, reportLine
)
76 #print "match - " + reportLine[:-1]
77 #print "0 - " + match.group(0)
78 #print "1 - " + match.group(1)
79 #print "2 - " + match.group(2)
80 #print "3 - " + match.group(3)
81 #print "4 - " + match.group(4)
83 rva
= int (match
.group(1), 16)
84 functionName
= match
.group(2)
85 sourceName
= match
.group(3)
86 if cmp (match
.group(4), "") != 0 :
87 lineName
= int (match
.group(4))
90 self
.listLineAddress
.append ([rva
, functionName
, lineName
, sourceName
])
92 self
.lineCount
= len (self
.listLineAddress
)
94 self
.listLineAddress
= sorted(self
.listLineAddress
, key
=lambda symbolAddress
:symbolAddress
[0])
96 #for key in self.listLineAddress :
97 #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]
99 def parse_pdb_file(self
, driverName
, pdbName
):
100 if cmp (pdbName
, "") == 0 :
102 self
.pdbName
= pdbName
;
105 #DIA2DumpCommand = "\"C:\\Program Files (x86)\Microsoft Visual Studio 14.0\\DIA SDK\\Samples\\DIA2Dump\\x64\\Debug\\Dia2Dump.exe\""
106 DIA2DumpCommand
= "Dia2Dump.exe"
107 #DIA2SymbolOption = "-p"
108 DIA2LinesOption
= "-l"
109 print("parsing (pdb) - " + pdbName
)
110 #os.system ('%s %s %s > DIA2Dump.symbol.log' % (DIA2DumpCommand, DIA2SymbolOption, pdbName))
111 os
.system ('%s %s %s > DIA2Dump.line.log' % (DIA2DumpCommand
, DIA2LinesOption
, pdbName
))
113 print('ERROR: DIA2Dump command not available. Please verify PATH')
119 linefile
= open("DIA2Dump.line.log")
120 reportLines
= linefile
.readlines()
123 # ** GetDebugPrintErrorLevel
124 # line 32 at [0000C790][0001:0000B790], len = 0x3 c:\home\edk-ii\mdepkg\library\basedebugprinterrorlevellib\basedebugprinterrorlevellib.c (MD5: 687C0AE564079D35D56ED5D84A6164CC)
125 # line 36 at [0000C793][0001:0000B793], len = 0x5
126 # line 37 at [0000C798][0001:0000B798], len = 0x2
128 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*"
129 patchLineFileMatchStringFunc
= "\*\*\s+(\w+)\s*"
131 for reportLine
in reportLines
:
132 #print "check line - " + reportLine
133 match
= re
.match(patchLineFileMatchString
, reportLine
)
134 if match
is not None:
135 #print "match - " + reportLine[:-1]
136 #print "0 - " + match.group(0)
137 #print "1 - " + match.group(1)
138 #print "2 - " + match.group(2)
139 if cmp (match
.group(3), "") != 0 :
140 self
.sourceName
= match
.group(3)
141 sourceName
= self
.sourceName
142 functionName
= self
.functionName
144 rva
= int (match
.group(2), 16)
145 lineName
= int (match
.group(1))
146 self
.listLineAddress
.append ([rva
, functionName
, lineName
, sourceName
])
148 match
= re
.match(patchLineFileMatchStringFunc
, reportLine
)
149 if match
is not None:
150 self
.functionName
= match
.group(1)
152 self
.lineCount
= len (self
.listLineAddress
)
153 self
.listLineAddress
= sorted(self
.listLineAddress
, key
=lambda symbolAddress
:symbolAddress
[0])
155 #for key in self.listLineAddress :
156 #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]
160 self
.symbolsTable
= {}
168 def getSymbolName(driverName
, rva
):
171 #print "driverName - " + driverName
174 symbolList
= symbolsFile
.symbolsTable
[driverName
]
175 if symbolList
is not None:
176 return symbolList
.getSymbol (rva
)
182 def processLine(newline
):
186 driverPrefixLen
= len("Driver - ")
188 if cmp(newline
[0:driverPrefixLen
], "Driver - ") == 0 :
189 driverlineList
= newline
.split(" ")
190 driverName
= driverlineList
[2]
191 #print "Checking : ", driverName
193 # EDKII application output
194 pdbMatchString
= "Driver - \w* \(Usage - 0x[0-9a-fA-F]+\) \(Pdb - ([:\-.\w\\\\/]*)\)\s*"
196 match
= re
.match(pdbMatchString
, newline
)
197 if match
is not None:
198 #print "match - " + newline
199 #print "0 - " + match.group(0)
200 #print "1 - " + match.group(1)
201 pdbName
= match
.group(1)
202 #print "PDB - " + pdbName
204 symbolsFile
.symbolsTable
[driverName
] = Symbols()
206 if cmp (pdbName
[-3:], "pdb") == 0 :
207 symbolsFile
.symbolsTable
[driverName
].parse_pdb_file (driverName
, pdbName
)
209 symbolsFile
.symbolsTable
[driverName
].parse_debug_file (driverName
, pdbName
)
211 elif cmp(newline
, "") == 0 :
215 if newline
.find ("<==") != -1 :
216 entry_list
= newline
.split(" ")
217 rvaName
= entry_list
[4]
218 #print "rva : ", rvaName
219 symbolName
= getSymbolName (driverName
, int(rvaName
, 16))
224 if cmp(rvaName
, "") == 0 :
227 return newline
+ symbolName
229 def myOptionParser():
230 usage
= "%prog [--version] [-h] [--help] [-i inputfile [-o outputfile]]"
231 Parser
= OptionParser(usage
=usage
, description
=__copyright__
, version
="%prog " + str(versionNumber
))
232 Parser
.add_option("-i", "--inputfile", dest
="inputfilename", type="string", help="The input memory profile info file output from MemoryProfileInfo application in MdeModulePkg")
233 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")
235 (Options
, args
) = Parser
.parse_args()
236 if Options
.inputfilename
is None:
237 Parser
.error("no input file specified")
238 if Options
.outputfilename
is None:
239 Options
.outputfilename
= "MemoryProfileInfoSymbol.txt"
245 Options
= myOptionParser()
247 symbolsFile
= SymbolsFile()
250 file = open(Options
.inputfilename
)
252 print("fail to open " + Options
.inputfilename
)
255 newfile
= open(Options
.outputfilename
, "w")
257 print("fail to open " + Options
.outputfilename
)
262 line
= file.readline()
267 newline
= processLine(newline
)
269 newfile
.write(newline
)
275 if __name__
== '__main__':