summaryrefslogtreecommitdiff
path: root/BaseTools
diff options
context:
space:
mode:
authorStar Zeng <star.zeng@intel.com>2016-06-26 13:07:26 +0800
committerHao Wu <hao.a.wu@intel.com>2016-07-13 09:34:09 +0800
commit77f5879b3fa4738ddd6243e7e399a61e7a75090c (patch)
tree2702ad132e46cb36297c47a619da0b422257ad45 /BaseTools
parent1d4f9134f786f8e376c1ad51b5ef0702f2996b27 (diff)
downloadedk2-platforms-77f5879b3fa4738ddd6243e7e399a61e7a75090c.tar.xz
BaseTools Scripts: Add MemoryProfileSymbolGen.py
This tool depends on DIA2Dump.exe (VS) or nm (gcc) to parse debug entry. Usage: MemoryProfileSymbolGen.py [--version] [-h] [--help] [-i inputfile [-o outputfile]] Copyright (c) 2016, Intel Corporation. All rights reserved. Options: --version show program's version number and exit -h, --help show this help message and exit -i INPUTFILENAME, --inputfile=INPUTFILENAME The input memory profile info file output from MemoryProfileInfo application in MdeModulePkg -o OUTPUTFILENAME, --outputfile=OUTPUTFILENAME The output memory profile info file with symbol, MemoryProfileInfoSymbol.txt will be used if it is not Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Liming Gao <liming.gao@intel.com> Cc: Yonghong Zhu <yonghong.zhu@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> (cherry picked from commit 1d9869f9e91605f6c099237eeb3414887f1258a9)
Diffstat (limited to 'BaseTools')
-rw-r--r--BaseTools/Scripts/MemoryProfileSymbolGen.py281
1 files changed, 281 insertions, 0 deletions
diff --git a/BaseTools/Scripts/MemoryProfileSymbolGen.py b/BaseTools/Scripts/MemoryProfileSymbolGen.py
new file mode 100644
index 0000000000..a9790d8883
--- /dev/null
+++ b/BaseTools/Scripts/MemoryProfileSymbolGen.py
@@ -0,0 +1,281 @@
+##
+# Generate symbal for memory profile info.
+#
+# This tool depends on DIA2Dump.exe (VS) or nm (gcc) to parse debug entry.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials are licensed and made available under
+# the terms and conditions of the BSD License that accompanies this distribution.
+# The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+import os
+import re
+import sys
+from optparse import OptionParser
+
+versionNumber = "1.0"
+__copyright__ = "Copyright (c) 2016, Intel Corporation. All rights reserved."
+
+class Symbols:
+ def __init__(self):
+ self.listLineAddress = []
+ self.pdbName = ""
+ # Cache for function
+ self.functionName = ""
+ # Cache for line
+ self.sourceName = ""
+
+
+ def getSymbol (self, rva):
+ index = 0
+ lineName = 0
+ sourceName = "??"
+ while index + 1 < self.lineCount :
+ if self.listLineAddress[index][0] <= rva and self.listLineAddress[index + 1][0] > rva :
+ offset = rva - self.listLineAddress[index][0]
+ functionName = self.listLineAddress[index][1]
+ lineName = self.listLineAddress[index][2]
+ sourceName = self.listLineAddress[index][3]
+ if lineName == 0 :
+ return " (" + self.listLineAddress[index][1] + "() - " + ")"
+ else :
+ return " (" + self.listLineAddress[index][1] + "() - " + sourceName + ":" + str(lineName) + ")"
+ index += 1
+
+ return " (unknown)"
+
+ def parse_debug_file(self, driverName, pdbName):
+ if cmp (pdbName, "") == 0 :
+ return
+ self.pdbName = pdbName;
+
+ try:
+ nmCommand = "nm"
+ nmLineOption = "-l"
+ print "parsing (debug) - " + pdbName
+ os.system ('%s %s %s > nmDump.line.log' % (nmCommand, nmLineOption, pdbName))
+ except :
+ print 'ERROR: nm command not available. Please verify PATH'
+ return
+
+ #
+ # parse line
+ #
+ linefile = open("nmDump.line.log")
+ reportLines = linefile.readlines()
+ linefile.close()
+
+ # 000113ca T AllocatePool c:\home\edk-ii\MdePkg\Library\UefiMemoryAllocationLib\MemoryAllocationLib.c:399
+ patchLineFileMatchString = "([0-9a-fA-F]{8})\s+[T|D|t|d]\s+(\w+)\s*((?:[a-zA-Z]:)?[\w+\-./_a-zA-Z0-9\\\\]*):?([0-9]*)"
+
+ for reportLine in reportLines:
+ #print "check - " + reportLine
+ match = re.match(patchLineFileMatchString, reportLine)
+ if match is not None:
+ #print "match - " + reportLine[:-1]
+ #print "0 - " + match.group(0)
+ #print "1 - " + match.group(1)
+ #print "2 - " + match.group(2)
+ #print "3 - " + match.group(3)
+ #print "4 - " + match.group(4)
+
+ rva = int (match.group(1), 16)
+ functionName = match.group(2)
+ sourceName = match.group(3)
+ if cmp (match.group(4), "") != 0 :
+ lineName = int (match.group(4))
+ else :
+ lineName = 0
+ self.listLineAddress.append ([rva, functionName, lineName, sourceName])
+
+ self.lineCount = len (self.listLineAddress)
+
+ self.listLineAddress = sorted(self.listLineAddress, key=lambda symbolAddress:symbolAddress[0])
+
+ #for key in self.listLineAddress :
+ #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]
+
+ def parse_pdb_file(self, driverName, pdbName):
+ if cmp (pdbName, "") == 0 :
+ return
+ self.pdbName = pdbName;
+
+ try:
+ #DIA2DumpCommand = "\"C:\\Program Files (x86)\Microsoft Visual Studio 14.0\\DIA SDK\\Samples\\DIA2Dump\\x64\\Debug\\Dia2Dump.exe\""
+ DIA2DumpCommand = "Dia2Dump.exe"
+ #DIA2SymbolOption = "-p"
+ DIA2LinesOption = "-l"
+ print "parsing (pdb) - " + pdbName
+ #os.system ('%s %s %s > DIA2Dump.symbol.log' % (DIA2DumpCommand, DIA2SymbolOption, pdbName))
+ os.system ('%s %s %s > DIA2Dump.line.log' % (DIA2DumpCommand, DIA2LinesOption, pdbName))
+ except :
+ print 'ERROR: DIA2Dump command not available. Please verify PATH'
+ return
+
+ #
+ # parse line
+ #
+ linefile = open("DIA2Dump.line.log")
+ reportLines = linefile.readlines()
+ linefile.close()
+
+ # ** GetDebugPrintErrorLevel
+ # line 32 at [0000C790][0001:0000B790], len = 0x3 c:\home\edk-ii\mdepkg\library\basedebugprinterrorlevellib\basedebugprinterrorlevellib.c (MD5: 687C0AE564079D35D56ED5D84A6164CC)
+ # line 36 at [0000C793][0001:0000B793], len = 0x5
+ # line 37 at [0000C798][0001:0000B798], len = 0x2
+
+ 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*"
+ patchLineFileMatchStringFunc = "\*\*\s+(\w+)\s*"
+
+ for reportLine in reportLines:
+ #print "check line - " + reportLine
+ match = re.match(patchLineFileMatchString, reportLine)
+ if match is not None:
+ #print "match - " + reportLine[:-1]
+ #print "0 - " + match.group(0)
+ #print "1 - " + match.group(1)
+ #print "2 - " + match.group(2)
+ if cmp (match.group(3), "") != 0 :
+ self.sourceName = match.group(3)
+ sourceName = self.sourceName
+ functionName = self.functionName
+
+ rva = int (match.group(2), 16)
+ lineName = int (match.group(1))
+ self.listLineAddress.append ([rva, functionName, lineName, sourceName])
+ else :
+ match = re.match(patchLineFileMatchStringFunc, reportLine)
+ if match is not None:
+ self.functionName = match.group(1)
+
+ self.lineCount = len (self.listLineAddress)
+ self.listLineAddress = sorted(self.listLineAddress, key=lambda symbolAddress:symbolAddress[0])
+
+ #for key in self.listLineAddress :
+ #print "rva - " + "%x"%(key[0]) + ", func - " + key[1] + ", line - " + str(key[2]) + ", source - " + key[3]
+
+class SymbolsFile:
+ def __init__(self):
+ self.symbolsTable = {}
+
+symbolsFile = ""
+
+driverName = ""
+rvaName = ""
+symbolName = ""
+
+def getSymbolName(driverName, rva):
+ global symbolsFile
+
+ #print "driverName - " + driverName
+
+ try :
+ symbolList = symbolsFile.symbolsTable[driverName]
+ if symbolList is not None:
+ return symbolList.getSymbol (rva)
+ else:
+ return " (???)"
+ except Exception:
+ return " (???)"
+
+def processLine(newline):
+ global driverName
+ global rvaName
+
+ driverPrefixLen = len("Driver - ")
+ # get driver name
+ if cmp(newline[0:driverPrefixLen],"Driver - ") == 0 :
+ driverlineList = newline.split(" ")
+ driverName = driverlineList[2]
+ #print "Checking : ", driverName
+
+ # EDKII application output
+ pdbMatchString = "Driver - \w* \(Usage - 0x[0-9a-fA-F]+\) \(Pdb - ([:\-.\w\\\\/]*)\)\s*"
+ pdbName = ""
+ match = re.match(pdbMatchString, newline)
+ if match is not None:
+ #print "match - " + newline
+ #print "0 - " + match.group(0)
+ #print "1 - " + match.group(1)
+ pdbName = match.group(1)
+ #print "PDB - " + pdbName
+
+ symbolsFile.symbolsTable[driverName] = Symbols()
+
+ if cmp (pdbName[-3:], "pdb") == 0 :
+ symbolsFile.symbolsTable[driverName].parse_pdb_file (driverName, pdbName)
+ else :
+ symbolsFile.symbolsTable[driverName].parse_debug_file (driverName, pdbName)
+
+ elif cmp(newline,"") == 0 :
+ driverName = ""
+
+ # check entry line
+ if newline.find ("<==") != -1 :
+ entry_list = newline.split(" ")
+ rvaName = entry_list[4]
+ #print "rva : ", rvaName
+ symbolName = getSymbolName (driverName, int(rvaName, 16))
+ else :
+ rvaName = ""
+ symbolName = ""
+
+ if cmp(rvaName,"") == 0 :
+ return newline
+ else :
+ return newline + symbolName
+
+def myOptionParser():
+ usage = "%prog [--version] [-h] [--help] [-i inputfile [-o outputfile]]"
+ Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber))
+ Parser.add_option("-i", "--inputfile", dest="inputfilename", type="string", help="The input memory profile info file output from MemoryProfileInfo application in MdeModulePkg")
+ 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")
+
+ (Options, args) = Parser.parse_args()
+ if Options.inputfilename is None:
+ Parser.error("no input file specified")
+ if Options.outputfilename is None:
+ Options.outputfilename = "MemoryProfileInfoSymbol.txt"
+ return Options
+
+def main():
+ global symbolsFile
+ global Options
+ Options = myOptionParser()
+
+ symbolsFile = SymbolsFile()
+
+ try :
+ file = open(Options.inputfilename)
+ except Exception:
+ print "fail to open " + Options.inputfilename
+ return 1
+ try :
+ newfile = open(Options.outputfilename, "w")
+ except Exception:
+ print "fail to open " + Options.outputfilename
+ return 1
+
+ try:
+ while 1:
+ line = file.readline()
+ if not line:
+ break
+ newline = line[:-1]
+
+ newline = processLine(newline)
+
+ newfile.write(newline)
+ newfile.write("\n")
+ finally:
+ file.close()
+ newfile.close()
+
+if __name__ == '__main__':
+ sys.exit(main())