]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Scripts/MemoryProfileSymbolGen.py
BaseTools/BinToPcd: Follow PEP-8 indent of 4 spaces
[mirror_edk2.git] / BaseTools / Scripts / MemoryProfileSymbolGen.py
CommitLineData
1d9869f9
SZ
1##\r
2# Generate symbal for memory profile info.\r
3#\r
4# This tool depends on DIA2Dump.exe (VS) or nm (gcc) to parse debug entry.\r
5#\r
6# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
7# This program and the accompanying materials are licensed and made available under\r
8# the terms and conditions of the BSD License that accompanies this distribution.\r
9# The full text of the license may be found at\r
10# http://opensource.org/licenses/bsd-license.php.\r
11#\r
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14#\r
15##\r
16\r
17import os\r
18import re\r
19import sys\r
20from optparse import OptionParser\r
21\r
d84577e5 22versionNumber = "1.1"\r
1d9869f9
SZ
23__copyright__ = "Copyright (c) 2016, Intel Corporation. All rights reserved."\r
24\r
25class Symbols:\r
26 def __init__(self):\r
27 self.listLineAddress = []\r
28 self.pdbName = ""\r
29 # Cache for function\r
30 self.functionName = ""\r
31 # Cache for line\r
32 self.sourceName = ""\r
33\r
34\r
35 def getSymbol (self, rva):\r
36 index = 0\r
37 lineName = 0\r
38 sourceName = "??"\r
39 while index + 1 < self.lineCount :\r
40 if self.listLineAddress[index][0] <= rva and self.listLineAddress[index + 1][0] > rva :\r
41 offset = rva - self.listLineAddress[index][0]\r
42 functionName = self.listLineAddress[index][1]\r
43 lineName = self.listLineAddress[index][2]\r
44 sourceName = self.listLineAddress[index][3]\r
45 if lineName == 0 :\r
46 return " (" + self.listLineAddress[index][1] + "() - " + ")"\r
47 else :\r
48 return " (" + self.listLineAddress[index][1] + "() - " + sourceName + ":" + str(lineName) + ")"\r
49 index += 1\r
50\r
51 return " (unknown)"\r
52\r
53 def parse_debug_file(self, driverName, pdbName):\r
54 if cmp (pdbName, "") == 0 :\r
55 return\r
56 self.pdbName = pdbName;\r
57\r
58 try:\r
59 nmCommand = "nm"\r
60 nmLineOption = "-l"\r
61 print "parsing (debug) - " + pdbName\r
62 os.system ('%s %s %s > nmDump.line.log' % (nmCommand, nmLineOption, pdbName))\r
63 except :\r
64 print 'ERROR: nm command not available. Please verify PATH'\r
65 return\r
66\r
67 #\r
68 # parse line\r
69 #\r
70 linefile = open("nmDump.line.log")\r
71 reportLines = linefile.readlines()\r
72 linefile.close()\r
73\r
74 # 000113ca T AllocatePool c:\home\edk-ii\MdePkg\Library\UefiMemoryAllocationLib\MemoryAllocationLib.c:399\r
d84577e5 75 patchLineFileMatchString = "([0-9a-fA-F]*)\s+[T|D|t|d]\s+(\w+)\s*((?:[a-zA-Z]:)?[\w+\-./_a-zA-Z0-9\\\\]*):?([0-9]*)"\r
1d9869f9
SZ
76\r
77 for reportLine in reportLines:\r
78 #print "check - " + reportLine\r
79 match = re.match(patchLineFileMatchString, reportLine)\r
80 if match is not None:\r
81 #print "match - " + reportLine[:-1]\r
82 #print "0 - " + match.group(0)\r
83 #print "1 - " + match.group(1)\r
84 #print "2 - " + match.group(2)\r
85 #print "3 - " + match.group(3)\r
86 #print "4 - " + match.group(4)\r
87\r
88 rva = int (match.group(1), 16)\r
89 functionName = match.group(2)\r
90 sourceName = match.group(3)\r
91 if cmp (match.group(4), "") != 0 :\r
92 lineName = int (match.group(4))\r
93 else :\r
94 lineName = 0\r
95 self.listLineAddress.append ([rva, functionName, lineName, sourceName])\r
96\r
97 self.lineCount = len (self.listLineAddress)\r
98\r
99 self.listLineAddress = sorted(self.listLineAddress, key=lambda symbolAddress:symbolAddress[0])\r
100\r
101 #for key in self.listLineAddress :\r
102 #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]\r
103\r
104 def parse_pdb_file(self, driverName, pdbName):\r
105 if cmp (pdbName, "") == 0 :\r
106 return\r
107 self.pdbName = pdbName;\r
108\r
109 try:\r
110 #DIA2DumpCommand = "\"C:\\Program Files (x86)\Microsoft Visual Studio 14.0\\DIA SDK\\Samples\\DIA2Dump\\x64\\Debug\\Dia2Dump.exe\""\r
111 DIA2DumpCommand = "Dia2Dump.exe"\r
112 #DIA2SymbolOption = "-p"\r
113 DIA2LinesOption = "-l"\r
114 print "parsing (pdb) - " + pdbName\r
115 #os.system ('%s %s %s > DIA2Dump.symbol.log' % (DIA2DumpCommand, DIA2SymbolOption, pdbName))\r
116 os.system ('%s %s %s > DIA2Dump.line.log' % (DIA2DumpCommand, DIA2LinesOption, pdbName))\r
117 except :\r
118 print 'ERROR: DIA2Dump command not available. Please verify PATH'\r
119 return\r
120\r
121 #\r
122 # parse line\r
123 #\r
124 linefile = open("DIA2Dump.line.log")\r
125 reportLines = linefile.readlines()\r
126 linefile.close()\r
127\r
128 # ** GetDebugPrintErrorLevel\r
129 # line 32 at [0000C790][0001:0000B790], len = 0x3 c:\home\edk-ii\mdepkg\library\basedebugprinterrorlevellib\basedebugprinterrorlevellib.c (MD5: 687C0AE564079D35D56ED5D84A6164CC)\r
130 # line 36 at [0000C793][0001:0000B793], len = 0x5\r
131 # line 37 at [0000C798][0001:0000B798], len = 0x2\r
132\r
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*"\r
134 patchLineFileMatchStringFunc = "\*\*\s+(\w+)\s*"\r
135\r
136 for reportLine in reportLines:\r
137 #print "check line - " + reportLine\r
138 match = re.match(patchLineFileMatchString, reportLine)\r
139 if match is not None:\r
140 #print "match - " + reportLine[:-1]\r
141 #print "0 - " + match.group(0)\r
142 #print "1 - " + match.group(1)\r
143 #print "2 - " + match.group(2)\r
144 if cmp (match.group(3), "") != 0 :\r
145 self.sourceName = match.group(3)\r
146 sourceName = self.sourceName\r
147 functionName = self.functionName\r
148\r
149 rva = int (match.group(2), 16)\r
150 lineName = int (match.group(1))\r
151 self.listLineAddress.append ([rva, functionName, lineName, sourceName])\r
152 else :\r
153 match = re.match(patchLineFileMatchStringFunc, reportLine)\r
154 if match is not None:\r
155 self.functionName = match.group(1)\r
156\r
157 self.lineCount = len (self.listLineAddress)\r
158 self.listLineAddress = sorted(self.listLineAddress, key=lambda symbolAddress:symbolAddress[0])\r
159\r
160 #for key in self.listLineAddress :\r
161 #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]\r
162\r
163class SymbolsFile:\r
164 def __init__(self):\r
165 self.symbolsTable = {}\r
166\r
167symbolsFile = ""\r
168\r
169driverName = ""\r
170rvaName = ""\r
171symbolName = ""\r
172\r
173def getSymbolName(driverName, rva):\r
174 global symbolsFile\r
175\r
176 #print "driverName - " + driverName\r
177\r
178 try :\r
179 symbolList = symbolsFile.symbolsTable[driverName]\r
180 if symbolList is not None:\r
181 return symbolList.getSymbol (rva)\r
182 else:\r
183 return " (???)"\r
184 except Exception:\r
185 return " (???)"\r
186\r
187def processLine(newline):\r
188 global driverName\r
189 global rvaName\r
190\r
191 driverPrefixLen = len("Driver - ")\r
192 # get driver name\r
193 if cmp(newline[0:driverPrefixLen],"Driver - ") == 0 :\r
194 driverlineList = newline.split(" ")\r
195 driverName = driverlineList[2]\r
196 #print "Checking : ", driverName\r
197\r
198 # EDKII application output\r
199 pdbMatchString = "Driver - \w* \(Usage - 0x[0-9a-fA-F]+\) \(Pdb - ([:\-.\w\\\\/]*)\)\s*"\r
200 pdbName = ""\r
201 match = re.match(pdbMatchString, newline)\r
202 if match is not None:\r
203 #print "match - " + newline\r
204 #print "0 - " + match.group(0)\r
205 #print "1 - " + match.group(1)\r
206 pdbName = match.group(1)\r
207 #print "PDB - " + pdbName\r
208\r
209 symbolsFile.symbolsTable[driverName] = Symbols()\r
210\r
211 if cmp (pdbName[-3:], "pdb") == 0 :\r
212 symbolsFile.symbolsTable[driverName].parse_pdb_file (driverName, pdbName)\r
213 else :\r
214 symbolsFile.symbolsTable[driverName].parse_debug_file (driverName, pdbName)\r
215\r
216 elif cmp(newline,"") == 0 :\r
217 driverName = ""\r
218\r
219 # check entry line\r
220 if newline.find ("<==") != -1 :\r
221 entry_list = newline.split(" ")\r
222 rvaName = entry_list[4]\r
223 #print "rva : ", rvaName\r
224 symbolName = getSymbolName (driverName, int(rvaName, 16))\r
225 else :\r
226 rvaName = ""\r
227 symbolName = ""\r
228\r
229 if cmp(rvaName,"") == 0 :\r
230 return newline\r
231 else :\r
232 return newline + symbolName\r
233\r
234def myOptionParser():\r
235 usage = "%prog [--version] [-h] [--help] [-i inputfile [-o outputfile]]"\r
236 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))\r
237 Parser.add_option("-i", "--inputfile", dest="inputfilename", type="string", help="The input memory profile info file output from MemoryProfileInfo application in MdeModulePkg")\r
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")\r
239\r
240 (Options, args) = Parser.parse_args()\r
241 if Options.inputfilename is None:\r
242 Parser.error("no input file specified")\r
243 if Options.outputfilename is None:\r
244 Options.outputfilename = "MemoryProfileInfoSymbol.txt"\r
245 return Options\r
246\r
247def main():\r
248 global symbolsFile\r
249 global Options\r
250 Options = myOptionParser()\r
251\r
252 symbolsFile = SymbolsFile()\r
253\r
254 try :\r
255 file = open(Options.inputfilename)\r
256 except Exception:\r
257 print "fail to open " + Options.inputfilename\r
258 return 1\r
259 try :\r
260 newfile = open(Options.outputfilename, "w")\r
261 except Exception:\r
262 print "fail to open " + Options.outputfilename\r
263 return 1\r
264\r
265 try:\r
266 while 1:\r
267 line = file.readline()\r
268 if not line:\r
269 break\r
270 newline = line[:-1]\r
271\r
272 newline = processLine(newline)\r
273\r
274 newfile.write(newline)\r
275 newfile.write("\n")\r
276 finally:\r
277 file.close()\r
278 newfile.close()\r
279\r
280if __name__ == '__main__':\r
281 sys.exit(main())\r